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