Skip to content

Commit

Permalink
Merge pull request #542 from aws/dev
Browse files Browse the repository at this point in the history
chore: release 0.43
  • Loading branch information
philasmar authored May 3, 2022
2 parents f2e5db5 + f3b7c28 commit 1344e9e
Show file tree
Hide file tree
Showing 25 changed files with 413 additions and 116 deletions.
1 change: 1 addition & 0 deletions THIRD_PARTY_LICENSES
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
** AWSSDK.Extensions.NETCore.Setup; version 3.7.1 -- https://www.nuget.org/packages/AWSSDK.Extensions.NETCore.Setup
** AWSSDK.IdentityManagement; version 3.7.2.25 -- https://www.nuget.org/packages/AWSSDK.IdentityManagement
** AWSSDK.SecurityToken; version 3.7.1.35 -- https://www.nuget.org/packages/AWSSDK.SecurityToken
** AWSSDK.SimpleSystemsManagement; version 3.7.16 -- https://www.nuget.org/packages/AWSSDK.SimpleSystemsManagement
** Constructs; version 10.0.0 -- https://www.nuget.org/packages/Constructs
** Amazon.CDK.Lib; version 2.13.0 -- https://www.nuget.org/packages/Amazon.CDK.Lib/
** Amazon.JSII.Runtime; version 1.54.0 -- https://www.nuget.org/packages/Amazon.JSII.Runtime
Expand Down
57 changes: 24 additions & 33 deletions src/AWS.Deploy.CLI/Commands/DeployCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -674,51 +674,42 @@ private bool ConfirmDeployment(Recommendation recommendation)

private async Task CreateDeploymentBundle(Orchestrator orchestrator, Recommendation selectedRecommendation, CloudApplication cloudApplication)
{
if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.Container)
try
{
_orchestratorInteractiveService.LogSectionStart("Creating deployment image",
"Using the docker CLI to perform a docker build to create a container image.");

while (!await orchestrator.CreateContainerDeploymentBundle(cloudApplication, selectedRecommendation))
await orchestrator.CreateDeploymentBundle(cloudApplication, selectedRecommendation);
}
catch(FailedToCreateDeploymentBundleException ex) when (ex.ErrorCode == DeployToolErrorCode.FailedToCreateContainerDeploymentBundle)
{
if (_toolInteractiveService.DisableInteractive)
{
if (_toolInteractiveService.DisableInteractive)
{
var errorMessage = "Failed to build Docker Image." + Environment.NewLine;
errorMessage += "Docker builds usually fail due to executing them from a working directory that is incompatible with the Dockerfile." + Environment.NewLine;
errorMessage += "Specify a valid Docker execution directory as part of the deployment settings file and try again.";
throw new DockerBuildFailedException(DeployToolErrorCode.DockerBuildFailed, errorMessage);
}
var errorMessage = "Failed to build Docker Image." + Environment.NewLine;
errorMessage += "Docker builds usually fail due to executing them from a working directory that is incompatible with the Dockerfile." + Environment.NewLine;
errorMessage += "Specify a valid Docker execution directory as part of the deployment settings file and try again.";
throw new DockerBuildFailedException(DeployToolErrorCode.DockerBuildFailed, errorMessage);
}

_toolInteractiveService.WriteLine(string.Empty);
var answer = _consoleUtilities.AskYesNoQuestion("Do you want to go back and modify the current configuration?", "false");
if (answer == YesNo.Yes)
_toolInteractiveService.WriteLine(string.Empty);
var answer = _consoleUtilities.AskYesNoQuestion("Do you want to go back and modify the current configuration?", "false");
if (answer == YesNo.Yes)
{
string dockerExecutionDirectory;
do
{
var dockerExecutionDirectory =
_consoleUtilities.AskUserForValue(
dockerExecutionDirectory = _consoleUtilities.AskUserForValue(
"Enter the docker execution directory where the docker build command will be executed from:",
selectedRecommendation.DeploymentBundle.DockerExecutionDirectory,
allowEmpty: true);

if (!_directoryManager.Exists(dockerExecutionDirectory))
continue;
{
_toolInteractiveService.WriteErrorLine($"Error, directory does not exist \"{dockerExecutionDirectory}\"");
}
} while (!_directoryManager.Exists(dockerExecutionDirectory));

selectedRecommendation.DeploymentBundle.DockerExecutionDirectory = dockerExecutionDirectory;
}
else
{
throw new FailedToCreateDeploymentBundleException(DeployToolErrorCode.FailedToCreateContainerDeploymentBundle, "Failed to create a deployment bundle");
}
selectedRecommendation.DeploymentBundle.DockerExecutionDirectory = dockerExecutionDirectory;
await CreateDeploymentBundle(orchestrator, selectedRecommendation, cloudApplication);
}
}
else if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.DotnetPublishZipFile)
{
_orchestratorInteractiveService.LogSectionStart("Creating deployment zip bundle",
"Using the dotnet CLI build the project and zip the publish artifacts.");

var dotnetPublishDeploymentBundleResult = await orchestrator.CreateDotnetPublishDeploymentBundle(selectedRecommendation);
if (!dotnetPublishDeploymentBundleResult)
throw new FailedToCreateDeploymentBundleException(DeployToolErrorCode.FailedToCreateDotnetPublishDeploymentBundle, "Failed to create a deployment bundle");
}
}

private async Task ConfigureDeploymentFromCli(Recommendation recommendation, IEnumerable<OptionSettingItem> configurableOptionSettings, bool showAdvancedSettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
using AWS.Deploy.Common;
using AWS.Deploy.Common.Recipes;
using AWS.Deploy.Common.TypeHintData;
using AWS.Deploy.Orchestration;
using AWS.Deploy.Orchestration.Data;
using Newtonsoft.Json;

namespace AWS.Deploy.CLI.Commands.TypeHints
{
Expand Down Expand Up @@ -48,18 +46,26 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
idSelector: app => app.ApplicationName,
displaySelector: app => app.ApplicationName,
defaultSelector: app => app.ApplicationName.Equals(currentTypeHintResponse?.ApplicationName),
defaultNewName: currentTypeHintResponse.ApplicationName)
defaultNewName: currentTypeHintResponse.ApplicationName ?? String.Empty)
{
AskNewName = true,
};

var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(applications, "Select Elastic Beanstalk application to deploy to:", userInputConfiguration);

return new BeanstalkApplicationTypeHintResponse(
userResponse.CreateNew,
userResponse.SelectedOption?.ApplicationName ?? userResponse.NewName
?? throw new UserPromptForNameReturnedNullException(DeployToolErrorCode.BeanstalkAppPromptForNameReturnedNull, "The user response for a new application name was null.")
);
var response = new BeanstalkApplicationTypeHintResponse(userResponse.CreateNew);
if(userResponse.CreateNew)
{
response.ApplicationName = userResponse.NewName ??
throw new UserPromptForNameReturnedNullException(DeployToolErrorCode.BeanstalkAppPromptForNameReturnedNull, "The user response for a new application name was null.");
}
else
{
response.ExistingApplicationName = userResponse.SelectedOption?.ApplicationName ??
throw new UserPromptForNameReturnedNullException(DeployToolErrorCode.BeanstalkAppPromptForNameReturnedNull, "The user response existing application name was null.");
}

return response;
}
}
}
21 changes: 3 additions & 18 deletions src/AWS.Deploy.CLI/ServerMode/Tasks/DeployRecommendationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public DeployRecommendationTask(OrchestratorSession orchestratorSession, Orchest

public async Task Execute()
{
await CreateDeploymentBundle();
await _orchestrator.CreateDeploymentBundle(_cloudApplication, _selectedRecommendation);
await _orchestrator.DeployRecommendation(_cloudApplication, _selectedRecommendation);
}

Expand All @@ -42,7 +42,8 @@ public async Task<string> GenerateCloudFormationTemplate(CdkProjectHandler cdkPr
if (cdkProjectHandler == null)
throw new FailedToCreateCDKProjectException(DeployToolErrorCode.FailedToCreateCDKProject, $"We could not create a CDK deployment project due to a missing dependency '{nameof(cdkProjectHandler)}'.");

await CreateDeploymentBundle();
await _orchestrator.CreateDeploymentBundle(_cloudApplication, _selectedRecommendation);

var cdkProject = await cdkProjectHandler.ConfigureCdkProject(_orchestratorSession, _cloudApplication, _selectedRecommendation);
try
{
Expand All @@ -53,21 +54,5 @@ public async Task<string> GenerateCloudFormationTemplate(CdkProjectHandler cdkPr
cdkProjectHandler.DeleteTemporaryCdkProject(cdkProject);
}
}

private async Task CreateDeploymentBundle()
{
if (_selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.Container)
{
var dockerBuildDeploymentBundleResult = await _orchestrator.CreateContainerDeploymentBundle(_cloudApplication, _selectedRecommendation);
if (!dockerBuildDeploymentBundleResult)
throw new FailedToCreateDeploymentBundleException(DeployToolErrorCode.FailedToCreateContainerDeploymentBundle, "Failed to create a deployment bundle");
}
else if (_selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.DotnetPublishZipFile)
{
var dotnetPublishDeploymentBundleResult = await _orchestrator.CreateDotnetPublishDeploymentBundle(_selectedRecommendation);
if (!dotnetPublishDeploymentBundleResult)
throw new FailedToCreateDeploymentBundleException(DeployToolErrorCode.FailedToCreateDotnetPublishDeploymentBundle, "Failed to create a deployment bundle");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@ namespace AWS.Deploy.CLI.TypeHintResponses
public class BeanstalkApplicationTypeHintResponse : IDisplayable
{
public bool CreateNew { get; set; }
public string ApplicationName { get; set; }
public string? ApplicationName { get; set; }
public string? ExistingApplicationName { get; set; }

public BeanstalkApplicationTypeHintResponse(
bool createNew,
string applicationName)
bool createNew)
{
CreateNew = createNew;
ApplicationName = applicationName;
}

public string ToDisplayString() => ApplicationName;
public string ToDisplayString()
{
if (CreateNew)
return ApplicationName!;
else
return ExistingApplicationName!;
}
}
}
3 changes: 2 additions & 1 deletion src/AWS.Deploy.Common/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ public enum DeployToolErrorCode
FailedToGetCredentialsForProfile = 10008900,
FailedToRunCDKDiff = 10009000,
FailedToCreateCDKProject = 10009100,
ResourceQuery = 10009200
ResourceQuery = 10009200,
FailedToCreateContainerDeploymentBundleFromGeneratedDockerFile = 10009300
}

public class ProjectFileNotFoundException : DeployToolException
Expand Down
10 changes: 10 additions & 0 deletions src/AWS.Deploy.Constants/CDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,15 @@ internal static class CDK
/// The file path of the CDK bootstrap template to be used
/// </summary>
public static string CDKBootstrapTemplatePath => Path.Combine(DeployToolWorkspaceDirectoryRoot, "CDKBootstrapTemplate.yaml");

/// <summary>
/// The version number CDK bootstrap specified in CDKBootstrapTemplate.yaml
/// </summary>
public const int CDKTemplateVersion = 12;

/// <summary>
/// The name of the CDK bootstrap CloudFormation stack
/// </summary>
public const string CDKBootstrapStackName = "CDKToolkit";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<PackageReference Include="AWSSDK.CloudFormation" Version="3.7.7.14" />
<PackageReference Include="AWSSDK.S3" Version="3.7.1.17" />
<PackageReference Include="AWSSDK.AppRunner" Version="3.7.3.11" />
<PackageReference Include="AWSSDK.SimpleSystemsManagement" Version="3.7.16" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="5.0.0" />
<PackageReference Include="Microsoft.TemplateEngine.IDE" Version="5.0.1" />
<PackageReference Include="Microsoft.TemplateEngine.Orchestrator.RunnableProjects" Version="5.0.1" />
Expand Down
55 changes: 45 additions & 10 deletions src/AWS.Deploy.Orchestration/CdkProjectHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,22 @@ public async Task DeployCdkProject(OrchestratorSession session, CloudApplication

var appSettingsFilePath = Path.Combine(cdkProjectPath, "appsettings.json");

// Ensure region is bootstrapped
var cdkBootstrap = await _commandLineWrapper.TryRunWithResult($"npx cdk bootstrap aws://{session.AWSAccountId}/{session.AWSRegion} -c {Constants.CloudFormationIdentifier.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\" --template \"{Constants.CDK.CDKBootstrapTemplatePath}\"",
workingDirectory: cdkProjectPath,
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.");
if (await DetermineIfCDKBootstrapShouldRun())
{
// Ensure region is bootstrapped
var cdkBootstrap = await _commandLineWrapper.TryRunWithResult($"npx cdk bootstrap aws://{session.AWSAccountId}/{session.AWSRegion} -c {Constants.CloudFormationIdentifier.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\" --template \"{Constants.CDK.CDKBootstrapTemplatePath}\"",
workingDirectory: cdkProjectPath,
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.");
}
else
{
_interactiveService.LogInfoMessage("Confirmed CDK Bootstrap CloudFormation stack already exists.");
}


_interactiveService.LogSectionStart("Deploying AWS CDK project",
Expand All @@ -120,7 +127,7 @@ public async Task DeployCdkProject(OrchestratorSession session, CloudApplication
var deploymentStartDate = DateTime.Now;
// Handover to CDK command line tool
// Use a CDK Context parameter to specify the settings file that has been serialized.
var cdkDeploy = await _commandLineWrapper.TryRunWithResult( $"npx cdk deploy --require-approval never -c {Constants.CloudFormationIdentifier.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\"",
var cdkDeploy = await _commandLineWrapper.TryRunWithResult($"npx cdk deploy --require-approval never -c {Constants.CloudFormationIdentifier.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\"",
workingDirectory: cdkProjectPath,
environmentVariables: environmentVariables,
needAwsCredentials: true,
Expand All @@ -133,6 +140,34 @@ public async Task DeployCdkProject(OrchestratorSession session, CloudApplication
throw new FailedToDeployCDKAppException(DeployToolErrorCode.FailedToDeployCdkApplication, "We had an issue deploying your application to AWS. Check the deployment output for more details.");
}

public async Task<bool> DetermineIfCDKBootstrapShouldRun()
{
var stack = await _awsResourceQueryer.GetCloudFormationStack(AWS.Deploy.Constants.CDK.CDKBootstrapStackName);
if (stack == null)
{
_interactiveService.LogDebugMessage("CDK Bootstrap stack not found.");
return true;
}

var qualiferParameter = stack.Parameters.FirstOrDefault(x => string.Equals("Qualifier", x.ParameterKey));
if (qualiferParameter == null || string.IsNullOrEmpty(qualiferParameter.ParameterValue))
{
_interactiveService.LogDebugMessage("CDK Bootstrap SSM parameter store value missing.");
return true;
}

var bootstrapVersionStr = await _awsResourceQueryer.GetParameterStoreTextValue($"/cdk-bootstrap/{qualiferParameter.ParameterValue}/version");
if (string.IsNullOrEmpty(bootstrapVersionStr) ||
!int.TryParse(bootstrapVersionStr, out var bootstrapVersion) ||
bootstrapVersion < AWS.Deploy.Constants.CDK.CDKTemplateVersion)
{
_interactiveService.LogDebugMessage($"CDK Bootstrap version is out of date: \"{AWS.Deploy.Constants.CDK.CDKTemplateVersion}\" < \"{bootstrapVersionStr}\".");
return true;
}

return false;
}

private async Task CheckCdkDeploymentFailure(CloudApplication cloudApplication, DateTime deploymentStartDate)
{
try
Expand Down
Loading

0 comments on commit 1344e9e

Please sign in to comment.