github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"destination": &schema.Schema{
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  				ForceNew: true,
    34  				StateFunc: func(v interface{}) string {
    35  					value := v.(string)
    36  					return strings.ToLower(value)
    37  				},
    38  			},
    39  
    40  			"role_arn": &schema.Schema{
    41  				Type:     schema.TypeString,
    42  				Required: true,
    43  			},
    44  
    45  			"s3_bucket_arn": &schema.Schema{
    46  				Type:     schema.TypeString,
    47  				Required: true,
    48  			},
    49  
    50  			"s3_prefix": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Optional: true,
    53  			},
    54  
    55  			"s3_buffer_size": &schema.Schema{
    56  				Type:     schema.TypeInt,
    57  				Optional: true,
    58  				Default:  5,
    59  			},
    60  
    61  			"s3_buffer_interval": &schema.Schema{
    62  				Type:     schema.TypeInt,
    63  				Optional: true,
    64  				Default:  300,
    65  			},
    66  
    67  			"s3_data_compression": &schema.Schema{
    68  				Type:     schema.TypeString,
    69  				Optional: true,
    70  				Default:  "UNCOMPRESSED",
    71  			},
    72  
    73  			"arn": &schema.Schema{
    74  				Type:     schema.TypeString,
    75  				Optional: true,
    76  				Computed: true,
    77  			},
    78  
    79  			"version_id": &schema.Schema{
    80  				Type:     schema.TypeString,
    81  				Optional: true,
    82  				Computed: true,
    83  			},
    84  
    85  			"destination_id": &schema.Schema{
    86  				Type:     schema.TypeString,
    87  				Optional: true,
    88  				Computed: true,
    89  			},
    90  		},
    91  	}
    92  }
    93  
    94  func resourceAwsKinesisFirehoseDeliveryStreamCreate(d *schema.ResourceData, meta interface{}) error {
    95  	conn := meta.(*AWSClient).firehoseconn
    96  
    97  	if d.Get("destination").(string) != "s3" {
    98  		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
    99  	}
   100  
   101  	sn := d.Get("name").(string)
   102  	input := &firehose.CreateDeliveryStreamInput{
   103  		DeliveryStreamName: aws.String(sn),
   104  	}
   105  
   106  	s3Config := &firehose.S3DestinationConfiguration{
   107  		BucketARN: aws.String(d.Get("s3_bucket_arn").(string)),
   108  		RoleARN:   aws.String(d.Get("role_arn").(string)),
   109  		BufferingHints: &firehose.BufferingHints{
   110  			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
   111  			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
   112  		},
   113  		CompressionFormat: aws.String(d.Get("s3_data_compression").(string)),
   114  	}
   115  	if v, ok := d.GetOk("s3_prefix"); ok {
   116  		s3Config.Prefix = aws.String(v.(string))
   117  	}
   118  
   119  	input.S3DestinationConfiguration = s3Config
   120  
   121  	var err error
   122  	for i := 0; i < 5; i++ {
   123  		_, err := conn.CreateDeliveryStream(input)
   124  		if awsErr, ok := err.(awserr.Error); ok {
   125  			// IAM roles can take ~10 seconds to propagate in AWS:
   126  			//  http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console
   127  			if awsErr.Code() == "InvalidArgumentException" && strings.Contains(awsErr.Message(), "Firehose is unable to assume role") {
   128  				log.Printf("[DEBUG] Firehose could not assume role referenced, retrying...")
   129  				time.Sleep(2 * time.Second)
   130  				continue
   131  			}
   132  		}
   133  		break
   134  	}
   135  	if err != nil {
   136  		if awsErr, ok := err.(awserr.Error); ok {
   137  			return fmt.Errorf("[WARN] Error creating Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
   138  		}
   139  		return err
   140  	}
   141  
   142  	stateConf := &resource.StateChangeConf{
   143  		Pending:    []string{"CREATING"},
   144  		Target:     []string{"ACTIVE"},
   145  		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
   146  		Timeout:    5 * time.Minute,
   147  		Delay:      10 * time.Second,
   148  		MinTimeout: 3 * time.Second,
   149  	}
   150  
   151  	firehoseStream, err := stateConf.WaitForState()
   152  	if err != nil {
   153  		return fmt.Errorf(
   154  			"Error waiting for Kinesis Stream (%s) to become active: %s",
   155  			sn, err)
   156  	}
   157  
   158  	s := firehoseStream.(*firehose.DeliveryStreamDescription)
   159  	d.SetId(*s.DeliveryStreamARN)
   160  	d.Set("arn", s.DeliveryStreamARN)
   161  
   162  	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
   163  }
   164  
   165  func resourceAwsKinesisFirehoseDeliveryStreamUpdate(d *schema.ResourceData, meta interface{}) error {
   166  	conn := meta.(*AWSClient).firehoseconn
   167  
   168  	if d.Get("destination").(string) != "s3" {
   169  		return fmt.Errorf("[ERROR] AWS Kinesis Firehose only supports S3 destinations for the first implementation")
   170  	}
   171  
   172  	sn := d.Get("name").(string)
   173  	s3_config := &firehose.S3DestinationUpdate{}
   174  
   175  	if d.HasChange("role_arn") {
   176  		s3_config.RoleARN = aws.String(d.Get("role_arn").(string))
   177  	}
   178  
   179  	if d.HasChange("s3_bucket_arn") {
   180  		s3_config.BucketARN = aws.String(d.Get("s3_bucket_arn").(string))
   181  	}
   182  
   183  	if d.HasChange("s3_prefix") {
   184  		s3_config.Prefix = aws.String(d.Get("s3_prefix").(string))
   185  	}
   186  
   187  	if d.HasChange("s3_data_compression") {
   188  		s3_config.CompressionFormat = aws.String(d.Get("s3_data_compression").(string))
   189  	}
   190  
   191  	if d.HasChange("s3_buffer_interval") || d.HasChange("s3_buffer_size") {
   192  		bufferingHints := &firehose.BufferingHints{
   193  			IntervalInSeconds: aws.Int64(int64(d.Get("s3_buffer_interval").(int))),
   194  			SizeInMBs:         aws.Int64(int64(d.Get("s3_buffer_size").(int))),
   195  		}
   196  		s3_config.BufferingHints = bufferingHints
   197  	}
   198  
   199  	destOpts := &firehose.UpdateDestinationInput{
   200  		DeliveryStreamName:             aws.String(sn),
   201  		CurrentDeliveryStreamVersionId: aws.String(d.Get("version_id").(string)),
   202  		DestinationId:                  aws.String(d.Get("destination_id").(string)),
   203  		S3DestinationUpdate:            s3_config,
   204  	}
   205  
   206  	_, err := conn.UpdateDestination(destOpts)
   207  	if err != nil {
   208  		return fmt.Errorf(
   209  			"Error Updating Kinesis Firehose Delivery Stream: \"%s\"\n%s",
   210  			sn, err)
   211  	}
   212  
   213  	return resourceAwsKinesisFirehoseDeliveryStreamRead(d, meta)
   214  }
   215  
   216  func resourceAwsKinesisFirehoseDeliveryStreamRead(d *schema.ResourceData, meta interface{}) error {
   217  	conn := meta.(*AWSClient).firehoseconn
   218  	sn := d.Get("name").(string)
   219  	describeOpts := &firehose.DescribeDeliveryStreamInput{
   220  		DeliveryStreamName: aws.String(sn),
   221  	}
   222  	resp, err := conn.DescribeDeliveryStream(describeOpts)
   223  	if err != nil {
   224  		if awsErr, ok := err.(awserr.Error); ok {
   225  			if awsErr.Code() == "ResourceNotFoundException" {
   226  				d.SetId("")
   227  				return nil
   228  			}
   229  			return fmt.Errorf("[WARN] Error reading Kinesis Firehose Delivery Stream: \"%s\", code: \"%s\"", awsErr.Message(), awsErr.Code())
   230  		}
   231  		return err
   232  	}
   233  
   234  	s := resp.DeliveryStreamDescription
   235  	d.Set("version_id", s.VersionId)
   236  	d.Set("arn", *s.DeliveryStreamARN)
   237  	if len(s.Destinations) > 0 {
   238  		destination := s.Destinations[0]
   239  		d.Set("destination_id", *destination.DestinationId)
   240  	}
   241  
   242  	return nil
   243  }
   244  
   245  func resourceAwsKinesisFirehoseDeliveryStreamDelete(d *schema.ResourceData, meta interface{}) error {
   246  	conn := meta.(*AWSClient).firehoseconn
   247  
   248  	sn := d.Get("name").(string)
   249  	_, err := conn.DeleteDeliveryStream(&firehose.DeleteDeliveryStreamInput{
   250  		DeliveryStreamName: aws.String(sn),
   251  	})
   252  
   253  	if err != nil {
   254  		return err
   255  	}
   256  
   257  	stateConf := &resource.StateChangeConf{
   258  		Pending:    []string{"DELETING"},
   259  		Target:     []string{"DESTROYED"},
   260  		Refresh:    firehoseStreamStateRefreshFunc(conn, sn),
   261  		Timeout:    5 * time.Minute,
   262  		Delay:      10 * time.Second,
   263  		MinTimeout: 3 * time.Second,
   264  	}
   265  
   266  	_, err = stateConf.WaitForState()
   267  	if err != nil {
   268  		return fmt.Errorf(
   269  			"Error waiting for Delivery Stream (%s) to be destroyed: %s",
   270  			sn, err)
   271  	}
   272  
   273  	d.SetId("")
   274  	return nil
   275  }
   276  
   277  func firehoseStreamStateRefreshFunc(conn *firehose.Firehose, sn string) resource.StateRefreshFunc {
   278  	return func() (interface{}, string, error) {
   279  		describeOpts := &firehose.DescribeDeliveryStreamInput{
   280  			DeliveryStreamName: aws.String(sn),
   281  		}
   282  		resp, err := conn.DescribeDeliveryStream(describeOpts)
   283  		if err != nil {
   284  			if awsErr, ok := err.(awserr.Error); ok {
   285  				if awsErr.Code() == "ResourceNotFoundException" {
   286  					return 42, "DESTROYED", nil
   287  				}
   288  				return nil, awsErr.Code(), err
   289  			}
   290  			return nil, "failed", err
   291  		}
   292  
   293  		return resp.DeliveryStreamDescription, *resp.DeliveryStreamDescription.DeliveryStreamStatus, nil
   294  	}
   295  }