github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/opsworks_layers.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  
     8  	"github.com/hashicorp/terraform/helper/hashcode"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/service/opsworks"
    14  )
    15  
    16  // OpsWorks has a single concept of "layer" which represents several different
    17  // layer types. The differences between these are in some extra properties that
    18  // get packed into an "Attributes" map, but in the OpsWorks UI these are presented
    19  // as first-class options, and so Terraform prefers to expose them this way and
    20  // hide the implementation detail that they are all packed into a single type
    21  // in the underlying API.
    22  //
    23  // This file contains utilities that are shared between all of the concrete
    24  // layer resource types, which have names matching aws_opsworks_*_layer .
    25  
    26  type opsworksLayerTypeAttribute struct {
    27  	AttrName  string
    28  	Type      schema.ValueType
    29  	Default   interface{}
    30  	Required  bool
    31  	WriteOnly bool
    32  }
    33  
    34  type opsworksLayerType struct {
    35  	TypeName         string
    36  	DefaultLayerName string
    37  	Attributes       map[string]*opsworksLayerTypeAttribute
    38  	CustomShortName  bool
    39  }
    40  
    41  var (
    42  	opsworksTrueString  = "true"
    43  	opsworksFalseString = "false"
    44  )
    45  
    46  func (lt *opsworksLayerType) SchemaResource() *schema.Resource {
    47  	resourceSchema := map[string]*schema.Schema{
    48  		"id": &schema.Schema{
    49  			Type:     schema.TypeString,
    50  			Computed: true,
    51  		},
    52  
    53  		"auto_assign_elastic_ips": &schema.Schema{
    54  			Type:     schema.TypeBool,
    55  			Optional: true,
    56  			Default:  false,
    57  		},
    58  
    59  		"auto_assign_public_ips": &schema.Schema{
    60  			Type:     schema.TypeBool,
    61  			Optional: true,
    62  			Default:  false,
    63  		},
    64  
    65  		"custom_instance_profile_arn": &schema.Schema{
    66  			Type:     schema.TypeString,
    67  			Optional: true,
    68  		},
    69  
    70  		"elastic_load_balancer": &schema.Schema{
    71  			Type:     schema.TypeString,
    72  			Optional: true,
    73  		},
    74  
    75  		"custom_setup_recipes": &schema.Schema{
    76  			Type:     schema.TypeList,
    77  			Optional: true,
    78  			Elem:     &schema.Schema{Type: schema.TypeString},
    79  		},
    80  
    81  		"custom_configure_recipes": &schema.Schema{
    82  			Type:     schema.TypeList,
    83  			Optional: true,
    84  			Elem:     &schema.Schema{Type: schema.TypeString},
    85  		},
    86  
    87  		"custom_deploy_recipes": &schema.Schema{
    88  			Type:     schema.TypeList,
    89  			Optional: true,
    90  			Elem:     &schema.Schema{Type: schema.TypeString},
    91  		},
    92  
    93  		"custom_undeploy_recipes": &schema.Schema{
    94  			Type:     schema.TypeList,
    95  			Optional: true,
    96  			Elem:     &schema.Schema{Type: schema.TypeString},
    97  		},
    98  
    99  		"custom_shutdown_recipes": &schema.Schema{
   100  			Type:     schema.TypeList,
   101  			Optional: true,
   102  			Elem:     &schema.Schema{Type: schema.TypeString},
   103  		},
   104  
   105  		"custom_security_group_ids": &schema.Schema{
   106  			Type:     schema.TypeSet,
   107  			Optional: true,
   108  			Elem:     &schema.Schema{Type: schema.TypeString},
   109  			Set:      schema.HashString,
   110  		},
   111  
   112  		"custom_json": &schema.Schema{
   113  			Type:      schema.TypeString,
   114  			StateFunc: normalizeJson,
   115  			Optional:  true,
   116  		},
   117  
   118  		"auto_healing": &schema.Schema{
   119  			Type:     schema.TypeBool,
   120  			Optional: true,
   121  			Default:  true,
   122  		},
   123  
   124  		"install_updates_on_boot": &schema.Schema{
   125  			Type:     schema.TypeBool,
   126  			Optional: true,
   127  			Default:  true,
   128  		},
   129  
   130  		"instance_shutdown_timeout": &schema.Schema{
   131  			Type:     schema.TypeInt,
   132  			Optional: true,
   133  			Default:  120,
   134  		},
   135  
   136  		"drain_elb_on_shutdown": &schema.Schema{
   137  			Type:     schema.TypeBool,
   138  			Optional: true,
   139  			Default:  true,
   140  		},
   141  
   142  		"system_packages": &schema.Schema{
   143  			Type:     schema.TypeSet,
   144  			Optional: true,
   145  			Elem:     &schema.Schema{Type: schema.TypeString},
   146  			Set:      schema.HashString,
   147  		},
   148  
   149  		"stack_id": &schema.Schema{
   150  			Type:     schema.TypeString,
   151  			ForceNew: true,
   152  			Required: true,
   153  		},
   154  
   155  		"use_ebs_optimized_instances": &schema.Schema{
   156  			Type:     schema.TypeBool,
   157  			Optional: true,
   158  			Default:  false,
   159  		},
   160  
   161  		"ebs_volume": &schema.Schema{
   162  			Type:     schema.TypeSet,
   163  			Optional: true,
   164  			Elem: &schema.Resource{
   165  				Schema: map[string]*schema.Schema{
   166  
   167  					"iops": &schema.Schema{
   168  						Type:     schema.TypeInt,
   169  						Optional: true,
   170  						Default:  0,
   171  					},
   172  
   173  					"mount_point": &schema.Schema{
   174  						Type:     schema.TypeString,
   175  						Required: true,
   176  					},
   177  
   178  					"number_of_disks": &schema.Schema{
   179  						Type:     schema.TypeInt,
   180  						Required: true,
   181  					},
   182  
   183  					"raid_level": &schema.Schema{
   184  						Type:     schema.TypeString,
   185  						Optional: true,
   186  						Default:  "",
   187  					},
   188  
   189  					"size": &schema.Schema{
   190  						Type:     schema.TypeInt,
   191  						Required: true,
   192  					},
   193  
   194  					"type": &schema.Schema{
   195  						Type:     schema.TypeString,
   196  						Optional: true,
   197  						Default:  "standard",
   198  					},
   199  				},
   200  			},
   201  			Set: func(v interface{}) int {
   202  				m := v.(map[string]interface{})
   203  				return hashcode.String(m["mount_point"].(string))
   204  			},
   205  		},
   206  	}
   207  
   208  	if lt.CustomShortName {
   209  		resourceSchema["short_name"] = &schema.Schema{
   210  			Type:     schema.TypeString,
   211  			Required: true,
   212  		}
   213  	}
   214  
   215  	if lt.DefaultLayerName != "" {
   216  		resourceSchema["name"] = &schema.Schema{
   217  			Type:     schema.TypeString,
   218  			Optional: true,
   219  			Default:  lt.DefaultLayerName,
   220  		}
   221  	} else {
   222  		resourceSchema["name"] = &schema.Schema{
   223  			Type:     schema.TypeString,
   224  			Required: true,
   225  		}
   226  	}
   227  
   228  	for key, def := range lt.Attributes {
   229  		resourceSchema[key] = &schema.Schema{
   230  			Type:     def.Type,
   231  			Default:  def.Default,
   232  			Required: def.Required,
   233  			Optional: !def.Required,
   234  		}
   235  	}
   236  
   237  	return &schema.Resource{
   238  		Read: func(d *schema.ResourceData, meta interface{}) error {
   239  			client := meta.(*AWSClient).opsworksconn
   240  			return lt.Read(d, client)
   241  		},
   242  		Create: func(d *schema.ResourceData, meta interface{}) error {
   243  			client := meta.(*AWSClient).opsworksconn
   244  			return lt.Create(d, client)
   245  		},
   246  		Update: func(d *schema.ResourceData, meta interface{}) error {
   247  			client := meta.(*AWSClient).opsworksconn
   248  			return lt.Update(d, client)
   249  		},
   250  		Delete: func(d *schema.ResourceData, meta interface{}) error {
   251  			client := meta.(*AWSClient).opsworksconn
   252  			return lt.Delete(d, client)
   253  		},
   254  		Importer: &schema.ResourceImporter{
   255  			State: schema.ImportStatePassthrough,
   256  		},
   257  
   258  		Schema: resourceSchema,
   259  	}
   260  }
   261  
   262  func (lt *opsworksLayerType) Read(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   263  
   264  	req := &opsworks.DescribeLayersInput{
   265  		LayerIds: []*string{
   266  			aws.String(d.Id()),
   267  		},
   268  	}
   269  
   270  	log.Printf("[DEBUG] Reading OpsWorks layer: %s", d.Id())
   271  
   272  	resp, err := client.DescribeLayers(req)
   273  	if err != nil {
   274  		if awserr, ok := err.(awserr.Error); ok {
   275  			if awserr.Code() == "ResourceNotFoundException" {
   276  				d.SetId("")
   277  				return nil
   278  			}
   279  		}
   280  		return err
   281  	}
   282  
   283  	layer := resp.Layers[0]
   284  	d.Set("id", layer.LayerId)
   285  	d.Set("auto_assign_elastic_ips", layer.AutoAssignElasticIps)
   286  	d.Set("auto_assign_public_ips", layer.AutoAssignPublicIps)
   287  	d.Set("custom_instance_profile_arn", layer.CustomInstanceProfileArn)
   288  	d.Set("custom_security_group_ids", flattenStringList(layer.CustomSecurityGroupIds))
   289  	d.Set("auto_healing", layer.EnableAutoHealing)
   290  	d.Set("install_updates_on_boot", layer.InstallUpdatesOnBoot)
   291  	d.Set("name", layer.Name)
   292  	d.Set("system_packages", flattenStringList(layer.Packages))
   293  	d.Set("stack_id", layer.StackId)
   294  	d.Set("use_ebs_optimized_instances", layer.UseEbsOptimizedInstances)
   295  
   296  	if lt.CustomShortName {
   297  		d.Set("short_name", layer.Shortname)
   298  	}
   299  
   300  	if v := layer.CustomJson; v == nil {
   301  		if err := d.Set("custom_json", ""); err != nil {
   302  			return err
   303  		}
   304  	} else if err := d.Set("custom_json", normalizeJson(*v)); err != nil {
   305  		return err
   306  	}
   307  
   308  	lt.SetAttributeMap(d, layer.Attributes)
   309  	lt.SetLifecycleEventConfiguration(d, layer.LifecycleEventConfiguration)
   310  	lt.SetCustomRecipes(d, layer.CustomRecipes)
   311  	lt.SetVolumeConfigurations(d, layer.VolumeConfigurations)
   312  
   313  	/* get ELB */
   314  	ebsRequest := &opsworks.DescribeElasticLoadBalancersInput{
   315  		LayerIds: []*string{
   316  			aws.String(d.Id()),
   317  		},
   318  	}
   319  	loadBalancers, err := client.DescribeElasticLoadBalancers(ebsRequest)
   320  	if err != nil {
   321  		return err
   322  	}
   323  
   324  	if loadBalancers.ElasticLoadBalancers == nil || len(loadBalancers.ElasticLoadBalancers) == 0 {
   325  		d.Set("elastic_load_balancer", "")
   326  	} else {
   327  		loadBalancer := loadBalancers.ElasticLoadBalancers[0]
   328  		if loadBalancer != nil {
   329  			d.Set("elastic_load_balancer", loadBalancer.ElasticLoadBalancerName)
   330  		}
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  func (lt *opsworksLayerType) Create(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   337  
   338  	req := &opsworks.CreateLayerInput{
   339  		AutoAssignElasticIps:        aws.Bool(d.Get("auto_assign_elastic_ips").(bool)),
   340  		AutoAssignPublicIps:         aws.Bool(d.Get("auto_assign_public_ips").(bool)),
   341  		CustomInstanceProfileArn:    aws.String(d.Get("custom_instance_profile_arn").(string)),
   342  		CustomRecipes:               lt.CustomRecipes(d),
   343  		CustomSecurityGroupIds:      expandStringSet(d.Get("custom_security_group_ids").(*schema.Set)),
   344  		EnableAutoHealing:           aws.Bool(d.Get("auto_healing").(bool)),
   345  		InstallUpdatesOnBoot:        aws.Bool(d.Get("install_updates_on_boot").(bool)),
   346  		LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d),
   347  		Name:                     aws.String(d.Get("name").(string)),
   348  		Packages:                 expandStringSet(d.Get("system_packages").(*schema.Set)),
   349  		Type:                     aws.String(lt.TypeName),
   350  		StackId:                  aws.String(d.Get("stack_id").(string)),
   351  		UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)),
   352  		Attributes:               lt.AttributeMap(d),
   353  		VolumeConfigurations:     lt.VolumeConfigurations(d),
   354  	}
   355  
   356  	if lt.CustomShortName {
   357  		req.Shortname = aws.String(d.Get("short_name").(string))
   358  	} else {
   359  		req.Shortname = aws.String(lt.TypeName)
   360  	}
   361  
   362  	req.CustomJson = aws.String(d.Get("custom_json").(string))
   363  
   364  	log.Printf("[DEBUG] Creating OpsWorks layer: %s", d.Id())
   365  
   366  	resp, err := client.CreateLayer(req)
   367  	if err != nil {
   368  		return err
   369  	}
   370  
   371  	layerId := *resp.LayerId
   372  	d.SetId(layerId)
   373  	d.Set("id", layerId)
   374  
   375  	loadBalancer := aws.String(d.Get("elastic_load_balancer").(string))
   376  	if loadBalancer != nil && *loadBalancer != "" {
   377  		log.Printf("[DEBUG] Attaching load balancer: %s", *loadBalancer)
   378  		_, err := client.AttachElasticLoadBalancer(&opsworks.AttachElasticLoadBalancerInput{
   379  			ElasticLoadBalancerName: loadBalancer,
   380  			LayerId:                 &layerId,
   381  		})
   382  		if err != nil {
   383  			return err
   384  		}
   385  	}
   386  
   387  	return lt.Read(d, client)
   388  }
   389  
   390  func (lt *opsworksLayerType) Update(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   391  
   392  	req := &opsworks.UpdateLayerInput{
   393  		LayerId:                     aws.String(d.Id()),
   394  		AutoAssignElasticIps:        aws.Bool(d.Get("auto_assign_elastic_ips").(bool)),
   395  		AutoAssignPublicIps:         aws.Bool(d.Get("auto_assign_public_ips").(bool)),
   396  		CustomInstanceProfileArn:    aws.String(d.Get("custom_instance_profile_arn").(string)),
   397  		CustomRecipes:               lt.CustomRecipes(d),
   398  		CustomSecurityGroupIds:      expandStringSet(d.Get("custom_security_group_ids").(*schema.Set)),
   399  		EnableAutoHealing:           aws.Bool(d.Get("auto_healing").(bool)),
   400  		InstallUpdatesOnBoot:        aws.Bool(d.Get("install_updates_on_boot").(bool)),
   401  		LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d),
   402  		Name:                     aws.String(d.Get("name").(string)),
   403  		Packages:                 expandStringSet(d.Get("system_packages").(*schema.Set)),
   404  		UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)),
   405  		Attributes:               lt.AttributeMap(d),
   406  		VolumeConfigurations:     lt.VolumeConfigurations(d),
   407  	}
   408  
   409  	if lt.CustomShortName {
   410  		req.Shortname = aws.String(d.Get("short_name").(string))
   411  	} else {
   412  		req.Shortname = aws.String(lt.TypeName)
   413  	}
   414  
   415  	req.CustomJson = aws.String(d.Get("custom_json").(string))
   416  
   417  	log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id())
   418  
   419  	if d.HasChange("elastic_load_balancer") {
   420  		lbo, lbn := d.GetChange("elastic_load_balancer")
   421  
   422  		loadBalancerOld := aws.String(lbo.(string))
   423  		loadBalancerNew := aws.String(lbn.(string))
   424  
   425  		if loadBalancerOld != nil && *loadBalancerOld != "" {
   426  			log.Printf("[DEBUG] Dettaching load balancer: %s", *loadBalancerOld)
   427  			_, err := client.DetachElasticLoadBalancer(&opsworks.DetachElasticLoadBalancerInput{
   428  				ElasticLoadBalancerName: loadBalancerOld,
   429  				LayerId:                 aws.String(d.Id()),
   430  			})
   431  			if err != nil {
   432  				return err
   433  			}
   434  		}
   435  
   436  		if loadBalancerNew != nil && *loadBalancerNew != "" {
   437  			log.Printf("[DEBUG] Attaching load balancer: %s", *loadBalancerNew)
   438  			_, err := client.AttachElasticLoadBalancer(&opsworks.AttachElasticLoadBalancerInput{
   439  				ElasticLoadBalancerName: loadBalancerNew,
   440  				LayerId:                 aws.String(d.Id()),
   441  			})
   442  			if err != nil {
   443  				return err
   444  			}
   445  		}
   446  	}
   447  
   448  	_, err := client.UpdateLayer(req)
   449  	if err != nil {
   450  		return err
   451  	}
   452  
   453  	return lt.Read(d, client)
   454  }
   455  
   456  func (lt *opsworksLayerType) Delete(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   457  	req := &opsworks.DeleteLayerInput{
   458  		LayerId: aws.String(d.Id()),
   459  	}
   460  
   461  	log.Printf("[DEBUG] Deleting OpsWorks layer: %s", d.Id())
   462  
   463  	_, err := client.DeleteLayer(req)
   464  	return err
   465  }
   466  
   467  func (lt *opsworksLayerType) AttributeMap(d *schema.ResourceData) map[string]*string {
   468  	attrs := map[string]*string{}
   469  
   470  	for key, def := range lt.Attributes {
   471  		value := d.Get(key)
   472  		switch def.Type {
   473  		case schema.TypeString:
   474  			strValue := value.(string)
   475  			attrs[def.AttrName] = &strValue
   476  		case schema.TypeInt:
   477  			intValue := value.(int)
   478  			strValue := strconv.Itoa(intValue)
   479  			attrs[def.AttrName] = &strValue
   480  		case schema.TypeBool:
   481  			boolValue := value.(bool)
   482  			if boolValue {
   483  				attrs[def.AttrName] = &opsworksTrueString
   484  			} else {
   485  				attrs[def.AttrName] = &opsworksFalseString
   486  			}
   487  		default:
   488  			// should never happen
   489  			panic(fmt.Errorf("Unsupported OpsWorks layer attribute type"))
   490  		}
   491  	}
   492  
   493  	return attrs
   494  }
   495  
   496  func (lt *opsworksLayerType) SetAttributeMap(d *schema.ResourceData, attrs map[string]*string) {
   497  	for key, def := range lt.Attributes {
   498  		// Ignore write-only attributes; we'll just keep what we already have stored.
   499  		// (The AWS API returns garbage placeholder values for these.)
   500  		if def.WriteOnly {
   501  			continue
   502  		}
   503  
   504  		if strPtr, ok := attrs[def.AttrName]; ok && strPtr != nil {
   505  			strValue := *strPtr
   506  
   507  			switch def.Type {
   508  			case schema.TypeString:
   509  				d.Set(key, strValue)
   510  			case schema.TypeInt:
   511  				intValue, err := strconv.Atoi(strValue)
   512  				if err == nil {
   513  					d.Set(key, intValue)
   514  				} else {
   515  					// Got garbage from the AWS API
   516  					d.Set(key, nil)
   517  				}
   518  			case schema.TypeBool:
   519  				boolValue := true
   520  				if strValue == opsworksFalseString {
   521  					boolValue = false
   522  				}
   523  				d.Set(key, boolValue)
   524  			default:
   525  				// should never happen
   526  				panic(fmt.Errorf("Unsupported OpsWorks layer attribute type"))
   527  			}
   528  			return
   529  
   530  		} else {
   531  			d.Set(key, nil)
   532  		}
   533  	}
   534  }
   535  
   536  func (lt *opsworksLayerType) LifecycleEventConfiguration(d *schema.ResourceData) *opsworks.LifecycleEventConfiguration {
   537  	return &opsworks.LifecycleEventConfiguration{
   538  		Shutdown: &opsworks.ShutdownEventConfiguration{
   539  			DelayUntilElbConnectionsDrained: aws.Bool(d.Get("drain_elb_on_shutdown").(bool)),
   540  			ExecutionTimeout:                aws.Int64(int64(d.Get("instance_shutdown_timeout").(int))),
   541  		},
   542  	}
   543  }
   544  
   545  func (lt *opsworksLayerType) SetLifecycleEventConfiguration(d *schema.ResourceData, v *opsworks.LifecycleEventConfiguration) {
   546  	if v == nil || v.Shutdown == nil {
   547  		d.Set("drain_elb_on_shutdown", nil)
   548  		d.Set("instance_shutdown_timeout", nil)
   549  	} else {
   550  		d.Set("drain_elb_on_shutdown", v.Shutdown.DelayUntilElbConnectionsDrained)
   551  		d.Set("instance_shutdown_timeout", v.Shutdown.ExecutionTimeout)
   552  	}
   553  }
   554  
   555  func (lt *opsworksLayerType) CustomRecipes(d *schema.ResourceData) *opsworks.Recipes {
   556  	return &opsworks.Recipes{
   557  		Configure: expandStringList(d.Get("custom_configure_recipes").([]interface{})),
   558  		Deploy:    expandStringList(d.Get("custom_deploy_recipes").([]interface{})),
   559  		Setup:     expandStringList(d.Get("custom_setup_recipes").([]interface{})),
   560  		Shutdown:  expandStringList(d.Get("custom_shutdown_recipes").([]interface{})),
   561  		Undeploy:  expandStringList(d.Get("custom_undeploy_recipes").([]interface{})),
   562  	}
   563  }
   564  
   565  func (lt *opsworksLayerType) SetCustomRecipes(d *schema.ResourceData, v *opsworks.Recipes) {
   566  	// Null out everything first, and then we'll consider what to put back.
   567  	d.Set("custom_configure_recipes", nil)
   568  	d.Set("custom_deploy_recipes", nil)
   569  	d.Set("custom_setup_recipes", nil)
   570  	d.Set("custom_shutdown_recipes", nil)
   571  	d.Set("custom_undeploy_recipes", nil)
   572  
   573  	if v == nil {
   574  		return
   575  	}
   576  
   577  	d.Set("custom_configure_recipes", flattenStringList(v.Configure))
   578  	d.Set("custom_deploy_recipes", flattenStringList(v.Deploy))
   579  	d.Set("custom_setup_recipes", flattenStringList(v.Setup))
   580  	d.Set("custom_shutdown_recipes", flattenStringList(v.Shutdown))
   581  	d.Set("custom_undeploy_recipes", flattenStringList(v.Undeploy))
   582  }
   583  
   584  func (lt *opsworksLayerType) VolumeConfigurations(d *schema.ResourceData) []*opsworks.VolumeConfiguration {
   585  	configuredVolumes := d.Get("ebs_volume").(*schema.Set).List()
   586  	result := make([]*opsworks.VolumeConfiguration, len(configuredVolumes))
   587  
   588  	for i := 0; i < len(configuredVolumes); i++ {
   589  		volumeData := configuredVolumes[i].(map[string]interface{})
   590  
   591  		result[i] = &opsworks.VolumeConfiguration{
   592  			MountPoint:    aws.String(volumeData["mount_point"].(string)),
   593  			NumberOfDisks: aws.Int64(int64(volumeData["number_of_disks"].(int))),
   594  			Size:          aws.Int64(int64(volumeData["size"].(int))),
   595  			VolumeType:    aws.String(volumeData["type"].(string)),
   596  		}
   597  		iops := int64(volumeData["iops"].(int))
   598  		if iops != 0 {
   599  			result[i].Iops = aws.Int64(iops)
   600  		}
   601  
   602  		raidLevelStr := volumeData["raid_level"].(string)
   603  		if raidLevelStr != "" {
   604  			raidLevel, err := strconv.Atoi(raidLevelStr)
   605  			if err == nil {
   606  				result[i].RaidLevel = aws.Int64(int64(raidLevel))
   607  			}
   608  		}
   609  	}
   610  
   611  	return result
   612  }
   613  
   614  func (lt *opsworksLayerType) SetVolumeConfigurations(d *schema.ResourceData, v []*opsworks.VolumeConfiguration) {
   615  	newValue := make([]*map[string]interface{}, len(v))
   616  
   617  	for i := 0; i < len(v); i++ {
   618  		config := v[i]
   619  		data := make(map[string]interface{})
   620  		newValue[i] = &data
   621  
   622  		if config.Iops != nil {
   623  			data["iops"] = int(*config.Iops)
   624  		} else {
   625  			data["iops"] = 0
   626  		}
   627  		if config.MountPoint != nil {
   628  			data["mount_point"] = *config.MountPoint
   629  		}
   630  		if config.NumberOfDisks != nil {
   631  			data["number_of_disks"] = int(*config.NumberOfDisks)
   632  		}
   633  		if config.RaidLevel != nil {
   634  			data["raid_level"] = strconv.Itoa(int(*config.RaidLevel))
   635  		}
   636  		if config.Size != nil {
   637  			data["size"] = int(*config.Size)
   638  		}
   639  		if config.VolumeType != nil {
   640  			data["type"] = *config.VolumeType
   641  		}
   642  	}
   643  
   644  	d.Set("ebs_volume", newValue)
   645  }