github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/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: "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: "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 }