Skip to content

Commit c171881

Browse files
committed
New CloudFormation stack listener for the core stack which saves the app
config services ECR repos when they are created or updated
1 parent 75d82c7 commit c171881

File tree

11 files changed

+760
-44
lines changed

11 files changed

+760
-44
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License").
6+
You may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
<parent>
21+
<groupId>com.amazon.aws.partners.saasfactory.saasboost</groupId>
22+
<artifactId>saasboost-functions</artifactId>
23+
<version>1.0.0</version>
24+
</parent>
25+
<artifactId>CoreStackListener</artifactId>
26+
<version>1.0.0</version>
27+
<packaging>jar</packaging>
28+
<licenses>
29+
<license>
30+
<name>Apache-2.0</name>
31+
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
32+
</license>
33+
</licenses>
34+
35+
<properties>
36+
<checkstyle.maxAllowedViolations>50</checkstyle.maxAllowedViolations>
37+
</properties>
38+
39+
<build>
40+
<finalName>${project.artifactId}</finalName>
41+
<plugins>
42+
<plugin>
43+
<groupId>org.apache.maven.plugins</groupId>
44+
<artifactId>maven-compiler-plugin</artifactId>
45+
</plugin>
46+
<plugin>
47+
<groupId>org.apache.maven.plugins</groupId>
48+
<artifactId>maven-surefire-plugin</artifactId>
49+
</plugin>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-assembly-plugin</artifactId>
53+
</plugin>
54+
<plugin>
55+
<groupId>pl.project13.maven</groupId>
56+
<artifactId>git-commit-id-plugin</artifactId>
57+
<version>4.0.0</version>
58+
<executions>
59+
<execution>
60+
<id>get-the-git-infos</id>
61+
<goals>
62+
<goal>revision</goal>
63+
</goals>
64+
<phase>initialize</phase>
65+
</execution>
66+
</executions>
67+
<configuration>
68+
<generateGitPropertiesFile>true</generateGitPropertiesFile>
69+
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
70+
<includeOnlyProperties>
71+
<includeOnlyProperty>^git.commit.id.describe</includeOnlyProperty>
72+
<includeOnlyProperty>^git.commit.id.describe-short</includeOnlyProperty>
73+
<includeOnlyProperty>^git.commit.time</includeOnlyProperty>
74+
<includeOnlyProperty>^git.closest.tag.name</includeOnlyProperty>
75+
</includeOnlyProperties>
76+
<commitIdGenerationMode>full</commitIdGenerationMode>
77+
<dotGitDirectory>../../.git</dotGitDirectory>
78+
<failOnNoGitDirectory>false</failOnNoGitDirectory>
79+
</configuration>
80+
</plugin>
81+
</plugins>
82+
</build>
83+
84+
<dependencies>
85+
<dependency>
86+
<groupId>junit</groupId>
87+
<artifactId>junit</artifactId>
88+
</dependency>
89+
<dependency>
90+
<groupId>org.slf4j</groupId>
91+
<artifactId>slf4j-nop</artifactId>
92+
</dependency>
93+
<dependency>
94+
<groupId>com.amazon.aws.partners.saasfactory.saasboost</groupId>
95+
<artifactId>Utils</artifactId>
96+
<version>1.0.0</version>
97+
<!-- Don't bundle our layer so we get the shared one at runtime -->
98+
<scope>provided</scope>
99+
</dependency>
100+
<dependency>
101+
<groupId>software.amazon.awssdk</groupId>
102+
<artifactId>cloudformation</artifactId>
103+
<version>${aws.java.sdk.version}</version>
104+
<exclusions>
105+
<exclusion>
106+
<groupId>software.amazon.awssdk</groupId>
107+
<artifactId>netty-nio-client</artifactId>
108+
</exclusion>
109+
<exclusion>
110+
<groupId>software.amazon.awssdk</groupId>
111+
<artifactId>apache-client</artifactId>
112+
</exclusion>
113+
</exclusions>
114+
</dependency>
115+
<dependency>
116+
<groupId>software.amazon.awssdk</groupId>
117+
<artifactId>eventbridge</artifactId>
118+
<version>${aws.java.sdk.version}</version>
119+
<exclusions>
120+
<exclusion>
121+
<groupId>software.amazon.awssdk</groupId>
122+
<artifactId>netty-nio-client</artifactId>
123+
</exclusion>
124+
<exclusion>
125+
<groupId>software.amazon.awssdk</groupId>
126+
<artifactId>apache-client</artifactId>
127+
</exclusion>
128+
</exclusions>
129+
</dependency>
130+
</dependencies>
131+
132+
</project>
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package com.amazon.aws.partners.saasfactory.saasboost;
2+
3+
import java.util.LinkedHashMap;
4+
import java.util.Map;
5+
6+
public class CloudFormationEvent {
7+
8+
private final String stackId;
9+
private final String timestamp;
10+
private final String eventId;
11+
private final String logicalResourceId;
12+
private final String namespace;
13+
private final String physicalResourceId;
14+
private final String principalId;
15+
private final Map<String, Object> resourceProperties;
16+
private final String resourceStatus;
17+
private final String resourceStatusReason;
18+
private final String resourceType;
19+
private final String stackName;
20+
private final String clientRequestToken;
21+
22+
private CloudFormationEvent(Builder builder) {
23+
this.stackId = builder.stackId;
24+
this.timestamp = builder.timestamp;
25+
this.eventId = builder.eventId;
26+
this.logicalResourceId = builder.logicalResourceId;
27+
this.namespace = builder.namespace;
28+
this.physicalResourceId = builder.physicalResourceId;
29+
this.principalId = builder.principalId;
30+
this.resourceProperties = builder.resourceProperties;
31+
this.resourceStatus = builder.resourceStatus;
32+
this.resourceStatusReason = builder.resourceStatusReason;
33+
this.resourceType = builder.resourceType;
34+
this.stackName = builder.stackName;
35+
this.clientRequestToken = builder.clientRequestToken;
36+
}
37+
38+
public static Builder builder() {
39+
return new Builder();
40+
}
41+
42+
public String getStackId() {
43+
return stackId;
44+
}
45+
46+
public String getTimestamp() {
47+
return timestamp;
48+
}
49+
50+
public String getEventId() {
51+
return eventId;
52+
}
53+
54+
public String getLogicalResourceId() {
55+
return logicalResourceId;
56+
}
57+
58+
public String getNamespace() {
59+
return namespace;
60+
}
61+
62+
public String getPhysicalResourceId() {
63+
return physicalResourceId;
64+
}
65+
66+
public String getPrincipalId() {
67+
return principalId;
68+
}
69+
70+
public Map<String, Object> getResourceProperties() {
71+
return resourceProperties != null ? Map.copyOf(resourceProperties) : null;
72+
}
73+
74+
public String getResourceStatus() {
75+
return resourceStatus;
76+
}
77+
78+
public String getResourceStatusReason() {
79+
return resourceStatusReason;
80+
}
81+
82+
public String getResourceType() {
83+
return resourceType;
84+
}
85+
86+
public String getStackName() {
87+
return stackName;
88+
}
89+
90+
public String getClientRequestToken() {
91+
return clientRequestToken;
92+
}
93+
94+
public static final class Builder {
95+
private String stackId;
96+
private String timestamp;
97+
private String eventId;
98+
private String logicalResourceId;
99+
private String namespace;
100+
private String physicalResourceId;
101+
private String principalId;
102+
private Map<String, Object> resourceProperties;
103+
private String resourceStatus;
104+
private String resourceStatusReason;
105+
private String resourceType;
106+
private String stackName;
107+
private String clientRequestToken;
108+
109+
private Builder() {
110+
this.resourceProperties = new LinkedHashMap<>();
111+
}
112+
113+
public Builder stackId(String stackId) {
114+
this.stackId = stackId;
115+
return this;
116+
}
117+
118+
public Builder timestamp(String timestamp) {
119+
this.timestamp = timestamp;
120+
return this;
121+
}
122+
123+
public Builder eventId(String eventId) {
124+
this.eventId = eventId;
125+
return this;
126+
}
127+
128+
public Builder logicalResourceId(String logicalResourceId) {
129+
this.logicalResourceId = logicalResourceId;
130+
return this;
131+
}
132+
133+
public Builder namespace(String namespace) {
134+
this.namespace = namespace;
135+
return this;
136+
}
137+
138+
public Builder physicalResourceId(String physicalResourceId) {
139+
this.physicalResourceId = physicalResourceId;
140+
return this;
141+
}
142+
143+
public Builder principalId(String principalId) {
144+
this.principalId = principalId;
145+
return this;
146+
}
147+
148+
public Builder resourceProperties(Map<String, Object> resourceProperties) {
149+
this.resourceProperties = resourceProperties != null ? resourceProperties : new LinkedHashMap<>();
150+
return this;
151+
}
152+
153+
public Builder resourceStatus(String resourceStatus) {
154+
this.resourceStatus = resourceStatus;
155+
return this;
156+
}
157+
158+
public Builder resourceStatusReason(String resourceStatusReason) {
159+
this.resourceStatusReason = resourceStatusReason;
160+
return this;
161+
}
162+
163+
public Builder resourceType(String resourceType) {
164+
this.resourceType = resourceType;
165+
return this;
166+
}
167+
168+
public Builder stackName(String stackName) {
169+
this.stackName = stackName;
170+
return this;
171+
}
172+
173+
public Builder clientRequestToken(String clientRequestToken) {
174+
this.clientRequestToken = clientRequestToken;
175+
return this;
176+
}
177+
178+
public CloudFormationEvent build() {
179+
return new CloudFormationEvent(this);
180+
}
181+
}
182+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.amazon.aws.partners.saasfactory.saasboost;
2+
3+
import java.util.LinkedHashMap;
4+
5+
public class CloudFormationEventDeserializer {
6+
7+
private CloudFormationEventDeserializer() {
8+
}
9+
10+
public static CloudFormationEvent deserialize(String snsMessage) {
11+
// Raw SNS message values are escaped JSON strings with \n instead of newlines and
12+
// single quotes instead of doubles around values
13+
CloudFormationEvent.Builder builder = CloudFormationEvent.builder();
14+
for (String keyValue : snsMessage.split("\\n")) {
15+
// Each line will look like Key='Value' e.g. ResourceStatus='CREATE_COMPLETE'
16+
// We'll be reckless and use substring instead of a regex to break it apart.
17+
String key = keyValue.substring(0, keyValue.indexOf("="));
18+
String value = keyValue.substring(keyValue.indexOf("=") + 2, keyValue.length() - 1);
19+
//LOGGER.info(key + " => " + value);
20+
if ("StackId".equals(key)) {
21+
builder.stackId(nullIf(value));
22+
} else if ("Timestamp".equals(key)) {
23+
builder.timestamp(nullIf(value));
24+
} else if ("EventId".equals(key)) {
25+
builder.eventId(nullIf(value));
26+
} else if ("LogicalResourceId".equals(key)) {
27+
builder.logicalResourceId(nullIf(value));
28+
} else if ("Namespace".equals(key)) {
29+
builder.namespace(nullIf(value));
30+
} else if ("PhysicalResourceId".equals(key)) {
31+
builder.physicalResourceId(nullIf(value));
32+
} else if ("PrincipalId".equals(key)) {
33+
builder.principalId(value);
34+
} else if ("ResourceProperties".equals(key)) {
35+
if (!"null".equals(value)) {
36+
String json = Utils.unescapeJson(value);
37+
builder.resourceProperties(Utils.fromJson(json, LinkedHashMap.class));
38+
}
39+
} else if ("ResourceStatus".equals(key)) {
40+
builder.resourceStatus(nullIf(value));
41+
} else if ("ResourceStatusReason".equals(key)) {
42+
builder.resourceStatusReason(nullIf(value));
43+
} else if ("ResourceType".equals(key)) {
44+
builder.resourceType(nullIf(value));
45+
} else if ("StackName".equals(key)) {
46+
builder.stackName(nullIf(value));
47+
} else if ("ClientRequestToken".equals(key)) {
48+
builder.clientRequestToken(nullIf(value));
49+
}
50+
}
51+
return builder.build();
52+
}
53+
54+
protected static String nullIf(String value) {
55+
return "null".equals(value) ? null : value;
56+
}
57+
}

0 commit comments

Comments
 (0)