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 }