コード例 #1
0
        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));
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
                }
コード例 #5
0
        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));
        }
コード例 #6
0
        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));
        }
コード例 #8
0
        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));
        }
コード例 #9
0
        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();
            }
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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);
        }
コード例 #13
0
        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);
        }
コード例 #14
0
        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
            });
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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));
        }
コード例 #17
0
        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));
        }
    }
コード例 #18
0
        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
            });
        }
コード例 #19
0
        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.")
                       ));
        }
コード例 #20
0
        public void SetOptionSettingTests_AllowedValues()
        {
            _optionSetting.SetValueOverride(_optionSetting.AllowedValues.First());

            Assert.Equal(_optionSetting.AllowedValues.First(), _recommendation.GetOptionSettingValue <string>(_optionSetting));
        }
コード例 #21
0
        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);
        }