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  }