Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade CDK to v2 #1452

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion common/config/rush/common-versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
* This design avoids unnecessary churn in this file.
*/
"allowedAlternativeVersions": {
"constructs": ["^3.3.69"]
/**
* For example, allow some projects to use an older TypeScript compiler
* (in addition to whatever "usual" version is being used by other projects in the repo):
Expand Down
1,509 changes: 130 additions & 1,379 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/framework-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@boostercloud/framework-provider-azure": "workspace:^1.19.1",
"@boostercloud/framework-provider-local": "workspace:^1.19.1",
"@boostercloud/framework-types": "workspace:^1.19.1",
"aws-sdk": "2.853.0",
"aws-sdk": "2.1475.0",
"graphql": "^16.6.0",
"tslib": "^2.4.0",
"@effect-ts/core": "^0.60.4",
Expand Down Expand Up @@ -48,7 +48,7 @@
"cdktf-cli": "^0.14.3",
"ink": "^3.0.5",
"react": "^17.0.0",
"constructs": "^10.0.0",
"constructs": "^10.3.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"child-process-promise": "^2.2.1",
Expand Down
33 changes: 9 additions & 24 deletions packages/framework-provider-aws-infrastructure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,20 @@
"node": ">=18.0.0 <19.0.0"
},
"dependencies": {
"@aws-cdk/aws-apigateway": "^1.170.0",
"@aws-cdk/aws-logs": "^1.170.0",
"@aws-cdk/assets": "^1.170.0",
"@aws-cdk/aws-apigatewayv2": "^1.170.0",
"@aws-cdk/cloudformation-diff": "^1.170.0",
"@aws-cdk/aws-cloudfront": "^1.170.0",
"@aws-cdk/custom-resources": "^1.170.0",
"@aws-cdk/aws-dynamodb": "^1.170.0",
"@aws-cdk/aws-events": "^1.170.0",
"@aws-cdk/aws-events-targets": "^1.170.0",
"@aws-cdk/aws-iam": "^1.170.0",
"@aws-cdk/aws-lambda": "^1.170.0",
"@aws-cdk/aws-lambda-event-sources": "^1.170.0",
"@aws-cdk/aws-s3": "^1.170.0",
"@aws-cdk/aws-s3-deployment": "^1.170.0",
"@aws-cdk/core": "^1.170.0",
"@aws-cdk/cx-api": "^1.170.0",
"@boostercloud/framework-common-helpers": "workspace:^1.19.1",
"@boostercloud/framework-provider-aws": "workspace:^1.19.1",
"@boostercloud/framework-types": "workspace:^1.19.1",
"constructs": "^3.3.69",
"aws-cdk": "^1.170.0",
"aws-sdk": "2.853.0",
"constructs": "^10.3.0",
"aws-cdk-lib": "^2.101.1",
"aws-sdk": "2.1475.0",
"colors": "^1.4.0",
"tslib": "^2.4.0",
"promptly": "~3.2.0",
"cdk-assets": "~2.39.1",
"cdk-assets": "~2.101.1",
"@effect-ts/core": "^0.60.4",
"yaml": "1.10.2",
"archiver": "5.3.0"
"archiver": "5.3.0",
"child-process-promise": "^2.2.1"
},
"scripts": {
"format": "prettier --write --ext '.js,.ts' **/*.ts **/*/*.ts",
Expand All @@ -62,7 +46,7 @@
"clean": "rimraf ./dist tsconfig.tsbuildinfo",
"prepack": "tsc -b tsconfig.json",
"test:provider-aws-infrastructure": "npm run test",
"test": ""
"test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\""
},
"bugs": {
"url": "https://github.com/boostercloud/booster/issues"
Expand Down Expand Up @@ -99,7 +83,8 @@
"ts-node": "^10.9.1",
"typescript": "4.7.4",
"velocityjs": "^2.0.0",
"eslint-plugin-unicorn": "~44.0.2"
"eslint-plugin-unicorn": "~44.0.2",
"@types/child-process-promise": "^2.2.1"
},
"pnpm": {
"overrides": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
import { RequireApproval } from 'aws-cdk/lib/diff'
import { Bootstrapper } from 'aws-cdk'
import { BoosterConfig } from '@boostercloud/framework-types'
import { getLogger } from '@boostercloud/framework-common-helpers'
import { EnvironmentUtils } from '@aws-cdk/cx-api'
import {
getStackNames,
getStackServiceConfiguration,
getStackToolkitBucketName,
getStackToolkitName,
} from './stack-tools'
import { getStackToolkitBucketName, getStackToolkitName } from './stack-tools'
import { InfrastructureRocket } from '../rockets/infrastructure-rocket'
import { exec } from 'child-process-promise'
import { App } from 'aws-cdk-lib'
import { ApplicationStack } from './stacks/application-stack'

/**
* Deploys the application using the credentials located in ~/.aws
*/
export async function deploy(config: BoosterConfig, rockets?: InfrastructureRocket[]): Promise<void> {
const logger = getLogger(config, 'deploy')
const { environment: env, cdkToolkit } = await getStackServiceConfiguration(config, rockets)
const toolkitStackName = getStackToolkitName(config)
const logger = getLogger(config, 'aws-deploy#deploy')

const boosterApp = new App()
const stack = new ApplicationStack(config, boosterApp, rockets)

logger.info('Bootstraping the following environment: ' + JSON.stringify(env))
await cdkToolkit.bootstrap(
[EnvironmentUtils.format(env.account, env.region)],
new Bootstrapper({ source: 'legacy' }),
{
toolkitStackName,
parameters: {
bucketName: getStackToolkitBucketName(config),
},
terminationProtection: false,
}
)
await bootstrapEnvironment(config, stack)

logger.info(`Deploying ${config.appName} on environment ${config.environmentName}`)
await cdkToolkit.deploy({
toolkitStackName,
selector: { patterns: getStackNames(config) },
requireApproval: RequireApproval.Never,
})
boosterApp.synth()
}

/**
* Bootstraps the AWS environment using the CDK v2 CLI.
*/
async function bootstrapEnvironment(config: BoosterConfig, stack: ApplicationStack): Promise<void> {
const logger = getLogger(config, 'aws-deploy#bootstrap')
const toolkitStackName = getStackToolkitName(config)
const toolkitBucketName = getStackToolkitBucketName(config)

logger.info(`Bootstrapping environment ${config.environmentName}...`)
const bootstrapCommand =
`cdk bootstrap aws://${stack.account}/${stack.region} ` +
`--toolkit-stack-name ${toolkitStackName} ` +
`--bootstrap-bucket-name ${toolkitBucketName}`

const bootstrapResult = await exec(bootstrapCommand)
logger.info(`Bootstrap output: ${bootstrapResult.stdout}`)
}
Original file line number Diff line number Diff line change
@@ -1,66 +1,57 @@
import { BoosterConfig } from '@boostercloud/framework-types'
import { getLogger } from '@boostercloud/framework-common-helpers'
import { ISDK } from 'aws-cdk'
import { emptyS3Bucket } from './s3utils'
import * as colors from 'colors'
import {
getStackNames,
getStackServiceConfiguration,
getStackToolkitBucketName,
getStackToolkitName,
} from './stack-tools'
import { CdkToolkit } from 'aws-cdk/lib/cdk-toolkit'
import { getStackNames, getStackToolkitBucketName, getStackToolkitName } from './stack-tools'
import { InfrastructureRocket } from '../rockets/infrastructure-rocket'
import { buildRocketUtils } from '../rockets/rocket-utils'
import { exec } from 'child-process-promise'

/**
* Nuke all the resources used in the "AppStacks"
*/
export async function nuke(config: BoosterConfig, rockets?: InfrastructureRocket[]): Promise<void> {
const logger = getLogger(config, 'nuke')
logger.info(colors.yellow('Destroying application') + ' ' + colors.blue(config.appName))
const { sdk, cdkToolkit } = await getStackServiceConfiguration(config, [])

await nukeToolkit(config, sdk)
if (rockets) await nukeRockets(config, sdk, rockets)
await nukeApplication(config, cdkToolkit)
await nukeToolkit(config)
if (rockets) await nukeRockets(config, rockets)
await nukeApplication(config)
logger.info('✅ ' + colors.blue(config.appName) + colors.red(': DESTROYED'))
}

/**
* Nuke all the resources used in the "Toolkit Stack"
*/
async function nukeToolkit(config: BoosterConfig, sdk: ISDK): Promise<void> {
async function nukeToolkit(config: BoosterConfig): Promise<void> {
const logger = getLogger(config, 'nuke#nukeToolkit')
const stackToolkitName = getStackToolkitName(config)
logger.info(colors.blue(stackToolkitName) + colors.yellow(': destroying...'))
await emptyS3Bucket(config, sdk, getStackToolkitBucketName(config))
await emptyS3Bucket(config, getStackToolkitBucketName(config))

await sdk.cloudFormation().deleteStack({ StackName: stackToolkitName }).promise()
await exec(`npx cdk destroy ${stackToolkitName} -f`)
logger.info('✅ ' + colors.blue(stackToolkitName) + colors.red(': DESTROYED'))
}

/**
* Calls to the rockets unmount method to allow them remove any resources that can't be automatically deleted by the stack (like non-empty S3 buckets)
*/
async function nukeRockets(config: BoosterConfig, sdk: ISDK, rockets: InfrastructureRocket[]): Promise<void> {
async function nukeRockets(config: BoosterConfig, rockets: InfrastructureRocket[]): Promise<void> {
const logger = getLogger(config, 'nuke#nukeRockets')
logger.info('Deleting rockets resources...')
const rocketUtils = buildRocketUtils(config, sdk)
const rocketUtils = buildRocketUtils(config)
rockets.forEach((rocket) => rocket.unmountStack?.(rocketUtils))
}

/**
* Nuke the application resources
*/
async function nukeApplication(config: BoosterConfig, cdkToolkit: CdkToolkit): Promise<void> {
async function nukeApplication(config: BoosterConfig): Promise<void> {
const logger = getLogger(config, 'nuke#nukeApplication')
logger.info('Destroying the application stack...')
await cdkToolkit.destroy({
selector: {
patterns: getStackNames(config),
},
exclusively: false,
force: true,
})

const stackNames = getStackNames(config).join(' ')

await exec(`npx cdk destroy ${stackNames} -f`)
logger.info('✅ ' + colors.blue(config.appName) + colors.red(': DESTROYED'))
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-magic-numbers */
import { Duration, Stack } from '@aws-cdk/core'
import { FunctionProps, Runtime, StartingPosition } from '@aws-cdk/aws-lambda'
import { Duration, Stack } from 'aws-cdk-lib'
import { FunctionProps, Runtime, StartingPosition } from 'aws-cdk-lib/aws-lambda'
import { BoosterConfig } from '@boostercloud/framework-types'
import { RestApi } from '@aws-cdk/aws-apigateway'
import { CfnApi } from '@aws-cdk/aws-apigatewayv2'
import { RestApi } from 'aws-cdk-lib/aws-apigateway'
import { CfnApi } from 'aws-cdk-lib/aws-apigatewayv2'
import { environmentVarNames } from '@boostercloud/framework-provider-aws'
import { DynamoEventSourceProps } from '@aws-cdk/aws-lambda-event-sources'
import { DynamoEventSourceProps } from 'aws-cdk-lib/aws-lambda-event-sources'

export interface APIs {
restAPI: RestApi
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ISDK } from 'aws-cdk'
import { ObjectIdentifier, ObjectIdentifierList } from 'aws-sdk/clients/s3'
import * as AWS from 'aws-sdk'
import { BoosterConfig } from '@boostercloud/framework-types'
import { getLogger } from '@boostercloud/framework-common-helpers'

export async function emptyS3Bucket(config: BoosterConfig, sdk: ISDK, bucketName: string): Promise<void> {
export async function emptyS3Bucket(config: BoosterConfig, bucketName: string): Promise<void> {
const logger = getLogger(config, 's3utils#emptyS3Bucket')
logger.info(bucketName + ': DELETE_IN_PROGRESS')
const s3: AWS.S3 = await sdk.s3()
const s3 = new AWS.S3()

if (await s3BucketExists(bucketName, s3)) {
const listedObjects = await s3.listObjectVersions({ Bucket: bucketName }).promise()
Expand All @@ -21,7 +20,7 @@ export async function emptyS3Bucket(config: BoosterConfig, sdk: ISDK, bucketName
} as ObjectIdentifier)
)
await s3.deleteObjects({ Bucket: bucketName, Delete: { Objects: records } }).promise()
if (listedObjects.IsTruncated) await emptyS3Bucket(config, sdk, bucketName)
if (listedObjects.IsTruncated) await emptyS3Bucket(config, bucketName)
}
logger.info(bucketName + ': DELETE_COMPLETE')
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,4 @@
import { ISDK, Mode, SdkProvider } from 'aws-cdk'
import { CdkToolkit } from 'aws-cdk/lib/cdk-toolkit'
import { BoosterConfig } from '@boostercloud/framework-types'
import { App } from '@aws-cdk/core'
import { ApplicationStackBuilder } from './stacks/application-stack'
import { CloudAssembly, Environment } from '@aws-cdk/cx-api'
import { InfrastructureRocket } from '../rockets/infrastructure-rocket'
import { Configuration } from 'aws-cdk/lib/settings'
import { CloudExecutable } from 'aws-cdk/lib/api/cxapp/cloud-executable'
import { CloudFormationDeployments } from 'aws-cdk/lib/api/cloudformation-deployments'

interface StackServiceConfiguration {
sdk: ISDK
environment: Environment
cdkToolkit: CdkToolkit
}

function assemble(config: BoosterConfig, rockets?: InfrastructureRocket[]): CloudAssembly {
const boosterApp = new App()
new ApplicationStackBuilder(config).buildOn(boosterApp, rockets)
// Here we could add other optional stacks like one with a lot of dashboards for analytics, etc.

return boosterApp.synth()
}

export function getStackNames(config: BoosterConfig): Array<string> {
return [config.resourceNames.applicationStack]
Expand All @@ -34,53 +11,3 @@ export function getStackToolkitName(config: BoosterConfig): string {
export function getStackToolkitBucketName(config: BoosterConfig): string {
return config.appName + '-toolkit-bucket'
}

async function getEnvironment(sdkProvider: SdkProvider): Promise<Environment> {
const account = await sdkProvider.defaultAccount()
const region = sdkProvider.defaultRegion

if (!account) {
throw new Error(
'Unable to load default AWS account. Check that you have properly set your AWS credentials in `~/.aws/credentials` file or the corresponding environment variables. Refer to AWS documentation for more details https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html'
)
}
if (!region) {
throw new Error(
'Unable to determine default region. Check that you have set it in your `~/.aws/config` file or AWS_REGION environment variable. Refer to AWS documentation for more details https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-region.html#setting-region-order-of-precedence'
)
}

return {
name: 'Default environment',
account: account.accountId,
region,
}
}

// Configure the SDK and CDKToolkit that contains all the information
// about the application we want to deploy
export async function getStackServiceConfiguration(
config: BoosterConfig,
rockets?: InfrastructureRocket[]
): Promise<StackServiceConfiguration> {
const sdkProvider = await SdkProvider.withAwsCliCompatibleDefaults()
const environment = await getEnvironment(sdkProvider)
const { sdk } = await sdkProvider.forEnvironment(environment, Mode.ForWriting)
const configuration = await new Configuration().load()
const cloudExecutable = new CloudExecutable({
configuration,
sdkProvider,
synthesizer: async (): Promise<CloudAssembly> => assemble(config, rockets),
})
const cdkToolkit = new CdkToolkit({
sdkProvider,
cloudExecutable,
cloudFormation: new CloudFormationDeployments({ sdkProvider }),
configuration,
})
return {
sdk,
environment,
cdkToolkit,
}
}
Loading