Skip to content

Commit

Permalink
Merge pull request #416 from aws/dev
Browse files Browse the repository at this point in the history
chore: release 0.31
  • Loading branch information
philasmar authored Dec 9, 2021
2 parents 6c508ac + a35ad22 commit 49dde02
Show file tree
Hide file tree
Showing 34 changed files with 872 additions and 14 deletions.
25 changes: 24 additions & 1 deletion src/AWS.Deploy.CLI/Commands/DeployCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ private void ConfigureDeploymentFromConfigFile(Recommendation recommendation, Us

var optionSetting = recommendation.GetOptionSetting(optionSettingJsonPath);

if (optionSetting == null)
throw new OptionSettingItemDoesNotExistException(DeployToolErrorCode.OptionSettingItemDoesNotExistInRecipe, $"The Option Setting Item {optionSettingJsonPath} does not exist.");

if (!recommendation.IsExistingCloudApplication || optionSetting.Updatable)
{
object settingValue;
Expand All @@ -388,6 +391,13 @@ private void ConfigureDeploymentFromConfigFile(Recommendation recommendation, Us
case OptionSettingValueType.Double:
settingValue = double.Parse(optionSettingValue);
break;
case OptionSettingValueType.KeyValue:
var optionSettingKey = optionSettingJsonPath.Split(".").Last();
var existingValue = recommendation.GetOptionSettingValue<Dictionary<string, string>>(optionSetting);
existingValue ??= new Dictionary<string, string>();
existingValue[optionSettingKey] = optionSettingValue;
settingValue = existingValue;
break;
default:
throw new InvalidOverrideValueException(DeployToolErrorCode.InvalidValueForOptionSettingItem, $"Invalid value {optionSettingValue} for option setting item {optionSettingJsonPath}");
}
Expand Down Expand Up @@ -772,6 +782,9 @@ private async Task ConfigureDeploymentFromCli(Recommendation recommendation, Opt
var answer = _consoleUtilities.AskYesNoQuestion(string.Empty, recommendation.GetOptionSettingValue(setting).ToString());
settingValue = answer == YesNo.Yes ? "true" : "false";
break;
case OptionSettingValueType.KeyValue:
settingValue = _consoleUtilities.AskUserForKeyValue(!string.IsNullOrEmpty(currentValue.ToString()) ? (Dictionary<string, string>) currentValue : new Dictionary<string, string>());
break;
case OptionSettingValueType.Object:
foreach (var childSetting in setting.ChildOptionSettings)
{
Expand Down Expand Up @@ -809,6 +822,7 @@ private async Task ConfigureDeploymentFromCli(Recommendation recommendation, Opt
private void DisplayValue(Recommendation recommendation, OptionSettingItem optionSetting, int optionSettingNumber, int optionSettingsCount, Type? typeHintResponseType, DisplayOptionSettingsMode mode)
{
object? displayValue = null;
Dictionary<string, string>? keyValuePair = null;
Dictionary<string, object>? objectValues = null;
if (typeHintResponseType != null)
{
Expand All @@ -823,7 +837,8 @@ private void DisplayValue(Recommendation recommendation, OptionSettingItem optio
{
var value = recommendation.GetOptionSettingValue(optionSetting);
objectValues = value as Dictionary<string, object>;
displayValue = objectValues == null ? value : string.Empty;
keyValuePair = value as Dictionary<string, string>;
displayValue = objectValues == null && keyValuePair == null ? value : string.Empty;
}

if (mode == DisplayOptionSettingsMode.Editable)
Expand All @@ -835,6 +850,14 @@ private void DisplayValue(Recommendation recommendation, OptionSettingItem optio
_toolInteractiveService.WriteLine($"{optionSetting.Name}: {displayValue}");
}

if (keyValuePair != null)
{
foreach (var (key, value) in keyValuePair)
{
_toolInteractiveService.WriteLine($"\t{key}: {value}");
}
}

if (objectValues != null)
{
var displayableValues = new Dictionary<string, object>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
{
const string NO_VALUE = "*** Do not select table ***";
var currentValue = recommendation.GetOptionSettingValue(optionSetting);
var typeHintData = optionSetting.GetTypeHintData<DynamoDBTableTypeHintData>();
var tables = await GetData();

tables.Add(NO_VALUE);
if (typeHintData?.AllowNoValue ?? false)
tables.Add(NO_VALUE);

var userResponse = _consoleUtilities.AskUserToChoose(
values: tables,
title: "Select a DynamoDB table:",
Expand Down
93 changes: 93 additions & 0 deletions src/AWS.Deploy.CLI/Commands/TypeHints/InstanceTypeCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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.EC2.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 InstanceTypeCommand : ITypeHintCommand
{
private readonly IAWSResourceQueryer _awsResourceQueryer;
private readonly IConsoleUtilities _consoleUtilities;

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

private async Task<List<InstanceTypeInfo>?> GetData(Recommendation recommendation, OptionSettingItem optionSetting)
{
return await _awsResourceQueryer.ListOfAvailableInstanceTypes();
}

public async Task<List<TypeHintResource>?> GetResources(Recommendation recommendation, OptionSettingItem optionSetting)
{
var instanceType = await GetData(recommendation, optionSetting);
return instanceType?
.Select(x => new TypeHintResource(x.InstanceType.Value, x.InstanceType.Value))
.Distinct()
.OrderBy(x => x)
.ToList();
}

public async Task<object> Execute(Recommendation recommendation, OptionSettingItem optionSetting)
{
var instanceTypes = await GetData(recommendation, optionSetting);
var instanceTypeDefaultValue = recommendation.GetOptionSettingDefaultValue<string>(optionSetting);
if (instanceTypes == null)
{
return _consoleUtilities.AskUserForValue("Select EC2 Instance Type:", instanceTypeDefaultValue ?? string.Empty, true);
}

var freeTierEligibleAnswer = _consoleUtilities.AskYesNoQuestion("Do you want the EC2 instance to be free tier eligible?", "true");
var freeTierEligible = freeTierEligibleAnswer == YesNo.Yes;

var architectureAllowedValues = new List<string> { "x86_64", "arm64"};

var architecture = _consoleUtilities.AskUserToChoose(architectureAllowedValues, "The architecture of the EC2 instances created for the environment.", "x86_64");

var cpuCores = instanceTypes
.Where(x => x.FreeTierEligible.Equals(freeTierEligible))
.Where(x => x.ProcessorInfo.SupportedArchitectures.Contains(architecture))
.Select(x => x.VCpuInfo.DefaultCores).Distinct().OrderBy(x => x).ToList();

if (cpuCores.Count == 0)
return _consoleUtilities.AskUserForValue("Select EC2 Instance Type:", instanceTypeDefaultValue ?? string.Empty, true);

var cpuCoreCount = int.Parse(_consoleUtilities.AskUserToChoose(cpuCores.Select(x => x.ToString()).ToList(), "Select EC2 Instance CPU Cores:", "1"));

var memory = instanceTypes
.Where(x => x.FreeTierEligible.Equals(freeTierEligible))
.Where(x => x.ProcessorInfo.SupportedArchitectures.Contains(architecture))
.Where(x => x.VCpuInfo.DefaultCores.Equals(cpuCoreCount))
.Select(x => x.MemoryInfo.SizeInMiB).Distinct().OrderBy(x => x).ToList();

if (memory.Count == 0)
return _consoleUtilities.AskUserForValue("Select EC2 Instance Type:", instanceTypeDefaultValue ?? string.Empty, true);

var memoryCount = _consoleUtilities.AskUserToChoose(memory.Select(x => x.ToString()).ToList(), "Select EC2 Instance Memory:", "1024");

var availableInstanceTypes = instanceTypes
.Where(x => x.FreeTierEligible.Equals(freeTierEligible))
.Where(x => x.ProcessorInfo.SupportedArchitectures.Contains(architecture))
.Where(x => x.VCpuInfo.DefaultCores.Equals(cpuCoreCount))
.Where(x => x.MemoryInfo.SizeInMiB.Equals(long.Parse(memoryCount)))
.Select(x => x.InstanceType.Value).Distinct().OrderBy(x => x).ToList();

if (availableInstanceTypes.Count == 0)
return _consoleUtilities.AskUserForValue("Select EC2 Instance Type:", instanceTypeDefaultValue ?? string.Empty, true);

var userResponse = _consoleUtilities.AskUserToChoose(availableInstanceTypes, "Select EC2 Instance Type:", availableInstanceTypes.First());

return userResponse;
}
}
}
5 changes: 4 additions & 1 deletion src/AWS.Deploy.CLI/Commands/TypeHints/S3BucketNameCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
{
const string NO_VALUE = "*** Do not select bucket ***";
var currentValue = recommendation.GetOptionSettingValue(optionSetting);
var typeHintData = optionSetting.GetTypeHintData<S3BucketNameTypeHintData>();
var buckets = (await GetData()).Select(bucket => bucket.BucketName).ToList();

buckets.Add(NO_VALUE);
if (typeHintData?.AllowNoValue ?? false)
buckets.Add(NO_VALUE);

var userResponse = _consoleUtilities.AskUserToChoose(
values: buckets,
title: "Select a S3 bucket:",
Expand Down
4 changes: 3 additions & 1 deletion src/AWS.Deploy.CLI/Commands/TypeHints/SNSTopicArnsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
{
const string NO_VALUE = "*** Do not select topic ***";
var currentValue = recommendation.GetOptionSettingValue(optionSetting);
var typeHintData = optionSetting.GetTypeHintData<SNSTopicArnsTypeHintData>();
var currentValueStr = currentValue.ToString() ?? string.Empty;
var topicArns = await GetResources(recommendation, optionSetting);

Expand All @@ -43,7 +44,8 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
currentName = currentValueStr.Substring(currentValueStr.LastIndexOf(':') + 1);
}

topicNames.Add(NO_VALUE);
if (typeHintData?.AllowNoValue ?? false)
topicNames.Add(NO_VALUE);
var userResponse = _consoleUtilities.AskUserToChoose(
values: topicNames,
title: "Select a SNS topic:",
Expand Down
4 changes: 3 additions & 1 deletion src/AWS.Deploy.CLI/Commands/TypeHints/SQSQueueUrlCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
{
const string NO_VALUE = "*** Do not select queue ***";
var currentValue = recommendation.GetOptionSettingValue(optionSetting);
var typeHintData = optionSetting.GetTypeHintData<SQSQueueUrlTypeHintData>();
var currentValueStr = currentValue.ToString() ?? string.Empty;
var queueUrls = await GetResources(recommendation, optionSetting);

Expand All @@ -43,7 +44,8 @@ public async Task<object> Execute(Recommendation recommendation, OptionSettingIt
currentName = currentValueStr.Substring(currentValueStr.LastIndexOf('/') + 1);
}

queueNames.Add(NO_VALUE);
if (typeHintData?.AllowNoValue ?? false)
queueNames.Add(NO_VALUE);
var userResponse = _consoleUtilities.AskUserToChoose(
values: queueNames,
title: "Select a SQS queue:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,27 @@ public TypeHintCommandFactory(IToolInteractiveService toolInteractiveService, IA
_commands = new Dictionary<OptionSettingTypeHint, ITypeHintCommand>
{
{ OptionSettingTypeHint.BeanstalkApplication, new BeanstalkApplicationCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ExistingBeanstalkApplication, new BeanstalkApplicationCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.BeanstalkEnvironment, new BeanstalkEnvironmentCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.DotnetBeanstalkPlatformArn, new DotnetBeanstalkPlatformArnCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.EC2KeyPair, new EC2KeyPairCommand(toolInteractiveService, awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.IAMRole, new IAMRoleCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ExistingIAMRole, new IAMRoleCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.Vpc, new VpcCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ExistingVpc, new VpcCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.DotnetPublishAdditionalBuildArguments, new DotnetPublishArgsCommand(consoleUtilities) },
{ OptionSettingTypeHint.DotnetPublishSelfContainedBuild, new DotnetPublishSelfContainedBuildCommand(consoleUtilities) },
{ OptionSettingTypeHint.DotnetPublishBuildConfiguration, new DotnetPublishBuildConfigurationCommand(consoleUtilities) },
{ OptionSettingTypeHint.DockerExecutionDirectory, new DockerExecutionDirectoryCommand(consoleUtilities, directoryManager) },
{ OptionSettingTypeHint.DockerBuildArgs, new DockerBuildArgsCommand(consoleUtilities) },
{ OptionSettingTypeHint.ECSCluster, new ECSClusterCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ExistingECSCluster, new ECSClusterCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.ExistingApplicationLoadBalancer, new ExistingApplicationLoadBalancerCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.DynamoDBTableName, new DynamoDBTableCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.SQSQueueUrl, new SQSQueueUrlCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.SNSTopicArn, new SNSTopicArnsCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.S3BucketName, new S3BucketNameCommand(awsResourceQueryer, consoleUtilities) },
{ OptionSettingTypeHint.InstanceType, new InstanceTypeCommand(awsResourceQueryer, consoleUtilities) },
};
}

Expand Down
63 changes: 63 additions & 0 deletions src/AWS.Deploy.CLI/ConsoleUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ T AskUserToChoose<T>(IList<T> options, string title, T defaultValue, string? def
YesNo AskYesNoQuestion(string question, string? defaultValue);
YesNo AskYesNoQuestion(string question, YesNo? defaultValue = default);
void DisplayValues(Dictionary<string, object> objectValues, string indent);
Dictionary<string, string> AskUserForKeyValue(Dictionary<string, string> keyValue);
}

public class ConsoleUtilities : IConsoleUtilities
Expand Down Expand Up @@ -306,6 +307,68 @@ public string AskUserForValue(string message, string defaultValue, bool allowEmp
return userValue;
}

public Dictionary<string, string> AskUserForKeyValue(Dictionary<string, string> keyValue)
{
keyValue ??= new Dictionary<string, string>();

if (keyValue.Keys.Count == 0)
{
AskToAddKeyValuePair(keyValue);
return keyValue;
}

const string ADD = "Add new";
const string UPDATE = "Update existing";
const string DELETE = "Delete existing";
var operations = new List<string> { ADD, UPDATE, DELETE };

var selectedOperation = AskUserToChoose(operations, "Select which operation you want to perform:", ADD);

if(selectedOperation.Equals(ADD))
AskToAddKeyValuePair(keyValue);

if(selectedOperation.Equals(UPDATE))
AskToUpdateKeyValuePair(keyValue);

if(selectedOperation.Equals(DELETE))
AskToDeleteKeyValuePair(keyValue);

return keyValue;
}

private void AskToAddKeyValuePair(Dictionary<string, string> keyValue)
{
const string RESET = "<reset>";
var variableName = string.Empty;
while (string.IsNullOrEmpty(variableName))
{
_interactiveService.WriteLine("Enter the name:");
variableName = _interactiveService.ReadLine()?.Trim() ?? "";
}

_interactiveService.WriteLine($"Enter the value (type {RESET} to reset):");
var variableValue = _interactiveService.ReadLine()?.Trim() ?? "";
if (string.Equals(RESET, variableValue.Trim(), StringComparison.OrdinalIgnoreCase) ||
string.Equals($"'{RESET}'", variableValue.Trim(), StringComparison.OrdinalIgnoreCase))
variableValue = keyValue.ContainsKey(variableName) ? keyValue[variableName] : "";

keyValue[variableName] = variableValue;
}

private void AskToUpdateKeyValuePair(Dictionary<string, string> keyValue)
{
var selectedKey = AskUserToChoose(keyValue.Keys.ToList(), "Select the one you wish to update:", null);
var selectedValue = AskUserForValue("Enter the value:", keyValue[selectedKey], true);

keyValue[selectedKey] = selectedValue;
}

private void AskToDeleteKeyValuePair(Dictionary<string, string> keyValue)
{
var selectedKey = AskUserToChoose(keyValue.Keys.ToList(), "Select the one you wish to delete:", null);
keyValue.Remove(selectedKey);
}

public string AskForEC2KeyPairSaveDirectory(string projectPath)
{
_interactiveService.WriteLine("Enter a directory to save the newly created Key Pair: (avoid from using your project directory)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public void SetValueOverride(object valueOverride)
!AllowedValues.Contains(valueOverride.ToString() ?? ""))
throw new InvalidOverrideValueException(DeployToolErrorCode.InvalidValueForOptionSettingItem, $"Invalid value for option setting item '{Name}'");

if (valueOverride is bool || valueOverride is int || valueOverride is long || valueOverride is double)
if (valueOverride is bool || valueOverride is int || valueOverride is long || valueOverride is double || valueOverride is Dictionary<string, string>)
{
_valueOverride = valueOverride;
}
Expand Down
7 changes: 6 additions & 1 deletion src/AWS.Deploy.Common/Recipes/OptionSettingTypeHint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public enum OptionSettingTypeHint
DynamoDBTableName,
SQSQueueUrl,
SNSTopicArn,
S3BucketName
S3BucketName,
BeanstalkRollingUpdates,
ExistingIAMRole,
ExistingECSCluster,
ExistingVpc,
ExistingBeanstalkApplication
};
}
1 change: 1 addition & 0 deletions src/AWS.Deploy.Common/Recipes/OptionSettingValueType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum OptionSettingValueType
Int,
Double,
Bool,
KeyValue,
Object
};
}
Loading

0 comments on commit 49dde02

Please sign in to comment.