yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aliyun/natgateway.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  	"fmt"
    19  	"strings"
    20  	"time"
    21  
    22  	"yunion.io/x/jsonutils"
    23  	"yunion.io/x/log"
    24  	"yunion.io/x/pkg/errors"
    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  )
    31  
    32  type SBandwidthPackageIds struct {
    33  	BandwidthPackageId []string
    34  }
    35  
    36  type SForwardTableIds struct {
    37  	ForwardTableId []string
    38  }
    39  
    40  type SSnatTableIds struct {
    41  	SnatTableId []string
    42  }
    43  
    44  type NatGatewayPrivateInfo struct {
    45  	EniInstanceId    string
    46  	IzNo             string
    47  	MaxBandwidth     int
    48  	PrivateIpAddress string
    49  	VswitchId        string
    50  }
    51  
    52  type SNatGateway struct {
    53  	multicloud.SNatGatewayBase
    54  	AliyunTags
    55  
    56  	vpc *SVpc
    57  
    58  	BandwidthPackageIds   SBandwidthPackageIds
    59  	BusinessStatus        string
    60  	CreationTime          time.Time
    61  	ExpiredTime           time.Time
    62  	Description           string
    63  	ForwardTableIds       SForwardTableIds
    64  	SnatTableIds          SSnatTableIds
    65  	InstanceChargeType    TChargeType
    66  	Name                  string
    67  	NatGatewayId          string
    68  	RegionId              string
    69  	Spec                  string
    70  	Status                string
    71  	VpcId                 string
    72  	NatGatewayPrivateInfo NatGatewayPrivateInfo
    73  }
    74  
    75  func (nat *SNatGateway) GetId() string {
    76  	return nat.NatGatewayId
    77  }
    78  
    79  func (nat *SNatGateway) GetGlobalId() string {
    80  	return nat.NatGatewayId
    81  }
    82  
    83  func (nat *SNatGateway) GetName() string {
    84  	if len(nat.Name) > 0 {
    85  		return nat.Name
    86  	}
    87  	return nat.NatGatewayId
    88  }
    89  
    90  func (nat *SNatGateway) GetStatus() string {
    91  	switch nat.Status {
    92  	case "Initiating":
    93  		return api.NAT_STATUS_ALLOCATE
    94  	case "Available":
    95  		return api.NAT_STAUTS_AVAILABLE
    96  	case "Pending":
    97  		return api.NAT_STATUS_DEPLOYING
    98  	default:
    99  		return api.NAT_STATUS_UNKNOWN
   100  	}
   101  }
   102  
   103  func (self *SNatGateway) GetINetworkId() string {
   104  	return self.NatGatewayPrivateInfo.VswitchId
   105  }
   106  
   107  func (self *SNatGateway) GetIpAddr() string {
   108  	return self.NatGatewayPrivateInfo.PrivateIpAddress
   109  }
   110  
   111  func (self *SNatGateway) GetBandwidthMb() int {
   112  	return self.NatGatewayPrivateInfo.MaxBandwidth
   113  }
   114  
   115  func (self *SNatGateway) Delete() error {
   116  	return self.vpc.region.DeleteNatGateway(self.NatGatewayId, false)
   117  }
   118  
   119  func (nat *SNatGateway) GetBillingType() string {
   120  	return convertChargeType(nat.InstanceChargeType)
   121  }
   122  
   123  func (nat *SNatGateway) GetNatSpec() string {
   124  	if len(nat.Spec) == 0 {
   125  		return api.ALIYUN_NAT_SKU_DEFAULT
   126  	}
   127  	return nat.Spec
   128  }
   129  
   130  func (self *SNatGateway) Refresh() error {
   131  	nat, total, err := self.vpc.region.GetNatGateways("", self.NatGatewayId, 0, 1)
   132  	if err != nil {
   133  		return errors.Wrapf(err, "GetNatGateways")
   134  	}
   135  	if total > 1 {
   136  		return errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d natgateways by id %s", total, self.NatGatewayId)
   137  	}
   138  	if total == 0 {
   139  		return errors.Wrapf(cloudprovider.ErrNotFound, self.NatGatewayId)
   140  	}
   141  	return jsonutils.Update(self, nat[0])
   142  }
   143  
   144  func (nat *SNatGateway) GetCreatedAt() time.Time {
   145  	return nat.CreationTime
   146  }
   147  
   148  func (nat *SNatGateway) GetExpiredAt() time.Time {
   149  	return nat.ExpiredTime
   150  }
   151  
   152  func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) {
   153  	eips := []SEipAddress{}
   154  	for {
   155  		parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, "", len(eips), 50)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		eips = append(eips, parts...)
   160  		if len(eips) >= total {
   161  			break
   162  		}
   163  	}
   164  	ieips := []cloudprovider.ICloudEIP{}
   165  	for i := 0; i < len(eips); i++ {
   166  		eips[i].region = nat.vpc.region
   167  		ieips = append(ieips, &eips[i])
   168  	}
   169  	return ieips, nil
   170  }
   171  
   172  func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) {
   173  	itables := []cloudprovider.ICloudNatDEntry{}
   174  	for _, dtableId := range nat.ForwardTableIds.ForwardTableId {
   175  		dtables, err := nat.vpc.region.GetAllDTables(dtableId)
   176  		if err != nil {
   177  			return nil, err
   178  		}
   179  		for i := 0; i < len(dtables); i++ {
   180  			dtables[i].nat = nat
   181  			itables = append(itables, &dtables[i])
   182  		}
   183  	}
   184  	return itables, nil
   185  }
   186  
   187  func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) {
   188  	stables, err := nat.getSnatEntries()
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  	itables := []cloudprovider.ICloudNatSEntry{}
   193  	for i := 0; i < len(stables); i++ {
   194  		stables[i].nat = nat
   195  		itables = append(itables, &stables[i])
   196  	}
   197  	return itables, nil
   198  }
   199  
   200  func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) {
   201  	dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id)
   202  	if err != nil {
   203  		return nil, cloudprovider.ErrNotFound
   204  	}
   205  	dNATEntry.nat = nat
   206  	return &dNATEntry, nil
   207  }
   208  
   209  func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) {
   210  	sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id)
   211  	if err != nil {
   212  		return nil, cloudprovider.ErrNotFound
   213  	}
   214  	sNATEntry.nat = nat
   215  	return &sNATEntry, nil
   216  }
   217  
   218  func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) {
   219  	entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0])
   220  	if err != nil {
   221  		return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId())
   222  	}
   223  	return nat.GetINatDEntryByID(entryID)
   224  }
   225  
   226  func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) {
   227  	entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0])
   228  	if err != nil {
   229  		return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId())
   230  	}
   231  	return nat.GetINatSEntryByID(entryID)
   232  }
   233  
   234  func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGateway, int, error) {
   235  	if limit > 50 || limit <= 0 {
   236  		limit = 50
   237  	}
   238  	params := make(map[string]string)
   239  	params["RegionId"] = self.RegionId
   240  	params["PageSize"] = fmt.Sprintf("%d", limit)
   241  	params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
   242  	if len(vpcId) > 0 {
   243  		params["VpcId"] = vpcId
   244  	}
   245  	if len(natGwId) > 0 {
   246  		params["NatGatewayId"] = natGwId
   247  	}
   248  
   249  	body, err := self.vpcRequest("DescribeNatGateways", params)
   250  	if err != nil {
   251  		return nil, 0, errors.Wrapf(err, "DescribeNatGateways")
   252  	}
   253  
   254  	if self.client.debug {
   255  		log.Debugf("%s", body.PrettyString())
   256  	}
   257  
   258  	gateways := make([]SNatGateway, 0)
   259  	err = body.Unmarshal(&gateways, "NatGateways", "NatGateway")
   260  	if err != nil {
   261  		return nil, 0, errors.Wrapf(err, "body.Unmarshal")
   262  	}
   263  	total, _ := body.Int("TotalCount")
   264  	return gateways, int(total), nil
   265  }
   266  
   267  func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) {
   268  	nat, err := self.region.CreateNatGateway(opts)
   269  	if err != nil {
   270  		return nil, errors.Wrapf(err, "CreateNatGateway")
   271  	}
   272  	nat.vpc = self
   273  	return nat, nil
   274  }
   275  
   276  func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) {
   277  	params := map[string]string{
   278  		"RegionId":           self.RegionId,
   279  		"VpcId":              opts.VpcId,
   280  		"VSwitchId":          opts.NetworkId,
   281  		"NatType":            "Enhanced",
   282  		"Name":               opts.Name,
   283  		"Description":        opts.Desc,
   284  		"ClientToken":        utils.GenRequestId(20),
   285  		"InstanceChargeType": "PostPaid",
   286  		"InternetChargeType": "PayBySpec",
   287  	}
   288  	if len(opts.NatSpec) == 0 || opts.NatSpec == api.ALIYUN_NAT_SKU_DEFAULT {
   289  		params["InternetChargeType"] = "PayByLcu"
   290  	} else {
   291  		params["Spec"] = opts.NatSpec
   292  	}
   293  
   294  	if opts.BillingCycle != nil {
   295  		params["InstanceChargeType"] = "PrePaid"
   296  		params["PricingCycle"] = "Month"
   297  		params["AutoPay"] = "false"
   298  		if opts.BillingCycle.GetYears() > 0 {
   299  			params["PricingCycle"] = "Year"
   300  			params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetYears())
   301  		} else if opts.BillingCycle.GetMonths() > 0 {
   302  			params["PricingCycle"] = "Year"
   303  			params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths())
   304  		}
   305  		if opts.BillingCycle.AutoRenew {
   306  			params["AutoPay"] = "true"
   307  		}
   308  	}
   309  	resp, err := self.vpcRequest("CreateNatGateway", params)
   310  	if err != nil {
   311  		return nil, errors.Wrapf(err, "CreateNatGateway")
   312  	}
   313  	natId, err := resp.GetString("NatGatewayId")
   314  	if err != nil {
   315  		return nil, errors.Wrapf(err, "resp.Get(NatGatewayId)")
   316  	}
   317  	if len(natId) == 0 {
   318  		return nil, errors.Errorf("empty NatGatewayId after created")
   319  	}
   320  
   321  	var nat *SNatGateway = nil
   322  	err = cloudprovider.Wait(time.Second*5, time.Minute*15, func() (bool, error) {
   323  		nats, total, err := self.GetNatGateways("", natId, 0, 1)
   324  		if err != nil {
   325  			return false, errors.Wrapf(err, "GetNatGateways(%s)", natId)
   326  		}
   327  		if total > 1 {
   328  			return false, errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d nats", total)
   329  		}
   330  		if total == 0 {
   331  			return false, errors.Wrapf(cloudprovider.ErrNotFound, "search %s after %s created", opts.Name, natId)
   332  		}
   333  		nat = &nats[0]
   334  		return true, nil
   335  	})
   336  	if err != nil {
   337  		return nil, errors.Wrapf(err, "cloudprovider.Wait")
   338  	}
   339  
   340  	return nat, nil
   341  }
   342  
   343  func (self *SRegion) DeleteNatGateway(natId string, isForce bool) error {
   344  	params := map[string]string{
   345  		"RegionId":     self.RegionId,
   346  		"NatGatewayId": natId,
   347  	}
   348  	if isForce {
   349  		params["Force"] = "true"
   350  	}
   351  	_, err := self.vpcRequest("DeleteNatGateway", params)
   352  	return errors.Wrapf(err, "DeleteNatGateway")
   353  }
   354  
   355  func (self *SNatGateway) GetTags() (map[string]string, error) {
   356  	_, tags, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId)
   357  	if err != nil {
   358  		return nil, errors.Wrapf(err, "ListTags")
   359  	}
   360  	tagMaps := map[string]string{}
   361  	for k, v := range tags {
   362  		tagMaps[strings.ToLower(k)] = v
   363  	}
   364  	return tagMaps, nil
   365  }
   366  
   367  func (self *SNatGateway) GetSysTags() map[string]string {
   368  	tags, _, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId)
   369  	if err != nil {
   370  		return nil
   371  	}
   372  	tagMaps := map[string]string{}
   373  	for k, v := range tags {
   374  		tagMaps[strings.ToLower(k)] = v
   375  	}
   376  	return tagMaps
   377  }
   378  
   379  func (self *SNatGateway) SetTags(tags map[string]string, replace bool) error {
   380  	return self.vpc.region.SetResourceTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.GetId(), tags, replace)
   381  }