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

     1  package alicloud
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/denverdino/aliyungo/common"
     7  	"github.com/denverdino/aliyungo/ecs"
     8  	"github.com/hashicorp/terraform/helper/resource"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"log"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  )
    15  
    16  func resourceAliyunNatGateway() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAliyunNatGatewayCreate,
    19  		Read:   resourceAliyunNatGatewayRead,
    20  		Update: resourceAliyunNatGatewayUpdate,
    21  		Delete: resourceAliyunNatGatewayDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"vpc_id": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  			"spec": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  			},
    33  			"name": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Optional: true,
    36  				Computed: true,
    37  			},
    38  			"description": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Optional: true,
    41  			},
    42  
    43  			"bandwidth_package_ids": &schema.Schema{
    44  				Type:     schema.TypeString,
    45  				Computed: true,
    46  			},
    47  
    48  			"snat_table_ids": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Computed: true,
    51  			},
    52  
    53  			"forward_table_ids": &schema.Schema{
    54  				Type:     schema.TypeString,
    55  				Computed: true,
    56  			},
    57  
    58  			"bandwidth_packages": &schema.Schema{
    59  				Type: schema.TypeList,
    60  				Elem: &schema.Resource{
    61  					Schema: map[string]*schema.Schema{
    62  						"ip_count": &schema.Schema{
    63  							Type:     schema.TypeInt,
    64  							Required: true,
    65  						},
    66  						"bandwidth": &schema.Schema{
    67  							Type:     schema.TypeInt,
    68  							Required: true,
    69  						},
    70  						"zone": &schema.Schema{
    71  							Type:     schema.TypeString,
    72  							Optional: true,
    73  						},
    74  						"public_ip_addresses": &schema.Schema{
    75  							Type:     schema.TypeString,
    76  							Computed: true,
    77  						},
    78  					},
    79  				},
    80  				Required: true,
    81  				MaxItems: 4,
    82  			},
    83  		},
    84  	}
    85  }
    86  
    87  func resourceAliyunNatGatewayCreate(d *schema.ResourceData, meta interface{}) error {
    88  	conn := meta.(*AliyunClient).vpcconn
    89  
    90  	args := &ecs.CreateNatGatewayArgs{
    91  		RegionId: getRegion(d, meta),
    92  		VpcId:    d.Get("vpc_id").(string),
    93  		Spec:     d.Get("spec").(string),
    94  	}
    95  
    96  	bandwidthPackages := d.Get("bandwidth_packages").([]interface{})
    97  
    98  	bandwidthPackageTypes := []ecs.BandwidthPackageType{}
    99  
   100  	for _, e := range bandwidthPackages {
   101  		pack := e.(map[string]interface{})
   102  		bandwidthPackage := ecs.BandwidthPackageType{
   103  			IpCount:   pack["ip_count"].(int),
   104  			Bandwidth: pack["bandwidth"].(int),
   105  		}
   106  		if pack["zone"].(string) != "" {
   107  			bandwidthPackage.Zone = pack["zone"].(string)
   108  		}
   109  
   110  		bandwidthPackageTypes = append(bandwidthPackageTypes, bandwidthPackage)
   111  	}
   112  
   113  	args.BandwidthPackage = bandwidthPackageTypes
   114  
   115  	var name string
   116  	if v, ok := d.GetOk("name"); ok {
   117  		name = v.(string)
   118  	}
   119  
   120  	args.Name = name
   121  
   122  	if v, ok := d.GetOk("description"); ok {
   123  		args.Description = v.(string)
   124  	}
   125  	resp, err := conn.CreateNatGateway(args)
   126  	if err != nil {
   127  		return fmt.Errorf("CreateNatGateway got error: %#v", err)
   128  	}
   129  
   130  	d.SetId(resp.NatGatewayId)
   131  
   132  	return resourceAliyunNatGatewayRead(d, meta)
   133  }
   134  
   135  func resourceAliyunNatGatewayRead(d *schema.ResourceData, meta interface{}) error {
   136  
   137  	client := meta.(*AliyunClient)
   138  
   139  	natGateway, err := client.DescribeNatGateway(d.Id())
   140  	if err != nil {
   141  		if notFoundError(err) {
   142  			d.SetId("")
   143  			return nil
   144  		}
   145  		return err
   146  	}
   147  
   148  	d.Set("name", natGateway.Name)
   149  	d.Set("spec", natGateway.Spec)
   150  	d.Set("bandwidth_package_ids", strings.Join(natGateway.BandwidthPackageIds.BandwidthPackageId, ","))
   151  	d.Set("snat_table_ids", strings.Join(natGateway.SnatTableIds.SnatTableId, ","))
   152  	d.Set("forward_table_ids", strings.Join(natGateway.ForwardTableIds.ForwardTableId, ","))
   153  	d.Set("description", natGateway.Description)
   154  	d.Set("vpc_id", natGateway.VpcId)
   155  	bindWidthPackages, err := flattenBandWidthPackages(natGateway.BandwidthPackageIds.BandwidthPackageId, meta, d)
   156  	if err != nil {
   157  		log.Printf("[ERROR] bindWidthPackages flattenBandWidthPackages failed. natgateway id is %#v", d.Id())
   158  	} else {
   159  		d.Set("bandwidth_packages", bindWidthPackages)
   160  	}
   161  
   162  	return nil
   163  }
   164  
   165  func resourceAliyunNatGatewayUpdate(d *schema.ResourceData, meta interface{}) error {
   166  
   167  	client := meta.(*AliyunClient)
   168  	conn := client.vpcconn
   169  
   170  	natGateway, err := client.DescribeNatGateway(d.Id())
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	d.Partial(true)
   176  	attributeUpdate := false
   177  	args := &ecs.ModifyNatGatewayAttributeArgs{
   178  		RegionId:     natGateway.RegionId,
   179  		NatGatewayId: natGateway.NatGatewayId,
   180  	}
   181  
   182  	if d.HasChange("name") {
   183  		d.SetPartial("name")
   184  		var name string
   185  		if v, ok := d.GetOk("name"); ok {
   186  			name = v.(string)
   187  		} else {
   188  			return fmt.Errorf("cann't change name to empty string")
   189  		}
   190  		args.Name = name
   191  
   192  		attributeUpdate = true
   193  	}
   194  
   195  	if d.HasChange("description") {
   196  		d.SetPartial("description")
   197  		var description string
   198  		if v, ok := d.GetOk("description"); ok {
   199  			description = v.(string)
   200  		} else {
   201  			return fmt.Errorf("can to change description to empty string")
   202  		}
   203  
   204  		args.Description = description
   205  
   206  		attributeUpdate = true
   207  	}
   208  
   209  	if attributeUpdate {
   210  		if err := conn.ModifyNatGatewayAttribute(args); err != nil {
   211  			return err
   212  		}
   213  	}
   214  
   215  	if d.HasChange("spec") {
   216  		d.SetPartial("spec")
   217  		var spec ecs.NatGatewaySpec
   218  		if v, ok := d.GetOk("spec"); ok {
   219  			spec = ecs.NatGatewaySpec(v.(string))
   220  		} else {
   221  			// set default to small spec
   222  			spec = ecs.NatGatewaySmallSpec
   223  		}
   224  
   225  		args := &ecs.ModifyNatGatewaySpecArgs{
   226  			RegionId:     natGateway.RegionId,
   227  			NatGatewayId: natGateway.NatGatewayId,
   228  			Spec:         spec,
   229  		}
   230  
   231  		err := conn.ModifyNatGatewaySpec(args)
   232  		if err != nil {
   233  			return fmt.Errorf("%#v %#v", err, *args)
   234  		}
   235  
   236  	}
   237  	d.Partial(false)
   238  
   239  	return resourceAliyunNatGatewayRead(d, meta)
   240  }
   241  
   242  func resourceAliyunNatGatewayDelete(d *schema.ResourceData, meta interface{}) error {
   243  
   244  	client := meta.(*AliyunClient)
   245  	conn := client.vpcconn
   246  
   247  	return resource.Retry(5*time.Minute, func() *resource.RetryError {
   248  
   249  		packages, err := conn.DescribeBandwidthPackages(&ecs.DescribeBandwidthPackagesArgs{
   250  			RegionId:     getRegion(d, meta),
   251  			NatGatewayId: d.Id(),
   252  		})
   253  		if err != nil {
   254  			log.Printf("[ERROR] Describe bandwidth package is failed, natGateway Id: %s", d.Id())
   255  			return resource.NonRetryableError(err)
   256  		}
   257  
   258  		retry := false
   259  		for _, pack := range packages {
   260  			err = conn.DeleteBandwidthPackage(&ecs.DeleteBandwidthPackageArgs{
   261  				RegionId:           getRegion(d, meta),
   262  				BandwidthPackageId: pack.BandwidthPackageId,
   263  			})
   264  
   265  			if err != nil {
   266  				er, _ := err.(*common.Error)
   267  				if er.ErrorResponse.Code == NatGatewayInvalidRegionId {
   268  					log.Printf("[ERROR] Delete bandwidth package is failed, bandwidthPackageId: %#v", pack.BandwidthPackageId)
   269  					return resource.NonRetryableError(err)
   270  				}
   271  				retry = true
   272  			}
   273  		}
   274  
   275  		if retry {
   276  			return resource.RetryableError(fmt.Errorf("Bandwidth package in use - trying again while it is deleted."))
   277  		}
   278  
   279  		args := &ecs.DeleteNatGatewayArgs{
   280  			RegionId:     getRegion(d, meta),
   281  			NatGatewayId: d.Id(),
   282  		}
   283  
   284  		err = conn.DeleteNatGateway(args)
   285  		if err != nil {
   286  			er, _ := err.(*common.Error)
   287  			if er.ErrorResponse.Code == DependencyViolationBandwidthPackages {
   288  				return resource.RetryableError(fmt.Errorf("NatGateway in use - trying again while it is deleted."))
   289  			}
   290  		}
   291  
   292  		describeArgs := &ecs.DescribeNatGatewaysArgs{
   293  			RegionId:     getRegion(d, meta),
   294  			NatGatewayId: d.Id(),
   295  		}
   296  		gw, _, gwErr := conn.DescribeNatGateways(describeArgs)
   297  
   298  		if gwErr != nil {
   299  			log.Printf("[ERROR] Describe NatGateways failed.")
   300  			return resource.NonRetryableError(gwErr)
   301  		} else if gw == nil || len(gw) < 1 {
   302  			return nil
   303  		}
   304  
   305  		return resource.RetryableError(fmt.Errorf("NatGateway in use - trying again while it is deleted."))
   306  	})
   307  }
   308  
   309  func flattenBandWidthPackages(bandWidthPackageIds []string, meta interface{}, d *schema.ResourceData) ([]map[string]interface{}, error) {
   310  
   311  	packageLen := len(bandWidthPackageIds)
   312  	result := make([]map[string]interface{}, 0, packageLen)
   313  
   314  	for i := packageLen - 1; i >= 0; i-- {
   315  		packageId := bandWidthPackageIds[i]
   316  		packages, err := getPackages(packageId, meta, d)
   317  		if err != nil {
   318  			log.Printf("[ERROR] NatGateways getPackages failed. packageId is %#v", packageId)
   319  			return result, err
   320  		}
   321  		ipAddress := flattenPackPublicIp(packages.PublicIpAddresses.PublicIpAddresse)
   322  		ipCont, ipContErr := strconv.Atoi(packages.IpCount)
   323  		bandWidth, bandWidthErr := strconv.Atoi(packages.Bandwidth)
   324  		if ipContErr != nil {
   325  			log.Printf("[ERROR] NatGateways getPackages failed: ipCont convert error. packageId is %#v", packageId)
   326  			return result, ipContErr
   327  		}
   328  		if bandWidthErr != nil {
   329  			log.Printf("[ERROR] NatGateways getPackages failed: bandWidthErr convert error. packageId is %#v", packageId)
   330  			return result, bandWidthErr
   331  		}
   332  		l := map[string]interface{}{
   333  			"ip_count":            ipCont,
   334  			"bandwidth":           bandWidth,
   335  			"zone":                packages.ZoneId,
   336  			"public_ip_addresses": ipAddress,
   337  		}
   338  		result = append(result, l)
   339  	}
   340  	return result, nil
   341  }
   342  
   343  func getPackages(packageId string, meta interface{}, d *schema.ResourceData) (*ecs.DescribeBandwidthPackageType, error) {
   344  	client := meta.(*AliyunClient)
   345  	conn := client.vpcconn
   346  	packages, err := conn.DescribeBandwidthPackages(&ecs.DescribeBandwidthPackagesArgs{
   347  		RegionId:           getRegion(d, meta),
   348  		BandwidthPackageId: packageId,
   349  	})
   350  
   351  	if err != nil {
   352  		log.Printf("[ERROR] Describe bandwidth package is failed, BandwidthPackageId Id: %s", packageId)
   353  		return nil, err
   354  	}
   355  
   356  	if len(packages) == 0 {
   357  		return nil, common.GetClientErrorFromString(InstanceNotfound)
   358  	}
   359  
   360  	return &packages[0], nil
   361  
   362  }
   363  
   364  func flattenPackPublicIp(publicIpAddressList []ecs.PublicIpAddresseType) string {
   365  	var result []string
   366  
   367  	for _, publicIpAddresses := range publicIpAddressList {
   368  		ipAddress := publicIpAddresses.IpAddress
   369  		result = append(result, ipAddress)
   370  	}
   371  
   372  	return strings.Join(result, ",")
   373  }