public string Build(CloudApplication cloudApplication, Recommendation recommendation) { // General Settings var appSettingsContainer = new RecipeConfiguration <Dictionary <string, object> >() { StackName = cloudApplication.StackName, ProjectPath = new FileInfo(recommendation.ProjectPath).Directory.FullName, ECRRepositoryName = recommendation.DeploymentBundle.ECRRepositoryName ?? "", ECRImageTag = recommendation.DeploymentBundle.ECRImageTag ?? "", DotnetPublishZipPath = recommendation.DeploymentBundle.DotnetPublishZipPath ?? "", DotnetPublishOutputDirectory = recommendation.DeploymentBundle.DotnetPublishOutputDirectory ?? "", Settings = new Dictionary <string, object>() }; appSettingsContainer.RecipeId = recommendation.Recipe.Id; appSettingsContainer.RecipeVersion = recommendation.Recipe.Version; // Option Settings foreach (var optionSetting in recommendation.Recipe.OptionSettings) { appSettingsContainer.Settings[optionSetting.Id] = recommendation.GetOptionSettingValue(optionSetting); } return(JsonConvert.SerializeObject(appSettingsContainer, Formatting.Indented)); }
public Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var settingValue = _consoleUtilities .AskUserForValue( string.Empty, recommendation.GetOptionSettingValue(optionSetting).ToString(), allowEmpty: true, resetValue: recommendation.GetOptionSettingDefaultValue <string>(optionSetting), // validators: publishArgs => (publishArgs.Contains("-o ") || publishArgs.Contains("--output ")) ? "You must not include -o/--output as an additional argument as it is used internally." : "", publishArgs => (publishArgs.Contains("-c ") || publishArgs.Contains("--configuration ") ? "You must not include -c/--configuration as an additional argument. You can set the build configuration in the advanced settings." : ""), publishArgs => (publishArgs.Contains("--self-contained") || publishArgs.Contains("--no-self-contained") ? "You must not include --self-contained/--no-self-contained as an additional argument. You can set the self-contained property in the advanced settings." : "")) .ToString() .Replace("\"", "\"\""); recommendation.DeploymentBundle.DotnetPublishAdditionalBuildArguments = settingValue; return(Task.FromResult <object>(settingValue)); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var currentValue = recommendation.GetOptionSettingValue(optionSetting); var applicationOptionSetting = recommendation.GetOptionSetting(optionSetting.ParentSettingId); var applicationName = recommendation.GetOptionSettingValue(applicationOptionSetting) as string; var environments = await _awsResourceQueryer.ListOfElasticBeanstalkEnvironments(_session, applicationName); var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew( options: environments.Select(env => env.EnvironmentName), title: "Select Elastic Beanstalk environment to deploy to:", askNewName: true, defaultNewName: currentValue.ToString()); return(userResponse.SelectedOption ?? userResponse.NewName); }
private async Task ConfigureDeployment(Recommendation recommendation, OptionSettingItem setting) { _toolInteractiveService.WriteLine(string.Empty); _toolInteractiveService.WriteLine($"{setting.Name}:"); _toolInteractiveService.WriteLine($"{setting.Description}"); var currentValue = recommendation.GetOptionSettingValue(setting); object settingValue = null; if (setting.AllowedValues?.Count > 0) { var userInputConfig = new UserInputConfiguration <string> { DisplaySelector = x => setting.ValueMapping[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 { if (setting.TypeHint.HasValue && _typeHintCommandFactory.GetCommand(setting.TypeHint.Value) is var typeHintCommand && typeHintCommand != null) { settingValue = await typeHintCommand.Execute(recommendation, setting); }
public Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var answer = _consoleUtilities.AskYesNoQuestion(string.Empty, recommendation.GetOptionSettingValue <string>(optionSetting)); recommendation.DeploymentBundle.DotnetPublishSelfContainedBuild = answer == YesNo.Yes; var result = answer == YesNo.Yes ? "true" : "false"; return(Task.FromResult <object>(result)); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var currentValue = recommendation.GetOptionSettingValue(optionSetting); var keyPairs = await _awsResourceQueryer.ListOfEC2KeyPairs(); var userInputConfiguration = new UserInputConfiguration <KeyPairInfo>( kp => kp.KeyName, kp => kp.KeyName.Equals(currentValue) ) { AskNewName = true, EmptyOption = true, CurrentValue = currentValue }; var settingValue = ""; while (true) { var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(keyPairs, "Select key pair to use:", userInputConfiguration); if (userResponse.IsEmpty) { settingValue = ""; break; } else { settingValue = userResponse.SelectedOption?.KeyName ?? userResponse.NewName ?? throw new UserPromptForNameReturnedNullException("The user prompt for a new EC2 Key Pair name was null or empty."); } if (userResponse.CreateNew && !string.IsNullOrEmpty(userResponse.NewName)) { _toolInteractiveService.WriteLine(string.Empty); _toolInteractiveService.WriteLine("You have chosen to create a new key pair."); _toolInteractiveService.WriteLine("You are required to specify a directory to save the key pair private key."); var answer = _consoleUtilities.AskYesNoQuestion("Do you want to continue?", "false"); if (answer == YesNo.No) { continue; } _toolInteractiveService.WriteLine(string.Empty); _toolInteractiveService.WriteLine($"A new key pair will be created with the name {settingValue}."); var keyPairDirectory = _consoleUtilities.AskForEC2KeyPairSaveDirectory(recommendation.ProjectPath); await _awsResourceQueryer.CreateEC2KeyPair(settingValue, keyPairDirectory); } break; } return(settingValue ?? ""); }
public Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var settingValue = _consoleUtilities.AskUserForValue( string.Empty, recommendation.GetOptionSettingValue <string>(optionSetting), allowEmpty: false, resetValue: recommendation.GetOptionSettingDefaultValue <string>(optionSetting) ?? ""); recommendation.DeploymentBundle.DotnetPublishBuildConfiguration = settingValue; return(Task.FromResult <object>(settingValue)); }
public Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var settingValue = _consoleUtilities .AskUserForValue( string.Empty, recommendation.GetOptionSettingValue <string>(optionSetting), allowEmpty: true, resetValue: recommendation.GetOptionSettingDefaultValue <string>(optionSetting) ?? "", validators: executionDirectory => ValidateExecutionDirectory(executionDirectory)); recommendation.DeploymentBundle.DockerExecutionDirectory = settingValue; return(Task.FromResult <object>(settingValue)); }
public async Task GenerateCDKProjectFromTemplate(Recommendation recommendation, OrchestratorSession session, string outputDirectory) { //The location of the base template that will be installed into the templating engine var cdkProjectTemplateDirectory = Path.Combine(Path.GetDirectoryName(recommendation.Recipe.RecipePath), recommendation.Recipe.CdkProjectTemplate); //Installing the base template into the templating engine to make it available for generation InstallTemplates(cdkProjectTemplateDirectory); //Looking up the installed template in the templating engine var template = _bootstrapper .ListTemplates( true, WellKnownSearchFilters.NameFilter(recommendation.Recipe.CdkProjectTemplateId)) .FirstOrDefault() ?.Info; //If the template is not found, throw an exception if (template == null) { throw new Exception($"Failed to find a Template for [{recommendation.Recipe.CdkProjectTemplateId}]"); } var templateParameters = new Dictionary <string, string> { { "AWSAccountID", session.AWSAccountId }, { "AWSRegion", session.AWSRegion }, // CDK Template projects can parameterize the version number of the AWS.Deploy.Recipes.CDK.Common package. This avoid // projects having to be modified every time the package version is bumped. { "AWSDeployRecipesCDKCommonVersion", FileVersionInfo.GetVersionInfo(typeof(CloudFormationIdentifierConstants).Assembly.Location).ProductVersion } }; foreach (var option in recommendation.Recipe.OptionSettings) { var currentValue = recommendation.GetOptionSettingValue(option); if (currentValue != null) { templateParameters[option.Id] = currentValue.ToString(); } } try { //Generate the CDK project using the installed template into the output directory await _bootstrapper.CreateAsync(template, recommendation.ProjectDefinition.AssemblyName, outputDirectory, templateParameters, false, ""); } catch { throw new TemplateGenerationFailedException(); } }
private void DisplayOptionSetting(Recommendation recommendation, OptionSettingItem optionSetting, int optionSettingNumber, int optionSettingsCount, DisplayOptionSettingsMode mode) { var value = recommendation.GetOptionSettingValue(optionSetting); Type typeHintResponseType = null; if (optionSetting.Type == OptionSettingValueType.Object) { var typeHintResponseTypeFullName = $"AWS.Deploy.CLI.TypeHintResponses.{optionSetting.TypeHint}TypeHintResponse"; typeHintResponseType = Assembly.GetExecutingAssembly().GetType(typeHintResponseTypeFullName); } DisplayValue(recommendation, optionSetting, optionSettingNumber, optionSettingsCount, typeHintResponseType, mode); }
public Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var settingValue = _consoleUtilities .AskUserForValue( string.Empty, recommendation.GetOptionSettingValue <string>(optionSetting), allowEmpty: true, resetValue: recommendation.GetOptionSettingDefaultValue <string>(optionSetting) ?? "", validators: buildArgs => ValidateBuildArgs(buildArgs)) .ToString() .Replace("\"", "\"\""); recommendation.DeploymentBundle.DockerBuildArgs = settingValue; return(Task.FromResult <object>(settingValue)); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var currentValue = recommendation.GetOptionSettingValue(optionSetting); var platformArns = await _awsResourceQueryer.GetElasticBeanstalkPlatformArns(_session); var userInputConfiguration = new UserInputConfiguration <PlatformSummary> { DisplaySelector = platform => $"{platform.PlatformBranchName} v{platform.PlatformVersion}", DefaultSelector = platform => platform.PlatformArn.Equals(currentValue), CreateNew = false }; var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(platformArns, "Select the Platform to use:", userInputConfiguration); return(userResponse.SelectedOption?.PlatformArn); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var loadBalancers = await _awsResourceQueryer.ListOfLoadBalancers(LoadBalancerTypeEnum.Application); var currentValue = recommendation.GetOptionSettingValue <string>(optionSetting); var userInputConfiguration = new UserInputConfiguration <LoadBalancer>( loadBalancer => loadBalancer.LoadBalancerName, loadBalancer => loadBalancer.LoadBalancerArn.Equals(currentValue)) { AskNewName = false }; var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(loadBalancers, "Select Load Balancer to deploy to:", userInputConfiguration); return(userResponse.SelectedOption?.LoadBalancerArn ?? string.Empty); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var typeHintData = optionSetting.GetTypeHintData <IAMRoleTypeHintData>(); var existingRoles = await _awsResourceQueryer.ListOfIAMRoles(typeHintData?.ServicePrincipal); var currentTypeHintResponse = recommendation.GetOptionSettingValue <IAMRoleTypeHintResponse>(optionSetting); var userInputConfiguration = new UserInputConfiguration <Role>( role => role.RoleName, role => currentTypeHintResponse.RoleArn?.Equals(role.Arn) ?? false); var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(existingRoles, "Select an IAM role", userInputConfiguration); return(new IAMRoleTypeHintResponse { CreateNew = userResponse.CreateNew, RoleArn = userResponse.SelectedOption?.Arn }); }
private List <OptionSettingItemSummary> ListOptionSettingSummary(Recommendation recommendation, IEnumerable <OptionSettingItem> configurableOptionSettings) { var optionSettingItems = new List <OptionSettingItemSummary>(); foreach (var setting in configurableOptionSettings) { var settingSummary = new OptionSettingItemSummary(setting.Id, setting.Name, setting.Description, setting.Type.ToString()) { TypeHint = setting.TypeHint?.ToString(), Value = recommendation.GetOptionSettingValue(setting), Advanced = setting.AdvancedSetting, Updatable = (!recommendation.IsExistingCloudApplication || setting.Updatable) && recommendation.IsOptionSettingDisplayable(setting), ChildOptionSettings = ListOptionSettingSummary(recommendation, setting.ChildOptionSettings) }; optionSettingItems.Add(settingSummary); } return(optionSettingItems); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var clusters = await _awsResourceQueryer.ListOfECSClusters(); var currentTypeHintResponse = recommendation.GetOptionSettingValue <ECSClusterTypeHintResponse>(optionSetting); var userInputConfiguration = new UserInputConfiguration <Cluster>( cluster => cluster.ClusterName, cluster => cluster.ClusterArn.Equals(currentTypeHintResponse?.ClusterArn), currentTypeHintResponse.NewClusterName) { AskNewName = true }; var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(clusters, "Select ECS cluster to deploy to:", userInputConfiguration); return(new ECSClusterTypeHintResponse( userResponse.CreateNew, userResponse.SelectedOption?.ClusterArn ?? string.Empty, userResponse.NewName ?? string.Empty)); }
public string Build(CloudApplication cloudApplication, Recommendation recommendation, OrchestratorSession session) { var projectPath = new FileInfo(recommendation.ProjectPath).Directory?.FullName; if (string.IsNullOrEmpty(projectPath)) { throw new InvalidProjectPathException("The project path provided is invalid."); } // General Settings var appSettingsContainer = new RecipeProps <Dictionary <string, object> >( cloudApplication.StackName, projectPath, recommendation.Recipe.Id, recommendation.Recipe.Version, session.AWSAccountId, session.AWSRegion, new () ) { ECRRepositoryName = recommendation.DeploymentBundle.ECRRepositoryName ?? "", ECRImageTag = recommendation.DeploymentBundle.ECRImageTag ?? "", DotnetPublishZipPath = recommendation.DeploymentBundle.DotnetPublishZipPath ?? "", DotnetPublishOutputDirectory = recommendation.DeploymentBundle.DotnetPublishOutputDirectory ?? "" }; // Option Settings foreach (var optionSetting in recommendation.Recipe.OptionSettings) { var optionSettingValue = recommendation.GetOptionSettingValue(optionSetting); if (optionSettingValue != null) { appSettingsContainer.Settings[optionSetting.Id] = optionSettingValue; } } return(JsonConvert.SerializeObject(appSettingsContainer, Formatting.Indented)); } }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var applications = await _awsResourceQueryer.ListOfElasticBeanstalkApplications(_session); var currentTypeHintResponse = recommendation.GetOptionSettingValue <BeanstalkApplicationTypeHintResponse>(optionSetting); var userInputConfiguration = new UserInputConfiguration <ApplicationDescription> { DisplaySelector = app => app.ApplicationName, DefaultSelector = app => app.ApplicationName.Equals(currentTypeHintResponse?.ApplicationName), AskNewName = true, DefaultNewName = currentTypeHintResponse.ApplicationName }; var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(applications, "Select Elastic Beanstalk application to deploy to:", userInputConfiguration); return(new BeanstalkApplicationTypeHintResponse { CreateNew = userResponse.CreateNew, ApplicationName = userResponse.SelectedOption?.ApplicationName ?? userResponse.NewName }); }
public async Task <object> Execute(Recommendation recommendation, OptionSettingItem optionSetting) { var applications = await _awsResourceQueryer.ListOfElasticBeanstalkApplications(); var currentTypeHintResponse = recommendation.GetOptionSettingValue <BeanstalkApplicationTypeHintResponse>(optionSetting); var userInputConfiguration = new UserInputConfiguration <ApplicationDescription>( app => app.ApplicationName, app => app.ApplicationName.Equals(currentTypeHintResponse?.ApplicationName), currentTypeHintResponse.ApplicationName) { 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("The user response for a new application name was null.") )); }
public void SetOptionSettingTests_AllowedValues() { _optionSetting.SetValueOverride(_optionSetting.AllowedValues.First()); Assert.Equal(_optionSetting.AllowedValues.First(), _recommendation.GetOptionSettingValue <string>(_optionSetting)); }
public async Task ExecuteAsync(bool saveCdkProject) { // Ensure a .NET project can be found. ProjectDefinition project = null; try { project = new ProjectDefinition(_session.ProjectPath); } catch (ProjectFileNotFoundException ex) { var files = Directory.GetFiles(_session.ProjectPath, "*.sln"); if (files.Any()) { _toolInteractiveService.WriteErrorLine($"This directory contains a solution file, but the tool requires a project file. Please run the tool from the directory that contains a .csproj/.fsproj or provide a path to the .csproj/.fsproj via --project-path flag."); } else { _toolInteractiveService.WriteErrorLine($"A project was not found at the path {_session.ProjectPath}"); } throw new FailedToFindDeployableTargetException(ex); } var orchestrator = new Orchestrator.Orchestrator( _session, _orchestratorInteractiveService, _cdkProjectHandler, _awsResourceQueryer, _deploymentBundleHandler, new[] { RecipeLocator.FindRecipeDefinitionsPath() }); // Determine what recommendations are possible for the project. var recommendations = await orchestrator.GenerateDeploymentRecommendations(); if (recommendations.Count == 0) { _toolInteractiveService.WriteLine(string.Empty); _toolInteractiveService.WriteErrorLine($"The project you are trying to deploy is currently not supported."); throw new FailedToGenerateAnyRecommendations(); } // Look to see if there are any existing deployed applications using any of the compatible recommendations. var existingApplications = await orchestrator.GetExistingDeployedApplications(recommendations); _toolInteractiveService.WriteLine(string.Empty); string cloudApplicationName; if (existingApplications.Count == 0) { var title = "Name the AWS stack to deploy your application to" + Environment.NewLine + "(A stack is a collection of AWS resources that you can manage as a single unit.)" + Environment.NewLine + "--------------------------------------------------------------------------------"; cloudApplicationName = _consoleUtilities.AskUserForValue( title, GetDefaultApplicationName(project.ProjectPath), allowEmpty: false); } else { var title = "Select the AWS stack to deploy your application to" + Environment.NewLine + "(A stack is a collection of AWS resources that you can manage as a single unit.)"; var userResponse = _consoleUtilities.AskUserToChooseOrCreateNew(existingApplications.Select(x => x.Name).ToList(), title, askNewName: true, defaultNewName: GetDefaultApplicationName(project.ProjectPath)); cloudApplicationName = userResponse.SelectedOption ?? userResponse.NewName; } var existingCloudApplication = existingApplications.FirstOrDefault(x => string.Equals(x.Name, cloudApplicationName)); Recommendation selectedRecommendation = null; _toolInteractiveService.WriteLine(string.Empty); // If using a previous deployment preset settings for deployment based on last deployment. if (existingCloudApplication != null) { var existingCloudApplicationMetadata = await orchestrator.LoadCloudApplicationMetadata(existingCloudApplication.Name); selectedRecommendation = recommendations.FirstOrDefault(x => string.Equals(x.Recipe.Id, existingCloudApplication.RecipeId, StringComparison.InvariantCultureIgnoreCase)); selectedRecommendation.ApplyPreviousSettings(existingCloudApplicationMetadata.Settings); var header = $"Loading {existingCloudApplication.Name} settings:"; _toolInteractiveService.WriteLine(header); _toolInteractiveService.WriteLine(new string('-', header.Length)); var optionSettings = selectedRecommendation .Recipe .OptionSettings .Where(x => { if (!selectedRecommendation.IsOptionSettingDisplayable(x)) { return(false); } var value = selectedRecommendation.GetOptionSettingValue(x); if (value == null || value.ToString() == string.Empty || object.Equals(value, x.DefaultValue)) { return(false); } return(true); }) .ToArray(); foreach (var setting in optionSettings) { DisplayOptionSetting(selectedRecommendation, setting, -1, optionSettings.Length, DisplayOptionSettingsMode.Readonly); } } else { selectedRecommendation = _consoleUtilities.AskToChooseRecommendation(recommendations); } // Apply the user enter project name to the recommendation so that any default settings based on project name are applied. selectedRecommendation.OverrideProjectName(cloudApplicationName); var systemCapabilities = await _session.SystemCapabilities; if (selectedRecommendation.Recipe.DeploymentType == DeploymentTypes.CdkProject && !systemCapabilities.NodeJsMinVersionInstalled) { _toolInteractiveService.WriteErrorLine("The selected deployment option requires Node.js 10.3 or later, which was not detected. Please install Node.js: https://nodejs.org/en/download/"); throw new MissingNodeJsException(); } if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.Container) { if (!systemCapabilities.DockerInfo.DockerInstalled) { _toolInteractiveService.WriteErrorLine("The selected deployment option requires Docker, which was not detected. Please install and start the appropriate version of Docker for you OS: https://docs.docker.com/engine/install/"); throw new MissingDockerException(); } if (!systemCapabilities.DockerInfo.DockerContainerType.Equals("linux", StringComparison.OrdinalIgnoreCase)) { _toolInteractiveService.WriteErrorLine("The deployment tool requires Docker to be running in linux mode. Please switch Docker to linux mode to continue."); throw new DockerContainerTypeException(); } } var deploymentBundleDefinition = orchestrator.GetDeploymentBundleDefinition(selectedRecommendation); var configurableOptionSettings = selectedRecommendation.Recipe.OptionSettings.Union(deploymentBundleDefinition.Parameters); await ConfigureDeployment(selectedRecommendation, configurableOptionSettings, false); var cloudApplication = new CloudApplication { Name = cloudApplicationName }; if (!ConfirmDeployment(selectedRecommendation)) { return; } await CreateDeploymentBundle(orchestrator, selectedRecommendation, cloudApplication); await orchestrator.DeployRecommendation(cloudApplication, selectedRecommendation); }