AWSTemplateFormatVersion: '2010-09-09'
Description: Sample template that deploys a Monte Carlo Agent, Data Store, and OpenTelemetry Collector.
Metadata:
  License: >
    Copyright 2023 Monte Carlo Data, Inc.

    The Software contained herein (the "Software") is the intellectual property of Monte Carlo Data, Inc. ("Licensor"),
    and Licensor retains all intellectual property rights in the Software, including any and all derivatives, changes and
    improvements thereto. Only customers who have entered into a commercial agreement with Licensor for use or
    purchase of the Software ("Licensee") are licensed or otherwise authorized to use the Software, and any Licensee
    agrees that it obtains no copyright or other intellectual property rights to the Software, except for the license
    expressly granted below or in accordance with the terms of their commercial agreement with Licensor (the
    "Agreement"). Subject to the terms and conditions of the Agreement, Licensor grants Licensee a non-exclusive,
    non-transferable, non-sublicensable, revocable, limited right and license to use the Software, in each case solely
    internally within Licensee's organization for non-commercial purposes and only in connection with the service
    provided by Licensor pursuant to the Agreement, and in object code form only. Without Licensor's express prior
    written consent, Licensee may not, directly or indirectly, (i) distribute the Software, any portion thereof, or any
    modifications, enhancements, or derivative works of any of the foregoing (collectively, the "Derivatives") to any
    third party, (ii) license, market, sell, offer for sale or otherwise attempt to commercialize any Software, Derivatives,
    or portions thereof, (iii) use the Software, Derivatives, or any portion thereof for the benefit of any third party, (iv)
    use the Software, Derivatives, or any portion thereof in any manner or with respect to any commercial activity
    which competes, or is reasonably likely to compete, with any business that Licensor conducts, proposes to conduct
    or demonstrably anticipates conducting, at any time; or (v) seek any patent or other intellectual property rights or
    protections over or in connection with any Software of Derivatives.
Parameters:
  ExistingVpcId:
    Description: The VPC ID where the Agent and OpenTelemetry Collector will be deployed
    Type: AWS::EC2::VPC::Id
  ExistingSubnetIds:
    Description: List of subnet IDs where the Agent and OpenTelemetry Collector will be deployed (should be private subnets)
    Type: List<AWS::EC2::Subnet::Id>
  ExistingSecurityGroupId:
    Description: Optional additional security group ID to attach to the OpenTelemetry Collector resources. If provided, this security group will be added to the Network Load Balancer and ECS Service.
    Type: String
    Default: "N/A"
    AllowedPattern: '^(|N/A|sg-[0-9a-f]*)$'
    ConstraintDescription: Must be either empty, N/A, or a valid security group ID (sg-xxxxxxxxx)
  MonteCarloCloudAccountId:
    Description: >
      For deployments on the V2 Platform, use the Collection AWS account ID from the Account information page. Accounts created 
      after April 24th, 2024, will automatically be on the V2 platform or newer. If you are using an older version of the platform, 
      please contact your Monte Carlo representative for the ID.
    Type: String
    AllowedPattern: '^[0-9]{12}$'
    ConstraintDescription: Must be a valid 12-digit AWS account ID
  AgentConcurrentExecutions:
    Default: 20
    Description: The number of concurrent lambda executions for the agent.
    MaxValue: 200
    MinValue: 0
    Type: Number
  AgentImageUri:
    Default: 590183797493.dkr.ecr.*.amazonaws.com/mcd-agent:latest
    Description: >
      URI of the Agent container image (ECR Repo). Note that the region automatically maps to where this stack 
      is deployed in.
    Type: String
  AgentMemorySize:
    Default: 512
    Description: >
      The amount of memory (MB) available to the agent at runtime; this value can be any multiple of 
      1 MB greater than 256MB.
    MinValue: 256
    MaxValue: 10240
    Type: Number
  OpenTelemetryCollectorExternalID:
    Description: External ID for OpenTelemetry Collector S3 access. Update this value later after the CF stack is created to the value provided by your warehouse (e.g. Snowflake, Databricks, BigQuery)
    Type: String
    Default: "N/A"
  OpenTelemetryCollectorExternalPrincipalType:
    Description: Type of principal for OpenTelemetry Collector external access role. For Snowflake and Databricks, use "AWS". For BigQuery, use "Federated".
    Type: String
    Default: "AWS"
    AllowedValues: ["AWS", "Federated"]
  OpenTelemetryCollectorExternalAccessPrincipal:
    Description: AWS Principal (ARN or account ID) allowed to assume the OpenTelemetry Collector external access role. If left empty, will use the current AWS account ID. Update this value later after the CF stack is created to the value provided by your warehouse (e.g. Snowflake, Databricks, BigQuery)
    Type: String
    Default: "N/A"
    AllowedPattern: '^(|N/A|[0-9]{12}|arn:aws:.*:.*)$'
    ConstraintDescription: Must be either empty, N/A, a 12-digit AWS account ID, or a valid AWS ARN
  OpenTelemetryCollectorExternalNotificationChannelArn:
    Description: SQS Queue ARN or SNS Topic ARN to receive S3 event notifications for telemetry data. If left empty, no notifications will be configured. Update this value later after the CF stack is created to the value provided by your warehouse (e.g. Snowflake, Databricks, BigQuery).
    Type: String
    Default: "N/A"
    AllowedPattern: '^(|N/A|arn:aws:(sqs|sns):[^:]+:[0-9]{12}:[^:]+)$'
    ConstraintDescription: Must be either empty, N/A, a valid SQS ARN (arn:aws:sqs:region:account:queue-name), or a valid SNS ARN (arn:aws:sns:region:account:topic-name)
  OpenTelemetryCollectorImage:
    Description: The image URI for the OpenTelemetry Collector container image.
    Type: String
    Default: "otel/opentelemetry-collector-contrib:latest"
  OpenTelemetryCollectorExistingBucketArn:
    Description: ARN of an existing S3 bucket to store OpenTelemetry data. If left empty, the data store bucket will be used.
    Type: String
    Default: "N/A"
  ExternalAccessRoleName:
    Description: Custom name of the external access role. If left empty, will use the default name of "{AWS::StackName}-EAR".
    Type: String
    Default: "N/A"
Conditions:
  UseExistingTelemetryDataBucket: !Not [!Equals [!Ref OpenTelemetryCollectorExistingBucketArn, "N/A"]]
  HasNotificationChannel: !And
    - !Not [!Equals [!Ref OpenTelemetryCollectorExternalNotificationChannelArn, "N/A"]]
    - !Not [!Equals [!Ref OpenTelemetryCollectorExternalNotificationChannelArn, ""]]
  IsSQSNotification: !And
    - !Condition HasNotificationChannel
    - !Not [!Equals [!Select [0, !Split ["arn:aws:sqs", !Ref OpenTelemetryCollectorExternalNotificationChannelArn]], !Ref OpenTelemetryCollectorExternalNotificationChannelArn]]
Resources:
  Agent:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://mcd-public-resources.s3.amazonaws.com/cloudformation/aws_apollo_agent.yaml
      Parameters:
        CloudAccountId: !Ref MonteCarloCloudAccountId
        ConcurrentExecutions: !Ref AgentConcurrentExecutions
        ExistingVpcId: !Ref ExistingVpcId
        ExistingSubnetIds: !Join [ ',', !Ref ExistingSubnetIds ]
        ImageUri: !Ref AgentImageUri
        MemorySize: !Ref AgentMemorySize
        ExistingStorageArn: !GetAtt Storage.Arn
  OpenTelemetryCollector:
    Type: AWS::CloudFormation::Stack
    DependsOn: [Agent]
    Properties:
      TemplateURL: https://mcd-public-resources.s3.amazonaws.com/cloudformation/aws_otel_collector_ecs.yaml
      Parameters:
        ExistingVpcId: !Ref ExistingVpcId
        ExistingSubnetIds: !Join [ ',', !Ref ExistingSubnetIds ]
        ExistingSecurityGroupId: !Ref ExistingSecurityGroupId
        TelemetryDataBucketArn: !If
          - UseExistingTelemetryDataBucket
          - !Ref OpenTelemetryCollectorExistingBucketArn
          - !GetAtt Storage.Arn
        ExternalID: !Ref OpenTelemetryCollectorExternalID
        ExternalAccessPrincipal: !Ref OpenTelemetryCollectorExternalAccessPrincipal
        ExternalAccessPrincipalType: !Ref OpenTelemetryCollectorExternalPrincipalType
        ContainerImage: !Ref OpenTelemetryCollectorImage
        ExternalAccessRoleName: !Ref ExternalAccessRoleName
  Storage:
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      LifecycleConfiguration:
        Rules:
          - ExpirationInDays: 90
            Prefix: 'mcd/'
            Status: Enabled
          - ExpirationInDays: 2
            Prefix: 'mcd/responses/'
            Status: Enabled
          - ExpirationInDays: 30
            Prefix: 'mcd/otel-collector/'
            Status: Enabled
      NotificationConfiguration: !If
        - HasNotificationChannel
        - !If
          - IsSQSNotification
          - QueueConfigurations:
              - Event: s3:ObjectCreated:*
                Queue: !Ref OpenTelemetryCollectorExternalNotificationChannelArn
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: mcd/otel-collector/
              - Event: s3:ObjectRemoved:*
                Queue: !Ref OpenTelemetryCollectorExternalNotificationChannelArn
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: mcd/otel-collector/
          - TopicConfigurations:
              - Event: s3:ObjectCreated:*
                Topic: !Ref OpenTelemetryCollectorExternalNotificationChannelArn
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: mcd/otel-collector/
              - Event: s3:ObjectRemoved:*
                Topic: !Ref OpenTelemetryCollectorExternalNotificationChannelArn
                Filter:
                  S3Key:
                    Rules:
                      - Name: prefix
                        Value: mcd/otel-collector/
        - !Ref AWS::NoValue
    Type: AWS::S3::Bucket
  StorageSSLPolicy:
    Properties:
      Bucket: !Ref Storage
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: DenyActionsWithoutSSL
            Effect: Deny
            Principal:
              AWS: '*'
            Action:
              - '*'
            Resource:
              - !GetAtt Storage.Arn
              - !Sub '${Storage.Arn}/*'
            Condition:
              Bool:
                aws:SecureTransport:
                  - false
    Type: AWS::S3::BucketPolicy
Outputs:
  StorageBucketName:
    Description: Name of the S3 bucket used by the Agent and OpenTelemetry Collector to store data sampling records and telemetry data.
    Value: !Ref Storage
  StorageBucketArn:
    Description: ARN of the S3 bucket used by the Agent and OpenTelemetry Collector to store data sampling records and telemetry data.
    Value: !GetAtt Storage.Arn
  AgentFunctionArn:
    Description: Agent Function ARN. To be used in registering.
    Value: !GetAtt Agent.Outputs.FunctionArn
  AgentInvocationRoleArn:
    Description: Assumable role ARN. To be used in registering.
    Value: !GetAtt Agent.Outputs.InvocationRoleArn
  AgentInvocationRoleExternalId:
    Description: Assumable role External ID. To be used in registering.
    Value: !GetAtt Agent.Outputs.InvocationRoleExternalId
  OpenTelemetryCollectorGRPCEndpoint:
    Description: The gRPC endpoint for the OpenTelemetry Collector
    Value: !GetAtt OpenTelemetryCollector.Outputs.OpenTelemetryCollectorGRPCEndpoint
  OpenTelemetryCollectorHTTPEndpoint:
    Description: The HTTP endpoint for the OpenTelemetry Collector
    Value: !GetAtt OpenTelemetryCollector.Outputs.OpenTelemetryCollectorHTTPEndpoint
  OpenTelemetryCollectorExternalAccessRoleArn:
    Description: The ARN of the IAM role for external access to the OpenTelemetry S3 bucket
    Value: !GetAtt OpenTelemetryCollector.Outputs.OpenTelemetryCollectorExternalAccessRoleArn
  OpenTelemetryCollectorSecurityGroupId:
    Description: The ID of the security group for the OpenTelemetry Collector
    Value: !GetAtt OpenTelemetryCollector.Outputs.OpenTelemetryCollectorSecurityGroupId
