in iot-onboarding-code-pipelines/lib/iot-onboarding-code-pipelines-stack.ts [13:343]
constructor(scope: cdk.Construct, id: string, props?: StackProps) {
super(scope, id, props);
const {
region,
} = new ScopedAws(this)
//const gitHubRepo = "aws-quickstart/quickstart-iot-device-connectivity"
const gitHubRepo = "quickstart-iot-device-connectivity"
//CloudFormatiion Input Parmetters to be provided by end user:
const contactEmail = new CfnParameter(this, "contactEmail", {
type: "String",
allowedPattern: "^([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\.([a-zA-Z]{2,5})$",
description: "Email address for the administrator. This is also used for the IoT Sitewise portal creation."
});
const quickSightAdminUserName = new CfnParameter(this, "quickSightAdminUserName", {
type: "String",
description: "(Optional) Username of an Amazon QuickSight user with an Admin role. If left blank, the QuickSight dashboard will not be included"
});
const quickSightAdminUserRegion = new CfnParameter(this, "quickSightAdminUserRegion", {
type: "String",
description: "The region of the above QuickSight user. E.g.: us-east-1"
});
const sourceTemplateArn = new CfnParameter(this, "sourceTemplateArn", {
type: "String",
description: "(Optional) ARN of a public QuickSight dashboard. If using Rigado Alegro kit use arn:aws:quicksight:eu-central-1:660526416360:template/iotOnboardingRigadoQuicksightPublicTemplatedev for an example dashboard."
});
const rootMqttTopic = new CfnParameter(this, "rootMqttTopic", {
type: "String",
allowedPattern: ".+",
default: "data/#",
description: "The root MQTT topic to which devices publish data. Leave the default (data/#) if using the Rigado Alegro kit. If using your own devices, you can create your own dataset, analysis and dashboard based on your devices."
});
const envNameVal = new CfnParameter(this, "environment", {
type: "String",
allowedPattern: ".+",
default: "int",
description: "Your environment name. Change to a unique name only if deploy the stack multiple times in the same region and account."
});
const gitHubUserName = new CfnParameter(this, "gitHubUserName", {
type: "String",
allowedPattern: ".+",
description: "Your github user name (see pre-deployment steps)"
});
const githubtoken = new CfnParameter(this, "githubtoken", {
type: "String",
allowedPattern: ".+",
description: "Your github Personal access tokens allowing access to the forked repository (see pre-deployment steps)"
});
const artifactBucket = new Bucket(this, "iotOnboardingArtifacts", {
removalPolicy: RemovalPolicy.DESTROY,
versioned: true
})
//TODO: provide a more granular access to the code build pipeline
const buildProjectRole = new Role(this, 'buildRole', {
assumedBy: new ServicePrincipal('codebuild.amazonaws.com'),
managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess")]
})
const infraBuild = new codebuild.PipelineProject(this, 'infraBuilProject', {
projectName: "code-build-iot-onboarding-infra-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
install: {
"runtime-versions": {
nodejs: 10
},
commands: [
'echo "CodeBuild is running in $AWS_REGION" && aws configure set region $AWS_REGION',
'npm install -g aws-cdk@1.139.0',
'npm -g install typescript@4.2.2',
'cdk --version',
'cd iot-onboarding-infra',
'npm install'
]
},
build: {
commands: [
'echo "Build and Deploy Infrastructure"',
'pwd && sh deploy.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName + " " + rootMqttTopic.valueAsString + " " + contactEmail.valueAsString
],
},
},
artifacts: {
"discard-path": "yes",
files: [
'iot-onboarding-infra/infra-config-' + envNameVal.valueAsString + '.json',
],
},
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
const lambdaBuild = new codebuild.PipelineProject(this, 'lambdaBuilProject', {
projectName: "code-build-iot-onboarding-lambda-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
install: {
"runtime-versions": {
golang: 1.13
}
},
build: {
commands: [
'echo "Build and Deploy lambda Function"',
'cd iot-onboarding-service',
'pwd && sh lbuild.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName
],
},
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
const glueEtlBuild = new codebuild.PipelineProject(this, 'glueETLBuilProject', {
projectName: "code-build-iot-onboarding-etl-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'echo "Uploading ETK script to s3"',
'cd iot-onboarding-data-processing',
'pwd && sh ./deploy.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName
],
},
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
const siteWiseBuild = new codebuild.PipelineProject(this, 'siteWiseBuildProject', {
projectName: "code-build-iot-onboarding-sitewise-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'echo "Building sitewise Assets model and project"',
'cd iot-onboarding-sitewise',
'pwd && sh ./sitewise.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName + " " + contactEmail.valueAsString
],
},
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
const quicksightBuild = new codebuild.PipelineProject(this, 'quicksightBuildProject', {
projectName: "code-build-iot-onboarding-quicksight-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'echo "Building Quicksight Dashboard"',
'cd iot-onboarding-quicksight',
'pwd && sh ./create-dashboard.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName + " " + quickSightAdminUserName.valueAsString + " " + sourceTemplateArn.valueAsString + " " + quickSightAdminUserRegion.valueAsString
],
},
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
const onboardingTest = new codebuild.PipelineProject(this, 'testProject', {
projectName: "code-build-iot-onboarding-test-" + envNameVal.valueAsString,
role: buildProjectRole,
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
install: {
"runtime-versions": {
nodejs: 10
},
commands: [
"yum -y install epel-release",
"yum -y install mosquitto",
"npm install -g newman@5.2.2"
]
},
build: {
commands: [
'echo "Testing Deployed on boarding service"',
'cd e2e',
'pwd && sh ./test.sh ' + envNameVal.valueAsString + " " + artifactBucket.bucketName
],
},
}
}),
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
},
});
//Output Artifacts
const sourceOutput = new codepipeline.Artifact();
const cdkBuildOutputLambda = new codepipeline.Artifact('CdkBuildOutputLambda');
const cdkBuildOutputETL = new codepipeline.Artifact('CdkBuildOutputETL');
const cdkBuildOutputInfra = new codepipeline.Artifact('CdkBuildOutputInfra');
const cdkBuildOutputTest = new codepipeline.Artifact('CdkBuildOutputTest');
const siteWiseOutput = new codepipeline.Artifact('siteWiseOutput');
const quickSightOutput = new codepipeline.Artifact('quickSightOutput');
const sourceBucker = Bucket.fromBucketAttributes(this, 'iotQuickstartSourceBucket', {
bucketName: "aws-quickstart-" + region
});
let stages: codepipeline.StageProps[] = []
//Source stage
stages.push({
stageName: 'Source',
actions: [
new codepipeline_actions.GitHubSourceAction({
actionName: 'GitHub_Source',
repo: gitHubRepo,
oauthToken: SecretValue.plainText(githubtoken.valueAsString),
branch: "main",
owner: gitHubUserName.valueAsString,
output: sourceOutput,
}),
],
})
//Build stage
stages.push({
stageName: 'Build',
actions: [
new codepipeline_actions.CodeBuildAction({
actionName: 'uploadELTScript',
project: glueEtlBuild,
input: sourceOutput,
runOrder: 1,
outputs: [cdkBuildOutputETL],
}),
new codepipeline_actions.CodeBuildAction({
actionName: 'buildLambdaCode',
project: lambdaBuild,
input: sourceOutput,
runOrder: 2,
outputs: [cdkBuildOutputLambda],
}),
new codepipeline_actions.CodeBuildAction({
actionName: 'deployInfra',
project: infraBuild,
input: sourceOutput,
runOrder: 3,
outputs: [cdkBuildOutputInfra],
}),
],
})
//Test Stage
stages.push({
stageName: 'Test',
actions: [
new codepipeline_actions.CodeBuildAction({
actionName: 'testOnboardingService',
project: onboardingTest,
input: sourceOutput,
outputs: [cdkBuildOutputTest],
}),
],
})
//Deploy Stages
let deployStage: codepipeline.StageProps = {
stageName: 'Deploy',
actions: [],
}
if (deployStage.actions) {
deployStage.actions.push(new codepipeline_actions.S3DeployAction({
actionName: "deployInfraConfigToS3",
bucket: artifactBucket,
runOrder: 1,
input: cdkBuildOutputInfra
}))
//QuickSight dashboard is conditionally added if a Quicksight admin user is provided
if (quickSightAdminUserName.valueAsString) {
deployStage.actions.push(new codepipeline_actions.CodeBuildAction({
actionName: 'setupQuicksight',
project: quicksightBuild,
input: sourceOutput,
runOrder: 2,
outputs: [quickSightOutput],
}))
}
deployStage.actions.push(new codepipeline_actions.CodeBuildAction({
actionName: 'setupSitewise',
project: siteWiseBuild,
input: sourceOutput,
runOrder: 2,
outputs: [siteWiseOutput],
}))
}
stages.push(deployStage)
//creating a dedicated bucker to avoid erroor with Key generated with identical id
const pipelineArtifactBucket = new Bucket(this, "iotOnboardingPipelineArtifacts", {
removalPolicy: RemovalPolicy.DESTROY,
versioned: true
})
new codepipeline.Pipeline(this, 'IotOnboardingPipeline', {
pipelineName: "code-pipeline-iot-onboarding-" + envNameVal.valueAsString,
stages: stages,
artifactBucket: pipelineArtifactBucket
});
}