github.com/mohanarpit/terraform@v0.6.16-0.20160909104007-291f29853544/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  
   255  		Schema: resourceSchema,
   256  	}
   257  }
   258  
   259  func (lt *opsworksLayerType) Read(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   260  
   261  	req := &opsworks.DescribeLayersInput{
   262  		LayerIds: []*string{
   263  			aws.String(d.Id()),
   264  		},
   265  	}
   266  
   267  	log.Printf("[DEBUG] Reading OpsWorks layer: %s", d.Id())
   268  
   269  	resp, err := client.DescribeLayers(req)
   270  	if err != nil {
   271  		if awserr, ok := err.(awserr.Error); ok {
   272  			if awserr.Code() == "ResourceNotFoundException" {
   273  				d.SetId("")
   274  				return nil
   275  			}
   276  		}
   277  		return err
   278  	}
   279  
   280  	layer := resp.Layers[0]
   281  	d.Set("id", layer.LayerId)
   282  	d.Set("auto_assign_elastic_ips", layer.AutoAssignElasticIps)
   283  	d.Set("auto_assign_public_ips", layer.AutoAssignPublicIps)
   284  	d.Set("custom_instance_profile_arn", layer.CustomInstanceProfileArn)
   285  	d.Set("custom_security_group_ids", flattenStringList(layer.CustomSecurityGroupIds))
   286  	d.Set("auto_healing", layer.EnableAutoHealing)
   287  	d.Set("install_updates_on_boot", layer.InstallUpdatesOnBoot)
   288  	d.Set("name", layer.Name)
   289  	d.Set("system_packages", flattenStringList(layer.Packages))
   290  	d.Set("stack_id", layer.StackId)
   291  	d.Set("use_ebs_optimized_instances", layer.UseEbsOptimizedInstances)
   292  
   293  	if lt.CustomShortName {
   294  		d.Set("short_name", layer.Shortname)
   295  	}
   296  
   297  	if v := layer.CustomJson; v == nil {
   298  		if err := d.Set("custom_json", ""); err != nil {
   299  			return err
   300  		}
   301  	} else if err := d.Set("custom_json", normalizeJson(*v)); err != nil {
   302  		return err
   303  	}
   304  
   305  	lt.SetAttributeMap(d, layer.Attributes)
   306  	lt.SetLifecycleEventConfiguration(d, layer.LifecycleEventConfiguration)
   307  	lt.SetCustomRecipes(d, layer.CustomRecipes)
   308  	lt.SetVolumeConfigurations(d, layer.VolumeConfigurations)
   309  
   310  	/* get ELB */
   311  	ebsRequest := &opsworks.DescribeElasticLoadBalancersInput{
   312  		LayerIds: []*string{
   313  			aws.String(d.Id()),
   314  		},
   315  	}
   316  	loadBalancers, err := client.DescribeElasticLoadBalancers(ebsRequest)
   317  	if err != nil {
   318  		return err
   319  	}
   320  
   321  	if loadBalancers.ElasticLoadBalancers == nil || len(loadBalancers.ElasticLoadBalancers) == 0 {
   322  		d.Set("elastic_load_balancer", "")
   323  	} else {
   324  		loadBalancer := loadBalancers.ElasticLoadBalancers[0]
   325  		if loadBalancer != nil {
   326  			d.Set("elastic_load_balancer", loadBalancer.ElasticLoadBalancerName)
   327  		}
   328  	}
   329  
   330  	return nil
   331  }
   332  
   333  func (lt *opsworksLayerType) Create(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   334  
   335  	req := &opsworks.CreateLayerInput{
   336  		AutoAssignElasticIps:        aws.Bool(d.Get("auto_assign_elastic_ips").(bool)),
   337  		AutoAssignPublicIps:         aws.Bool(d.Get("auto_assign_public_ips").(bool)),
   338  		CustomInstanceProfileArn:    aws.String(d.Get("custom_instance_profile_arn").(string)),
   339  		CustomRecipes:               lt.CustomRecipes(d),
   340  		CustomSecurityGroupIds:      expandStringSet(d.Get("custom_security_group_ids").(*schema.Set)),
   341  		EnableAutoHealing:           aws.Bool(d.Get("auto_healing").(bool)),
   342  		InstallUpdatesOnBoot:        aws.Bool(d.Get("install_updates_on_boot").(bool)),
   343  		LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d),
   344  		Name:                     aws.String(d.Get("name").(string)),
   345  		Packages:                 expandStringSet(d.Get("system_packages").(*schema.Set)),
   346  		Type:                     aws.String(lt.TypeName),
   347  		StackId:                  aws.String(d.Get("stack_id").(string)),
   348  		UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)),
   349  		Attributes:               lt.AttributeMap(d),
   350  		VolumeConfigurations:     lt.VolumeConfigurations(d),
   351  	}
   352  
   353  	if lt.CustomShortName {
   354  		req.Shortname = aws.String(d.Get("short_name").(string))
   355  	} else {
   356  		req.Shortname = aws.String(lt.TypeName)
   357  	}
   358  
   359  	req.CustomJson = aws.String(d.Get("custom_json").(string))
   360  
   361  	log.Printf("[DEBUG] Creating OpsWorks layer: %s", d.Id())
   362  
   363  	resp, err := client.CreateLayer(req)
   364  	if err != nil {
   365  		return err
   366  	}
   367  
   368  	layerId := *resp.LayerId
   369  	d.SetId(layerId)
   370  	d.Set("id", layerId)
   371  
   372  	loadBalancer := aws.String(d.Get("elastic_load_balancer").(string))
   373  	if loadBalancer != nil && *loadBalancer != "" {
   374  		log.Printf("[DEBUG] Attaching load balancer: %s", *loadBalancer)
   375  		_, err := client.AttachElasticLoadBalancer(&opsworks.AttachElasticLoadBalancerInput{
   376  			ElasticLoadBalancerName: loadBalancer,
   377  			LayerId:                 &layerId,
   378  		})
   379  		if err != nil {
   380  			return err
   381  		}
   382  	}
   383  
   384  	return lt.Read(d, client)
   385  }
   386  
   387  func (lt *opsworksLayerType) Update(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   388  
   389  	req := &opsworks.UpdateLayerInput{
   390  		LayerId:                     aws.String(d.Id()),
   391  		AutoAssignElasticIps:        aws.Bool(d.Get("auto_assign_elastic_ips").(bool)),
   392  		AutoAssignPublicIps:         aws.Bool(d.Get("auto_assign_public_ips").(bool)),
   393  		CustomInstanceProfileArn:    aws.String(d.Get("custom_instance_profile_arn").(string)),
   394  		CustomRecipes:               lt.CustomRecipes(d),
   395  		CustomSecurityGroupIds:      expandStringSet(d.Get("custom_security_group_ids").(*schema.Set)),
   396  		EnableAutoHealing:           aws.Bool(d.Get("auto_healing").(bool)),
   397  		InstallUpdatesOnBoot:        aws.Bool(d.Get("install_updates_on_boot").(bool)),
   398  		LifecycleEventConfiguration: lt.LifecycleEventConfiguration(d),
   399  		Name:                     aws.String(d.Get("name").(string)),
   400  		Packages:                 expandStringSet(d.Get("system_packages").(*schema.Set)),
   401  		UseEbsOptimizedInstances: aws.Bool(d.Get("use_ebs_optimized_instances").(bool)),
   402  		Attributes:               lt.AttributeMap(d),
   403  		VolumeConfigurations:     lt.VolumeConfigurations(d),
   404  	}
   405  
   406  	if lt.CustomShortName {
   407  		req.Shortname = aws.String(d.Get("short_name").(string))
   408  	} else {
   409  		req.Shortname = aws.String(lt.TypeName)
   410  	}
   411  
   412  	req.CustomJson = aws.String(d.Get("custom_json").(string))
   413  
   414  	log.Printf("[DEBUG] Updating OpsWorks layer: %s", d.Id())
   415  
   416  	if d.HasChange("elastic_load_balancer") {
   417  		lbo, lbn := d.GetChange("elastic_load_balancer")
   418  
   419  		loadBalancerOld := aws.String(lbo.(string))
   420  		loadBalancerNew := aws.String(lbn.(string))
   421  
   422  		if loadBalancerOld != nil && *loadBalancerOld != "" {
   423  			log.Printf("[DEBUG] Dettaching load balancer: %s", *loadBalancerOld)
   424  			_, err := client.DetachElasticLoadBalancer(&opsworks.DetachElasticLoadBalancerInput{
   425  				ElasticLoadBalancerName: loadBalancerOld,
   426  				LayerId:                 aws.String(d.Id()),
   427  			})
   428  			if err != nil {
   429  				return err
   430  			}
   431  		}
   432  
   433  		if loadBalancerNew != nil && *loadBalancerNew != "" {
   434  			log.Printf("[DEBUG] Attaching load balancer: %s", *loadBalancerNew)
   435  			_, err := client.AttachElasticLoadBalancer(&opsworks.AttachElasticLoadBalancerInput{
   436  				ElasticLoadBalancerName: loadBalancerNew,
   437  				LayerId:                 aws.String(d.Id()),
   438  			})
   439  			if err != nil {
   440  				return err
   441  			}
   442  		}
   443  	}
   444  
   445  	_, err := client.UpdateLayer(req)
   446  	if err != nil {
   447  		return err
   448  	}
   449  
   450  	return lt.Read(d, client)
   451  }
   452  
   453  func (lt *opsworksLayerType) Delete(d *schema.ResourceData, client *opsworks.OpsWorks) error {
   454  	req := &opsworks.DeleteLayerInput{
   455  		LayerId: aws.String(d.Id()),
   456  	}
   457  
   458  	log.Printf("[DEBUG] Deleting OpsWorks layer: %s", d.Id())
   459  
   460  	_, err := client.DeleteLayer(req)
   461  	return err
   462  }
   463  
   464  func (lt *opsworksLayerType) AttributeMap(d *schema.ResourceData) map[string]*string {
   465  	attrs := map[string]*string{}
   466  
   467  	for key, def := range lt.Attributes {
   468  		value := d.Get(key)
   469  		switch def.Type {
   470  		case schema.TypeString:
   471  			strValue := value.(string)
   472  			attrs[def.AttrName] = &strValue
   473  		case schema.TypeInt:
   474  			intValue := value.(int)
   475  			strValue := strconv.Itoa(intValue)
   476  			attrs[def.AttrName] = &strValue
   477  		case schema.TypeBool:
   478  			boolValue := value.(bool)
   479  			if boolValue {
   480  				attrs[def.AttrName] = &opsworksTrueString
   481  			} else {
   482  				attrs[def.AttrName] = &opsworksFalseString
   483  			}
   484  		default:
   485  			// should never happen
   486  			panic(fmt.Errorf("Unsupported OpsWorks layer attribute type"))
   487  		}
   488  	}
   489  
   490  	return attrs
   491  }
   492  
   493  func (lt *opsworksLayerType) SetAttributeMap(d *schema.ResourceData, attrs map[string]*string) {
   494  	for key, def := range lt.Attributes {
   495  		// Ignore write-only attributes; we'll just keep what we already have stored.
   496  		// (The AWS API returns garbage placeholder values for these.)
   497  		if def.WriteOnly {
   498  			continue
   499  		}
   500  
   501  		if strPtr, ok := attrs[def.AttrName]; ok && strPtr != nil {
   502  			strValue := *strPtr
   503  
   504  			switch def.Type {
   505  			case schema.TypeString:
   506  				d.Set(key, strValue)
   507  			case schema.TypeInt:
   508  				intValue, err := strconv.Atoi(strValue)
   509  				if err == nil {
   510  					d.Set(key, intValue)
   511  				} else {
   512  					// Got garbage from the AWS API
   513  					d.Set(key, nil)
   514  				}
   515  			case schema.TypeBool:
   516  				boolValue := true
   517  				if strValue == opsworksFalseString {
   518  					boolValue = false
   519  				}
   520  				d.Set(key, boolValue)
   521  			default:
   522  				// should never happen
   523  				panic(fmt.Errorf("Unsupported OpsWorks layer attribute type"))
   524  			}
   525  			return
   526  
   527  		} else {
   528  			d.Set(key, nil)
   529  		}
   530  	}
   531  }
   532  
   533  func (lt *opsworksLayerType) LifecycleEventConfiguration(d *schema.ResourceData) *opsworks.LifecycleEventConfiguration {
   534  	return &opsworks.LifecycleEventConfiguration{
   535  		Shutdown: &opsworks.ShutdownEventConfiguration{
   536  			DelayUntilElbConnectionsDrained: aws.Bool(d.Get("drain_elb_on_shutdown").(bool)),
   537  			ExecutionTimeout:                aws.Int64(int64(d.Get("instance_shutdown_timeout").(int))),
   538  		},
   539  	}
   540  }
   541  
   542  func (lt *opsworksLayerType) SetLifecycleEventConfiguration(d *schema.ResourceData, v *opsworks.LifecycleEventConfiguration) {
   543  	if v == nil || v.Shutdown == nil {
   544  		d.Set("drain_elb_on_shutdown", nil)
   545  		d.Set("instance_shutdown_timeout", nil)
   546  	} else {
   547  		d.Set("drain_elb_on_shutdown", v.Shutdown.DelayUntilElbConnectionsDrained)
   548  		d.Set("instance_shutdown_timeout", v.Shutdown.ExecutionTimeout)
   549  	}
   550  }
   551  
   552  func (lt *opsworksLayerType) CustomRecipes(d *schema.ResourceData) *opsworks.Recipes {
   553  	return &opsworks.Recipes{
   554  		Configure: expandStringList(d.Get("custom_configure_recipes").([]interface{})),
   555  		Deploy:    expandStringList(d.Get("custom_deploy_recipes").([]interface{})),
   556  		Setup:     expandStringList(d.Get("custom_setup_recipes").([]interface{})),
   557  		Shutdown:  expandStringList(d.Get("custom_shutdown_recipes").([]interface{})),
   558  		Undeploy:  expandStringList(d.Get("custom_undeploy_recipes").([]interface{})),
   559  	}
   560  }
   561  
   562  func (lt *opsworksLayerType) SetCustomRecipes(d *schema.ResourceData, v *opsworks.Recipes) {
   563  	// Null out everything first, and then we'll consider what to put back.
   564  	d.Set("custom_configure_recipes", nil)
   565  	d.Set("custom_deploy_recipes", nil)
   566  	d.Set("custom_setup_recipes", nil)
   567  	d.Set("custom_shutdown_recipes", nil)
   568  	d.Set("custom_undeploy_recipes", nil)
   569  
   570  	if v == nil {
   571  		return
   572  	}
   573  
   574  	d.Set("custom_configure_recipes", flattenStringList(v.Configure))
   575  	d.Set("custom_deploy_recipes", flattenStringList(v.Deploy))
   576  	d.Set("custom_setup_recipes", flattenStringList(v.Setup))
   577  	d.Set("custom_shutdown_recipes", flattenStringList(v.Shutdown))
   578  	d.Set("custom_undeploy_recipes", flattenStringList(v.Undeploy))
   579  }
   580  
   581  func (lt *opsworksLayerType) VolumeConfigurations(d *schema.ResourceData) []*opsworks.VolumeConfiguration {
   582  	configuredVolumes := d.Get("ebs_volume").(*schema.Set).List()
   583  	result := make([]*opsworks.VolumeConfiguration, len(configuredVolumes))
   584  
   585  	for i := 0; i < len(configuredVolumes); i++ {
   586  		volumeData := configuredVolumes[i].(map[string]interface{})
   587  
   588  		result[i] = &opsworks.VolumeConfiguration{
   589  			MountPoint:    aws.String(volumeData["mount_point"].(string)),
   590  			NumberOfDisks: aws.Int64(int64(volumeData["number_of_disks"].(int))),
   591  			Size:          aws.Int64(int64(volumeData["size"].(int))),
   592  			VolumeType:    aws.String(volumeData["type"].(string)),
   593  		}
   594  		iops := int64(volumeData["iops"].(int))
   595  		if iops != 0 {
   596  			result[i].Iops = aws.Int64(iops)
   597  		}
   598  
   599  		raidLevelStr := volumeData["raid_level"].(string)
   600  		if raidLevelStr != "" {
   601  			raidLevel, err := strconv.Atoi(raidLevelStr)
   602  			if err == nil {
   603  				result[i].RaidLevel = aws.Int64(int64(raidLevel))
   604  			}
   605  		}
   606  	}
   607  
   608  	return result
   609  }
   610  
   611  func (lt *opsworksLayerType) SetVolumeConfigurations(d *schema.ResourceData, v []*opsworks.VolumeConfiguration) {
   612  	newValue := make([]*map[string]interface{}, len(v))
   613  
   614  	for i := 0; i < len(v); i++ {
   615  		config := v[i]
   616  		data := make(map[string]interface{})
   617  		newValue[i] = &data
   618  
   619  		if config.Iops != nil {
   620  			data["iops"] = int(*config.Iops)
   621  		} else {
   622  			data["iops"] = 0
   623  		}
   624  		if config.MountPoint != nil {
   625  			data["mount_point"] = *config.MountPoint
   626  		}
   627  		if config.NumberOfDisks != nil {
   628  			data["number_of_disks"] = int(*config.NumberOfDisks)
   629  		}
   630  		if config.RaidLevel != nil {
   631  			data["raid_level"] = strconv.Itoa(int(*config.RaidLevel))
   632  		}
   633  		if config.Size != nil {
   634  			data["size"] = int(*config.Size)
   635  		}
   636  		if config.VolumeType != nil {
   637  			data["type"] = *config.VolumeType
   638  		}
   639  	}
   640  
   641  	d.Set("ebs_volume", newValue)
   642  }