constructor()

in resources/beam-on-kda/cdk/lib/windows-dev-environment.ts [24:219]


  constructor(scope: cdk.Construct, id: string, props: WindowsDevEnvironmentProps) {
    super(scope, id);


    new GithubBuildPipeline(this, 'KinesisReplayBuildPipeline', {
      url: `https://github.com/aws-samples/amazon-kinesis-replay/archive/${props.kinesisReplayVersion}.zip`,
      bucket: props.bucket,
      extract: true
    });


    const localAdminPassword = new secretsmanager.Secret(this, 'TemplatedSecret', {
      generateSecretString: {
        secretStringTemplate: JSON.stringify({ username: 'Administrator' }),
        generateStringKey: 'password',
        passwordLength: 16,
        excludePunctuation: true,
        includeSpace: false
      }
    });

    

    const policy = new iam.PolicyDocument();

    policy.addStatements(new iam.PolicyStatement({
      actions: [
        'secretsmanager:GetSecretValue',
      ],
      resources: [ localAdminPassword.secretArn ]
    }));

    policy.addStatements(new iam.PolicyStatement({
      actions: [
        'ec2:AssociateAddress',
        'cloudwatch:PutMetricData',
        'logs:Describe*', 'logs:PutLogEvents',
        'kinesis:DescribeStream', 'kinesis:ListShards', 'kinesis:GetShardIterator', 'kinesis:GetRecords', 'kinesis:PutRecord', 'kinesis:PutRecords',
        'kinesisanalytics:StartApplication'
      ],
      resources: [ '*' ]
    }));

    policy.addStatements(new iam.PolicyStatement({
      actions: [
        'cloudformation:DescribeStacks'
      ],
      resources: [ cdk.Aws.STACK_ID ]
    }));

    policy.addStatements(new iam.PolicyStatement({
      actions: [
        's3:GetObject*', 's3:GetBucket*', 's3:List*'
      ],
      resources: [
        props.bucket.bucketArn,
        `${props.bucket.bucketArn}/*`,
        `arn:${cdk.Aws.PARTITION}:s3:::aws-bigdata-blog`,
        `arn:${cdk.Aws.PARTITION}:s3:::aws-bigdata-blog/*`,
      ]
    }));


    const eip = new ec2.CfnEIP(this, 'InstanceEip');

    const ami = new ec2.WindowsImage(ec2.WindowsVersion.WINDOWS_SERVER_2019_ENGLISH_FULL_BASE);

    const instanceRole = new iam.Role(this, 'InstanceRole', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')
      ],
      inlinePolicies: {
        WorkshopPermissions: policy
      }
    });

    const instanceProfile = new iam.CfnInstanceProfile(this, 'InstanceProfile', {
      roles: [
        instanceRole.roleName
      ]
    });

    const waitHandle = new cfn.CfnWaitConditionHandle(this, 'InstanceWaitHandle');

    const waitCondition = new cfn.CfnWaitCondition(this, 'InstanceBootstrapWaitCondition', {
      count: 1,
      handle: waitHandle.ref,
      timeout: Duration.minutes(20).toSeconds().toString()
    });

    const launchTemplate = new ec2.CfnLaunchTemplate(this, 'LaunchTemplate', {
      launchTemplateData: {
        imageId: ami.getImage(this).imageId,
        iamInstanceProfile: {
          arn: instanceProfile.attrArn
        },
        networkInterfaces: [{
          associatePublicIpAddress: true,
          deleteOnTermination: true,
          deviceIndex: 0,
          groups: [props.sg.securityGroupId]
        }],
        userData: cdk.Fn.base64(
          `<powershell>            
            Import-Module AWSPowerShell

            # Install choco
            iex ((New-Object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))

            # Add gitter and retry to install commands
            $iter = 0
            $sleep = 5

            Do {
              Start-Sleep -Seconds (Get-Random -Maximum ($sleep*[Math]::Pow(2,$iter++)))
              choco install git --no-progress -y
            } Until ($LASTEXITCODE -eq 0)

            Do {
              Start-Sleep -Seconds (Get-Random -Maximum ($sleep*[Math]::Pow(2,$iter++)))
              choco install firefox --no-progress -y
            } Until ($LASTEXITCODE -eq 0)

            Do {
              Start-Sleep -Seconds (Get-Random -Maximum ($sleep*[Math]::Pow(2,$iter++)))
              choco install intellijidea-community --no-progress --version 2020.1.2 -y
            } Until ($LASTEXITCODE -eq 0)

            # Add IntelliJ Java 11 to the path
            $PATH = [Environment]::GetEnvironmentVariable("PATH", "Machine")
            $intellij_path = "C:\\Program Files\\JetBrains\\IntelliJ IDEA Community Edition 2020.1.2\\jbr\\bin"
            [Environment]::SetEnvironmentVariable("PATH", "$PATH;$intellij_path", "Machine")

            $desktop = "C:\\Users\\Administrator\\Desktop"

            # Create desktop shortcuts
            Remove-Item -path "$desktop\\*.website"

            # Change password
            $password = ((Get-SECSecretValue -SecretId '${localAdminPassword.secretArn}').SecretString | ConvertFrom-Json).Password
            net.exe user Administrator "$password"

            # Associate EIP
            $instanceId = Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/instance-id
            Register-EC2Address -InstanceId "$instanceId" -AllocationId "${eip.attrAllocationId}"

            # Signal success to CFN
            cfn-signal.exe --success true --region "${cdk.Aws.REGION}" "${waitHandle.ref}"


            # Download artifacts
            New-Item -Path "$desktop" -Name "workshop-resources" -ItemType "directory"

            # Wait until build pipelines have successfully build all artifacts
            Wait-CFNStack -StackName "${cdk.Aws.STACK_NAME}" -Timeout 1800

            Copy-S3Object -BucketName "${props.bucket.bucketName}" -KeyPrefix target -LocalFolder "$desktop\\workshop-resources"
          </powershell>`.split('\n').map(line => line.trimLeft()).join('\n')
        )
      }
    });

    waitCondition.addDependsOn(launchTemplate);


    this.autoscaling = new autoscaling.CfnAutoScalingGroup(this, 'AutoScalingGroup', {
      mixedInstancesPolicy: {
        launchTemplate: {
          launchTemplateSpecification: {
            launchTemplateId: launchTemplate.ref,
            version: launchTemplate.attrDefaultVersionNumber
          },
          overrides: [
            {instanceType: 'm5.2xlarge'},
            {instanceType: 'c5.2xlarge'},
            {instanceType: 'm3.2xlarge'},
            {instanceType: 'm5.xlarge'},
            {instanceType: 'c5.xlarge'},
            {instanceType: 'm4.xlarge'},
            {instanceType: 'c4.xlarge'}
           ]
        },
        instancesDistribution: {
          onDemandBaseCapacity: 1
        }
      },
      maxSize: '1',
      minSize: '1',
      desiredCapacity: '1',
      vpcZoneIdentifier: props.vpc.publicSubnets.map(subnet => subnet.subnetId)
    });

    new cdk.CfnOutput(scope, 'DevEnvironmentIp', { value: eip.ref });
    new cdk.CfnOutput(scope, 'DevEnvironmentCredentials', { value: `https://console.aws.amazon.com/secretsmanager/#!/secret?name=${localAdminPassword.secretArn}` });    
  }