| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package hcso
- import (
- "fmt"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/errors"
- api "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/cloudmux/pkg/multicloud"
- "yunion.io/x/cloudmux/pkg/multicloud/huawei"
- )
- // date: 2019.07.15
- // In Huawei cloud, there are only two routing tables in a vpc, which are
- // self-defined routing tables and peer-to-peer routing tables.
- // The routing in these two tables is different, one's NextHop is a IP address and
- // the other one's NextHop address is a instance ID of peer-to-peer connection.
- // The former has no id and it's Type is ROUTE_TYPR_IP, and the latter's Type is ROUTE_TYPE_PEER.
- const (
- ROUTE_TYPR_IP = "IP"
- ROUTE_TYPE_PEER = "peering"
- )
- type SRouteEntry struct {
- multicloud.SResourceBase
- huawei.HuaweiTags
- routeTable *SRouteTable
- ID string // route ID
- Type string // route type
- Destination string // route destination
- NextHop string // route next hop (ip or id)
- }
- func (route *SRouteEntry) GetId() string {
- if len(route.ID) == 0 {
- return route.Destination + ":" + route.NextHop
- }
- return route.ID
- }
- func (route *SRouteEntry) GetName() string {
- return ""
- }
- func (route *SRouteEntry) GetGlobalId() string {
- return route.GetId()
- }
- func (route *SRouteEntry) GetStatus() string {
- return api.ROUTE_ENTRY_STATUS_AVAILIABLE
- }
- func (route *SRouteEntry) Refresh() error {
- return nil
- }
- func (route *SRouteEntry) IsEmulated() bool {
- return false
- }
- func (route *SRouteEntry) GetType() string {
- if route.Type == ROUTE_TYPE_PEER {
- return api.ROUTE_ENTRY_TYPE_CUSTOM
- }
- return api.ROUTE_ENTRY_TYPE_SYSTEM
- }
- func (route *SRouteEntry) GetCidr() string {
- return route.Destination
- }
- func (route *SRouteEntry) GetNextHopType() string {
- // In Huawei Cloud, NextHopType is same with itself
- switch route.Type {
- case ROUTE_TYPE_PEER:
- return api.NEXT_HOP_TYPE_VPCPEERING
- default:
- return ""
- }
- }
- func (route *SRouteEntry) GetNextHop() string {
- return route.NextHop
- }
- // SRouteTable has no ID and Name because there is no id or name of route table in huawei cloud.
- // And some method such as GetId and GetName of ICloudRouteTable has no practical meaning
- type SRouteTable struct {
- multicloud.SResourceBase
- huawei.HuaweiTags
- region *SRegion
- vpc *SVpc
- VpcId string
- Description string
- Type string
- Routes []*SRouteEntry
- }
- func NewSRouteTable(vpc *SVpc, Type string) SRouteTable {
- return SRouteTable{
- region: vpc.region,
- vpc: vpc,
- Type: Type,
- VpcId: vpc.GetId(),
- }
- }
- func (self *SRouteTable) GetId() string {
- return self.GetGlobalId()
- }
- func (self *SRouteTable) GetName() string {
- return ""
- }
- func (self *SRouteTable) GetGlobalId() string {
- return fmt.Sprintf("%s-%s", self.GetVpcId(), self.GetType())
- }
- func (self *SRouteTable) GetStatus() string {
- return api.ROUTE_TABLE_AVAILABLE
- }
- func (self *SRouteTable) Refresh() error {
- return nil
- }
- func (self *SRouteTable) IsEmulated() bool {
- return false
- }
- func (self *SRouteTable) GetDescription() string {
- return self.Description
- }
- func (self *SRouteTable) GetRegionId() string {
- return self.region.GetId()
- }
- func (self *SRouteTable) GetVpcId() string {
- return self.VpcId
- }
- func (self *SRouteTable) GetType() cloudprovider.RouteTableType {
- return cloudprovider.RouteTableTypeSystem
- }
- func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) {
- if self.Routes == nil {
- err := self.fetchRoutes()
- if err != nil {
- return nil, err
- }
- }
- ret := []cloudprovider.ICloudRoute{}
- for i := range self.Routes {
- ret = append(ret, self.Routes[i])
- }
- return ret, nil
- }
- // fetchRoutes fetch Routes
- func (self *SRouteTable) fetchRoutes() error {
- if self.Type == ROUTE_TYPR_IP {
- return self.fetchRoutesForIP()
- }
- return self.fetchRoutesForPeer()
- }
- // fetchRoutesForIP fetch the Routes which Type is ROUTE_TYPR_IP through vpc's get api
- func (self *SRouteTable) fetchRoutesForIP() error {
- ret, err := self.region.ecsClient.Vpcs.Get(self.GetVpcId(), map[string]string{})
- if err != nil {
- return errors.Wrap(err, "get vpc info error")
- }
- routeArray, err := ret.GetArray("routes")
- routes := make([]*SRouteEntry, 0, len(routeArray))
- for i := range routeArray {
- destination, err := routeArray[i].GetString("destination")
- if err != nil {
- return errors.Wrap(err, "get destination of route error")
- }
- nextHop, err := routeArray[i].GetString("nexthop")
- if err != nil {
- return errors.Wrap(err, "get nexthop of route error")
- }
- routes = append(routes, &SRouteEntry{
- routeTable: self,
- ID: "",
- Type: ROUTE_TYPR_IP,
- Destination: destination,
- NextHop: nextHop,
- })
- }
- self.Routes = routes
- return nil
- }
- // fetchRoutesForPeer fetch the routes which Type is ROUTE_TYPE_PEER through vpcRoute's list api
- func (self *SRouteTable) fetchRoutesForPeer() error {
- retPeer, err := self.region.ecsClient.VpcRoutes.List(map[string]string{"vpc_id": self.GetVpcId()})
- if err != nil {
- return errors.Wrap(err, "get peer route error")
- }
- routesPeer := make([]*SRouteEntry, 0, retPeer.Total)
- for i := range retPeer.Data {
- route := retPeer.Data[i]
- id, err := route.GetString("id")
- if err != nil {
- return errors.Wrap(err, "get id of peer route error")
- }
- destination, err := route.GetString("destination")
- if err != nil {
- return errors.Wrap(err, "get destination of peer route error")
- }
- nextHop, err := route.GetString("nexthop")
- if err != nil {
- return errors.Wrap(err, "get nexthop of peer route error")
- }
- routesPeer = append(routesPeer, &SRouteEntry{
- routeTable: self,
- ID: id,
- Type: ROUTE_TYPE_PEER,
- Destination: destination,
- NextHop: nextHop,
- })
- }
- self.Routes = routesPeer
- return nil
- }
- func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation {
- result := []cloudprovider.RouteTableAssociation{}
- return result
- }
- func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error {
- if route.NextHopType != api.NEXT_HOP_TYPE_VPCPEERING {
- return cloudprovider.ErrNotSupported
- }
- err := self.region.CreatePeeringRoute(self.vpc.GetId(), route.Destination, route.NextHop)
- if err != nil {
- return errors.Wrapf(err, " self.region.CreatePeeringRoute(%s,%s,%s)", self.vpc.GetId(), route.Destination, route.NextHop)
- }
- return nil
- }
- func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error {
- err := self.RemoveRoute(route)
- if err != nil {
- return errors.Wrap(err, "self.RemoveRoute(route)")
- }
- err = self.CreateRoute(route)
- if err != nil {
- return errors.Wrap(err, "self.CreateRoute(route)")
- }
- return nil
- }
- func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error {
- err := self.region.DeletePeeringRoute(route.RouteId)
- if err != nil {
- return errors.Wrapf(err, "self.region.DeletePeeringRoute(%s)", route.RouteId)
- }
- return nil
- }
- // GetRouteTables return []SRouteTable of self
- func (self *SVpc) getRouteTables() ([]SRouteTable, error) {
- // every Vpc has two route table in Huawei Cloud
- routeTableIp := NewSRouteTable(self, ROUTE_TYPR_IP)
- routeTablePeer := NewSRouteTable(self, ROUTE_TYPE_PEER)
- if err := routeTableIp.fetchRoutesForIP(); err != nil {
- return nil, errors.Wrap(err, `get route table whilc type is "ip" error`)
- }
- if err := routeTablePeer.fetchRoutesForPeer(); err != nil {
- return nil, errors.Wrap(err, `get route table whilc type is "peering" error`)
- }
- ret := make([]SRouteTable, 0, 2)
- if len(routeTableIp.Routes) != 0 {
- ret = append(ret, routeTableIp)
- }
- if len(routeTablePeer.Routes) != 0 {
- ret = append(ret, routeTablePeer)
- }
- return ret, nil
- }
- // GetRouteTables return []SRouteTable of vpc which id is vpcId if vpcId is no-nil,
- // otherwise return []SRouteTable of all vpc in this SRegion
- func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) {
- vpcs, err := self.GetVpcs()
- if err != nil {
- return nil, errors.Wrap(err, "Get Vpcs error")
- }
- if vpcId != "" {
- for i := range vpcs {
- if vpcs[i].GetId() == vpcId {
- vpcs = vpcs[i : i+1]
- break
- }
- }
- }
- ret := make([]SRouteTable, 0, 2*len(vpcs))
- for _, vpc := range vpcs {
- routetables, err := vpc.getRouteTables()
- if err != nil {
- return nil, errors.Wrapf(err, "get vpc's route tables whilch id is %s error", vpc.GetId())
- }
- ret = append(ret, routetables...)
- }
- return ret, nil
- }
- func (self *SRegion) CreatePeeringRoute(vpcId, destinationCidr, target string) error {
- params := jsonutils.NewDict()
- routeObj := jsonutils.NewDict()
- routeObj.Set("type", jsonutils.NewString("peering"))
- routeObj.Set("nexthop", jsonutils.NewString(target))
- routeObj.Set("destination", jsonutils.NewString(destinationCidr))
- routeObj.Set("vpc_id", jsonutils.NewString(vpcId))
- params.Set("route", routeObj)
- err := DoCreate(self.ecsClient.VpcRoutes.Create, params, nil)
- if err != nil {
- return errors.Wrapf(err, "DoCreate(self.ecsClient.VpcRoutes.Create, %s, &ret)", jsonutils.Marshal(params).String())
- }
- return nil
- }
- func (self *SRegion) DeletePeeringRoute(routeId string) error {
- err := DoDelete(self.ecsClient.VpcRoutes.Delete, routeId, nil, nil)
- if err != nil {
- return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcRoutes.Delete,%s,nil)", routeId)
- }
- return nil
- }
|