yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/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 qcloud
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    24  	"yunion.io/x/jsonutils"
    25  
    26  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    27  	"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
    28  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    29  	"yunion.io/x/cloudmux/pkg/multicloud"
    30  )
    31  
    32  var HTTP_CODES = []string{
    33  	api.LB_HEALTH_CHECK_HTTP_CODE_1xx,
    34  	api.LB_HEALTH_CHECK_HTTP_CODE_2xx,
    35  	api.LB_HEALTH_CHECK_HTTP_CODE_3xx,
    36  	api.LB_HEALTH_CHECK_HTTP_CODE_4xx,
    37  	api.LB_HEALTH_CHECK_HTTP_CODE_5xx,
    38  }
    39  
    40  const (
    41  	PROTOCOL_TCP     = "TCP"
    42  	PROTOCOL_UDP     = "UDP"
    43  	PROTOCOL_TCP_SSL = "TCP_SSL"
    44  	PROTOCOL_HTTP    = "HTTP"
    45  	PROTOCOL_HTTPS   = "HTTPS"
    46  )
    47  
    48  type certificate struct {
    49  	SSLMode  string `json:"SSLMode"`
    50  	CERTCAID string `json:"CertCaId"`
    51  	CERTID   string `json:"CertId"`
    52  }
    53  
    54  /*
    55  健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。
    56  1 表示探测后返回值 1xx 表示健康,2 表示返回 2xx 表示健康,4 表示返回 3xx 表示健康,8 表示返回 4xx 表示健康,16 表示返回 5xx 表示健康。
    57  若希望多种码都表示健康,则将相应的值相加。
    58  */
    59  type healthCheck struct {
    60  	HTTPCheckDomain string `json:"HttpCheckDomain"`
    61  	HealthSwitch    int    `json:"HealthSwitch"`
    62  	HTTPCheckPath   string `json:"HttpCheckPath"`
    63  	HTTPCheckMethod string `json:"HttpCheckMethod"`
    64  	UnHealthNum     int    `json:"UnHealthNum"`
    65  	IntervalTime    int    `json:"IntervalTime"`
    66  	HTTPCode        int    `json:"HttpCode"` // 健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。
    67  	HealthNum       int    `json:"HealthNum"`
    68  	TimeOut         int    `json:"TimeOut"`
    69  }
    70  
    71  type SLBListener struct {
    72  	multicloud.SResourceBase
    73  	multicloud.SLoadbalancerRedirectBase
    74  	QcloudTags
    75  	lb *SLoadbalancer
    76  
    77  	Protocol          string            `json:"Protocol"` // 监听器协议类型,取值 TCP | UDP | HTTP | HTTPS | TCP_SSL
    78  	Certificate       certificate       `json:"Certificate"`
    79  	SniSwitch         int64             `json:"SniSwitch"`   // 是否开启SNI特性(本参数仅对于HTTPS监听器有意义)
    80  	HealthCheck       healthCheck       `json:"HealthCheck"` // 仅适用于TCP/UDP/TCP_SSL监听器
    81  	ListenerID        string            `json:"ListenerId"`
    82  	ListenerName      string            `json:"ListenerName"`
    83  	Rules             []SLBListenerRule `json:"Rules"` // 监听器下的全部转发规则(本参数仅对于HTTP/HTTPS监听器有意义)
    84  	Scheduler         string            `json:"Scheduler"`
    85  	SessionExpireTime int               `json:"SessionExpireTime"` // 会话保持时间,单位:秒。可选值:30~3600,默认 0,表示不开启。此参数仅适用于TCP/UDP监听器。
    86  	Port              int               `json:"Port"`
    87  	ClassicListener   bool              // 这个字段是在qcloud返回字段基础上,额外增加的字段。用于区分listener 是否是classic。
    88  }
    89  
    90  // 腾讯云后端端口不是与listener绑定的
    91  func (self *SLBListener) GetBackendServerPort() int {
    92  	return 0
    93  }
    94  
    95  // https://cloud.tencent.com/document/product/214/30691
    96  func (self *SLBListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
    97  	hc := getListenerRuleHealthCheck(rule)
    98  	requestId, err := self.lb.region.CreateLoadbalancerListenerRule(self.lb.GetId(),
    99  		self.GetId(),
   100  		rule.Domain,
   101  		rule.Path,
   102  		rule.Scheduler,
   103  		rule.StickySessionCookieTimeout,
   104  		hc)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	err = self.Refresh()
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	for _, r := range self.Rules {
   120  		if r.GetPath() == rule.Path {
   121  			r.listener = self
   122  			return &r, nil
   123  		}
   124  	}
   125  
   126  	return nil, cloudprovider.ErrNotFound
   127  }
   128  
   129  func (self *SLBListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
   130  	rules, err := self.GetILoadbalancerListenerRules()
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	for _, rule := range rules {
   136  		if rule.GetId() == ruleId {
   137  			return rule, nil
   138  		}
   139  	}
   140  
   141  	return nil, cloudprovider.ErrNotFound
   142  }
   143  
   144  func (self *SLBListener) Start() error {
   145  	return nil
   146  }
   147  
   148  func (self *SLBListener) Stop() error {
   149  	return cloudprovider.ErrNotSupported
   150  }
   151  
   152  // https://cloud.tencent.com/document/product/214/30677
   153  func (self *SLBListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error {
   154  	lockman.LockRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId)
   155  	defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId)
   156  
   157  	hc := getHealthCheck(listener)
   158  	cert := getCertificate(listener)
   159  	requestId, err := self.lb.region.UpdateLoadbalancerListener(
   160  		self.lb.Forward,
   161  		self.lb.GetId(),
   162  		self.GetId(),
   163  		&listener.Name,
   164  		getScheduler(listener),
   165  		&listener.StickySessionCookieTimeout,
   166  		hc,
   167  		cert)
   168  	if err != nil {
   169  		return err
   170  	}
   171  
   172  	return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
   173  }
   174  
   175  func (self *SLBListener) Delete(ctx context.Context) error {
   176  	lockman.LockRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId)
   177  	defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId)
   178  
   179  	requestId, err := self.lb.region.DeleteLoadbalancerListener(self.lb.Forward, self.lb.GetId(), self.GetId())
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second)
   185  }
   186  
   187  // https://cloud.tencent.com/document/api/214/30694#ClassicalListener
   188  type SLBClassicListener struct {
   189  	InstancePort  int64  `json:"InstancePort"`
   190  	CERTCAID      string `json:"CertCaId"`
   191  	Status        int64  `json:"Status"`
   192  	CERTID        string `json:"CertId"`
   193  	Protocol      string `json:"Protocol"`
   194  	TimeOut       int    `json:"TimeOut"`
   195  	HTTPHash      string `json:"HttpHash"` // 公网固定IP型的 HTTP、HTTPS 协议监听器的轮询方法。wrr 表示按权重轮询,ip_hash 表示根据访问的源 IP 进行一致性哈希方式来分发
   196  	UnhealthNum   int    `json:"UnhealthNum"`
   197  	IntervalTime  int    `json:"IntervalTime"`
   198  	ListenerID    string `json:"ListenerId"`
   199  	ListenerPort  int    `json:"ListenerPort"`
   200  	HTTPCheckPath string `json:"HttpCheckPath"`
   201  	HealthNum     int    `json:"HealthNum"`
   202  	ListenerName  string `json:"ListenerName"`
   203  	HealthSwitch  int    `json:"HealthSwitch"`
   204  	SSLMode       string `json:"SSLMode"`
   205  	SessionExpire int    `json:"SessionExpire"`
   206  	HTTPCode      int    `json:"HttpCode"`
   207  }
   208  
   209  func (self *SLBClassicListener) ToLBListener() SLBListener {
   210  	// 转换之后丢弃了 InstancePort、Status、HttpHash
   211  	return SLBListener{
   212  		Protocol: self.Protocol,
   213  		Certificate: certificate{
   214  			SSLMode:  self.SSLMode,
   215  			CERTCAID: self.CERTCAID,
   216  			CERTID:   self.CERTID,
   217  		},
   218  		HealthCheck: healthCheck{
   219  			HTTPCheckDomain: "",
   220  			HealthSwitch:    self.HealthSwitch,
   221  			HTTPCheckPath:   self.HTTPCheckPath,
   222  			HTTPCheckMethod: "",
   223  			UnHealthNum:     self.UnhealthNum,
   224  			IntervalTime:    self.IntervalTime,
   225  			HTTPCode:        self.HTTPCode,
   226  			HealthNum:       self.HealthNum,
   227  			TimeOut:         self.TimeOut,
   228  		},
   229  		ListenerID:        self.ListenerID,
   230  		ListenerName:      self.ListenerName,
   231  		Rules:             nil,
   232  		Scheduler:         self.HTTPHash,
   233  		SessionExpireTime: self.SessionExpire,
   234  		Port:              self.ListenerPort,
   235  		ClassicListener:   true,
   236  	}
   237  }
   238  
   239  func (self *SLBListener) GetId() string {
   240  	return self.ListenerID
   241  }
   242  
   243  func (self *SLBListener) GetName() string {
   244  	return self.ListenerName
   245  }
   246  
   247  func (self *SLBListener) GetGlobalId() string {
   248  	return self.ListenerID
   249  }
   250  
   251  // 腾讯云负载均衡没有启用禁用操作
   252  func (self *SLBListener) GetStatus() string {
   253  	return api.LB_STATUS_ENABLED
   254  }
   255  
   256  func (self *SLBListener) Refresh() error {
   257  	listeners, err := self.lb.region.GetLoadbalancerListeners(self.lb.GetId(), self.lb.Forward, "")
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	for _, listener := range listeners {
   263  		if listener.GetId() == self.GetId() {
   264  			listener.lb = self.lb
   265  			err := jsonutils.Update(self, listener)
   266  			if err != nil {
   267  				return err
   268  			}
   269  
   270  			return nil
   271  		}
   272  	}
   273  
   274  	return cloudprovider.ErrNotFound
   275  }
   276  
   277  func (self *SLBListener) IsEmulated() bool {
   278  	return false
   279  }
   280  
   281  func (self *SLBListener) GetEgressMbps() int {
   282  	return 0
   283  }
   284  
   285  func (self *SLBListener) GetListenerType() string {
   286  	switch self.Protocol {
   287  	case PROTOCOL_TCP:
   288  		return api.LB_LISTENER_TYPE_TCP
   289  	case PROTOCOL_UDP:
   290  		return api.LB_LISTENER_TYPE_UDP
   291  	case PROTOCOL_HTTP:
   292  		return api.LB_LISTENER_TYPE_HTTP
   293  	case PROTOCOL_HTTPS:
   294  		return api.LB_LISTENER_TYPE_HTTPS
   295  	case PROTOCOL_TCP_SSL:
   296  		return api.LB_LISTENER_TYPE_TCP
   297  	default:
   298  		return ""
   299  	}
   300  }
   301  
   302  func (self *SLBListener) GetListenerPort() int {
   303  	return self.Port
   304  }
   305  
   306  func (self *SLBListener) GetScheduler() string {
   307  	switch strings.ToLower(self.Scheduler) {
   308  	case "wrr":
   309  		return api.LB_SCHEDULER_WRR
   310  	case "ip_hash":
   311  		return api.LB_SCHEDULER_SCH
   312  	case "least_conn":
   313  		return api.LB_SCHEDULER_WLC
   314  	default:
   315  		return ""
   316  	}
   317  }
   318  
   319  func (self *SLBListener) GetAclStatus() string {
   320  	return api.LB_BOOL_OFF
   321  }
   322  
   323  func (self *SLBListener) GetAclType() string {
   324  	return ""
   325  }
   326  
   327  func (self *SLBListener) GetAclId() string {
   328  	return ""
   329  }
   330  
   331  func (self *SLBListener) GetHealthCheck() string {
   332  	if self.HealthCheck.HealthSwitch == 0 {
   333  		return api.LB_BOOL_OFF
   334  	} else {
   335  		return api.LB_BOOL_ON
   336  	}
   337  }
   338  
   339  func (self *SLBListener) GetHealthCheckType() string {
   340  	if len(self.HealthCheck.HTTPCheckMethod) > 0 {
   341  		return api.LB_HEALTH_CHECK_HTTP
   342  	} else {
   343  		return api.LB_HEALTH_CHECK_TCP
   344  	}
   345  }
   346  
   347  func (self *SLBListener) GetHealthCheckTimeout() int {
   348  	return self.HealthCheck.TimeOut
   349  }
   350  
   351  func (self *SLBListener) GetHealthCheckInterval() int {
   352  	return self.HealthCheck.IntervalTime
   353  }
   354  
   355  func (self *SLBListener) GetHealthCheckRise() int {
   356  	return self.HealthCheck.HealthNum
   357  }
   358  
   359  func (self *SLBListener) GetHealthCheckFail() int {
   360  	return self.HealthCheck.UnHealthNum
   361  }
   362  
   363  func (self *SLBListener) GetHealthCheckReq() string {
   364  	return ""
   365  }
   366  
   367  func (self *SLBListener) GetHealthCheckExp() string {
   368  	return ""
   369  }
   370  
   371  func (self *SLBListener) GetBackendGroup() *SLBBackendGroup {
   372  	t := self.GetListenerType()
   373  	// http、https类型的监听不能直接绑定服务器
   374  	if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS {
   375  		return nil
   376  	} else {
   377  		return &SLBBackendGroup{lb: self.lb, listener: self}
   378  	}
   379  }
   380  
   381  func (self *SLBListener) GetBackendGroupId() string {
   382  	bg := self.GetBackendGroup()
   383  	if bg == nil {
   384  		return ""
   385  	}
   386  
   387  	return bg.GetId()
   388  }
   389  
   390  func (self *SLBListener) GetHealthCheckDomain() string {
   391  	return self.HealthCheck.HTTPCheckDomain
   392  }
   393  
   394  func (self *SLBListener) GetHealthCheckURI() string {
   395  	return self.HealthCheck.HTTPCheckPath
   396  }
   397  
   398  func (self *SLBListener) GetHealthCheckCode() string {
   399  	codes := []string{}
   400  	for i := uint8(0); i < 5; i++ {
   401  		n := 1 << i
   402  		if (self.HealthCheck.HTTPCode & n) == n {
   403  			codes = append(codes, HTTP_CODES[i])
   404  		}
   405  	}
   406  
   407  	return strings.Join(codes, ",")
   408  }
   409  
   410  // 仅http、https类型监听包含rules
   411  func (self *SLBListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) {
   412  	rules := self.Rules
   413  	iRules := []cloudprovider.ICloudLoadbalancerListenerRule{}
   414  	for i := 0; i < len(rules); i++ {
   415  		rules[i].listener = self
   416  		iRules = append(iRules, &rules[i])
   417  	}
   418  	return iRules, nil
   419  }
   420  
   421  func (self *SLBListener) GetStickySession() string {
   422  	if self.SessionExpireTime == 0 {
   423  		return api.LB_BOOL_OFF
   424  	} else {
   425  		return api.LB_BOOL_ON
   426  	}
   427  }
   428  
   429  // 支持基于 cookie 插入的会话保持能力 https://cloud.tencent.com/document/product/214/6154
   430  func (self *SLBListener) GetStickySessionType() string {
   431  	return api.LB_STICKY_SESSION_TYPE_INSERT
   432  }
   433  
   434  // https://cloud.tencent.com/document/product/214/2736
   435  // 经测试应用型负载均衡返回都是 tgw_l7_route。
   436  func (self *SLBListener) GetStickySessionCookie() string {
   437  	if self.GetListenerType() == api.LB_LISTENER_TYPE_HTTPS {
   438  		return "tgw_l7_route"
   439  	}
   440  
   441  	return ""
   442  }
   443  
   444  func (self *SLBListener) GetStickySessionCookieTimeout() int {
   445  	return self.SessionExpireTime
   446  }
   447  
   448  /*
   449  7层负载均衡系统提供 X-Forwarded-For 的方式获取访问者真实 IP,LB 侧默认开启
   450  
   451  https://cloud.tencent.com/document/product/214/6151
   452  七层转发获取来访真实IP的方法 https://cloud.tencent.com/document/product/214/3728
   453  */
   454  func (self *SLBListener) XForwardedForEnabled() bool {
   455  	switch self.GetListenerType() {
   456  	case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS:
   457  		return true
   458  	default:
   459  		return false
   460  	}
   461  }
   462  
   463  // HTTP/HTTPS协议默认支持用户开启gzip压缩功能
   464  // 负载均衡开启Gzip配置及检测方法说明 https://cloud.tencent.com/document/product/214/5404
   465  func (self *SLBListener) GzipEnabled() bool {
   466  	switch self.GetListenerType() {
   467  	case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS:
   468  		return true
   469  	default:
   470  		return false
   471  	}
   472  }
   473  
   474  func (self *SLBListener) GetCertificateId() string {
   475  	return self.Certificate.CERTID
   476  }
   477  
   478  // https://cloud.tencent.com/document/product/214/5412#2.-https.E6.94.AF.E6.8C.81.E5.93.AA.E4.BA.9B.E7.89.88.E6.9C.AC.E7.9A.84ssl.2Ftls.E5.AE.89.E5.85.A8.E5.8D.8F.E8.AE.AE.EF.BC.9F
   479  func (self *SLBListener) GetTLSCipherPolicy() string {
   480  	return ""
   481  }
   482  
   483  // 负载均衡能力说明 https://cloud.tencent.com/document/product/214/6534
   484  func (self *SLBListener) HTTP2Enabled() bool {
   485  	return true
   486  }
   487  
   488  func (self *SRegion) GetLoadbalancerListeners(lbid string, t LB_TYPE, protocol string) ([]SLBListener, error) {
   489  	params := map[string]string{"LoadBalancerId": lbid}
   490  	if len(protocol) > 0 {
   491  		params["Protocol"] = protocol
   492  	}
   493  
   494  	listeners := []SLBListener{}
   495  	if t == LB_TYPE_CLASSIC {
   496  		resp, err := self.clbRequest("DescribeClassicalLBListeners", params)
   497  		if err != nil {
   498  			return nil, err
   499  		}
   500  
   501  		clisteners := []SLBClassicListener{}
   502  		err = resp.Unmarshal(&clisteners, "Listeners")
   503  		if err != nil {
   504  			return nil, err
   505  		}
   506  
   507  		for _, l := range clisteners {
   508  			listeners = append(listeners, l.ToLBListener())
   509  		}
   510  
   511  		return listeners, nil
   512  	}
   513  
   514  	resp, err := self.clbRequest("DescribeListeners", params)
   515  	if err != nil {
   516  		return nil, err
   517  	}
   518  
   519  	err = resp.Unmarshal(&listeners, "Listeners")
   520  	if err != nil {
   521  		return nil, err
   522  	}
   523  
   524  	return listeners, nil
   525  }
   526  
   527  //  返回requestID
   528  func (self *SRegion) CreateLoadbalancerListenerRule(lbid string, listenerId string, domain string, url string, scheduler string, sessionExpireTime int, hc *healthCheck) (string, error) {
   529  	if len(lbid) == 0 {
   530  		return "", fmt.Errorf("loadbalancer id should not be empty")
   531  	}
   532  
   533  	params := map[string]string{
   534  		"LoadBalancerId": lbid,
   535  		"ListenerId":     listenerId,
   536  		"Rules.0.Domain": domain,
   537  		"Rules.0.Url":    url,
   538  	}
   539  
   540  	params["Rules.0.Scheduler"] = scheduler
   541  	params["Rules.0.SessionExpireTime"] = strconv.Itoa(sessionExpireTime)
   542  
   543  	// health check
   544  	params["Rules.0.HealthCheck.HealthSwitch"] = strconv.Itoa(hc.HealthSwitch)
   545  	params["Rules.0.HealthCheck.IntervalTime"] = strconv.Itoa(hc.IntervalTime)
   546  	params["Rules.0.HealthCheck.HealthNum"] = strconv.Itoa(hc.HealthNum)
   547  	params["Rules.0.HealthCheck.UnHealthNum"] = strconv.Itoa(hc.UnHealthNum)
   548  	if hc.HTTPCode > 0 {
   549  		params["Rules.0.HealthCheck.HttpCode"] = strconv.Itoa(hc.HTTPCode)
   550  		params["Rules.0.HealthCheck.HttpCheckPath"] = hc.HTTPCheckPath
   551  		params["Rules.0.HealthCheck.HttpCheckDomain"] = hc.HTTPCheckDomain
   552  		params["Rules.0.HealthCheck.HttpCheckMethod"] = hc.HTTPCheckMethod
   553  	}
   554  
   555  	resp, err := self.clbRequest("CreateRule", params)
   556  	if err != nil {
   557  		return "", err
   558  	}
   559  
   560  	return resp.GetString("RequestId")
   561  }
   562  
   563  //  返回requestID
   564  func (self *SRegion) deleteLoadbalancerListener(lbid string, listenerId string) (string, error) {
   565  	if len(lbid) == 0 {
   566  		return "", fmt.Errorf("loadbalancer id should not be empty")
   567  	}
   568  
   569  	params := map[string]string{
   570  		"LoadBalancerId": lbid,
   571  		"ListenerId":     listenerId,
   572  	}
   573  
   574  	resp, err := self.clbRequest("DeleteListener", params)
   575  	if err != nil {
   576  		return "", err
   577  	}
   578  
   579  	return resp.GetString("RequestId")
   580  }
   581  
   582  //  返回requestID
   583  func (self *SRegion) deleteClassicLoadbalancerListener(lbid string, listenerId string) (string, error) {
   584  	if len(lbid) == 0 {
   585  		return "", fmt.Errorf("classic loadbalancer id should not be empty")
   586  	}
   587  
   588  	params := map[string]string{
   589  		"loadBalancerId": lbid,
   590  		"listenerIds.0":  listenerId,
   591  	}
   592  
   593  	resp, err := self.lbRequest("DeleteLoadBalancerListeners", params)
   594  	if err != nil {
   595  		return "", err
   596  	}
   597  
   598  	_requestId, err := resp.Float("requestId")
   599  	if err != nil {
   600  		return "", err
   601  	}
   602  
   603  	return fmt.Sprintf("%.f", _requestId), nil
   604  }
   605  
   606  //  返回requestID
   607  func (self *SRegion) DeleteLoadbalancerListener(t LB_TYPE, lbid string, listenerId string) (string, error) {
   608  	ctx := context.Background()
   609  	lockman.LockRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId)
   610  	defer lockman.ReleaseRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId)
   611  
   612  	if len(lbid) == 0 {
   613  		return "", fmt.Errorf("loadbalancer id should not be empty")
   614  	}
   615  
   616  	if t == LB_TYPE_APPLICATION {
   617  		return self.deleteLoadbalancerListener(lbid, listenerId)
   618  	} else {
   619  		return self.deleteClassicLoadbalancerListener(lbid, listenerId)
   620  	}
   621  }
   622  
   623  // https://cloud.tencent.com/document/product/214/30681
   624  func (self *SRegion) updateLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
   625  	params := map[string]string{
   626  		"LoadBalancerId": lbid,
   627  		"ListenerId":     listenerId,
   628  	}
   629  
   630  	if listenerName != nil && len(*listenerName) > 0 {
   631  		params["ListenerName"] = *listenerName
   632  	}
   633  
   634  	if scheduler != nil && len(*scheduler) > 0 {
   635  		params["Scheduler"] = *scheduler
   636  	}
   637  
   638  	if sessionExpireTime != nil {
   639  		params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime)
   640  	}
   641  
   642  	params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.")
   643  	params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.")
   644  
   645  	resp, err := self.clbRequest("ModifyListener", params)
   646  	if err != nil {
   647  		return "", err
   648  	}
   649  
   650  	return resp.GetString("RequestId")
   651  }
   652  
   653  // https://cloud.tencent.com/document/api/214/3601
   654  func (self *SRegion) updateClassicLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
   655  	params := map[string]string{
   656  		"loadBalancerId": lbid,
   657  		"listenerId":     listenerId,
   658  	}
   659  
   660  	if listenerName != nil && len(*listenerName) > 0 {
   661  		params["listenerName"] = *listenerName
   662  	}
   663  
   664  	if scheduler != nil && len(*scheduler) > 0 {
   665  		params["scheduler"] = strings.ToLower(*scheduler)
   666  	}
   667  
   668  	if sessionExpireTime != nil {
   669  		params["sessionExpire"] = strconv.Itoa(*sessionExpireTime)
   670  	}
   671  
   672  	params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "listeners.0.")
   673  	params = certificateParams(LB_TYPE_APPLICATION, params, cert, "listeners.0.")
   674  
   675  	resp, err := self.lbRequest("ModifyLoadBalancerListener", params)
   676  	if err != nil {
   677  		return "", err
   678  	}
   679  
   680  	return resp.GetString("RequestId")
   681  }
   682  
   683  func (self *SRegion) UpdateLoadbalancerListener(t LB_TYPE, lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) {
   684  	if len(lbid) == 0 {
   685  		return "", fmt.Errorf("loadbalancer id should not be empty")
   686  	}
   687  
   688  	if len(listenerId) == 0 {
   689  		return "", fmt.Errorf("loadbalancer listener id should not be empty")
   690  	}
   691  
   692  	if t == LB_TYPE_APPLICATION {
   693  		return self.updateLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert)
   694  	} else {
   695  		return self.updateClassicLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert)
   696  	}
   697  }
   698  
   699  func getHealthCheck(listener *cloudprovider.SLoadbalancerListener) *healthCheck {
   700  	var hc *healthCheck
   701  	if listener.HealthCheck == api.LB_BOOL_ON {
   702  		hc = &healthCheck{
   703  			HealthSwitch: 1,
   704  			UnHealthNum:  listener.HealthCheckFail,
   705  			IntervalTime: listener.HealthCheckInterval,
   706  			HealthNum:    listener.HealthCheckRise,
   707  			TimeOut:      listener.HealthCheckTimeout,
   708  		}
   709  
   710  		httpCode := onecloudHealthCodeToQcloud(listener.HealthCheckHttpCode)
   711  		if httpCode > 0 {
   712  			hc.HTTPCode = httpCode
   713  			hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model
   714  			hc.HTTPCheckDomain = listener.HealthCheckDomain
   715  			hc.HTTPCheckPath = listener.HealthCheckURI
   716  		}
   717  	} else {
   718  		hc = &healthCheck{
   719  			HealthSwitch: 0,
   720  			UnHealthNum:  3,
   721  			IntervalTime: 5,
   722  			HealthNum:    3,
   723  			TimeOut:      2,
   724  		}
   725  	}
   726  
   727  	return hc
   728  }
   729  
   730  func getListenerRuleHealthCheck(rule *cloudprovider.SLoadbalancerListenerRule) *healthCheck {
   731  	var hc *healthCheck
   732  	if rule.HealthCheck == api.LB_BOOL_ON {
   733  		hc = &healthCheck{
   734  			HealthSwitch: 1,
   735  			UnHealthNum:  rule.HealthCheckFail,
   736  			IntervalTime: rule.HealthCheckInterval,
   737  			HealthNum:    rule.HealthCheckRise,
   738  			TimeOut:      rule.HealthCheckTimeout,
   739  		}
   740  
   741  		httpCode := onecloudHealthCodeToQcloud(rule.HealthCheckHttpCode)
   742  		if httpCode > 0 {
   743  			hc.HTTPCode = httpCode
   744  			hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model
   745  			hc.HTTPCheckDomain = rule.HealthCheckDomain
   746  			hc.HTTPCheckPath = rule.HealthCheckURI
   747  		}
   748  	} else {
   749  		hc = &healthCheck{
   750  			HealthSwitch: 0,
   751  			UnHealthNum:  3,
   752  			IntervalTime: 5,
   753  			HealthNum:    3,
   754  			TimeOut:      2,
   755  		}
   756  	}
   757  
   758  	return hc
   759  }
   760  
   761  func getCertificate(listener *cloudprovider.SLoadbalancerListener) *certificate {
   762  	var cert *certificate
   763  	if len(listener.CertificateID) > 0 {
   764  		cert = &certificate{
   765  			SSLMode:  "UNIDIRECTIONAL",
   766  			CERTCAID: "",
   767  			CERTID:   listener.CertificateID,
   768  		}
   769  	}
   770  
   771  	return cert
   772  }
   773  
   774  func getProtocol(listener *cloudprovider.SLoadbalancerListener) string {
   775  	switch listener.ListenerType {
   776  	case api.LB_LISTENER_TYPE_HTTPS:
   777  		return PROTOCOL_HTTPS
   778  	case api.LB_LISTENER_TYPE_HTTP:
   779  		return PROTOCOL_HTTP
   780  	case api.LB_LISTENER_TYPE_TCP:
   781  		return PROTOCOL_TCP
   782  	case api.LB_LISTENER_TYPE_UDP:
   783  		return PROTOCOL_UDP
   784  	case "tcp_ssl":
   785  		return PROTOCOL_TCP_SSL
   786  	default:
   787  		return ""
   788  	}
   789  }
   790  
   791  func getClassicLBProtocol(listener *cloudprovider.SLoadbalancerListener) int {
   792  	switch listener.ListenerType {
   793  	case api.LB_LISTENER_TYPE_HTTP:
   794  		return 1
   795  	case api.LB_LISTENER_TYPE_HTTPS:
   796  		return 4
   797  	case api.LB_LISTENER_TYPE_TCP:
   798  		return 2
   799  	case api.LB_LISTENER_TYPE_UDP:
   800  		return 3
   801  	default:
   802  		return 0 // 非法值
   803  	}
   804  }
   805  
   806  func getScheduler(listener *cloudprovider.SLoadbalancerListener) *string {
   807  	var sch string
   808  	switch listener.Scheduler {
   809  	case api.LB_SCHEDULER_WRR:
   810  		sch = "WRR"
   811  	case api.LB_SCHEDULER_WLC:
   812  		sch = "LEAST_CONN"
   813  	case api.LB_SCHEDULER_SCH:
   814  		sch = "IP_HASH"
   815  	default:
   816  		return nil
   817  	}
   818  
   819  	return &sch
   820  }
   821  
   822  func healthCheckParams(t LB_TYPE, params map[string]string, hc *healthCheck, paramPrefix string) map[string]string {
   823  	if hc == nil {
   824  		return params
   825  	}
   826  
   827  	if t == LB_TYPE_APPLICATION {
   828  		params[paramPrefix+"HealthSwitch"] = strconv.Itoa(hc.HealthSwitch)
   829  		params[paramPrefix+"TimeOut"] = strconv.Itoa(hc.TimeOut)
   830  		params[paramPrefix+"IntervalTime"] = strconv.Itoa(hc.IntervalTime)
   831  		params[paramPrefix+"HealthNum"] = strconv.Itoa(hc.HealthNum)
   832  		params[paramPrefix+"UnHealthNum"] = strconv.Itoa(hc.UnHealthNum)
   833  		if hc.HTTPCode > 0 {
   834  			params[paramPrefix+"HttpCode"] = strconv.Itoa(hc.HTTPCode)
   835  			params[paramPrefix+"HttpCheckPath"] = hc.HTTPCheckPath
   836  			params[paramPrefix+"HttpCheckDomain"] = hc.HTTPCheckDomain
   837  			params[paramPrefix+"HttpCheckMethod"] = hc.HTTPCheckMethod
   838  		}
   839  	} else {
   840  		params[paramPrefix+"healthSwitch"] = strconv.Itoa(hc.HealthSwitch)
   841  		params[paramPrefix+"timeOut"] = strconv.Itoa(hc.TimeOut)
   842  		params[paramPrefix+"intervalTime"] = strconv.Itoa(hc.IntervalTime)
   843  		params[paramPrefix+"healthNum"] = strconv.Itoa(hc.HealthNum)
   844  		params[paramPrefix+"unHealthNum"] = strconv.Itoa(hc.UnHealthNum)
   845  		if hc.HTTPCode > 0 {
   846  			params[paramPrefix+"httpCode"] = strconv.Itoa(hc.HTTPCode)
   847  			params[paramPrefix+"httpCheckPath"] = hc.HTTPCheckPath
   848  		}
   849  	}
   850  	return params
   851  }
   852  
   853  func certificateParams(t LB_TYPE, params map[string]string, cert *certificate, paramPrefix string) map[string]string {
   854  	if cert == nil {
   855  		return params
   856  	}
   857  
   858  	if t == LB_TYPE_APPLICATION {
   859  		params[paramPrefix+"SSLMode"] = cert.SSLMode
   860  		params[paramPrefix+"CertId"] = cert.CERTID
   861  		if len(cert.CERTCAID) > 0 {
   862  			params[paramPrefix+"CertCaId"] = cert.CERTCAID
   863  		}
   864  	} else {
   865  		params[paramPrefix+"SSLMode"] = strings.ToLower(cert.SSLMode)
   866  		params[paramPrefix+"certId"] = cert.CERTID
   867  		if len(cert.CERTCAID) > 0 {
   868  			params[paramPrefix+"certCaId"] = cert.CERTCAID
   869  		}
   870  	}
   871  	return params
   872  }
   873  
   874  func (self *SLBListener) GetProjectId() string {
   875  	return self.lb.GetProjectId()
   876  }
   877  
   878  func (self *SLBListener) GetClientIdleTimeout() int {
   879  	return 0
   880  }
   881  
   882  func (self *SLBListener) GetBackendConnectTimeout() int {
   883  	return 0
   884  }