public void SerializeEmptyParameter() { // arrange var template = new CloudFormationTemplate { Parameters = { ["Param1"] = new CloudFormationParameter { Type = "String" } } }; // act var json = JsonSerializer.Serialize(template, new JsonSerializerOptions { IgnoreNullValues = true, WriteIndented = true }); // assert json.Should().Be( @"{ ""AWSTemplateFormatVersion"": ""2010-09-09"", ""Parameters"": { ""Param1"": { ""Type"": ""String"" } } }" ); }
public void SerializeEmptyResource() { // arrange var template = new CloudFormationTemplate { Resources = { ["Resource1"] = new CloudFormationResource("AWS::SNS::Topic") { ["TopicName"] = new CloudFormationLiteral("topic-name") } } }; // act var json = JsonSerializer.Serialize(template, new JsonSerializerOptions { IgnoreNullValues = true, WriteIndented = true }); // assert json.Should().Be( @"{ ""AWSTemplateFormatVersion"": ""2010-09-09"", ""Resources"": { ""Resource1"": { ""Type"": ""AWS::SNS::Topic"", ""Properties"": { ""TopicName"": ""topic-name"" } } } }" ); }
public void SerializeResource() { // arrange var template = new CloudFormationTemplate { Resources = { ["Resource1"] = new CloudFormationResource("AWS::SNS::Topic") { Properties = { ["TopicName"] = new CloudFormationLiteral("topic-name") }, DependsOn = { "Resource1" }, Metadata = { ["meta-data"] = new CloudFormationObject { ["OriginalName"] = new CloudFormationLiteral("name") } }, Condition = "Condition1", DeletionPolicy = "Retain" } } }; // act var json = JsonSerializer.Serialize(template, new JsonSerializerOptions { IgnoreNullValues = true, WriteIndented = true }); // assert json.Should().Be( @"{ ""AWSTemplateFormatVersion"": ""2010-09-09"", ""Resources"": { ""Resource1"": { ""Type"": ""AWS::SNS::Topic"", ""Properties"": { ""TopicName"": ""topic-name"" }, ""DependsOn"": [ ""Resource1"" ], ""Metadata"": { ""meta-data"": { ""OriginalName"": ""name"" } }, ""Condition"": ""Condition1"", ""DeletionPolicy"": ""Retain"" } } }" ); }
public void SerializeParameter() { // arrange var template = new CloudFormationTemplate { Parameters = { ["Param1"] = new CloudFormationParameter { Type = "String", Description = "Hello", AllowedPattern = ".*", AllowedValues = new List <string> { "abc", "def" }, ConstraintDescription = "Constraint", Default = "ghi", MinLength = 1, MaxLength = 10, MinValue = 100, MaxValue = 1000, NoEcho = false } } }; // act var json = JsonSerializer.Serialize(template, new JsonSerializerOptions { IgnoreNullValues = true, WriteIndented = true }); // assert json.Should().Be( @"{ ""AWSTemplateFormatVersion"": ""2010-09-09"", ""Parameters"": { ""Param1"": { ""Type"": ""String"", ""Description"": ""Hello"", ""AllowedPattern"": "".*"", ""AllowedValues"": [ ""abc"", ""def"" ], ""ConstraintDescription"": ""Constraint"", ""Default"": ""ghi"", ""MinLength"": 1, ""MaxLength"": 10, ""MinValue"": 100, ""MaxValue"": 1000, ""NoEcho"": false } } }" ); }
/// <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, CloudFormationTemplate template) { Guard.NotNull(deployment, "deployment can not be null"); try { var result = await ClientHelpers.CreateCloudFormationClient(awsEnvironmentGeneration).UpdateStackAsync(new UpdateStackRequest { StackName = stackName, TemplateBody = template.Content, Parameters = template.Inputs.ToList(), Capabilities = capabilities, RoleARN = roleArnProvider(deployment) }); 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)); return(await CreateCloudFormation(deployment, template)); } catch (AmazonServiceException ex) { LogAmazonServiceException(ex); throw ex; } }
public void SerializeEmptyTemplate() { // arrange var template = new CloudFormationTemplate(); // act var json = JsonSerializer.Serialize(template, new JsonSerializerOptions { IgnoreNullValues = true, WriteIndented = true }); // assert json.Should().Be( @"{ ""AWSTemplateFormatVersion"": ""2010-09-09"" }" ); }
/// <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, CloudFormationTemplate template) { Guard.NotNull(template, "template can not be null"); return(WithAmazonServiceExceptionHandling(async() => { var result = await clientFactory.CreateStackAsync(new CreateStackRequest { StackName = stackName, TemplateBody = template.Content, Parameters = template.Inputs.ToList(), Capabilities = capabilities, DisableRollback = disableRollback, RoleARN = roleArnProvider(deployment) }); Log.Info("Created stack with id {stackId} in region {awsEnvironmentGeneration.AwsRegion.SystemName}"); return result; })); }
/// <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, CloudFormationTemplate template) { 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)); } // 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]\""); }
public override int Execute(string[] commandLineArguments) { Options.Parse(commandLineArguments); var filesInPackage = !string.IsNullOrWhiteSpace(pathToPackage); var environment = AwsEnvironmentGeneration.Create(log, variables).GetAwaiter().GetResult(); var templateResolver = new TemplateResolver(fileSystem); IAmazonCloudFormation ClientFactory() => ClientHelpers.CreateCloudFormationClient(environment); StackArn StackProvider(RunningDeployment x) => new StackArn(stackName); ChangeSetArn ChangesetProvider(RunningDeployment x) => new ChangeSetArn(x.Variables[AwsSpecialVariables.CloudFormation.Changesets.Arn]); string RoleArnProvider(RunningDeployment x) => x.Variables[AwsSpecialVariables.CloudFormation.RoleArn]; var iamCapabilities = JsonConvert.DeserializeObject <List <string> >(variables.Get(AwsSpecialVariables.IamCapabilities, "[]")); CloudFormationTemplate TemplateFactory() { var resolvedTemplate = templateResolver.Resolve(templateFile, filesInPackage, variables); var resolvedParameters = templateResolver.MaybeResolve(templateParameterFile, filesInPackage, variables); if (templateParameterFile != null && !resolvedParameters.Some()) { throw new CommandException("Could not find template parameters file: " + templateParameterFile); } var parameters = CloudFormationParametersFile.Create(resolvedParameters, fileSystem, variables); return(CloudFormationTemplate.Create(resolvedTemplate, parameters, fileSystem, variables)); } var stackEventLogger = new StackEventLogger(log); var conventions = new List <IConvention> { new LogAwsUserInfoConvention(environment), new DelegateInstallConvention(d => extractPackage.ExtractToStagingDirectory(pathToPackage)), //Create or Update the stack using changesets new AggregateInstallationConvention( new GenerateCloudFormationChangesetNameConvention(log), new CreateCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, RoleArnProvider, TemplateFactory, iamCapabilities), new DescribeCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider), new ExecuteCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider, waitForComplete) .When(ImmediateChangesetExecution), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider, () => TemplateFactory().HasOutputs) .When(ImmediateChangesetExecution) ).When(ChangesetsEnabled), //Create or update stack using a template (no changesets) new AggregateInstallationConvention( new DeployAwsCloudFormationConvention( ClientFactory, TemplateFactory, stackEventLogger, StackProvider, RoleArnProvider, waitForComplete, stackName, iamCapabilities, disableRollback, environment), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider, () => TemplateFactory().HasOutputs) ) .When(ChangesetsDisabled) }; var deployment = new RunningDeployment(pathToPackage, variables); var conventionRunner = new ConventionProcessor(deployment, conventions, log); conventionRunner.RunConventions(); return(0); }
private CreateChangeSetRequest CreateChangesetRequest(StackStatus status, string changesetName, StackArn stack, string roleArn, CloudFormationTemplate template, List <string> capabilities) { return(new CreateChangeSetRequest { StackName = stack.Value, TemplateBody = template.Content, Parameters = template.Inputs.ToList(), ChangeSetName = changesetName, ChangeSetType = status == StackStatus.DoesNotExist ? ChangeSetType.CREATE : ChangeSetType.UPDATE, Capabilities = capabilities, RoleARN = roleArn }); }
private async Task DeployCloudFormation(RunningDeployment deployment, StackArn stack, CloudFormationTemplate template) { Guard.NotNull(deployment, "deployment can not be null"); await clientFactory.WaitForStackToComplete(CloudFormationDefaults.StatusWaitPeriod, stack, LogAndThrowRollbacks(clientFactory, stack, false)); await DeployStack(deployment, stack, template); }
public override int Execute(string[] commandLineArguments) { Options.Parse(commandLineArguments); if (variablesFile != null && !File.Exists(variablesFile)) { throw new CommandException("Could not find variables file: " + variablesFile); } var variables = new CalamariVariableDictionary(variablesFile, sensitiveVariablesFile, sensitiveVariablesPassword); var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem(); var filesInPackage = !string.IsNullOrWhiteSpace(packageFile); var environment = new AwsEnvironmentGeneration(variables); var templateResolver = new TemplateResolver(fileSystem); IAmazonCloudFormation ClientFactory() => ClientHelpers.CreateCloudFormationClient(environment); StackArn StackProvider(RunningDeployment x) => new StackArn(stackName); ChangeSetArn ChangesetProvider(RunningDeployment x) => new ChangeSetArn(x.Variables[AwsSpecialVariables.CloudFormation.Changesets.Arn]); string RoleArnProvider(RunningDeployment x) => x.Variables[AwsSpecialVariables.CloudFormation.RoleArn]; CloudFormationTemplate TemplateFactory() { var resolvedTemplate = templateResolver.Resolve(templateFile, filesInPackage, variables); var resolvedParameters = templateResolver.MaybeResolve(templateParameterFile, filesInPackage, variables); if (templateParameterFile != null && !resolvedParameters.Some()) { throw new CommandException("Could not find template parameters file: " + templateParameterFile); } var parameters = CloudFormationParametersFile.Create(resolvedParameters, fileSystem, variables); return(CloudFormationTemplate.Create(resolvedTemplate, parameters, fileSystem, variables)); } var stackEventLogger = new StackEventLogger(new LogWrapper()); var conventions = new List <IConvention> { new LogAwsUserInfoConvention(environment), new ContributeEnvironmentVariablesConvention(), new LogVariablesConvention(), new ExtractPackageToStagingDirectoryConvention(new GenericPackageExtractorFactory().createStandardGenericPackageExtractor(), fileSystem), //Create or Update the stack using changesets new AggregateInstallationConvention( new GenerateCloudFormationChangesetNameConvention(), new CreateCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, RoleArnProvider, TemplateFactory, iamCapabilities), new DescribeCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider), new ExecuteCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider, waitForComplete) .When(ImmediateChangesetExecution), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider, () => TemplateFactory().HasOutputs) .When(ImmediateChangesetExecution) ).When(ChangesetsEnabled), //Create or update stack using a template (no changesets) new AggregateInstallationConvention( new DeployAwsCloudFormationConvention( ClientFactory, TemplateFactory, stackEventLogger, StackProvider, RoleArnProvider, waitForComplete, stackName, iamCapabilities, disableRollback, environment), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider, () => TemplateFactory().HasOutputs) ) .When(ChangesetsDisabled) }; var deployment = new RunningDeployment(packageFile, variables); var conventionRunner = new ConventionProcessor(deployment, conventions); conventionRunner.RunConventions(); return(0); }
public override int Execute(string[] commandLineArguments) { Options.Parse(commandLineArguments); var filesInPackage = !string.IsNullOrWhiteSpace(pathToPackage); var environment = AwsEnvironmentGeneration.Create(log, variables).GetAwaiter().GetResult(); var templateResolver = new TemplateResolver(fileSystem); IAmazonCloudFormation ClientFactory() => ClientHelpers.CreateCloudFormationClient(environment); StackArn StackProvider(RunningDeployment x) => new StackArn(stackName); ChangeSetArn ChangesetProvider(RunningDeployment x) => new ChangeSetArn(x.Variables[AwsSpecialVariables.CloudFormation.Changesets.Arn]); string RoleArnProvider(RunningDeployment x) => x.Variables[AwsSpecialVariables.CloudFormation.RoleArn]; var iamCapabilities = JsonConvert.DeserializeObject <List <string> >(variables.Get(AwsSpecialVariables.IamCapabilities, "[]")); var tags = JsonConvert.DeserializeObject <List <KeyValuePair <string, string> > >(variables.Get(AwsSpecialVariables.CloudFormation.Tags, "[]")); var deployment = new RunningDeployment(pathToPackage, variables); ICloudFormationRequestBuilder TemplateFactory() => string.IsNullOrWhiteSpace(templateS3Url) ? CloudFormationTemplate.Create(templateResolver, templateFile, templateParameterFile, filesInPackage, fileSystem, variables, stackName, iamCapabilities, disableRollback, RoleArnProvider(deployment), tags, StackProvider(deployment), ClientFactory) : CloudFormationS3Template.Create(templateS3Url, templateParameterS3Url, fileSystem, variables, log, stackName, iamCapabilities, disableRollback, RoleArnProvider(deployment), tags, StackProvider(deployment), ClientFactory); var stackEventLogger = new StackEventLogger(log); var conventions = new List <IConvention> { new LogAwsUserInfoConvention(environment), new DelegateInstallConvention(d => extractPackage.ExtractToStagingDirectory(pathToPackage)), new StructuredConfigurationVariablesConvention(new StructuredConfigurationVariablesBehaviour(structuredConfigVariablesService)), //Create or Update the stack using changesets new AggregateInstallationConvention( new GenerateCloudFormationChangesetNameConvention(log), new CreateCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, TemplateFactory), new DescribeCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider), new ExecuteCloudFormationChangeSetConvention(ClientFactory, stackEventLogger, StackProvider, ChangesetProvider, waitForComplete) .When(ImmediateChangesetExecution), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider) .When(ImmediateChangesetExecution) ).When(ChangesetsEnabled), //Create or update stack using a template (no changesets) new AggregateInstallationConvention( new DeployAwsCloudFormationConvention( ClientFactory, TemplateFactory, stackEventLogger, StackProvider, RoleArnProvider, waitForComplete, stackName, environment), new CloudFormationOutputsAsVariablesConvention(ClientFactory, stackEventLogger, StackProvider) ) .When(ChangesetsDisabled) }; var conventionRunner = new ConventionProcessor(deployment, conventions, log); conventionRunner.RunConventions(); return(0); }