yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/google/loadbalancer_listener.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  	"context"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    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  )
    30  
    31  type SLoadbalancerListener struct {
    32  	lb             *SLoadbalancer
    33  	rules          []SLoadbalancerListenerRule
    34  	forwardRule    SForwardingRule    // 服务IP地址
    35  	backendService SBackendServices   //
    36  	httpProxy      *STargetHttpProxy  // http
    37  	httpsProxy     *STargetHttpsProxy // https
    38  	healthChecks   []HealthChecks
    39  
    40  	ForwardRuleName    string `json:"forward_rule_name"`
    41  	BackendServiceName string `json:"backend_service_name"`
    42  	Protocol           string `json:"protocol"`
    43  	Port               string `json:"port"` // 监听端口
    44  }
    45  
    46  func (self *SLoadbalancerListener) GetId() string {
    47  	return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetGlobalId(), self.backendService.GetGlobalId(), self.Port)
    48  }
    49  
    50  func (self *SLoadbalancerListener) GetName() string {
    51  	return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetName(), self.backendService.GetName(), self.Port)
    52  }
    53  
    54  func (self *SLoadbalancerListener) GetGlobalId() string {
    55  	return self.GetId()
    56  }
    57  
    58  func (self *SLoadbalancerListener) GetStatus() string {
    59  	return api.LB_STATUS_ENABLED
    60  }
    61  
    62  func (self *SLoadbalancerListener) Refresh() error {
    63  	return nil
    64  }
    65  
    66  func (self *SLoadbalancerListener) IsEmulated() bool {
    67  	return true
    68  }
    69  
    70  func (self *SLoadbalancerListener) GetCreatedAt() time.Time {
    71  	return time.Time{}
    72  }
    73  
    74  func (self *SLoadbalancerListener) GetSysTags() map[string]string {
    75  	return nil
    76  }
    77  
    78  func (self *SLoadbalancerListener) GetTags() (map[string]string, error) {
    79  	if len(self.forwardRule.IPAddress) > 0 {
    80  		return map[string]string{"FrontendIP": self.forwardRule.IPAddress}, nil
    81  	}
    82  
    83  	return map[string]string{}, nil
    84  }
    85  
    86  func (self *SLoadbalancerListener) SetTags(tags map[string]string, replace bool) error {
    87  	return cloudprovider.ErrNotSupported
    88  }
    89  
    90  func (self *SLoadbalancerListener) GetProjectId() string {
    91  	return self.lb.GetProjectId()
    92  }
    93  
    94  func (self *SLoadbalancerListener) GetListenerType() string {
    95  	return self.Protocol
    96  }
    97  
    98  func (self *SLoadbalancerListener) GetListenerPort() int {
    99  	port, err := strconv.Atoi(self.Port)
   100  	if err != nil {
   101  		log.Errorf("GetListenerPort %s", err)
   102  		return 0
   103  	}
   104  
   105  	return port
   106  }
   107  
   108  /*
   109  在本地范围内使用的负载均衡算法。可能的值为:
   110  
   111  ROUND_ROBIN:这是一个简单的策略,其中按循环顺序选择每个健康的后端。这是默认设置。
   112  LEAST_REQUEST:一种 O(1) 算法,它选择两个随机的健康主机并选择具有较少活动请求的主机。
   113  RING_HASH:环/模散列负载均衡器对后端实现一致的散列。该算法的特性是从一组 N 个主机中添加/删除一个主机只会影响 1/N 的请求。
   114  RANDOM:负载均衡器随机选择一个健康的主机。
   115  ORIGINAL_DESTINATION:根据客户端连接元数据选择后端主机,即在连接被重定向到负载均衡器之前,连接被打开到与传入连接的目标地址相同的地址。
   116  MAGLEV:用作环形哈希负载均衡器的替代品。Maglev 不如环哈希稳定,但具有更快的表查找构建时间和主机选择时间。有关磁悬浮的更多信息,请参阅https://ai.google/research/pubs/pub44824
   117  此字段适用于:
   118  
   119  service_protocol 设置为 HTTP、HTTPS 或 HTTP2,并且 load_balancing_scheme 设置为 INTERNAL_MANAGED 的区域后端服务。
   120  load_balancing_scheme 设置为 INTERNAL_SELF_MANAGED 的全局后端服务。
   121  如果 sessionAffinity 不为 NONE,并且该字段未设置为 MAGLEV 或 RING_HASH,则会话亲缘性设置不会生效。
   122  
   123  当后端服务被绑定到目标 gRPC 代理且 validateForProxyless 字段设置为 true 的 URL 映射引用时,仅支持默认的 ROUND_ROBIN 策略。
   124  */
   125  // todo: fix me ???
   126  func (self *SLoadbalancerListener) GetScheduler() string {
   127  	switch self.backendService.LocalityLBPolicy {
   128  	case "ROUND_ROBIN":
   129  		return api.LB_SCHEDULER_RR
   130  	case "LEAST_REQUEST":
   131  		return api.LB_SCHEDULER_WLC
   132  	case "RING_HASH":
   133  		return api.LB_SCHEDULER_QCH
   134  	case "ORIGINAL_DESTINATION":
   135  		return api.LB_SCHEDULER_SCH
   136  	case "MAGLEV":
   137  		return api.LB_SCHEDULER_MH
   138  	default:
   139  		return ""
   140  	}
   141  }
   142  
   143  func (self *SLoadbalancerListener) GetAclStatus() string {
   144  	return api.LB_BOOL_OFF
   145  }
   146  
   147  func (self *SLoadbalancerListener) GetAclType() string {
   148  	return ""
   149  }
   150  
   151  func (self *SLoadbalancerListener) GetAclId() string {
   152  	return ""
   153  }
   154  
   155  func (self *SLoadbalancerListener) GetEgressMbps() int {
   156  	return 0
   157  }
   158  
   159  func (self *SLoadbalancerListener) GetBackendGroupId() string {
   160  	return self.backendService.GetGlobalId()
   161  }
   162  
   163  func (self *SLoadbalancerListener) GetBackendServerPort() int {
   164  	igs, err := self.GetInstanceGroups()
   165  	if err != nil {
   166  		log.Errorf("GetInstanceGroups %s", err)
   167  		return 0
   168  	}
   169  
   170  	for i := range igs {
   171  		for j := range igs[i].NamedPorts {
   172  			if igs[i].NamedPorts[j].Name == self.backendService.PortName {
   173  				return int(igs[i].NamedPorts[j].Port)
   174  			}
   175  		}
   176  	}
   177  
   178  	return 0
   179  }
   180  
   181  func (self *SLoadbalancerListener) GetClientIdleTimeout() int {
   182  	return int(self.backendService.ConnectionDraining.DrainingTimeoutSEC)
   183  }
   184  
   185  func (self *SLoadbalancerListener) GetBackendConnectTimeout() int {
   186  	return int(self.backendService.TimeoutSEC)
   187  }
   188  
   189  func (self *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
   190  	return nil, cloudprovider.ErrNotImplemented
   191  }
   192  
   193  func (self *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
   194  	rules, err := self.GetLoadbalancerListenerRules()
   195  	if err != nil {
   196  		return nil, errors.Wrap(err, "GetLoadbalancerListenerRules")
   197  	}
   198  
   199  	for i := range rules {
   200  		if rules[i].GetGlobalId() == ruleId {
   201  			return &rules[i], nil
   202  		}
   203  	}
   204  
   205  	return nil, cloudprovider.ErrNotFound
   206  }
   207  
   208  func (self *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) {
   209  	rules, err := self.GetLoadbalancerListenerRules()
   210  	if err != nil {
   211  		return nil, errors.Wrap(err, "GetLoadbalancerListenerRules")
   212  	}
   213  
   214  	irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules))
   215  	for i := range rules {
   216  		irules[i] = &rules[i]
   217  	}
   218  
   219  	return irules, nil
   220  }
   221  
   222  func (self *SLoadbalancerListener) GetStickySession() string {
   223  	if self.backendService.SessionAffinity == "NONE" {
   224  		return api.LB_BOOL_OFF
   225  	} else {
   226  		return api.LB_BOOL_ON
   227  	}
   228  }
   229  
   230  /*
   231  https://cloud.google.com/load-balancing/docs/backend-service#sessionAffinity
   232  区域级外部 HTTP(S) 负载均衡器:
   233     无 (NONE)
   234     客户端 IP (CLIENT_IP)
   235     生成的 Cookie (GENERATED_COOKIE)
   236     标头字段 (HEADER_FIELD)
   237     HTTP Cookie (HTTP_COOKIE)
   238  */
   239  func (self *SLoadbalancerListener) GetStickySessionType() string {
   240  	switch self.backendService.SessionAffinity {
   241  	case "HTTP_COOKIE":
   242  		return api.LB_STICKY_SESSION_TYPE_SERVER
   243  	case "GENERATED_COOKIE":
   244  		return api.LB_STICKY_SESSION_TYPE_INSERT
   245  	}
   246  	return self.backendService.SessionAffinity
   247  }
   248  
   249  func (self *SLoadbalancerListener) GetStickySessionCookie() string {
   250  	return self.backendService.ConsistentHash.HTTPCookie.Name
   251  }
   252  
   253  func (self *SLoadbalancerListener) GetStickySessionCookieTimeout() int {
   254  	if len(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) == 0 {
   255  		return 0
   256  	}
   257  
   258  	sec, err := strconv.Atoi(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds)
   259  	if err != nil {
   260  		log.Debugf("GetStickySessionCookieTimeout %s", err)
   261  		return 0
   262  	}
   263  
   264  	return sec
   265  }
   266  
   267  // https://cloud.google.com/load-balancing/docs/https
   268  func (self *SLoadbalancerListener) XForwardedForEnabled() bool {
   269  	return true
   270  }
   271  
   272  // https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs
   273  func (self *SLoadbalancerListener) GzipEnabled() bool {
   274  	return false
   275  }
   276  
   277  func (self *SLoadbalancerListener) GetCertificateId() string {
   278  	if self.httpsProxy != nil && len(self.httpsProxy.SSLCertificates) > 0 {
   279  		cert := SResourceBase{
   280  			Name:     "",
   281  			SelfLink: self.httpsProxy.SSLCertificates[0],
   282  		}
   283  		return cert.GetGlobalId()
   284  	}
   285  
   286  	return ""
   287  }
   288  
   289  func (self *SLoadbalancerListener) GetTLSCipherPolicy() string {
   290  	return ""
   291  }
   292  
   293  // https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs
   294  func (self *SLoadbalancerListener) HTTP2Enabled() bool {
   295  	return true
   296  }
   297  
   298  // todo: fix me route
   299  // 高级配置才有重定向,具体怎么解析?
   300  func (self *SLoadbalancerListener) GetRedirect() string {
   301  	//self.lb.urlMap.PathMatchers[0].RouteRules[0].URLRedirect
   302  	return ""
   303  }
   304  
   305  func (self *SLoadbalancerListener) GetRedirectCode() int64 {
   306  	return 0
   307  }
   308  
   309  func (self *SLoadbalancerListener) GetRedirectScheme() string {
   310  	return ""
   311  }
   312  
   313  func (self *SLoadbalancerListener) GetRedirectHost() string {
   314  	return ""
   315  }
   316  
   317  func (self *SLoadbalancerListener) GetRedirectPath() string {
   318  	return ""
   319  }
   320  
   321  func (self *SLoadbalancerListener) GetHealthCheck() string {
   322  	if len(self.backendService.HealthChecks) > 0 {
   323  		return api.LB_BOOL_ON
   324  	} else {
   325  		return api.LB_BOOL_OFF
   326  	}
   327  }
   328  
   329  func (self *SLoadbalancerListener) GetHealthChecks() []HealthChecks {
   330  	if self.healthChecks != nil {
   331  		return self.healthChecks
   332  	}
   333  
   334  	hcm, err := self.lb.GetHealthCheckMaps()
   335  	if err != nil {
   336  		log.Errorf("GetHealthCheckMaps %s", err)
   337  		return nil
   338  	}
   339  	ret := make([]HealthChecks, 0)
   340  	for i := range self.backendService.HealthChecks {
   341  		hc := self.backendService.HealthChecks[i]
   342  		if _, ok := hcm[hc]; ok {
   343  			ret = append(ret, hcm[hc])
   344  		}
   345  	}
   346  
   347  	self.healthChecks = ret
   348  	return ret
   349  }
   350  
   351  func (self *SLoadbalancerListener) GetHealthCheckType() string {
   352  	hcs := self.GetHealthChecks()
   353  	if hcs == nil {
   354  		return ""
   355  	}
   356  
   357  	switch strings.ToLower(hcs[0].Type) {
   358  	case "tcp":
   359  		return api.LB_HEALTH_CHECK_TCP
   360  	case "udp":
   361  		return api.LB_HEALTH_CHECK_UDP
   362  	case "http", "http2":
   363  		return api.LB_HEALTH_CHECK_HTTP
   364  	case "https", "ssl":
   365  		return api.LB_HEALTH_CHECK_HTTPS
   366  	default:
   367  		return ""
   368  	}
   369  }
   370  
   371  func (self *SLoadbalancerListener) GetHealthCheckTimeout() int {
   372  	hcs := self.GetHealthChecks()
   373  	if hcs == nil {
   374  		return 0
   375  	}
   376  
   377  	return int(hcs[0].TimeoutSEC)
   378  }
   379  
   380  func (self *SLoadbalancerListener) GetHealthCheckInterval() int {
   381  	hcs := self.GetHealthChecks()
   382  	if hcs == nil {
   383  		return 0
   384  	}
   385  
   386  	return int(hcs[0].CheckIntervalSEC)
   387  }
   388  
   389  func (self *SLoadbalancerListener) GetHealthCheckRise() int {
   390  	hcs := self.GetHealthChecks()
   391  	if hcs == nil {
   392  		return 0
   393  	}
   394  
   395  	return int(hcs[0].HealthyThreshold)
   396  }
   397  
   398  func (self *SLoadbalancerListener) GetHealthCheckFail() int {
   399  	hcs := self.GetHealthChecks()
   400  	if hcs == nil {
   401  		return 0
   402  	}
   403  
   404  	return int(hcs[0].UnhealthyThreshold)
   405  }
   406  
   407  func (self *SLoadbalancerListener) GetHealthCheckReq() string {
   408  	return ""
   409  }
   410  
   411  func (self *SLoadbalancerListener) GetHealthCheckExp() string {
   412  	return ""
   413  }
   414  
   415  func (self *SLoadbalancerListener) GetHealthCheckDomain() string {
   416  	hcs := self.GetHealthChecks()
   417  	if hcs == nil {
   418  		return ""
   419  	}
   420  	switch hcs[0].Type {
   421  	case "HTTPS":
   422  		return hcs[0].HTTPSHealthCheck.Host
   423  	case "HTTP2":
   424  		return hcs[0].Http2HealthCheck.Host
   425  	case "HTTP":
   426  		return hcs[0].HTTPHealthCheck.Host
   427  	default:
   428  		return ""
   429  	}
   430  }
   431  
   432  func (self *SLoadbalancerListener) GetHealthCheckURI() string {
   433  	hcs := self.GetHealthChecks()
   434  	if hcs == nil {
   435  		return ""
   436  	}
   437  	switch hcs[0].Type {
   438  	case "HTTPS":
   439  		return hcs[0].HTTPSHealthCheck.RequestPath
   440  	case "HTTP2":
   441  		return hcs[0].Http2HealthCheck.RequestPath
   442  	case "HTTP":
   443  		return hcs[0].HTTPHealthCheck.RequestPath
   444  	default:
   445  		return ""
   446  	}
   447  }
   448  
   449  func (self *SLoadbalancerListener) GetHealthCheckCode() string {
   450  	return ""
   451  }
   452  
   453  func (self *SLoadbalancerListener) Start() error {
   454  	return cloudprovider.ErrNotSupported
   455  }
   456  
   457  func (self *SLoadbalancerListener) Stop() error {
   458  	return cloudprovider.ErrNotSupported
   459  }
   460  
   461  func (self *SLoadbalancerListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error {
   462  	return cloudprovider.ErrNotSupported
   463  }
   464  
   465  func (self *SLoadbalancerListener) Delete(ctx context.Context) error {
   466  	return cloudprovider.ErrNotSupported
   467  }
   468  
   469  func (self *SLoadbalancerListener) GetInstanceGroups() ([]SInstanceGroup, error) {
   470  	igs, err := self.lb.GetInstanceGroupsMap()
   471  	if err != nil {
   472  		return nil, errors.Wrap(err, "GetInstanceGroups")
   473  	}
   474  
   475  	ret := make([]SInstanceGroup, 0)
   476  	for i := range self.backendService.Backends {
   477  		b := self.backendService.Backends[i]
   478  		if ig, ok := igs[b.Group]; ok {
   479  			ret = append(ret, ig)
   480  		}
   481  	}
   482  
   483  	return ret, nil
   484  }
   485  
   486  func (self *SLoadbalancer) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
   487  	if self.urlMap != nil {
   488  		return self.GetHTTPLoadbalancerListeners()
   489  	} else {
   490  		return self.GetNetworkLoadbalancerListeners()
   491  	}
   492  }
   493  
   494  func (self *SLoadbalancer) GetHTTPLoadbalancerListeners() ([]SLoadbalancerListener, error) {
   495  	frs, err := self.GetForwardingRules()
   496  	if err != nil {
   497  		return nil, errors.Wrap(err, "GetForwardingRules")
   498  	}
   499  
   500  	_hps, err := self.GetTargetHttpProxies()
   501  	if err != nil {
   502  		return nil, errors.Wrap(err, "GetTargetHttpProxies")
   503  	}
   504  
   505  	hps := make(map[string]STargetHttpProxy, 0)
   506  	for i := range _hps {
   507  		hps[_hps[i].SelfLink] = _hps[i]
   508  	}
   509  
   510  	_hsps, err := self.GetTargetHttpsProxies()
   511  	if err != nil {
   512  		return nil, errors.Wrap(err, "GetTargetHttpsProxies")
   513  	}
   514  
   515  	hsps := make(map[string]STargetHttpsProxy, 0)
   516  	for i := range _hsps {
   517  		hsps[_hsps[i].SelfLink] = _hsps[i]
   518  	}
   519  
   520  	bss, err := self.GetBackendServices()
   521  	if err != nil {
   522  		return nil, errors.Wrap(err, "GetBackendServices")
   523  	}
   524  
   525  	lbls := make([]SLoadbalancerListener, 0)
   526  	for i := range frs {
   527  		fr := frs[i]
   528  		for j := range bss {
   529  			bs := bss[j]
   530  			port := "80"
   531  			protocol := "http"
   532  			var hp STargetHttpProxy
   533  			var hsp STargetHttpsProxy
   534  			if fr.PortRange == "443-443" {
   535  				port = "443"
   536  				hsp = hsps[fr.Target]
   537  				protocol = "https"
   538  			} else if fr.PortRange == "8080-8080" {
   539  				port = "8080"
   540  				hp = hps[fr.Target]
   541  			} else {
   542  				hp = hps[fr.Target]
   543  			}
   544  
   545  			lbl := SLoadbalancerListener{
   546  				lb:                 self,
   547  				forwardRule:        fr,
   548  				backendService:     bs,
   549  				httpProxy:          &hp,
   550  				httpsProxy:         &hsp,
   551  				ForwardRuleName:    fr.GetName(),
   552  				BackendServiceName: bs.GetName(),
   553  				Protocol:           protocol,
   554  				Port:               port,
   555  			}
   556  			lbls = append(lbls, lbl)
   557  		}
   558  	}
   559  
   560  	return lbls, nil
   561  }
   562  
   563  func (self *SLoadbalancer) GetNetworkLoadbalancerListeners() ([]SLoadbalancerListener, error) {
   564  	frs, err := self.GetForwardingRules()
   565  	if err != nil {
   566  		return nil, errors.Wrap(err, "GetForwardingRules")
   567  	}
   568  
   569  	bss, err := self.GetBackendServices()
   570  	if err != nil {
   571  		return nil, errors.Wrap(err, "GetBackendServices")
   572  	}
   573  
   574  	lbls := make([]SLoadbalancerListener, 0)
   575  	for i := range frs {
   576  		fr := frs[i]
   577  		for j := range bss {
   578  			bs := bss[j]
   579  			for n := range fr.Ports {
   580  				lbl := SLoadbalancerListener{
   581  					lb:                 self,
   582  					forwardRule:        fr,
   583  					backendService:     bs,
   584  					ForwardRuleName:    fr.GetName(),
   585  					BackendServiceName: bs.GetName(),
   586  					Protocol:           strings.ToLower(fr.IPProtocol),
   587  					Port:               fr.Ports[n],
   588  				}
   589  
   590  				lbls = append(lbls, lbl)
   591  			}
   592  		}
   593  	}
   594  
   595  	return lbls, nil
   596  }