yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/cloud_connect_network.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 qcloud 16 17 import ( 18 "fmt" 19 "strconv" 20 21 "yunion.io/x/jsonutils" 22 "yunion.io/x/pkg/errors" 23 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 29 type SCcn struct { 30 multicloud.SResourceBase 31 QcloudTags 32 region *SRegion 33 34 CcnID string `json:"CcnId"` 35 CcnName string `json:"CcnName"` 36 CcnDescription string `json:"CcnDescription"` 37 InstanceCount int `json:"InstanceCount"` 38 CreateTime string `json:"CreateTime"` 39 State string `json:"State"` 40 AttachedInstances []SCcnInstance 41 } 42 43 type SCcnInstance struct { 44 CcnID string `json:"CcnId"` 45 InstanceType string `json:"InstanceType"` 46 InstanceID string `json:"InstanceId"` 47 InstanceName string `json:"InstanceName"` 48 InstanceRegion string `json:"InstanceRegion"` 49 InstanceUin string `json:"InstanceUin"` 50 CidrBlock []string `json:"CidrBlock"` 51 State string `json:"State"` 52 } 53 54 type SCcnAttachInstanceInput struct { 55 InstanceType string 56 InstanceId string 57 InstanceRegion string 58 } 59 60 func (self *SRegion) DescribeCcns(ccnIds []string, offset int, limit int) ([]SCcn, int, error) { 61 params := map[string]string{} 62 params["Offset"] = strconv.Itoa(offset) 63 params["Limit"] = strconv.Itoa(limit) 64 if ccnIds != nil && len(ccnIds) > 0 { 65 for index, ccnId := range ccnIds { 66 params[fmt.Sprintf("CcnIds.%d", index)] = ccnId 67 } 68 } 69 resp, err := self.vpcRequest("DescribeCcns", params) 70 if err != nil { 71 return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcns", %s)`, jsonutils.Marshal(params).String()) 72 } 73 ccns := []SCcn{} 74 err = resp.Unmarshal(&ccns, "CcnSet") 75 if err != nil { 76 return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&ccns,"CcnSet")`, jsonutils.Marshal(resp).String()) 77 } 78 total, _ := resp.Float("TotalCount") 79 return ccns, int(total), nil 80 } 81 82 func (self *SRegion) GetAllCcns() ([]SCcn, error) { 83 ccns := []SCcn{} 84 for { 85 part, total, err := self.DescribeCcns(nil, len(ccns), 50) 86 if err != nil { 87 return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccns)) 88 } 89 ccns = append(ccns, part...) 90 if len(ccns) >= total { 91 break 92 } 93 } 94 for i := range ccns { 95 ccns[i].region = self 96 } 97 return ccns, nil 98 } 99 100 func (self *SRegion) GetCcnById(ccnId string) (*SCcn, error) { 101 ccns, _, err := self.DescribeCcns([]string{ccnId}, 0, 50) 102 if err != nil { 103 return nil, errors.Wrapf(err, "self.DescribeCcns(%s, 0, 50)", ccnId) 104 } 105 if len(ccns) < 1 { 106 return nil, errors.Wrap(cloudprovider.ErrNotFound, "DescribeCcns") 107 } 108 if len(ccns) > 1 { 109 return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "DescribeCcns") 110 } 111 ccns[0].region = self 112 return &ccns[0], nil 113 } 114 115 func (self *SRegion) DescribeCcnAttachedInstances(ccnId string, offset int, limit int) ([]SCcnInstance, int, error) { 116 params := map[string]string{} 117 params["Offset"] = strconv.Itoa(offset) 118 params["Limit"] = strconv.Itoa(limit) 119 params["Filters.0.Name"] = "ccn-id" 120 params["Filters.0.Values.0"] = ccnId 121 resp, err := self.vpcRequest("DescribeCcnAttachedInstances", params) 122 if err != nil { 123 return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcnAttachedInstances", %s)`, jsonutils.Marshal(params).String()) 124 } 125 instances := []SCcnInstance{} 126 err = resp.Unmarshal(&instances, "InstanceSet") 127 if err != nil { 128 return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&instances, "InstanceSet")`, jsonutils.Marshal(resp).String()) 129 } 130 total, _ := resp.Float("TotalCount") 131 return instances, int(total), nil 132 } 133 134 func (self *SRegion) GetAllCcnAttachedInstances(ccnId string) ([]SCcnInstance, error) { 135 ccnInstances := []SCcnInstance{} 136 for { 137 part, total, err := self.DescribeCcnAttachedInstances(ccnId, len(ccnInstances), 50) 138 if err != nil { 139 return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccnInstances)) 140 } 141 ccnInstances = append(ccnInstances, part...) 142 if len(ccnInstances) >= total { 143 break 144 } 145 } 146 return ccnInstances, nil 147 } 148 149 func (self *SRegion) CreateCcn(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) { 150 params := make(map[string]string) 151 params["CcnName"] = opts.Name 152 params["CcnDescription"] = opts.Desc 153 // 默认的后付费不能被支持 154 params["InstanceChargeType"] = "PREPAID" 155 // 预付费仅支持地域间限速 156 params["BandwidthLimitType"] = "INTER_REGION_LIMIT" 157 resp, err := self.vpcRequest("CreateCcn", params) 158 if err != nil { 159 return "", errors.Wrapf(err, `self.vpcRequest("CreateCcn", %s)`, jsonutils.Marshal(params).String()) 160 } 161 ccn := &SCcn{} 162 err = resp.Unmarshal(ccn, "Ccn") 163 if err != nil { 164 return "", errors.Wrapf(err, `(%s).Unmarshal(ccn, "Ccn")`, jsonutils.Marshal(resp).String()) 165 } 166 return ccn.CcnID, nil 167 } 168 169 func (self *SRegion) AcceptAttachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { 170 params := make(map[string]string) 171 params["CcnId"] = ccnId 172 for i := range instances { 173 params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType 174 params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId 175 params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion 176 } 177 _, err := self.vpcRequest("AcceptAttachCcnInstances", params) 178 if err != nil { 179 return errors.Wrapf(err, `self.vpcRequest("AcceptAttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) 180 } 181 return nil 182 } 183 184 func (self *SRegion) DeleteCcn(ccnId string) error { 185 params := make(map[string]string) 186 params["CcnId"] = ccnId 187 _, err := self.vpcRequest("DeleteCcn", params) 188 if err != nil { 189 return errors.Wrapf(err, ` self.vpcRequest("DeleteCcn", %s)`, jsonutils.Marshal(params).String()) 190 } 191 return nil 192 } 193 194 func (self *SRegion) AttachCcnInstances(ccnId string, ccnUin string, instances []SCcnAttachInstanceInput) error { 195 params := make(map[string]string) 196 params["CcnId"] = ccnId 197 if len(ccnUin) > 0 { 198 params["CcnUin"] = ccnUin 199 } 200 for i := range instances { 201 params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType 202 params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId 203 params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion 204 } 205 206 _, err := self.vpcRequest("AttachCcnInstances", params) 207 if err != nil { 208 return errors.Wrapf(err, ` self.vpcRequest("AttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) 209 } 210 return nil 211 } 212 213 func (self *SRegion) DetachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { 214 params := make(map[string]string) 215 params["CcnId"] = ccnId 216 217 for i := range instances { 218 params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType 219 params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId 220 params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion 221 } 222 223 _, err := self.vpcRequest("DetachCcnInstances", params) 224 if err != nil { 225 return errors.Wrapf(err, ` self.vpcRequest("DetachCcnInstances", %s)`, jsonutils.Marshal(params).String()) 226 } 227 return nil 228 } 229 230 func (self *SCcn) GetId() string { 231 return self.CcnID 232 } 233 234 func (self *SCcn) GetName() string { 235 return self.CcnName 236 } 237 238 func (self *SCcn) GetGlobalId() string { 239 return self.GetId() 240 } 241 242 func (self *SCcn) GetStatus() string { 243 switch self.State { 244 case "AVAILABLE": 245 return api.INTER_VPC_NETWORK_STATUS_AVAILABLE 246 case "ISOLATED": 247 return api.INTER_VPC_NETWORK_STATUS_UNKNOWN 248 default: 249 return api.INTER_VPC_NETWORK_STATUS_UNKNOWN 250 } 251 } 252 253 func (self *SCcn) Refresh() error { 254 ccn, err := self.region.GetCcnById(self.GetId()) 255 if err != nil { 256 return errors.Wrapf(err, "self.region.GetCcnById(%s)", self.GetId()) 257 } 258 return jsonutils.Update(self, ccn) 259 } 260 261 func (self *SCcn) GetAuthorityOwnerId() string { 262 return self.region.client.ownerName 263 } 264 265 func (self *SCcn) fetchAttachedInstances() error { 266 if self.AttachedInstances != nil { 267 return nil 268 } 269 270 instances, err := self.region.GetAllCcnAttachedInstances(self.GetId()) 271 if err != nil { 272 return errors.Wrapf(err, "self.region.GetAllCcnAttachedInstances(%s)", self.GetId()) 273 } 274 self.AttachedInstances = instances 275 return nil 276 } 277 278 func (self *SCcn) GetICloudVpcIds() ([]string, error) { 279 err := self.fetchAttachedInstances() 280 if err != nil { 281 return nil, errors.Wrap(err, "self.fetchAttachedInstances()") 282 } 283 result := []string{} 284 for i := range self.AttachedInstances { 285 if self.AttachedInstances[i].InstanceType == "VPC" { 286 result = append(result, self.AttachedInstances[i].InstanceID) 287 } 288 } 289 return result, nil 290 } 291 292 func (self *SCcn) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error { 293 if self.GetAuthorityOwnerId() == opts.VpcAuthorityOwnerId { 294 return nil 295 } 296 instance := SCcnAttachInstanceInput{ 297 InstanceType: "VPC", 298 InstanceId: opts.VpcId, 299 InstanceRegion: opts.VpcRegionId, 300 } 301 err := self.region.AcceptAttachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) 302 if err != nil { 303 return errors.Wrapf(err, "self.region.AcceptAttachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) 304 } 305 return nil 306 } 307 308 func (self *SCcn) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error { 309 instance := SCcnAttachInstanceInput{ 310 InstanceType: "VPC", 311 InstanceId: opts.VpcId, 312 InstanceRegion: opts.VpcRegionId, 313 } 314 err := self.region.DetachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) 315 if err != nil { 316 return errors.Wrapf(err, "self.client.DetachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) 317 } 318 return nil 319 } 320 321 func (self *SCcn) Delete() error { 322 err := self.region.DeleteCcn(self.GetId()) 323 if err != nil { 324 return errors.Wrapf(err, "self.region.DeleteCcn(%s)", self.GetId()) 325 } 326 return nil 327 } 328 329 func (self *SCcn) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) { 330 routes, err := self.region.GetAllCcnRouteSets(self.GetId()) 331 if err != nil { 332 return nil, errors.Wrap(err, " self.region.GetAllCcnRouteSets(self.GetId())") 333 } 334 result := []cloudprovider.ICloudInterVpcNetworkRoute{} 335 for i := range routes { 336 result = append(result, &routes[i]) 337 } 338 return result, nil 339 } 340 341 func (self *SCcn) EnableRouteEntry(routeId string) error { 342 err := self.region.EnableCcnRoutes(self.GetId(), []string{routeId}) 343 if err != nil { 344 return errors.Wrap(err, "self.region.EnableCcnRoutes") 345 } 346 return nil 347 } 348 349 func (self *SCcn) DisableRouteEntry(routeId string) error { 350 err := self.region.DisableCcnRoutes(self.GetId(), []string{routeId}) 351 if err != nil { 352 return errors.Wrap(err, "self.region.DisableCcnRoutes") 353 } 354 return nil 355 } 356 357 func (client *SQcloudClient) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { 358 region, err := client.getDefaultRegion() 359 if err != nil { 360 return nil, errors.Wrap(err, "getDefaultRegion") 361 } 362 sccns, err := region.GetAllCcns() 363 if err != nil { 364 return nil, errors.Wrap(err, " region.GetAllCcns()") 365 } 366 result := []cloudprovider.ICloudInterVpcNetwork{} 367 for i := range sccns { 368 result = append(result, &sccns[i]) 369 } 370 return result, nil 371 } 372 373 func (client *SQcloudClient) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { 374 region, err := client.getDefaultRegion() 375 if err != nil { 376 return nil, errors.Wrap(err, "getDefaultRegion") 377 } 378 ccn, err := region.GetCcnById(id) 379 if err != nil { 380 return nil, errors.Wrapf(err, "region.GetCcnById(%s)", id) 381 } 382 return ccn, nil 383 } 384 385 func (client *SQcloudClient) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { 386 region, err := client.getDefaultRegion() 387 if err != nil { 388 return nil, errors.Wrap(err, "getDefaultRegion") 389 } 390 391 ccnId, err := region.CreateCcn(opts) 392 if err != nil { 393 return nil, errors.Wrapf(err, "region.CreateCcn(%s)", jsonutils.Marshal(opts).String()) 394 } 395 iNetwork, err := client.GetICloudInterVpcNetworkById(ccnId) 396 if err != nil { 397 return nil, errors.Wrapf(err, "client.GetICloudInterVpcNetworkById(%s)", ccnId) 398 } 399 return iNetwork, nil 400 }