alicloud/resource_alicloud_route_entry.go (194 lines of code) (raw):

package alicloud import ( "strings" "time" "github.com/aliyun/alibaba-cloud-sdk-go/services/vpc" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAliyunRouteEntry() *schema.Resource { return &schema.Resource{ Create: resourceAliyunRouteEntryCreate, Read: resourceAliyunRouteEntryRead, Delete: resourceAliyunRouteEntryDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ "route_table_id": { Type: schema.TypeString, Required: true, ForceNew: true, }, "destination_cidrblock": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "nexthop_type": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "nexthop_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "name": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: StringLenBetween(2, 128), }, "description": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "router_id": { Type: schema.TypeString, Computed: true, Deprecated: "Attribute router_id has been deprecated and suggest removing it from your template.", }, }, } } func resourceAliyunRouteEntryCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) vpcService := VpcService{client} var cidr string rtId := d.Get("route_table_id").(string) nt := d.Get("nexthop_type").(string) ni := d.Get("nexthop_id").(string) table, err := vpcService.QueryRouteTableById(rtId) if err != nil { return WrapError(err) } request := vpc.CreateCreateRouteEntryRequest() request.RegionId = client.RegionId request.RouteTableId = rtId if v, ok := d.GetOk("destination_cidrblock"); ok && v.(string) != "" { cidr = v.(string) if strings.Contains(v.(string), ":") { cidr = strings.Replace(v.(string), ":", "_", -1) } request.DestinationCidrBlock = v.(string) } request.NextHopType = nt request.NextHopId = ni request.ClientToken = buildClientToken(request.GetActionName()) if v, ok := d.GetOk("name"); ok { request.RouteEntryName = v.(string) } if v, ok := d.GetOk("description"); ok { request.Description = v.(string) } // retry 10 min to create lots of entries concurrently err = resource.Retry(10*time.Minute, func() *resource.RetryError { if err := vpcService.WaitForAllRouteEntriesAvailable(rtId, DefaultTimeout); err != nil { return resource.NonRetryableError(err) } args := *request raw, err := client.WithVpcClient(func(vpcClient *vpc.Client) (interface{}, error) { return vpcClient.CreateRouteEntry(&args) }) if err != nil { // Route Entry does not support concurrence when creating or deleting it; // Route Entry does not support creating or deleting within 5 seconds frequently // It must ensure all the route entries, vpc, vswitches' status must be available before creating or deleting route entry. if IsExpectedErrors(err, []string{"TaskConflict", "OperationConflict", "IncorrectRouteEntryStatus", "IncorrectVpcStatus", "IncorrectVSwitchStatus", "IncorrectHaVipStatus", "IncorrectInstanceStatus", "InvalidVBRStatus", "IncorrectStatus.Ipv4Gateway", "IncorrectStatus.Ipv6Address", "LastTokenProcessing", "IncorrectStatus.VpcPeer", "IncorrectStatus.MultiScopeRiRouteEntry", "IncorrectStatus.RouteTableStatus", "OperationFailed.DistibuteLock", "ServiceUnavailable", "SystemBusy", "UnknownError", "IncorrectStatus.RouterInterface", "IncorrectStatus.PrefixList"}) || NeedRetry(err) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"RouterEntryConflict.Duplicated"}) { en, err := vpcService.DescribeRouteEntry(rtId + ":" + table.VRouterId + ":" + cidr + ":" + nt + ":" + ni) if err != nil { return WrapError(err) } return WrapError(Error("The route entry %s has already existed. "+ "Please import it using ID '%s:%s:%s:%s:%s' or specify a new 'destination_cidrblock' and try again.", en.DestinationCidrBlock, en.RouteTableId, table.VRouterId, en.DestinationCidrBlock, en.NextHopType, ni)) } return WrapErrorf(err, DefaultErrorMsg, "alicloud_route_entry", request.GetActionName(), AlibabaCloudSdkGoERROR) } // route_table_id:router_id:destination_cidrblock:nexthop_type:nexthop_id d.SetId(rtId + ":" + table.VRouterId + ":" + cidr + ":" + nt + ":" + ni) if err := vpcService.WaitForRouteEntry(d.Id(), Available, DefaultTimeout); err != nil { return WrapError(err) } return resourceAliyunRouteEntryRead(d, meta) } func resourceAliyunRouteEntryRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) vpcService := VpcService{client} parts, err := ParseResourceId(d.Id(), 5) if err != nil { return WrapError(err) } object, err := vpcService.DescribeRouteEntry(d.Id()) if err != nil { if NotFoundError(err) { d.SetId("") return nil } return WrapError(err) } d.Set("route_table_id", object.RouteTableId) d.Set("destination_cidrblock", object.DestinationCidrBlock) d.Set("nexthop_type", object.NextHopType) d.Set("nexthop_id", object.InstanceId) d.Set("name", object.RouteEntryName) d.Set("description", object.Description) d.Set("router_id", parts[1]) return nil } func resourceAliyunRouteEntryDelete(d *schema.ResourceData, meta interface{}) error { request, err := buildAliyunRouteEntryDeleteArgs(d, meta) if err != nil { return WrapError(err) } client := meta.(*connectivity.AliyunClient) request.RegionId = client.RegionId vpcService := VpcService{client} parts, err := ParseResourceId(d.Id(), 5) rtId := parts[0] if err := vpcService.WaitForAllRouteEntriesAvailable(rtId, DefaultTimeout); err != nil { return WrapError(err) } retryTimes := 7 err = resource.Retry(10*time.Minute, func() *resource.RetryError { raw, err := client.WithVpcClient(func(vpcClient *vpc.Client) (interface{}, error) { return vpcClient.DeleteRouteEntry(request) }) if err != nil { if IsExpectedErrors(err, []string{"IncorrectVpcStatus", "TaskConflict", "OperationConflict", "SystemBusy", "IncorrectRouteEntryStatus", "IncorrectInstanceStatus", "Forbbiden", "UnknownError", "InvalidVBRStatus", "LastTokenProcessing", "IncorrectStatus.Ipv6Address", "OperationFailed.DistibuteLock", "ServiceUnavailable", "IncorrectStatus.RouteTableStatus", "IncorrectStatus.MultiScopeRiRouteEntry", "IncorrectHaVipStatus", "IncorrectStatus.Ipv4Gateway", "IncorrectStatus.VpcPeer", "IncorrectStatus.PrefixList"}) || NeedRetry(err) { // Route Entry does not support creating or deleting within 5 seconds frequently time.Sleep(time.Duration(retryTimes) * time.Second) return resource.RetryableError(err) } return resource.NonRetryableError(err) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) return nil }) if err != nil { if IsExpectedErrors(err, []string{"InvalidRouteEntry.NotFound"}) { return nil } return WrapErrorf(err, DefaultErrorMsg, d.Id(), request.GetActionName(), AlibabaCloudSdkGoERROR) } return WrapError(vpcService.WaitForRouteEntry(d.Id(), Deleted, DefaultTimeout)) } func buildAliyunRouteEntryDeleteArgs(d *schema.ResourceData, meta interface{}) (*vpc.DeleteRouteEntryRequest, error) { request := vpc.CreateDeleteRouteEntryRequest() request.RouteTableId = d.Get("route_table_id").(string) request.DestinationCidrBlock = d.Get("destination_cidrblock").(string) if v := d.Get("destination_cidrblock").(string); v != "" { request.DestinationCidrBlock = v } if v := d.Get("nexthop_id").(string); v != "" { request.NextHopId = v } return request, nil }