Пример #1
0
        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""
    }
  }
}"
                );
        }
Пример #2
0
        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""
      }
    }
  }
}"
                );
        }
Пример #3
0
        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""
    }
  }
}"
                );
        }
Пример #4
0
        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;
            }
        }
Пример #6
0
        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]\"");
        }
Пример #9
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, "[]"));

            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);
        }
Пример #10
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);
        }
Пример #13
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);
        }