Skip to content

@aws-cdk/aws-servicecatalogappregistry-alpha: Using Fn::Join with Name attribute in AWS::ServiceCatalogAppRegistry::Application generates Outputs that is not deployable #23641

Closed
@knihit

Description

Describe the bug

Using Fn.join in applicationName attribute when creating Application using https://docs.aws.amazon.com/cdk/api/v2/docs/@aws-cdk_aws-servicecatalogappregistry-alpha.Application.html to generate AWS::ServiceCatalogAppRegistry::Application also generates generates a Description in Outputs that is not deployable.

        const application = new appreg.Application(this, 'RegistrySetup', {
            applicationName: `App-${cdk.Aws.STACK_NAME}-application-name`,
            description: `Service Catalog application to track and manage all your resources for the solution ${this.solutionName}`
        });

Expected Behavior

Because the applicationName is dynamic, do not use it for Description for Outputs

Current Behavior

The above code also generates Outputs

   "Description": {
    "Fn::Join": [
     "",
     [
      "Application manager url for application App-",
      {
       "Ref": "AWS::StackName"
      },
      "-application-name"
     ]
    ]
   },
   "Value": {
    "Fn::Join": [
     "",
     [
      "https://",
      {
       "Ref": "AWS::Region"
      },
      ".console.aws.amazon.com/systems-manager/appmanager/application/AWS_AppRegistry_Application-App-",
      {
       "Ref": "AWS::StackName"
      },
      "-application-name"
     ]
    ]
   }
  }

Because the Description is not a string, the stack becomes undeployable

Reproduction Steps

Refer method createAppForAppRegistry

import * as cdk from 'aws-cdk-lib';
import * as applicationinsights from 'aws-cdk-lib/aws-applicationinsights';
import * as appreg from '@aws-cdk/aws-servicecatalogappregistry-alpha';
import { Construct, IConstruct } from 'constructs';

export class AppRegistry extends Construct implements cdk.IAspect {
    /**
     * Name of the solution as set through from cdk.json
     */
    private solutionName: string;

    /**
     * Name of the application used to create an entry in AppRegistry as set through cdk.json
     */
    private applicationName: string;

    /**
     * Solution ID as set through cdk.json
     */
    private solutionID: string;

    /**
     * Solution version as set through cdk.json
     */
    private solutionVersion: string;

    /**
     * An AttributeGroupName initialized in the constructor of this class
     */
    private attributeGroupName: string;

    /**
     * An application type attribute initialized in the constructor of this class
     */
    private applicationType: string;

    /**
     * The instance of application that the solution stacks should be associated with
     */
    private application: appreg.Application;

    constructor(scope: Construct, id: string) {
        super(scope, id);
        this.solutionName = scope.node.tryGetContext('solution_name');
        this.applicationName = scope.node.tryGetContext('app_registry_name');
        this.solutionID = scope.node.tryGetContext('solution_id');
        this.solutionVersion = scope.node.tryGetContext('solution_version');
        this.applicationType = scope.node.tryGetContext('application_type');
    }

    /**
     * Method invoked as a `Visitor` pattern to inject aspects during cdk synthesis
     *
     * @param node
     */
    public visit(node: IConstruct): void {
        if (node instanceof cdk.Stack) {
            const stack = node as cdk.Stack;
            // parent stack
            if (!stack.nested) {
                this.createAppForAppRegistry();
                this.createAttributeGroup();
                this.createAppForAppInsights();
            }
            this.addTagsforApplication();
            this.application.associateAllStacksInScope(stack);
        }
    }

    /**
     * Method to initialize an Application in AppRegistry service
     *
     * @returns - Instance of AppRegistry's Application class
     */
    private createAppForAppRegistry(): void {
        this.application = new appreg.Application(this, 'RegistrySetup', {
            applicationName: cdk.Fn.join('-', [this.applicationName, cdk.Aws.REGION, cdk.Aws.ACCOUNT_ID]),
            description: `Service Catalog application to track and manage all your resources for the solution ${this.solutionName}`
        });
    }

    /**
     * Method to add tags to the AppRegistry's Application instance
     *
     */
    private addTagsforApplication(): void {
        if (!this.application) {
            this.createAppForAppRegistry();
        }

        cdk.Tags.of(this.application).add('Solutions:SolutionID', this.solutionID);
        cdk.Tags.of(this.application).add('Solutions:SolutionName', this.solutionName);
        cdk.Tags.of(this.application).add('Solutions:SolutionVersion', this.solutionVersion);
        cdk.Tags.of(this.application).add('Solutions:ApplicationType', this.applicationType);
    }

    /**
     * Method to create AttributeGroup to be associated with the Application's instance in AppRegistry
     *
     */
    private createAttributeGroup(): void {
        if (!this.application) {
            this.createAppForAppRegistry();
        }

        this.application.associateAttributeGroup(
            new appreg.AttributeGroup(this, 'AppAttributes', {
                attributeGroupName: cdk.Aws.STACK_NAME,
                description: 'Attributes for Solutions Metadata',
                attributes: {
                    applicationType: this.applicationType,
                    version: this.solutionVersion,
                    solutionID: this.solutionID,
                    solutionName: this.solutionName
                }
            })
        );
    }

    /**
     * Method to create resources to enable application insights
     */
    private createAppForAppInsights(): void {
        if (!this.application) {
            this.createAppForAppRegistry();
        }
        new applicationinsights.CfnApplication(this, 'AppInsightsSetup', {
            resourceGroupName: cdk.Fn.join('-', [
                'AWS_AppRegistry_Application',
                this.applicationName,
                cdk.Aws.REGION,
                cdk.Aws.ACCOUNT_ID
            ]),
            autoConfigurationEnabled: true,
            cweMonitorEnabled: true,
            opsCenterEnabled: true
        }).addDependency(this.application.node.defaultChild as cdk.CfnResource);
    }
}

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.59.0

Framework Version

2.59.0

Node.js Version

16.16.0

OS

Ventura (Mac OSX)

Language

Typescript

Language Version

4.7.4

Other information

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions