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