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