vswitch.go 8.2 KB

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