yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/apsara/loadbalancer.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 apsara
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  	"time"
    22  
    23  	"yunion.io/x/jsonutils"
    24  	"yunion.io/x/log"
    25  	"yunion.io/x/pkg/errors"
    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 ListenerProtocol string
    33  
    34  const (
    35  	ListenerProtocolTCP   ListenerProtocol = "tcp"
    36  	ListenerProtocolUDP   ListenerProtocol = "udp"
    37  	ListenerProtocolHTTP  ListenerProtocol = "http"
    38  	ListenerProtocolHTTPS ListenerProtocol = "https"
    39  )
    40  
    41  type ListenerPorts struct {
    42  	ListenerPort []int
    43  }
    44  
    45  type ListenerPortsAndProtocol struct {
    46  	ListenerPortAndProtocol []ListenerPortAndProtocol
    47  }
    48  
    49  type ListenerPortAndProtocol struct {
    50  	Description      string
    51  	ListenerPort     int
    52  	ListenerProtocol ListenerProtocol
    53  }
    54  
    55  type BackendServers struct {
    56  	BackendServer []SLoadbalancerDefaultBackend
    57  }
    58  
    59  type SLoadbalancer struct {
    60  	multicloud.SLoadbalancerBase
    61  	ApsaraTags
    62  	region *SRegion
    63  
    64  	LoadBalancerId           string //负载均衡实例ID。
    65  	LoadBalancerName         string //负载均衡实例的名称。
    66  	LoadBalancerStatus       string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。
    67  	Address                  string //负载均衡实例的服务地址。
    68  	RegionId                 string //负载均衡实例的地域ID。
    69  	RegionIdAlias            string //负载均衡实例的地域名称。
    70  	AddressType              string //负载均衡实例的网络类型。
    71  	VSwitchId                string //私网负载均衡实例的交换机ID。
    72  	VpcId                    string //私网负载均衡实例的专有网络ID。
    73  	NetworkType              string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例
    74  	ListenerPorts            ListenerPorts
    75  	ListenerPortsAndProtocol ListenerPortsAndProtocol
    76  	BackendServers           BackendServers
    77  	CreateTime               time.Time           //负载均衡实例的创建时间。
    78  	MasterZoneId             string              //实例的主可用区ID。
    79  	SlaveZoneId              string              //实例的备可用区ID。
    80  	InternetChargeType       TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。
    81  	PayType                  string              //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费
    82  	LoadBalancerSpec         string              //负载均衡实例的的性能规格
    83  	Bandwidth                int                 //按带宽计费的公网型实例的带宽峰值
    84  	DepartmentInfo
    85  }
    86  
    87  func (lb *SLoadbalancer) GetName() string {
    88  	return lb.LoadBalancerName
    89  }
    90  
    91  func (lb *SLoadbalancer) GetId() string {
    92  	return lb.LoadBalancerId
    93  }
    94  
    95  func (lb *SLoadbalancer) GetGlobalId() string {
    96  	return lb.LoadBalancerId
    97  }
    98  
    99  func (lb *SLoadbalancer) GetStatus() string {
   100  	if lb.LoadBalancerStatus == "active" {
   101  		return api.LB_STATUS_ENABLED
   102  	}
   103  	return api.LB_STATUS_DISABLED
   104  }
   105  
   106  func (lb *SLoadbalancer) GetTags() (map[string]string, error) {
   107  	tags, err := lb.region.ListResourceTags("slb", "instance", []string{lb.GetId()})
   108  	if err != nil {
   109  		return nil, errors.Wrap(err, "lb.region.ListResourceTags")
   110  	}
   111  	if _, ok := tags[lb.GetId()]; !ok {
   112  		return map[string]string{}, nil
   113  	}
   114  	return *tags[lb.GetId()], nil
   115  }
   116  
   117  func (lb *SLoadbalancer) GetAddress() string {
   118  	return lb.Address
   119  }
   120  
   121  func (lb *SLoadbalancer) GetAddressType() string {
   122  	return lb.AddressType
   123  }
   124  
   125  func (lb *SLoadbalancer) GetNetworkType() string {
   126  	return lb.NetworkType
   127  }
   128  
   129  func (lb *SLoadbalancer) GetNetworkIds() []string {
   130  	return []string{lb.VSwitchId}
   131  }
   132  
   133  func (lb *SLoadbalancer) GetZoneId() string {
   134  	zone, err := lb.region.getZoneById(lb.MasterZoneId)
   135  	if err != nil {
   136  		log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err)
   137  		return ""
   138  	}
   139  	return zone.GetGlobalId()
   140  }
   141  
   142  func (self *SLoadbalancer) GetZone1Id() string {
   143  	return ""
   144  }
   145  
   146  func (lb *SLoadbalancer) IsEmulated() bool {
   147  	return false
   148  }
   149  
   150  func (lb *SLoadbalancer) GetVpcId() string {
   151  	return lb.VpcId
   152  }
   153  
   154  func (lb *SLoadbalancer) Refresh() error {
   155  	loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	return jsonutils.Update(lb, loadbalancer)
   160  }
   161  
   162  func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) {
   163  	params := map[string]string{}
   164  	params["RegionId"] = region.RegionId
   165  	if ids != nil && len(ids) > 0 {
   166  		params["LoadBalancerId"] = strings.Join(ids, ",")
   167  	}
   168  	body, err := region.lbRequest("DescribeLoadBalancers", params)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	lbs := []SLoadbalancer{}
   173  	return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer")
   174  }
   175  
   176  func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) {
   177  	params := map[string]string{}
   178  	params["RegionId"] = region.RegionId
   179  	params["LoadBalancerId"] = loadbalancerId
   180  	body, err := region.lbRequest("DescribeLoadBalancerAttribute", params)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	lb := SLoadbalancer{region: region}
   185  	return &lb, body.Unmarshal(&lb)
   186  }
   187  
   188  func (lb *SLoadbalancer) Delete(ctx context.Context) error {
   189  	params := map[string]string{}
   190  	params["RegionId"] = lb.region.RegionId
   191  	params["LoadBalancerId"] = lb.LoadBalancerId
   192  	_, err := lb.region.lbRequest("DeleteLoadBalancer", params)
   193  	return err
   194  }
   195  
   196  func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) {
   197  	ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{}
   198  	{
   199  		backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId)
   200  		if err != nil {
   201  			return nil, err
   202  		}
   203  
   204  		for i := 0; i < len(backendgroups); i++ {
   205  			backendgroups[i].lb = lb
   206  			ibackendgroups = append(ibackendgroups, &backendgroups[i])
   207  		}
   208  	}
   209  	{
   210  		iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb}
   211  		ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup)
   212  
   213  	}
   214  	{
   215  		backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId)
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  		for i := 0; i < len(backendgroups); i++ {
   220  			backendgroups[i].lb = lb
   221  			ibackendgroups = append(ibackendgroups, &backendgroups[i])
   222  		}
   223  	}
   224  	return ibackendgroups, nil
   225  }
   226  
   227  func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
   228  	switch group.GroupType {
   229  	case api.LB_BACKENDGROUP_TYPE_NORMAL:
   230  		group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends)
   231  		if err != nil {
   232  			return nil, err
   233  		}
   234  		group.lb = lb
   235  		return group, nil
   236  	case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE:
   237  		group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends)
   238  		if err != nil {
   239  			return nil, err
   240  		}
   241  		group.lb = lb
   242  		return group, nil
   243  	default:
   244  		return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType)
   245  	}
   246  }
   247  
   248  func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) {
   249  	switch listener.ListenerType {
   250  	case api.LB_LISTENER_TYPE_TCP:
   251  		return lb.region.CreateLoadbalancerTCPListener(lb, listener)
   252  	case api.LB_LISTENER_TYPE_UDP:
   253  		return lb.region.CreateLoadbalancerUDPListener(lb, listener)
   254  	case api.LB_LISTENER_TYPE_HTTP:
   255  		return lb.region.CreateLoadbalancerHTTPListener(lb, listener)
   256  	case api.LB_LISTENER_TYPE_HTTPS:
   257  		return lb.region.CreateLoadbalancerHTTPSListener(lb, listener)
   258  	}
   259  	return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType)
   260  }
   261  
   262  func (lb *SLoadbalancer) GetLoadbalancerSpec() string {
   263  	if len(lb.LoadBalancerSpec) == 0 {
   264  		lb.Refresh()
   265  	}
   266  	return lb.LoadBalancerSpec
   267  }
   268  
   269  func (lb *SLoadbalancer) GetChargeType() string {
   270  	switch lb.InternetChargeType {
   271  	case "paybybandwidth":
   272  		return api.LB_CHARGE_TYPE_BY_BANDWIDTH
   273  	case "paybytraffic":
   274  		return api.LB_CHARGE_TYPE_BY_TRAFFIC
   275  	}
   276  	return "unknown"
   277  }
   278  
   279  func (lb *SLoadbalancer) GetCreatedAt() time.Time {
   280  	return lb.CreateTime
   281  }
   282  
   283  func (lb *SLoadbalancer) GetEgressMbps() int {
   284  	if lb.Bandwidth < 1 {
   285  		return 0
   286  	}
   287  	return lb.Bandwidth
   288  }
   289  
   290  func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
   291  	groups, err := lb.GetILoadBalancerBackendGroups()
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	for i := 0; i < len(groups); i++ {
   296  		if groups[i].GetGlobalId() == groupId {
   297  			return groups[i], nil
   298  		}
   299  	}
   300  	return nil, cloudprovider.ErrNotFound
   301  }
   302  
   303  func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) {
   304  	if lb.AddressType == "internet" {
   305  		eip := SEipAddress{
   306  			region:             lb.region,
   307  			IpAddress:          lb.Address,
   308  			InstanceId:         lb.GetGlobalId(),
   309  			InstanceType:       EIP_INTANNCE_TYPE_SLB,
   310  			Status:             EIP_STATUS_INUSE,
   311  			AllocationId:       lb.GetGlobalId(),
   312  			AllocationTime:     lb.CreateTime,
   313  			Bandwidth:          lb.Bandwidth,
   314  			InternetChargeType: lb.InternetChargeType,
   315  		}
   316  		return &eip, nil
   317  	}
   318  	eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, 0, 1)
   319  	if err != nil {
   320  		return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId)
   321  	}
   322  	if total != 1 {
   323  		return nil, cloudprovider.ErrNotFound
   324  	}
   325  	eips[0].region = lb.region
   326  	return &eips[0], nil
   327  }
   328  
   329  func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error {
   330  	params := map[string]string{}
   331  	params["RegionId"] = region.RegionId
   332  	params["LoadBalancerId"] = loadbalancerId
   333  	params["LoadBalancerStatus"] = status
   334  	_, err := region.lbRequest("SetLoadBalancerStatus", params)
   335  	return err
   336  }
   337  
   338  func (lb *SLoadbalancer) Start() error {
   339  	if lb.LoadBalancerStatus != "active" {
   340  		return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active")
   341  	}
   342  	return nil
   343  }
   344  
   345  func (lb *SLoadbalancer) Stop() error {
   346  	if lb.LoadBalancerStatus != "inactive" {
   347  		return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive")
   348  	}
   349  	return nil
   350  }
   351  
   352  func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) {
   353  	listener, err := lb.GetILoadBalancerListeners()
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	for i := 0; i < len(listener); i++ {
   358  		if listener[i].GetGlobalId() == listenerId {
   359  			return listener[i], nil
   360  		}
   361  	}
   362  	return nil, cloudprovider.ErrNotFound
   363  }
   364  
   365  func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) {
   366  	loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId)
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  	listeners := []cloudprovider.ICloudLoadbalancerListener{}
   371  	for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol {
   372  		switch listenerInfo.ListenerProtocol {
   373  		case ListenerProtocolHTTP:
   374  			listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
   375  			if err != nil {
   376  				return nil, err
   377  			}
   378  			listener.lb = lb
   379  			listeners = append(listeners, listener)
   380  		case ListenerProtocolHTTPS:
   381  			listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
   382  			if err != nil {
   383  				return nil, err
   384  			}
   385  			listener.lb = lb
   386  			listeners = append(listeners, listener)
   387  		case ListenerProtocolTCP:
   388  			listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
   389  			if err != nil {
   390  				return nil, err
   391  			}
   392  			listener.lb = lb
   393  			listeners = append(listeners, listener)
   394  		case ListenerProtocolUDP:
   395  			listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort)
   396  			if err != nil {
   397  				return nil, err
   398  			}
   399  			listener.lb = lb
   400  			listeners = append(listeners, listener)
   401  		default:
   402  			return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol)
   403  		}
   404  	}
   405  	return listeners, nil
   406  }
   407  
   408  func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error {
   409  	return lb.region.SetResourceTags("slb", "instance", []string{lb.LoadBalancerId}, tags, replace)
   410  }