---
AWSTemplateFormatVersion: 2010-09-09
Description: 'Master manifest for ADP Promotion Planning usecase'
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: General configuration
        Parameters:
          - ADPS3BucketName
          - ADPS3BucketRegion
          - BasePlatformVersion
          - UseCaseVersion
          - DnsZoneType
          - EnableExternalAccess
          - DatasetBucket
      - Label:
          default: Application configuration
        Parameters:
          - UseKubernetesModel
          - UseSagemakerModel
          - KubeNamespace
          - DockerPPUIImage
          - DockerRegistry
          - DockerMlModelImage
          - MlflowServiceImageRepository
      - Label:
          default: Notebook-Instance configuration
        Parameters:
          - NotebookInstanceName
          - NotebookInstanceType
          - GitHubRepository
          - MlflowSetExperiment
          - EndpointName

Parameters:
  ADPS3BucketName:
    Type: String
    AllowedPattern: ^[0-9a-z]+([0-9a-z-]*[0-9a-z])*$
    ConstraintDescription:
      'Bucket name can include numbers, lowercase letters, and hyphens (-).
       It cannot start or end with a hyphen (-).'
    Description:
      'ADP bucket name with cloudformation scripts can include numbers,
      lowercase letters, and hyphens (-). It cannot start or end with a hyphen (-).'
    Default: 'griddynamics-analytical-data-platform-releases'
  ADPS3BucketRegion:
    Type: String
    Description: 'The AWS Region where the ADP S3 bucket (ADPS3BucketName) is hosted.'
    Default: 'us-east-1'
  BasePlatformVersion:
    Type: String
    Description: 'BasePlatform build version.'
    Default: '2023-02-16-marketplace'
  UseCaseVersion:
    Type: String
    Description: 'UseCase build version.'
    Default: '2023-02-16-marketplace'
  KubeNamespace:
    Type: String
    Description: 'K8s deployment namespace.'
    Default: 'promotion-planning-endpoint'
  EnableExternalAccess:
    Type: String
    Description:
      'Allow or deny access to UI from outside of VPC (disables ELB for EKS-based applications).
      Disabled by default to minimize unauthorized access.'
    AllowedValues: [ "Enabled", "Disabled" ]
    Default: 'Disabled'
  DnsZoneType:
    Type: String
    Description:
      'Should match with ADP Base Platform settings. Choose public if you already delegated responsibility for the subdomain to Route 53. This subdomain
      should be configured in Route53HostedZoneName. Otherwise choose a private DNS zone.'
    AllowedValues: [ "public", "private" ]
    Default: 'private'
  DockerPPUIImage:
    Type: String
    Description: 'Docker image name for Promotion Planning UI application.'
    Default: 'griddynamics/adp-promotion-planning-ui'
  DockerRegistry:
    Type: String
    Description: 'Docker registry.'
    Default: '125667932402.dkr.ecr.us-east-1.amazonaws.com'
  DatasetBucket:
    Type: String
    Description: 'An existing S3 bucket where Promotion planning dataset is located.'
    Default: ''
  NotebookInstanceName:
    Type: String
    Description: 'Name of the Amazon SageMaker Notebook instance'
    Default: 'adp-promotion-planning-instance'
  NotebookInstanceType:
    Description: 'The EC2 instance type for the data lake Amazon SageMaker Notebook instance.'
    ConstraintDescription: 'Must select a valid Notebook instance type'
    Type: String
    AllowedValues:
      - ml.t2.medium
      - ml.t2.large
      - ml.t2.xlarge
      - ml.t3.medium
      - ml.t3.large
    Default: 'ml.t3.large'
  GitHubRepository:
    Description: '[OPTIONAL] The Git repository associated with the notebook instance as its default code repository'
    Type: String
  UseKubernetesModel:
    Type: String
    AllowedValues: [ "Enabled", "Disabled" ]
    Default: 'Disabled'
  UseSagemakerModel:
    Type: String
    AllowedValues: [ "Enabled", "Disabled" ]
    Default: 'Enabled'
  MlflowSetExperiment:
    Description: 'Name of the Experiment into mlflow'
    Type: String
    Default: 'adp-promotion-planning-experiment'
  DockerMlModelImage:
    Type: String
    Default: 'griddynamics/adp-model-deployment'
  MlflowServiceImageRepository:
    Type: String
    Description: Enter your path of image. Repository should be created before starting this case
    Default: 'griddynamics/adp-mlflow-churn-predictions'
  EndpointName:
    Type: String
    Default: 'promotion-planning-endpoint'

Conditions:
  RunningInAnotherRegion: !Not [!Equals [!Ref ADPS3BucketRegion, !Ref "AWS::Region"]]
  EnableExternalAccessCondition: !And
    - !Equals [!Ref DnsZoneType, 'private']
    - !Equals [!Ref EnableExternalAccess, 'Enabled']
  UsingKubernetesModel: !Equals [ !Ref UseKubernetesModel, "Enabled" ]
  UsingSagemakerModel: !Equals [ !Ref UseSagemakerModel, "Enabled" ]

Resources:
  BasePlatformUtils:
    Type: AWS::CloudFormation::Stack
    Properties:
      Tags:
        - Key: 'Name'
          Value: 'BasePlatformUtils'
        - Key: 'Owner'
          Value: !ImportValue ADPPlatformOwner
        - Key: 'Project'
          Value: 'ADP'
      TemplateURL: !Sub 'https://${ADPS3BucketName}.s3.${ADPS3BucketRegion}.${AWS::URLSuffix}/platform/${BasePlatformVersion}/cloudformation/l0/base/utils.yaml'
      Parameters:
        ResourcePrefix: !ImportValue ADPResourcePrefix
        ADPS3BucketName: !Sub
          - '${BucketName}'
          - BucketName: !If [RunningInAnotherRegion, !ImportValue ADPS3BucketAnotherRegion, !Ref ADPS3BucketName]
        BasePlatformVersion: !Ref BasePlatformVersion

  BasePlatformOutputs:
    DependsOn: BasePlatformUtils
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformOutputsLambdaArn
      BpStateBucket: !Sub
        - "${ResourcePrefix}-platform-state-${AWS::AccountId}"
        - ResourcePrefix: !ImportValue ADPResourcePrefix

  BasePlatformLambdaFunctionsOutputs:
    DependsOn: BasePlatformOutputs
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformOutputsLambdaArn
      StackName: "BasePlatformLambdaFunctions"
      BpStateBucket: !Sub
        - "${ResourcePrefix}-platform-state-${AWS::AccountId}"
        - ResourcePrefix: !ImportValue ADPResourcePrefix

  BasePlatformInputs:
    DependsOn: BasePlatformLambdaFunctionsOutputs
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformInputsLambdaArn
      BpStateBucket: !Sub
        - "${ResourcePrefix}-platform-state-${AWS::AccountId}"
        - ResourcePrefix: !ImportValue ADPResourcePrefix

  BasePlatformCloudMapOutputs:
    DependsOn: BasePlatformInputs
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformOutputsLambdaArn
      StackName: "CloudMapStack"
      BpStateBucket: !Sub
        - "${ResourcePrefix}-platform-state-${AWS::AccountId}"
        - ResourcePrefix: !ImportValue ADPResourcePrefix

  BasePlatformVPCOutputs:
    DependsOn: BasePlatformCloudMapOutputs
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformOutputsLambdaArn
      StackName: "VPCStack"
      BpStateBucket: !Sub
        - "${ResourcePrefix}-platform-state-${AWS::AccountId}"
        - ResourcePrefix: !ImportValue ADPResourcePrefix

  BasePlatformKubernetes:
    DependsOn: BasePlatformCloudMapOutputs
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformLambdaOperateArn
      BpStateBucket: !GetAtt BasePlatformUtils.Outputs.BasePlatformStateBucketName
      BpGdComponent: "promotion_planning"
      BpAwsComponent: "Kubernetes"
      BpReferenceComponentName: "KubernetesStack"

  BasePlatformKubernetesExtra:
    DependsOn: BasePlatformKubernetes
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformLambdaOperateArn
      BpStateBucket: !GetAtt BasePlatformUtils.Outputs.BasePlatformStateBucketName
      BpGdComponent: "promotion_planning"
      BpAwsComponent: "KubernetesExtra"
      BpReferenceComponentName: "KubernetesExtraStack"

  BasePlatformMlflow:
    DependsOn: BasePlatformKubernetesExtra
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformLambdaOperateArn
      BpStateBucket: !GetAtt BasePlatformUtils.Outputs.BasePlatformStateBucketName
      BpGdComponent: "promotion_planning"
      BpAwsComponent: "Mlflow"
      BpReferenceComponentName: "MlflowStack"

  BasePlatformRedshift:
    DependsOn: BasePlatformMlflow
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt BasePlatformUtils.Outputs.BasePlatformLambdaOperateArn
      BpStateBucket: !GetAtt BasePlatformUtils.Outputs.BasePlatformStateBucketName
      BpGdComponent: "promotion_planning"
      BpAwsComponent: "Redshift"
      BpReferenceComponentName: "RedshiftStack"

  # Use-Case stack to hide custom resources from validator.
  PromotionPlanning:
    DependsOn: BasePlatformKubernetesExtra
    Type: AWS::CloudFormation::Stack
    Properties:
      Tags:
        - Key: 'Name'
          Value: 'PromotionPlanning'
        - Key: 'Owner'
          Value: !ImportValue ADPPlatformOwner
        - Key: 'Project'
          Value: 'ADP'
      TemplateURL: !Sub 'https://${ADPS3BucketName}.s3.${ADPS3BucketRegion}.${AWS::URLSuffix}/platform/${BasePlatformVersion}/cloudformation/l2/case-promotion-planning-eks.yaml'
      Parameters:
        ResourcePrefix: !ImportValue ADPResourcePrefix
        ADPS3BucketName: !Ref ADPS3BucketName
        UseCaseVersion: !Ref UseCaseVersion
        DockerRegistry: !Ref DockerRegistry
        DockerPPUIImage: !Ref DockerPPUIImage
        KubeManifestLambdaArn: !GetAtt BasePlatformKubernetes.KubeManifestLambdaArn
        KubeGetLambdaArn: !GetAtt BasePlatformKubernetes.KubeGetLambdaArn
        EKSClusterName: !GetAtt BasePlatformKubernetes.EKSClusterName
        ClusterOID: !GetAtt BasePlatformKubernetes.ClusterOID
        CloudMapNamespaceId: !GetAtt BasePlatformCloudMapOutputs.CloudMapNamespaceId
        Route53HostedZoneName: !GetAtt BasePlatformInputs.Route53HostedZoneName
        SagemakerEndpointName: !If [ UsingSagemakerModel, !Ref EndpointName, "" ]
        ModelKubeEndpoint: !If [ UsingKubernetesModel, !Sub "http://model-deployment.${KubeNamespace}.svc.cluster.local:8080", "" ]
        RemoteAccessCIDR: !ImportValue ADPRemoteAccessCIDR
        DnsZoneType: !Ref DnsZoneType
        EnableExternalAccess: !Ref EnableExternalAccess

  ModelsSMOutputBucket:
    DependsOn: PromotionPlanning
    Type: AWS::S3::Bucket
    DeletionPolicy: Delete
    Properties:
      BucketName: !Sub
        - '${ResourcePrefix}-sagemaker-${StackPrefix}'
        - { ResourcePrefix: !ImportValue ADPResourcePrefix,
            StackPrefix: !Select [ 2, !Split [ "/", !Ref "AWS::StackId" ] ] }
      AccessControl: "Private"
      Tags:
        - Key: 'Name'
          Value: 'ModelsSMOutputBucket'
        - Key: 'Owner'
          Value: !ImportValue ADPPlatformOwner
        - Key: 'Project'
          Value: 'ADP'

  EmptyBucketLambdaExec:
    DependsOn: ModelsSMOutputBucket
    Type: "Custom::EmptyBucketLambda"
    Properties:
      ServiceToken: !GetAtt BasePlatformLambdaFunctionsOutputs.EmptyBucketLambdaArn
      BucketToEmpty: !Ref ModelsSMOutputBucket

  SageMakerNotebook:
    DependsOn: EmptyBucketLambdaExec
    Type: AWS::CloudFormation::Stack
    Properties:
      Tags:
        - Key: 'Name'
          Value: 'SageMakerNotebook'
        - Key: 'Owner'
          Value: !ImportValue ADPPlatformOwner
        - Key: 'Project'
          Value: 'ADP'
      TemplateURL: !Sub 'https://${ADPS3BucketName}.s3.${ADPS3BucketRegion}.${AWS::URLSuffix}/platform/${BasePlatformVersion}/cloudformation/l1/ml/main.yaml'
      Parameters:
        DownloadFile: !Sub 'applications/adp/${UseCaseVersion}/notebooks/promotion-planning.ipynb'
        NotebookS3BucketName: !Ref ADPS3BucketName
        NotebookInstanceName: !Ref NotebookInstanceName
        SubnetID: !GetAtt BasePlatformVPCOutputs.PrivateSubnet1AID
        NotebookInstanceType: !Ref NotebookInstanceType
        MLEngineerGroupName: !GetAtt BasePlatformOutputs.MLEngineerGroupName
        DevOpsEngineerGroupName: !GetAtt BasePlatformOutputs.DevOpsEngineerGroupName
        VPCID: !GetAtt BasePlatformVPCOutputs.VPCID
        GitHubRepository: !Ref GitHubRepository
        MlflowTrackingUri: !GetAtt BasePlatformMlflow.MlflowFQDN
        MlflowSetExperiment: !Ref MlflowSetExperiment
        ResourcePrefix: !ImportValue ADPResourcePrefix

  SagemakerPPRunMLLambdaSecurityGroup:
    DependsOn: SageMakerNotebook
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SG for ml run initializer lambda function
      VpcId: !GetAtt BasePlatformVPCOutputs.VPCID
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          FromPort: -1
          IpProtocol: '-1'
          ToPort: -1

  SageMakerLambdaServiceRole:
    DependsOn: SagemakerPPRunMLLambdaSecurityGroup
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "sagemaker.amazonaws.com"
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AmazonSageMakerFullAccess"
        - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
        - "arn:aws:iam::aws:policy/AWSCloudMapDiscoverInstanceAccess"
      Policies:
        - PolicyName: SecretsManagerReadOnly
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'secretsmanager:GetResourcePolicy'
                  - 'secretsmanager:GetSecretValue'
                  - 'secretsmanager:DescribeSecret'
                  - 'secretsmanager:ListSecretVersionIds'
                Resource: !Sub
                  - 'arn:aws:secretsmanager:*:${AWS::AccountId}:secret:${ResourcePrefix}-*'
                  - ResourcePrefix: !ImportValue ADPResourcePrefix
              - Effect: Allow
                Action:
                  - 'iam:GetRolePolicy'
                Resource:
                  - '*'
              - Effect: Allow
                Action:
                  - "servicediscovery:GetInstance"
                  - "servicediscovery:RegisterInstance"
                Resource:
                  - !Sub "arn:aws:servicediscovery:${AWS::Region}:${AWS::AccountId}:*/*"
              - Effect: Allow
                Action:
                  - "ecr:PutImage"
                  - "ecr:CompleteLayerUpload"
                  - "ecr:UploadLayerPart"
                  - "ecr:InitiateLayerUpload"
                Resource:
                  - !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/${MlflowServiceImageRepository}"
              - Effect: Allow
                Action:
                  - 's3:PutObject*'
                Resource:
                  - !Sub "arn:aws:s3:::${ModelsSMOutputBucket}/*"
                  - !Sub
                    - "arn:aws:s3:::${MlflowArtifactS3Bucket}/*"
                    - MlflowArtifactS3Bucket: !GetAtt BasePlatformMlflow.MlflowArtifactS3Bucket

  SageMakerLambdaSelfPolicy:
    DependsOn: SageMakerLambdaServiceRole
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: SageMakerLambdaSelfPolicy
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - 'iam:GetRole'
            Resource:
              - !Sub 'arn:aws:iam::${AWS::AccountId}:role/${SageMakerLambdaServiceRole}'
      Roles:
        - !Ref SageMakerLambdaServiceRole

  SagemakerPPRunMLLambda:
    DependsOn: SageMakerLambdaServiceRole
    Type: "AWS::Lambda::Function"
    Properties:
      Description: Lambda function to work with Endpoints
      MemorySize: 8192
      Role: !GetAtt [SageMakerLambdaServiceRole, Arn]
      Timeout: 900
      PackageType: Image
      VpcConfig:
        SecurityGroupIds: [ !Ref SagemakerPPRunMLLambdaSecurityGroup ]
        SubnetIds:
          - !GetAtt BasePlatformVPCOutputs.PrivateSubnet1AID
      Code:
         ImageUri: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/griddynamics/ppmlflowlambda:${BasePlatformVersion}"

  SagemakerPPRunMLLambdaExec:
    DependsOn: SagemakerPPRunMLLambda
    Type: "Custom::SagemakerPPRunMLLambda"
    Properties:
      ServiceToken: !GetAtt SagemakerPPRunMLLambda.Arn
      Region: !Ref AWS::Region
      EndpointName: !Ref EndpointName
      DatasetBucket: !Ref DatasetBucket
      MlflowTrackingUri: !GetAtt BasePlatformMlflow.MlflowFQDN
      SageMakerServiceRole: !Ref SageMakerLambdaServiceRole
      MlflowServiceImageRepository: !Ref MlflowServiceImageRepository
      ModelsSMOutputBucket: !Ref ModelsSMOutputBucket
      InstanceType: "ml.m4.xlarge"
      PromotionPlanningSDService: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUICloudMapService
      PromotionPlanningSDInstance: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUICloudMapInstance
      PromotionPlanningSDAttribute: "artifacts_uri"
      UseKubernetesModel: !Ref UseKubernetesModel
      UseSagemakerModel: !Ref UseSagemakerModel

  LambdaCleanUpEPRole:
    Condition: UsingSagemakerModel
    DependsOn: SagemakerPPRunMLLambdaExec
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service: [lambda.amazonaws.com]
          Action: ['sts:AssumeRole']
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
        - "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
      Policies:
      - PolicyName: root
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
              - "sagemaker:InvokeEndpoint*"
              - "sagemaker:DescribeEndpoint*"
              - "sagemaker:DeleteModel"
              - "sagemaker:DescribeModel"
              - "sagemaker:DeleteEndpoint*"
              - "sagemaker:UpdateEndpoint"
            Resource:
              - !Sub "arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint/${EndpointName}"
              - !Sub "arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:endpoint-config/${EndpointName}*"
              - !Sub "arn:aws:sagemaker:${AWS::Region}:${AWS::AccountId}:model/${EndpointName}-model-*"
          - Effect: Allow
            Action:
              - "sagemaker:ListEndpoints"
            Resource: "*"
          - Effect: Allow
            Action:
              - 's3:DeleteObjectTagging'
              - 's3:GetJobTagging'
              - 's3:DeleteObjectVersion'
              - 's3:GetObjectVersionTagging'
              - 's3:ListBucketVersions'
              - 's3:ListJobs'
              - 's3:ListBucket'
              - 's3:DeleteObjectVersionTagging'
              - 's3:DeleteBucketPolicy'
              - 's3:GetObject'
              - 's3:DeleteJobTagging'
              - 's3:ListAllMyBuckets'
              - 's3:GetObjectTagging'
              - 's3:PutObjectTagging'
              - 's3:DeleteObject'
            Resource:
              - !Sub "arn:aws:s3:::${ModelsSMOutputBucket}/*"

  CrhelperLayer:
    Condition: UsingSagemakerModel
    DependsOn: LambdaCleanUpEPRole
    Type: AWS::Lambda::LayerVersion
    Properties:
      CompatibleRuntimes:
        - python3.6
        - python3.7
      Content:
        S3Bucket: !Sub
          - '${BucketName}'
          - BucketName: !If [ RunningInAnotherRegion, !ImportValue ADPS3BucketAnotherRegion, !Ref ADPS3BucketName ]
        S3Key: !Sub 'platform/${BasePlatformVersion}/functions/packages/crhelperLayer/lambda.zip'

  SagemakerCleanUpEPLambda:
    Condition: UsingSagemakerModel
    DependsOn: LambdaCleanUpEPRole
    Type: AWS::Lambda::Function
    Properties:
      Description: Lambda function to cleanup SageMaker Endpoint
      MemorySize: 1024
      Role: !GetAtt [LambdaCleanUpEPRole, Arn]
      Timeout: 90
      PackageType: Image
      Code:
        ImageUri: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/griddynamics/cleanup-ep-lambda:${BasePlatformVersion}"

  SagemakerCleanUpEPLambdaExec:
    Condition: UsingSagemakerModel
    DependsOn: SagemakerCleanUpEPLambda
    Type: "Custom::SagemakerCleanUpEPLambda"
    Properties:
      ServiceToken: !GetAtt SagemakerCleanUpEPLambda.Arn
      Region: !Ref AWS::Region
      EndpointName: !Ref EndpointName

  MlModelDeployment:
    DependsOn: SagemakerPPRunMLLambdaExec
    Condition: UsingKubernetesModel
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub 'https://${ADPS3BucketName}.s3.${ADPS3BucketRegion}.${AWS::URLSuffix}/platform/${BasePlatformVersion}/cloudformation/l1/ml/ml-model-deployment.yaml'
      Parameters:
        ResourcePrefix: !ImportValue ADPResourcePrefix
        DefaultS3BucketName: !Ref ADPS3BucketName
        ADPS3BucketName: !Ref ADPS3BucketName
        UseCaseVersion: !Ref UseCaseVersion
        DockerRegistry: !Ref DockerRegistry
        DockerMlModelImage: !Ref DockerMlModelImage
        KubeManifestLambdaArn: !GetAtt BasePlatformKubernetes.KubeManifestLambdaArn
        KubeGetLambdaArn: !GetAtt BasePlatformKubernetes.KubeGetLambdaArn
        EKSClusterName: !GetAtt BasePlatformKubernetes.EKSClusterName
        ClusterOID: !GetAtt BasePlatformKubernetes.ClusterOID
        Route53HostedZoneName: !GetAtt BasePlatformInputs.Route53HostedZoneName
        KubeNamespace: !Ref KubeNamespace
        CloudMapServiceId: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUICloudMapService
        CloudMapInstanceName: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUICloudMapInstance

Outputs:
  PromotionPlanningUIELB:
    Condition: EnableExternalAccessCondition
    Value: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUIELB
    Description: Promotion Planning service ELB address (will not work if external access is disabled)
  PromotionPlanningUIFQDN:
    Value: !GetAtt PromotionPlanning.Outputs.PromotionPlanningUIFQDN
    Description: Promotion Planning service DNS address (private zone will not be accessible form outside of VPC)
  NotebookInstanceName:
    Description: SageMaker Promotion Planning Instance Name
    Value: !Ref NotebookInstanceName
  NotebookURL:
    Description: "URL for the newly created SageMaker Notebook Instance"
    Value: !Sub 'https://${AWS::Region}.console.aws.amazon.com/sagemaker/home?region=${AWS::Region}#/notebook-instances/openNotebook/${NotebookInstanceName}'
