Exemple #1
0
        /// <summary>
        /// Retrieves the displayed resource data for known resource types by executing specific resource commands.
        /// For unknown resource types, this returns the physical resource ID and type.
        /// </summary>
        public async Task <List <DisplayedResourceItem> > GetDeploymentOutputs(CloudApplication cloudApplication, Recommendation recommendation)
        {
            var displayedResources = new List <DisplayedResourceItem>();

            if (recommendation.Recipe.DisplayedResources == null)
            {
                return(displayedResources);
            }

            var resources = await _awsResourceQueryer.DescribeCloudFormationResources(cloudApplication.StackName);

            foreach (var displayedResource in recommendation.Recipe.DisplayedResources)
            {
                var resource = resources.FirstOrDefault(x => x.LogicalResourceId.Equals(displayedResource.LogicalId));
                if (resource == null)
                {
                    continue;
                }

                var data = new Dictionary <string, string>();
                if (!string.IsNullOrEmpty(resource.ResourceType) && _displayedResourcesFactory.GetResource(resource.ResourceType) is var displayedResourceCommand && displayedResourceCommand != null)
                {
                    data = await displayedResourceCommand.Execute(resource.PhysicalResourceId);
                }
                displayedResources.Add(new DisplayedResourceItem(resource.PhysicalResourceId, displayedResource.Description, resource.ResourceType, data));
            }

            return(displayedResources);
        }
        public async Task <string> ConfigureCdkProject(OrchestratorSession session, CloudApplication cloudApplication, Recommendation recommendation)
        {
            string?cdkProjectPath;

            if (recommendation.Recipe.PersistedDeploymentProject)
            {
                if (string.IsNullOrEmpty(recommendation.Recipe.RecipePath))
                {
                    throw new InvalidOperationException($"{nameof(recommendation.Recipe.RecipePath)} cannot be null");
                }

                // The CDK deployment project is already saved in the same directory.
                cdkProjectPath = _directoryManager.GetDirectoryInfo(recommendation.Recipe.RecipePath).Parent.FullName;
            }
            else
            {
                // Create a new temporary CDK project for a new deployment
                _interactiveService.LogMessageLine($"Generating a {recommendation.Recipe.Name} CDK Project");
                cdkProjectPath = CreateCdkProject(recommendation, session);
            }

            // Write required configuration in appsettings.json
            var appSettingsBody     = _appSettingsBuilder.Build(cloudApplication, recommendation, session);
            var appSettingsFilePath = Path.Combine(cdkProjectPath, "appsettings.json");

            await using var appSettingsFile = new StreamWriter(appSettingsFilePath);
            await appSettingsFile.WriteAsync(appSettingsBody);

            return(cdkProjectPath);
        }
Exemple #3
0
        public async Task <string> BuildDockerImage(CloudApplication cloudApplication, Recommendation recommendation)
        {
            _interactiveService.LogMessageLine(string.Empty);
            _interactiveService.LogMessageLine("Building the docker image...");

            var dockerExecutionDirectory = GetDockerExecutionDirectory(recommendation);
            var tagSuffix  = DateTime.UtcNow.Ticks;
            var imageTag   = $"{cloudApplication.StackName.ToLower()}:{tagSuffix}";
            var dockerFile = GetDockerFilePath(recommendation);
            var buildArgs  = GetDockerBuildArgs(recommendation);

            var dockerBuildCommand = $"docker build -t {imageTag} -f \"{dockerFile}\"{buildArgs} .";

            _interactiveService.LogMessageLine($"Docker Execution Directory: {Path.GetFullPath(dockerExecutionDirectory)}");
            _interactiveService.LogMessageLine($"Docker Build Command: {dockerBuildCommand}");


            recommendation.DeploymentBundle.DockerExecutionDirectory = dockerExecutionDirectory;

            var result = await _commandLineWrapper.TryRunWithResult(dockerBuildCommand, dockerExecutionDirectory, redirectIO : false);

            if (result.ExitCode != 0)
            {
                throw new DockerBuildFailedException(result.StandardError ?? "");
            }

            return(imageTag);
        }
Exemple #4
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));
        }
        public async Task <bool> CreateContainerDeploymentBundle(CloudApplication cloudApplication, Recommendation recommendation)
        {
            var dockerEngine =
                new DockerEngine.DockerEngine(
                    new ProjectDefinition(recommendation.ProjectPath));

            if (!recommendation.ProjectDefinition.HasDockerFile)
            {
                _interactiveService.LogMessageLine("Generating Dockerfile...");
                dockerEngine.GenerateDockerFile();
            }

            dockerEngine.DetermineDockerExecutionDirectory(recommendation);

            try
            {
                var imageTag = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

                await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, imageTag);
            }
            catch (DockerBuildFailedException ex)
            {
                _interactiveService.LogErrorMessageLine("We were unable to build the docker image due to the following error:");
                _interactiveService.LogErrorMessageLine(ex.Message);
                _interactiveService.LogErrorMessageLine("Docker builds usually fail due to executing them from a working directory that is incompatible with the Dockerfile.");
                _interactiveService.LogErrorMessageLine("You can try setting the 'Docker Execution Directory' in the option settings.");
                return(false);
            }

            return(true);
        }
Exemple #6
0
        public IActionResult Add()
        {
            var application = new CloudApplication
            {
                Icon = "cloud"
            };

            application.Icon = "cloud";
            return(View(ResponseModel.Success(data: application)));
        }
        public async Task PushDockerImage_RepositoryNameCheck()
        {
            var projectPath = SystemIOUtilities.ResolvePath("ConsoleAppTask");
            var project     = await _projectDefinitionParser.Parse(projectPath);

            var recommendation = new Recommendation(_recipeDefinition, project, new List <OptionSettingItem>(), 100, new Dictionary <string, string>());

            var cloudApplication = new CloudApplication("ConsoleAppTask", String.Empty);
            await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, "ConsoleAppTask:latest");

            Assert.Equal(cloudApplication.StackName.ToLower(), recommendation.DeploymentBundle.ECRRepositoryName);
        }
 public DisplayedResourcesHandlerTests()
 {
     _mockAWSResourceQueryer    = new Mock <IAWSResourceQueryer>();
     _cloudApplication          = new CloudApplication("StackName", "RecipeId");
     _displayedResourcesFactory = new DisplayedResourceCommandFactory(_mockAWSResourceQueryer.Object);
     _stackResource             = new StackResource();
     _stackResources            = new List <StackResource>()
     {
         _stackResource
     };
     _environmentDescription = new EnvironmentDescription();
     _loadBalancer           = new LoadBalancer();
 }
Exemple #9
0
        /// <summary>
        /// Configure option setings using the CLI or a user provided configuration file.
        /// </summary>
        /// <param name="cloudApplication"><see cref="CloudApplication"/></param>
        /// <param name="orchestrator"><see cref="Orchestrator"/></param>
        /// <param name="selectedRecommendation"><see cref="Recommendation"/></param>
        /// <param name="userDeploymentSettings"><see cref="UserDeploymentSettings"/></param>
        public async Task ConfigureDeployment(CloudApplication cloudApplication, Orchestrator orchestrator, Recommendation selectedRecommendation, UserDeploymentSettings?userDeploymentSettings)
        {
            var configurableOptionSettings = selectedRecommendation.GetConfigurableOptionSettingItems();

            if (userDeploymentSettings != null)
            {
                ConfigureDeploymentFromConfigFile(selectedRecommendation, userDeploymentSettings);
            }

            if (!_toolInteractiveService.DisableInteractive)
            {
                await ConfigureDeploymentFromCli(selectedRecommendation, configurableOptionSettings, false);
            }
        }
        public async Task DockerExecutionDirectory_DockerfileLevel()
        {
            var projectPath = Path.Combine("docker", "WebAppNoSolution");
            var engine      = await BuildRecommendationEngine(projectPath);

            var recommendations = await engine.ComputeRecommendations();

            var recommendation = recommendations.FirstOrDefault(x => x.Recipe.DeploymentBundle.Equals(DeploymentBundleTypes.Container));

            var cloudApplication = new CloudApplication("WebAppNoSolution", String.Empty);
            var result           = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

            Assert.Equal(Path.GetFullPath(SystemIOUtilities.ResolvePath(projectPath)), recommendation.DeploymentBundle.DockerExecutionDirectory);
        }
Exemple #11
0
        public async Task PushDockerImage_RepositoryNameCheck()
        {
            var projectPath       = SystemIOUtilities.ResolvePath("ConsoleAppTask");
            var projectDefinition = new ProjectDefinition(projectPath);
            var recipeDefinition  = new Mock <RecipeDefinition>();
            var recommendation    = new Recommendation(recipeDefinition.Object, projectDefinition.ProjectPath, 100, new Dictionary <string, string>());

            var cloudApplication = new CloudApplication {
                Name = "ConsoleAppTask"
            };
            await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, "ConsoleAppTask:latest");

            Assert.Equal(cloudApplication.StackName.ToLower(), recommendation.DeploymentBundle.ECRRepositoryName);
        }
Exemple #12
0
        public async Task DockerExecutionDirectory_DockerfileLevel()
        {
            var projectPath = SystemIOUtilities.ResolvePath("docker\\WebAppNoSolution");
            var engine      = new RecommendationEngine(new[] { RecipeLocator.FindRecipeDefinitionsPath() }, _session);

            var recommendations = await engine.ComputeRecommendations(projectPath, new());

            var recommendation = recommendations.FirstOrDefault(x => x.Recipe.DeploymentBundle.Equals(DeploymentBundleTypes.Container));

            var cloudApplication = new CloudApplication {
                Name = "WebAppNoSolution"
            };
            var result = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

            Assert.Equal(Path.GetFullPath(projectPath), recommendation.DeploymentBundle.DockerExecutionDirectory);
        }
        public async Task <bool> CreateContainerDeploymentBundle(CloudApplication cloudApplication, Recommendation recommendation)
        {
            if (_interactiveService == null)
            {
                throw new InvalidOperationException($"{nameof(_recipeDefinitionPaths)} is null as part of the orchestartor object");
            }
            if (_dockerEngine == null)
            {
                throw new InvalidOperationException($"{nameof(_dockerEngine)} is null as part of the orchestartor object");
            }
            if (_deploymentBundleHandler == null)
            {
                throw new InvalidOperationException($"{nameof(_deploymentBundleHandler)} is null as part of the orchestartor object");
            }

            if (!recommendation.ProjectDefinition.HasDockerFile)
            {
                _interactiveService.LogMessageLine("Generating Dockerfile...");
                try
                {
                    _dockerEngine.GenerateDockerFile();
                }
                catch (DockerEngineExceptionBase ex)
                {
                    throw new FailedToGenerateDockerFileException("Failed to generate a docker file", ex);
                }
            }

            _dockerEngine.DetermineDockerExecutionDirectory(recommendation);

            try
            {
                var imageTag = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

                await _deploymentBundleHandler.PushDockerImageToECR(cloudApplication, recommendation, imageTag);
            }
            catch (DockerBuildFailedException ex)
            {
                _interactiveService.LogErrorMessageLine("We were unable to build the docker image due to the following error:");
                _interactiveService.LogErrorMessageLine(ex.Message);
                _interactiveService.LogErrorMessageLine("Docker builds usually fail due to executing them from a working directory that is incompatible with the Dockerfile.");
                _interactiveService.LogErrorMessageLine("You can try setting the 'Docker Execution Directory' in the option settings.");
                return(false);
            }

            return(true);
        }
        public async Task BuildDockerImage_DockerExecutionDirectoryNotSet()
        {
            var projectPath = SystemIOUtilities.ResolvePath("ConsoleAppTask");
            var project     = await _projectDefinitionParser.Parse(projectPath);

            var recommendation = new Recommendation(_recipeDefinition, project, new List <OptionSettingItem>(), 100, new Dictionary <string, string>());

            var cloudApplication = new CloudApplication("ConsoleAppTask", String.Empty);
            var result           = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

            var dockerFile = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(recommendation.ProjectPath)), "Dockerfile");
            var dockerExecutionDirectory = Directory.GetParent(Path.GetFullPath(recommendation.ProjectPath)).Parent.Parent;

            Assert.Equal($"docker build -t {result} -f \"{dockerFile}\" .",
                         _commandLineWrapper.CommandsToExecute.First().Command);
            Assert.Equal(dockerExecutionDirectory.FullName,
                         _commandLineWrapper.CommandsToExecute.First().WorkingDirectory);
        }
Exemple #15
0
        public async Task PushDockerImageToECR(CloudApplication cloudApplication, Recommendation recommendation, string sourceTag)
        {
            _interactiveService.LogMessageLine(string.Empty);
            _interactiveService.LogMessageLine("Pushing the docker image to ECR repository...");

            await InitiateDockerLogin();

            var tagSuffix  = sourceTag.Split(":")[1];
            var repository = await SetupECRRepository(cloudApplication.StackName.ToLower());

            var targetTag = $"{repository.RepositoryUri}:{tagSuffix}";

            await TagDockerImage(sourceTag, targetTag);

            await PushDockerImage(targetTag);

            recommendation.DeploymentBundle.ECRRepositoryName = repository.RepositoryName;
            recommendation.DeploymentBundle.ECRImageTag       = tagSuffix;
        }
Exemple #16
0
        public IActionResult UpdateLogic(CloudApplication entity)
        {
            var result = Result.Success()
                         .ContinueEnsureArgumentNotNullOrEmpty(entity, nameof(entity))
                         .ContinueEnsureArgumentNotNullOrEmpty(entity.Name, nameof(entity.Name))
                         .ContinueAssert(_ => entity.Id != Guid.Empty, "Id Can Not Be Null")
                         .Continue(_ =>
            {
                entity.ModifyBy = CurrentUserId;
                return(_applicationService.UpdateWithOutCode(entity));
            });

            if (!result.IsSuccess)
            {
                return(View("Update", result.ToResponseModel(entity)));
            }

            return(RedirectToAction("List"));
        }
Exemple #17
0
        public IActionResult AddLogic(CloudApplication entity)
        {
            var result = Result.Success()
                         .ContinueEnsureArgumentNotNullOrEmpty(entity, nameof(entity))
                         .ContinueEnsureArgumentNotNullOrEmpty(entity.Name, nameof(entity.Name))
                         .ContinueEnsureArgumentNotNullOrEmpty(entity.Code, nameof(entity.Code))
                         .ContinueAssert(_ => entity.Code.IsAlnum(2, 50), "编码不合法,2-50位且只能包含字母和数字(字母开头)")
                         .Continue(_ =>
            {
                entity.CreateBy = CurrentUserId;
                return(_applicationService.Add(entity));
            });

            if (!result.IsSuccess)
            {
                return(View("Add", result.ToResponseModel(entity)));
            }

            return(RedirectToAction("List"));
        }
Exemple #18
0
        public async Task BuildDockerImage_DockerExecutionDirectorySet()
        {
            var projectPath       = SystemIOUtilities.ResolvePath("ConsoleAppTask");
            var projectDefinition = new ProjectDefinition(projectPath);
            var recipeDefinition  = new Mock <RecipeDefinition>();
            var recommendation    = new Recommendation(recipeDefinition.Object, projectDefinition.ProjectPath, 100, new Dictionary <string, string>());

            recommendation.DeploymentBundle.DockerExecutionDirectory = projectPath;

            var cloudApplication = new CloudApplication {
                Name = "ConsoleAppTask"
            };
            var result = await _deploymentBundleHandler.BuildDockerImage(cloudApplication, recommendation);

            var dockerFile = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(recommendation.ProjectPath)), "Dockerfile");

            Assert.Equal($"docker build -t {result} -f \"{dockerFile}\" .",
                         _commandLineWrapper.CommandsToExecute.First().Command);
            Assert.Equal(projectPath,
                         _commandLineWrapper.CommandsToExecute.First().WorkingDirectory);
        }
        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 DeployRecommendation(CloudApplication cloudApplication, Recommendation recommendation)
        {
            _interactiveService.LogMessageLine(string.Empty);
            _interactiveService.LogMessageLine($"Initiating deployment: {recommendation.Name}");

            if (recommendation.Recipe.DeploymentType == DeploymentTypes.CdkProject)
            {
                _interactiveService.LogMessageLine("AWS CDK is being configured.");
                await _session.CdkManager.EnsureCompatibleCDKExists(CDKConstants.DeployToolWorkspaceDirectoryRoot, CDKConstants.MinimumCDKVersion);
            }

            switch (recommendation.Recipe.DeploymentType)
            {
            case DeploymentTypes.CdkProject:
                await _cdkProjectHandler.CreateCdkDeployment(_session, cloudApplication, recommendation);

                break;

            default:
                _interactiveService.LogErrorMessageLine($"Unknown deployment type {recommendation.Recipe.DeploymentType} specified in recipe.");
                break;
            }
        }
Exemple #21
0
        public async Task CreateCdkDeployment(OrchestratorSession session, CloudApplication cloudApplication, Recommendation recommendation)
        {
            // Create a new temporary CDK project for a new deployment
            _interactiveService.LogMessageLine($"Generating a {recommendation.Recipe.Name} CDK Project");
            var cdkProjectPath = await CreateCdkProjectForDeployment(recommendation, session);

            // Write required configuration in appsettings.json
            var appSettingsBody     = _appSettingsBuilder.Build(cloudApplication, recommendation);
            var appSettingsFilePath = Path.Combine(cdkProjectPath, "appsettings.json");

            using (var appSettingsFile = new StreamWriter(appSettingsFilePath))
            {
                await appSettingsFile.WriteAsync(appSettingsBody);
            }

            _interactiveService.LogMessageLine("Starting deployment of CDK Project");

            // Ensure region is bootstrapped
            await _commandLineWrapper.Run($"npx cdk bootstrap aws://{session.AWSAccountId}/{session.AWSRegion}");

            // Handover to CDK command line tool
            // Use a CDK Context parameter to specify the settings file that has been serialized.
            await _commandLineWrapper.Run($"npx cdk deploy --require-approval never -c {CloudFormationIdentifierConstants.SETTINGS_PATH_CDK_CONTEXT_PARAMETER}=\"{appSettingsFilePath}\"", cdkProjectPath);
        }
Exemple #22
0
        private async Task <Recommendation> GetSelectedRecommendationFromPreviousDeployment(List <Recommendation> recommendations, CloudApplication deployedApplication, UserDeploymentSettings?userDeploymentSettings)
        {
            var existingCloudApplicationMetadata = await _templateMetadataReader.LoadCloudApplicationMetadata(deployedApplication.Name);

            var deploymentSettingRecipeId = userDeploymentSettings?.RecipeId;
            var selectedRecommendation    = recommendations.FirstOrDefault(x => string.Equals(x.Recipe.Id, deployedApplication.RecipeId, StringComparison.InvariantCultureIgnoreCase));

            if (selectedRecommendation == null)
            {
                var errorMessage = $"{deployedApplication.StackName} already exists as a Cloudformation stack but the recommendation used to deploy to the stack was not found.";
                throw new FailedToFindCompatibleRecipeException(errorMessage);
            }
            if (!string.IsNullOrEmpty(deploymentSettingRecipeId) && !string.Equals(deploymentSettingRecipeId, selectedRecommendation.Recipe.Id, StringComparison.InvariantCultureIgnoreCase))
            {
                var errorMessage = $"The existing stack {deployedApplication.StackName} was created from a different deployment recommendation. " +
                                   "Deploying to an existing stack must be performed with the original deployment recommendation to avoid unintended destructive changes to the stack.";
                if (_toolInteractiveService.Diagnostics)
                {
                    errorMessage += Environment.NewLine + $"The original deployment recipe ID was {deployedApplication.RecipeId} and the current deployment recipe ID is {deploymentSettingRecipeId}";
                }
                throw new InvalidUserDeploymentSettingsException(errorMessage.Trim());
            }

            selectedRecommendation = selectedRecommendation.ApplyPreviousSettings(existingCloudApplicationMetadata.Settings);

            var header = $"Loading {deployedApplication.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)
                {
                    return(false);
                }

                return(true);
            })
                .ToArray();

            foreach (var setting in optionSettings)
            {
                DisplayOptionSetting(selectedRecommendation, setting, -1, optionSettings.Length, DisplayOptionSettingsMode.Readonly);
            }

            return(selectedRecommendation);
        }
Exemple #23
0
 public DeployRecommendationTask(Orchestrator orchestrator, CloudApplication cloudApplication, Recommendation selectedRecommendation)
 {
     _orchestrator           = orchestrator;
     _cloudApplication       = cloudApplication;
     _selectedRecommendation = selectedRecommendation;
 }
        public async Task DeployRecommendation(CloudApplication cloudApplication, Recommendation recommendation)
        {
            if (_interactiveService == null)
            {
                throw new InvalidOperationException($"{nameof(_interactiveService)} is null as part of the orchestartor object");
            }
            if (_cdkManager == null)
            {
                throw new InvalidOperationException($"{nameof(_cdkManager)} is null as part of the orchestartor object");
            }
            if (_cdkProjectHandler == null)
            {
                throw new InvalidOperationException($"{nameof(_cdkProjectHandler)} is null as part of the orchestartor object");
            }
            if (_localUserSettingsEngine == null)
            {
                throw new InvalidOperationException($"{nameof(_localUserSettingsEngine)} is null as part of the orchestartor object");
            }
            if (_session == null)
            {
                throw new InvalidOperationException($"{nameof(_session)} is null as part of the orchestartor object");
            }

            _interactiveService.LogMessageLine(string.Empty);
            _interactiveService.LogMessageLine($"Initiating deployment: {recommendation.Name}");

            switch (recommendation.Recipe.DeploymentType)
            {
            case DeploymentTypes.CdkProject:
                if (_cdkVersionDetector == null)
                {
                    throw new InvalidOperationException($"{nameof(_cdkVersionDetector)} must not be null.");
                }

                if (_directoryManager == null)
                {
                    throw new InvalidOperationException($"{nameof(_directoryManager)} must not be null.");
                }

                var cdkProject = await _cdkProjectHandler.ConfigureCdkProject(_session, cloudApplication, recommendation);

                _interactiveService.LogMessageLine("AWS CDK is being configured.");

                var projFiles  = _directoryManager.GetProjFiles(cdkProject);
                var cdkVersion = _cdkVersionDetector.Detect(projFiles);
                await _cdkManager.EnsureCompatibleCDKExists(Constants.CDK.DeployToolWorkspaceDirectoryRoot, cdkVersion);

                try
                {
                    await _cdkProjectHandler.DeployCdkProject(_session, cdkProject, recommendation);
                }
                finally
                {
                    _cdkProjectHandler.DeleteTemporaryCdkProject(cdkProject);
                }
                break;

            default:
                _interactiveService.LogErrorMessageLine($"Unknown deployment type {recommendation.Recipe.DeploymentType} specified in recipe.");
                return;
            }

            await _localUserSettingsEngine.UpdateLastDeployedStack(cloudApplication.StackName, _session.ProjectDefinition.ProjectName, _session.AWSAccountId, _session.AWSRegion);
        }
        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 #26
0
        //[TestMethod]
        public void LoadFakeData()
        {
            //set the context to a fake stub
            this.FakeContext = new CloudCompareContext();

            //_context = new StationEntities();

            //now use this fake stub as the repository
            var repository = new QueryRepository(this.FakeContext);

            //add our sample fake station entities to the repository
            CloudApplication ca;
            ca = new CloudApplication()
            {
                AddDate = DateTime.Now,
                ApplicationContentStatusID = 1,
                ApprovalAssignedPersonID = 1,
                ApprovalStatusID = 1,
                AverageEaseOfUse = 1,
                AverageFunctionality = 1,
                AverageOverallRating = 1,
                AverageValueForMoney = 1,
                Brand = "BRAND",
                CategoryID = 1,
                CloudApplicationID = 1,
                CostPerAnnum = 1,
                CostPerMonth = 1,
                Description = "DESCRIPTION",
                FacebookFollowers = 1,
                FacebookURL = "FACEBOOKURL",
                Features = new List<Feature>(),
                FreeTrialID = 1,
                FreeTrialPeriodID = 1,
                IsPromotional = true,
                LanguageID = 1,
                LicenceTypeID = 1,
                LinkedInFollowers = 1,
                LinkedInURL = "LINKEDINURL",
                MaximumMeetingAttendees = 1,
                MaximumWebinarAttendees = 1,
                MinimumContractID = 1,
                OperatingSystemID = 1,
                PaymentFrequencyID = 1,
                PaymentOptions = new List<PaymentOption>(),
                SetupFee = 1,
                SupportDaysID = 1,
                SupportHoursID = 1,
                SupportTypeID = 1,
                ThumbnailDocuments = new List<ThumbnailDocument>(),
                Title = "TITLE",
                TwitterFollowers = 1,
                TwitterURL = "TWITTERURL",
                Vendor = new Vendor(),
                VideoTrainingSupport = true
            };
            repository.AddCloudApplication(ca);

            // Mock the Products Repository using Moq
            Mock<ICloudCompareContext> mockCloudCompareRepository = new Mock<ICloudCompareContext>();

            // Try finding a product by id
            CloudApplication testCloudApplication = mockCloudCompareRepository.Object.FindById(2);

            Assert.IsNotNull(testCloudApplication); // Test if null
            Assert.IsInstanceOfType(typeof(CloudApplication),testCloudApplication); // Test type
            Assert.AreEqual("TITLE", testCloudApplication.Title); // Verify it is the right product
        }
 public void AddCloudApplication(CloudApplication ca)
 {
     _context.CloudApplications.Add(ca);
 }
Exemple #28
0
        public static void PushApp(string appName, string sourceDir, string url, List<string> directoriesCreated, CloudConnection cloudConnection, string vendor ,string serviceName, string path)
        {
            if (path == null)
                path = TestUtil.CopyFolderToTemp(sourceDir);
            directoriesCreated.Add(path);

            if (serviceName == null)
                serviceName = appName + "svc";

            if (vendor != null)
            {
                cloudConnection.CreateProvisionedService(cloudConnection.SystemServices.FirstOrDefault(ss => ss.Vendor == vendor), serviceName, true);
                Thread.Sleep(10000);
            }

            CloudApplication cloudApp = new CloudApplication()
            {
                Name = appName,
                Urls = new string[1] { url },
                DeploymentPath = path,
                Deployable = true,
                Framework = "dotNet",
                InstanceCount = 1,
                Memory = 128,
                Runtime = "iis",
            };
            PushTracker pushTracker = new PushTracker();
            Guid tracker = Guid.NewGuid();
            pushTracker.TrackId = tracker;
            currentJobs.Add(tracker);
            cloudConnection.PushJob.Start(pushTracker, cloudApp);

            cloudConnection.PushJob.JobCompleted += new EventHandler<global::System.ComponentModel.AsyncCompletedEventArgs>(PushJob_JobCompleted);

            while (currentJobs.Contains(tracker))
            {
                Thread.Sleep(1000);
            }

            App currentApp = cloudConnection.Apps.FirstOrDefault(app => app.Name == cloudApp.Name);

            ProvisionedService provisionedService = cloudConnection.ProvisionedServices.FirstOrDefault(ps => ps.Name == serviceName);
            if (vendor != null)
            {
                currentApp.BindService(provisionedService);
                Thread.Sleep(1000);
            }
            currentApp.Start();

            int retryCount = 10;
            while (true)
            {
                App pushedApp = cloudConnection.Apps.FirstOrDefault(app => app.Name == cloudApp.Name);
                if (pushedApp.State == AppState.RUNNING)
                    break;
                Thread.Sleep(1000);
                retryCount--;
                if (retryCount == 0)
                    break;
            }
        }
Exemple #29
0
        private async Task CreateDeploymentBundle(Orchestrator orchestrator, Recommendation selectedRecommendation, CloudApplication cloudApplication)
        {
            if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.Container)
            {
                while (!await orchestrator.CreateContainerDeploymentBundle(cloudApplication, selectedRecommendation))
                {
                    if (_toolInteractiveService.DisableInteractive)
                    {
                        var errorMessage = "Failed to build Docker Image." + Environment.NewLine;
                        errorMessage += "Docker builds usually fail due to executing them from a working directory that is incompatible with the Dockerfile." + Environment.NewLine;
                        errorMessage += "Specify a valid Docker execution directory as part of the deployment settings file and try again.";
                        throw new DockerBuildFailedException(errorMessage);
                    }

                    _toolInteractiveService.WriteLine(string.Empty);
                    var answer = _consoleUtilities.AskYesNoQuestion("Do you want to go back and modify the current configuration?", "false");
                    if (answer == YesNo.Yes)
                    {
                        var dockerExecutionDirectory =
                            _consoleUtilities.AskUserForValue(
                                "Enter the docker execution directory where the docker build command will be executed from:",
                                selectedRecommendation.DeploymentBundle.DockerExecutionDirectory,
                                allowEmpty: true);

                        if (!_directoryManager.Exists(dockerExecutionDirectory))
                        {
                            continue;
                        }

                        selectedRecommendation.DeploymentBundle.DockerExecutionDirectory = dockerExecutionDirectory;
                    }
                    else
                    {
                        throw new FailedToCreateDeploymentBundleException("Failed to create a deployment bundle");
                    }
                }
            }
            else if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.DotnetPublishZipFile)
            {
                var dotnetPublishDeploymentBundleResult = await orchestrator.CreateDotnetPublishDeploymentBundle(selectedRecommendation);

                if (!dotnetPublishDeploymentBundleResult)
                {
                    throw new FailedToCreateDeploymentBundleException("Failed to create a deployment bundle");
                }
            }
        }
Exemple #30
0
        public static void PushApp(string appName, string sourceDir, string url, List <string> directoriesCreated, CloudConnection cloudConnection, string vendor, string serviceName, string path)
        {
            if (path == null)
            {
                path = TestUtil.CopyFolderToTemp(sourceDir);
            }
            directoriesCreated.Add(path);

            if (serviceName == null)
            {
                serviceName = appName + "svc";
            }

            if (vendor != null)
            {
                cloudConnection.CreateProvisionedService(cloudConnection.SystemServices.FirstOrDefault(ss => ss.Vendor == vendor), serviceName, true);
                Thread.Sleep(10000);
            }

            CloudApplication cloudApp = new CloudApplication()
            {
                Name = appName,
                Urls = new string[1] {
                    url
                },
                DeploymentPath = path,
                Deployable     = true,
                Framework      = "dotNet",
                InstanceCount  = 1,
                Memory         = 128,
                Runtime        = "iis",
            };
            PushTracker pushTracker = new PushTracker();
            Guid        tracker     = Guid.NewGuid();

            pushTracker.TrackId = tracker;
            currentJobs.Add(tracker);
            cloudConnection.PushJob.Start(pushTracker, cloudApp);


            cloudConnection.PushJob.JobCompleted += new EventHandler <global::System.ComponentModel.AsyncCompletedEventArgs>(PushJob_JobCompleted);

            while (currentJobs.Contains(tracker))
            {
                Thread.Sleep(1000);
            }

            App currentApp = cloudConnection.Apps.FirstOrDefault(app => app.Name == cloudApp.Name);

            ProvisionedService provisionedService = cloudConnection.ProvisionedServices.FirstOrDefault(ps => ps.Name == serviceName);

            if (vendor != null)
            {
                currentApp.BindService(provisionedService);
                Thread.Sleep(1000);
            }
            currentApp.Start();

            int retryCount = 10;

            while (true)
            {
                App pushedApp = cloudConnection.Apps.FirstOrDefault(app => app.Name == cloudApp.Name);
                if (pushedApp.State == AppState.RUNNING)
                {
                    break;
                }
                Thread.Sleep(1000);
                retryCount--;
                if (retryCount == 0)
                {
                    break;
                }
            }
        }
Exemple #31
0
        //[TestMethod]
        public void LoadFakeData()
        {
            //set the context to a fake stub
            this.FakeContext = new CloudCompareContext();

            //_context = new StationEntities();

            //now use this fake stub as the repository
            var repository = new QueryRepository(this.FakeContext);

            //add our sample fake station entities to the repository
            CloudApplication ca;
            ca = new CloudApplication()
            {
                AddDate = DateTime.Now,
                ApplicationContentStatusID = 1,
                ApprovalAssignedPersonID = 1,
                ApprovalStatusID = 1,
                AverageEaseOfUse = 1,
                AverageFunctionality = 1,
                AverageOverallRating = 1,
                AverageValueForMoney = 1,
                Brand = "BRAND",
                CategoryID = 1,
                CloudApplicationID = 1,
                CostPerAnnum = 1,
                CostPerMonth = 1,
                Description = "DESCRIPTION",
                FacebookFollowers = 1,
                FacebookURL = "FACEBOOKURL",
                Features = new List<Feature>(),
                FreeTrialID = 1,
                FreeTrialPeriodID = 1,
                IsPromotional = true,
                LanguageID = 1,
                LicenceTypeID = 1,
                LinkedInFollowers = 1,
                LinkedInURL = "LINKEDINURL",
                MaximumMeetingAttendees = 1,
                MaximumWebinarAttendees = 1,
                MinimumContractID = 1,
                OperatingSystemID = 1,
                PaymentFrequencyID = 1,
                PaymentOptions = new List<PaymentOption>(),
                SetupFee = 1,
                SupportDaysID = 1,
                SupportHoursID = 1,
                SupportTypeID = 1,
                ThumbnailDocuments = new List<ThumbnailDocument>(),
                Title = "TITLE",
                TwitterFollowers = 1,
                TwitterURL = "TWITTERURL",
                Vendor = new Vendor(),
                VideoTrainingSupport = true
            };
            repository.AddCloudApplication(ca);


            // Mock the Products Repository using Moq
            Mock<ICloudCompareContext> mockCloudCompareRepository = new Mock<ICloudCompareContext>();

            // Try finding a product by id
            CloudApplication testCloudApplication = mockCloudCompareRepository.Object.FindById(2);

            Assert.IsNotNull(testCloudApplication); // Test if null
            Assert.IsInstanceOfType(typeof(CloudApplication),testCloudApplication); // Test type
            Assert.AreEqual("TITLE", testCloudApplication.Title); // Verify it is the right product
        }
        private async Task CreateDeploymentBundle(Orchestrator.Orchestrator orchestrator, Recommendation selectedRecommendation, CloudApplication cloudApplication)
        {
            if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.Container)
            {
                while (!await orchestrator.CreateContainerDeploymentBundle(cloudApplication, selectedRecommendation))
                {
                    _toolInteractiveService.WriteLine(string.Empty);
                    var answer = _consoleUtilities.AskYesNoQuestion("Do you want to go back and modify the current configuration?", "true");
                    if (answer == ConsoleUtilities.YesNo.Yes)
                    {
                        var dockerExecutionDirectory =
                            _consoleUtilities.AskUserForValue(
                                "Enter the docker execution directory where the docker build command will be executed from:",
                                selectedRecommendation.DeploymentBundle.DockerExecutionDirectory,
                                allowEmpty: true);

                        if (!Directory.Exists(dockerExecutionDirectory))
                        {
                            continue;
                        }

                        selectedRecommendation.DeploymentBundle.DockerExecutionDirectory = dockerExecutionDirectory;
                    }
                    else
                    {
                        _toolInteractiveService.WriteLine(string.Empty);
                        throw new FailedToCreateDeploymentBundleException();
                    }
                }
            }
            else if (selectedRecommendation.Recipe.DeploymentBundle == DeploymentBundleTypes.DotnetPublishZipFile)
            {
                var dotnetPublishDeploymentBundleResult = await orchestrator.CreateDotnetPublishDeploymentBundle(selectedRecommendation);

                if (!dotnetPublishDeploymentBundleResult)
                {
                    throw new FailedToCreateDeploymentBundleException();
                }
            }
        }