yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/routetable.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package aliyun
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"yunion.io/x/log"
    23  
    24  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    25  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    26  	"yunion.io/x/cloudmux/pkg/multicloud"
    27  )
    28  
    29  // {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"}
    30  
    31  type SNextHops struct {
    32  	NextHop []string
    33  }
    34  
    35  type SRouteEntry struct {
    36  	multicloud.SResourceBase
    37  	AliyunTags
    38  	routeTable *SRouteTable
    39  
    40  	RouteTableId         string
    41  	Type                 string
    42  	DestinationCidrBlock string
    43  	NextHopType          string
    44  	InstanceId           string
    45  	RouteEntryId         string
    46  	RouteEntryName       string
    47  	NextHops             SNextHops
    48  }
    49  
    50  func (route *SRouteEntry) GetId() string {
    51  	return fmt.Sprintf("%s-%s-%s", route.RouteTableId, route.DestinationCidrBlock, route.NextHopType)
    52  }
    53  
    54  func (route *SRouteEntry) GetName() string {
    55  	return route.RouteEntryName
    56  }
    57  
    58  func (route *SRouteEntry) GetGlobalId() string {
    59  	return route.GetId()
    60  }
    61  
    62  func (route *SRouteEntry) GetStatus() string {
    63  	return api.ROUTE_ENTRY_STATUS_AVAILIABLE
    64  }
    65  
    66  func (route *SRouteEntry) Refresh() error {
    67  	return nil
    68  }
    69  
    70  func (route *SRouteEntry) IsEmulated() bool {
    71  	return false
    72  }
    73  
    74  // Custom:自定义路由。 System:系统路由。
    75  func (route *SRouteEntry) GetType() string {
    76  	return route.Type
    77  }
    78  
    79  func (route *SRouteEntry) GetCidr() string {
    80  	return route.DestinationCidrBlock
    81  }
    82  
    83  func (route *SRouteEntry) GetNextHopType() string {
    84  	switch route.NextHopType {
    85  	case "Instance":
    86  		return api.NEXT_HOP_TYPE_INSTANCE
    87  	case "HaVip":
    88  		return api.NEXT_HOP_TYPE_HAVIP
    89  	case "VpnGateway":
    90  		return api.NEXT_HOP_TYPE_VPN
    91  	case "NatGateway":
    92  		return api.NEXT_HOP_TYPE_NAT
    93  	case "NetworkInterface":
    94  		return api.NEXT_HOP_TYPE_NETWORK
    95  	case "RouterInterface":
    96  		return api.NEXT_HOP_TYPE_ROUTER
    97  	case "IPv6Gateway":
    98  		return api.NEXT_HOP_TYPE_IPV6
    99  	case "InternetGateway":
   100  		return api.NEXT_HOP_TYPE_INTERNET
   101  	case "Next_HOP_TYPE_EGRESS_INTERNET":
   102  		return api.NEXT_HOP_TYPE_EGRESS_INTERNET
   103  	default:
   104  		return ""
   105  	}
   106  }
   107  
   108  func (route *SRouteEntry) GetNextHop() string {
   109  	return route.InstanceId
   110  }
   111  
   112  type SRouteEntrys struct {
   113  	RouteEntry []*SRouteEntry
   114  }
   115  
   116  type SRouteTable struct {
   117  	multicloud.SResourceBase
   118  	AliyunTags
   119  	region *SRegion
   120  	vpc    *SVpc
   121  	routes []cloudprovider.ICloudRoute
   122  
   123  	VpcId        string
   124  	CreationTime time.Time
   125  	RouteEntrys  SRouteEntrys
   126  	VRouterId    string
   127  	Description  string
   128  
   129  	RouteTableId   string
   130  	RouteTableName string
   131  	RouteTableType string
   132  	RouterId       string
   133  	RouterType     string
   134  	VSwitchIds     SRouteTableVSwitchIds
   135  }
   136  
   137  type SRouteTableVSwitchIds struct {
   138  	VSwitchId []string
   139  }
   140  
   141  type sDescribeRouteTablesResponseRouteTables struct {
   142  	RouteTable []SRouteTable
   143  }
   144  
   145  type sDescribeRouteTablesResponse struct {
   146  	RouteTables sDescribeRouteTablesResponseRouteTables
   147  	TotalCount  int
   148  }
   149  
   150  func (self *SRouteTable) GetDescription() string {
   151  	return self.Description
   152  }
   153  
   154  func (self *SRouteTable) GetId() string {
   155  	return self.RouteTableId
   156  }
   157  
   158  func (self *SRouteTable) GetGlobalId() string {
   159  	return self.RouteTableId
   160  }
   161  
   162  func (self *SRouteTable) GetName() string {
   163  	return self.RouteTableName
   164  }
   165  
   166  func (self *SRouteTable) GetRegionId() string {
   167  	return self.region.RegionId
   168  }
   169  
   170  // VRouter:VPC路由器。 VBR:边界路由器。
   171  func (self *SRouteTable) GetType() cloudprovider.RouteTableType {
   172  	switch self.RouteTableType {
   173  	case "System":
   174  		return cloudprovider.RouteTableTypeSystem
   175  	case "Custom":
   176  		return cloudprovider.RouteTableTypeCustom
   177  	default:
   178  		return cloudprovider.RouteTableTypeSystem
   179  	}
   180  }
   181  
   182  func (self *SRouteTable) GetVpcId() string {
   183  	return self.VpcId
   184  }
   185  
   186  func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) {
   187  	if self.routes == nil {
   188  		err := self.fetchRoutes()
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  	}
   193  	return self.routes, nil
   194  }
   195  
   196  func (self *SRouteTable) GetStatus() string {
   197  	return api.ROUTE_TABLE_AVAILABLE
   198  }
   199  
   200  func (self *SRouteTable) IsEmulated() bool {
   201  	return false
   202  }
   203  
   204  func (self *SRouteTable) Refresh() error {
   205  	return nil
   206  }
   207  
   208  func (self *SRouteTable) fetchRoutes() error {
   209  	routes := []*SRouteEntry{}
   210  	for {
   211  		parts, total, err := self.RemoteGetRoutes(len(routes), 50)
   212  		if err != nil {
   213  			return err
   214  		}
   215  		routes = append(routes, parts...)
   216  		if len(routes) >= total {
   217  			break
   218  		}
   219  	}
   220  	self.routes = make([]cloudprovider.ICloudRoute, len(routes))
   221  	for i := 0; i < len(routes); i++ {
   222  		routes[i].routeTable = self
   223  		self.routes[i] = routes[i]
   224  	}
   225  	return nil
   226  }
   227  
   228  func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) {
   229  	if limit > 50 || limit <= 0 {
   230  		limit = 50
   231  	}
   232  	params := make(map[string]string)
   233  	params["RouteTableId"] = self.RouteTableId
   234  	params["PageSize"] = fmt.Sprintf("%d", limit)
   235  	params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
   236  
   237  	body, err := self.region.ecsRequest("DescribeRouteTables", params)
   238  	if err != nil {
   239  		log.Errorf("RemoteGetRoutes fail %s", err)
   240  		return nil, 0, err
   241  	}
   242  
   243  	resp := sDescribeRouteTablesResponse{}
   244  	err = body.Unmarshal(&resp)
   245  	if err != nil {
   246  		log.Errorf("Unmarshal routeEntrys fail %s", err)
   247  		return nil, 0, err
   248  	}
   249  	routeTables := resp.RouteTables.RouteTable
   250  	if len(routeTables) != 1 {
   251  		return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables))
   252  	}
   253  	routeTable := routeTables[0]
   254  	return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil
   255  }
   256  
   257  func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation {
   258  	result := []cloudprovider.RouteTableAssociation{}
   259  	switch self.RouterType {
   260  	case "VRouter":
   261  		for i := range self.VSwitchIds.VSwitchId {
   262  			association := cloudprovider.RouteTableAssociation{
   263  				AssociationId:        self.RouteTableId + ":" + self.VSwitchIds.VSwitchId[i],
   264  				AssociationType:      cloudprovider.RouteTableAssociaToSubnet,
   265  				AssociatedResourceId: self.VSwitchIds.VSwitchId[i],
   266  			}
   267  			result = append(result, association)
   268  		}
   269  	case "VBR":
   270  		association := cloudprovider.RouteTableAssociation{
   271  			AssociationId:        self.RouteTableId + ":" + self.RouterId,
   272  			AssociationType:      cloudprovider.RouteTableAssociaToRouter,
   273  			AssociatedResourceId: self.RouterId,
   274  		}
   275  		result = append(result, association)
   276  	}
   277  
   278  	return result
   279  }
   280  
   281  func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error {
   282  	return cloudprovider.ErrNotSupported
   283  }
   284  
   285  func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error {
   286  	return cloudprovider.ErrNotSupported
   287  }
   288  
   289  func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error {
   290  	return cloudprovider.ErrNotSupported
   291  }
   292  
   293  func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) {
   294  	if limit > 50 || limit <= 0 {
   295  		limit = 50
   296  	}
   297  	params := make(map[string]string)
   298  	params["VpcId"] = self.VpcId
   299  	params["PageSize"] = fmt.Sprintf("%d", limit)
   300  	params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
   301  
   302  	body, err := self.region.vpcRequest("DescribeRouteTableList", params)
   303  	if err != nil {
   304  		log.Errorf("RemoteGetRouteTableList fail %s", err)
   305  		return nil, 0, err
   306  	}
   307  
   308  	routeTables := make([]*SRouteTable, 0)
   309  	err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType")
   310  	if err != nil {
   311  		log.Errorf("Unmarshal routeTables fail %s", err)
   312  		return nil, 0, err
   313  	}
   314  	for _, routeTable := range routeTables {
   315  		routeTable.region = self.region
   316  	}
   317  	total, _ := body.Int("TotalCount")
   318  	return routeTables, int(total), nil
   319  }
   320  
   321  func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error {
   322  	params := make(map[string]string)
   323  	params["RegionId"] = region.RegionId
   324  	params["RouteTableId"] = rtableId
   325  	params["VSwitchId"] = vswitchId
   326  	_, err := region.vpcRequest("AssociateRouteTable", params)
   327  	return err
   328  }
   329  
   330  func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error {
   331  	params := make(map[string]string)
   332  	params["RegionId"] = region.RegionId
   333  	params["RouteTableId"] = rtableId
   334  	params["VSwitchId"] = vswitchId
   335  	_, err := region.vpcRequest("UnassociateRouteTable", params)
   336  	return err
   337  }
   338  
   339  func (routeTable *SRouteTable) IsSystem() bool {
   340  	return strings.ToLower(routeTable.RouteTableType) == "system"
   341  }