Skip to content

Commit 70710ed

Browse files
author
PoeppingT
committed
Fix bug in updating repository for services with non-CloudFormation-compatible names.
When a new AppConfig is published with additional services, multiple parts of a workflow kick off. 1. Settings Service fires an event to the Onboarding service to update the stack. 2. Onboarding service updates the core stack with the updated AppConfig (updating created infrastructure for configured services). 3. As part of the update-stack kicked off by the Onboarding service, the app-services-ecr-macro kicks in to alter the template according to that new AppConfig because CloudFormation executes the template update. 4. core-stack-listener function automatically listens to updates on that stack, waiting for ECR repositories to be marked as CREATE_COMPLETE. When that happens, core-stack-listener pulls the service name from that resource and fires an event to Settings to update the configured ECR repository for that service. Before this commit, there was a bug in the interaction between the core-stack-listener and the app-services-ecr-macro. The core-stack-listener was expecting the CloudFormation resource name of the ECR repository to represent the real service name as stored in the Settings service, while the app-services-ecr-macro had made changes to that same name to ensure the resource matched CloudFormation restrictions ([a-zA-Z0-9]+). The Settings service only enforces that service names conform to SSM ParameterStore restrictions ([a-zA-Z0-9\.-_]+). Luckily, the app-services-ecr-macro was already creating a Tag for the ECR resource containing the service name. So this commit alters the core-stack-listener to: 1. have permissions to list tags for ECR resources matching the repository name patterns that will be created by the core stack 2. resolves the service name for a given repository by reading the tag, rather than the resource name (falling back to resource name if no tag was found) before sending the event to Settings In manual testing this has been shown to fix the issue.
1 parent 965e4d2 commit 70710ed

File tree

3 files changed

+59
-10
lines changed

3 files changed

+59
-10
lines changed

functions/core-stack-listener/pom.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ limitations under the License.
3333
</licenses>
3434

3535
<properties>
36-
<checkstyle.maxAllowedViolations>50</checkstyle.maxAllowedViolations>
36+
<checkstyle.maxAllowedViolations>0</checkstyle.maxAllowedViolations>
3737
</properties>
3838

3939
<build>
@@ -126,6 +126,21 @@ limitations under the License.
126126
</exclusion>
127127
</exclusions>
128128
</dependency>
129+
<dependency>
130+
<groupId>software.amazon.awssdk</groupId>
131+
<artifactId>ecr</artifactId>
132+
<version>${aws.java.sdk.version}</version>
133+
<exclusions>
134+
<exclusion>
135+
<groupId>software.amazon.awssdk</groupId>
136+
<artifactId>netty-nio-client</artifactId>
137+
</exclusion>
138+
<exclusion>
139+
<groupId>software.amazon.awssdk</groupId>
140+
<artifactId>apache-client</artifactId>
141+
</exclusion>
142+
</exclusions>
143+
</dependency>
129144
</dependencies>
130145

131146
</project>

functions/core-stack-listener/src/main/java/com/amazon/aws/partners/saasfactory/saasboost/CoreStackListener.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
import org.slf4j.LoggerFactory;
2424
import software.amazon.awssdk.core.exception.SdkServiceException;
2525
import software.amazon.awssdk.services.cloudformation.CloudFormationClient;
26-
import software.amazon.awssdk.services.cloudformation.model.*;
26+
import software.amazon.awssdk.services.cloudformation.model.ListStackResourcesResponse;
27+
import software.amazon.awssdk.services.cloudformation.model.ResourceStatus;
28+
import software.amazon.awssdk.services.cloudformation.model.StackResourceSummary;
29+
import software.amazon.awssdk.services.ecr.EcrClient;
30+
import software.amazon.awssdk.services.ecr.model.ListTagsForResourceResponse;
31+
import software.amazon.awssdk.services.ecr.model.Tag;
2732
import software.amazon.awssdk.services.eventbridge.EventBridgeClient;
2833

2934
import java.util.*;
@@ -40,6 +45,7 @@ public class CoreStackListener implements RequestHandler<SNSEvent, Object> {
4045
Arrays.asList("CREATE_COMPLETE", "UPDATE_COMPLETE"));
4146
private final CloudFormationClient cfn;
4247
private final EventBridgeClient eventBridge;
48+
private final EcrClient ecr;
4349

4450
public CoreStackListener() {
4551
final long startTimeMillis = System.currentTimeMillis();
@@ -51,13 +57,20 @@ public CoreStackListener() {
5157
}
5258
this.cfn = Utils.sdkClient(CloudFormationClient.builder(), CloudFormationClient.SERVICE_NAME);
5359
this.eventBridge = Utils.sdkClient(EventBridgeClient.builder(), EventBridgeClient.SERVICE_NAME);
60+
this.ecr = Utils.sdkClient(EcrClient.builder(), EcrClient.SERVICE_NAME);
5461
LOGGER.info("Constructor init: {}", System.currentTimeMillis() - startTimeMillis);
5562
}
5663

5764
@Override
5865
public Object handleRequest(SNSEvent event, Context context) {
5966
LOGGER.info(Utils.toJson(event));
6067

68+
// ARN: arn:<partition>:<service>:<region>:<accountId>:<itemType>/<itemName>
69+
final String[] thisLambdaArn = context.getInvokedFunctionArn().split(":");
70+
final String partition = thisLambdaArn[1];
71+
final String region = thisLambdaArn[3];
72+
final String accountId = thisLambdaArn[4];
73+
6174
List<SNSEvent.SNSRecord> records = event.getRecords();
6275
SNSEvent.SNS sns = records.get(0).getSNS();
6376
String message = sns.getMessage();
@@ -81,18 +94,34 @@ public Object handleRequest(SNSEvent event, Context context) {
8194
Map<String, Object> appConfig = new HashMap<>();
8295
Map<String, Object> services = new HashMap<>();
8396
for (StackResourceSummary resource : resources.stackResourceSummaries()) {
84-
// LOGGER.debug("Processing resource {} {} {} {}", resource.resourceType(),
85-
// resource.resourceStatusAsString(), resource.logicalResourceId(),
86-
// resource.physicalResourceId());
87-
if ("CREATE_COMPLETE".equals(resource.resourceStatusAsString())
88-
&& "AWS::ECR::Repository".equals(resource.resourceType())) {
97+
// LOGGER.debug("Processing resource {} {} {} {}", resource.resourceType(),
98+
// resource.resourceStatusAsString(), resource.logicalResourceId(),
99+
// resource.physicalResourceId());
100+
// TODO or UPDATE_COMPLETE?
101+
if (ResourceStatus.CREATE_COMPLETE == resource.resourceStatus()
102+
&& AwsResource.ECR_REPO.getResourceType().equals(resource.resourceType())) {
89103
String ecrRepo = resource.physicalResourceId();
104+
String ecrResourceArn = AwsResource.ECR_REPO.formatArn(partition, region, accountId, ecrRepo);
105+
ListTagsForResourceResponse response = ecr.listTagsForResource(request -> request
106+
.resourceArn(ecrResourceArn));
90107
String serviceName = resource.logicalResourceId();
91-
LOGGER.info("Publishing appConfig update event for ECR repository {} {}", serviceName,
108+
String serviceNameContext = "Read from Template";
109+
if (response.hasTags()) {
110+
for (Tag tag : response.tags()) {
111+
if (tag.key().equalsIgnoreCase("Name")) {
112+
serviceName = tag.value();
113+
serviceNameContext = "Read from Tag";
114+
}
115+
}
116+
}
117+
118+
LOGGER.info("Publishing appConfig update event for ECR repository {}({}) {}",
119+
serviceName,
120+
serviceNameContext,
92121
ecrRepo);
93122
services.put(serviceName, Map.of("containerRepo", ecrRepo));
94-
} else if ("CREATE_COMPLETE".equals(resource.resourceStatusAsString())
95-
|| "UPDATE_COMPLETE".equals(resource.resourceStatusAsString())) {
123+
} else if (ResourceStatus.CREATE_COMPLETE.equals(resource.resourceStatus())
124+
|| ResourceStatus.UPDATE_COMPLETE.equals(resource.resourceStatus())) {
96125
if ("AWS::Route53::HostedZone".equals(resource.resourceType())) {
97126
// When CloudFormation stack first completes, the Settings Service won't even exist yet.
98127
String hostedZoneId = resource.physicalResourceId();

resources/saas-boost.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,11 @@ Resources:
534534
- events:PutEvents
535535
Resource:
536536
- !Sub arn:aws:events:${AWS::Region}:${AWS::AccountId}:event-bus/${SaaSBoostEventBus}
537+
- Effect: Allow
538+
Action:
539+
- ecr:ListTagsForResource
540+
Resource:
541+
- !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/sb-${Environment}-core-*
537542
CoreStackListenerLogs:
538543
Type: AWS::Logs::LogGroup
539544
Properties:

0 commit comments

Comments
 (0)