alicloud/resource_alicloud_vpc_route_entry.go (476 lines of code) (raw):
package alicloud
import (
"encoding/json"
"fmt"
"log"
"strings"
"time"
"github.com/PaesslerAG/jsonpath"
"github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/tidwall/sjson"
)
func resourceAliCloudVpcRouteEntry() *schema.Resource {
return &schema.Resource{
Create: resourceAliCloudVpcRouteEntryCreate,
Read: resourceAliCloudVpcRouteEntryRead,
Update: resourceAliCloudVpcRouteEntryUpdate,
Delete: resourceAliCloudVpcRouteEntryDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},
Schema: map[string]*schema.Schema{
"description": {
Type: schema.TypeString,
Optional: true,
},
"destination_cidr_block": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"nexthop_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"nexthop_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: StringInSlice([]string{"HaVip", "RouterInterface", "NetworkInterface", "VpnGateway", "IPv6Gateway", "NatGateway", "Attachment", "VpcPeer", "Ipv4Gateway", "GatewayEndpoint", "Ecr", "GatewayLoadBalancerEndpoint", "Instance"}, false),
},
"next_hops": {
Type: schema.TypeList,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"nexthop_type": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"next_hop_region_id": {
Type: schema.TypeString,
Computed: true,
},
"nexthop_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"enabled": {
Type: schema.TypeInt,
Computed: true,
},
"next_hop_related_info": {
Type: schema.TypeList,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"instance_id": {
Type: schema.TypeString,
Computed: true,
},
"region_id": {
Type: schema.TypeString,
Computed: true,
},
"instance_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"weight": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
},
},
},
},
"route_entry_name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"route_publish_targets": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"target_type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: StringInSlice([]string{"ECR"}, false),
},
"target_instance_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"publish_status": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"route_table_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceAliCloudVpcRouteEntryCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AliyunClient)
action := "CreateRouteEntry"
var request map[string]interface{}
var response map[string]interface{}
query := make(map[string]interface{})
var err error
request = make(map[string]interface{})
if v, ok := d.GetOk("route_table_id"); ok {
request["RouteTableId"] = v
}
if v, ok := d.GetOk("destination_cidr_block"); ok {
request["DestinationCidrBlock"] = v
}
request["RegionId"] = client.RegionId
request["ClientToken"] = buildClientToken(action)
if v, ok := d.GetOk("name"); ok || d.HasChange("name") {
request["RouteEntryName"] = v
}
if v, ok := d.GetOk("route_entry_name"); ok {
request["RouteEntryName"] = v
}
if v, ok := d.GetOk("description"); ok {
request["Description"] = v
}
if v, ok := d.GetOk("next_hops"); ok {
nextHopListMapsArray := make([]interface{}, 0)
for _, dataLoop := range v.([]interface{}) {
dataLoopTmp := dataLoop.(map[string]interface{})
dataLoopMap := make(map[string]interface{})
dataLoopMap["NextHopId"] = dataLoopTmp["nexthop_id"]
dataLoopMap["Weight"] = dataLoopTmp["weight"]
dataLoopMap["NextHopType"] = dataLoopTmp["nexthop_type"]
nextHopListMapsArray = append(nextHopListMapsArray, dataLoopMap)
}
request["NextHopList"] = nextHopListMapsArray
}
if v, ok := d.GetOk("nexthop_id"); ok {
request["NextHopId"] = v
}
if v, ok := d.GetOk("nexthop_type"); ok {
request["NextHopType"] = v
}
wait := incrementalWait(3*time.Second, 5*time.Second)
err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError {
response, err = client.RpcPost("Vpc", "2016-04-28", action, query, request, true)
if err != nil {
if IsExpectedErrors(err, []string{"IncorrectInstanceStatus", "IncorrectRouteEntryStatus", "SystemBusy", "InvalidVBRStatus", "LastTokenProcessing", "IncorrectStatus.Ipv6Address", "IncorrectStatus", "OperationFailed.DistibuteLock", "ServiceUnavailable", "IncorrectStatus.RouteTableStatus", "IncorrectStatus.MultiScopeRiRouteEntry", "IncorrectVpcStatus", "IncorrectHaVipStatus", "OperationConflict", "TaskConflict", "IncorrectStatus.Ipv4Gateway", "IncorrectStatus.VpcPeer", "IncorrectVSwitchStatus"}) || NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, "alicloud_vpc_route_entry", action, AlibabaCloudSdkGoERROR)
}
d.SetId(fmt.Sprintf("%v:%v", request["RouteTableId"], request["DestinationCidrBlock"]))
return resourceAliCloudVpcRouteEntryUpdate(d, meta)
}
func resourceAliCloudVpcRouteEntryRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AliyunClient)
vpcServiceV2 := VpcServiceV2{client}
objectRaw, err := vpcServiceV2.DescribeVpcRouteEntry(d.Id())
if err != nil {
if !d.IsNewResource() && NotFoundError(err) {
log.Printf("[DEBUG] Resource alicloud_vpc_route_entry DescribeVpcRouteEntry Failed!!! %s", err)
d.SetId("")
return nil
}
return WrapError(err)
}
d.Set("description", objectRaw["Description"])
d.Set("route_entry_name", objectRaw["RouteEntryName"])
d.Set("status", objectRaw["Status"])
d.Set("destination_cidr_block", objectRaw["DestinationCidrBlock"])
d.Set("route_table_id", objectRaw["RouteTableId"])
nextHopsRaw, _ := jsonpath.Get("$.NextHops.NextHop[0]", objectRaw)
d.Set("nexthop_id", nextHopsRaw.(map[string]interface{})["NextHopId"])
d.Set("nexthop_type", nextHopsRaw.(map[string]interface{})["NextHopType"])
nextHopRaw, _ := jsonpath.Get("$.NextHops.NextHop", objectRaw)
nextHopsMaps := make([]map[string]interface{}, 0)
if nextHopRaw != nil {
for _, nextHopChildRaw := range nextHopRaw.([]interface{}) {
nextHopsMap := make(map[string]interface{})
nextHopChildRaw := nextHopChildRaw.(map[string]interface{})
nextHopsMap["enabled"] = nextHopChildRaw["Enabled"]
nextHopsMap["nexthop_id"] = nextHopChildRaw["NextHopId"]
nextHopsMap["next_hop_region_id"] = nextHopChildRaw["NextHopRegionId"]
nextHopsMap["nexthop_type"] = nextHopChildRaw["NextHopType"]
nextHopsMap["weight"] = nextHopChildRaw["Weight"]
nextHopRelatedInfoMaps := make([]map[string]interface{}, 0)
nextHopRelatedInfoMap := make(map[string]interface{})
nextHopRelatedInfoRawObj, _ := jsonpath.Get("$.NextHopRelatedInfo", nextHopChildRaw)
nextHopRelatedInfoRaw := make(map[string]interface{})
if nextHopRelatedInfoRawObj != nil {
nextHopRelatedInfoRaw = nextHopRelatedInfoRawObj.(map[string]interface{})
}
if len(nextHopRelatedInfoRaw) > 0 {
nextHopRelatedInfoMap["instance_id"] = nextHopRelatedInfoRaw["InstanceId"]
nextHopRelatedInfoMap["instance_type"] = nextHopRelatedInfoRaw["InstanceType"]
nextHopRelatedInfoMap["region_id"] = nextHopRelatedInfoRaw["RegionId"]
nextHopRelatedInfoMaps = append(nextHopRelatedInfoMaps, nextHopRelatedInfoMap)
}
nextHopsMap["next_hop_related_info"] = nextHopRelatedInfoMaps
nextHopsMaps = append(nextHopsMaps, nextHopsMap)
}
}
if err := d.Set("next_hops", nextHopsMaps); err != nil {
return err
}
objectRaw, err = vpcServiceV2.DescribeRouteEntryListVpcPublishedRouteEntries(d.Id())
if err != nil && !NotFoundError(err) {
if !IsExpectedErrors(err, []string{"ResourceNotAssociated.TargetInstance"}) {
return WrapError(err)
}
objectRaw = make(map[string]interface{})
}
routePublishTargetsRaw, _ := jsonpath.Get("$.RoutePublishTargets", objectRaw)
routePublishTargetsMaps := make([]map[string]interface{}, 0)
if routePublishTargetsRaw != nil {
for _, routePublishTargetsChildRaw := range routePublishTargetsRaw.([]interface{}) {
routePublishTargetsMap := make(map[string]interface{})
routePublishTargetsChildRaw := routePublishTargetsChildRaw.(map[string]interface{})
if routePublishTargetsChildRaw["PublishStatus"] == "NonPublished" {
continue
}
routePublishTargetsMap["publish_status"] = routePublishTargetsChildRaw["PublishStatus"]
routePublishTargetsMap["target_instance_id"] = routePublishTargetsChildRaw["PublishTargetInstanceId"]
routePublishTargetsMap["target_type"] = routePublishTargetsChildRaw["PublishTargetType"]
routePublishTargetsMaps = append(routePublishTargetsMaps, routePublishTargetsMap)
}
}
if err := d.Set("route_publish_targets", routePublishTargetsMaps); err != nil {
return err
}
d.Set("name", d.Get("route_entry_name"))
return nil
}
func resourceAliCloudVpcRouteEntryUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AliyunClient)
var request map[string]interface{}
var response map[string]interface{}
var query map[string]interface{}
update := false
var err error
parts := strings.Split(d.Id(), ":")
action := "ModifyRouteEntry"
request = make(map[string]interface{})
query = make(map[string]interface{})
request["DestinationCidrBlock"] = parts[1]
request["RouteTableId"] = parts[0]
request["RegionId"] = client.RegionId
if !d.IsNewResource() && d.HasChange("name") {
update = true
request["RouteEntryName"] = d.Get("name")
}
if !d.IsNewResource() && d.HasChange("route_entry_name") {
update = true
request["RouteEntryName"] = d.Get("route_entry_name")
}
if !d.IsNewResource() && d.HasChange("description") {
update = true
request["Description"] = d.Get("description")
}
if !d.IsNewResource() && d.HasChange("nexthop_id") {
update = true
request["NewNextHopId"] = d.Get("nexthop_id")
}
if !d.IsNewResource() && d.HasChange("nexthop_type") {
update = true
request["NewNextHopType"] = d.Get("nexthop_type")
}
if update {
wait := incrementalWait(3*time.Second, 5*time.Second)
err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError {
response, err = client.RpcPost("Vpc", "2016-04-28", action, query, request, true)
if err != nil {
if IsExpectedErrors(err, []string{"IncorrectInstanceStatus", "IncorrectRouteEntryStatus", "SystemBusy", "InvalidVBRStatus", "LastTokenProcessing", "IncorrectStatus.Ipv6Address", "IncorrectStatus", "OperationFailed.DistibuteLock", "ServiceUnavailable", "IncorrectStatus.RouteTableStatus", "IncorrectStatus.MultiScopeRiRouteEntry", "IncorrectVpcStatus", "IncorrectHaVipStatus", "OperationConflict", "TaskConflict", "IncorrectStatus.Ipv4Gateway", "IncorrectStatus.VpcPeer"}) || NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR)
}
}
if d.HasChange("route_publish_targets") {
oldEntry, newEntry := d.GetChange("route_publish_targets")
removed := oldEntry
added := newEntry
if len(removed.([]interface{})) > 0 {
routePublishTargets := removed.([]interface{})
for _, item := range routePublishTargets {
parts := strings.Split(d.Id(), ":")
action := "WithdrawVpcPublishedRouteEntries"
request = make(map[string]interface{})
query = make(map[string]interface{})
request["RegionId"] = client.RegionId
jsonPathResult, err := jsonpath.Get("$.target_type", item)
if err == nil {
request["TargetType"] = jsonPathResult
}
jsonPathResult1, err := jsonpath.Get("$.target_instance_id", item)
if err == nil {
request["TargetInstanceId"] = jsonPathResult1
}
jsonString := convertObjectToJsonString(request)
jsonString, _ = sjson.Set(jsonString, "RouteEntries.0.RouteTableId", parts[0])
jsonString, _ = sjson.Set(jsonString, "RouteEntries.0.DestinationCidrBlock", parts[1])
_ = json.Unmarshal([]byte(jsonString), &request)
wait := incrementalWait(3*time.Second, 5*time.Second)
err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError {
response, err = client.RpcPost("Vpc", "2016-04-28", action, query, request, true)
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR)
}
}
}
if len(added.([]interface{})) > 0 {
routePublishTargets := added.([]interface{})
for _, item := range routePublishTargets {
parts := strings.Split(d.Id(), ":")
action := "PublishVpcRouteEntries"
request = make(map[string]interface{})
query = make(map[string]interface{})
request["RegionId"] = client.RegionId
jsonPathResult, err := jsonpath.Get("$.target_type", item)
if err == nil {
request["TargetType"] = jsonPathResult
}
jsonPathResult1, err := jsonpath.Get("$.target_instance_id", item)
if err == nil {
request["TargetInstanceId"] = jsonPathResult1
}
jsonString := convertObjectToJsonString(request)
jsonString, _ = sjson.Set(jsonString, "RouteEntries.0.RouteTableId", parts[0])
jsonString, _ = sjson.Set(jsonString, "RouteEntries.0.DestinationCidrBlock", parts[1])
_ = json.Unmarshal([]byte(jsonString), &request)
wait := incrementalWait(3*time.Second, 5*time.Second)
err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError {
response, err = client.RpcPost("Vpc", "2016-04-28", action, query, request, true)
if err != nil {
if NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR)
}
}
}
}
return resourceAliCloudVpcRouteEntryRead(d, meta)
}
func resourceAliCloudVpcRouteEntryDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AliyunClient)
parts := strings.Split(d.Id(), ":")
action := "DeleteRouteEntry"
var request map[string]interface{}
var response map[string]interface{}
query := make(map[string]interface{})
var err error
request = make(map[string]interface{})
request["RouteTableId"] = parts[0]
request["DestinationCidrBlock"] = parts[1]
request["RegionId"] = client.RegionId
if v, ok := d.GetOk("next_hops"); !ok || len(v.([]interface{})) == 1 {
if v, ok := d.GetOk("route_entry_id"); ok {
request["RouteEntryId"] = v
}
if v, ok := d.GetOk("nexthop_id"); ok {
request["NextHopId"] = v
}
}
if v, ok := d.GetOk("next_hops"); ok && len(v.([]interface{})) > 1 {
nextHopListMapsArray := make([]interface{}, 0)
for _, dataLoop := range v.([]interface{}) {
dataLoopTmp := dataLoop.(map[string]interface{})
dataLoopMap := make(map[string]interface{})
dataLoopMap["NextHopId"] = dataLoopTmp["nexthop_id"]
dataLoopMap["NextHopType"] = dataLoopTmp["nexthop_type"]
nextHopListMapsArray = append(nextHopListMapsArray, dataLoopMap)
}
request["NextHopList"] = nextHopListMapsArray
}
wait := incrementalWait(3*time.Second, 5*time.Second)
err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError {
response, err = client.RpcPost("Vpc", "2016-04-28", action, query, request, true)
if err != nil {
if IsExpectedErrors(err, []string{"IncorrectInstanceStatus", "IncorrectRouteEntryStatus", "SystemBusy", "InvalidVBRStatus", "LastTokenProcessing", "IncorrectStatus.Ipv6Address", "IncorrectStatus", "OperationFailed.DistibuteLock", "ServiceUnavailable", "IncorrectStatus.RouteTableStatus", "IncorrectStatus.MultiScopeRiRouteEntry", "IncorrectVpcStatus", "IncorrectHaVipStatus", "OperationConflict", "TaskConflict", "IncorrectStatus.Ipv4Gateway", "IncorrectStatus.VpcPeer", "IncorrectStatus.PrefixList"}) || NeedRetry(err) {
wait()
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
addDebug(action, response, request)
if err != nil {
if NotFoundError(err) {
return nil
}
return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR)
}
vpcServiceV2 := VpcServiceV2{client}
stateConf := BuildStateConf([]string{}, []string{}, d.Timeout(schema.TimeoutDelete), 5*time.Second, vpcServiceV2.VpcRouteEntryStateRefreshFunc(d.Id(), "Status", []string{}))
if _, err := stateConf.WaitForState(); err != nil {
return WrapErrorf(err, IdMsg, d.Id())
}
return nil
}