修正:由于阿里云网络与SNAT关联,导致无法删除

This commit is contained in:
Qiu Jian
2019-01-22 02:46:35 +08:00
parent 7a5347420b
commit c5343a111b
12 changed files with 392 additions and 71 deletions
+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")
+1 -1
View File
@@ -10,7 +10,7 @@ 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",
"group_vnics", "bm_vnics", "reserve_vnics", "lb_vnics", "server_type",
"Status"},
[]string{})
+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
}