yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/vswitch.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 apsara
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"yunion.io/x/jsonutils"
    23  	"yunion.io/x/log"
    24  	"yunion.io/x/pkg/util/netutils"
    25  	"yunion.io/x/pkg/utils"
    26  
    27  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/cloudmux/pkg/multicloud"
    30  	"yunion.io/x/onecloud/pkg/util/rbacutils"
    31  )
    32  
    33  // {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"}
    34  
    35  const (
    36  	VSwitchPending   = "Pending"
    37  	VSwitchAvailable = "Available"
    38  )
    39  
    40  type SCloudResources struct {
    41  	CloudResourceSetType []string
    42  }
    43  
    44  type SVSwitch struct {
    45  	multicloud.SResourceBase
    46  	ApsaraTags
    47  	wire *SWire
    48  
    49  	AvailableIpAddressCount int
    50  
    51  	CidrBlock     string
    52  	Ipv6CidrBlock string
    53  	CreationTime  time.Time
    54  	Description   string
    55  	IsDefault     bool
    56  	Status        string
    57  	VSwitchId     string
    58  	VSwitchName   string
    59  	VpcId         string
    60  	ZoneId        string
    61  
    62  	CloudResources SCloudResources
    63  	RouteTable     SRouteTable
    64  	DepartmentInfo
    65  }
    66  
    67  func (self *SVSwitch) GetId() string {
    68  	return self.VSwitchId
    69  }
    70  
    71  func (self *SVSwitch) GetName() string {
    72  	if len(self.VSwitchName) > 0 {
    73  		return self.VSwitchName
    74  	}
    75  	return self.VSwitchId
    76  }
    77  
    78  func (self *SVSwitch) GetGlobalId() string {
    79  	return self.VSwitchId
    80  }
    81  
    82  func (self *SVSwitch) GetCreatedAt() time.Time {
    83  	return self.CreationTime
    84  }
    85  
    86  func (self *SVSwitch) GetStatus() string {
    87  	return strings.ToLower(self.Status)
    88  }
    89  
    90  func (self *SVSwitch) Refresh() error {
    91  	log.Debugf("vsiwtch refresh %s", self.VSwitchId)
    92  	new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	return jsonutils.Update(self, new)
    97  }
    98  
    99  func (self *SVSwitch) GetIWire() cloudprovider.ICloudWire {
   100  	return self.wire
   101  }
   102  
   103  func (self *SVSwitch) GetIpStart() string {
   104  	pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
   105  	startIp := pref.Address.NetAddr(pref.MaskLen) // 0
   106  	startIp = startIp.StepUp()                    // 1
   107  	return startIp.String()
   108  }
   109  
   110  func (self *SVSwitch) GetIpEnd() string {
   111  	pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
   112  	endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
   113  	endIp = endIp.StepDown()                          // 254
   114  	endIp = endIp.StepDown()                          // 253
   115  	endIp = endIp.StepDown()                          // 252
   116  	return endIp.String()
   117  }
   118  
   119  func (self *SVSwitch) GetIpMask() int8 {
   120  	pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
   121  	return pref.MaskLen
   122  }
   123  
   124  func (self *SVSwitch) GetGateway() string {
   125  	pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
   126  	endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
   127  	endIp = endIp.StepDown()                          // 254
   128  	return endIp.String()
   129  }
   130  
   131  func (self *SVSwitch) GetServerType() string {
   132  	return api.NETWORK_TYPE_GUEST
   133  }
   134  
   135  func (self *SVSwitch) GetIsPublic() bool {
   136  	// return self.IsDefault
   137  	return true
   138  }
   139  
   140  func (self *SVSwitch) GetPublicScope() rbacutils.TRbacScope {
   141  	return rbacutils.ScopeDomain
   142  }
   143  
   144  func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) {
   145  	params := make(map[string]string)
   146  	params["ZoneId"] = zoneId
   147  	params["VpcId"] = vpcId
   148  	params["CidrBlock"] = cidr
   149  	params["VSwitchName"] = name
   150  	if len(desc) > 0 {
   151  		params["Description"] = desc
   152  	}
   153  	params["ClientToken"] = utils.GenRequestId(20)
   154  
   155  	body, err := self.vpcRequest("CreateVSwitch", params)
   156  	if err != nil {
   157  		return "", err
   158  	}
   159  	return body.GetString("VSwitchId")
   160  }
   161  
   162  func (self *SRegion) DeleteVSwitch(vswitchId string) error {
   163  	params := make(map[string]string)
   164  	params["VSwitchId"] = vswitchId
   165  
   166  	_, err := self.vpcRequest("DeleteVSwitch", params)
   167  	return err
   168  }
   169  
   170  func (self *SVSwitch) Delete() error {
   171  	err := self.Refresh()
   172  	if err != nil {
   173  		log.Errorf("refresh vswitch fail %s", err)
   174  		return err
   175  	}
   176  	if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() {
   177  		err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId)
   178  		if err != nil {
   179  			log.Errorf("unassociate routetable fail %s", err)
   180  			return err
   181  		}
   182  	}
   183  	err = self.dissociateWithSNAT()
   184  	if err != nil {
   185  		log.Errorf("fail to dissociateWithSNAT")
   186  		return err
   187  	}
   188  	err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) {
   189  		err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId)
   190  		if err != nil {
   191  			// delete network immediately after deleting vm on it
   192  			// \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"}
   193  			if isError(err, "DependencyViolation") {
   194  				return false, nil
   195  			}
   196  			return false, err
   197  		} else {
   198  			return true, nil
   199  		}
   200  	})
   201  	return err
   202  }
   203  
   204  func (self *SVSwitch) GetAllocTimeoutSeconds() int {
   205  	return 120 // 2 minutes
   206  }
   207  
   208  func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) {
   209  	if limit > 50 || limit <= 0 {
   210  		limit = 50
   211  	}
   212  	params := make(map[string]string)
   213  	params["RegionId"] = self.RegionId
   214  	params["PageSize"] = fmt.Sprintf("%d", limit)
   215  	params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
   216  	if ids != nil && len(ids) > 0 {
   217  		params["VSwitchId"] = strings.Join(ids, ",")
   218  	}
   219  	if len(vpcId) > 0 {
   220  		params["VpcId"] = vpcId
   221  	}
   222  
   223  	body, err := self.vpcRequest("DescribeVSwitches", params)
   224  	if err != nil {
   225  		log.Errorf("GetVSwitches fail %s", err)
   226  		return nil, 0, err
   227  	}
   228  
   229  	switches := make([]SVSwitch, 0)
   230  	err = body.Unmarshal(&switches, "VSwitches", "VSwitch")
   231  	if err != nil {
   232  		log.Errorf("Unmarshal vswitches fail %s", err)
   233  		return nil, 0, err
   234  	}
   235  	total, _ := body.Int("TotalCount")
   236  	return switches, int(total), nil
   237  }
   238  
   239  func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) {
   240  	params := make(map[string]string)
   241  	params["VSwitchId"] = idstr
   242  
   243  	body, err := self.vpcRequest("DescribeVSwitchAttributes", params)
   244  	if err != nil {
   245  		log.Errorf("DescribeVSwitchAttributes fail %s", err)
   246  		return nil, err
   247  	}
   248  	if self.client.debug {
   249  		log.Debugf("%s", body.PrettyString())
   250  	}
   251  	switches := SVSwitch{}
   252  	err = body.Unmarshal(&switches)
   253  	if err != nil {
   254  		log.Errorf("Unmarshal vswitches fail %s", err)
   255  		return nil, err
   256  	}
   257  	return &switches, nil
   258  }
   259  
   260  func (vsw *SVSwitch) dissociateWithSNAT() error {
   261  	natgatways, err := vsw.wire.vpc.getNatGateways()
   262  	if err != nil {
   263  		return err
   264  	}
   265  	for i := range natgatways {
   266  		err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId)
   267  		if err != nil {
   268  			return err
   269  		}
   270  	}
   271  	return nil
   272  }