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

feat: add support for deploying ARM console apps to ECS Fargate #875

Open
wants to merge 5 commits into
base: asmarp/ecs-fargate-arm-support
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions .autover/changes/3bbbb972-6181-431c-8313-097ce38a2463.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"Projects": [
{
"Name": "AWS.Deploy.CLI",
"Type": "Minor",
"ChangelogMessages": [
"Add support for deploying ARM web apps to ECS Fargate"
]
}
]
}
11 changes: 11 additions & 0 deletions .autover/changes/a2dd7cca-b2c5-47e1-8bce-34eb5239a047.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"Projects": [
{
"Name": "AWS.Deploy.CLI",
"Type": "Minor",
"ChangelogMessages": [
"Add support for deploying ARM console apps to ECS Fargate"
]
}
]
}
6 changes: 5 additions & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
codecov:
branch: dev # set the default branch to 'dev'. This branch provides the coverage baselines during pull requests.
branch: dev # set the default branch to 'dev'. This branch provides the coverage baselines during pull requests.

coverage:
exclude:
- "test/**"
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@
* ID: AppRunnerEnvironmentVariables
* Description: Configure environment properties for your application.
* Type: KeyValue
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Docker Build Args**
* ID: DockerBuildArgs
* Description: The list of additional options to append to the `docker build` command.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@
* ID: SecurityGroups
* Description: Lists the Amazon EC2 security groups to assign to the EC2 instances in the Auto Scaling group to define firewall rules for the instances.
* Type: List
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Dotnet Build Configuration**
* ID: DotnetBuildConfiguration
* Description: The build configuration to use for the dotnet build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@
* ID: SecurityGroups
* Description: Lists the Amazon EC2 security groups to assign to the EC2 instances in the Auto Scaling group to define firewall rules for the instances.
* Type: List
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Dotnet Build Configuration**
* ID: DotnetBuildConfiguration
* Description: The build configuration to use for the dotnet build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@
* ID: ECSEnvironmentVariables
* Description: Configure environment properties for your application.
* Type: KeyValue
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Docker Build Args**
* ID: DockerBuildArgs
* Description: The list of additional options to append to the `docker build` command.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
* ID: HealthCheckURL
* Description: Customize the load balancer health check to ensure that your application, and not just the web server, is in a good state.
* Type: String
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Dotnet Build Configuration**
* ID: DotnetBuildConfiguration
* Description: The build configuration to use for the dotnet build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
* ID: HealthCheckURL
* Description: Customize the load balancer health check to ensure that your application, and not just the web server, is in a good state.
* Type: String
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Dotnet Build Configuration**
* ID: DotnetBuildConfiguration
* Description: The build configuration to use for the dotnet build
Expand Down
4 changes: 4 additions & 0 deletions site/content/docs/cicd/recipes/Blazor WebAssembly App.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@
* ID: WebAclId
* Description: The AWS WAF (web application firewall) ACL arn
* Type: String
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Dotnet Build Configuration**
* ID: DotnetBuildConfiguration
* Description: The build configuration to use for the dotnet build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
* ID: ImageTag
* Description: This tag will be associated to the container images which are pushed to Amazon Elastic Container Registry.
* Type: String
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Docker Build Args**
* ID: DockerBuildArgs
* Description: The list of additional options to append to the `docker build` command.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
* ID: ECSEnvironmentVariables
* Description: Configure environment properties for your application.
* Type: KeyValue
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Docker Build Args**
* ID: DockerBuildArgs
* Description: The list of additional options to append to the `docker build` command.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@
* ID: ECSEnvironmentVariables
* Description: Configure environment properties for your application.
* Type: KeyValue
* **Environment Architecture**
* ID: EnvironmentArchitecture
* Description: The CPU architecture of the environment to create.
* Type: String
* **Docker Build Args**
* ID: DockerBuildArgs
* Description: The list of additional options to append to the `docker build` command.
Expand Down
35 changes: 18 additions & 17 deletions src/AWS.Deploy.CLI/Commands/DeployCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -726,28 +726,29 @@ private async Task ConfigureDeploymentFromCli(Recommendation recommendation, Opt

object currentValue = _optionSettingHandler.GetOptionSettingValue(recommendation, setting);
object? settingValue = null;
if (setting.AllowedValues?.Count > 0)
{
var userInputConfig = new UserInputConfiguration<string>(
idSelector: x => x,
displaySelector: x => setting.ValueMapping.ContainsKey(x) ? setting.ValueMapping[x] : x,
defaultSelector: x => x.Equals(currentValue))
{
CreateNew = false
};

var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(setting.AllowedValues, string.Empty, userInputConfig);
settingValue = userResponse.SelectedOption;

// If they didn't change the value then don't store so we can rely on using the default in the recipe.
if (Equals(settingValue, currentValue))
return;
if (setting.TypeHint.HasValue && _typeHintCommandFactory.GetCommand(setting.TypeHint.Value) is var typeHintCommand && typeHintCommand != null)
{
settingValue = await typeHintCommand.Execute(recommendation, setting);
}
else
{
if (setting.TypeHint.HasValue && _typeHintCommandFactory.GetCommand(setting.TypeHint.Value) is var typeHintCommand && typeHintCommand != null)
if (setting.AllowedValues?.Count > 0)
{
settingValue = await typeHintCommand.Execute(recommendation, setting);
var userInputConfig = new UserInputConfiguration<string>(
idSelector: x => x,
displaySelector: x => setting.ValueMapping.ContainsKey(x) ? setting.ValueMapping[x] : x,
defaultSelector: x => x.Equals(currentValue))
{
CreateNew = false
};

var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(setting.AllowedValues, string.Empty, userInputConfig);
settingValue = userResponse.SelectedOption;

// If they didn't change the value then don't store so we can rely on using the default in the recipe.
if (Equals(settingValue, currentValue))
return;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AWS.Deploy.Common;
using AWS.Deploy.Common.Recipes;
using AWS.Deploy.Common.TypeHintData;

namespace AWS.Deploy.CLI.Commands.TypeHints
{
public class EnvironmentArchitectureCommand : ITypeHintCommand
{
private readonly IConsoleUtilities _consoleUtilities;
private readonly IOptionSettingHandler _optionSettingHandler;

public EnvironmentArchitectureCommand(IConsoleUtilities consoleUtilities, IOptionSettingHandler optionSettingHandler)
{
_consoleUtilities = consoleUtilities;
_optionSettingHandler = optionSettingHandler;
}

public Task<TypeHintResourceTable> GetResources(Recommendation recommendation, OptionSettingItem optionSetting)
{
var resourceTable = new TypeHintResourceTable
{
Columns = new List<TypeHintResourceColumn>()
{
new TypeHintResourceColumn("Architecture")
}
};

foreach (var value in recommendation.Recipe.SupportedArchitectures ??
new List<SupportedArchitecture> { Enum.Parse<SupportedArchitecture>(Constants.Recipe.DefaultSupportedArchitecture) })
{
var stringValue = value.ToString();
var row = new TypeHintResource(stringValue, stringValue);
row.ColumnValues.Add(stringValue);

resourceTable.Rows.Add(row);
}

return Task.FromResult(resourceTable);
}

public async Task<object> Execute(Recommendation recommendation, OptionSettingItem optionSetting)
{
var currentValue = _optionSettingHandler.GetOptionSettingValue(recommendation, optionSetting);
var resourceTable = await GetResources(recommendation, optionSetting);

var userInputConfiguration = new UserInputConfiguration<TypeHintResource>(
idSelector: platform => platform.SystemName,
displaySelector: platform => platform.DisplayName,
defaultSelector: platform => platform.SystemName.Equals(currentValue))
{
CreateNew = false
};

var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(resourceTable.Rows, "Select the Platform to use:", userInputConfiguration);

var result = userResponse.SelectedOption?.SystemName!;
recommendation.DeploymentBundle.EnvironmentArchitecture = Enum.Parse<SupportedArchitecture>(result);
return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public TypeHintCommandFactory(IServiceProvider serviceProvider, IToolInteractive
{ OptionSettingTypeHint.FilePath, ActivatorUtilities.CreateInstance<FilePathCommand>(serviceProvider) },
{ OptionSettingTypeHint.ElasticBeanstalkVpc, ActivatorUtilities.CreateInstance<ElasticBeanstalkVpcCommand>(serviceProvider) },
{ OptionSettingTypeHint.DockerHttpPort, ActivatorUtilities.CreateInstance<DockerHttpPortCommand>(serviceProvider) },
{ OptionSettingTypeHint.EnvironmentArchitecture, ActivatorUtilities.CreateInstance<EnvironmentArchitectureCommand>(serviceProvider) },
};
}

Expand Down
8 changes: 8 additions & 0 deletions src/AWS.Deploy.Common/DeploymentBundles/DeploymentBundle.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using AWS.Deploy.Common.Recipes;

namespace AWS.Deploy.Common
{
/// <summary>
Expand Down Expand Up @@ -63,5 +66,10 @@ public class DeploymentBundle
/// The list of additional dotnet publish args passed to the target application.
/// </summary>
public string DotnetPublishAdditionalBuildArguments { get; set; } = "";

/// <summary>
/// The CPU architecture of the environment to create.
/// </summary>
public SupportedArchitecture EnvironmentArchitecture { get; set; } = Enum.Parse<SupportedArchitecture>(Constants.Recipe.DefaultSupportedArchitecture);
}
}
3 changes: 2 additions & 1 deletion src/AWS.Deploy.Common/Recipes/OptionSettingTypeHint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public enum OptionSettingTypeHint
VPCConnector,
FilePath,
ElasticBeanstalkVpc,
DockerHttpPort
DockerHttpPort,
EnvironmentArchitecture
};
}
5 changes: 5 additions & 0 deletions src/AWS.Deploy.Common/Recipes/RecipeDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public class RecipeDefinition
/// </summary>
public TargetPlatform? TargetPlatform { get; set; }

/// <summary>
/// The CPU architecture that is supported by the recipe.
/// </summary>
public List<SupportedArchitecture>? SupportedArchitectures { get; set; }

/// <summary>
/// The list of DisplayedResources that lists logical CloudFormation IDs with a description.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/AWS.Deploy.Common/Recipes/SupportedArchitecture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
// SPDX-License-Identifier: Apache-2.0

namespace AWS.Deploy.Common.Recipes;

public enum SupportedArchitecture
{
X86_64,
Arm64
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class RequiredValidator : IOptionSettingItemValidator
public Task<ValidationResult> Validate(object input, Recommendation recommendation, OptionSettingItem optionSettingItem)
{
var message = ValidationFailedMessage.Replace("{{OptionSetting}}", optionSettingItem.Name);
if (input?.TryDeserialize<SortedSet<string>>(out var inputList) ?? false && inputList != null)
if (input?.TryDeserialize<SortedSet<string>>(out var inputList) ?? false)
{
return Task.FromResult<ValidationResult>(new()
{
Expand Down
1 change: 1 addition & 0 deletions src/AWS.Deploy.Constants/AWS.Deploy.Constants.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Docker.cs" />
<Compile Include="$(MSBuildThisFileDirectory)EC2.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ElasticBeanstalk.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Recipe.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RecipeIdentifier.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/AWS.Deploy.Constants/Recipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
// SPDX-License-Identifier: Apache-2.0

namespace AWS.Deploy.Constants
{
internal class Recipe
{
/// <summary>
/// The default supported architecture
/// </summary>
public const string DefaultSupportedArchitecture = "X86_64";
}
}
6 changes: 6 additions & 0 deletions src/AWS.Deploy.Constants/RecipeIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal static class RecipeIdentifier
public const string REPLACE_TOKEN_HAS_DEFAULT_VPC = "{HasDefaultVpc}";
public const string REPLACE_TOKEN_HAS_NOT_VPCS = "{HasNotVpcs}";
public const string REPLACE_TOKEN_DEFAULT_CONTAINER_PORT = "{DefaultContainerPort}";
public const string REPLACE_TOKEN_DEFAULT_ENVIRONMENT_ARCHITECTURE = "{DefaultEnvironmentArchitecture}";

/// <summary>
/// Id for the 'dotnet publish --configuration' recipe option
Expand All @@ -38,6 +39,11 @@ internal static class RecipeIdentifier
/// </summary>
public const string DotnetPublishSelfContainedBuildOptionId = "SelfContainedBuild";

/// <summary>
/// Id for the environment architecture recipe option
/// </summary>
public const string EnvironmentArchitectureOptionId = "EnvironmentArchitecture";

public const string TARGET_SERVICE_ELASTIC_BEANSTALK = "AWS Elastic Beanstalk";
}
}
3 changes: 2 additions & 1 deletion src/AWS.Deploy.Orchestration/CdkAppSettingsSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public string Build(CloudApplication cloudApplication, Recommendation recommenda
ECRRepositoryName = recommendation.DeploymentBundle.ECRRepositoryName ?? "",
ECRImageTag = recommendation.DeploymentBundle.ECRImageTag ?? "",
DotnetPublishZipPath = recommendation.DeploymentBundle.DotnetPublishZipPath ?? "",
DotnetPublishOutputDirectory = recommendation.DeploymentBundle.DotnetPublishOutputDirectory ?? ""
DotnetPublishOutputDirectory = recommendation.DeploymentBundle.DotnetPublishOutputDirectory ?? "",
EnvironmentArchitecture = recommendation.DeploymentBundle.EnvironmentArchitecture.ToString()
};

// Persist deployment bundle settings
Expand Down
6 changes: 4 additions & 2 deletions src/AWS.Deploy.Orchestration/DeploymentBundleHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ public async Task BuildDockerImage(CloudApplication cloudApplication, Recommenda
DockerUtilities.TryGetAbsoluteDockerfile(recommendation, _fileManager, _directoryManager, out var dockerFile);

var dockerBuildCommand = $"docker build -t {imageTag} -f \"{dockerFile}\"{buildArgs} .";
if (RuntimeInformation.OSArchitecture != Architecture.X64)
var currentArchitecture = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? SupportedArchitecture.Arm64 : SupportedArchitecture.X86_64;
var dockerPlatform = recommendation.DeploymentBundle.EnvironmentArchitecture == SupportedArchitecture.Arm64 ? "linux/arm64" : "linux/amd64";
if (currentArchitecture != recommendation.DeploymentBundle.EnvironmentArchitecture)
{
dockerBuildCommand = $"docker buildx build --platform linux/amd64 -t {imageTag} -f \"{dockerFile}\"{buildArgs} .";
dockerBuildCommand = $"docker buildx build --platform {dockerPlatform} -t {imageTag} -f \"{dockerFile}\"{buildArgs} .";
}

_interactiveService.LogInfoMessage($"Docker Execution Directory: {Path.GetFullPath(dockerExecutionDirectory)}");
Expand Down
Loading
Loading