func (p *AWSProvider) ServiceCreate(name, kind string, params map[string]string) (*structs.Service, error) { _, err := p.ServiceGet(name) if awsError(err) != "ValidationError" { return nil, fmt.Errorf("service named %s already exists", name) } s := &structs.Service{ Name: name, Parameters: cfParams(params), Type: kind, } var req *cloudformation.CreateStackInput switch s.Type { case "syslog": req, err = createSyslog(s) } if err != nil { return s, err } // pass through service parameters as Cloudformation Parameters for key, value := range s.Parameters { req.Parameters = append(req.Parameters, &cloudformation.Parameter{ ParameterKey: aws.String(key), ParameterValue: aws.String(value), }) } // tag the service tags := map[string]string{ "Rack": os.Getenv("RACK"), "System": "convox", "Service": s.Type, "Type": "service", "Name": s.Name, } for key, value := range tags { req.Tags = append(req.Tags, &cloudformation.Tag{Key: aws.String(key), Value: aws.String(value)}) } _, err = p.cloudformation().CreateStack(req) p.EventSend(&structs.Event{ Action: "service:create", Data: map[string]string{ "name": s.Name, "type": s.Type, }, }, err) return s, err }
func (s *Service) Create() error { var req *cloudformation.CreateStackInput var err error switch s.Type { case "papertrail": req, err = s.CreatePapertrail() case "webhook": req, err = s.CreateWebhook() case "s3": req, err = s.CreateS3() case "sns": req, err = s.CreateSNS() case "sqs": req, err = s.CreateSQS() default: req, err = s.CreateDatastore() } if err != nil { return err } // pass through service parameters as Cloudformation Parameters for key, value := range s.Parameters { req.Parameters = append(req.Parameters, &cloudformation.Parameter{ ParameterKey: aws.String(key), ParameterValue: aws.String(value), }) } // tag the service tags := map[string]string{ "Rack": os.Getenv("RACK"), "System": "convox", "Service": s.Type, "Type": "service", "Name": s.Name, } for key, value := range tags { req.Tags = append(req.Tags, &cloudformation.Tag{Key: aws.String(key), Value: aws.String(value)}) } _, err = CloudFormation().CreateStack(req) if err != nil { NotifySuccess("service:create", map[string]string{ "name": s.Name, "type": s.Type, }) } return err }
func resourceAwsCloudFormationStackCreate(d *schema.ResourceData, meta interface{}) error { retryTimeout := int64(30) conn := meta.(*AWSClient).cfconn input := cloudformation.CreateStackInput{ StackName: aws.String(d.Get("name").(string)), } if v, ok := d.GetOk("template_body"); ok { input.TemplateBody = aws.String(normalizeJson(v.(string))) } if v, ok := d.GetOk("template_url"); ok { input.TemplateURL = aws.String(v.(string)) } if v, ok := d.GetOk("capabilities"); ok { input.Capabilities = expandStringList(v.(*schema.Set).List()) } if v, ok := d.GetOk("disable_rollback"); ok { input.DisableRollback = aws.Bool(v.(bool)) } if v, ok := d.GetOk("notification_arns"); ok { input.NotificationARNs = expandStringList(v.(*schema.Set).List()) } if v, ok := d.GetOk("on_failure"); ok { input.OnFailure = aws.String(v.(string)) } if v, ok := d.GetOk("parameters"); ok { input.Parameters = expandCloudFormationParameters(v.(map[string]interface{})) } if v, ok := d.GetOk("policy_body"); ok { input.StackPolicyBody = aws.String(normalizeJson(v.(string))) } if v, ok := d.GetOk("policy_url"); ok { input.StackPolicyURL = aws.String(v.(string)) } if v, ok := d.GetOk("tags"); ok { input.Tags = expandCloudFormationTags(v.(map[string]interface{})) } if v, ok := d.GetOk("timeout_in_minutes"); ok { m := int64(v.(int)) input.TimeoutInMinutes = aws.Int64(m) if m > retryTimeout { retryTimeout = m + 5 log.Printf("[DEBUG] CloudFormation timeout: %d", retryTimeout) } } log.Printf("[DEBUG] Creating CloudFormation Stack: %s", input) resp, err := conn.CreateStack(&input) if err != nil { return fmt.Errorf("Creating CloudFormation stack failed: %s", err.Error()) } d.SetId(*resp.StackId) wait := resource.StateChangeConf{ Pending: []string{"CREATE_IN_PROGRESS", "ROLLBACK_IN_PROGRESS", "ROLLBACK_COMPLETE"}, Target: []string{"CREATE_COMPLETE"}, Timeout: time.Duration(retryTimeout) * time.Minute, MinTimeout: 5 * time.Second, Refresh: func() (interface{}, string, error) { resp, err := conn.DescribeStacks(&cloudformation.DescribeStacksInput{ StackName: aws.String(d.Get("name").(string)), }) status := *resp.Stacks[0].StackStatus log.Printf("[DEBUG] Current CloudFormation stack status: %q", status) if status == "ROLLBACK_COMPLETE" { stack := resp.Stacks[0] failures, err := getCloudFormationFailures(stack.StackName, *stack.CreationTime, conn) if err != nil { return resp, "", fmt.Errorf( "Failed getting details about rollback: %q", err.Error()) } return resp, "", fmt.Errorf("ROLLBACK_COMPLETE:\n%q", failures) } return resp, status, err }, } _, err = wait.WaitForState() if err != nil { return err } log.Printf("[INFO] CloudFormation Stack %q created", d.Get("name").(string)) return resourceAwsCloudFormationStackRead(d, meta) }
func resourceAwsCloudFormationStackCreate(d *schema.ResourceData, meta interface{}) error { retryTimeout := int64(30) conn := meta.(*AWSClient).cfconn input := cloudformation.CreateStackInput{ StackName: aws.String(d.Get("name").(string)), } if v, ok := d.GetOk("template_body"); ok { template, _ := normalizeJsonString(v.(string)) input.TemplateBody = aws.String(template) } if v, ok := d.GetOk("template_url"); ok { input.TemplateURL = aws.String(v.(string)) } if v, ok := d.GetOk("capabilities"); ok { input.Capabilities = expandStringList(v.(*schema.Set).List()) } if v, ok := d.GetOk("disable_rollback"); ok { input.DisableRollback = aws.Bool(v.(bool)) } if v, ok := d.GetOk("notification_arns"); ok { input.NotificationARNs = expandStringList(v.(*schema.Set).List()) } if v, ok := d.GetOk("on_failure"); ok { input.OnFailure = aws.String(v.(string)) } if v, ok := d.GetOk("parameters"); ok { input.Parameters = expandCloudFormationParameters(v.(map[string]interface{})) } if v, ok := d.GetOk("policy_body"); ok { policy, _ := normalizeJsonString(v.(string)) input.StackPolicyBody = aws.String(policy) } if v, ok := d.GetOk("policy_url"); ok { input.StackPolicyURL = aws.String(v.(string)) } if v, ok := d.GetOk("tags"); ok { input.Tags = expandCloudFormationTags(v.(map[string]interface{})) } if v, ok := d.GetOk("timeout_in_minutes"); ok { m := int64(v.(int)) input.TimeoutInMinutes = aws.Int64(m) if m > retryTimeout { retryTimeout = m + 5 log.Printf("[DEBUG] CloudFormation timeout: %d", retryTimeout) } } log.Printf("[DEBUG] Creating CloudFormation Stack: %s", input) resp, err := conn.CreateStack(&input) if err != nil { return fmt.Errorf("Creating CloudFormation stack failed: %s", err.Error()) } d.SetId(*resp.StackId) var lastStatus string wait := resource.StateChangeConf{ Pending: []string{ "CREATE_IN_PROGRESS", "DELETE_IN_PROGRESS", "ROLLBACK_IN_PROGRESS", }, Target: []string{ "CREATE_COMPLETE", "CREATE_FAILED", "DELETE_COMPLETE", "DELETE_FAILED", "ROLLBACK_COMPLETE", "ROLLBACK_FAILED", }, Timeout: time.Duration(retryTimeout) * time.Minute, MinTimeout: 1 * time.Second, Refresh: func() (interface{}, string, error) { resp, err := conn.DescribeStacks(&cloudformation.DescribeStacksInput{ StackName: aws.String(d.Id()), }) if err != nil { log.Printf("[ERROR] Failed to describe stacks: %s", err) return nil, "", err } if len(resp.Stacks) == 0 { // This shouldn't happen unless CloudFormation is inconsistent // See https://github.com/hashicorp/terraform/issues/5487 log.Printf("[WARN] CloudFormation stack %q not found.\nresponse: %q", d.Id(), resp) return resp, "", fmt.Errorf( "CloudFormation stack %q vanished unexpectedly during creation.\n"+ "Unless you knowingly manually deleted the stack "+ "please report this as bug at https://github.com/hashicorp/terraform/issues\n"+ "along with the config & Terraform version & the details below:\n"+ "Full API response: %s\n", d.Id(), resp) } status := *resp.Stacks[0].StackStatus lastStatus = status log.Printf("[DEBUG] Current CloudFormation stack status: %q", status) return resp, status, err }, } _, err = wait.WaitForState() if err != nil { return err } if lastStatus == "ROLLBACK_COMPLETE" || lastStatus == "ROLLBACK_FAILED" { reasons, err := getCloudFormationRollbackReasons(d.Id(), nil, conn) if err != nil { return fmt.Errorf("Failed getting rollback reasons: %q", err.Error()) } return fmt.Errorf("%s: %q", lastStatus, reasons) } if lastStatus == "DELETE_COMPLETE" || lastStatus == "DELETE_FAILED" { reasons, err := getCloudFormationDeletionReasons(d.Id(), conn) if err != nil { return fmt.Errorf("Failed getting deletion reasons: %q", err.Error()) } d.SetId("") return fmt.Errorf("%s: %q", lastStatus, reasons) } if lastStatus == "CREATE_FAILED" { reasons, err := getCloudFormationFailures(d.Id(), conn) if err != nil { return fmt.Errorf("Failed getting failure reasons: %q", err.Error()) } return fmt.Errorf("%s: %q", lastStatus, reasons) } log.Printf("[INFO] CloudFormation Stack %q created", d.Id()) return resourceAwsCloudFormationStackRead(d, meta) }
BeforeEach(func() { stackDetails.OnFailure = "test-on-failure" createStackInput.OnFailure = aws.String("test-on-failure") }) It("makes the proper call", func() { err := stack.Create(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"} createStackInput.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.Create(stackName, stackDetails) Expect(err).ToNot(HaveOccurred()) }) }) Context("when has ResourceTypes", func() { BeforeEach(func() { stackDetails.ResourceTypes = []string{"test-resource-type"} createStackInput.ResourceTypes = aws.StringSlice([]string{"test-resource-type"}) })
func (p *AWSProvider) ServiceCreate(name, kind string, params map[string]string) (*structs.Service, error) { _, err := p.ServiceGet(name) if awsError(err) != "ValidationError" { return nil, fmt.Errorf("service named %s already exists", name) } s := &structs.Service{ Name: name, Parameters: cfParams(params), Type: kind, } s.Parameters["CustomTopic"] = customTopic s.Parameters["NotificationTopic"] = notificationTopic var req *cloudformation.CreateStackInput switch s.Type { case "memcached", "mysql", "postgres", "redis", "sqs": req, err = p.createService(s) case "fluentd": req, err = p.createServiceURL(s, "tcp") case "s3": if s.Parameters["Topic"] != "" { s.Parameters["Topic"] = fmt.Sprintf("%s-%s", p.Rack, s.Parameters["Topic"]) } req, err = p.createService(s) case "sns": if s.Parameters["Queue"] != "" { s.Parameters["Queue"] = fmt.Sprintf("%s-%s", p.Rack, s.Parameters["Queue"]) } req, err = p.createService(s) case "syslog": req, err = p.createServiceURL(s, "tcp", "tcp+tls", "udp") case "webhook": s.Parameters["Url"] = fmt.Sprintf("http://%s/sns?endpoint=%s", p.NotificationHost, url.QueryEscape(s.Parameters["Url"])) req, err = p.createServiceURL(s, "http", "https") default: err = fmt.Errorf("Invalid service type: %s", s.Type) } if err != nil { return s, err } keys := []string{} for key := range s.Parameters { keys = append(keys, key) } // sort keys for easier testing sort.Strings(keys) // pass through service parameters as Cloudformation Parameters for _, key := range keys { req.Parameters = append(req.Parameters, &cloudformation.Parameter{ ParameterKey: aws.String(key), ParameterValue: aws.String(s.Parameters[key]), }) } // tag the service tags := map[string]string{ "Name": s.Name, "Rack": p.Rack, "Service": s.Type, "System": "convox", "Type": "service", } tagKeys := []string{} for key := range tags { tagKeys = append(tagKeys, key) } // sort keys for easier testing sort.Strings(tagKeys) for _, key := range tagKeys { req.Tags = append(req.Tags, &cloudformation.Tag{Key: aws.String(key), Value: aws.String(tags[key])}) } _, err = p.cloudformation().CreateStack(req) p.EventSend(&structs.Event{ Action: "service:create", Data: map[string]string{ "name": s.Name, "type": s.Type, }, }, err) return s, err }