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