github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_codedeploy_deployment_group.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "regexp" 8 "sort" 9 "time" 10 11 "github.com/hashicorp/terraform/helper/hashcode" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 15 "github.com/aws/aws-sdk-go/aws" 16 "github.com/aws/aws-sdk-go/aws/awserr" 17 "github.com/aws/aws-sdk-go/service/codedeploy" 18 ) 19 20 func resourceAwsCodeDeployDeploymentGroup() *schema.Resource { 21 return &schema.Resource{ 22 Create: resourceAwsCodeDeployDeploymentGroupCreate, 23 Read: resourceAwsCodeDeployDeploymentGroupRead, 24 Update: resourceAwsCodeDeployDeploymentGroupUpdate, 25 Delete: resourceAwsCodeDeployDeploymentGroupDelete, 26 27 Schema: map[string]*schema.Schema{ 28 "app_name": &schema.Schema{ 29 Type: schema.TypeString, 30 Required: true, 31 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 32 value := v.(string) 33 if len(value) > 100 { 34 errors = append(errors, fmt.Errorf( 35 "%q cannot exceed 100 characters", k)) 36 } 37 return 38 }, 39 }, 40 41 "deployment_group_name": &schema.Schema{ 42 Type: schema.TypeString, 43 Required: true, 44 ForceNew: true, 45 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 46 value := v.(string) 47 if len(value) > 100 { 48 errors = append(errors, fmt.Errorf( 49 "%q cannot exceed 100 characters", k)) 50 } 51 return 52 }, 53 }, 54 55 "service_role_arn": &schema.Schema{ 56 Type: schema.TypeString, 57 Required: true, 58 }, 59 60 "alarm_configuration": &schema.Schema{ 61 Type: schema.TypeList, 62 Optional: true, 63 MaxItems: 1, 64 Elem: &schema.Resource{ 65 Schema: map[string]*schema.Schema{ 66 "alarms": &schema.Schema{ 67 Type: schema.TypeSet, 68 MaxItems: 10, 69 Optional: true, 70 Set: schema.HashString, 71 Elem: &schema.Schema{Type: schema.TypeString}, 72 }, 73 74 "enabled": &schema.Schema{ 75 Type: schema.TypeBool, 76 Optional: true, 77 }, 78 79 "ignore_poll_alarm_failure": &schema.Schema{ 80 Type: schema.TypeBool, 81 Optional: true, 82 Default: false, 83 }, 84 }, 85 }, 86 }, 87 88 "auto_rollback_configuration": &schema.Schema{ 89 Type: schema.TypeList, 90 Optional: true, 91 MaxItems: 1, 92 Elem: &schema.Resource{ 93 Schema: map[string]*schema.Schema{ 94 "enabled": &schema.Schema{ 95 Type: schema.TypeBool, 96 Optional: true, 97 }, 98 99 "events": &schema.Schema{ 100 Type: schema.TypeSet, 101 Optional: true, 102 Set: schema.HashString, 103 Elem: &schema.Schema{Type: schema.TypeString}, 104 }, 105 }, 106 }, 107 }, 108 109 "autoscaling_groups": &schema.Schema{ 110 Type: schema.TypeSet, 111 Optional: true, 112 Elem: &schema.Schema{Type: schema.TypeString}, 113 Set: schema.HashString, 114 }, 115 116 "deployment_config_name": &schema.Schema{ 117 Type: schema.TypeString, 118 Optional: true, 119 Default: "CodeDeployDefault.OneAtATime", 120 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 121 value := v.(string) 122 if len(value) > 100 { 123 errors = append(errors, fmt.Errorf( 124 "%q cannot exceed 100 characters", k)) 125 } 126 return 127 }, 128 }, 129 130 "ec2_tag_filter": &schema.Schema{ 131 Type: schema.TypeSet, 132 Optional: true, 133 Elem: &schema.Resource{ 134 Schema: map[string]*schema.Schema{ 135 "key": &schema.Schema{ 136 Type: schema.TypeString, 137 Optional: true, 138 }, 139 140 "type": &schema.Schema{ 141 Type: schema.TypeString, 142 Optional: true, 143 ValidateFunc: validateTagFilters, 144 }, 145 146 "value": &schema.Schema{ 147 Type: schema.TypeString, 148 Optional: true, 149 }, 150 }, 151 }, 152 Set: resourceAwsCodeDeployTagFilterHash, 153 }, 154 155 "on_premises_instance_tag_filter": &schema.Schema{ 156 Type: schema.TypeSet, 157 Optional: true, 158 Elem: &schema.Resource{ 159 Schema: map[string]*schema.Schema{ 160 "key": &schema.Schema{ 161 Type: schema.TypeString, 162 Optional: true, 163 }, 164 165 "type": &schema.Schema{ 166 Type: schema.TypeString, 167 Optional: true, 168 ValidateFunc: validateTagFilters, 169 }, 170 171 "value": &schema.Schema{ 172 Type: schema.TypeString, 173 Optional: true, 174 }, 175 }, 176 }, 177 Set: resourceAwsCodeDeployTagFilterHash, 178 }, 179 180 "trigger_configuration": &schema.Schema{ 181 Type: schema.TypeSet, 182 Optional: true, 183 Elem: &schema.Resource{ 184 Schema: map[string]*schema.Schema{ 185 "trigger_events": &schema.Schema{ 186 Type: schema.TypeSet, 187 Required: true, 188 Set: schema.HashString, 189 Elem: &schema.Schema{ 190 Type: schema.TypeString, 191 ValidateFunc: validateTriggerEvent, 192 }, 193 }, 194 195 "trigger_name": &schema.Schema{ 196 Type: schema.TypeString, 197 Required: true, 198 }, 199 200 "trigger_target_arn": &schema.Schema{ 201 Type: schema.TypeString, 202 Required: true, 203 }, 204 }, 205 }, 206 Set: resourceAwsCodeDeployTriggerConfigHash, 207 }, 208 }, 209 } 210 } 211 212 func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta interface{}) error { 213 conn := meta.(*AWSClient).codedeployconn 214 215 application := d.Get("app_name").(string) 216 deploymentGroup := d.Get("deployment_group_name").(string) 217 218 input := codedeploy.CreateDeploymentGroupInput{ 219 ApplicationName: aws.String(application), 220 DeploymentGroupName: aws.String(deploymentGroup), 221 ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)), 222 } 223 if attr, ok := d.GetOk("deployment_config_name"); ok { 224 input.DeploymentConfigName = aws.String(attr.(string)) 225 } 226 if attr, ok := d.GetOk("autoscaling_groups"); ok { 227 input.AutoScalingGroups = expandStringList(attr.(*schema.Set).List()) 228 } 229 if attr, ok := d.GetOk("on_premises_instance_tag_filter"); ok { 230 onPremFilters := buildOnPremTagFilters(attr.(*schema.Set).List()) 231 input.OnPremisesInstanceTagFilters = onPremFilters 232 } 233 if attr, ok := d.GetOk("ec2_tag_filter"); ok { 234 ec2TagFilters := buildEC2TagFilters(attr.(*schema.Set).List()) 235 input.Ec2TagFilters = ec2TagFilters 236 } 237 if attr, ok := d.GetOk("trigger_configuration"); ok { 238 triggerConfigs := buildTriggerConfigs(attr.(*schema.Set).List()) 239 input.TriggerConfigurations = triggerConfigs 240 } 241 242 if attr, ok := d.GetOk("auto_rollback_configuration"); ok { 243 input.AutoRollbackConfiguration = buildAutoRollbackConfig(attr.([]interface{})) 244 } 245 246 if attr, ok := d.GetOk("alarm_configuration"); ok { 247 input.AlarmConfiguration = buildAlarmConfig(attr.([]interface{})) 248 } 249 250 // Retry to handle IAM role eventual consistency. 251 var resp *codedeploy.CreateDeploymentGroupOutput 252 var err error 253 err = resource.Retry(5*time.Minute, func() *resource.RetryError { 254 resp, err = conn.CreateDeploymentGroup(&input) 255 if err != nil { 256 retry := false 257 codedeployErr, ok := err.(awserr.Error) 258 if !ok { 259 return resource.NonRetryableError(err) 260 } 261 if codedeployErr.Code() == "InvalidRoleException" { 262 retry = true 263 } 264 if codedeployErr.Code() == "InvalidTriggerConfigException" { 265 r := regexp.MustCompile("^Topic ARN .+ is not valid$") 266 if r.MatchString(codedeployErr.Message()) { 267 retry = true 268 } 269 } 270 if retry { 271 log.Printf("[DEBUG] Trying to create deployment group again: %q", 272 codedeployErr.Message()) 273 return resource.RetryableError(err) 274 } 275 276 return resource.NonRetryableError(err) 277 } 278 return nil 279 }) 280 if err != nil { 281 return err 282 } 283 284 d.SetId(*resp.DeploymentGroupId) 285 286 return resourceAwsCodeDeployDeploymentGroupRead(d, meta) 287 } 288 289 func resourceAwsCodeDeployDeploymentGroupRead(d *schema.ResourceData, meta interface{}) error { 290 conn := meta.(*AWSClient).codedeployconn 291 292 log.Printf("[DEBUG] Reading CodeDeploy DeploymentGroup %s", d.Id()) 293 resp, err := conn.GetDeploymentGroup(&codedeploy.GetDeploymentGroupInput{ 294 ApplicationName: aws.String(d.Get("app_name").(string)), 295 DeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)), 296 }) 297 if err != nil { 298 if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "DeploymentGroupDoesNotExistException" { 299 log.Printf("[INFO] CodeDeployment DeploymentGroup %s not found", d.Get("deployment_group_name").(string)) 300 d.SetId("") 301 return nil 302 } 303 304 return err 305 } 306 307 d.Set("app_name", resp.DeploymentGroupInfo.ApplicationName) 308 d.Set("autoscaling_groups", resp.DeploymentGroupInfo.AutoScalingGroups) 309 d.Set("deployment_config_name", resp.DeploymentGroupInfo.DeploymentConfigName) 310 d.Set("deployment_group_name", resp.DeploymentGroupInfo.DeploymentGroupName) 311 d.Set("service_role_arn", resp.DeploymentGroupInfo.ServiceRoleArn) 312 if err := d.Set("ec2_tag_filter", ec2TagFiltersToMap(resp.DeploymentGroupInfo.Ec2TagFilters)); err != nil { 313 return err 314 } 315 if err := d.Set("on_premises_instance_tag_filter", onPremisesTagFiltersToMap(resp.DeploymentGroupInfo.OnPremisesInstanceTagFilters)); err != nil { 316 return err 317 } 318 if err := d.Set("trigger_configuration", triggerConfigsToMap(resp.DeploymentGroupInfo.TriggerConfigurations)); err != nil { 319 return err 320 } 321 322 if err := d.Set("auto_rollback_configuration", autoRollbackConfigToMap(resp.DeploymentGroupInfo.AutoRollbackConfiguration)); err != nil { 323 return err 324 } 325 326 if err := d.Set("alarm_configuration", alarmConfigToMap(resp.DeploymentGroupInfo.AlarmConfiguration)); err != nil { 327 return err 328 } 329 330 return nil 331 } 332 333 func resourceAwsCodeDeployDeploymentGroupUpdate(d *schema.ResourceData, meta interface{}) error { 334 conn := meta.(*AWSClient).codedeployconn 335 336 input := codedeploy.UpdateDeploymentGroupInput{ 337 ApplicationName: aws.String(d.Get("app_name").(string)), 338 CurrentDeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)), 339 ServiceRoleArn: aws.String(d.Get("service_role_arn").(string)), 340 } 341 342 if d.HasChange("autoscaling_groups") { 343 _, n := d.GetChange("autoscaling_groups") 344 input.AutoScalingGroups = expandStringList(n.(*schema.Set).List()) 345 } 346 if d.HasChange("deployment_config_name") { 347 _, n := d.GetChange("deployment_config_name") 348 input.DeploymentConfigName = aws.String(n.(string)) 349 } 350 if d.HasChange("deployment_group_name") { 351 _, n := d.GetChange("deployment_group_name") 352 input.NewDeploymentGroupName = aws.String(n.(string)) 353 } 354 355 // TagFilters aren't like tags. They don't append. They simply replace. 356 if d.HasChange("on_premises_instance_tag_filter") { 357 _, n := d.GetChange("on_premises_instance_tag_filter") 358 onPremFilters := buildOnPremTagFilters(n.(*schema.Set).List()) 359 input.OnPremisesInstanceTagFilters = onPremFilters 360 } 361 if d.HasChange("ec2_tag_filter") { 362 _, n := d.GetChange("ec2_tag_filter") 363 ec2Filters := buildEC2TagFilters(n.(*schema.Set).List()) 364 input.Ec2TagFilters = ec2Filters 365 } 366 if d.HasChange("trigger_configuration") { 367 _, n := d.GetChange("trigger_configuration") 368 triggerConfigs := buildTriggerConfigs(n.(*schema.Set).List()) 369 input.TriggerConfigurations = triggerConfigs 370 } 371 372 if d.HasChange("auto_rollback_configuration") { 373 _, n := d.GetChange("auto_rollback_configuration") 374 input.AutoRollbackConfiguration = buildAutoRollbackConfig(n.([]interface{})) 375 } 376 377 if d.HasChange("alarm_configuration") { 378 _, n := d.GetChange("alarm_configuration") 379 input.AlarmConfiguration = buildAlarmConfig(n.([]interface{})) 380 } 381 382 log.Printf("[DEBUG] Updating CodeDeploy DeploymentGroup %s", d.Id()) 383 // Retry to handle IAM role eventual consistency. 384 err := resource.Retry(5*time.Minute, func() *resource.RetryError { 385 _, err := conn.UpdateDeploymentGroup(&input) 386 if err != nil { 387 retry := false 388 codedeployErr, ok := err.(awserr.Error) 389 if !ok { 390 return resource.NonRetryableError(err) 391 } 392 if codedeployErr.Code() == "InvalidRoleException" { 393 retry = true 394 } 395 if codedeployErr.Code() == "InvalidTriggerConfigException" { 396 r := regexp.MustCompile("^Topic ARN .+ is not valid$") 397 if r.MatchString(codedeployErr.Message()) { 398 retry = true 399 } 400 } 401 if retry { 402 log.Printf("[DEBUG] Retrying Code Deployment Group Update: %q", 403 codedeployErr.Message()) 404 return resource.RetryableError(err) 405 } 406 407 return resource.NonRetryableError(err) 408 } 409 return nil 410 }) 411 412 if err != nil { 413 return err 414 } 415 416 return resourceAwsCodeDeployDeploymentGroupRead(d, meta) 417 } 418 419 func resourceAwsCodeDeployDeploymentGroupDelete(d *schema.ResourceData, meta interface{}) error { 420 conn := meta.(*AWSClient).codedeployconn 421 422 log.Printf("[DEBUG] Deleting CodeDeploy DeploymentGroup %s", d.Id()) 423 _, err := conn.DeleteDeploymentGroup(&codedeploy.DeleteDeploymentGroupInput{ 424 ApplicationName: aws.String(d.Get("app_name").(string)), 425 DeploymentGroupName: aws.String(d.Get("deployment_group_name").(string)), 426 }) 427 if err != nil { 428 return err 429 } 430 431 d.SetId("") 432 433 return nil 434 } 435 436 // buildOnPremTagFilters converts raw schema lists into a list of 437 // codedeploy.TagFilters. 438 func buildOnPremTagFilters(configured []interface{}) []*codedeploy.TagFilter { 439 filters := make([]*codedeploy.TagFilter, 0) 440 for _, raw := range configured { 441 var filter codedeploy.TagFilter 442 m := raw.(map[string]interface{}) 443 444 if v, ok := m["key"]; ok { 445 filter.Key = aws.String(v.(string)) 446 } 447 if v, ok := m["type"]; ok { 448 filter.Type = aws.String(v.(string)) 449 } 450 if v, ok := m["value"]; ok { 451 filter.Value = aws.String(v.(string)) 452 } 453 454 filters = append(filters, &filter) 455 } 456 457 return filters 458 } 459 460 // buildEC2TagFilters converts raw schema lists into a list of 461 // codedeploy.EC2TagFilters. 462 func buildEC2TagFilters(configured []interface{}) []*codedeploy.EC2TagFilter { 463 filters := make([]*codedeploy.EC2TagFilter, 0) 464 for _, raw := range configured { 465 var filter codedeploy.EC2TagFilter 466 m := raw.(map[string]interface{}) 467 468 filter.Key = aws.String(m["key"].(string)) 469 filter.Type = aws.String(m["type"].(string)) 470 filter.Value = aws.String(m["value"].(string)) 471 472 filters = append(filters, &filter) 473 } 474 475 return filters 476 } 477 478 // buildTriggerConfigs converts a raw schema list into a list of 479 // codedeploy.TriggerConfig. 480 func buildTriggerConfigs(configured []interface{}) []*codedeploy.TriggerConfig { 481 configs := make([]*codedeploy.TriggerConfig, 0, len(configured)) 482 for _, raw := range configured { 483 var config codedeploy.TriggerConfig 484 m := raw.(map[string]interface{}) 485 486 config.TriggerEvents = expandStringSet(m["trigger_events"].(*schema.Set)) 487 config.TriggerName = aws.String(m["trigger_name"].(string)) 488 config.TriggerTargetArn = aws.String(m["trigger_target_arn"].(string)) 489 490 configs = append(configs, &config) 491 } 492 return configs 493 } 494 495 // buildAutoRollbackConfig converts a raw schema list containing a map[string]interface{} 496 // into a single codedeploy.AutoRollbackConfiguration 497 func buildAutoRollbackConfig(configured []interface{}) *codedeploy.AutoRollbackConfiguration { 498 result := &codedeploy.AutoRollbackConfiguration{} 499 500 if len(configured) == 1 { 501 config := configured[0].(map[string]interface{}) 502 result.Enabled = aws.Bool(config["enabled"].(bool)) 503 result.Events = expandStringSet(config["events"].(*schema.Set)) 504 } else { // delete the configuration 505 result.Enabled = aws.Bool(false) 506 result.Events = make([]*string, 0) 507 } 508 509 return result 510 } 511 512 // buildAlarmConfig converts a raw schema list containing a map[string]interface{} 513 // into a single codedeploy.AlarmConfiguration 514 func buildAlarmConfig(configured []interface{}) *codedeploy.AlarmConfiguration { 515 result := &codedeploy.AlarmConfiguration{} 516 517 if len(configured) == 1 { 518 config := configured[0].(map[string]interface{}) 519 names := expandStringSet(config["alarms"].(*schema.Set)) 520 alarms := make([]*codedeploy.Alarm, 0, len(names)) 521 522 for _, name := range names { 523 alarm := &codedeploy.Alarm{ 524 Name: name, 525 } 526 alarms = append(alarms, alarm) 527 } 528 529 result.Alarms = alarms 530 result.Enabled = aws.Bool(config["enabled"].(bool)) 531 result.IgnorePollAlarmFailure = aws.Bool(config["ignore_poll_alarm_failure"].(bool)) 532 } else { // delete the configuration 533 result.Alarms = make([]*codedeploy.Alarm, 0) 534 result.Enabled = aws.Bool(false) 535 result.IgnorePollAlarmFailure = aws.Bool(false) 536 } 537 538 return result 539 } 540 541 // ec2TagFiltersToMap converts lists of tag filters into a []map[string]string. 542 func ec2TagFiltersToMap(list []*codedeploy.EC2TagFilter) []map[string]string { 543 result := make([]map[string]string, 0, len(list)) 544 for _, tf := range list { 545 l := make(map[string]string) 546 if tf.Key != nil && *tf.Key != "" { 547 l["key"] = *tf.Key 548 } 549 if tf.Value != nil && *tf.Value != "" { 550 l["value"] = *tf.Value 551 } 552 if tf.Type != nil && *tf.Type != "" { 553 l["type"] = *tf.Type 554 } 555 result = append(result, l) 556 } 557 return result 558 } 559 560 // onPremisesTagFiltersToMap converts lists of on-prem tag filters into a []map[string]string. 561 func onPremisesTagFiltersToMap(list []*codedeploy.TagFilter) []map[string]string { 562 result := make([]map[string]string, 0, len(list)) 563 for _, tf := range list { 564 l := make(map[string]string) 565 if tf.Key != nil && *tf.Key != "" { 566 l["key"] = *tf.Key 567 } 568 if tf.Value != nil && *tf.Value != "" { 569 l["value"] = *tf.Value 570 } 571 if tf.Type != nil && *tf.Type != "" { 572 l["type"] = *tf.Type 573 } 574 result = append(result, l) 575 } 576 return result 577 } 578 579 // triggerConfigsToMap converts a list of []*codedeploy.TriggerConfig into a []map[string]interface{} 580 func triggerConfigsToMap(list []*codedeploy.TriggerConfig) []map[string]interface{} { 581 result := make([]map[string]interface{}, 0, len(list)) 582 for _, tc := range list { 583 item := make(map[string]interface{}) 584 item["trigger_events"] = schema.NewSet(schema.HashString, flattenStringList(tc.TriggerEvents)) 585 item["trigger_name"] = *tc.TriggerName 586 item["trigger_target_arn"] = *tc.TriggerTargetArn 587 result = append(result, item) 588 } 589 return result 590 } 591 592 // autoRollbackConfigToMap converts a codedeploy.AutoRollbackConfiguration 593 // into a []map[string]interface{} list containing a single item 594 func autoRollbackConfigToMap(config *codedeploy.AutoRollbackConfiguration) []map[string]interface{} { 595 result := make([]map[string]interface{}, 0, 1) 596 597 // only create configurations that are enabled or temporarily disabled (retaining events) 598 // otherwise empty configurations will be created 599 if config != nil && (*config.Enabled == true || len(config.Events) > 0) { 600 item := make(map[string]interface{}) 601 item["enabled"] = *config.Enabled 602 item["events"] = schema.NewSet(schema.HashString, flattenStringList(config.Events)) 603 result = append(result, item) 604 } 605 606 return result 607 } 608 609 // alarmConfigToMap converts a codedeploy.AlarmConfiguration 610 // into a []map[string]interface{} list containing a single item 611 func alarmConfigToMap(config *codedeploy.AlarmConfiguration) []map[string]interface{} { 612 result := make([]map[string]interface{}, 0, 1) 613 614 // only create configurations that are enabled or temporarily disabled (retaining alarms) 615 // otherwise empty configurations will be created 616 if config != nil && (*config.Enabled == true || len(config.Alarms) > 0) { 617 names := make([]*string, 0, len(config.Alarms)) 618 for _, alarm := range config.Alarms { 619 names = append(names, alarm.Name) 620 } 621 622 item := make(map[string]interface{}) 623 item["alarms"] = schema.NewSet(schema.HashString, flattenStringList(names)) 624 item["enabled"] = *config.Enabled 625 item["ignore_poll_alarm_failure"] = *config.IgnorePollAlarmFailure 626 627 result = append(result, item) 628 } 629 630 return result 631 } 632 633 func resourceAwsCodeDeployTagFilterHash(v interface{}) int { 634 var buf bytes.Buffer 635 m := v.(map[string]interface{}) 636 637 // Nothing's actually required in tag filters, so we must check the 638 // presence of all values before attempting a hash. 639 if v, ok := m["key"]; ok { 640 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 641 } 642 if v, ok := m["type"]; ok { 643 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 644 } 645 if v, ok := m["value"]; ok { 646 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 647 } 648 649 return hashcode.String(buf.String()) 650 } 651 652 func resourceAwsCodeDeployTriggerConfigHash(v interface{}) int { 653 var buf bytes.Buffer 654 m := v.(map[string]interface{}) 655 buf.WriteString(fmt.Sprintf("%s-", m["trigger_name"].(string))) 656 buf.WriteString(fmt.Sprintf("%s-", m["trigger_target_arn"].(string))) 657 658 if triggerEvents, ok := m["trigger_events"]; ok { 659 names := triggerEvents.(*schema.Set).List() 660 strings := make([]string, len(names)) 661 for i, raw := range names { 662 strings[i] = raw.(string) 663 } 664 sort.Strings(strings) 665 666 for _, s := range strings { 667 buf.WriteString(fmt.Sprintf("%s-", s)) 668 } 669 } 670 return hashcode.String(buf.String()) 671 } 672 673 func validateTriggerEvent(v interface{}, k string) (ws []string, errors []error) { 674 value := v.(string) 675 triggerEvents := map[string]bool{ 676 "DeploymentStart": true, 677 "DeploymentStop": true, 678 "DeploymentSuccess": true, 679 "DeploymentFailure": true, 680 "DeploymentRollback": true, 681 "InstanceStart": true, 682 "InstanceSuccess": true, 683 "InstanceFailure": true, 684 } 685 686 if !triggerEvents[value] { 687 errors = append(errors, fmt.Errorf("%q must be a valid event type value: %q", k, value)) 688 } 689 return 690 }