Exemple #1
0
        internal string Execute()
        {
            _toolInteractiveService.WriteLine();
            _toolInteractiveService.WriteLine($"Enter MFA code for {_options.MfaSerialNumber}: ");
            var consoleUtilites = new ConsoleUtilities(_toolInteractiveService, _directoryManager);
            var code            = consoleUtilites.ReadSecretFromConsole();

            return(code);
        }
Exemple #2
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 ?? "");
        }
Exemple #3
0
        /// <summary>
        /// This method takes a user specified directory path and generates the CDK deployment project at this location.
        /// If the provided directory path is an empty string, then a default directory is created to save the CDK deployment project.
        /// </summary>
        /// <param name="saveCdkDirectoryPath">An absolute or a relative path provided by the user.</param>
        /// <param name="projectDisplayName">The name of the deployment project that will be displayed in the list of available deployment options.</param>
        /// <returns></returns>
        public async Task ExecuteAsync(string saveCdkDirectoryPath, string projectDisplayName)
        {
            var orchestrator    = new Orchestrator(_session, new[] { RecipeLocator.FindRecipeDefinitionsPath() });
            var recommendations = await GenerateRecommendationsToSaveDeploymentProject(orchestrator);

            var selectedRecommendation = _consoleUtilities.AskToChooseRecommendation(recommendations);

            if (string.IsNullOrEmpty(saveCdkDirectoryPath))
            {
                saveCdkDirectoryPath = GenerateDefaultSaveDirectoryPath();
            }

            var newDirectoryCreated = CreateSaveCdkDirectory(saveCdkDirectoryPath);

            var(isValid, errorMessage) = ValidateSaveCdkDirectory(saveCdkDirectoryPath);
            if (!isValid)
            {
                if (newDirectoryCreated)
                {
                    _directoryManager.Delete(saveCdkDirectoryPath);
                }
                errorMessage = $"Failed to generate deployment project.{Environment.NewLine}{errorMessage}";
                throw new InvalidSaveDirectoryForCdkProject(errorMessage.Trim());
            }

            var directoryUnderSourceControl = await IsDirectoryUnderSourceControl(saveCdkDirectoryPath);

            if (!directoryUnderSourceControl)
            {
                var userPrompt = "Warning: The target directory is not being tracked by source control. If the saved deployment " +
                                 "project is used for deployment it is important that the deployment project is retained to allow " +
                                 "future redeployments to previously deployed applications. " + Environment.NewLine + Environment.NewLine +
                                 "Do you still want to continue?";

                _toolInteractiveService.WriteLine();
                var yesNoResult = _consoleUtilities.AskYesNoQuestion(userPrompt, YesNo.Yes);

                if (yesNoResult == YesNo.No)
                {
                    if (newDirectoryCreated)
                    {
                        _directoryManager.Delete(saveCdkDirectoryPath);
                    }
                    return;
                }
            }

            _cdkProjectHandler.CreateCdkProject(selectedRecommendation, _session, saveCdkDirectoryPath);
            await GenerateDeploymentRecipeSnapShot(selectedRecommendation, saveCdkDirectoryPath, projectDisplayName);

            var saveCdkDirectoryFullPath = _directoryManager.GetDirectoryInfo(saveCdkDirectoryPath).FullName;

            _toolInteractiveService.WriteLine();
            _toolInteractiveService.WriteLine($"The CDK deployment project is saved at: {saveCdkDirectoryFullPath}");

            await _deploymentManifestEngine.UpdateDeploymentManifestFile(saveCdkDirectoryFullPath, _targetApplicationFullPath);
        }
        public async Task ExecuteAsync()
        {
            // Add Header
            _interactiveService.WriteLine();
            _interactiveService.WriteLine("Cloud Applications:");
            _interactiveService.WriteLine("-------------------");

            var existingApplications = await _deployedApplicationQueryer.GetExistingDeployedApplications();

            foreach (var app in existingApplications)
            {
                _interactiveService.WriteLine(app.Name);
            }
        }
        /// <summary>
        /// Deletes given CloudFormation stack
        /// </summary>
        /// <param name="stackName">The stack name to be deleted</param>
        /// <exception cref="FailedToDeleteException">Thrown when deletion fails</exception>
        public async Task ExecuteAsync(string stackName)
        {
            var canDelete = await CanDeleteAsync(stackName);

            if (!canDelete)
            {
                return;
            }

            var confirmDelete = _consoleUtilities.AskYesNoQuestion($"Are you sure you want to delete {stackName}?", YesNo.No);

            if (confirmDelete == YesNo.No)
            {
                return;
            }

            _interactiveService.WriteLine($"{stackName}: deleting...");
            var monitor = new StackEventMonitor(stackName, _awsClientFactory, _consoleUtilities);

            try
            {
                await _cloudFormationClient.DeleteStackAsync(new DeleteStackRequest
                {
                    StackName = stackName
                });

                // Fire and forget the monitor
                // Monitor updates the stdout with current status of the CloudFormation stack
                var _ = monitor.StartAsync();

                await WaitForStackDelete(stackName);

                if (_session != null)
                {
                    await _localUserSettingsEngine.DeleteLastDeployedStack(stackName, _session.ProjectDefinition.ProjectName, _session.AWSAccountId, _session.AWSRegion);
                }

                _interactiveService.WriteLine($"{stackName}: deleted");
            }
            finally
            {
                // Stop monitoring CloudFormation stack status once the deletion operation finishes
                monitor.Stop();
            }
        }
Exemple #6
0
        public async Task <int> Run(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            SetExecutionEnvironment();

            _toolInteractiveService.WriteLine("AWS .NET deployment tool for deploying .NET Core applications to AWS.");
            _toolInteractiveService.WriteLine("Project Home: https://github.com/aws/aws-dotnet-deploy");
            _toolInteractiveService.WriteLine(string.Empty);

            // if user didn't specify a command, default to help
            if (args.Length == 0)
            {
                args = new[] { "-h" };
            }

            return(await _commandFactory.BuildRootCommand().InvokeAsync(args));
        }
Exemple #7
0
        /// <summary>
        /// Deletes given CloudFormation stack
        /// </summary>
        /// <param name="stackName">The stack name to be deleted</param>
        /// <exception cref="FailedToDeleteException">Thrown when deletion fails</exception>
        public async Task ExecuteAsync(string stackName)
        {
            var canDelete = await CanDeleteAsync(stackName);

            if (!canDelete)
            {
                return;
            }

            var confirmDelete = _consoleUtilities.AskYesNoQuestion($"Are you sure you want to delete {stackName}?", ConsoleUtilities.YesNo.No);

            if (confirmDelete == ConsoleUtilities.YesNo.No)
            {
                return;
            }

            _interactiveService.WriteLine($"{stackName}: deleting...");
            var monitor = new StackEventMonitor(stackName, _awsClientFactory, _interactiveService, _session);

            try
            {
                await _cloudFormationClient.DeleteStackAsync(new DeleteStackRequest
                {
                    StackName = stackName
                });

                // Fire and forget the monitor
                // Monitor updates the stdout with current status of the CloudFormation stack
                var _ = monitor.StartAsync();

                await WaitForStackDelete(stackName);

                _interactiveService.WriteLine($"{stackName}: deleted");
            }
            catch (AmazonCloudFormationException)
            {
                throw new FailedToDeleteException($"Failed to delete {stackName} stack.");
            }
            finally
            {
                // Stop monitoring CloudFormation stack status once the deletion operation finishes
                monitor.Stop();
            }
        }
Exemple #8
0
        public async Task <AWSCredentials> ResolveAWSCredentials(string profileName, string lastUsedProfileName)
        {
            AWSCredentials credentials;

            var chain = new CredentialProfileStoreChain();

            if (!string.IsNullOrEmpty(profileName))
            {
                if (chain.TryGetAWSCredentials(profileName, out credentials) &&
                    await CanLoadCredentials(credentials))
                {
                    _toolInteractiveService.WriteLine($"Configuring AWS Credentials from Profile {profileName}.");
                    return(credentials);
                }
            }

            if (!string.IsNullOrEmpty(lastUsedProfileName) &&
                chain.TryGetAWSCredentials(lastUsedProfileName, out credentials) &&
                await CanLoadCredentials(credentials))
            {
                _toolInteractiveService.WriteLine($"Configuring AWS Credentials with previous configured profile value {lastUsedProfileName}.");
                return(credentials);
            }

            try
            {
                credentials = FallbackCredentialsFactory.GetCredentials();

                if (await CanLoadCredentials(credentials))
                {
                    _toolInteractiveService.WriteLine("Configuring AWS Credentials using AWS SDK credential search.");
                    return(credentials);
                }
            }
            catch (AmazonServiceException)
            {
                // FallbackCredentialsFactory throws an exception if no credentials are found. Burying exception because if no credentials are found
                // we want to continue and ask the user to select a profile.
            }

            var sharedCredentials = new SharedCredentialsFile();

            if (sharedCredentials.ListProfileNames().Count == 0)
            {
                _toolInteractiveService.WriteErrorLine("Unable to resolve AWS credentials to access AWS.");
                throw new NoAWSCredentialsFoundException();
            }

            var consoleUtilities    = new ConsoleUtilities(_toolInteractiveService);
            var selectedProfileName = consoleUtilities.AskUserToChoose(sharedCredentials.ListProfileNames(), "Select AWS Credentials Profile", null);

            if (!chain.TryGetAWSCredentials(selectedProfileName, out credentials) ||
                !(await CanLoadCredentials(credentials)))
            {
                _toolInteractiveService.WriteErrorLine($"Unable to create AWS credentials for profile {selectedProfileName}.");
                throw new NoAWSCredentialsFoundException();
            }

            return(credentials);
        }
Exemple #9
0
        public async Task ExecuteAsync()
        {
            var orchestrator =
                new Orchestrator.Orchestrator(
                    _session,
                    _orchestratorInteractiveService,
                    _cdkProjectHandler,
                    _awsResourceQueryer,
                    _deploymentBundleHandler,
                    new[] { RecipeLocator.FindRecipeDefinitionsPath() });

            // Add Header
            _interactiveService.WriteLine();
            _interactiveService.WriteLine("Cloud Applications:");
            _interactiveService.WriteLine("-------------------");

            var existingApplications = await orchestrator.GetExistingDeployedApplications();

            foreach (var app in existingApplications)
            {
                _interactiveService.WriteLine(app.Name);
            }
        }
        public async Task ExecuteAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            _interactiveService.WriteLine("Server mode is an experimental feature being developed to allow communication between this CLI and the AWS Toolkit for Visual Studio. Expect behavior changes and API changes as server mode is being developed.");

            IEncryptionProvider encryptionProvider = CreateEncryptionProvider();

            if (IsPortInUse(_port))
            {
                throw new TcpPortInUseException("The port you have selected is currently in use by another process.");
            }

            var url = $"http://localhost:{_port}";

            var builder = new WebHostBuilder()
                          .UseKestrel()
                          .UseUrls(url)
                          .ConfigureServices(services =>
            {
                services.AddSingleton <IEncryptionProvider>(encryptionProvider);
            })
                          .UseStartup <Startup>();

            var host = builder.Build();

            if (_parentPid == null)
            {
                await host.RunAsync(cancellationToken);
            }
            else
            {
                try
                {
                    var process = Process.GetProcessById((int)_parentPid);
                    process.EnableRaisingEvents = true;
                    process.Exited += async(sender, args) => { await ShutDownHost(host, cancellationToken); };
                }
                catch (Exception)
                {
                    return;
                }

                await host.RunAsync(cancellationToken);
            }
        }
 public static void WriteLine(this IToolInteractiveService service)
 {
     service.WriteLine(string.Empty);
 }
Exemple #12
0
        public Recommendation AskToChooseRecommendation(IList <Recommendation> recommendations)
        {
            if (recommendations.Count == 0)
            {
                // This should never happen as application should have aborted sooner if there was no valid recommendations.
                throw new Exception("No recommendations available for user to select");
            }

            _interactiveService.WriteLine("Recommended Deployment Option");
            _interactiveService.WriteLine("-----------------------------");
            _interactiveService.WriteLine($"1: {recommendations[0].Name}");
            _interactiveService.WriteLine(recommendations[0].Description);

            _interactiveService.WriteLine(string.Empty);

            if (recommendations.Count > 1)
            {
                _interactiveService.WriteLine("Additional Deployments Options");
                _interactiveService.WriteLine("------------------------------");
                for (var index = 1; index < recommendations.Count; index++)
                {
                    _interactiveService.WriteLine($"{index + 1}: {recommendations[index].Name}");
                    _interactiveService.WriteLine(recommendations[index].Description);
                    _interactiveService.WriteLine(string.Empty);
                }
            }

            _interactiveService.WriteLine($"Choose deployment option (recommended default: 1)");

            return(ReadOptionFromUser(recommendations, 1));
        }
        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);
        }
Exemple #14
0
 public void LogMessageLine(string?message)
 {
     _interactiveService.WriteLine(message);
 }
Exemple #15
0
        public async Task <AWSCredentials> ResolveAWSCredentials(string?profileName, string?lastUsedProfileName = null)
        {
            async Task <AWSCredentials> Resolve()
            {
                var chain = new CredentialProfileStoreChain();

                if (!string.IsNullOrEmpty(profileName) && chain.TryGetAWSCredentials(profileName, out var profileCredentials) &&
                    // Skip checking CanLoadCredentials for AssumeRoleAWSCredentials because it might require an MFA token and the callback hasn't been setup yet.
                    (profileCredentials is AssumeRoleAWSCredentials || await CanLoadCredentials(profileCredentials)))
                {
                    _toolInteractiveService.WriteLine($"Configuring AWS Credentials from Profile {profileName}.");
                    return(profileCredentials);
                }

                if (!string.IsNullOrEmpty(lastUsedProfileName) &&
                    chain.TryGetAWSCredentials(lastUsedProfileName, out var lastUsedCredentials) &&
                    await CanLoadCredentials(lastUsedCredentials))
                {
                    _toolInteractiveService.WriteLine($"Configuring AWS Credentials with previous configured profile value {lastUsedProfileName}.");
                    return(lastUsedCredentials);
                }

                try
                {
                    var fallbackCredentials = FallbackCredentialsFactory.GetCredentials();

                    if (await CanLoadCredentials(fallbackCredentials))
                    {
                        _toolInteractiveService.WriteLine("Configuring AWS Credentials using AWS SDK credential search.");
                        return(fallbackCredentials);
                    }
                }
                catch (AmazonServiceException)
                {
                    // FallbackCredentialsFactory throws an exception if no credentials are found. Burying exception because if no credentials are found
                    // we want to continue and ask the user to select a profile.
                }

                var sharedCredentials = new SharedCredentialsFile();

                if (sharedCredentials.ListProfileNames().Count == 0)
                {
                    throw new NoAWSCredentialsFoundException("Unable to resolve AWS credentials to access AWS.");
                }

                var selectedProfileName = _consoleUtilities.AskUserToChoose(sharedCredentials.ListProfileNames(), "Select AWS Credentials Profile", null);

                if (chain.TryGetAWSCredentials(selectedProfileName, out var selectedProfileCredentials) &&
                    (await CanLoadCredentials(selectedProfileCredentials)))
                {
                    return(selectedProfileCredentials);
                }

                throw new NoAWSCredentialsFoundException($"Unable to create AWS credentials for profile {selectedProfileName}.");
            }

            var credentials = await Resolve();

            if (credentials is AssumeRoleAWSCredentials assumeRoleAWSCredentials)
            {
                var assumeOptions = assumeRoleAWSCredentials.Options;
                assumeOptions.MfaTokenCodeCallback = new AssumeRoleMfaTokenCodeCallback(_toolInteractiveService, _directoryManager, assumeOptions).Execute;
            }

            return(credentials);
        }
Exemple #16
0
 private void DisplayOutputResources(List <DisplayedResourceItem> displayedResourceItems)
 {
     _toolInteractiveService.WriteLine("Resources");
     _toolInteractiveService.WriteLine("---------");
     foreach (var resource in displayedResourceItems)
     {
         _toolInteractiveService.WriteLine($"{resource.Description}:");
         _toolInteractiveService.WriteLine($"\t{nameof(resource.Id)}: {resource.Id}");
         _toolInteractiveService.WriteLine($"\t{nameof(resource.Type)}: {resource.Type}");
         foreach (var resourceKey in resource.Data.Keys)
         {
             _toolInteractiveService.WriteLine($"\t{resourceKey}: {resource.Data[resourceKey]}");
         }
     }
 }