Automatic merge from release/2.5.0 -> release/2.6.0

* commit '3c48686318d232bf4d13f610861f0b7f6f9206cf':
  add cmd loadbalancer-network-list
  minor fixes
  修正:由于阿里云网络与SNAT关联,导致无法删除
This commit is contained in:
邱剑
2019-01-23 19:49:27 +08:00
14 changed files with 456 additions and 72 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ import (
)
type BaseOptions struct {
Debug bool `help:"debug mode"`
Help bool `help:"Show help"`
AccessKey string `help:"Access key" default:"$ALIYUN_ACCESS_KEY"`
Secret string `help:"Secret" default:"$ALIYUN_SECRET"`
@@ -69,7 +70,7 @@ func newClient(options *BaseOptions) (*aliyun.SRegion, error) {
return nil, fmt.Errorf("Missing secret")
}
cli, err := aliyun.NewAliyunClient("", "", options.AccessKey, options.Secret)
cli, err := aliyun.NewAliyunClient("", "", options.AccessKey, options.Secret, options.Debug)
if err != nil {
return nil, err
}
+46
View File
@@ -0,0 +1,46 @@
package shell
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type LoadbalancerNetworkListOptions struct {
options.BaseListOptions
Loadbalancer string `help:"ID or Name of Loadbalancer"`
Network string `help:"ID or Name of network"`
Ip string `help:"search the IP address"`
}
R(&LoadbalancerNetworkListOptions{}, "loadbalancer-network-list", "List loadbalancer network pairs", func(s *mcclient.ClientSession, args *LoadbalancerNetworkListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = args.BaseListOptions.Params()
if err != nil {
return err
}
}
if len(args.Ip) > 0 {
params.Add(jsonutils.NewString(args.Ip), "ip_addr")
}
var result *modules.ListResult
var err error
if len(args.Loadbalancer) > 0 {
result, err = modules.Loadbalancernetworks.ListDescendent(s, args.Loadbalancer, params)
} else if len(args.Network) > 0 {
result, err = modules.Loadbalancernetworks.ListDescendent2(s, args.Network, params)
} else {
result, err = modules.Loadbalancernetworks.List(s, params)
}
if err != nil {
return err
}
printList(result, modules.Loadbalancernetworks.GetColumns(s))
return nil
})
}
+1
View File
@@ -831,6 +831,7 @@ func (self *SNetwork) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSOND
extra.Add(jsonutils.NewInt(int64(self.GetTotalNicCount())), "ports_used")
extra.Add(jsonutils.NewInt(int64(self.GetGuestnicsCount())), "vnics")
extra.Add(jsonutils.NewInt(int64(self.GetBaremetalNicsCount())), "bm_vnics")
extra.Add(jsonutils.NewInt(int64(self.GetLoadbalancerIpsCount())), "lb_vnics")
extra.Add(jsonutils.NewInt(int64(self.GetGroupNicsCount())), "group_vnics")
extra.Add(jsonutils.NewInt(int64(self.GetReservedNicsCount())), "reserve_vnics")
@@ -0,0 +1,17 @@
package modules
var (
Loadbalancernetworks JointResourceManager
)
func init() {
Loadbalancernetworks = NewJointComputeManager(
"loadbalancernetwork",
"loadbalancernetworks",
[]string{"Loadbalancer_ID", "Loadbalancer",
"Network_ID", "Network", "Ip_Addr"},
[]string{},
&Loadbalancers,
&Networks)
registerCompute(&Loadbalancernetworks)
}
+2 -2
View File
@@ -10,8 +10,8 @@ func init() {
"Guest_ip_end", "Guest_ip_mask",
"wire_id", "wire", "is_public", "exit", "Ports",
"vnics", "guest_gateway",
"group_vnics", "bm_vnics", "reserve_vnics", "server_type",
"Status"},
"group_vnics", "bm_vnics", "reserve_vnics", "lb_vnics",
"server_type", "Status"},
[]string{})
registerCompute(&Networks)
+4 -2
View File
@@ -37,10 +37,12 @@ type SAliyunClient struct {
accessKey string
secret string
iregions []cloudprovider.ICloudRegion
Debug bool
}
func NewAliyunClient(providerId string, providerName string, accessKey string, secret string) (*SAliyunClient, error) {
client := SAliyunClient{providerId: providerId, providerName: providerName, accessKey: accessKey, secret: secret}
func NewAliyunClient(providerId string, providerName string, accessKey string, secret string, isDebug bool) (*SAliyunClient, error) {
client := SAliyunClient{providerId: providerId, providerName: providerName, accessKey: accessKey, secret: secret, Debug: isDebug}
err := client.fetchRegions()
if err != nil {
return nil, err
+166
View File
@@ -0,0 +1,166 @@
package aliyun
import (
"fmt"
"time"
"yunion.io/x/log"
)
type SBandwidthPackageIds struct {
BandwidthPackageId []string
}
type SForwardTableIds struct {
ForwardTableId []string
}
type SSnatTableIds struct {
SnatTableId []string
}
type SNatGetway struct {
vpc *SVpc
BandwidthPackageIds SBandwidthPackageIds
BusinessStatus string
CreationTime time.Time
Description string
ForwardTableIds SForwardTableIds
SnatTableIds SSnatTableIds
InstanceChargeType string
Name string
NatGatewayId string
RegionId string
Spec string
Status string
VpcId string
}
func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGetway, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
if len(vpcId) > 0 {
params["VpcId"] = vpcId
}
if len(natGwId) > 0 {
params["NatGatewayId"] = natGwId
}
body, err := self.vpcRequest("DescribeNatGateways", params)
if err != nil {
log.Errorf("GetVSwitches fail %s", err)
return nil, 0, err
}
if self.client.Debug {
log.Debugf("%s", body.PrettyString())
}
gateways := make([]SNatGetway, 0)
err = body.Unmarshal(&gateways, "NatGateways", "NatGateway")
if err != nil {
log.Errorf("Unmarshal gateways fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
return gateways, int(total), nil
}
type SSNATTableEntry struct {
SnatEntryId string
SnatIp string
SnatTableId string `json:"snat_table_id"`
SourceCIDR string `json:"source_cidr"`
SourceVSwitchId string `json:"source_vswitch_id"`
Status string
}
func (self *SRegion) GetSNATEntries(tableId string, offset, limit int) ([]SSNATTableEntry, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
params["SnatTableId"] = tableId
body, err := self.vpcRequest("DescribeSnatTableEntries", params)
if err != nil {
log.Errorf("DescribeSnatTableEntries fail %s", err)
return nil, 0, err
}
if self.client.Debug {
log.Debugf("%s", body.PrettyString())
}
entries := make([]SSNATTableEntry, 0)
err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry")
if err != nil {
log.Errorf("Unmarshal entries fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
return entries, int(total), nil
}
func (region *SRegion) DeleteSnatEntry(tableId string, entryId string) error {
params := make(map[string]string)
params["RegionId"] = region.RegionId
params["SnatTableId"] = tableId
params["SnatEntryId"] = entryId
_, err := region.vpcRequest("DeleteSnatEntry", params)
return err
}
func (nat *SNatGetway) getSnatEntriesForTable(tblId string) ([]SSNATTableEntry, error) {
entries := make([]SSNATTableEntry, 0)
entryTotal := -1
for entryTotal < 0 || len(entries) < entryTotal {
parts, total, err := nat.vpc.region.GetSNATEntries(tblId, len(entries), 50)
if err != nil {
return nil, err
}
if len(parts) > 0 {
entries = append(entries, parts...)
}
entryTotal = total
}
return entries, nil
}
func (nat *SNatGetway) getSnatEntries() ([]SSNATTableEntry, error) {
entries := make([]SSNATTableEntry, 0)
for i := range nat.SnatTableIds.SnatTableId {
sentries, err := nat.getSnatEntriesForTable(nat.SnatTableIds.SnatTableId[i])
if err != nil {
return nil, err
}
entries = append(entries, sentries...)
}
return entries, nil
}
func (nat *SNatGetway) dissociateWithVswitch(vswitchId string) error {
entries, err := nat.getSnatEntries()
if err != nil {
return err
}
for i := range entries {
log.Debugf("%s", entries[i])
if entries[i].SourceVSwitchId == vswitchId {
err := nat.vpc.region.DeleteSnatEntry(entries[i].SnatTableId, entries[i].SnatEntryId)
if err != nil {
return err
}
}
}
return nil
}
+1 -1
View File
@@ -72,7 +72,7 @@ func (self *SAliyunProviderFactory) GetProvider(providerId, providerName, url, a
return self.providerTable[providerId], nil
*/
client, err := aliyun.NewAliyunClient(providerId, providerName, account, secret)
client, err := aliyun.NewAliyunClient(providerId, providerName, account, secret, false)
if err != nil {
return nil, err
}
+10 -31
View File
@@ -21,6 +21,8 @@ type SRegion struct {
sdkClient *sdk.Client
ossClient *oss.Client
Debug bool
RegionId string
LocalName string
@@ -87,6 +89,14 @@ func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonu
return jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params)
}
func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.getSdkClient()
if err != nil {
return nil, err
}
return jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params)
}
func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.getSdkClient()
if err != nil {
@@ -365,37 +375,6 @@ func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRou
return routetables, int(total), nil
}
func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
if ids != nil && len(ids) > 0 {
params["VSwitchId"] = strings.Join(ids, ",")
}
if len(vpcId) > 0 {
params["VpcId"] = vpcId
}
body, err := self.ecsRequest("DescribeVSwitches", params)
if err != nil {
log.Errorf("GetVSwitches fail %s", err)
return nil, 0, err
}
switches := make([]SVSwitch, 0)
err = body.Unmarshal(&switches, "VSwitches", "VSwitch")
if err != nil {
log.Errorf("Unmarshal vswitches fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
return switches, int(total), nil
}
func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) {
if self.instanceTypes == nil {
types, err := self.GetInstanceTypes()
+24 -1
View File
@@ -7,6 +7,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"strings"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -195,7 +196,7 @@ func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
body, err := self.apiRequest("DescribeRouteTableList", params)
body, err := self.region.vpcRequest("DescribeRouteTableList", params)
if err != nil {
log.Errorf("RemoteGetRouteTableList fail %s", err)
return nil, 0, err
@@ -213,3 +214,25 @@ func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable
total, _ := body.Int("TotalCount")
return routeTables, int(total), nil
}
func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error {
params := make(map[string]string)
params["RegionId"] = region.RegionId
params["RouteTableId"] = rtableId
params["VSwitchId"] = vswitchId
_, err := region.vpcRequest("AssociateRouteTable", params)
return err
}
func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error {
params := make(map[string]string)
params["RegionId"] = region.RegionId
params["RouteTableId"] = rtableId
params["VSwitchId"] = vswitchId
_, err := region.vpcRequest("UnassociateRouteTable", params)
return err
}
func (routeTable *SRouteTable) IsSystem() bool {
return strings.ToLower(routeTable.RouteTableType) == "system"
}
+36
View File
@@ -0,0 +1,36 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aliyun"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type NatGatewayListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&NatGatewayListOptions{}, "natgateway-list", "List NAT gateways", func(cli *aliyun.SRegion, args *NatGatewayListOptions) error {
gws, total, e := cli.GetNatGateways("", "", args.Offset, args.Limit)
if e != nil {
return e
}
printList(gws, total, args.Offset, args.Limit, []string{})
return nil
})
type SNatEntryListOptions struct {
ID string `help:"SNat Table ID"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&SNatEntryListOptions{}, "snat-entry-list", "List SNAT entries", func(cli *aliyun.SRegion, args *SNatEntryListOptions) error {
entries, total, e := cli.GetSNATEntries(args.ID, args.Offset, args.Limit)
if e != nil {
return e
}
printList(entries, total, args.Offset, args.Limit, []string{})
return nil
})
}
+20
View File
@@ -18,4 +18,24 @@ func init() {
printList(vswitches, total, args.Offset, args.Limit, []string{})
return nil
})
type VSwitchShowOptions struct {
ID string `help:"show vswitch details"`
}
shellutils.R(&VSwitchShowOptions{}, "vswitch-show", "Show vswitch details", func(cli *aliyun.SRegion, args *VSwitchShowOptions) error {
vswitch, e := cli.GetVSwitchAttributes(args.ID)
if e != nil {
return e
}
printObject(vswitch)
return nil
})
shellutils.R(&VSwitchShowOptions{}, "vswitch-delete", "Show vswitch details", func(cli *aliyun.SRegion, args *VSwitchShowOptions) error {
e := cli.DeleteVSwitch(args.ID)
if e != nil {
return e
}
return nil
})
}
+19 -8
View File
@@ -46,14 +46,6 @@ type SVpc struct {
VpcName string
}
func (self *SVpc) apiRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
client, err := self.region.getSdkClient()
if err != nil {
return nil, err
}
return jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, action, params)
}
func (self *SVpc) GetMetadata() *jsonutils.JSONDict {
return nil
}
@@ -242,3 +234,22 @@ func (self *SVpc) Delete() error {
}
return self.region.DeleteVpc(self.VpcId)
}
func (self *SVpc) getNatGateways() ([]SNatGetway, error) {
natgatways := make([]SNatGetway, 0)
gwTotal := -1
for gwTotal < 0 || len(natgatways) < gwTotal {
parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(natgatways), 50)
if err != nil {
return nil, err
}
if len(parts) > 0 {
natgatways = append(natgatways, parts...)
}
gwTotal = total
}
for i := 0; i < len(natgatways); i += 1 {
natgatways[i].vpc = self
}
return natgatways, nil
}
+108 -26
View File
@@ -9,6 +9,7 @@ import (
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/utils"
"fmt"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
@@ -20,19 +21,29 @@ const (
VSwitchAvailable = "Available"
)
type SCloudResources struct {
CloudResourceSetType []string
}
type SVSwitch struct {
wire *SWire
AvailableIpAddressCount int
CidrBlock string
CreationTime time.Time
Description string
IsDefault bool
Status string
VSwitchId string
VSwitchName string
VpcId string
ZoneId string
CidrBlock string
Ipv6CidrBlock string
CreationTime time.Time
Description string
IsDefault bool
Status string
VSwitchId string
VSwitchName string
VpcId string
ZoneId string
CloudResources SCloudResources
ResourceGroupId string
RouteTable SRouteTable
}
func (self *SVSwitch) GetMetadata() *jsonutils.JSONDict {
@@ -64,7 +75,7 @@ func (self *SVSwitch) GetStatus() string {
func (self *SVSwitch) Refresh() error {
log.Debugf("vsiwtch refresh %s", self.VSwitchId)
new, err := self.wire.zone.region.getVSwitch(self.VSwitchId)
new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId)
if err != nil {
return err
}
@@ -123,37 +134,108 @@ func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cid
}
params["ClientToken"] = utils.GenRequestId(20)
body, err := self.ecsRequest("CreateVSwitch", params)
body, err := self.vpcRequest("CreateVSwitch", params)
if err != nil {
return "", err
}
return body.GetString("VSwitchId")
}
func (self *SRegion) getVSwitch(vswitchId string) (*SVSwitch, error) {
vswitches, total, err := self.GetVSwitches([]string{vswitchId}, "", 0, 1)
log.Debugf("getVSwitch %d %d %s %s", len(vswitches), total, err, vswitchId)
if err != nil {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
return &vswitches[0], nil
}
func (self *SRegion) deleteVSwitch(vswitchId string) error {
func (self *SRegion) DeleteVSwitch(vswitchId string) error {
params := make(map[string]string)
params["VSwitchId"] = vswitchId
_, err := self.ecsRequest("DeleteVSwitch", params)
_, err := self.vpcRequest("DeleteVSwitch", params)
return err
}
func (self *SVSwitch) Delete() error {
return self.wire.zone.region.deleteVSwitch(self.VSwitchId)
err := self.Refresh()
if err != nil {
log.Errorf("refresh vswitch fail %s", err)
return err
}
if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() {
err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId)
if err != nil {
log.Errorf("unassociate routetable fail %s", err)
return err
}
}
err = self.dissociateWithSNAT()
if err != nil {
log.Errorf("fail to dissociateWithSNAT")
return err
}
return self.wire.zone.region.DeleteVSwitch(self.VSwitchId)
}
func (self *SVSwitch) GetAllocTimeoutSeconds() int {
return 120 // 2 minutes
}
func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
if ids != nil && len(ids) > 0 {
params["VSwitchId"] = strings.Join(ids, ",")
}
if len(vpcId) > 0 {
params["VpcId"] = vpcId
}
body, err := self.vpcRequest("DescribeVSwitches", params)
if err != nil {
log.Errorf("GetVSwitches fail %s", err)
return nil, 0, err
}
switches := make([]SVSwitch, 0)
err = body.Unmarshal(&switches, "VSwitches", "VSwitch")
if err != nil {
log.Errorf("Unmarshal vswitches fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
return switches, int(total), nil
}
func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) {
params := make(map[string]string)
params["VSwitchId"] = idstr
body, err := self.vpcRequest("DescribeVSwitchAttributes", params)
if err != nil {
log.Errorf("DescribeVSwitchAttributes fail %s", err)
return nil, err
}
if self.client.Debug {
log.Debugf("%s", body.PrettyString())
}
switches := SVSwitch{}
err = body.Unmarshal(&switches)
if err != nil {
log.Errorf("Unmarshal vswitches fail %s", err)
return nil, err
}
return &switches, nil
}
func (vsw *SVSwitch) dissociateWithSNAT() error {
natgatways, err := vsw.wire.vpc.getNatGateways()
if err != nil {
return err
}
for i := range natgatways {
err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId)
if err != nil {
return err
}
}
return nil
}