constructor()

in v2/etl_simple/cdk/lib/EtlSimpleStack.ts [19:189]


  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    if (cdk.Stack.of(this).stackName.length > 20) {
      console.error("Stack name must be less than 20 characters in length")
      process.exitCode = 1
    }
    const parentStack = this.node.tryGetContext("baseStack")
    if (parentStack === undefined) {
      console.error('Parent stack must be provided with --context baseStack="gg-accel-base" argument for "cdk deploy" or "cdk destroy"')
      process.exitCode = 1
    }

    // suffix to use for all stack resources to make unique
    // In this stack all resources will use the format STACKNAME-RESOURCENAME-RANDOMSUFFIX
    const stackRandom: string = makeid(8, parentStack)

    // Load parameters from parent stack
    const thingArn = cdk.Fn.importValue(`${parentStack}-ThingArn`)
    const thingName = cdk.Fn.importValue(`${parentStack}-ThingName`)
    const certificateArn = cdk.Fn.importValue(`${parentStack}-CertificateArn`)
    const iamRoleArn = cdk.Fn.importValue(`${parentStack}-IamRoleArn`)
    const componentBucketArn = cdk.Fn.importValue(`${parentStack}-ComponentBucketArn`)

    // Layered constructs - each constructs derived values can be used for subsequent constructs

    // Create IoT policy and attach to certificate
    const etlSimplePolicyName = fullResourceName({
      stackName: cdk.Stack.of(this).stackName,
      baseName: "gg-accel-etl-simple",
      suffix: stackRandom,
      resourceRegex: "\\w+=,.@-",
      maxLength: 128
    })
    const iotPolicy = new IotPolicy(this, "EtlSimpleIotPolicy", {
      iotPolicyName: etlSimplePolicyName,
      iotPolicy: myConst.etlSimpleIoTPolicy,
      certificateArn: certificateArn,
      policyParameterMapping: {
        thingname: thingName,
        region: cdk.Fn.ref("AWS::Region"),
        account: cdk.Fn.ref("AWS::AccountId")
      }
    })
    // Add an inline policy to the IAM role used by the IoT role alias
    const etlSimpleInlinePolicy = new iam.Policy(this, "EtlSimplePolicy", {
      policyName: "EtlSimpleAccelerator",
      statements: [
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams"],
          resources: ["arn:aws:logs:*:*:*"]
        })
      ]
    })
    const sourceRole = iam.Role.fromRoleArn(this, "BaseRole", iamRoleArn, {
      mutable: true
    })
    sourceRole.attachInlinePolicy(etlSimpleInlinePolicy)

    // Define stack-specific name of the IoT thing group
    const groupName = fullResourceName({
      stackName: cdk.Stack.of(this).stackName,
      baseName: "deployment-group-etl",
      suffix: stackRandom,
      resourceRegex: "a-zA-Z0-9:_-",
      maxLength: 128
    })
    // Create thing group as deployment target and add the thing
    const deploymentGroup = new IotThingGroup(this, "DeploymentGroupEtl", {
      thingGroupName: groupName
    })
    deploymentGroup.addThing(thingArn)

    // Create component(s) for accelerator

    // Reference the base stack's component bucket
    const componentBucket = s3.Bucket.fromBucketArn(this, "ComponentBucket", componentBucketArn)

    // Create ETL Simple components
    // uses same component file name and path as AWS published components,
    // see the source recipe file for more details
    const etlSimpleExtractComponentName = "ggAccel.etl_simple.extract"
    const etlSimpleExtractComponentVersion = "1.0.0"
    const etlSimpleExtractComponent = new GreengrassV2Component(this, "EtlSimpleExtractComponent", {
      componentName: etlSimpleExtractComponentName,
      componentVersion: etlSimpleExtractComponentVersion,
      bucket: componentBucket,
      artifactZipPrefix: `${etlSimpleExtractComponentName}/${etlSimpleExtractComponentVersion}/`,
      targetArtifactKeyName: `${etlSimpleExtractComponentName}.zip`,
      sourceArtifactPath: path.join(__dirname, "..", "components", etlSimpleExtractComponentName, "artifacts", etlSimpleExtractComponentName, etlSimpleExtractComponentVersion),
      sourceRecipeFile: path.join(__dirname, "..", "components", etlSimpleExtractComponentName, `${etlSimpleExtractComponentName}-${etlSimpleExtractComponentVersion}.json`)
    })
    
    const etlSimpleTransformComponentName = "ggAccel.etl_simple.transform"
    const etlSimpleTransformComponentVersion = "1.0.0"
    const etlSimpleTransformComponent = new GreengrassV2Component(this, "EtlSimpleTransformComponent", {
      componentName: etlSimpleTransformComponentName,
      componentVersion: etlSimpleTransformComponentVersion,
      bucket: componentBucket,
      artifactZipPrefix: `${etlSimpleTransformComponentName}/${etlSimpleTransformComponentVersion}/`,
      targetArtifactKeyName: `${etlSimpleTransformComponentName}.zip`,
      sourceArtifactPath: path.join(__dirname, "..", "components", etlSimpleTransformComponentName, "artifacts", etlSimpleTransformComponentName, etlSimpleTransformComponentVersion),
      sourceRecipeFile: path.join(__dirname, "..", "components", etlSimpleTransformComponentName, `${etlSimpleTransformComponentName}-${etlSimpleTransformComponentVersion}.json`)
    })
    
    const etlSimpleLoadComponentName = "ggAccel.etl_simple.load"
    const etlSimpleLoadComponentVersion = "1.0.0"
    const etlSimpleLoadComponent = new GreengrassV2Component(this, "EtlSimpleLoadComponent", {
      componentName: etlSimpleLoadComponentName,
      componentVersion: etlSimpleLoadComponentVersion,
      bucket: componentBucket,
      artifactZipPrefix: `${etlSimpleLoadComponentName}/${etlSimpleLoadComponentVersion}/`,
      targetArtifactKeyName: `${etlSimpleLoadComponentName}.zip`,
      sourceArtifactPath: path.join(__dirname, "..", "components", etlSimpleLoadComponentName, "artifacts", etlSimpleLoadComponentName, etlSimpleLoadComponentVersion),
      sourceRecipeFile: path.join(__dirname, "..", "components", etlSimpleLoadComponentName, `${etlSimpleLoadComponentName}-${etlSimpleLoadComponentVersion}.json`)
    })

    // create deployment -- cancel deployment
    const greengrassDeployment = new GreengrassV2Deployment(this, "EtlSimpleDeployment", {
      targetArn: deploymentGroup.thingGroupArn,
      deploymentName: `${this.stackName} - extract transform load deployment`,
      component: {
        // accelerator component(s)
        [etlSimpleExtractComponent.componentName]: {
          componentVersion: etlSimpleExtractComponent.componentVersion
        },
        [etlSimpleTransformComponent.componentName]: {
          componentVersion: etlSimpleTransformComponent.componentVersion
        },
        [etlSimpleLoadComponent.componentName]: {
          componentVersion: etlSimpleLoadComponent.componentVersion
        }
      }
    })

    // Set stack outputs to be consumed by local processes
    new cdk.CfnOutput(this, "CloudPublishTopic", {
      value: `${thingName}/etl_simple/load`
    })

    // ************ End of CDK Constructs / stack - Supporting functions below ************

    function makeid(length: number, seed: string) {
      // Generate a n-length random value for each resource
      var result = ""
      var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
      var charactersLength = characters.length
      seedrandom(seed, { global: true })
      for (var i = 0; i < length; i++) {
        result += characters.charAt(Math.floor(Math.random() * charactersLength))
      }
      return result
    }

    interface ResourceName {
      stackName: string
      baseName: string
      suffix: string
      resourceRegex: string
      maxLength: number
    }

    function fullResourceName({ stackName, baseName, suffix, resourceRegex, maxLength }: ResourceName) {
      let re = new RegExp(`[^\\[${resourceRegex}]`, "g")
      let resourceName = `${stackName}-${baseName}`.replace(re, "")
      resourceName = resourceName.substring(0, maxLength - suffix.length - 1)
      resourceName = `${resourceName}-${suffix}`
      return resourceName
    }
  }