Exemple #1
0
// Service Update takes a map of CF Parameter changes and applies on top of
// the existing parameters and the newest template.
// The CLI / Client / Server delegates everything to CloudFormation, and
// makes no guarantees of service uptime during update. In fact, most datastore
// updates guarantee resource replacement which will cause database downtime.
func (s *Service) Update(changes map[string]string) error {
	var req *cloudformation.UpdateStackInput
	var err error

	switch s.Type {
	case "papertrail":
		return fmt.Errorf("can not update papertrail")
	case "webhook":
		return fmt.Errorf("can not update webhook")
	case "s3", "sns", "sqs":
		req, err = s.UpdateIAMService()
	default:
		req, err = s.UpdateDatastore()
	}

	if err != nil {
		return err
	}

	params := map[string]string{}

	// copy existing parameters
	for key, value := range s.Parameters {
		params[key] = value
	}

	// update changes
	for key, value := range changes {
		params[key] = value
	}

	fp, err := formationParameters(*req.TemplateBody)

	if err != nil {
		return err
	}

	// remove params that don't exist in the template
	for key := range params {
		if _, ok := fp[key]; !ok {
			delete(params, key)
		}
	}

	// pass through service parameters as Cloudformation Parameters
	for key, value := range params {
		req.Parameters = append(req.Parameters, &cloudformation.Parameter{
			ParameterKey:   aws.String(key),
			ParameterValue: aws.String(value),
		})
	}

	_, err = CloudFormation().UpdateStack(req)

	return err
}
Exemple #2
0
// executeStackUpdate performs a stack update.
func (s *Scheduler) executeStackUpdate(input *cloudformation.UpdateStackInput) error {
	stack, err := s.stack(input.StackName)
	if err != nil {
		return err
	}

	// If we're updating a stack, without changing the template, merge in
	// existing parameters with their previous value.
	if input.UsePreviousTemplate != nil && *input.UsePreviousTemplate == true {
		// The parameters that the stack defines. We need to make sure that we
		// provide all parameters in the update (lame).
		definedParams := make(map[string]bool)
		for _, p := range stack.Parameters {
			definedParams[*p.ParameterKey] = true
		}

		// The parameters that are provided in this update.
		providedParams := make(map[string]bool)
		for _, p := range input.Parameters {
			providedParams[*p.ParameterKey] = true
		}

		// Fill in any parameters that weren't provided with their default
		// value.
		for k := range definedParams {
			if !providedParams[k] {
				input.Parameters = append(input.Parameters, &cloudformation.Parameter{
					ParameterKey:     aws.String(k),
					UsePreviousValue: aws.Bool(true),
				})
			}
		}
	}

	_, err = s.cloudformation.UpdateStack(input)
	if err != nil {
		if err, ok := err.(awserr.Error); ok {
			if err.Code() == "ValidationError" && err.Message() == "No updates are to be performed." {
				return nil
			}
		}

		return fmt.Errorf("error updating stack: %v", err)
	}

	return nil
}
			BeforeEach(func() {
				stackDetails.NotificationARNs = []string{"test-notification-arn"}
				updateStackInput.NotificationARNs = aws.StringSlice([]string{"test-notification-arn"})
			})

			It("makes the proper call", func() {
				err := stack.Modify(stackName, stackDetails)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		Context("when has Parameters", func() {
			BeforeEach(func() {
				stackDetails.Parameters = map[string]string{"test-parameter-key-1": "test-parameter-value-1"}
				updateStackInput.Parameters = []*cloudformation.Parameter{
					&cloudformation.Parameter{ParameterKey: aws.String("test-parameter-key-1"), ParameterValue: aws.String("test-parameter-value-1")},
				}
			})

			It("makes the proper call", func() {
				err := stack.Modify(stackName, stackDetails)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		Context("when has ResourceTypes", func() {
			BeforeEach(func() {
				stackDetails.ResourceTypes = []string{"test-resource-type"}
				updateStackInput.ResourceTypes = aws.StringSlice([]string{"test-resource-type"})
			})