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