in src/AWS.Deploy.Orchestration/CdkProjectHandler.cs [110:183]
public async Task DeployCdkProject(OrchestratorSession session, CloudApplication cloudApplication, string cdkProjectPath, Recommendation recommendation)
{
var recipeInfo = $"{recommendation.Recipe.Id}_{recommendation.Recipe.Version}";
var environmentVariables = new Dictionary<string, string>
{
{ EnvironmentVariableKeys.AWS_EXECUTION_ENV, recipeInfo }
};
var appSettingsFilePath = Path.Combine(cdkProjectPath, "appsettings.json");
if (await DetermineIfCDKBootstrapShouldRun())
{
// Ensure region is bootstrapped
var cdkBootstrap = await _commandLineWrapper.TryRunWithResult($"npx cdk bootstrap aws://{session.AWSAccountId}/{session.AWSRegion} --template \"{_workspaceMetadata.CDKBootstrapTemplatePath}\"",
workingDirectory: _workspaceMetadata.DeployToolWorkspaceDirectoryRoot,
needAwsCredentials: true,
redirectIO: true,
streamOutputToInteractiveService: true);
if (cdkBootstrap.ExitCode != 0)
throw new FailedToDeployCDKAppException(DeployToolErrorCode.FailedToRunCDKBootstrap, "The AWS CDK Bootstrap, which is the process of provisioning initial resources for the deployment environment, has failed. Please review the output above for additional details [and check out our troubleshooting guide for the most common failure reasons]. You can learn more about CDK bootstrapping at https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html.", cdkBootstrap.ExitCode);
}
else
{
_interactiveService.LogInfoMessage("Confirmed CDK Bootstrap CloudFormation stack already exists.");
}
_interactiveService.LogSectionStart("Deploying AWS CDK project",
"Use the CDK project to create or update the AWS CloudFormation stack and deploy the project to the AWS resources in the stack.");
// Handover to CDK command line tool
// Use a CDK Context parameter to specify the settings file that has been serialized.
var cdkDeployTask = _commandLineWrapper.TryRunWithResult( $"npx cdk deploy --require-approval never -c {Constants.CloudFormationIdentifier.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\"",
workingDirectory: cdkProjectPath,
environmentVariables: environmentVariables,
needAwsCredentials: true,
redirectIO: true,
streamOutputToInteractiveService: true);
var cancellationTokenSource = new CancellationTokenSource();
var retrieveStackIdTask = RetrieveStackId(cloudApplication, cancellationTokenSource.Token);
var deploymentStartDate = DateTime.UtcNow;
var firstCompletedTask = await Task.WhenAny(cdkDeployTask, retrieveStackIdTask);
// Deployment end date is captured at this point after 1 of the 2 running tasks yields.
var deploymentEndDate = DateTime.UtcNow;
TryRunResult? cdkDeploy = null;
if (firstCompletedTask == retrieveStackIdTask)
{
// If retrieveStackIdTask completes first, that means a stack was created and exists in CloudFormation.
// We can proceed with checking for deployment failures.
var stackId = cloudApplication.Name;
if (!retrieveStackIdTask.IsFaulted)
stackId = retrieveStackIdTask.Result;
cdkDeploy = await cdkDeployTask;
// We recapture the deployment end date at this point after the deployment task completes.
deploymentEndDate = DateTime.UtcNow;
await CheckCdkDeploymentFailure(stackId, deploymentStartDate, deploymentEndDate, cdkDeploy);
}
else
{
// If cdkDeployTask completes first, that means 'cdk deploy' failed before creating a stack in CloudFormation.
// In this case, we skip checking for deployment failures since a stack does not exist.
cdkDeploy = cdkDeployTask.Result;
cancellationTokenSource.Cancel();
}
var deploymentTotalTime = Math.Round((deploymentEndDate - deploymentStartDate).TotalSeconds, 2);
if (cdkDeploy.ExitCode != 0)
throw new FailedToDeployCDKAppException(DeployToolErrorCode.FailedToDeployCdkApplication, $"We had an issue deploying your application to AWS. Check the deployment output for more details. Deployment took {deploymentTotalTime}s.", cdkDeploy.ExitCode);
}