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 }