Skip to content

Commit

Permalink
Merge pull request #465 from aws/dev
Browse files Browse the repository at this point in the history
chore: release 0.35
  • Loading branch information
96malhar authored Feb 25, 2022
2 parents 7b97884 + f40933f commit fd8403e
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 29 deletions.
55 changes: 55 additions & 0 deletions src/AWS.Deploy.CLI/Commands/TypeHints/ECRRepositoryCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.ECR.Model;
using AWS.Deploy.Common;
using AWS.Deploy.Common.Recipes;
using AWS.Deploy.Common.TypeHintData;
using AWS.Deploy.Orchestration.Data;

namespace AWS.Deploy.CLI.Commands.TypeHints
{
public class ECRRepositoryCommand : ITypeHintCommand
{
private readonly IAWSResourceQueryer _awsResourceQueryer;
private readonly IConsoleUtilities _consoleUtilities;

public ECRRepositoryCommand(IAWSResourceQueryer awsResourceQueryer, IConsoleUtilities consoleUtilities)
{
_awsResourceQueryer = awsResourceQueryer;
_consoleUtilities = consoleUtilities;
}

public async Task<object> Execute(Recommendation recommendation, OptionSettingItem optionSetting)
{
var repositories = await GetData();
var currentRepositoryName = recommendation.GetOptionSettingValue<string>(optionSetting);

var userInputConfiguration = new UserInputConfiguration<Repository>(
rep => rep.RepositoryName,
rep => rep.RepositoryName.Equals(currentRepositoryName),
currentRepositoryName)
{
AskNewName = true,
};

var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(repositories, "Select ECR Repository:", userInputConfiguration);

return userResponse.SelectedOption?.RepositoryName ?? userResponse.NewName
?? throw new UserPromptForNameReturnedNullException(DeployToolErrorCode.ECRRepositoryPromptForNameReturnedNull, "The user response for an ECR Repository was null");
}
public async Task<List<TypeHintResource>?> GetResources(Recommendation recommendation, OptionSettingItem optionSetting)
{
var repositories = await GetData();
return repositories.Select(x => new TypeHintResource(x.RepositoryName, x.RepositoryName)).ToList();
}

private async Task<List<Repository>> GetData()
{
return await _awsResourceQueryer.GetECRRepositories();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public TypeHintCommandFactory(IToolInteractiveService toolInteractiveService, IA
{ OptionSettingTypeHint.SNSTopicArn, new SNSTopicArnsCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.S3BucketName, new S3BucketNameCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.InstanceType, new InstanceTypeCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ECRRepository, new ECRRepositoryCommand(awsResourceQueryer, consoleUtilities)}
};
}

Expand Down
1 change: 1 addition & 0 deletions src/AWS.Deploy.Common/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public enum DeployToolErrorCode
FailedToCreateElasticBeanstalkStorageLocation = 10007900,
UnableToAccessAWSRegion = 10008000,
OptInRegionDisabled = 10008100,
ECRRepositoryPromptForNameReturnedNull = 10008200
}

public class ProjectFileNotFoundException : DeployToolException
Expand Down
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 @@ -30,6 +30,7 @@ public enum OptionSettingTypeHint
ExistingIAMRole,
ExistingECSCluster,
ExistingVpc,
ExistingBeanstalkApplication
ExistingBeanstalkApplication,
ECRRepository
};
}
2 changes: 1 addition & 1 deletion src/AWS.Deploy.Common/Recommendation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public Recommendation(RecipeDefinition recipe, ProjectDefinition projectDefiniti
DeploymentBundle = new DeploymentBundle();
DeploymentBundleSettings = deploymentBundleSettings;

CollectRecommendationReplacementTokens(Recipe.OptionSettings);
CollectRecommendationReplacementTokens(GetConfigurableOptionSettingItems().ToList());

foreach (var replacement in additionalReplacements)
{
Expand Down
3 changes: 0 additions & 3 deletions src/AWS.Deploy.Constants/CLI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,5 @@ internal static class CLI
public const string PROMPT_CHOOSE_DEPLOYMENT_TARGET = "Choose deployment target";

public const string CLI_APP_NAME = "AWS .NET Deployment Tool";

public const string REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN = "{LatestDotnetBeanstalkPlatformArn}";
public const string REPLACE_TOKEN_STACK_NAME = "{StackName}";
}
}
6 changes: 5 additions & 1 deletion src/AWS.Deploy.Constants/RecipeIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ namespace AWS.Deploy.Constants
{
internal static class RecipeIdentifier
{
// Recipe IDs
public const string EXISTING_BEANSTALK_ENVIRONMENT_RECIPE_ID = "AspNetAppExistingBeanstalkEnvironment";

// Replacement Tokens
public const string REPLACE_TOKEN_STACK_NAME = "{StackName}";
public const string REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN = "{LatestDotnetBeanstalkPlatformArn}";
public const string EXISTING_BEANSTALK_ENVIRONMENT_RECIPE_ID = "AspNetAppExistingBeanstalkEnvironment";
public const string REPLACE_TOKEN_ECR_REPOSITORY_NAME = "{DefaultECRRepositoryName}";
}
}
4 changes: 2 additions & 2 deletions src/AWS.Deploy.Orchestration/Data/AWSResourceQueryer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public interface IAWSResourceQueryer
Task<List<PlatformSummary>> GetElasticBeanstalkPlatformArns();
Task<PlatformSummary> GetLatestElasticBeanstalkPlatformArn();
Task<List<AuthorizationData>> GetECRAuthorizationToken();
Task<List<Repository>> GetECRRepositories(List<string> repositoryNames);
Task<List<Repository>> GetECRRepositories(List<string>? repositoryNames = null);
Task<Repository> CreateECRRepository(string repositoryName);
Task<List<Stack>> GetCloudFormationStacks();
Task<GetCallerIdentityResponse> GetCallerIdentity(string awsRegion);
Expand Down Expand Up @@ -407,7 +407,7 @@ public async Task<List<AuthorizationData>> GetECRAuthorizationToken()
return response.AuthorizationData;
}

public async Task<List<Repository>> GetECRRepositories(List<string> repositoryNames)
public async Task<List<Repository>> GetECRRepositories(List<string>? repositoryNames = null)
{
var ecrClient = _awsClientFactory.GetAWSClient<IAmazonECR>();

Expand Down
6 changes: 3 additions & 3 deletions src/AWS.Deploy.Orchestration/DeploymentBundleHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface IDeploymentBundleHandler
{
Task<string> BuildDockerImage(CloudApplication cloudApplication, Recommendation recommendation);
Task<string> CreateDotnetPublishZip(Recommendation recommendation);
Task PushDockerImageToECR(CloudApplication cloudApplication, Recommendation recommendation, string sourceTag);
Task PushDockerImageToECR(Recommendation recommendation, string repositoryName, string sourceTag);
}

public class DeploymentBundleHandler : IDeploymentBundleHandler
Expand Down Expand Up @@ -71,15 +71,15 @@ public async Task<string> BuildDockerImage(CloudApplication cloudApplication, Re
return imageTag;
}

public async Task PushDockerImageToECR(CloudApplication cloudApplication, Recommendation recommendation, string sourceTag)
public async Task PushDockerImageToECR(Recommendation recommendation, string repositoryName, string sourceTag)
{
_interactiveService.LogMessageLine(string.Empty);
_interactiveService.LogMessageLine("Pushing the docker image to ECR repository...");

await InitiateDockerLogin();

var tagSuffix = sourceTag.Split(":")[1];
var repository = await SetupECRRepository(cloudApplication.Name.ToLower());
var repository = await SetupECRRepository(repositoryName);
var targetTag = $"{repository.RepositoryUri}:{tagSuffix}";

await TagDockerImage(sourceTag, targetTag);
Expand Down
16 changes: 10 additions & 6 deletions src/AWS.Deploy.Orchestration/Orchestrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,22 @@ public async Task<List<Recommendation>> GenerateRecommendationsFromSavedDeployme

public async Task ApplyAllReplacementTokens(Recommendation recommendation, string cloudApplicationName)
{
if (recommendation.ReplacementTokens.ContainsKey(Constants.CLI.REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN))
if (recommendation.ReplacementTokens.ContainsKey(Constants.RecipeIdentifier.REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN))
{
if (_awsResourceQueryer == null)
throw new InvalidOperationException($"{nameof(_awsResourceQueryer)} is null as part of the Orchestrator object");

var latestPlatform = await _awsResourceQueryer.GetLatestElasticBeanstalkPlatformArn();
recommendation.AddReplacementToken(Constants.CLI.REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN, latestPlatform.PlatformArn);
recommendation.AddReplacementToken(Constants.RecipeIdentifier.REPLACE_TOKEN_LATEST_DOTNET_BEANSTALK_PLATFORM_ARN, latestPlatform.PlatformArn);
}
if (recommendation.ReplacementTokens.ContainsKey(Constants.CLI.REPLACE_TOKEN_STACK_NAME))
if (recommendation.ReplacementTokens.ContainsKey(Constants.RecipeIdentifier.REPLACE_TOKEN_STACK_NAME))
{
// Apply the user entered stack name to the recommendation so that any default settings based on stack name are applied.
recommendation.AddReplacementToken(Constants.CLI.REPLACE_TOKEN_STACK_NAME, cloudApplicationName);
recommendation.AddReplacementToken(Constants.RecipeIdentifier.REPLACE_TOKEN_STACK_NAME, cloudApplicationName);
}
if (recommendation.ReplacementTokens.ContainsKey(Constants.RecipeIdentifier.REPLACE_TOKEN_ECR_REPOSITORY_NAME))
{
recommendation.AddReplacementToken(Constants.RecipeIdentifier.REPLACE_TOKEN_ECR_REPOSITORY_NAME, cloudApplicationName.ToLower());
}
}

Expand Down Expand Up @@ -169,8 +173,8 @@ public async Task<bool> CreateContainerDeploymentBundle(CloudApplication cloudAp
try
{
var imageTag = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, imageTag);
var respositoryName = recommendation.GetOptionSettingValue<string>(recommendation.GetOptionSetting("ECRRepositoryName"));
await _deploymentBundleHandler.PushDockerImageToECR(recommendation, respositoryName, imageTag);
}
catch(DockerBuildFailedException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,33 @@ namespace ConsoleAppEcsFargateService.Configurations
{
public partial class AutoScalingConfiguration
{
const int defaultCooldown = 300;

public bool Enabled { get; set; }

public int MinCapacity { get; set; }
public int MinCapacity { get; set; } = 1;

public int MaxCapacity { get; set; }
public int MaxCapacity { get; set; } = 3;

public enum ScalingTypeEnum { Cpu, Memory }

public ScalingTypeEnum? ScalingType { get; set; }



public double CpuTypeTargetUtilizationPercent { get; set; }
public double CpuTypeTargetUtilizationPercent { get; set; } = 70;

public int CpuTypeScaleInCooldownSeconds { get; set; }
public int CpuTypeScaleInCooldownSeconds { get; set; } = defaultCooldown;

public int CpuTypeScaleOutCooldownSeconds { get; set; }
public int CpuTypeScaleOutCooldownSeconds { get; set; } = defaultCooldown;



public int MemoryTypeTargetUtilizationPercent { get; set; }
public int MemoryTypeTargetUtilizationPercent { get; set; } = 70;

public int MemoryTypeScaleInCooldownSeconds { get; set; }
public int MemoryTypeScaleInCooldownSeconds { get; set; } = defaultCooldown;

public int MemoryTypeScaleOutCooldownSeconds { get; set; }
public int MemoryTypeScaleOutCooldownSeconds { get; set; } = defaultCooldown;

/// A parameterless constructor is needed for <see cref="Microsoft.Extensions.Configuration.ConfigurationBuilder"/>
/// or the classes will fail to initialize.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@
"DefaultValue": "",
"AdvancedSetting": true,
"Updatable": true
},
{
"Id": "ECRRepositoryName",
"Name": "ECS Repository Name",
"Description": "Specifies the ECR repository where the docker images will be stored",
"Type": "String",
"TypeHint": "ECRRepository",
"DefaultValue": "{DefaultECRRepositoryName}",
"AdvancedSetting": false,
"Updatable": true,
"Validators": [
{
"ValidatorType": "Regex",
"Configuration" : {
"Regex": "^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$",
"ValidationFailedMessage": "Invalid ECR repository Name. The ECR repository name can only contain lowercase letters, numbers, hyphens(-), dots(.), underscores(_) and forward slashes (/). For more information visit https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecr-repository.html#cfn-ecr-repository-repositoryname"
}
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ public void ListenerConditionPathPatternValidationTest(string value, bool isVali
Validate(optionSettingItem, value, isValid);
}

[Theory]
[InlineData("myrepo123", true)]
[InlineData("myrepo123.a/b", true)]
[InlineData("MyRepo", false)] // cannot contain uppercase letters
[InlineData("myrepo123@", false)] // cannot contain @
[InlineData("myrepo123.a//b", false)] // cannot contain consecutive slashes.
public void ECRRepositoryNameValidationTest(string value, bool isValid)
{
var optionSettingItem = new OptionSettingItem("id", "name", "description");
optionSettingItem.Validators.Add(GetRegexValidatorConfig("^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$"));
Validate(optionSettingItem, value, isValid);
}

private OptionSettingItemValidatorConfig GetRegexValidatorConfig(string regex)
{
var regexValidatorConfig = new OptionSettingItemValidatorConfig
Expand Down
9 changes: 9 additions & 0 deletions test/AWS.Deploy.CLI.IntegrationTests/ConsoleAppTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ public async Task DefaultConfigurations(params string[] components)
var listStdOut = _interactiveService.StdOutReader.ReadAllLines().Select(x => x.Split()[0]).ToList();
Assert.Contains(listStdOut, (deployment) => _stackName.Equals(deployment));

// Arrange input for re-deployment
await _interactiveService.StdInWriter.WriteAsync(Environment.NewLine); // Select default option settings
await _interactiveService.StdInWriter.FlushAsync();

// Perform re-deployment
deployArgs = new[] { "deploy", "--project-path", _testAppManager.GetProjectPath(Path.Combine(components)), "--application-name", _stackName, "--diagnostics" };
Assert.Equal(CommandReturnCodes.SUCCESS, await _app.Run(deployArgs));
Assert.Equal(StackStatus.UPDATE_COMPLETE, await _cloudFormationHelper.GetStackStatus(_stackName));

// Arrange input for delete
await _interactiveService.StdInWriter.WriteAsync("y"); // Confirm delete
await _interactiveService.StdInWriter.FlushAsync();
Expand Down
6 changes: 3 additions & 3 deletions test/AWS.Deploy.CLI.UnitTests/DeploymentBundleHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ public async Task PushDockerImage_RepositoryNameCheck()
var projectPath = SystemIOUtilities.ResolvePath("ConsoleAppTask");
var project = await _projectDefinitionParser.Parse(projectPath);
var recommendation = new Recommendation(_recipeDefinition, project, new List<OptionSettingItem>(), 100, new Dictionary<string, string>());
var repositoryName = "repository";

var cloudApplication = new CloudApplication("ConsoleAppTask", string.Empty, CloudApplicationResourceType.CloudFormationStack, string.Empty);
await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, "ConsoleAppTask:latest");
await _deploymentBundleHandler.PushDockerImageToECR(recommendation, repositoryName, "ConsoleAppTask:latest");

Assert.Equal(cloudApplication.Name.ToLower(), recommendation.DeploymentBundle.ECRRepositoryName);
Assert.Equal(repositoryName, recommendation.DeploymentBundle.ECRRepositoryName);
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "0.34",
"version": "0.35",
"publicReleaseRefSpec": [
".*"
],
Expand Down

0 comments on commit fd8403e

Please sign in to comment.