From 456932632219ad081d9dac910d579e15969a5377 Mon Sep 17 00:00:00 2001 From: lvyangyang Date: Fri, 6 Nov 2020 10:34:18 +0800 Subject: [PATCH] add:qcloud routetable --- pkg/apis/compute/routetable_routesets.go | 23 +- pkg/multicloud/qcloud/route_table.go | 248 +++++++++++++++++++++ pkg/multicloud/qcloud/shell/route_table.go | 48 ++++ pkg/multicloud/qcloud/vpc.go | 21 +- 4 files changed, 329 insertions(+), 11 deletions(-) create mode 100644 pkg/multicloud/qcloud/route_table.go create mode 100644 pkg/multicloud/qcloud/shell/route_table.go diff --git a/pkg/apis/compute/routetable_routesets.go b/pkg/apis/compute/routetable_routesets.go index cd62c80615..98c6225464 100644 --- a/pkg/apis/compute/routetable_routesets.go +++ b/pkg/apis/compute/routetable_routesets.go @@ -23,16 +23,19 @@ const ( ) const ( - Next_HOP_TYPE_INSTANCE = "Instance" // ECS实例。 - Next_HOP_TYPE_HAVIP = "HaVip" // 高可用虚拟IP。 - Next_HOP_TYPE_VPN = "VpnGateway" // VPN网关。 - Next_HOP_TYPE_NAT = "NatGateway" // NAT网关。 - Next_HOP_TYPE_NETWORK = "NetworkInterface" // 辅助弹性网卡。 - Next_HOP_TYPE_ROUTER = "RouterInterface" // 路由器接口。 - Next_HOP_TYPE_IPV6 = "IPv6Gateway" // IPv6网关。 - Next_HOP_TYPE_INTERNET = "InternetGateway" // Internet网关。 - Next_HOP_TYPE_EGRESS_INTERNET = "EgressInternetGateway" // egress only Internet网关。 - Next_HOP_TYPE_VPCPEERING = "VpcPeering" // vpc对等连接 + Next_HOP_TYPE_INSTANCE = "Instance" // ECS实例。 + Next_HOP_TYPE_HAVIP = "HaVip" // 高可用虚拟IP。 + Next_HOP_TYPE_VPN = "VpnGateway" // VPN网关。 + Next_HOP_TYPE_NAT = "NatGateway" // NAT网关。 + Next_HOP_TYPE_NETWORK = "NetworkInterface" // 辅助弹性网卡。 + Next_HOP_TYPE_EIP = "Eip" // 弹性IP + Next_HOP_TYPE_ROUTER = "RouterInterface" // 路由器接口。 + Next_HOP_TYPE_IPV6 = "IPv6Gateway" // IPv6网关。 + Next_HOP_TYPE_INTERNET = "InternetGateway" // Internet网关。 + Next_HOP_TYPE_EGRESS_INTERNET = "EgressInternetGateway" // egress only Internet网关。 + Next_HOP_TYPE_VPCPEERING = "VpcPeering" // vpc对等连接 + Next_HOP_TYPE_INTERVPCNETWORK = "InterVpcNetwork" //vpc 互联网络 + Next_HOP_TYPE_DIRECTCONNECTION = "DirectConnection" //专线 ) const ( diff --git a/pkg/multicloud/qcloud/route_table.go b/pkg/multicloud/qcloud/route_table.go new file mode 100644 index 0000000000..989feaf7db --- /dev/null +++ b/pkg/multicloud/qcloud/route_table.go @@ -0,0 +1,248 @@ +// 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 qcloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SRouteSet struct { + RouteID int `json:"RouteId"` + RouteItemID string `json:"RouteItemId"` + DestinationIpv6CidrBlock string `json:"DestinationIpv6CidrBlock,omitempty"` + GatewayType string `json:"GatewayType"` + GatewayID string `json:"GatewayId"` + RouteDescription string `json:"RouteDescription"` + DestinationCidrBlock string `json:"DestinationCidrBlock,omitempty"` + RouteType string `json:"RouteType"` +} +type SRouteTableSet struct { + vpc *SVpc + VpcID string `json:"VpcId"` + RouteTableID string `json:"RouteTableId"` + RouteTableName string `json:"RouteTableName"` + AssociationSet []RouteTableAssociationSet `json:"AssociationSet"` + RouteSet []SRouteSet `json:"RouteSet"` + Main bool `json:"Main"` + CreatedTime string `json:"CreatedTime"` +} + +type RouteTableAssociationSet struct { + SubnetId string + RouteTableId string +} + +func (self *SRegion) DescribeRouteTables(vpcId string, routetables []string, offset int, limit int) ([]SRouteTableSet, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + for i := range routetables { + params[fmt.Sprintf("RouteTableIds.%d", i)] = routetables[i] + } + + if len(vpcId) > 0 { + params["Filters.0.Name"] = "vpc-id" + params["Filters.0.Values.0"] = vpcId + } + body, err := self.vpcRequest("DescribeRouteTables", params) + if err != nil { + return nil, 0, errors.Wrapf(err, ` self.vpcRequest("DescribeRouteTables", %s)`, jsonutils.Marshal(params)) + } + routeTables := make([]SRouteTableSet, 0) + err = body.Unmarshal(&routeTables, "RouteTableSet") + if err != nil { + return nil, 0, errors.Wrapf(err, "body.Unmarshal(RouteTableSet)[%s]", body.String()) + } + total, _ := body.Float("TotalCount") + return routeTables, int(total), nil +} + +func (self *SRegion) GetAllRouteTables(vpcId string, routetables []string) ([]SRouteTableSet, error) { + routeTables := make([]SRouteTableSet, 0) + for { + part, total, err := self.DescribeRouteTables(vpcId, routetables, len(routeTables), 50) + if err != nil { + return nil, errors.Wrap(err, "self.DescribeRouteTables(vpcId, routetables, offset, limit)") + } + routeTables = append(routeTables, part...) + if len(routeTables) >= total { + break + } + } + return routeTables, nil +} + +func (self *SRouteTableSet) GetId() string { + return self.RouteTableID +} + +func (self *SRouteTableSet) GetName() string { + return self.RouteTableName +} + +func (self *SRouteTableSet) GetGlobalId() string { + return self.RouteTableID +} + +func (self *SRouteTableSet) GetStatus() string { + return "" +} + +func (self *SRouteTableSet) Refresh() error { + return nil +} + +func (self *SRouteTableSet) IsEmulated() bool { + return false +} + +func (self *SRouteTableSet) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SRouteTableSet) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + for i := range self.AssociationSet { + association := cloudprovider.RouteTableAssociation{ + AssociationType: cloudprovider.RouteTableAssociaToSubnet, + AssociatedResourceId: self.AssociationSet[i].SubnetId, + } + result = append(result, association) + } + return result +} + +func (self *SRouteTableSet) GetDescription() string { + return "" +} + +func (self *SRouteTableSet) GetRegionId() string { + return self.vpc.GetRegion().GetId() +} + +func (self *SRouteTableSet) GetVpcId() string { + return self.vpc.GetId() +} + +func (self *SRouteTableSet) GetType() cloudprovider.RouteTableType { + if self.Main { + return cloudprovider.RouteTableTypeSystem + } + return cloudprovider.RouteTableTypeCustom +} + +func (self *SRouteTableSet) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + result := []cloudprovider.ICloudRoute{} + for i := range self.RouteSet { + result = append(result, &self.RouteSet[i]) + } + return result, nil +} + +func (self *SRouteTableSet) CreateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTableSet) UpdateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTableSet) RemoveRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteSet) GetId() string { + return self.RouteItemID +} + +func (self *SRouteSet) GetName() string { + return "" +} + +func (self *SRouteSet) GetGlobalId() string { + return self.RouteItemID +} + +func (self *SRouteSet) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (self *SRouteSet) Refresh() error { + return nil +} + +func (self *SRouteSet) IsEmulated() bool { + return false +} + +func (self *SRouteSet) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SRouteSet) GetType() string { + switch self.RouteType { + case "USER": + return api.ROUTE_ENTRY_TYPE_CUSTOM + case "NETD": + return api.ROUTE_ENTRY_TYPE_SYSTEM + case "CCN": + return api.ROUTE_ENTRY_TYPE_PROPAGATE + default: + return api.ROUTE_ENTRY_TYPE_SYSTEM + } +} + +func (self *SRouteSet) GetCidr() string { + return self.DestinationCidrBlock +} + +func (self *SRouteSet) GetNextHopType() string { + switch self.GatewayType { + case "CVM": + return api.Next_HOP_TYPE_INSTANCE + case "VPN": + return api.Next_HOP_TYPE_VPN + case "DIRECTCONNECT": + return api.Next_HOP_TYPE_DIRECTCONNECTION + case "PEERCONNECTION": + return api.Next_HOP_TYPE_VPCPEERING + case "SSLVPN": + return api.Next_HOP_TYPE_VPN + case "NAT": + return api.Next_HOP_TYPE_NAT + case "NORMAL_CVM": + return api.Next_HOP_TYPE_INSTANCE + case "EIP": + return api.Next_HOP_TYPE_EIP + case "CCN": + return api.Next_HOP_TYPE_INTERVPCNETWORK + default: + return "" + } +} + +func (self *SRouteSet) GetNextHop() string { + return self.GatewayID +} diff --git a/pkg/multicloud/qcloud/shell/route_table.go b/pkg/multicloud/qcloud/shell/route_table.go new file mode 100644 index 0000000000..9f3966d115 --- /dev/null +++ b/pkg/multicloud/qcloud/shell/route_table.go @@ -0,0 +1,48 @@ +// 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 shell + +import ( + "github.com/pkg/errors" + + "yunion.io/x/onecloud/pkg/multicloud/qcloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type RouteTableListOption struct { + VpcId string + } + shellutils.R(&RouteTableListOption{}, "routetable-list", "list routetable", func(cli *qcloud.SRegion, args *RouteTableListOption) error { + routetables, err := cli.GetAllRouteTables(args.VpcId, []string{}) + if err != nil { + return errors.Wrapf(err, "GetAllRouteTables") + } + printList(routetables, 0, 0, 0, nil) + return nil + }) + + type RouteTableShowOption struct { + ROUTETABLEID string + } + shellutils.R(&RouteTableShowOption{}, "routetable-show", "show routetable", func(cli *qcloud.SRegion, args *RouteTableShowOption) error { + routetables, err := cli.GetAllRouteTables("", []string{args.ROUTETABLEID}) + if err != nil { + return errors.Wrapf(err, "GetAllRouteTables") + } + printList(routetables, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/multicloud/qcloud/vpc.go b/pkg/multicloud/qcloud/vpc.go index a878d4314b..7600206b7e 100644 --- a/pkg/multicloud/qcloud/vpc.go +++ b/pkg/multicloud/qcloud/vpc.go @@ -107,11 +107,30 @@ func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, err func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { rts := []cloudprovider.ICloudRouteTable{} + routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{}) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) + } + for i := range routetables { + routetables[i].vpc = self + rts = append(rts, &routetables[i]) + } return rts, nil } func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported + routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{routeTableId}) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) + } + if len(routetables) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(routetables) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + routetables[0].vpc = self + return &routetables[0], nil } func (self *SVpc) getWireByZoneId(zoneId string) *SWire {