yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/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 hcso
    16  
    17  import (
    18  	"strings"
    19  	"time"
    20  
    21  	"yunion.io/x/jsonutils"
    22  	"yunion.io/x/pkg/errors"
    23  
    24  	billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
    25  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    26  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    27  	"yunion.io/x/cloudmux/pkg/multicloud"
    28  	"yunion.io/x/cloudmux/pkg/multicloud/huawei"
    29  )
    30  
    31  type SNatGateway struct {
    32  	multicloud.SNatGatewayBase
    33  	huawei.HuaweiTags
    34  	region *SRegion
    35  
    36  	ID                string
    37  	Name              string
    38  	Description       string
    39  	Spec              string
    40  	Status            string
    41  	InternalNetworkId string
    42  	CreatedTime       string `json:"created_at"`
    43  }
    44  
    45  func (gateway *SNatGateway) GetId() string {
    46  	return gateway.ID
    47  }
    48  
    49  func (gateway *SNatGateway) GetName() string {
    50  	return gateway.Name
    51  }
    52  
    53  func (gateway *SNatGateway) GetGlobalId() string {
    54  	return gateway.GetId()
    55  }
    56  
    57  func (gateway *SNatGateway) GetStatus() string {
    58  	return NatResouceStatusTransfer(gateway.Status)
    59  }
    60  
    61  func (self *SNatGateway) Delete() error {
    62  	return self.region.DeleteNatGateway(self.ID)
    63  }
    64  
    65  func (self *SNatGateway) Refresh() error {
    66  	nat, err := self.region.GetNatGateway(self.ID)
    67  	if err != nil {
    68  		return errors.Wrapf(err, "GetNatGateway(%s)", self.ID)
    69  	}
    70  	return jsonutils.Update(self, nat)
    71  }
    72  
    73  func (self *SNatGateway) GetINetworkId() string {
    74  	return self.InternalNetworkId
    75  }
    76  
    77  func (gateway *SNatGateway) GetNatSpec() string {
    78  	switch gateway.Spec {
    79  	case "1":
    80  		return api.NAT_SPEC_SMALL
    81  	case "2":
    82  		return api.NAT_SPEC_MIDDLE
    83  	case "3":
    84  		return api.NAT_SPEC_LARGE
    85  	case "4":
    86  		return api.NAT_SPEC_XLARGE
    87  	}
    88  	return gateway.Spec
    89  }
    90  
    91  func (gateway *SNatGateway) GetDescription() string {
    92  	return gateway.Description
    93  }
    94  
    95  func (gateway *SNatGateway) GetBillingType() string {
    96  	// Up to 2019.07.17, only support post pay
    97  	return billing_api.BILLING_TYPE_POSTPAID
    98  }
    99  
   100  func (gateway *SNatGateway) GetCreatedAt() time.Time {
   101  	t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime)
   102  	return t
   103  }
   104  
   105  func (gateway *SNatGateway) GetExpiredAt() time.Time {
   106  	// no support for expired time
   107  	return time.Time{}
   108  }
   109  
   110  func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) {
   111  	IEips, err := gateway.region.GetIEips()
   112  	if err != nil {
   113  		return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId())
   114  	}
   115  	dNatTables, err := gateway.GetINatDTable()
   116  	if err != nil {
   117  		return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId())
   118  	}
   119  	sNatTables, err := gateway.GetINatSTable()
   120  	if err != nil {
   121  		return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId())
   122  	}
   123  
   124  	// Get natIPSet of nat rules
   125  	natIPSet := make(map[string]struct{})
   126  	for _, snat := range sNatTables {
   127  		natIPSet[snat.GetIP()] = struct{}{}
   128  	}
   129  	for _, dnat := range dNatTables {
   130  		natIPSet[dnat.GetExternalIp()] = struct{}{}
   131  	}
   132  
   133  	// Add Eip whose GetIpAddr() in natIPSet to ret
   134  	ret := make([]cloudprovider.ICloudEIP, 0, 2)
   135  	for i := range IEips {
   136  		if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok {
   137  			ret = append(ret, IEips[i])
   138  		}
   139  	}
   140  	return ret, nil
   141  }
   142  
   143  func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) {
   144  	dNatTable, err := gateway.getNatDTable()
   145  	if err != nil {
   146  		return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId())
   147  	}
   148  	ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable))
   149  	for i := range dNatTable {
   150  		ret[i] = &dNatTable[i]
   151  	}
   152  	return ret, nil
   153  }
   154  
   155  func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) {
   156  	sNatTable, err := gateway.getNatSTable()
   157  	if err != nil {
   158  		return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId())
   159  	}
   160  	ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable))
   161  	for i := range sNatTable {
   162  		ret[i] = &sNatTable[i]
   163  	}
   164  	return ret, nil
   165  }
   166  
   167  func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) {
   168  	dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId())
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	dnat.gateway = gateway
   173  	return &dnat, nil
   174  }
   175  
   176  func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) {
   177  	snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId())
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	snat.gateway = gateway
   182  	return &snat, nil
   183  }
   184  
   185  func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) {
   186  	dnat, err := gateway.region.GetNatDEntryByID(id)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	dnat.gateway = gateway
   191  	return &dnat, nil
   192  }
   193  
   194  func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) {
   195  	snat, err := gateway.region.GetNatSEntryByID(id)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	snat.gateway = gateway
   200  	return &snat, nil
   201  }
   202  
   203  func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) {
   204  	queues := make(map[string]string)
   205  	if len(natGatewayID) != 0 {
   206  		queues["id"] = natGatewayID
   207  	}
   208  	if len(vpcID) != 0 {
   209  		queues["router_id"] = vpcID
   210  	}
   211  	natGateways := make([]SNatGateway, 0, 2)
   212  	err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways)
   213  	if err != nil {
   214  		return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid")
   215  	}
   216  	for i := range natGateways {
   217  		natGateways[i].region = region
   218  	}
   219  	return natGateways, nil
   220  }
   221  
   222  func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) {
   223  	params := make(map[string]interface{})
   224  	params["nat_gateway_id"] = gatewayID
   225  	params["private_ip"] = rule.InternalIP
   226  	params["internal_service_port"] = rule.InternalPort
   227  	params["floating_ip_id"] = rule.ExternalIPID
   228  	params["external_service_port"] = rule.ExternalPort
   229  	params["protocol"] = rule.Protocol
   230  
   231  	packParams := map[string]map[string]interface{}{
   232  		"dnat_rule": params,
   233  	}
   234  
   235  	ret := SNatDEntry{}
   236  	err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret)
   237  	if err != nil {
   238  		return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID)
   239  	}
   240  	return ret, nil
   241  }
   242  
   243  func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) {
   244  	params := make(map[string]interface{})
   245  	params["nat_gateway_id"] = gatewayID
   246  	if len(rule.NetworkID) != 0 {
   247  		params["network_id"] = rule.NetworkID
   248  	}
   249  	if len(rule.SourceCIDR) != 0 {
   250  		params["cidr"] = rule.SourceCIDR
   251  	}
   252  	params["floating_ip_id"] = rule.ExternalIPID
   253  
   254  	packParams := map[string]map[string]interface{}{
   255  		"snat_rule": params,
   256  	}
   257  
   258  	ret := SNatSEntry{}
   259  	err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret)
   260  	if err != nil {
   261  		return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID)
   262  	}
   263  	return ret, nil
   264  }
   265  
   266  func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) {
   267  	dnat := SNatDEntry{}
   268  	err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat)
   269  
   270  	if err != nil {
   271  		return SNatDEntry{}, err
   272  	}
   273  	return dnat, nil
   274  }
   275  
   276  func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) {
   277  	snat := SNatSEntry{}
   278  	err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat)
   279  	if err != nil {
   280  		return SNatSEntry{}, cloudprovider.ErrNotFound
   281  	}
   282  	return snat, nil
   283  }
   284  
   285  func NatResouceStatusTransfer(status string) string {
   286  	// In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE",
   287  	// "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE".
   288  	switch status {
   289  	case "ACTIVE":
   290  		return api.NAT_STAUTS_AVAILABLE
   291  	case "PENDING_CREATE":
   292  		return api.NAT_STATUS_ALLOCATE
   293  	case "PENDING_UPDATE", "PENDING_DELETE":
   294  		return api.NAT_STATUS_DEPLOYING
   295  	default:
   296  		return api.NAT_STATUS_UNKNOWN
   297  	}
   298  }
   299  
   300  func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) {
   301  	resp, err := self.ecsClient.NatGateways.Get(id, nil)
   302  	if err != nil {
   303  		return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id)
   304  	}
   305  	nat := &SNatGateway{region: self}
   306  	err = resp.Unmarshal(nat)
   307  	return nat, errors.Wrap(err, "resp.Unmarshal")
   308  }
   309  
   310  func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) {
   311  	nat, err := self.region.CreateNatGateway(opts)
   312  	if err != nil {
   313  		return nil, errors.Wrapf(err, "CreateNatGateway")
   314  	}
   315  	return nat, nil
   316  }
   317  
   318  func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) {
   319  	spec := ""
   320  	switch strings.ToLower(opts.NatSpec) {
   321  	case api.NAT_SPEC_SMALL:
   322  		spec = "1"
   323  	case api.NAT_SPEC_MIDDLE:
   324  		spec = "2"
   325  	case api.NAT_SPEC_LARGE:
   326  		spec = "3"
   327  	case api.NAT_SPEC_XLARGE:
   328  		spec = "4"
   329  	}
   330  	params := jsonutils.Marshal(map[string]map[string]interface{}{
   331  		"nat_gateway": map[string]interface{}{
   332  			"name":                opts.Name,
   333  			"description":         opts.Desc,
   334  			"router_id":           opts.VpcId,
   335  			"internal_network_id": opts.NetworkId,
   336  			"spec":                spec,
   337  		},
   338  	})
   339  	resp, err := self.ecsClient.NatGateways.Create(params)
   340  	if err != nil {
   341  		return nil, errors.Wrap(err, "AsyncCreate")
   342  	}
   343  	nat := &SNatGateway{region: self}
   344  	err = resp.Unmarshal(nat)
   345  	if err != nil {
   346  		return nil, errors.Wrapf(err, "resp.Unmarshal")
   347  	}
   348  	return nat, nil
   349  }
   350  
   351  func (self *SRegion) DeleteNatGateway(id string) error {
   352  	_, err := self.ecsClient.NatGateways.Delete(id, nil)
   353  	return errors.Wrapf(err, "NatGateways.Delete(%s)", id)
   354  }