Merge pull request #1761 from ioito/hotfix/qx-elb-eip-sync

添加lb eip同步
This commit is contained in:
yunion-ci-robot
2019-07-18 15:43:58 +08:00
committed by GitHub
11 changed files with 279 additions and 10 deletions

View File

@@ -18,8 +18,9 @@ const (
EIP_MODE_INSTANCE_PUBLICIP = "public_ip"
EIP_MODE_STANDALONE_EIP = "elastic_ip"
EIP_ASSOCIATE_TYPE_SERVER = "server"
EIP_ASSOCIATE_TYPE_NAT_GATEWAY = "natgateway"
EIP_ASSOCIATE_TYPE_SERVER = "server"
EIP_ASSOCIATE_TYPE_NAT_GATEWAY = "natgateway"
EIP_ASSOCIATE_TYPE_LOADBALANCER = "loadbalancer"
EIP_STATUS_READY = "ready"
EIP_STATUS_UNKNOWN = "unknown"

View File

@@ -460,6 +460,8 @@ type ICloudLoadbalancer interface {
GetChargeType() string
GetEgressMbps() int
GetIEIP() (ICloudEIP, error)
Delete() error
Start() error

View File

@@ -725,6 +725,8 @@ func syncRegionLoadbalancers(ctx context.Context, userCred mcclient.TokenCredent
lockman.LockObject(ctx, &localLbs[i])
defer lockman.ReleaseObject(ctx, &localLbs[i])
syncLoadbalancerEip(ctx, userCred, provider, &localLbs[i], remoteLbs[i])
syncLoadbalancerBackendgroups(ctx, userCred, syncResults, provider, &localLbs[i], remoteLbs[i], syncRange)
syncLoadbalancerListeners(ctx, userCred, syncResults, provider, &localLbs[i], remoteLbs[i], syncRange)
@@ -732,6 +734,21 @@ func syncRegionLoadbalancers(ctx context.Context, userCred mcclient.TokenCredent
}
}
func syncLoadbalancerEip(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, localLb *SLoadbalancer, remoteLb cloudprovider.ICloudLoadbalancer) {
eip, err := remoteLb.GetIEIP()
if err != nil {
msg := fmt.Sprintf("GetIEIP for Loadbalancer %s failed %s", remoteLb.GetName(), err)
log.Errorf(msg)
return
}
result := localLb.SyncLoadbalancerEip(ctx, userCred, provider, eip)
msg := result.Result()
log.Infof("SyncEip for Loadbalancer %s result: %s", localLb.Name, msg)
if result.IsError() {
return
}
}
func syncLoadbalancerListeners(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localLoadbalancer *SLoadbalancer, remoteLoadbalancer cloudprovider.ICloudLoadbalancer, syncRange *SSyncRange) {
remoteListeners, err := remoteLoadbalancer.GetILoadBalancerListeners()
if err != nil {

View File

@@ -503,6 +503,21 @@ func (self *SElasticip) GetAssociateVM() *SGuest {
return nil
}
func (self *SElasticip) GetAssociateLoadbalancer() *SLoadbalancer {
if self.AssociateType == api.EIP_ASSOCIATE_TYPE_LOADBALANCER && len(self.AssociateId) > 0 {
_lb, err := LoadbalancerManager.FetchById(self.AssociateId)
if err != nil {
return nil
}
lb := _lb.(*SLoadbalancer)
if lb.PendingDeleted {
return nil
}
return lb
}
return nil
}
func (self *SElasticip) GetAssociateNatGateway() *SNatGateway {
if self.AssociateType == api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY && len(self.AssociateId) > 0 {
natGateway, err := NatGatewayManager.FetchById(self.AssociateId)
@@ -520,6 +535,7 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
}
var vm *SGuest
var nat *SNatGateway
var lb *SLoadbalancer
switch self.AssociateType {
case api.EIP_ASSOCIATE_TYPE_SERVER:
vm = self.GetAssociateVM()
@@ -531,6 +547,11 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
if nat == nil {
log.Errorf("dissociate Nat gateway not exists???")
}
case api.EIP_ASSOCIATE_TYPE_LOADBALANCER:
lb = self.GetAssociateLoadbalancer()
if lb == nil {
log.Errorf("dissociate loadbalancer not exists???")
}
}
_, err := db.Update(self, func() error {
@@ -553,12 +574,41 @@ func (self *SElasticip) Dissociate(ctx context.Context, userCred mcclient.TokenC
db.OpsLog.LogEvent(nat, db.ACT_EIP_DETACH, self.GetShortDesc(ctx), userCred)
}
if lb != nil {
db.OpsLog.LogDetachEvent(ctx, lb, self, userCred, self.GetShortDesc(ctx))
db.OpsLog.LogEvent(self, db.ACT_EIP_DETACH, lb.GetShortDesc(ctx), userCred)
db.OpsLog.LogEvent(lb, db.ACT_EIP_DETACH, self.GetShortDesc(ctx), userCred)
}
if self.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
self.Delete(ctx, userCred)
}
return nil
}
func (self *SElasticip) AssociateLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer) error {
if lb.PendingDeleted {
return fmt.Errorf("loadbalancer is deleted")
}
if len(self.AssociateType) > 0 {
return fmt.Errorf("EIP has been associated!!")
}
_, err := db.Update(self, func() error {
self.AssociateType = api.EIP_ASSOCIATE_TYPE_LOADBALANCER
self.AssociateId = lb.Id
return nil
})
if err != nil {
return err
}
db.OpsLog.LogAttachEvent(ctx, lb, self, userCred, self.GetShortDesc(ctx))
db.OpsLog.LogEvent(self, db.ACT_EIP_ATTACH, lb.GetShortDesc(ctx), userCred)
db.OpsLog.LogEvent(lb, db.ACT_EIP_ATTACH, self.GetShortDesc(ctx), userCred)
return nil
}
func (self *SElasticip) AssociateVM(ctx context.Context, userCred mcclient.TokenCredential, vm *SGuest) error {
if vm.PendingDeleted || vm.Deleted {
return fmt.Errorf("vm is deleted")

View File

@@ -485,6 +485,12 @@ func (lb *SLoadbalancer) GetCustomizeColumns(ctx context.Context, userCred mccli
}
}
eip, _ := lb.GetEip()
if eip != nil {
extra.Set("eip", jsonutils.NewString(eip.IpAddr))
extra.Set("eip_mode", jsonutils.NewString(eip.Mode))
}
if lb.BackendGroupId != "" {
lbbg, err := LoadbalancerBackendGroupManager.FetchById(lb.BackendGroupId)
if err != nil {
@@ -710,6 +716,105 @@ func (lb *SLoadbalancer) syncLoadbalancerNetwork(ctx context.Context, userCred m
}
}
func (self *SLoadbalancer) DeleteEip(ctx context.Context, userCred mcclient.TokenCredential) error {
eip, err := self.GetEip()
if err != nil {
log.Errorf("Delete eip fail for get Eip %s", err)
return err
}
if eip == nil {
return nil
}
if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
err = eip.RealDelete(ctx, userCred)
if err != nil {
log.Errorf("Delete eip on delete server fail %s", err)
return err
}
} else {
err = eip.Dissociate(ctx, userCred)
if err != nil {
log.Errorf("Dissociate eip on delete server fail %s", err)
return err
}
}
return nil
}
func (self *SLoadbalancer) GetEip() (*SElasticip, error) {
return ElasticipManager.getEipForInstance(api.EIP_ASSOCIATE_TYPE_LOADBALANCER, self.Id)
}
func (self *SLoadbalancer) SyncLoadbalancerEip(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extEip cloudprovider.ICloudEIP) compare.SyncResult {
result := compare.SyncResult{}
eip, err := self.GetEip()
if err != nil {
result.Error(fmt.Errorf("getEip error %s", err))
return result
}
if eip == nil && extEip == nil {
// do nothing
} else if eip == nil && extEip != nil {
// add
neip, err := ElasticipManager.getEipByExtEip(ctx, userCred, extEip, provider, self.GetRegion(), provider.GetOwnerId())
if err != nil {
log.Errorf("getEipByExtEip error %v", err)
result.AddError(err)
} else {
err = neip.AssociateLoadbalancer(ctx, userCred, self)
if err != nil {
log.Errorf("AssociateVM error %v", err)
result.AddError(err)
} else {
result.Add()
}
}
} else if eip != nil && extEip == nil {
// remove
err = eip.Dissociate(ctx, userCred)
if err != nil {
result.DeleteError(err)
} else {
result.Delete()
}
} else {
// sync
if eip.IpAddr != extEip.GetIpAddr() {
// remove then add
err = eip.Dissociate(ctx, userCred)
if err != nil {
// fail to remove
result.DeleteError(err)
} else {
result.Delete()
neip, err := ElasticipManager.getEipByExtEip(ctx, userCred, extEip, provider, self.GetRegion(), provider.GetOwnerId())
if err != nil {
result.AddError(err)
} else {
err = neip.AssociateLoadbalancer(ctx, userCred, self)
if err != nil {
result.AddError(err)
} else {
result.Add()
}
}
}
} else {
// do nothing
err := eip.SyncWithCloudEip(ctx, userCred, provider, extEip, provider.GetOwnerId())
if err != nil {
result.UpdateError(err)
} else {
result.Update()
}
}
}
return result
}
func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, extLb cloudprovider.ICloudLoadbalancer, syncOwnerId mcclient.IIdentityProvider) error {
lockman.LockObject(ctx, lb)
defer lockman.ReleaseObject(ctx, lb)

View File

@@ -295,6 +295,11 @@ func (lb *SLoadbalancer) purge(ctx context.Context, userCred mcclient.TokenCrede
return err
}
err = lb.DeleteEip(ctx, userCred)
if err != nil {
return err
}
err = lb.purgeBackendGroups(ctx, userCred)
if err != nil {
return err

View File

@@ -22,6 +22,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -176,6 +177,15 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancer(ctx co
if err := lb.SyncWithCloudLoadbalancer(ctx, userCred, iLoadbalancer, nil); err != nil {
return nil, err
}
//公网lb,需要同步public ip
if lb.AddressType == api.LB_ADDR_TYPE_INTERNET {
publicIp, err := iLoadbalancer.GetIEIP()
if err != nil {
return nil, errors.Wrap(err, "iLoadbalancer.GetIEIP()")
}
lb.SyncLoadbalancerEip(ctx, userCred, lb.GetCloudprovider(), publicIp)
}
lbbgs, err := iLoadbalancer.GetILoadBalancerBackendGroups()
if err != nil {
return nil, err

View File

@@ -60,6 +60,7 @@ func (self *LoadbalancerDeleteTask) OnInit(ctx context.Context, obj db.IStandalo
func (self *LoadbalancerDeleteTask) OnLoadbalancerDeleteComplete(ctx context.Context, lb *models.SLoadbalancer, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(lb, db.ACT_DELETE, lb.GetShortDesc(ctx), self.UserCred)
logclient.AddActionLogWithStartable(self, lb, logclient.ACT_DELOCATE, nil, self.UserCred, true)
lb.DeleteEip(ctx, self.UserCred)
lb.LBPendingDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}

View File

@@ -0,0 +1,27 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package multicloud
import (
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SLoadbalancerBase struct {
SResourceBase
}
func (lb *SLoadbalancerBase) GetIEIP() (cloudprovider.ICloudEIP, error) {
return nil, nil
}

View File

@@ -17,6 +17,10 @@ package aliyun
import (
"fmt"
"strings"
"time"
"yunion.io/x/onecloud/pkg/multicloud"
"yunion.io/x/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -53,6 +57,7 @@ type BackendServers struct {
}
type SLoadbalancer struct {
multicloud.SLoadbalancerBase
region *SRegion
LoadBalancerId string //负载均衡实例ID。
@@ -68,14 +73,14 @@ type SLoadbalancer struct {
ListenerPorts ListenerPorts
ListenerPortsAndProtocol ListenerPortsAndProtocol
BackendServers BackendServers
CreateTime string //负载均衡实例的创建时间。
MasterZoneId string //实例的主可用区ID。
SlaveZoneId string //实例的备可用区ID。
InternetChargeType string //公网实例的计费方式。取值paybybandwidth按带宽计费 paybytraffic按流量计费默认值 说明 当 PayType参数的值为PrePay时只支持按带宽计费。
PayType string //实例的计费类型取值PayOnDemand按量付费 PrePay预付费
ResourceGroupId string //企业资源组ID。
LoadBalancerSpec string //负载均衡实例的的性能规格
Bandwidth int //按带宽计费的公网型实例的带宽峰值
CreateTime time.Time //负载均衡实例的创建时间。
MasterZoneId string //实例的主可用区ID。
SlaveZoneId string //实例的备可用区ID。
InternetChargeType TInternetChargeType //公网实例的计费方式。取值paybybandwidth按带宽计费 paybytraffic按流量计费默认值 说明 当 PayType参数的值为PrePay时只支持按带宽计费。
PayType string //实例的计费类型取值PayOnDemand按量付费 PrePay预付费
ResourceGroupId string //企业资源组ID。
LoadBalancerSpec string //负载均衡实例的的性能规格
Bandwidth int //按带宽计费的公网型实例的带宽峰值
}
func (lb *SLoadbalancer) GetName() string {
@@ -259,6 +264,10 @@ func (lb *SLoadbalancer) GetChargeType() string {
return "unknown"
}
func (lb *SLoadbalancer) GetCreatedAt() time.Time {
return lb.CreateTime
}
func (lb *SLoadbalancer) GetEgressMbps() int {
if lb.Bandwidth < 1 {
return 0
@@ -279,6 +288,32 @@ func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloud
return nil, cloudprovider.ErrNotFound
}
func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) {
if lb.AddressType == "internet" {
eip := SEipAddress{
region: lb.region,
IpAddress: lb.Address,
InstanceId: lb.GetGlobalId(),
InstanceType: EIP_INTANNCE_TYPE_SLB,
Status: EIP_STATUS_INUSE,
AllocationId: lb.GetGlobalId(),
AllocationTime: lb.CreateTime,
Bandwidth: lb.Bandwidth,
InternetChargeType: lb.InternetChargeType,
}
return &eip, nil
}
eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, 0, 1)
if err != nil {
return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId)
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
eips[0].region = lb.region
return &eips[0], nil
}
func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error {
params := map[string]string{}
params["RegionId"] = region.RegionId

View File

@@ -25,6 +25,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
const (
@@ -47,6 +48,7 @@ todo:
// https://cloud.tencent.com/document/api/214/30694#LoadBalancer
type SLoadbalancer struct {
multicloud.SLoadbalancerBase
region *SRegion
Status int64 `json:"Status"` // 0创建中1正常运行
@@ -343,6 +345,20 @@ func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.IClo
return ibgs, nil
}
func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) {
if self.LoadBalancerType == "OPEN" && len(self.LoadBalancerVips) > 0 {
return &SEipAddress{
region: self.region,
AddressId: self.LoadBalancerID,
AddressIp: self.LoadBalancerVips[0],
AddressType: EIP_STATUS_BIND,
InstanceId: self.LoadBalancerID,
CreatedTime: self.CreateTime,
}, nil
}
return nil, nil
}
func (self *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) {
params := map[string]string{}
for i, id := range ids {