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