/// <summary> /// Creates the stack and returns the stack ID /// </summary> /// <param name="deployment">The running deployment</param> /// <returns>The stack id</returns> private Task <string> CreateCloudFormation(RunningDeployment deployment, ICloudFormationRequestBuilder template) { Guard.NotNull(template, "template can not be null"); return(WithAmazonServiceExceptionHandling(async() => { var stackId = await clientFactory.CreateStackAsync(template.BuildCreateStackRequest()); Log.Info($"Created stack {stackId} in region {awsEnvironmentGeneration.AwsRegion.SystemName}"); return stackId; })); }
/// <summary> /// Updates the stack and returns the stack ID /// </summary> /// <param name="stack">The stack name or id</param> /// <param name="deployment">The current deployment</param> /// <param name="template">The CloudFormation template</param> /// <returns>stackId</returns> private async Task <string> UpdateCloudFormation( RunningDeployment deployment, StackArn stack, ICloudFormationRequestBuilder template) { Guard.NotNull(deployment, "deployment can not be null"); var deploymentStartTime = DateTime.Now; try { var result = await ClientHelpers.CreateCloudFormationClient(awsEnvironmentGeneration) .UpdateStackAsync(template.BuildUpdateStackRequest()); Log.Info( $"Updated stack with id {result.StackId} in region {awsEnvironmentGeneration.AwsRegion.SystemName}"); return(result.StackId); } catch (AmazonCloudFormationException ex) { // Some stack states indicate that we can delete the stack and start again. Otherwise we have some other // exception that needs to be dealt with. if (!(await StackMustBeDeleted(stack)).SelectValueOrDefault(x => x)) { // Is this an unrecoverable state, or just a stack that has nothing to update? if (DealWithUpdateException(ex)) { // There was nothing to update, but we return the id for consistency anyway var result = await QueryStackAsync(clientFactory, stack); return(result.StackId); } } // If the stack exists, is in a ROLLBACK_COMPLETE state, and was never successfully // created in the first place, we can end up here. In this case we try to create // the stack from scratch. await DeleteCloudFormation(stack); await clientFactory.WaitForStackToComplete(CloudFormationDefaults.StatusWaitPeriod, stack, LogAndThrowRollbacks(clientFactory, stack, false, filter : FilterStackEventsSince(deploymentStartTime))); return(await CreateCloudFormation(deployment, template)); } catch (AmazonServiceException ex) { LogAmazonServiceException(ex); throw; } }
/// <summary> /// Update or create the stack /// </summary> /// <param name="deployment">The current deployment</param> /// <param name="stack"></param> /// <param name="template"></param> private async Task DeployStack(RunningDeployment deployment, StackArn stack, ICloudFormationRequestBuilder template, DateTime deploymentStartTime) { Guard.NotNull(deployment, "deployment can not be null"); var stackId = await template.Inputs // Use the parameters to either create or update the stack .Map(async parameters => await StackExists(stack, StackStatus.DoesNotExist) != StackStatus.DoesNotExist ?await UpdateCloudFormation(deployment, stack, template) : await CreateCloudFormation(deployment, template)); if (waitForComplete) { await clientFactory.WaitForStackToComplete(CloudFormationDefaults.StatusWaitPeriod, stack, LogAndThrowRollbacks(clientFactory, stack, filter : FilterStackEventsSince(deploymentStartTime))); } // Take the stack ID returned by the create or update events, and save it as an output variable Log.SetOutputVariable("AwsOutputs[StackId]", stackId ?? "", deployment.Variables); Log.Info( $"Saving variable \"Octopus.Action[{deployment.Variables["Octopus.Action.Name"]}].Output.AwsOutputs[StackId]\""); }
private async Task DeployCloudFormation(RunningDeployment deployment, StackArn stack, ICloudFormationRequestBuilder template) { Guard.NotNull(deployment, "deployment can not be null"); var deploymentStartTime = DateTime.Now; await clientFactory.WaitForStackToComplete(CloudFormationDefaults.StatusWaitPeriod, stack, LogAndThrowRollbacks(clientFactory, stack, false, filter : FilterStackEventsSince(deploymentStartTime))); await DeployStack(deployment, stack, template, deploymentStartTime); }