/// <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); }
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); }
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); }
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(); }
/// <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); }
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); }
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); }
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; }
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")); }
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")); }
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; } }
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); }
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); }
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); }
//[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); }
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; } }
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"); } } }
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; } } }
//[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(); } } }