yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/loadbalancerlistener.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 aws 16 17 import ( 18 "context" 19 "encoding/json" 20 "fmt" 21 "strconv" 22 "strings" 23 "time" 24 25 "github.com/aws/aws-sdk-go/service/elbv2" 26 "github.com/pkg/errors" 27 28 "yunion.io/x/jsonutils" 29 "yunion.io/x/log" 30 31 api "yunion.io/x/cloudmux/pkg/apis/compute" 32 "yunion.io/x/cloudmux/pkg/cloudprovider" 33 "yunion.io/x/cloudmux/pkg/multicloud" 34 ) 35 36 type SElbListener struct { 37 multicloud.SResourceBase 38 multicloud.SLoadbalancerRedirectBase 39 AwsTags 40 region *SRegion 41 lb *SElb 42 group *SElbBackendGroup 43 44 Port int `json:"Port"` 45 Protocol string `json:"Protocol"` 46 DefaultActions []DefaultAction `json:"DefaultActions"` 47 SSLPolicy string `json:"SslPolicy"` 48 Certificates []Certificate `json:"Certificates"` 49 LoadBalancerArn string `json:"LoadBalancerArn"` 50 ListenerArn string `json:"ListenerArn"` 51 } 52 53 type Certificate struct { 54 CertificateArn string `json:"CertificateArn"` 55 } 56 57 type DefaultAction struct { 58 TargetGroupArn string `json:"TargetGroupArn"` 59 Type string `json:"Type"` 60 } 61 62 func (self *SElbListener) GetId() string { 63 return self.ListenerArn 64 } 65 66 func (self *SElbListener) GetName() string { 67 segs := strings.Split(self.ListenerArn, "/") 68 return segs[len(segs)-1] 69 } 70 71 func (self *SElbListener) GetGlobalId() string { 72 return self.GetId() 73 } 74 75 func (self *SElbListener) GetStatus() string { 76 return api.LB_STATUS_ENABLED 77 } 78 79 func (self *SElbListener) Refresh() error { 80 listener, err := self.region.GetElbListener(self.GetId()) 81 if err != nil { 82 return err 83 } 84 85 err = jsonutils.Update(self, listener) 86 if err != nil { 87 return err 88 } 89 90 return nil 91 } 92 93 func (self *SElbListener) IsEmulated() bool { 94 return false 95 } 96 97 func (self *SElbListener) GetProjectId() string { 98 return "" 99 } 100 101 func (self *SElbListener) GetListenerType() string { 102 switch self.Protocol { 103 case "TCP": 104 return api.LB_LISTENER_TYPE_TCP 105 case "UDP": 106 return api.LB_LISTENER_TYPE_UDP 107 case "HTTP": 108 return api.LB_LISTENER_TYPE_HTTP 109 case "HTTPS": 110 return api.LB_LISTENER_TYPE_HTTPS 111 case "TCP_SSL": 112 return api.LB_LISTENER_TYPE_TCP 113 case "TCP_UDP": 114 return api.LB_LISTENER_TYPE_TCP_UDP 115 default: 116 return "" 117 } 118 } 119 120 func (self *SElbListener) GetListenerPort() int { 121 return self.Port 122 } 123 124 func (self *SElbListener) GetScheduler() string { 125 // api.LB_SCHEDULER_RR ? 126 return "" 127 } 128 129 func (self *SElbListener) GetAclStatus() string { 130 return api.LB_BOOL_OFF 131 } 132 133 func (self *SElbListener) GetAclType() string { 134 return "" 135 } 136 137 func (self *SElbListener) GetAclId() string { 138 return "" 139 } 140 141 func (self *SElbListener) GetEgressMbps() int { 142 return 0 143 } 144 145 func (self *SElbListener) GetHealthCheck() string { 146 group, err := self.getBackendGroup() 147 if err != nil { 148 return "" 149 } 150 151 health, err := group.GetHealthCheck() 152 if err != nil { 153 return "" 154 } 155 156 return health.HealthCheck 157 } 158 159 func (self *SElbListener) getBackendGroup() (*SElbBackendGroup, error) { 160 if self.group != nil { 161 return self.group, nil 162 } 163 164 lbbg, err := self.region.GetElbBackendgroup(self.DefaultActions[0].TargetGroupArn) 165 if err != nil { 166 return nil, errors.Wrap(err, "GetElbBackendgroup") 167 } 168 169 self.group = lbbg 170 return self.group, nil 171 } 172 173 func (self *SElbListener) GetHealthCheckType() string { 174 group, err := self.getBackendGroup() 175 if err != nil { 176 return "" 177 } 178 179 health, err := group.GetHealthCheck() 180 if err != nil { 181 return "" 182 } 183 184 return health.HealthCheckType 185 } 186 187 func (self *SElbListener) GetHealthCheckTimeout() int { 188 group, err := self.getBackendGroup() 189 if err != nil { 190 return 0 191 } 192 193 health, err := group.GetHealthCheck() 194 if err != nil { 195 return 0 196 } 197 198 return health.HealthCheckTimeout 199 } 200 201 func (self *SElbListener) GetHealthCheckInterval() int { 202 group, err := self.getBackendGroup() 203 if err != nil { 204 return 0 205 } 206 207 health, err := group.GetHealthCheck() 208 if err != nil { 209 return 0 210 } 211 212 return health.HealthCheckInterval 213 } 214 215 func (self *SElbListener) GetHealthCheckRise() int { 216 group, err := self.getBackendGroup() 217 if err != nil { 218 return 0 219 } 220 221 health, err := group.GetHealthCheck() 222 if err != nil { 223 return 0 224 } 225 226 return health.HealthCheckRise 227 } 228 229 func (self *SElbListener) GetHealthCheckFail() int { 230 group, err := self.getBackendGroup() 231 if err != nil { 232 return 0 233 } 234 235 health, err := group.GetHealthCheck() 236 if err != nil { 237 return 0 238 } 239 240 return health.HealthCheckFail 241 } 242 243 func (self *SElbListener) GetHealthCheckReq() string { 244 group, err := self.getBackendGroup() 245 if err != nil { 246 return "" 247 } 248 249 health, err := group.GetHealthCheck() 250 if err != nil { 251 return "" 252 } 253 254 return health.HealthCheckReq 255 } 256 257 func (self *SElbListener) GetHealthCheckExp() string { 258 group, err := self.getBackendGroup() 259 if err != nil { 260 return "" 261 } 262 263 health, err := group.GetHealthCheck() 264 if err != nil { 265 return "" 266 } 267 268 return health.HealthCheckExp 269 } 270 271 func (self *SElbListener) GetBackendGroupId() string { 272 return self.DefaultActions[0].TargetGroupArn 273 } 274 275 func (self *SElbListener) GetBackendServerPort() int { 276 return 0 277 } 278 279 func (self *SElbListener) GetHealthCheckDomain() string { 280 group, err := self.getBackendGroup() 281 if err != nil { 282 return "" 283 } 284 285 health, err := group.GetHealthCheck() 286 if err != nil { 287 return "" 288 } 289 290 return health.HealthCheckDomain 291 } 292 293 func (self *SElbListener) GetHealthCheckURI() string { 294 group, err := self.getBackendGroup() 295 if err != nil { 296 return "" 297 } 298 299 health, err := group.GetHealthCheck() 300 if err != nil { 301 return "" 302 } 303 304 return health.HealthCheckURI 305 } 306 307 func (self *SElbListener) GetHealthCheckCode() string { 308 group, err := self.getBackendGroup() 309 if err != nil { 310 return "" 311 } 312 313 health, err := group.GetHealthCheck() 314 if err != nil { 315 return "" 316 } 317 318 return health.HealthCheckHttpCode 319 } 320 321 func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { 322 rules, err := self.GetILoadbalancerListenerRules() 323 if err != nil { 324 return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") 325 } else { 326 if err := self.region.UpdateRulesPriority(rules); err != nil { 327 return nil, errors.Wrap(err, "UpdateRulesPriority") 328 } 329 } 330 331 ret, err := self.region.CreateElbListenerRule(self.GetId(), rule) 332 if err != nil { 333 return nil, errors.Wrap(err, "CreateElbListenerRule") 334 } 335 336 ret.listener = self 337 ret.region = self.region 338 return ret, nil 339 } 340 341 func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { 342 rule, err := self.region.GetElbListenerRuleById(ruleId) 343 if err != nil { 344 return nil, errors.Wrap(err, "GetElbListenerRuleById") 345 } 346 347 rule.listener = self 348 return rule, nil 349 } 350 351 func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { 352 rules, err := self.region.GetElbListenerRules(self.GetId(), "") 353 if err != nil { 354 return nil, errors.Wrap(err, "GetElbListenerRules") 355 } 356 357 irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules)) 358 for i := range rules { 359 rules[i].listener = self 360 irules[i] = &rules[i] 361 } 362 363 return irules, nil 364 } 365 366 func (self *SElbListener) GetStickySession() string { 367 group, err := self.getBackendGroup() 368 if err != nil { 369 return "" 370 } 371 372 session, err := group.GetStickySession() 373 if err != nil { 374 return "" 375 } 376 377 return session.StickySession 378 } 379 380 func (self *SElbListener) GetStickySessionType() string { 381 group, err := self.getBackendGroup() 382 if err != nil { 383 return "" 384 } 385 386 session, err := group.GetStickySession() 387 if err != nil { 388 return "" 389 } 390 391 return session.StickySessionType 392 } 393 394 func (self *SElbListener) GetStickySessionCookie() string { 395 group, err := self.getBackendGroup() 396 if err != nil { 397 return "" 398 } 399 400 session, err := group.GetStickySession() 401 if err != nil { 402 return "" 403 } 404 405 return session.StickySessionCookie 406 } 407 408 func (self *SElbListener) GetStickySessionCookieTimeout() int { 409 group, err := self.getBackendGroup() 410 if err != nil { 411 return 0 412 } 413 414 session, err := group.GetStickySession() 415 if err != nil { 416 return 0 417 } 418 419 return session.StickySessionCookieTimeout 420 } 421 422 func (self *SElbListener) XForwardedForEnabled() bool { 423 return false 424 } 425 426 func (self *SElbListener) GzipEnabled() bool { 427 return false 428 } 429 430 func (self *SElbListener) GetCertificateId() string { 431 if len(self.Certificates) > 0 { 432 return self.Certificates[0].CertificateArn 433 } 434 435 return "" 436 } 437 438 func (self *SElbListener) GetTLSCipherPolicy() string { 439 return self.SSLPolicy 440 } 441 442 func (self *SElbListener) HTTP2Enabled() bool { 443 return false 444 } 445 446 func (self *SElbListener) GetClientIdleTimeout() int { 447 return 0 448 } 449 450 func (self *SElbListener) GetBackendConnectTimeout() int { 451 return 0 452 } 453 454 func (self *SElbListener) Start() error { 455 return nil 456 } 457 458 func (self *SElbListener) Stop() error { 459 return cloudprovider.ErrNotSupported 460 } 461 462 func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { 463 return self.region.SyncElbListener(self, listener) 464 } 465 466 func (self *SElbListener) Delete(ctx context.Context) error { 467 return self.region.DeleteElbListener(self.GetId()) 468 } 469 470 func (self *SRegion) GetElbListeners(elbId string) ([]SElbListener, error) { 471 client, err := self.GetElbV2Client() 472 if err != nil { 473 return nil, errors.Wrap(err, "GetElbV2Client") 474 } 475 476 params := &elbv2.DescribeListenersInput{} 477 params.SetLoadBalancerArn(elbId) 478 ret, err := client.DescribeListeners(params) 479 if err != nil { 480 return nil, errors.Wrap(err, "DescribeListeners") 481 } 482 483 listeners := []SElbListener{} 484 err = unmarshalAwsOutput(ret, "Listeners", &listeners) 485 if err != nil { 486 return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") 487 } 488 489 for i := range listeners { 490 listeners[i].region = self 491 } 492 493 return listeners, nil 494 } 495 496 func unmarshalAwsOutput(output interface{}, respKey string, result interface{}) error { 497 _ret, err := json.Marshal(output) 498 if err != nil { 499 return err 500 } 501 502 obj, err := jsonutils.Parse(_ret) 503 if err != nil { 504 return err 505 } 506 507 if len(respKey) == 0 { 508 err = obj.Unmarshal(result) 509 if err != nil { 510 return err 511 } 512 } else { 513 err = obj.Unmarshal(result, respKey) 514 if err != nil { 515 return err 516 } 517 } 518 519 return nil 520 } 521 522 func (self *SRegion) GetElbListener(listenerId string) (*SElbListener, error) { 523 client, err := self.GetElbV2Client() 524 if err != nil { 525 return nil, errors.Wrap(err, "GetElbV2Client") 526 } 527 528 params := &elbv2.DescribeListenersInput{} 529 params.SetListenerArns([]*string{&listenerId}) 530 ret, err := client.DescribeListeners(params) 531 if err != nil { 532 return nil, errors.Wrap(err, "DescribeListeners") 533 } 534 535 listeners := []SElbListener{} 536 err = unmarshalAwsOutput(ret, "Listeners", &listeners) 537 if err != nil { 538 return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") 539 } 540 541 if len(listeners) == 1 { 542 listeners[0].region = self 543 return &listeners[0], nil 544 } 545 546 return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListener") 547 } 548 549 func (self *SRegion) CreateElbListener(listener *cloudprovider.SLoadbalancerListener) (*SElbListener, error) { 550 client, err := self.GetElbV2Client() 551 if err != nil { 552 return nil, errors.Wrap(err, "GetElbV2Client") 553 } 554 555 listenerType := strings.ToUpper(listener.ListenerType) 556 params := &elbv2.CreateListenerInput{} 557 params.SetLoadBalancerArn(listener.LoadbalancerID) 558 params.SetPort(int64(listener.ListenerPort)) 559 params.SetProtocol(listenerType) 560 action := &elbv2.Action{} 561 action.SetType("forward") 562 action.SetTargetGroupArn(listener.BackendGroupID) 563 params.SetDefaultActions([]*elbv2.Action{action}) 564 if listenerType == "HTTPS" { 565 cert := &elbv2.Certificate{ 566 CertificateArn: &listener.CertificateID, 567 } 568 569 params.SetCertificates([]*elbv2.Certificate{cert}) 570 params.SetSslPolicy("ELBSecurityPolicy-2016-08") 571 } 572 573 ret, err := client.CreateListener(params) 574 if err != nil { 575 // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 576 time.Sleep(10 * time.Second) 577 if strings.Contains(err.Error(), "CertificateNotFound") { 578 ret, err = client.CreateListener(params) 579 if err != nil { 580 return nil, errors.Wrap(err, "Region.CreateElbListener.Retry") 581 } 582 } else { 583 return nil, errors.Wrap(err, "Region.CreateElbListener") 584 } 585 } 586 587 listeners := []SElbListener{} 588 err = unmarshalAwsOutput(ret, "Listeners", &listeners) 589 if err != nil { 590 return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") 591 } 592 593 if len(listeners) == 1 { 594 listeners[0].region = self 595 return &listeners[0], nil 596 } 597 598 return nil, fmt.Errorf("CreateElbListener err %#v", listeners) 599 } 600 601 func (self *SRegion) GetElbListenerRules(listenerId string, ruleId string) ([]SElbListenerRule, error) { 602 client, err := self.GetElbV2Client() 603 if err != nil { 604 return nil, errors.Wrap(err, "GetElbV2Client") 605 } 606 607 params := &elbv2.DescribeRulesInput{} 608 if len(listenerId) > 0 { 609 params.SetListenerArn(listenerId) 610 } 611 612 if len(ruleId) > 0 { 613 params.SetRuleArns([]*string{&ruleId}) 614 } 615 616 ret, err := client.DescribeRules(params) 617 if err != nil { 618 return nil, errors.Wrap(err, "DescribeRules") 619 } 620 621 rules := []SElbListenerRule{} 622 err = unmarshalAwsOutput(ret, "Rules", &rules) 623 if err != nil { 624 return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") 625 } 626 627 for i := range rules { 628 rules[i].region = self 629 } 630 631 return rules, nil 632 } 633 634 func (self *SRegion) GetElbListenerRuleById(ruleId string) (*SElbListenerRule, error) { 635 client, err := self.GetElbV2Client() 636 if err != nil { 637 return nil, errors.Wrap(err, "GetElbV2Client") 638 } 639 640 params := &elbv2.DescribeRulesInput{} 641 if len(ruleId) > 0 { 642 params.SetRuleArns([]*string{&ruleId}) 643 } 644 645 ret, err := client.DescribeRules(params) 646 if err != nil { 647 return nil, errors.Wrap(err, "DescribeRules") 648 } 649 650 rules := []SElbListenerRule{} 651 err = unmarshalAwsOutput(ret, "Rules", &rules) 652 if err != nil { 653 return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") 654 } 655 656 if len(rules) == 1 { 657 rules[0].region = self 658 return &rules[0], nil 659 } else { 660 log.Errorf("GetElbListenerRuleById %s %d found", ruleId, len(rules)) 661 return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListenerRuleById") 662 } 663 } 664 665 func (self *SRegion) DeleteElbListener(listenerId string) error { 666 client, err := self.GetElbV2Client() 667 if err != nil { 668 return err 669 } 670 671 params := &elbv2.DeleteListenerInput{} 672 params.SetListenerArn(listenerId) 673 _, err = client.DeleteListener(params) 674 if err != nil { 675 return err 676 } 677 678 return nil 679 } 680 681 func (self *SRegion) SyncElbListener(listener *SElbListener, config *cloudprovider.SLoadbalancerListener) error { 682 client, err := self.GetElbV2Client() 683 if err != nil { 684 return err 685 } 686 687 params := &elbv2.ModifyListenerInput{} 688 params.SetListenerArn(listener.GetId()) 689 params.SetPort(int64(config.ListenerPort)) 690 params.SetProtocol(strings.ToUpper(config.ListenerType)) 691 action := &elbv2.Action{} 692 action.SetType("forward") 693 action.SetTargetGroupArn(config.BackendGroupID) 694 params.SetDefaultActions([]*elbv2.Action{action}) 695 696 if config.ListenerType == api.LB_LISTENER_TYPE_HTTPS { 697 cert := &elbv2.Certificate{} 698 cert.SetCertificateArn(config.CertificateID) 699 params.SetCertificates([]*elbv2.Certificate{cert}) 700 } 701 702 _, err = client.ModifyListener(params) 703 if err != nil { 704 if strings.Contains(err.Error(), "CertificateNotFound") { 705 // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 706 time.Sleep(10 * time.Second) 707 _, err = client.ModifyListener(params) 708 if err != nil { 709 return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener.Retry") 710 } 711 } 712 713 return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener") 714 } 715 716 hc := &cloudprovider.SLoadbalancerHealthCheck{ 717 HealthCheckType: config.HealthCheckType, 718 HealthCheckReq: config.HealthCheckReq, 719 HealthCheckExp: config.HealthCheckExp, 720 HealthCheck: config.HealthCheck, 721 HealthCheckTimeout: config.HealthCheckTimeout, 722 HealthCheckDomain: config.HealthCheckDomain, 723 HealthCheckHttpCode: config.HealthCheckHttpCode, 724 HealthCheckURI: config.HealthCheckURI, 725 HealthCheckInterval: config.HealthCheckInterval, 726 HealthCheckRise: config.HealthCheckRise, 727 HealthCheckFail: config.HealthCheckFail, 728 } 729 err = self.modifyELbBackendGroup(config.BackendGroupID, hc) 730 if err != nil { 731 return errors.Wrap(err, "region.SyncElbListener.updateELbBackendGroup") 732 } 733 734 return nil 735 } 736 737 func (self *SRegion) UpdateRulesPriority(rules []cloudprovider.ICloudLoadbalancerListenerRule) error { 738 client, err := self.GetElbV2Client() 739 if err != nil { 740 return err 741 } 742 743 ps := []*elbv2.RulePriorityPair{} 744 for i := range rules { 745 rule := rules[i].(*SElbListenerRule) 746 if !rule.IsDefaultRule { 747 v, _ := strconv.Atoi(rule.Priority) 748 p := &elbv2.RulePriorityPair{} 749 p.SetRuleArn(rules[i].GetId()) 750 p.SetPriority(int64(v + 1)) 751 752 ps = append(ps, p) 753 } 754 } 755 756 if len(ps) == 0 { 757 return nil 758 } 759 760 params := &elbv2.SetRulePrioritiesInput{} 761 params.SetRulePriorities(ps) 762 _, err = client.SetRulePriorities(params) 763 if err != nil { 764 return err 765 } 766 767 return nil 768 }