internal ExecuteChangeSetResponse ExecuteChangeSet(ExecuteChangeSetRequest request) { var marshaller = new ExecuteChangeSetRequestMarshaller(); var unmarshaller = ExecuteChangeSetResponseUnmarshaller.Instance; return(Invoke <ExecuteChangeSetRequest, ExecuteChangeSetResponse>(request, marshaller, unmarshaller)); }
/// <summary> /// Initiates the asynchronous execution of the ExecuteChangeSet operation. /// </summary> /// /// <param name="request">Container for the necessary parameters to execute the ExecuteChangeSet operation.</param> /// <param name="cancellationToken"> /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// </param> /// <returns>The task object representing the asynchronous operation.</returns> public Task <ExecuteChangeSetResponse> ExecuteChangeSetAsync(ExecuteChangeSetRequest request, System.Threading.CancellationToken cancellationToken = default(CancellationToken)) { var marshaller = new ExecuteChangeSetRequestMarshaller(); var unmarshaller = ExecuteChangeSetResponseUnmarshaller.Instance; return(InvokeAsync <ExecuteChangeSetRequest, ExecuteChangeSetResponse>(request, marshaller, unmarshaller, cancellationToken)); }
private async Task ExecuteChangeSet(string stackId, DeployContext context, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var request = new ExecuteChangeSetRequest { ChangeSetName = context.ChangeSetName, StackName = stackId }; await cloudformation.ExecuteChangeSetAsync(request, cancellationToken); }
public override async Task <bool> ExecuteAsync() { try { string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, DefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string stackName = this.GetStringValueOrDefault(this.StackName, DefinedCommandOptions.ARGUMENT_STACK_NAME, true); string s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, DefinedCommandOptions.ARGUMENT_S3_BUCKET, true); string s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, DefinedCommandOptions.ARGUMENT_S3_PREFIX, false); string templatePath = this.GetStringValueOrDefault(this.CloudFormationTemplate, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE, true); await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket); if (!Path.IsPathRooted(templatePath)) { templatePath = Path.Combine(Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation), templatePath); } if (!File.Exists(templatePath)) { throw new LambdaToolsException($"Template file {templatePath} cannot be found.", LambdaToolsException.ErrorCode.ServerlessTemplateNotFound); } // Build and bundle up the users project. string publishLocation; string zipArchivePath = null; string package = this.GetStringValueOrDefault(this.Package, DefinedCommandOptions.ARGUMENT_PACKAGE, false); if (string.IsNullOrEmpty(package)) { string configuration = this.GetStringValueOrDefault(this.Configuration, DefinedCommandOptions.ARGUMENT_CONFIGURATION, true); string targetFramework = this.GetStringValueOrDefault(this.TargetFramework, DefinedCommandOptions.ARGUMENT_FRAMEWORK, true); LambdaPackager.CreateApplicationBundle(this.DefaultConfig, this.Logger, this.WorkingDirectory, projectLocation, configuration, targetFramework, out publishLocation, ref zipArchivePath); if (string.IsNullOrEmpty(zipArchivePath)) { return(false); } } else { if (!File.Exists(package)) { throw new LambdaToolsException($"Package {package} does not exist", LambdaToolsException.ErrorCode.InvalidPackage); } if (!string.Equals(Path.GetExtension(package), ".zip", StringComparison.OrdinalIgnoreCase)) { throw new LambdaToolsException($"Package {package} must be a zip file", LambdaToolsException.ErrorCode.InvalidPackage); } this.Logger.WriteLine($"Skipping compilation and using precompiled package {package}"); zipArchivePath = package; } // Upload the app bundle to S3 string s3KeyApplicationBundle; using (var stream = new MemoryStream(File.ReadAllBytes(zipArchivePath))) { s3KeyApplicationBundle = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, stackName, stream); } // Read in the serverless template and update all the locations for Lambda functions to point to the app bundle that was just uploaded. string templateBody = File.ReadAllText(templatePath); // Process any template substitutions templateBody = Utilities.ProcessTemplateSubstitions(this.Logger, templateBody, this.GetKeyValuePairOrDefault(this.TemplateSubstitutions, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE_SUBSTITUTIONS, false), Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation)); templateBody = UpdateCodeLocationInTemplate(templateBody, s3Bucket, s3KeyApplicationBundle); // Upload the template to S3 instead of sending it straight to CloudFormation to avoid the size limitation string s3KeyTemplate; using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(templateBody))) { s3KeyTemplate = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, stackName + "-" + Path.GetFileName(templatePath), stream); } var existingStack = await GetExistingStackAsync(stackName); this.Logger.WriteLine("Found existing stack: " + (existingStack != null)); var changeSetName = "Lambda-Tools-" + DateTime.Now.Ticks; // Determine if the stack is in a good state to be updated. ChangeSetType changeSetType; if (existingStack == null || existingStack.StackStatus == StackStatus.REVIEW_IN_PROGRESS || existingStack.StackStatus == StackStatus.DELETE_COMPLETE) { changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_COMPLETE that means the stack failed on initial creation // and the resources were cleaned up. It is safe to delete the stack so we can recreate it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_IN_PROGRESS that means the initial creation is failing. // Wait to see if it goes into ROLLBACK_COMPLETE status meaning everything got cleaned up and then delete it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_IN_PROGRESS) { existingStack = await WaitForNoLongerInProgress(existingStack.StackName); if (existingStack != null && existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); } changeSetType = ChangeSetType.CREATE; } // If the status was DELETE_IN_PROGRESS then just wait for delete to complete else if (existingStack.StackStatus == StackStatus.DELETE_IN_PROGRESS) { await WaitForNoLongerInProgress(existingStack.StackName); changeSetType = ChangeSetType.CREATE; } // The Stack state is in a normal state and ready to be updated. else if (existingStack.StackStatus == StackStatus.CREATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_ROLLBACK_COMPLETE) { changeSetType = ChangeSetType.UPDATE; } // All other states means the Stack is in an inconsistent state. else { this.Logger.WriteLine($"The stack's current state of {existingStack.StackStatus} is invalid for updating"); return(false); } CreateChangeSetResponse changeSetResponse; try { var templateParameters = GetTemplateParameters(changeSetType == ChangeSetType.UPDATE ? existingStack : null); if (templateParameters?.Count > 0) { var setParameters = templateParameters.Where(x => !x.UsePreviousValue); if (setParameters?.Count() > 0) { this.Logger.WriteLine("Template Parameters Applied:"); foreach (var parameter in setParameters) { this.Logger.WriteLine($"\t{parameter.ParameterKey}: {parameter.ParameterValue}"); } } } var capabilities = new List <string>(); var disabledCapabilties = GetStringValuesOrDefault(this.DisabledCapabilities, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_DISABLE_CAPABILITIES, false); if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_IAM"); } if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_NAMED_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_NAMED_IAM"); } var changeSetRequest = new CreateChangeSetRequest { StackName = stackName, Parameters = templateParameters, ChangeSetName = changeSetName, ChangeSetType = changeSetType, Capabilities = capabilities, RoleARN = this.GetStringValueOrDefault(this.CloudFormationRole, DefinedCommandOptions.ARGUMENT_CLOUDFORMATION_ROLE, false), Tags = new List <Tag> { new Tag { Key = Constants.SERVERLESS_TAG_NAME, Value = "true" } } }; if (new FileInfo(templatePath).Length < Constants.MAX_TEMPLATE_BODY_IN_REQUEST_SIZE) { changeSetRequest.TemplateBody = templateBody; } else { changeSetRequest.TemplateURL = this.S3Client.GetPreSignedURL(new S3.Model.GetPreSignedUrlRequest { BucketName = s3Bucket, Key = s3KeyTemplate, Expires = DateTime.Now.AddHours(1) }); } // Create the change set which performs the transformation on the Serverless resources in the template. changeSetResponse = await this.CloudFormationClient.CreateChangeSetAsync(changeSetRequest); this.Logger.WriteLine("CloudFormation change set created"); } catch (LambdaToolsException) { throw; } catch (Exception e) { throw new LambdaToolsException($"Error creating CloudFormation change set: {e.Message}", LambdaToolsException.ErrorCode.CloudFormationCreateStack, e); } // The change set can take a few seconds to be reviewed and be ready to be executed. if (!await WaitForChangeSetBeingAvailableAsync(changeSetResponse.Id, existingStack != null)) { return(false); } var executeChangeSetRequest = new ExecuteChangeSetRequest { StackName = stackName, ChangeSetName = changeSetResponse.Id }; // Execute the change set. DateTime timeChangeSetExecuted = DateTime.Now; ExecuteChangeSetResponse executeChangeSetResponse; try { executeChangeSetResponse = await this.CloudFormationClient.ExecuteChangeSetAsync(executeChangeSetRequest); if (changeSetType == ChangeSetType.CREATE) { this.Logger.WriteLine($"Created CloudFormation stack {stackName}"); } else { this.Logger.WriteLine($"Initiated CloudFormation stack update on {stackName}"); } } catch (Exception e) { throw new LambdaToolsException($"Error executing CloudFormation change set: {e.Message}", LambdaToolsException.ErrorCode.CloudFormationCreateChangeSet, e); } // Wait for the stack to finish unless the user opts out of waiting. The VS Toolkit opts out and // instead shows the stack view in the IDE, enabling the user to view progress. var shouldWait = GetBoolValueOrDefault(this.WaitForStackToComplete, DefinedCommandOptions.ARGUMENT_STACK_WAIT, false); if (!shouldWait.HasValue || shouldWait.Value) { var updatedStack = await WaitStackToCompleteAsync(stackName, timeChangeSetExecuted); if (updatedStack.StackStatus == StackStatus.CREATE_COMPLETE || updatedStack.StackStatus == StackStatus.UPDATE_COMPLETE) { this.Logger.WriteLine($"Stack finished updating with status: {updatedStack.StackStatus}"); // Display the output parameters. DisplayOutputs(updatedStack); } else { this.Logger.WriteLine($"Stack update failed with status: {updatedStack.StackStatus} ({updatedStack.StackStatusReason})"); return(false); } } if (this.GetBoolValueOrDefault(this.PersistConfigFile, DefinedCommandOptions.ARGUMENT_PERSIST_CONFIG_FILE, false).GetValueOrDefault()) { this.SaveConfigFile(); } return(true); } catch (LambdaToolsException e) { this.Logger.WriteLine(e.Message); this.LastToolsException = e; return(false); } catch (Exception e) { this.Logger.WriteLine($"Unknown error executing AWS Serverless deployment: {e.Message}"); this.Logger.WriteLine(e.StackTrace); return(false); } }
public ExecuteChangeSetResponse ExecuteChangeSetWithOptions(string stackName, string stackId, string changeSetName, ExecuteChangeSetRequest request, AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime) { AlibabaCloud.TeaUtil.Common.ValidateModel(request); return(TeaModel.ToObject <ExecuteChangeSetResponse>(DoRequest("2015-09-01", "HTTPS", "PUT", "AK", "/stacks/" + stackName + "/" + stackId + "/changeSets/" + changeSetName + "/execute", null, request.Headers, null, runtime))); }
public async Task <ExecuteChangeSetResponse> ExecuteChangeSetAsync(string stackName, string stackId, string changeSetName, ExecuteChangeSetRequest request) { AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions(); return(await ExecuteChangeSetWithOptionsAsync(stackName, stackId, changeSetName, request, runtime)); }
public ExecuteChangeSetResponse ExecuteChangeSet(string stackName, string stackId, string changeSetName, ExecuteChangeSetRequest request) { AlibabaCloud.TeaUtil.Models.RuntimeOptions runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions(); return(ExecuteChangeSetWithOptions(stackName, stackId, changeSetName, request, runtime)); }
protected override async Task <bool> PerformActionAsync() { string projectLocation = this.GetStringValueOrDefault(this.ProjectLocation, CommonDefinedCommandOptions.ARGUMENT_PROJECT_LOCATION, false); string stackName = this.GetStringValueOrDefault(this.StackName, LambdaDefinedCommandOptions.ARGUMENT_STACK_NAME, true); string s3Bucket = this.GetStringValueOrDefault(this.S3Bucket, LambdaDefinedCommandOptions.ARGUMENT_S3_BUCKET, true); string s3Prefix = this.GetStringValueOrDefault(this.S3Prefix, LambdaDefinedCommandOptions.ARGUMENT_S3_PREFIX, false); string templatePath = this.GetStringValueOrDefault(this.CloudFormationTemplate, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE, true); await Utilities.ValidateBucketRegionAsync(this.S3Client, s3Bucket); if (!Path.IsPathRooted(templatePath)) { templatePath = Path.Combine(Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation), templatePath); } if (!File.Exists(templatePath)) { throw new LambdaToolsException($"Template file {templatePath} cannot be found.", LambdaToolsException.LambdaErrorCode.ServerlessTemplateNotFound); } // Read in the serverless template and update all the locations for Lambda functions to point to the app bundle that was just uploaded. string templateBody = File.ReadAllText(templatePath); // Process any template substitutions templateBody = LambdaUtilities.ProcessTemplateSubstitions(this.Logger, templateBody, this.GetKeyValuePairOrDefault(this.TemplateSubstitutions, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_TEMPLATE_SUBSTITUTIONS, false), Utilities.DetermineProjectLocation(this.WorkingDirectory, projectLocation)); var options = new DefaultLocationOption { Configuration = this.GetStringValueOrDefault(this.Configuration, CommonDefinedCommandOptions.ARGUMENT_CONFIGURATION, false), TargetFramework = this.GetStringValueOrDefault(this.TargetFramework, CommonDefinedCommandOptions.ARGUMENT_FRAMEWORK, false), MSBuildParameters = this.GetStringValueOrDefault(this.MSBuildParameters, CommonDefinedCommandOptions.ARGUMENT_MSBUILD_PARAMETERS, false), DisableVersionCheck = this.GetBoolValueOrDefault(this.DisableVersionCheck, LambdaDefinedCommandOptions.ARGUMENT_DISABLE_VERSION_CHECK, false).GetValueOrDefault(), Package = this.GetStringValueOrDefault(this.Package, LambdaDefinedCommandOptions.ARGUMENT_PACKAGE, false) }; var templateProcessor = new TemplateProcessorManager(this.Logger, this.S3Client, s3Bucket, s3Prefix, options); templateBody = await templateProcessor.TransformTemplateAsync(templatePath, templateBody); // Upload the template to S3 instead of sending it straight to CloudFormation to avoid the size limitation string s3KeyTemplate; using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(templateBody))) { s3KeyTemplate = await Utilities.UploadToS3Async(this.Logger, this.S3Client, s3Bucket, s3Prefix, stackName + "-" + Path.GetFileName(templatePath), stream); } var existingStack = await GetExistingStackAsync(stackName); this.Logger.WriteLine("Found existing stack: " + (existingStack != null)); var changeSetName = "Lambda-Tools-" + DateTime.Now.Ticks; List <Tag> tagList = null; { var tags = this.GetKeyValuePairOrDefault(this.Tags, LambdaDefinedCommandOptions.ARGUMENT_FUNCTION_TAGS, false); if (tags != null) { tagList = new List <Tag>(); foreach (var kvp in tags) { tagList.Add(new Tag { Key = kvp.Key, Value = kvp.Value }); } } } // Determine if the stack is in a good state to be updated. ChangeSetType changeSetType; if (existingStack == null || existingStack.StackStatus == StackStatus.REVIEW_IN_PROGRESS || existingStack.StackStatus == StackStatus.DELETE_COMPLETE) { changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_COMPLETE that means the stack failed on initial creation // and the resources were cleaned up. It is safe to delete the stack so we can recreate it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_IN_PROGRESS that means the initial creation is failing. // Wait to see if it goes into ROLLBACK_COMPLETE status meaning everything got cleaned up and then delete it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_IN_PROGRESS) { existingStack = await WaitForNoLongerInProgress(existingStack.StackName); if (existingStack != null && existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(existingStack); } changeSetType = ChangeSetType.CREATE; } // If the status was DELETE_IN_PROGRESS then just wait for delete to complete else if (existingStack.StackStatus == StackStatus.DELETE_IN_PROGRESS) { await WaitForNoLongerInProgress(existingStack.StackName); changeSetType = ChangeSetType.CREATE; } // The Stack state is in a normal state and ready to be updated. else if (existingStack.StackStatus == StackStatus.CREATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_ROLLBACK_COMPLETE) { changeSetType = ChangeSetType.UPDATE; if (tagList == null) { tagList = existingStack.Tags; } } // All other states means the Stack is in an inconsistent state. else { this.Logger.WriteLine($"The stack's current state of {existingStack.StackStatus} is invalid for updating"); return(false); } CreateChangeSetResponse changeSetResponse; try { var definedParameters = LambdaUtilities.GetTemplateDefinedParameters(templateBody); var templateParameters = GetTemplateParameters(changeSetType == ChangeSetType.UPDATE ? existingStack : null, definedParameters); if (templateParameters != null && templateParameters.Any()) { var setParameters = templateParameters.Where(x => !x.UsePreviousValue); // ReSharper disable once PossibleMultipleEnumeration if (setParameters.Any()) { this.Logger.WriteLine("Template Parameters Applied:"); foreach (var parameter in setParameters) { Tuple <string, bool> dp = null; if (definedParameters != null) { dp = definedParameters.FirstOrDefault(x => string.Equals(x.Item1, parameter.ParameterKey)); } if (dp != null && dp.Item2) { this.Logger.WriteLine($"\t{parameter.ParameterKey}: ****"); } else { this.Logger.WriteLine($"\t{parameter.ParameterKey}: {parameter.ParameterValue}"); } } } } var capabilities = new List <string>(); var disabledCapabilties = GetStringValuesOrDefault(this.DisabledCapabilities, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_DISABLE_CAPABILITIES, false); if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_IAM"); } if (disabledCapabilties?.FirstOrDefault(x => string.Equals(x, "CAPABILITY_NAMED_IAM", StringComparison.OrdinalIgnoreCase)) == null) { capabilities.Add("CAPABILITY_NAMED_IAM"); } if (tagList == null) { tagList = new List <Tag>(); } if (tagList.FirstOrDefault(x => string.Equals(x.Key, LambdaConstants.SERVERLESS_TAG_NAME)) == null) { tagList.Add(new Tag { Key = LambdaConstants.SERVERLESS_TAG_NAME, Value = "true" }); } var changeSetRequest = new CreateChangeSetRequest { StackName = stackName, Parameters = templateParameters, ChangeSetName = changeSetName, ChangeSetType = changeSetType, Capabilities = capabilities, RoleARN = this.GetStringValueOrDefault(this.CloudFormationRole, LambdaDefinedCommandOptions.ARGUMENT_CLOUDFORMATION_ROLE, false), Tags = tagList }; if (new FileInfo(templatePath).Length < LambdaConstants.MAX_TEMPLATE_BODY_IN_REQUEST_SIZE) { changeSetRequest.TemplateBody = templateBody; } else { changeSetRequest.TemplateURL = this.S3Client.GetPreSignedURL(new S3.Model.GetPreSignedUrlRequest { BucketName = s3Bucket, Key = s3KeyTemplate, Expires = DateTime.Now.AddHours(1) }); } // Create the change set which performs the transformation on the Serverless resources in the template. changeSetResponse = await this.CloudFormationClient.CreateChangeSetAsync(changeSetRequest); this.Logger.WriteLine("CloudFormation change set created"); } catch (LambdaToolsException) { throw; } catch (Exception e) { throw new LambdaToolsException($"Error creating CloudFormation change set: {e.Message}", LambdaToolsException.LambdaErrorCode.CloudFormationCreateStack, e); } // The change set can take a few seconds to be reviewed and be ready to be executed. if (!await WaitForChangeSetBeingAvailableAsync(changeSetResponse.Id)) { return(false); } var executeChangeSetRequest = new ExecuteChangeSetRequest { StackName = stackName, ChangeSetName = changeSetResponse.Id }; // Execute the change set. DateTime timeChangeSetExecuted = DateTime.Now; try { await this.CloudFormationClient.ExecuteChangeSetAsync(executeChangeSetRequest); if (changeSetType == ChangeSetType.CREATE) { this.Logger.WriteLine($"Created CloudFormation stack {stackName}"); } else { this.Logger.WriteLine($"Initiated CloudFormation stack update on {stackName}"); } } catch (Exception e) { throw new LambdaToolsException($"Error executing CloudFormation change set: {e.Message}", LambdaToolsException.LambdaErrorCode.CloudFormationCreateChangeSet, e); } // Wait for the stack to finish unless the user opts out of waiting. The VS Toolkit opts out and // instead shows the stack view in the IDE, enabling the user to view progress. var shouldWait = GetBoolValueOrDefault(this.WaitForStackToComplete, LambdaDefinedCommandOptions.ARGUMENT_STACK_WAIT, false); if (!shouldWait.HasValue || shouldWait.Value) { var updatedStack = await WaitStackToCompleteAsync(stackName, timeChangeSetExecuted); if (updatedStack.StackStatus == StackStatus.CREATE_COMPLETE || updatedStack.StackStatus == StackStatus.UPDATE_COMPLETE) { this.Logger.WriteLine($"Stack finished updating with status: {updatedStack.StackStatus}"); // Display the output parameters. DisplayOutputs(updatedStack); } else { this.Logger.WriteLine($"Stack update failed with status: {updatedStack.StackStatus} ({updatedStack.StackStatusReason})"); return(false); } } return(true); }
/// <summary> /// 执行更改集 /// </summary> /// <param name="request">请求参数信息</param> /// <returns>请求结果信息</returns> public async Task <ExecuteChangeSetResponse> ExecuteChangeSet(ExecuteChangeSetRequest request) { return(await new ExecuteChangeSetExecutor().Client(this).Execute <ExecuteChangeSetResponse, ExecuteChangeSetResult, ExecuteChangeSetRequest>(request).ConfigureAwait(false)); }
/// <summary> /// 执行更改集 /// </summary> /// <param name="request">请求参数信息</param> /// <returns>请求结果信息</returns> public ExecuteChangeSetResponse ExecuteChangeSet(ExecuteChangeSetRequest request) { return(new ExecuteChangeSetExecutor().Client(this).Execute <ExecuteChangeSetResponse, ExecuteChangeSetResult, ExecuteChangeSetRequest>(request)); }
public static async Task <DeployStackResult> DeployStackAsync(ILogger log, IAmazonCloudFormation cloudformation, long ticks, string stackName, List <Tag> tags, Dictionary <string, string> parameters, string templateBody = null, Uri templateUrl = null, string roleArn = null) { log.Information("Checking stack: {stackName}", stackName); Stack existingStack = await GetExistingStackAsync(cloudformation, stackName).ConfigureAwait(false); log.Information("Found existing stack: " + (existingStack != null)); var changeSetName = stackName + "-" + ticks; var param = parameters.Select(x => new Parameter { ParameterKey = x.Key, ParameterValue = x.Value }).ToList(); // Determine if the stack is in a good state to be updated. ChangeSetType changeSetType; if (existingStack == null || existingStack.StackStatus == StackStatus.REVIEW_IN_PROGRESS || existingStack.StackStatus == StackStatus.DELETE_COMPLETE) { changeSetType = ChangeSetType.CREATE; } // If the state was ROLLBACK_COMPLETE that means the stack failed on initial creation and the resources where cleaned up. // It is safe to delete the stack so we can recreate it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(log, cloudformation, existingStack).ConfigureAwait(false); changeSetType = ChangeSetType.CREATE; } // If the status was ROLLBACK_IN_PROGRESS that means the initial creation is failing. // Wait to see if it goes into ROLLBACK_COMPLETE status meaning everything got cleaned up and then delete it. else if (existingStack.StackStatus == StackStatus.ROLLBACK_IN_PROGRESS) { existingStack = await WaitForNoLongerInProgress(log, cloudformation, existingStack.StackName).ConfigureAwait(false); if (existingStack != null && existingStack.StackStatus == StackStatus.ROLLBACK_COMPLETE) { await DeleteRollbackCompleteStackAsync(log, cloudformation, existingStack).ConfigureAwait(false); } changeSetType = ChangeSetType.CREATE; } // If the status was DELETE_IN_PROGRESS then just wait for delete to complete else if (existingStack.StackStatus == StackStatus.DELETE_IN_PROGRESS) { await WaitForNoLongerInProgress(log, cloudformation, existingStack.StackName).ConfigureAwait(false); changeSetType = ChangeSetType.CREATE; } // The Stack state is in a normal state and ready to be updated. else if (existingStack.StackStatus == StackStatus.CREATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_COMPLETE || existingStack.StackStatus == StackStatus.UPDATE_ROLLBACK_COMPLETE) { changeSetType = ChangeSetType.UPDATE; } // All other states means the Stack is in an inconsistent state. else { log.Error($"The stack's current state of {existingStack.StackStatus} is invalid for updating"); return(DeployStackResult.Failed); } CreateChangeSetResponse changeSetResponse; try { var changeSetRequest = new CreateChangeSetRequest { StackName = stackName, ChangeSetName = changeSetName, ChangeSetType = changeSetType, Capabilities = new List <string> { CAPABILITY_NAMED_IAM }, Tags = tags, Parameters = param, RoleARN = roleArn }; if (templateUrl != null) { changeSetRequest.TemplateURL = templateUrl.ToString(); } else { changeSetRequest.TemplateBody = templateBody; } // Create the change set which performs the transformation on the Serverless resources in the template. changeSetResponse = await cloudformation.CreateChangeSetAsync(changeSetRequest).ConfigureAwait(false); log.Information("CloudFormation change set created. StackName: {stackName}, ChangeSetName: {changeSetName}", stackName, changeSetName); } catch (Exception e) { log.Error(e, "Error creating cloudformation change set"); throw; } // The change set can take a few seconds to be reviewed and be ready to be executed. DeployStackResult waitResult = await WaitForChangeSetBeingAvailableAsync(log, cloudformation, changeSetResponse.Id).ConfigureAwait(false); if (waitResult == DeployStackResult.NoChanges || waitResult == DeployStackResult.Failed) { return(waitResult); } var executeChangeSetRequest = new ExecuteChangeSetRequest { StackName = stackName, ChangeSetName = changeSetResponse.Id }; // Execute the change set. var timeChangeSetExecuted = DateTime.Now; try { await cloudformation.ExecuteChangeSetAsync(executeChangeSetRequest).ConfigureAwait(false); if (changeSetType == ChangeSetType.CREATE) { log.Information($"Created CloudFormation stack {stackName}"); } else { log.Information($"Initiated CloudFormation stack update on {stackName}"); } } catch (Exception e) { log.Error(e, "Error executing cloudformation change set"); throw; } // Wait for the stack to finish var updatedStack = await WaitStackToCompleteAsync(log, cloudformation, stackName, timeChangeSetExecuted).ConfigureAwait(false); if (updatedStack.StackStatus == StackStatus.CREATE_COMPLETE || updatedStack.StackStatus == StackStatus.UPDATE_COMPLETE) { log.Information($"Stack finished updating with status: {updatedStack.StackStatus}"); // Display the output parameters. DisplayOutputs(log, updatedStack); } else { log.Error($"Stack update failed with status: {updatedStack.StackStatus} ({updatedStack.StackStatusReason})"); return(DeployStackResult.Failed); } return(DeployStackResult.Ok); }