yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/google/eip.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 google
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"yunion.io/x/jsonutils"
    22  	"yunion.io/x/log"
    23  	"yunion.io/x/pkg/errors"
    24  
    25  	billing "yunion.io/x/cloudmux/pkg/apis/billing"
    26  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    27  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    28  	"yunion.io/x/cloudmux/pkg/multicloud"
    29  )
    30  
    31  type SAddress struct {
    32  	region *SRegion
    33  	SResourceBase
    34  	multicloud.SEipBase
    35  	GoogleTags
    36  	instanceId string
    37  
    38  	CreationTimestamp time.Time
    39  	Description       string
    40  	Address           string
    41  	Status            string
    42  	Region            string
    43  	Users             []string
    44  	NetworkTier       string
    45  	AddressType       string
    46  	Kind              string
    47  }
    48  
    49  func (region *SRegion) GetEips(address string, maxResults int, pageToken string) ([]SAddress, error) {
    50  	eips := []SAddress{}
    51  	params := map[string]string{}
    52  	if len(address) > 0 {
    53  		params["filter"] = fmt.Sprintf(`address="%s"`, address)
    54  	}
    55  	resource := fmt.Sprintf("regions/%s/addresses", region.Name)
    56  	return eips, region.List(resource, params, maxResults, pageToken, &eips)
    57  }
    58  
    59  func (region *SRegion) GetEip(id string) (*SAddress, error) {
    60  	eip := &SAddress{region: region}
    61  	return eip, region.Get("addresses", id, eip)
    62  }
    63  
    64  func (addr *SAddress) GetStatus() string {
    65  	switch addr.Status {
    66  	case "RESERVING":
    67  		return api.EIP_STATUS_ASSOCIATE
    68  	case "RESERVED":
    69  		return api.EIP_STATUS_READY
    70  	case "IN_USE":
    71  		return api.EIP_STATUS_READY
    72  	default:
    73  		log.Errorf("Unknown eip status: %s", addr.Status)
    74  		return api.EIP_STATUS_UNKNOWN
    75  	}
    76  }
    77  
    78  func (addr *SAddress) GetProjectId() string {
    79  	return addr.region.GetProjectId()
    80  }
    81  
    82  func (addr *SAddress) IsEmulated() bool {
    83  	return len(addr.instanceId) > 0
    84  }
    85  
    86  func (addr *SAddress) GetCreatedAt() time.Time {
    87  	return addr.CreationTimestamp
    88  }
    89  
    90  func (addr *SAddress) GetExpiredAt() time.Time {
    91  	return time.Time{}
    92  }
    93  
    94  func (addr *SAddress) GetBillingType() string {
    95  	return billing.BILLING_TYPE_POSTPAID
    96  }
    97  
    98  func (self *SAddress) Refresh() error {
    99  	if self.IsEmulated() {
   100  		return nil
   101  	}
   102  	addr, err := self.region.GetEip(self.Id)
   103  	if err != nil {
   104  		return err
   105  	}
   106  	return jsonutils.Update(self, addr)
   107  }
   108  
   109  func (addr *SAddress) GetIpAddr() string {
   110  	return addr.Address
   111  }
   112  
   113  func (addr *SAddress) GetMode() string {
   114  	if addr.IsEmulated() {
   115  		return api.EIP_MODE_INSTANCE_PUBLICIP
   116  	}
   117  	return api.EIP_MODE_STANDALONE_EIP
   118  }
   119  
   120  func (addr *SAddress) GetINetworkId() string {
   121  	return ""
   122  }
   123  
   124  func (addr *SAddress) GetAssociationType() string {
   125  	if len(addr.GetAssociationExternalId()) > 0 {
   126  		return api.EIP_ASSOCIATE_TYPE_SERVER
   127  	}
   128  	return ""
   129  }
   130  
   131  func (addr *SAddress) GetAssociationExternalId() string {
   132  	if len(addr.instanceId) > 0 {
   133  		return addr.instanceId
   134  	}
   135  	if len(addr.Users) > 0 {
   136  		res := &SResourceBase{}
   137  		err := addr.region.GetBySelfId(addr.Users[0], res)
   138  		if err != nil {
   139  			return ""
   140  		}
   141  		return res.GetGlobalId()
   142  	}
   143  	return ""
   144  }
   145  
   146  func (addr *SAddress) GetBandwidth() int {
   147  	return 0
   148  }
   149  
   150  func (addr *SAddress) GetInternetChargeType() string {
   151  	return api.EIP_CHARGE_TYPE_BY_TRAFFIC
   152  }
   153  
   154  func (addr *SAddress) Delete() error {
   155  	return addr.region.Delete(addr.SelfLink)
   156  }
   157  
   158  func (addr *SAddress) Associate(conf *cloudprovider.AssociateConfig) error {
   159  	return addr.region.AssociateInstanceEip(conf.InstanceId, addr.Address)
   160  }
   161  
   162  func (addr *SAddress) Dissociate() error {
   163  	if len(addr.Users) > 0 {
   164  		return addr.region.DissociateInstanceEip(addr.Users[0], addr.Address)
   165  	}
   166  	return nil
   167  }
   168  
   169  func (addr *SAddress) ChangeBandwidth(bw int) error {
   170  	return cloudprovider.ErrNotSupported
   171  }
   172  
   173  func (region *SRegion) CreateEip(name string, desc string) (*SAddress, error) {
   174  	body := map[string]string{
   175  		"name":        name,
   176  		"description": desc,
   177  	}
   178  	resource := fmt.Sprintf("regions/%s/addresses", region.Name)
   179  	addr := &SAddress{region: region}
   180  	err := region.Insert(resource, jsonutils.Marshal(body), addr)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	return addr, nil
   185  }
   186  
   187  func (region *SRegion) AssociateInstanceEip(instanceId string, eip string) error {
   188  	instance, err := region.GetInstance(instanceId)
   189  	if err != nil {
   190  		return errors.Wrap(err, "region.GetInstance")
   191  	}
   192  	for _, networkInterface := range instance.NetworkInterfaces {
   193  		body := map[string]interface{}{
   194  			"type":  "ONE_TO_ONE_NAT",
   195  			"name":  "External NAT",
   196  			"natIP": eip,
   197  		}
   198  		params := map[string]string{"networkInterface": networkInterface.Name}
   199  		return region.Do(instance.SelfLink, "addAccessConfig", params, jsonutils.Marshal(body))
   200  	}
   201  	return fmt.Errorf("no valid networkinterface to associate")
   202  }
   203  
   204  func (self *SRegion) DissociateInstanceEip(instanceId string, eip string) error {
   205  	instance := SInstance{}
   206  	err := self.GetBySelfId(instanceId, &instance)
   207  	if err != nil {
   208  		return errors.Wrap(err, "region.GetInstance")
   209  	}
   210  	for _, networkInterface := range instance.NetworkInterfaces {
   211  		for _, accessConfig := range networkInterface.AccessConfigs {
   212  			if accessConfig.NatIP == eip {
   213  				body := map[string]string{}
   214  				params := map[string]string{
   215  					"networkInterface": networkInterface.Name,
   216  					"accessConfig":     accessConfig.Name,
   217  				}
   218  				return self.Do(instance.SelfLink, "deleteAccessConfig", params, jsonutils.Marshal(body))
   219  			}
   220  		}
   221  	}
   222  	return nil
   223  }