yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/cloud_enterprise_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 aliyun
    16  
    17  import (
    18  	"strconv"
    19  	"strings"
    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 SCen struct {
    30  	multicloud.SResourceBase
    31  	AliyunTags
    32  	client                 *SAliyunClient
    33  	Status                 string                 `json:"Status"`
    34  	ProtectionLevel        string                 `json:"ProtectionLevel"`
    35  	CenID                  string                 `json:"CenId"`
    36  	CreationTime           string                 `json:"CreationTime"`
    37  	CenBandwidthPackageIds CenBandwidthPackageIds `json:"CenBandwidthPackageIds"`
    38  	Name                   string                 `json:"Name"`
    39  }
    40  
    41  type SCens struct {
    42  	TotalCount int    `json:"TotalCount"`
    43  	RequestID  string `json:"RequestId"`
    44  	PageSize   int    `json:"PageSize"`
    45  	PageNumber int    `json:"PageNumber"`
    46  	Cens       sCens  `json:"Cens"`
    47  }
    48  
    49  type CenBandwidthPackageIds struct {
    50  	CenBandwidthPackageID []string `json:"CenBandwidthPackageId"`
    51  }
    52  
    53  type sCens struct {
    54  	Cen []SCen `json:"Cen"`
    55  }
    56  
    57  type SCenChildInstances struct {
    58  	PageNumber     int                `json:"PageNumber"`
    59  	ChildInstances sCenChildInstances `json:"ChildInstances"`
    60  	TotalCount     int                `json:"TotalCount"`
    61  	PageSize       int                `json:"PageSize"`
    62  	RequestID      string             `json:"RequestId"`
    63  }
    64  
    65  type SCenChildInstance struct {
    66  	Status                string `json:"Status"`
    67  	ChildInstanceOwnerID  string `json:"ChildInstanceOwnerId"`
    68  	ChildInstanceID       string `json:"ChildInstanceId"`
    69  	ChildInstanceRegionID string `json:"ChildInstanceRegionId"`
    70  	CenID                 string `json:"CenId"`
    71  	ChildInstanceType     string `json:"ChildInstanceType"`
    72  }
    73  
    74  type sCenChildInstances struct {
    75  	ChildInstance []SCenChildInstance `json:"ChildInstance"`
    76  }
    77  
    78  type SCenAttachInstanceInput struct {
    79  	InstanceType         string
    80  	InstanceId           string
    81  	InstanceRegion       string
    82  	ChildInstanceOwnerId string
    83  }
    84  
    85  func (client *SAliyunClient) DescribeCens(pageNumber int, pageSize int) (SCens, error) {
    86  	scens := SCens{}
    87  	params := map[string]string{}
    88  	params["Action"] = "DescribeCens"
    89  	params["PageNumber"] = strconv.Itoa(pageNumber)
    90  	params["PageSize"] = strconv.Itoa(pageSize)
    91  	resp, err := client.cbnRequest("DescribeCens", params)
    92  	if err != nil {
    93  		return scens, errors.Wrap(err, "DescribeCens")
    94  	}
    95  	err = resp.Unmarshal(&scens)
    96  	if err != nil {
    97  		return scens, errors.Wrap(err, "resp.Unmarshal")
    98  	}
    99  	return scens, nil
   100  }
   101  
   102  func (client *SAliyunClient) GetAllCens() ([]SCen, error) {
   103  	pageNumber := 0
   104  	sCen := []SCen{}
   105  	for {
   106  		pageNumber++
   107  		cens, err := client.DescribeCens(pageNumber, 20)
   108  		if err != nil {
   109  			return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber)
   110  		}
   111  		sCen = append(sCen, cens.Cens.Cen...)
   112  		if len(sCen) >= cens.TotalCount {
   113  			break
   114  		}
   115  	}
   116  	for i := 0; i < len(sCen); i++ {
   117  		sCen[i].client = client
   118  	}
   119  	return sCen, nil
   120  }
   121  
   122  func (client *SAliyunClient) CreateCen(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) {
   123  	params := map[string]string{}
   124  	params["Name"] = opts.Name
   125  	params["Description"] = opts.Desc
   126  	resp, err := client.cbnRequest("CreateCen", params)
   127  	if err != nil {
   128  		return "", errors.Wrap(err, "CreateCen")
   129  	}
   130  	type CentId struct {
   131  		CenId string `json:"CenId"`
   132  	}
   133  	centId := CentId{}
   134  	err = resp.Unmarshal(&centId)
   135  	if err != nil {
   136  		return "", errors.Wrap(err, "resp.Unmarshal")
   137  	}
   138  	return centId.CenId, nil
   139  }
   140  
   141  func (client *SAliyunClient) DeleteCen(id string) error {
   142  	params := map[string]string{}
   143  	params["CenId"] = id
   144  	_, err := client.cbnRequest("DeleteCen", params)
   145  	if err != nil {
   146  		return errors.Wrap(err, "DeleteCen")
   147  	}
   148  	return nil
   149  }
   150  
   151  func (client *SAliyunClient) DescribeCenAttachedChildInstances(cenId string, pageNumber int, pageSize int) (SCenChildInstances, error) {
   152  	scenChilds := SCenChildInstances{}
   153  	params := map[string]string{}
   154  	params["CenId"] = cenId
   155  	params["PageNumber"] = strconv.Itoa(pageNumber)
   156  	params["PageSize"] = strconv.Itoa(pageSize)
   157  	resp, err := client.cbnRequest("DescribeCenAttachedChildInstances", params)
   158  	if err != nil {
   159  		return scenChilds, errors.Wrap(err, "DescribeCenAttachedChildInstances")
   160  	}
   161  	err = resp.Unmarshal(&scenChilds)
   162  	if err != nil {
   163  		return scenChilds, errors.Wrap(err, "resp.Unmarshal")
   164  	}
   165  	return scenChilds, nil
   166  }
   167  
   168  func (client *SAliyunClient) GetAllCenAttachedChildInstances(cenId string) ([]SCenChildInstance, error) {
   169  	pageNumber := 0
   170  	scenChilds := []SCenChildInstance{}
   171  	for {
   172  		pageNumber++
   173  		cenChilds, err := client.DescribeCenAttachedChildInstances(cenId, pageNumber, 20)
   174  		if err != nil {
   175  			return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber)
   176  		}
   177  		scenChilds = append(scenChilds, cenChilds.ChildInstances.ChildInstance...)
   178  		if len(scenChilds) >= cenChilds.TotalCount {
   179  			break
   180  		}
   181  	}
   182  	return scenChilds, nil
   183  }
   184  
   185  func (client *SAliyunClient) AttachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error {
   186  	params := map[string]string{}
   187  	params["CenId"] = cenId
   188  	params["ChildInstanceId"] = instance.InstanceId
   189  	params["ChildInstanceRegionId"] = instance.InstanceRegion
   190  	params["ChildInstanceType"] = instance.InstanceType
   191  	params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId
   192  	_, err := client.cbnRequest("AttachCenChildInstance", params)
   193  	if err != nil {
   194  		return errors.Wrap(err, "AttachCenChildInstance")
   195  	}
   196  	return nil
   197  }
   198  
   199  func (client *SAliyunClient) DetachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error {
   200  	params := map[string]string{}
   201  	params["CenId"] = cenId
   202  	params["ChildInstanceId"] = instance.InstanceId
   203  	params["ChildInstanceRegionId"] = instance.InstanceRegion
   204  	params["ChildInstanceType"] = instance.InstanceType
   205  	params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId
   206  	_, err := client.cbnRequest("DetachCenChildInstance", params)
   207  	if err != nil {
   208  		return errors.Wrap(err, "DetachCenChildInstance")
   209  	}
   210  	return nil
   211  }
   212  
   213  func (self *SCen) GetId() string {
   214  	return self.CenID
   215  }
   216  
   217  func (self *SCen) GetName() string {
   218  	return self.Name
   219  }
   220  
   221  func (self *SCen) GetGlobalId() string {
   222  	return self.GetId()
   223  }
   224  
   225  func (self *SCen) GetStatus() string {
   226  	switch self.Status {
   227  	case "Creating":
   228  		return api.INTER_VPC_NETWORK_STATUS_CREATING
   229  	case "Active":
   230  		return api.INTER_VPC_NETWORK_STATUS_AVAILABLE
   231  	case "Deleting":
   232  		return api.INTER_VPC_NETWORK_STATUS_DELETING
   233  	default:
   234  		return api.INTER_VPC_NETWORK_STATUS_UNKNOWN
   235  	}
   236  }
   237  
   238  func (self *SCen) Refresh() error {
   239  	scens, err := self.client.GetAllCens()
   240  	if err != nil {
   241  		return errors.Wrap(err, "self.client.GetAllCens()")
   242  	}
   243  	for i := range scens {
   244  		if scens[i].CenID == self.CenID {
   245  			return jsonutils.Update(self, scens[i])
   246  		}
   247  	}
   248  	return cloudprovider.ErrNotFound
   249  }
   250  
   251  func (self *SCen) GetAuthorityOwnerId() string {
   252  	return self.client.ownerId
   253  }
   254  
   255  func (self *SCen) GetICloudVpcIds() ([]string, error) {
   256  	childs, err := self.client.GetAllCenAttachedChildInstances(self.GetId())
   257  	if err != nil {
   258  		return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())")
   259  	}
   260  	vpcIds := []string{}
   261  	for i := range childs {
   262  		if childs[i].ChildInstanceType == "VPC" {
   263  			vpcIds = append(vpcIds, childs[i].ChildInstanceID)
   264  		}
   265  	}
   266  	return vpcIds, nil
   267  }
   268  
   269  func (self *SCen) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error {
   270  	instance := SCenAttachInstanceInput{
   271  		InstanceType:         "VPC",
   272  		InstanceId:           opts.VpcId,
   273  		InstanceRegion:       opts.VpcRegionId,
   274  		ChildInstanceOwnerId: opts.VpcAuthorityOwnerId,
   275  	}
   276  	err := self.client.AttachCenChildInstance(self.GetId(), instance)
   277  	if err != nil {
   278  		return errors.Wrapf(err, "self.client.AttachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String())
   279  	}
   280  	return nil
   281  }
   282  
   283  func (self *SCen) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error {
   284  	instance := SCenAttachInstanceInput{
   285  		InstanceType:         "VPC",
   286  		InstanceId:           opts.VpcId,
   287  		InstanceRegion:       opts.VpcRegionId,
   288  		ChildInstanceOwnerId: opts.VpcAuthorityOwnerId,
   289  	}
   290  	err := self.client.DetachCenChildInstance(self.GetId(), instance)
   291  	if err != nil {
   292  		return errors.Wrapf(err, "self.client.DetachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String())
   293  	}
   294  	return nil
   295  }
   296  
   297  func (self *SCen) Delete() error {
   298  	err := self.client.DeleteCen(self.GetId())
   299  	if err != nil {
   300  		return errors.Wrapf(err, "self.client.DeleteCen(%s)", self.GetId())
   301  	}
   302  	return nil
   303  }
   304  
   305  func (self *SCen) GetInstanceRouteEntries() ([]SCenRouteEntry, error) {
   306  	childInstance, err := self.client.GetAllCenAttachedChildInstances(self.GetId())
   307  	if err != nil {
   308  		return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())")
   309  	}
   310  	result := []SCenRouteEntry{}
   311  	for i := range childInstance {
   312  		routes, err := self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType)
   313  		if err != nil {
   314  			return nil, errors.Wrap(err, "self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType)")
   315  		}
   316  		for j := range routes {
   317  			// CEN 类型的路由是通过CEN从其他vpc/vbr的路由表中传播过来的
   318  			// 只关注路由的发源
   319  			if routes[j].Type != "CEN" {
   320  				routes[j].ChildInstance = &childInstance[i]
   321  				result = append(result, routes[j])
   322  			}
   323  		}
   324  	}
   325  	return result, nil
   326  }
   327  
   328  func (self *SCen) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) {
   329  	result := []cloudprovider.ICloudInterVpcNetworkRoute{}
   330  	routeEntries, err := self.GetInstanceRouteEntries()
   331  	if err != nil {
   332  		return nil, errors.Wrap(err, "self.GetInstanceRouteEntries()")
   333  	}
   334  	for i := range routeEntries {
   335  		result = append(result, &routeEntries[i])
   336  	}
   337  	return result, nil
   338  }
   339  
   340  func (self *SCen) EnableRouteEntry(routeId string) error {
   341  	idContent := strings.Split(routeId, ":")
   342  	if len(idContent) != 2 {
   343  		return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId)
   344  	}
   345  	routeTable := idContent[0]
   346  	cidr := idContent[1]
   347  	routeEntries, err := self.GetInstanceRouteEntries()
   348  	if err != nil {
   349  		return errors.Wrap(err, "self.GetInstanceRouteEntries()")
   350  	}
   351  	routeEntry := SCenRouteEntry{}
   352  	for i := range routeEntries {
   353  		if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr {
   354  			routeEntry = routeEntries[i]
   355  			break
   356  		}
   357  	}
   358  	if routeEntry.GetEnabled() {
   359  		return nil
   360  	}
   361  	err = self.client.PublishRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr)
   362  	if err != nil {
   363  		return errors.Wrap(err, "self.client.PublishRouteEntries()")
   364  	}
   365  	return nil
   366  }
   367  
   368  func (self *SCen) DisableRouteEntry(routeId string) error {
   369  	idContent := strings.Split(routeId, ":")
   370  	if len(idContent) != 2 {
   371  		return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId)
   372  	}
   373  	routeTable := idContent[0]
   374  	cidr := idContent[1]
   375  	routeEntries, err := self.GetInstanceRouteEntries()
   376  	if err != nil {
   377  		return errors.Wrap(err, "self.GetInstanceRouteEntries()")
   378  	}
   379  	routeEntry := SCenRouteEntry{}
   380  	for i := range routeEntries {
   381  		if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr {
   382  			routeEntry = routeEntries[i]
   383  			break
   384  		}
   385  	}
   386  	if !routeEntry.GetEnabled() {
   387  		return nil
   388  	}
   389  	err = self.client.WithdrawPublishedRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr)
   390  	if err != nil {
   391  		return errors.Wrap(err, "self.client.PublishRouteEntries()")
   392  	}
   393  	return nil
   394  }