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

chore: release 1.23 #848

Merged
merged 3 commits into from
Aug 6, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public DotnetBeanstalkPlatformArnCommand(IAWSResourceQueryer awsResourceQueryer,
_optionSettingHandler = optionSettingHandler;
}

private async Task<List<PlatformSummary>> GetData()
private async Task<List<PlatformSummary>> GetData(Recommendation recommendation)
{
return await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(BeanstalkPlatformType.Linux);
return await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(recommendation.ProjectDefinition.TargetFramework, BeanstalkPlatformType.Linux);
}

public async Task<TypeHintResourceTable> GetResources(Recommendation recommendation, OptionSettingItem optionSetting)
{
var platformArns = await GetData();
var platformArns = await GetData(recommendation);

var resourceTable = new TypeHintResourceTable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ public DotnetWindowsBeanstalkPlatformArnCommand(IAWSResourceQueryer awsResourceQ
_optionSettingHandler = optionSettingHandler;
}

private async Task<List<PlatformSummary>> GetData()
private async Task<List<PlatformSummary>> GetData(Recommendation recommendation)
{
return await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(BeanstalkPlatformType.Windows);
return await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(recommendation.ProjectDefinition.TargetFramework, BeanstalkPlatformType.Windows);
}

public async Task<TypeHintResourceTable> GetResources(Recommendation recommendation, OptionSettingItem optionSetting)
{
var platformArns = await GetData();
var platformArns = await GetData(recommendation);

var resourceTable = new TypeHintResourceTable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,15 @@ public async Task<List<Repository>> GetECRRepositories(List<string>? repositoryN
}

/// <inheritdoc/>
public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(params BeanstalkPlatformType[]? platformTypes)
public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(string? targetFramework, params BeanstalkPlatformType[]? platformTypes)
{
return (await GetAndCache(async () => await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(platformTypes), new object?[] { platformTypes }))!;
return (await GetAndCache(async () => await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(targetFramework, platformTypes), new object?[] { platformTypes }))!;
}

/// <inheritdoc/>
public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(BeanstalkPlatformType platformType)
public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(string? targetFramework, BeanstalkPlatformType platformType)
{
return (await GetAndCache(async () => await _awsResourceQueryer.GetLatestElasticBeanstalkPlatformArn(platformType), new object[] { platformType }))!;
return (await GetAndCache(async () => await _awsResourceQueryer.GetLatestElasticBeanstalkPlatformArn(targetFramework, platformType), new object[] { platformType }))!;
}

/// <inheritdoc/>
Expand Down
4 changes: 2 additions & 2 deletions src/AWS.Deploy.Common/Data/IAWSResourceQueryer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public interface IAWSResourceQueryer
Task<string> CreateEC2KeyPair(string keyName, string saveLocation);
Task<List<Role>> ListOfIAMRoles(string? servicePrincipal);
Task<List<Vpc>> GetListOfVpcs();
Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(params BeanstalkPlatformType[]? platformTypes);
Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(BeanstalkPlatformType platformType);
Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(string? targetFramework, params BeanstalkPlatformType[]? platformTypes);
Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(string? targetFramework, BeanstalkPlatformType platformType);
Task<List<AuthorizationData>> GetECRAuthorizationToken();
Task<List<Repository>> GetECRRepositories(List<string>? repositoryNames = null);

Expand Down
2 changes: 1 addition & 1 deletion src/AWS.Deploy.Common/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public enum DeployToolErrorCode
FailedToSaveDeploymentSettings = 10010600,
InvalidWindowsManifestFile = 10010700,
UserDeploymentFileNotFound = 10010800,
DockerInspectFailed = 10004200,
DockerInspectFailed = 10004200
}

public class ProjectFileNotFoundException : DeployToolException
Expand Down
6 changes: 5 additions & 1 deletion src/AWS.Deploy.Orchestration/CDK/CDKBootstrapTemplate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ Resources:
Resource:
- Fn::Sub: ${StagingBucket.Arn}
- Fn::Sub: ${StagingBucket.Arn}/*
Condition:
StringEquals:
aws:ResourceAccount:
- Fn::Sub: ${AWS::AccountId}
Effect: Allow
- Action:
- kms:Decrypt
Expand Down Expand Up @@ -585,7 +589,7 @@ Resources:
Type: String
Name:
Fn::Sub: /cdk-bootstrap/${Qualifier}/version
Value: "20"
Value: "21"
Outputs:
BucketName:
Description: The name of the S3 bucket owned by the CDK toolkit stack
Expand Down
92 changes: 86 additions & 6 deletions src/AWS.Deploy.Orchestration/Data/AWSResourceQueryer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ public async Task<List<Vpc>> GetListOfVpcs()
"Error attempting to retrieve the default VPC");
}

public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(params BeanstalkPlatformType[]? platformTypes)
public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(string? targetFramework, params BeanstalkPlatformType[]? platformTypes)
{
if(platformTypes == null || platformTypes.Length == 0)
{
Expand Down Expand Up @@ -557,7 +557,9 @@ public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(params
var allPlatformSummaries = new List<PlatformSummary>();
if (platformTypes.Contains(BeanstalkPlatformType.Linux))
{
allPlatformSummaries.AddRange(await fetchPlatforms(Constants.ElasticBeanstalk.LinuxPlatformType));
var linuxPlatforms = await fetchPlatforms(Constants.ElasticBeanstalk.LinuxPlatformType);
linuxPlatforms = SortElasticBeanstalkLinuxPlatforms(targetFramework, linuxPlatforms);
allPlatformSummaries.AddRange(linuxPlatforms);
}
if (platformTypes.Contains(BeanstalkPlatformType.Windows))
{
Expand All @@ -581,9 +583,9 @@ public async Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns(params
return platformVersions;
}

public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(BeanstalkPlatformType platformType)
public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(string? targetFramework, BeanstalkPlatformType platformType)
{
var platforms = await GetElasticBeanstalkPlatformArns(platformType);
var platforms = await GetElasticBeanstalkPlatformArns(targetFramework, platformType);

if (!platforms.Any())
{
Expand All @@ -596,12 +598,90 @@ public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(Beanstal
return platforms.First();
}

/// <summary>
/// For Linux beanstalk platforms the describe calls return a collection of .NET x and .NET Core based platforms.
/// The order returned will be sorted by .NET version in increasing order then by platform versions. So for example we could get a result like the following
///
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.2
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.6
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.5
/// .NET 8 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET Core running on 64bit Amazon Linux 2 v2.8.0
/// .NET Core running on 64bit Amazon Linux 2 v2.7.3
/// .NET Core running on 64bit Amazon Linux 2 v2.6.0
///
/// We want the user to see the .NET version corresponding to their application on the latest Beanstalk platform first.
/// If the user is trying to deploy a .NET 6 application, the above example will be sorted into the following.
///
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET 8 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.2
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.6
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.5
/// .NET Core running on 64bit Amazon Linux 2 v2.8.0
/// .NET Core running on 64bit Amazon Linux 2 v2.7.3
/// .NET Core running on 64bit Amazon Linux 2 v2.6.0
///
/// In case the target framework is not known in advance, the platforms will be sorted by Beanstalk Platform followed by the .NET version, with .NET Core coming in last.
/// The above example will be sorted into the following.
///
/// .NET 8 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.3
/// .NET 6 running on 64bit Amazon Linux 2023 v3.1.2
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.6
/// .NET 6 running on 64bit Amazon Linux 2023 v3.0.5
/// .NET Core running on 64bit Amazon Linux 2 v2.8.0
/// .NET Core running on 64bit Amazon Linux 2 v2.7.3
/// .NET Core running on 64bit Amazon Linux 2 v2.6.0
/// </summary>
/// <param name="platforms"></param>
/// <param name="targetFramework"></param>
public static List<PlatformSummary> SortElasticBeanstalkLinuxPlatforms(string? targetFramework, List<PlatformSummary> platforms)
{
var dotnetVersionMap = new System.Collections.Generic.Dictionary<string, decimal>();
foreach (var platform in platforms)
{
var runningIndexOf = platform.PlatformBranchName.IndexOf("running", StringComparison.InvariantCultureIgnoreCase);
if (runningIndexOf == -1)
{
dotnetVersionMap[platform.PlatformArn] = 0;
continue;
}

var framework = platform.PlatformBranchName.Substring(0, runningIndexOf).Trim();
var frameworkSplit = framework.Split(" ");
if (frameworkSplit.Length != 2)
{
dotnetVersionMap[platform.PlatformArn] = 0;
continue;
}

if (!decimal.TryParse(frameworkSplit[1], out var dotnetVersion))
{
dotnetVersionMap[platform.PlatformArn] = 0;
continue;
}

if (decimal.TryParse(targetFramework?.Replace("net", ""), out var currentTargetFramework))
{
if (currentTargetFramework.Equals(dotnetVersion))
{
dotnetVersionMap[platform.PlatformArn] = 1000;
continue;
}
}

dotnetVersionMap[platform.PlatformArn] = dotnetVersion;
}

return platforms.OrderByDescending(x => new Version(x.PlatformVersion)).ThenByDescending(x => dotnetVersionMap[x.PlatformArn]).ToList();
}

/// <summary>
/// For Windows beanstalk platforms the describe calls return a collection of Windows Server Code and Windows Server based platforms.
/// The order return will be sorted by platform versions but not OS. So for example we could get a result like the following
///
///
/// IIS 10.0 running on 64bit Windows Server 2016 (1.1.0)
/// IIS 10.0 running on 64bit Windows Server 2016 (1.0.0)
/// IIS 10.0 running on 64bit Windows Server Core 2016 (1.1.0)
Expand All @@ -613,7 +693,7 @@ public async Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn(Beanstal
///
/// We want the user to use the latest version of each OS first as well as the latest version of Windows first. Also Windows Server should come before Windows Server Core.
/// This matches the behavior of the existing VS toolkit picker. The above example will be sorted into the following.
///
///
/// IIS 10.0 running on 64bit Windows Server 2019 (1.1.0)
/// IIS 10.0 running on 64bit Windows Server Core 2019 (1.1.0)
/// IIS 10.0 running on 64bit Windows Server 2016 (1.1.0)
Expand Down
82 changes: 71 additions & 11 deletions src/AWS.Deploy.Orchestration/DeploymentBundleHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -43,21 +44,24 @@ public class DeploymentBundleHandler : IDeploymentBundleHandler
private readonly IDirectoryManager _directoryManager;
private readonly IZipFileManager _zipFileManager;
private readonly IFileManager _fileManager;
private readonly IOptionSettingHandler _optionSettingHandler;

public DeploymentBundleHandler(
ICommandLineWrapper commandLineWrapper,
IAWSResourceQueryer awsResourceQueryer,
IOrchestratorInteractiveService interactiveService,
IDirectoryManager directoryManager,
IZipFileManager zipFileManager,
IFileManager fileManager)
IFileManager fileManager,
IOptionSettingHandler optionSettingHandler)
{
_commandLineWrapper = commandLineWrapper;
_awsResourceQueryer = awsResourceQueryer;
_interactiveService = interactiveService;
_directoryManager = directoryManager;
_zipFileManager = zipFileManager;
_fileManager = fileManager;
_optionSettingHandler = optionSettingHandler;
}

public async Task BuildDockerImage(CloudApplication cloudApplication, Recommendation recommendation, string imageTag)
Expand Down Expand Up @@ -108,21 +112,77 @@ public async Task PushDockerImageToECR(Recommendation recommendation, string rep
recommendation.DeploymentBundle.ECRImageTag = tagSuffix;
}

/// <summary>
/// The supported .NET versions on Elastic Beanstalk are dependent on the available platform versions.
/// These versions do not always have the required .NET runtimes installed so we need to perform extra checks
/// and perform a self-contained publish when creating the deployment bundle if needed.
/// </summary>
private void SwitchToSelfContainedBuildIfNeeded(Recommendation recommendation)
{
if (recommendation.Recipe.TargetService == RecipeIdentifier.TARGET_SERVICE_ELASTIC_BEANSTALK)
{
if (recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild)
return;

var targetFramework = recommendation.ProjectDefinition.TargetFramework ?? string.Empty;
if (string.IsNullOrEmpty(targetFramework))
return;

// Elastic Beanstalk doesn't currently have .NET 7 preinstalled.
var unavailableFramework = new List<string> { "net7.0" };
var frameworkNames = new Dictionary<string, string> { { "net7.0", ".NET 7" } };
if (unavailableFramework.Contains(targetFramework))
{
_interactiveService.LogInfoMessage($"Using self-contained publish since AWS Elastic Beanstalk does not currently have {frameworkNames[targetFramework]} preinstalled");
recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild = true;
return;
}

var beanstalkPlatformSetting = recommendation.Recipe.OptionSettings.FirstOrDefault(x => x.Id.Equals("ElasticBeanstalkPlatformArn"));
if (beanstalkPlatformSetting != null)
{
var beanstalkPlatformSettingValue = _optionSettingHandler.GetOptionSettingValue<string>(recommendation, beanstalkPlatformSetting);
var beanstalkPlatformSettingValueSplit = beanstalkPlatformSettingValue?.Split("/");
if (beanstalkPlatformSettingValueSplit?.Length != 3)
// If the platform is not in the expected format, we will proceed normally to allow users to manually set the self-contained build to true.
return;
var beanstalkPlatformName = beanstalkPlatformSettingValueSplit[1];
if (!Version.TryParse(beanstalkPlatformSettingValueSplit[2], out var beanstalkPlatformVersion))
// If the platform is not in the expected format, we will proceed normally to allow users to manually set the self-contained build to true.
return;

// Elastic Beanstalk recently added .NET8 support in
// platform '.NET 8 on AL2023 version 3.1.1' and '.NET Core on AL2 version 2.8.0'.
// If users are using platform versions other than the above or older than '2.8.0' for '.NET Core'
// we need to perform a self-contained publish.
if (targetFramework.Equals("net8.0"))
{
if (beanstalkPlatformName.Contains(".NET Core"))
{
if (beanstalkPlatformVersion < new Version(2, 8, 0))
{
_interactiveService.LogInfoMessage($"Using self-contained publish since AWS Elastic Beanstalk does not currently have .NET 8 preinstalled on {beanstalkPlatformName} ({beanstalkPlatformVersion.ToString()})");
recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild = true;
return;
}
}
else if (!beanstalkPlatformName.Contains(".NET 8"))
{
_interactiveService.LogInfoMessage($"Using self-contained publish since AWS Elastic Beanstalk does not currently have .NET 8 preinstalled on {beanstalkPlatformName} ({beanstalkPlatformVersion.ToString()})");
recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild = true;
return;
}
}
}
}
}

public async Task<string> CreateDotnetPublishZip(Recommendation recommendation)
{
_interactiveService.LogInfoMessage(string.Empty);
_interactiveService.LogInfoMessage("Creating Dotnet Publish Zip file...");

// Since Beanstalk doesn't currently have .NET 7 and .NET 8 preinstalled we need to make sure we are doing a self-contained publish when creating the deployment bundle.
var targetFramework = recommendation.ProjectDefinition.TargetFramework ?? string.Empty;
var unavailableFramework = new List<string> { "net7.0", "net8.0" };
var frameworkNames = new Dictionary<string, string> { { "net7.0", ".NET 7" }, { "net8.0", ".NET 8" } };
if (recommendation.Recipe.TargetService == RecipeIdentifier.TARGET_SERVICE_ELASTIC_BEANSTALK &&
unavailableFramework.Contains(targetFramework))
{
_interactiveService.LogInfoMessage($"Using self-contained publish since AWS Elastic Beanstalk does not currently have {frameworkNames[targetFramework]} preinstalled");
recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild = true;
}
SwitchToSelfContainedBuildIfNeeded(recommendation);

var publishDirectoryInfo = _directoryManager.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
var additionalArguments = recommendation.DeploymentBundle.DotnetPublishAdditionalBuildArguments;
Expand Down
Loading
Loading