github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/builtin/providers/aws/resource_aws_kinesis_firehose_delivery_stream.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/service/firehose" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 ) 15 16 func resourceAwsKinesisFirehoseDeliveryStream() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceAwsKinesisFirehoseDeliveryStreamCreate, 19 Read: resourceAwsKinesisFirehoseDeliveryStreamRead, 20 Update: resourceAwsKinesisFirehoseDeliveryStreamUpdate, 21 Delete: resourceAwsKinesisFirehoseDeliveryStreamDelete, 22 23 SchemaVersion: 1, 24 MigrateState: resourceAwsKinesisFirehoseMigrateState, 25 Schema: map[string]*schema.Schema{ 26 "name": &schema.Schema{ 27 Type: schema.TypeString, 28 Required: true, 29 ForceNew: true, 30 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 31 value := v.(string) 32 if len(value) > 64 { 33 errors = append(errors, fmt.Errorf( 34 "%q cannot be longer than 64 characters", k)) 35 } 36 return 37 }, 38 }, 39 40 "destination": &schema.Schema{ 41 Type: schema.TypeString, 42 Required: true, 43 ForceNew: true, 44 StateFunc: func(v interface{}) string { 45 value := v.(string) 46 return strings.ToLower(value) 47 }, 48 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 49 value := v.(string) 50 if value != "s3" && value != "redshift" && value != "elasticsearch" { 51 errors = append(errors, fmt.Errorf( 52 "%q must be one of 's3', 'redshift', 'elasticsearch'", k)) 53 } 54 return 55 }, 56 }, 57 58 // elements removed in v0.7.0 59 "role_arn": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 Removed: "role_arn has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 63 }, 64 65 "s3_bucket_arn": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 Removed: "s3_bucket_arn has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 69 }, 70 71 "s3_prefix": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 Removed: "s3_prefix has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 75 }, 76 77 "s3_buffer_size": &schema.Schema{ 78 Type: schema.TypeInt, 79 Optional: true, 80 Removed: "s3_buffer_size has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 81 }, 82 83 "s3_buffer_interval": &schema.Schema{ 84 Type: schema.TypeInt, 85 Optional: true, 86 Removed: "s3_buffer_interval has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 87 }, 88 89 "s3_data_compression": &schema.Schema{ 90 Type: schema.TypeString, 91 Optional: true, 92 Removed: "s3_data_compression has been removed. Use a s3_configuration block instead. See https://terraform.io/docs/providers/aws/r/kinesis_firehose_delivery_stream.html", 93 }, 94 95 "s3_configuration": &schema.Schema{ 96 Type: schema.TypeList, 97 Required: true, 98 MaxItems: 1, 99 Elem: &schema.Resource{ 100 Schema: map[string]*schema.Schema{ 101 "bucket_arn": &schema.Schema{ 102 Type: schema.TypeString, 103 Required: true, 104 }, 105 106 "buffer_size": &schema.Schema{ 107 Type: schema.TypeInt, 108 Optional: true, 109 Default: 5, 110 }, 111 112 "buffer_interval": &schema.Schema{ 113 Type: schema.TypeInt, 114 Optional: true, 115 Default: 300, 116 }, 117 118 "compression_format": &schema.Schema{ 119 Type: schema.TypeString, 120 Optional: true, 121 Default: "UNCOMPRESSED", 122 }, 123 124 "kms_key_arn": &schema.Schema{ 125 Type: schema.TypeString, 126 Optional: true, 127 }, 128 129 "role_arn": &schema.Schema{ 130 Type: schema.TypeString, 131 Required: true, 132 }, 133 134 "prefix": &schema.Schema{ 135 Type: schema.TypeString, 136 Optional: true, 137 }, 138 }, 139 }, 140 }, 141 142 "redshift_configuration": &schema.Schema{ 143 Type: schema.TypeList, 144 Optional: true, 145 MaxItems: 1, 146 Elem: &schema.Resource{ 147 Schema: map[string]*schema.Schema{ 148 "cluster_jdbcurl": &schema.Schema{ 149 Type: schema.TypeString, 150 Required: true, 151 }, 152 153 "username": &schema.Schema{ 154 Type: schema.TypeString, 155 Required: true, 156 }, 157 158 "password": &schema.Schema{ 159 Type: schema.TypeString, 160 Required: true, 161 }, 162 163 "role_arn": &schema.Schema{ 164 Type: schema.TypeString, 165 Required: true, 166 }, 167 168 "copy_options": &schema.Schema{ 169 Type: schema.TypeString, 170 Optional: true, 171 }, 172 173 "data_table_columns": &schema.Schema{ 174 Type: schema.TypeString, 175 Optional: true, 176 }, 177 178 "data_table_name": &schema.Schema{ 179 Type: schema.TypeString, 180 Required: true, 181 }, 182 }, 183 }, 184 }, 185 186 "elasticsearch_configuration": &schema.Schema{ 187 Type: schema.TypeList, 188 Optional: true, 189 MaxItems: 1, 190 Elem: &schema.Resource{ 191 Schema: map[string]*schema.Schema{ 192 "buffering_interval": &schema.Schema{ 193 Type: schema.TypeInt, 194 Optional: true, 195 Default: 300, 196 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 197 value := v.(int) 198 if value < 60 || value > 900 { 199 errors = append(errors, fmt.Errorf( 200 "%q must be in the range from 60 to 900 seconds.", k)) 201 } 202 return 203 }, 204 }, 205 206 "buffering_size": &schema.Schema{ 207 Type: schema.TypeInt, 208 Optional: true, 209 Default: 5, 210 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 211 value := v.(int) 212 if value < 1 || value > 100 { 213 errors = append(errors, fmt.Errorf( 214 "%q must be in the range from 1 to 100 MB.", k)) 215 } 216 return 217 }, 218 }, 219 220 "domain_arn": &schema.Schema{ 221 Type: schema.TypeString, 222 Required: true, 223 }, 224 225 "index_name": &schema.Schema{ 226 Type: schema.TypeString, 227 Required: true, 228 }, 229 230 "index_rotation_period": &schema.Schema{ 231 Type: schema.TypeString, 232 Optional: true, 233 Default: "OneDay", 234 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 235 value := v.(string) 236 if value != "NoRotation" && value != "OneHour" && value != "OneDay" && value != "OneWeek" && value != "OneMonth" { 237 errors = append(errors, fmt.Errorf( 238 "%q must be one of 'NoRotation', 'OneHour', 'OneDay', 'OneWeek', 'OneMonth'", k)) 239 } 240 return 241 }, 242 }, 243 244 "retry_duration": &schema.Schema{ 245 Type: schema.TypeInt, 246 Optional: true, 247 Default: 300, 248 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 249 value := v.(int) 250 if value < 0 || value > 7200 { 251 errors = append(errors, fmt.Errorf( 252 "%q must be in the range from 0 to 7200 seconds.", k)) 253 } 254 return 255 }, 256 }, 257 258 "role_arn": &schema.Schema{ 259 Type: schema.TypeString, 260 Required: true, 261 }, 262 263 "s3_backup_mode": &schema.Schema{ 264 Type: schema.TypeString, 265 Optional: true, 266 Default: "FailedDocumentsOnly", 267 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 268 value := v.(string) 269 if value != "FailedDocumentsOnly" && value != "AllDocuments" { 270 errors = append(errors, fmt.Errorf( 271 "%q must be one of 'FailedDocumentsOnly', 'AllDocuments'", k)) 272 } 273 return 274 }, 275 }, 276 277 "type_name": &schema.Schema{ 278 Type: schema.TypeString, 279 Optional: true, 280 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 281 value := v.(string) 282 if len(value) > 100 { 283 errors = append(errors, fmt.Errorf( 284 "%q cannot be longer than 100 characters", k)) 285 } 286 return 287 }, 288 }, 289 }, 290 }, 291 }, 292 293 "arn": &schema.Schema{ 294 Type: schema.TypeString, 295 Optional: true, 296 Computed: true, 297 }, 298 299 "version_id": &schema.Schema{ 300 Type: schema.TypeString, 301 Optional: true, 302 Computed: true, 303 }, 304 305 "destination_id": &schema.Schema{ 306 Type: schema.TypeString, 307 Optional: true, 308 Computed: true, 309 }, 310 }, 311 } 312 } 313 314 func createS3Config(d *schema.ResourceData) *firehose.S3DestinationConfiguration { 315 s3 := d.Get("s3_configuration").([]interface{})[0].(map[string]interface{}) 316 317 return &firehose.S3DestinationConfiguration{ 318 BucketARN: aws.String(s3["bucket_arn"].(string)), 319 RoleARN: aws.String(s3["role_arn"].(string)), 320 BufferingHints: &firehose.BufferingHints{ 321 IntervalInSeconds: aws.Int64(int64(s3["buffer_interval"].(int))), 322 SizeInMBs: aws.Int64(int64(s3["buffer_size"].(int))), 323 }, 324 Prefix: extractPrefixConfiguration(s3), 325 CompressionFormat: aws.String(s3["compression_format"].(string)), 326 EncryptionConfiguration: extractEncryptionConfiguration(s3), 327 } 328 } 329 330 func updateS3Config(d *schema.ResourceData) *firehose.S3DestinationUpdate { 331 s3 := d.Get("s3_configuration").([]interface{})[0].(map[string]interface{}) 332 333 return &firehose.S3DestinationUpdate{ 334 BucketARN: aws.String(s3["bucket_arn"].(string)), 335 RoleARN: aws.String(s3["role_arn"].(string)), 336 BufferingHints: &firehose.BufferingHints{ 337 IntervalInSeconds: aws.Int64((int64)(s3["buffer_interval"].(int))), 338 SizeInMBs: aws.Int64((int64)(s3["buffer_size"].(int))), 339 }, 340 Prefix: extractPrefixConfiguration(s3), 341 CompressionFormat: aws.String(s3["compression_format"].(string)), 342 EncryptionConfiguration: extractEncryptionConfiguration(s3), 343 } 344 } 345 346 func extractEncryptionConfiguration(s3 map[string]interface{}) *firehose.EncryptionConfiguration { 347 if key, ok := s3["kms_key_arn"]; ok && len(key.(string)) > 0 { 348 return &firehose.EncryptionConfiguration{ 349 KMSEncryptionConfig: &firehose.KMSEncryptionConfig{ 350 AWSKMSKeyARN: aws.String(key.(string)), 351 }, 352 } 353 } 354 355 return &firehose.EncryptionConfiguration{ 356 NoEncryptionConfig: aws.String("NoEncryption"), 357 } 358 } 359 360 func extractPrefixConfiguration(s3 map[string]interface{}) *string { 361 if v, ok := s3["prefix"]; ok { 362 return aws.String(v.(string)) 363 } 364 365 return nil 366 } 367 368 func createRedshiftConfig(d *schema.ResourceData, s3Config *firehose.S3DestinationConfiguration) (*firehose.RedshiftDestinationConfiguration, error) { 369 redshiftRaw, ok := d.GetOk("redshift_configuration") 370 if !ok { 371 return nil, fmt.Errorf("[ERR] Error loading Redshift Configuration for Kinesis Firehose: redshift_configuration not found") 372 } 373 rl := redshiftRaw.([]interface{}) 374 375 redshift := rl[0].(map[string]interface{}) 376 377 return &firehose.RedshiftDestinationConfiguration{ 378 ClusterJDBCURL: aws.String(redshift["cluster_jdbcurl"].(string)), 379 Password: aws.String(redshift["password"].(string)), 380 Username: aws.String(redshift["username"].(string)), 381 RoleARN: aws.String(redshift["role_arn"].(string)), 382 CopyCommand: extractCopyCommandConfiguration(redshift), 383 S3Configuration: s3Config, 384 }, nil 385 } 386 387 func updateRedshiftConfig(d *schema.ResourceData, s3Update *firehose.S3DestinationUpdate) (*firehose.RedshiftDestinationUpdate, error) { 388 redshiftRaw, ok := d.GetOk("redshift_configuration") 389 if !ok { 390 return nil, fmt.Errorf("[ERR] Error loading Redshift Configuration for Kinesis Firehose: redshift_configuration not found") 391 } 392 rl := redshiftRaw.([]interface{}) 393 394 redshift := rl[0].(map[string]interface{}) 395 396 return &firehose.RedshiftDestinationUpdate{ 397 ClusterJDBCURL: aws.String(redshift["cluster_jdbcurl"].(string)), 398 Password: aws.String(redshift["password"].(string)), 399 Username: aws.String(redshift["username"].(string)), 400 RoleARN: aws.String(redshift["role_arn"].(string)), 401 CopyCommand: extractCopyCommandConfiguration(redshift), 402 S3Update: s3Update, 403 }, nil 404 } 405 406 func createElasticsearchConfig(d *schema.ResourceData, s3Config *firehose.S3DestinationConfiguration) (*firehose.ElasticsearchDestinationConfiguration, error) { 407 esConfig, ok := d.GetOk("elasticsearch_configuration") 408 if !ok { 409 return nil, fmt.Errorf("[ERR] Error loading Elasticsearch Configuration for Kinesis Firehose: elasticsearch_configuration not found") 410 } 411 esList := esConfig.([]interface{}) 412 413 es := esList[0].(map[string]interface{}) 414 415 config := &firehose.ElasticsearchDestinationConfiguration{ 416 BufferingHints: extractBufferingHints(es), 417 DomainARN: aws.String(es["domain_arn"].(string)), 418 IndexName: aws.String(es["index_name"].(string)), 419 RetryOptions: extractRetryOptions(es), 420 RoleARN: aws.String(es["role_arn"].(string)), 421 TypeName: aws.String(es["type_name"].(string)), 422 S3Configuration: s3Config, 423 } 424 425 if indexRotationPeriod, ok := es["index_rotation_period"]; ok { 426 config.IndexRotationPeriod = aws.String(indexRotationPeriod.(string)) 427 } 428 if s3BackupMode, ok := es["s3_backup_mode"]; ok { 429 config.S3BackupMode = aws.String(s3BackupMode.(string)) 430 } 431 432 return config, nil 433 } 434 435 func updateElasticsearchConfig(d *schema.ResourceData, s3Update *firehose.S3DestinationUpdate) (*firehose.ElasticsearchDestinationUpdate, error) { 436 esConfig, ok := d.GetOk("elasticsearch_configuration") 437 if !ok { 438 return nil, fmt.Errorf("[ERR] Error loading Elasticsearch Configuration for Kinesis Firehose: elasticsearch_configuration not found") 439 } 440 esList := esConfig.([]interface{}) 441 442 es := esList[0].(map[string]interface{}) 443 444 update := &firehose.ElasticsearchDestinationUpdate{ 445 BufferingHints: extractBufferingHints(es), 446 DomainARN: aws.String(es["domain_arn"].(string)), 447 IndexName: aws.String(es["index_name"].(string)), 448 RetryOptions: extractRetryOptions(es), 449 RoleARN: aws.String(es["role_arn"].(string)), 450 TypeName: aws.String(es["type_name"].(string)), 451 S3Update: s3Update, 452 } 453 454 if indexRotationPeriod, ok := es["index_rotation_period"]; ok { 455 update.IndexRotationPeriod = aws.String(indexRotationPeriod.(string)) 456 } 457 458 return update, nil 459 } 460 461 func extractBufferingHints(es map[string]interface{}) *firehose.ElasticsearchBufferingHints { 462 bufferingHints := &firehose.ElasticsearchBufferingHints{} 463 464 if bufferingInterval, ok := es["buffering_hints"].(int); ok { 465 bufferingHints.IntervalInSeconds = aws.Int64(int64(bufferingInterval)) 466 } 467 if bufferingSize, ok := es["buffering_size"].(int); ok { 468 bufferingHints.SizeInMBs = aws.Int64(int64(bufferingSize)) 469 } 470 471 return bufferingHints 472 473 } 474 475 func extractRetryOptions(es map[string]interface{}) *firehose.ElasticsearchRetryOptions { 476 retryOptions := &firehose.ElasticsearchRetryOptions{} 477 478 if retryDuration, ok := es["retry_duration"].(int); ok { 479 retryOptions.DurationInSeconds = aws.Int64(int64(retryDuration)) 480 } 481 482 return retryOptions 483 } 484 485 func extractCopyCommandConfiguration(redshift map[string]interface{}) *firehose.CopyCommand { 486 cmd := &firehose.CopyCommand{ 487 DataTableName: aws.String(redshift["data_table_name"].(string)), 488 } 489 if copyOptions, ok := redshift["copy_options"]; ok { 490 cmd.CopyOptions = aws.String(copyOptions.(string)) 491 } 492 if columns, ok := redshift["data_table_columns"]; ok { 493 cmd.DataTableColumns = aws.String(columns.(string)) 494 } 495 496 return cmd 497 } 498 499 func resourceAwsKinesisFirehoseDeliveryStreamCreate(d *schema.ResourceData, meta interface{}) error { 500 conn := meta.(*AWSClient).firehoseconn 501 502 sn := d.Get("name").(string) 503 s3Config := createS3Config(d) 504 505 createInput := &firehose.CreateDeliveryStreamInput{ 506 DeliveryStreamName: aws.String(sn), 507 } 508 509 if d.Get("destination").(string) == "s3" { 510 createInput.S3DestinationConfiguration = s3Config 511 } else if d.Get("destination").(string) == "elasticsearch" { 512 esConfig, err := createElasticsearchConfig(d, s3Config) 513 if err != nil { 514 return err 515 } 516 createInput.ElasticsearchDestinationConfiguration = esConfig 517 } else { 518 rc, err := createRedshiftConfig(d, s3Config) 519 if err != nil { 520 return err 521 } 522 createInput.RedshiftDestinationConfiguration = rc 523 } 524 525 var lastError error 526 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 527 _, err := conn.CreateDeliveryStream(createInput) 528 if err != nil { 529 log.Printf("[DEBUG] Error creating Firehose Delivery Stream: %s", err) 530 lastError = err 531 532 if awsErr, ok := err.(awserr.Error); ok { 533 // IAM roles can take ~10 seconds to propagate in AWS: 534 // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console 535 if awsErr.Code() == "InvalidArgumentException" && strings.Contains(awsErr.Message(), "Firehose is unable to assume role") { 536 log.Printf("[DEBUG] Firehose could not assume role referenced, retrying...") 537 return resource.RetryableError(awsErr) 538 } 539 } 540 // Not retryable 541 return resource.NonRetryableError(err) 542 } 543 544 return nil 545 }) 546 if err != nil { 547 if awsErr, ok := lastError.(awserr.Error); ok { 548 return fmt.Errorf("[WARN] Error creating Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code()) 549 } 550 return err 551 } 552 553 stateConf := &resource.StateChangeConf{ 554 Pending: []string{"CREATING"}, 555 Target: []string{"ACTIVE"}, 556 Refresh: firehoseStreamStateRefreshFunc(conn, sn), 557 Timeout: 20 * time.Minute, 558 Delay: 10 * time.Second, 559 MinTimeout: 3 * time.Second, 560 } 561 562 firehoseStream, err := stateConf.WaitForState() 563 if err != nil { 564 return fmt.Errorf( 565 "Error waiting for Kinesis Stream (%s) to become active: %s", 566 sn, err) 567 } 568 569 s := firehoseStream.(*firehose.DeliveryStreamDescription) 570 d.SetId(*s.DeliveryStreamARN) 571 d.Set("arn", s.DeliveryStreamARN) 572 573 return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta) 574 } 575 576 func resourceAwsKinesisFirehoseDeliveryStreamUpdate(d *schema.ResourceData, meta interface{}) error { 577 conn := meta.(*AWSClient).firehoseconn 578 579 sn := d.Get("name").(string) 580 s3Config := updateS3Config(d) 581 582 updateInput := &firehose.UpdateDestinationInput{ 583 DeliveryStreamName: aws.String(sn), 584 CurrentDeliveryStreamVersionId: aws.String(d.Get("version_id").(string)), 585 DestinationId: aws.String(d.Get("destination_id").(string)), 586 } 587 588 if d.Get("destination").(string) == "s3" { 589 updateInput.S3DestinationUpdate = s3Config 590 } else if d.Get("destination").(string) == "elasticsearch" { 591 esUpdate, err := updateElasticsearchConfig(d, s3Config) 592 if err != nil { 593 return err 594 } 595 updateInput.ElasticsearchDestinationUpdate = esUpdate 596 } else { 597 rc, err := updateRedshiftConfig(d, s3Config) 598 if err != nil { 599 return err 600 } 601 updateInput.RedshiftDestinationUpdate = rc 602 } 603 604 _, err := conn.UpdateDestination(updateInput) 605 if err != nil { 606 return fmt.Errorf( 607 "Error Updating Kinesis Firehose Delivery Stream: \"%s\"\n%s", 608 sn, err) 609 } 610 611 return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta) 612 } 613 614 func resourceAwsKinesisFirehoseDeliveryStreamRead(d *schema.ResourceData, meta interface{}) error { 615 conn := meta.(*AWSClient).firehoseconn 616 617 resp, err := conn.DescribeDeliveryStream(&firehose.DescribeDeliveryStreamInput{ 618 DeliveryStreamName: aws.String(d.Get("name").(string)), 619 }) 620 621 if err != nil { 622 if awsErr, ok := err.(awserr.Error); ok { 623 if awsErr.Code() == "ResourceNotFoundException" { 624 d.SetId("") 625 return nil 626 } 627 return fmt.Errorf("[WARN] Error reading Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code()) 628 } 629 return err 630 } 631 632 s := resp.DeliveryStreamDescription 633 d.Set("version_id", s.VersionId) 634 d.Set("arn", *s.DeliveryStreamARN) 635 if len(s.Destinations) > 0 { 636 destination := s.Destinations[0] 637 d.Set("destination_id", *destination.DestinationId) 638 } 639 640 return nil 641 } 642 643 func resourceAwsKinesisFirehoseDeliveryStreamDelete(d *schema.ResourceData, meta interface{}) error { 644 conn := meta.(*AWSClient).firehoseconn 645 646 sn := d.Get("name").(string) 647 _, err := conn.DeleteDeliveryStream(&firehose.DeleteDeliveryStreamInput{ 648 DeliveryStreamName: aws.String(sn), 649 }) 650 651 if err != nil { 652 return err 653 } 654 655 stateConf := &resource.StateChangeConf{ 656 Pending: []string{"DELETING"}, 657 Target: []string{"DESTROYED"}, 658 Refresh: firehoseStreamStateRefreshFunc(conn, sn), 659 Timeout: 20 * time.Minute, 660 Delay: 10 * time.Second, 661 MinTimeout: 3 * time.Second, 662 } 663 664 _, err = stateConf.WaitForState() 665 if err != nil { 666 return fmt.Errorf( 667 "Error waiting for Delivery Stream (%s) to be destroyed: %s", 668 sn, err) 669 } 670 671 d.SetId("") 672 return nil 673 } 674 675 func firehoseStreamStateRefreshFunc(conn *firehose.Firehose, sn string) resource.StateRefreshFunc { 676 return func() (interface{}, string, error) { 677 describeOpts := &firehose.DescribeDeliveryStreamInput{ 678 DeliveryStreamName: aws.String(sn), 679 } 680 resp, err := conn.DescribeDeliveryStream(describeOpts) 681 if err != nil { 682 if awsErr, ok := err.(awserr.Error); ok { 683 if awsErr.Code() == "ResourceNotFoundException" { 684 return 42, "DESTROYED", nil 685 } 686 return nil, awsErr.Code(), err 687 } 688 return nil, "failed", err 689 } 690 691 return resp.DeliveryStreamDescription, *resp.DeliveryStreamDescription.DeliveryStreamStatus, nil 692 } 693 }