Skip to content
This repository has been archived by the owner on Feb 3, 2021. It is now read-only.

Commit

Permalink
feat: configure AWS IoT for just in time provisioning
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart committed Jul 18, 2019
1 parent a2629d7 commit 623b78b
Show file tree
Hide file tree
Showing 32 changed files with 13,285 additions and 5,087 deletions.
12 changes: 11 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"error"
],
"@typescript-eslint/no-type-alias": [
"error"
"off"
],
"@typescript-eslint/no-unnecessary-type-assertion": [
"error"
Expand Down Expand Up @@ -92,6 +92,16 @@
"requireLast": false
}
}
],
"@typescript-eslint/prefer-interface": [
"off"
],
"@typescript-eslint/consistent-type-definitions": [
"error",
"type"
],
"@typescript-eslint/no-explicit-any": [
"off"
]
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ npm-debug.log
.env
dist/
cdk.out/
certificates/
9 changes: 0 additions & 9 deletions cdk/BifravstApp.ts

This file was deleted.

17 changes: 17 additions & 0 deletions cdk/apps/Bifravst.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { App } from '@aws-cdk/core'
import { BifravstStack } from '../stacks/Bifravst'
import { LayeredLambdas } from '@nrfcloud/package-layered-lambdas'
import { BifravstLambdas } from '../cloudformation'

export class BifravstApp extends App {
public constructor(args: {
stackId: string
mqttEndpoint: string
sourceCodeBucketName: string
baseLayerZipFileName: string
lambdas: LayeredLambdas<BifravstLambdas>
}) {
super()
new BifravstStack(this, args.stackId, args)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as CloudFormation from '@aws-cdk/core'
import { BifravstContinuousDeploymentStack } from './BifravstContinuousDeploymentStack'
import { ContinuousDeploymentStack } from '../stacks/ContinuousDeployment'

export class BifravstContinuousDeploymentApp extends CloudFormation.App {
export class ContinuousDeploymentApp extends CloudFormation.App {
public constructor(props: {
stackId: string
bifravstStackId: string
Expand All @@ -16,6 +16,6 @@ export class BifravstContinuousDeploymentApp extends CloudFormation.App {
}) {
super()

new BifravstContinuousDeploymentStack(this, props.stackId, props)
new ContinuousDeploymentStack(this, props.stackId, props)
}
}
15 changes: 15 additions & 0 deletions cdk/apps/LambdaSourceCodeStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { App } from '@aws-cdk/core'
import { LambdaSourceCodeStorageStack } from '../stacks/LambdaSourceCodeStorage'

/**
* In order to deploy lambda functions written in TypeScript we need to publish
* the compiled source code to an S3 bucket.
* This app provides the bucket and run before the main app.
*/
export class LambdaSourceCodeStorageApp extends App {
public constructor(args: { stackId: string }) {
super()

new LambdaSourceCodeStorageStack(this, args.stackId)
}
}
4 changes: 2 additions & 2 deletions cdk/cloudformation-cd.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BifravstContinuousDeploymentApp } from './BifravstContinuousDeploymentApp'
import { ContinuousDeploymentApp } from './apps/ContinuousDeployment'
import { readFileSync } from 'fs'
import * as path from 'path'
import { extractRepoAndOwner } from './helper/extract-repo-and-owner'
Expand All @@ -9,7 +9,7 @@ const pjson = JSON.parse(
readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'),
)

new BifravstContinuousDeploymentApp({
new ContinuousDeploymentApp({
stackId: `${STACK_ID}-continuous-deployment`,
bifravstStackId: STACK_ID,
...extractRepoAndOwner(pjson.repository.url),
Expand Down
8 changes: 8 additions & 0 deletions cdk/cloudformation-sourcecode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LambdaSourceCodeStorageApp } from './apps/LambdaSourceCodeStorage'
import { stackId } from './stacks/LambdaSourceCodeStorage'

const STACK_ID = process.env.STACK_ID || 'bifravst'

new LambdaSourceCodeStorageApp({
stackId: stackId({ bifravstStackName: STACK_ID }),
}).synth()
46 changes: 45 additions & 1 deletion cdk/cloudformation.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { BifravstApp } from './BifravstApp'
import { BifravstApp } from './apps/Bifravst'
import { Iot } from 'aws-sdk'
import * as path from 'path'
import { promises as fs } from 'fs'
import { getLambdaSourceCodeBucketName } from './helper/getLambdaSourceCodeBucketName'
import {
packBaseLayer,
packLayeredLambdas,
WebpackMode,
} from '@nrfcloud/package-layered-lambdas'

const STACK_ID = process.env.STACK_ID || 'bifravst'

export type BifravstLambdas = {
createThingGroup: string
}

const main = async () => {
// Detect the AWS IoT endpoint
const { endpointAddress } = await new Iot({
region: process.env.AWS_DEFAULT_REGION,
})
Expand All @@ -14,9 +27,40 @@ const main = async () => {
throw new Error(`Failed to resolved AWS IoT endpoint`)
}

// Pack the lambdas
const rootDir = process.cwd()
const outDir = path.resolve(rootDir, 'dist', 'lambdas')
try {
await fs.stat(outDir)
} catch (_) {
await fs.mkdir(outDir)
}
const sourceCodeBucketName = await getLambdaSourceCodeBucketName({
bifravstStackName: STACK_ID,
})
const baseLayerZipFileName = await packBaseLayer({
srcDir: rootDir,
outDir,
Bucket: sourceCodeBucketName,
})
const lambdas = await packLayeredLambdas<BifravstLambdas>({
id: 'bifravst',
mode: WebpackMode.production,
srcDir: rootDir,
outDir,
Bucket: sourceCodeBucketName,
lambdas: {
createThingGroup: path.resolve(rootDir, 'cdk', 'createThingGroup.ts'),
},
tsConfig: path.resolve(rootDir, 'tsconfig.json'),
})

new BifravstApp({
stackId: STACK_ID,
mqttEndpoint: endpointAddress,
sourceCodeBucketName,
baseLayerZipFileName,
lambdas,
}).synth()
}

Expand Down
25 changes: 25 additions & 0 deletions cdk/createThingGroup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { Iot } = require('aws-sdk')
const response = require('cfn-response')
const iot = new Iot()
exports.handler = (event, context) => {
const { RequestType, ResourceProperties: { ThingGroupName, ThingGroupProperties, PolicyName } } = event
let p = Promise.resolve()
switch (RequestType) {
case 'Create':
p = iot
.createThingGroup({ thingGroupName: ThingGroupName, thingGroupProperties: ThingGroupProperties })
.promise()
.then(({ thingGroupArn }) => iot.attachPolicy({
policyName: PolicyName,
target: thingGroupArn,
}).promise())
break
}
p
.then(() => {
response.send(event, context, response.SUCCESS, { ThingGroupName }, false, ThingGroupName)
})
.catch(err => {
response.send(event, context, response.FAILED, { Error: `${err.message} (${err})` })
})
}
57 changes: 57 additions & 0 deletions cdk/createThingGroup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Iot } from 'aws-sdk'
import * as response from 'cfn-response'
import { Context, CloudFormationCustomResourceEvent } from 'aws-lambda'

const iot = new Iot()

export const handler = (
event: CloudFormationCustomResourceEvent,
context: Context,
) => {
const {
RequestType,
ResourceProperties: { ThingGroupName, ThingGroupProperties, PolicyName },
} = event
if (RequestType === 'Create') {
iot
.createThingGroup({
thingGroupName: ThingGroupName,
thingGroupProperties: ThingGroupProperties,
})
.promise()
.then(async ({ thingGroupArn }) => {
if (!thingGroupArn) {
throw new Error(`Failed to create thing group ${ThingGroupName}!`)
}
return iot
.attachPolicy({
policyName: PolicyName,
target: thingGroupArn,
})
.promise()
})
.then(() => {
response.send(
event,
context,
response.SUCCESS,
{ ThingGroupName },
ThingGroupName,
)
})
.catch(err => {
response.send(event, context, response.FAILED, {
Error: `${err.message} (${err})`,
})
})
} else {
console.log(`${RequestType} not supported.`)
response.send(
event,
context,
response.SUCCESS,
{ ThingGroupName },
ThingGroupName,
)
}
}
36 changes: 36 additions & 0 deletions cdk/helper/getLambdaSourceCodeBucketName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CloudFormation } from 'aws-sdk'
import { stackId } from '../stacks/LambdaSourceCodeStorage'

const cf = new CloudFormation({
region: process.env.AWS_DEFAULT_REGION,
})

export const getLambdaSourceCodeBucketName = async ({
bifravstStackName,
}: {
bifravstStackName: string
}): Promise<string> =>
cf
.describeStacks({
StackName: stackId({ bifravstStackName }),
})
.promise()
.then(({ Stacks }) => {
if (Stacks === undefined || !Stacks.length) {
throw new Error(
`${stackId({ bifravstStackName })} stack is not available.`,
)
} else {
const stack = Stacks[0]
const BucketOutput =
stack.Outputs &&
stack.Outputs.find(({ OutputKey }) => OutputKey === 'bucketName')
if (
BucketOutput === undefined ||
BucketOutput.OutputValue === undefined
) {
throw new Error(`${stackId({ bifravstStackName })} bucket not found.`)
}
return BucketOutput.OutputValue
}
})
Loading

0 comments on commit 623b78b

Please sign in to comment.