AWSTemplateFormatVersion: "2010-09-09"
Description: "Deploys the EC2 Autoscaling, LaunchConfig, ECS Cluster, and calls nested Stack for the ECS Service"
Parameters:
  PrivateSubnet1ID:
    Type: 'AWS::EC2::Subnet::Id'
  PrivateSubnet2ID:
    Type: 'AWS::EC2::Subnet::Id'
  MinScalingNodes:
    Type: Number
  MaxScalingNodes:
    Type: Number
  InstanceType:
    Type: String
  VolumeSize:
    Type: Number
  ClusterName:
    Description: Desired name for your cluster.
    Default: JFrog  
    Type: String
  CreateNewECSCluster:
    Description: Whether to create the ECS Cluster with given name or not.
    Default: Enabled
    Type: String
  DeploymentTag:
    Type: String
  NumberOfSecondary:
    Type: Number
  ArtifactoryLicense1:
    Type: String
  ArtifactoryLicense2:
    Type: String
  ArtifactoryLicense3:
    Type: String
  ArtifactoryLicense4:
    Type: String
  ArtifactoryServerName:
    Type: String
  CertificateDomain:
    Type: String    
  ArtifactoryIAMAcessKey:
    Type: String
    NoEcho: 'true'
  SecretAccessKey:
    Type: String
    NoEcho: 'true'
  ArtifactoryS3Bucket:
    Type: String
  CertificateKey:
    Type: String
    NoEcho: 'true'
  Certificate:
    Type: String
  DBType:
    Type: String
  DBPluginUrl:
    Default: https://bintray.com/artifact/download/bintray/jcenter/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar
    Type: String
  DBPlugin:
    Default: mysql-connector-java-5.1.38.jar
    Type: String
  ArtifactoryDBEndpointAddress:
    Type: String
  DatabaseName:
    Type: String
  DatabaseUser:
    Type: String
  DatabasePassword:
    NoEcho: 'true'
    Type: String
  MasterKey:
    Type: String
    NoEcho: 'true'
  ExtraJavaOptions:
    Type: String
  ArtifactoryVersion:
    Type: String
  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName    
  ArtifactoryTargetGroupArn:
    Type: String
  SecurityGroups:
    Type: String
  AnsibleVaultPass:
    Description: Ansiblevault Password to secure the artifactory.yml
    NoEcho: 'true'  
    Type: String
  QSS3BucketName:
    Type: String
  QSS3KeyPrefix:
    Type: String
Mappings:
  AWSAMIRegionMap:
    #AMI:
    #   AMZECSOTP: amzn-ami-2018.03.a-amazon-ecs-optimized
    us-east-2:
       AMI: ami-0307f7ccf6ea35750
    us-east-1:
       AMI: ami-045f1b3f87ed83659
    us-west-2:
       AMI: ami-01b70aea4161476b7
    us-west-1:
       AMI: ami-0285183bbef6224bd
    eu-west-3:
       AMI: ami-0f4738fbeb53e6c3a
    eu-west-2:
       AMI: ami-01bee3897bba49d78
    eu-west-1:
       AMI: ami-0627e141ce928067c
    eu-central-1:
       AMI: ami-0eaa3baf6969912ba
    eu-north-1:
       AMI: ami-03494b0c9e1c22492
    ap-northeast-2:
       AMI: ami-00294948a592fc052
    ap-northeast-1:
       AMI: ami-05b296a384694dfa4
    ap-southeast-2:
       AMI: ami-02c73ee1100ce3e7a
    ap-southeast-1:
       AMI: ami-050865a806e0dae53
    ca-central-1:
       AMI: ami-0f552e0a86f08b660
    ap-south-1:
       AMI: ami-01ef9f6a829ae3956
    sa-east-1:
       AMI: ami-084b1eee100c102ee
Conditions:
  CreateECSCluster: !Equals [!Ref 'CreateNewECSCluster', 'Enabled']
  GovCloudCondition: !Equals 
    - !Ref 'AWS::Region'
    - us-gov-west-1       
Resources:
  ECSRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      RoleName: !Sub
        ${ClusterName}-ECSRole-${AWS::Region}
      AssumeRolePolicyDocument:
        Statement:
          - Action:
            - sts:AssumeRole
            Principal:
              Service:
                - ecs-tasks.amazonaws.com
                - ec2.amazonaws.com
                - ecs.amazonaws.com
            Effect: Allow
        Version: 2012-10-17
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM'
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
      Policies:
        - PolicyName: ecs-service
          PolicyDocument: 
            Statement:
              - Effect: Allow
                Action:
                  - ecs:ListClusters
                  - ecs:ListServices
                  - ecs:DescribeServices
                  - ecr:ListImages
                  - ecs:RegisterTaskDefinition
                  - ecs:CreateService
                  - ecs:ListTasks
                  - ecs:DescribeTasks
                  - ecs:CreateService
                  - ecs:DeleteService
                  - ecs:UpdateService
                  - ecs:DescribeContainerInstances
                  - ecs:DescribeTaskDefinition
                  - application-autoscaling:DescribeScalableTargets
                  - iam:ListRoles
                Resource: "*"
  ECSInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties: 
      Path: /
      Roles: 
        - !Ref ECSRole
  ECSCluster: 
    Condition: CreateECSCluster
    Type: AWS::ECS::Cluster
    Properties: 
      ClusterName: !Ref ClusterName
  ArtifactoryScalingGroup:
    Type: 'AWS::AutoScaling::AutoScalingGroup'
    Properties:
      AutoScalingGroupName: ArtifactoryECSEC2ScaleGroup
      LaunchConfigurationName: !Ref ArtifactoryLaunchConfiguration
      VPCZoneIdentifier:
        - !Ref PrivateSubnet1ID
        - !Ref PrivateSubnet2ID
      MinSize: !Ref MinScalingNodes
      MaxSize: !Ref MaxScalingNodes
      Cooldown: '300'
      DesiredCapacity: !Ref MinScalingNodes
      HealthCheckType: EC2
      HealthCheckGracePeriod: 600
      Tags:
        - Key: Name
          Value: !Ref DeploymentTag
          PropagateAtLaunch: true
    CreationPolicy:
      ResourceSignal:
        Count: 1
        Timeout: PT30M                
  ArtifactoryLaunchConfiguration:
    Type: 'AWS::AutoScaling::LaunchConfiguration'
    Metadata:
      'AWS::CloudFormation::Authentication':
        S3AccessCreds:
          type: S3
          roleName: 
            - !Ref ECSRole
          buckets:
            - !Ref QSS3BucketName
      'AWS::CloudFormation::Init':
        configSets:
          artifactory_install:
            - "config-artifactory-master"
            - "secure-artifactory"
        config-artifactory-master:
          files:
            /root/.artifactory_ansible/artifactory.yml:
              content: !Sub 
                  - |
                    # Base install for Artifactory
                    - import_playbook: site-artifactory.yml
                      vars:
                        ecs_deployment: true
                        artifactory_hostname: artifactory
                        ssl_dir: /data/jfrog/nginx/ssl/
                        key_dir: /data/jfrog/nginx/ssl/
                        artifactory_license1: ${ArtifactoryLicense1}
                        artifactory_license2: ${ArtifactoryLicense2}
                        artifactory_license3: ${ArtifactoryLicense3}
                        artifactory_license4: ${ArtifactoryLicense4}
                        s3_endpoint: s3.${AWS::Region}.amazonaws.com
                        s3_access_key: ${ArtifactoryIAMAcessKey}
                        s3_access_secret_key: ${SecretAccessKey}
                        s3_bucket: ${ArtifactoryS3Bucket}
                        artifactory_server_name: ${ArtifactoryServerName}
                        certificate_domain: ${CertificateDomain}
                        certificate: ${cert}
                        certificate_key: ${cert_key}
                        java_mysql_driver:
                          url: ${DBPluginUrl}
                          dest: /data/jfrog/artifactory/plugins/${DBPlugin}
                          owner: root
                          group: root
                        rds_cert:
                          url: https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem
                          dest: /data/jfrog/artifactory/java_certs/rds-combined-ca-bundle.pem
                          owner: root
                          group: root
                  - cert: !Base64
                       "Fn::Sub": "${Certificate}"
                    cert_key: !Base64
                       "Fn::Sub": "${CertificateKey}"                        
              mode: "0400"
            /root/.vault_pass.txt:
              content: !Sub |
                ${AnsibleVaultPass}
              mode: "0400"
            /root/.secureit.sh:
              content: /usr/local/bin/ansible-vault encrypt /root/.artifactory_ansible/artifactory.yml --vault-id /root/.vault_pass.txt
              mode: "0770"
        secure-artifactory:
          commands:
            'secure ansible playbook':
              command: '/root/.secureit.sh'
              ignoreErrors: 'false'
    Properties:
      AssociatePublicIpAddress: false
      KeyName: !Ref KeyPairName
      IamInstanceProfile: !Ref ECSInstanceProfile
      ImageId: !FindInMap 
        - AWSAMIRegionMap
        - !Ref 'AWS::Region'
        - AMI
      SecurityGroups:
        - !Ref SecurityGroups
      InstanceType: !Ref InstanceType
      LaunchConfigurationName: ArtifactoryECSEC2LaunchConfig
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: !Ref VolumeSize
            VolumeType: gp2
            DeleteOnTermination: true
      UserData: !Base64 
        'Fn::Sub':
          - >
            #!/bin/bash -x

            #CFN Functions

            function cfn_fail

            {

            cfn-signal -e 1 --stack ${AWS::StackName} --region ${AWS::Region}
            --resource ArtifactoryScalingGroup

            exit 1

            }

            function cfn_success

            {

            cfn-signal -e 0 --stack ${AWS::StackName} --region ${AWS::Region}
            --resource ArtifactoryScalingGroup

            exit 0

            }

            echo ECS_CLUSTER=${ClusterName} >> /etc/ecs/ecs.config

            S3URI=https://${QSS3BucketName}.${S3Region}.amazonaws.com/${QSS3KeyPrefix}

            yum install -y git

            echo $PATH

            PATH=/usr/local/bin/:/opt/aws/bin:$PATH

            echo $PATH
            echo \'[Cloning: Load QuickStart Common Utils]\'

            git clone
            https://github.com/aws-quickstart/quickstart-linux-utilities.git

            source /quickstart-linux-utilities/quickstart-cfn-tools.source

            echo \'[Loaded: Load QuickStart Common Utils]\'

            echo \'[Update Operating System]\'

            qs_update-os || qs_err

            qs_bootstrap_pip || qs_err

            qs_aws-cfn-bootstrap || qs_err

            pip install awscli &> /var/log/userdata.awscli_install.log || qs_err " awscli install failed "
            
            pip install ansible &> /var/log/userdata.ansible_install.log || qs_err " ansible install failed "

            mkdir ~/.artifactory_ansible

            aws s3 sync s3://${QSS3BucketName}/${QSS3KeyPrefix}scripts/ ~/.artifactory_ansible/ 

            cfn-init -v --stack ${AWS::StackName} --resource
            ArtifactoryLaunchConfiguration --configsets artifactory_install
            --region ${AWS::Region} || cfn_fail

            export ANSIBLE_VAULT_PASSWORD_FILE="/root/.vault_pass.txt"

            /usr/local/bin/ansible-playbook /root/.artifactory_ansible/artifactory.yml

            rm -rf /root/.secureit.sh

            [ $(qs_status) == 0 ] && cfn_success || cfn_fail
          - S3Region: !If 
            - GovCloudCondition
            - s3-us-gov-west-1
            - s3
  ECSLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 7
  PrimaryStack:
    DependsOn: ArtifactoryScalingGroup
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub 'https://${QSS3BucketName}.s3.amazonaws.com/${QSS3KeyPrefix}templates/jfrog-jcr6-ecs.template.yaml'
      Parameters:
        ECSCluster: !Ref ClusterName # In case we do not build the cluster we still require the Name of the cluster built.
        ServiceName: ArtifactoryPrimary
        ArtifactoryTargetGroupArn: !Ref ArtifactoryTargetGroupArn
        ArtifactoryVersion: !Ref ArtifactoryVersion
        DBPlugin: !Ref DBPlugin
        MasterKey: !Ref MasterKey
        ExtraJavaOptions: !Ref ExtraJavaOptions
        NumberNodes: "1"
        ArtifactoryPrimary: "true"
        DBType: !Ref DBType
        DatabaseUser: !Ref DatabaseUser
        DatabaseName: !Ref DatabaseName
        DatabasePassword: !Ref DatabasePassword
        ArtifactoryDBEndpointAddress: !Ref ArtifactoryDBEndpointAddress
        ECSLogGroup: !Ref ECSLogGroup
        ECSRoleArn: 
          Fn::GetAtt: ECSRole.Arn
