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