fix: vpc eip misc fixes: 1. eip filter 2. lb filter 3. create eip when (#14343)

lb creating

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2022-05-29 23:51:28 +08:00
committed by GitHub
co-authored by Qiu Jian
parent 01a90bad17
commit ea5f72563b
6 changed files with 158 additions and 8 deletions
+16
View File
@@ -92,6 +92,12 @@ type LoadbalancerListInput struct {
ChargeType []string `json:"charge_type"`
// 套餐名称
LoadbalancerSpec []string `json:"loadbalancer_spec"`
// filter for EIP
WithEip *bool `json:"with_eip"`
WithoutEip *bool `json:"without_eip"`
EipAssociable *bool `json:"eip_associable"`
UsableLoadbalancerForEip string `json:"usable_loadbalancer_for_eip"`
}
type LoadbalancerAgentListInput struct {
@@ -253,6 +259,16 @@ type LoadbalancerCreateInput struct {
// 套餐名称
LoadbalancerSpec string `json:"loadbalancer_spec"`
// 弹性公网IP带宽
// 指定此参数后会创建新的弹性公网IP并绑定到新建的负载均衡
EipBw int `json:"eip_bw,omitzero"`
// 弹性公网IP线路类型
EipBgpType string `json:"eip_bgp_type,omitzero"`
// 弹性公网IP计费类型
EipChargeType string `json:"eip_charge_type,omitempty"`
// 是否跟随主机删除而自动释放
EipAutoDellocate bool `json:"eip_auto_dellocate,omitempty"`
// EIP ID
Eip string `json:"eip"`
+10
View File
@@ -231,6 +231,16 @@ func (manager *SElasticipManager) ListItemFilter(
q = q.Equals("cloudregion_id", lb.CloudregionId)
if len(lb.ManagerId) > 0 {
q = q.Equals("manager_id", lb.ManagerId)
} else {
zone, _ := lb.GetZone()
networks := NetworkManager.Query().SubQuery()
wires := WireManager.Query().SubQuery()
sq := networks.Query(networks.Field("id")).Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id"))).
Filter(sqlchemy.Equals(wires.Field("zone_id"), zone.Id)).SubQuery()
q = q.Filter(sqlchemy.In(q.Field("network_id"), sq))
gns := LoadbalancernetworkManager.Query("network_id").Equals("loadbalancer_id", lb.Id).SubQuery()
q = q.Filter(sqlchemy.NotIn(q.Field("network_id"), gns))
}
q = q.IsNullOrEmpty("associate_type")
default:
+89 -6
View File
@@ -203,6 +203,79 @@ func (man *SLoadbalancerManager) ListItemFilter(
q = q.Filter(sqlchemy.OR(c1, c2))
}
// eip filters
usableLbForEipFilter := query.UsableLoadbalancerForEip
if len(usableLbForEipFilter) > 0 {
eipObj, err := ElasticipManager.FetchByIdOrName(userCred, usableLbForEipFilter)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError("eip %s not found", usableLbForEipFilter)
}
return nil, httperrors.NewGeneralError(err)
}
eip := eipObj.(*SElasticip)
if len(eip.NetworkId) > 0 {
// kvm
sq := LoadbalancernetworkManager.Query("loadbalancer_id").Equals("network_id", eip.NetworkId).SubQuery()
q = q.NotIn("id", sq)
if cp := eip.GetCloudprovider(); cp == nil || cp.Provider == api.CLOUD_PROVIDER_ONECLOUD {
gnq := LoadbalancernetworkManager.Query().SubQuery()
nq := NetworkManager.Query().SubQuery()
wq := WireManager.Query().SubQuery()
vq := VpcManager.Query().SubQuery()
q.Join(gnq, sqlchemy.Equals(gnq.Field("loadbalancer_id"), q.Field("id")))
q.Join(nq, sqlchemy.Equals(nq.Field("id"), gnq.Field("network_id")))
q.Join(wq, sqlchemy.Equals(wq.Field("id"), nq.Field("wire_id")))
q.Join(vq, sqlchemy.Equals(vq.Field("id"), wq.Field("vpc_id")))
q.Filter(sqlchemy.IsNullOrEmpty(gnq.Field("eip_id")))
q.Filter(sqlchemy.NotEquals(vq.Field("id"), api.DEFAULT_VPC_ID))
// vpc provider thing will be handled ok below
}
}
if eip.ManagerId != "" {
q = q.Equals("manager_id", eip.ManagerId)
} else {
q = q.IsNullOrEmpty("manager_id")
}
region, err := eip.GetRegion()
if err != nil {
return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
}
q = q.Equals("cloudregion_id", region.Id)
}
withEip := (query.WithEip != nil && *query.WithEip)
withoutEip := (query.WithoutEip != nil && *query.WithoutEip) || (query.EipAssociable != nil && *query.EipAssociable)
if withEip || withoutEip {
eips := ElasticipManager.Query().SubQuery()
sq := eips.Query(eips.Field("associate_id")).Equals("associate_type", api.EIP_ASSOCIATE_TYPE_LOADBALANCER)
sq = sq.IsNotNull("associate_id").IsNotEmpty("associate_id")
if withEip {
q = q.In("id", sq)
} else if withoutEip {
q = q.NotIn("id", sq)
}
}
if query.EipAssociable != nil {
sq1 := NetworkManager.Query("id")
sq2 := WireManager.Query().SubQuery()
sq3 := VpcManager.Query().SubQuery()
sq1 = sq1.Join(sq2, sqlchemy.Equals(sq1.Field("wire_id"), sq2.Field("id")))
sq1 = sq1.Join(sq3, sqlchemy.Equals(sq2.Field("vpc_id"), sq3.Field("id")))
cond1 := []string{api.VPC_EXTERNAL_ACCESS_MODE_EIP, api.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW}
if *query.EipAssociable {
sq1 = sq1.Filter(sqlchemy.In(sq3.Field("external_access_mode"), cond1))
} else {
sq1 = sq1.Filter(sqlchemy.NotIn(sq3.Field("external_access_mode"), cond1))
}
sq := LoadbalancernetworkManager.Query("loadbalancer_id").In("network_id", sq1)
q = q.In("id", sq)
}
if len(query.AddressType) > 0 {
q = q.In("address_type", query.AddressType)
}
@@ -359,6 +432,9 @@ func (man *SLoadbalancerManager) ValidateCreateData(
quotaKeys := fetchRegionalQuotaKeys(rbacutils.ScopeProject, ownerId, region, cloudprovider)
pendingUsage := SRegionQuota{Loadbalancer: 1}
if input.EipBw > 0 && len(input.Eip) == 0 {
pendingUsage.Eip = 1
}
pendingUsage.SetKeys(quotaKeys)
if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
return nil, httperrors.NewOutOfQuotaError("%s", err)
@@ -565,11 +641,13 @@ func (lb *SLoadbalancer) StartLoadBalancerDeleteTask(ctx context.Context, userCr
}
func (lb *SLoadbalancer) StartLoadBalancerCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
taskData := jsonutils.NewDict()
eipId, _ := data.GetString("eip_id")
if len(eipId) > 0 {
taskData.Set("eip_id", jsonutils.NewString(eipId)) // for huawei internet elb
}
taskData := data.CopyIncludes(
"eip_id", // for huawei internet elb
"eip_bw",
"eip_bgp_type",
"eip_charge_type",
"eip_auto_dellocate",
)
task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerCreateTask", lb, userCred, taskData, parentTaskId, "", nil)
if err != nil {
return err
@@ -743,7 +821,12 @@ func (lb *SLoadbalancer) validatePurgeCondition(ctx context.Context) error {
func (lb *SLoadbalancer) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
lb.SetStatus(userCred, api.LB_STATUS_DELETING, "")
return lb.StartLoadBalancerDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
params := jsonutils.NewDict()
deleteEip := jsonutils.QueryBoolean(data, "delete_eip", false)
if deleteEip {
params.Set("delete_eip", jsonutils.JSONTrue)
}
return lb.StartLoadBalancerDeleteTask(ctx, userCred, params, "")
}
func (lb *SLoadbalancer) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
+35 -1
View File
@@ -32,6 +32,7 @@ import (
hostapi "yunion.io/x/onecloud/pkg/apis/host"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -797,7 +798,40 @@ func (self *SKVMRegionDriver) RequestCreateLoadbalancer(ctx context.Context, use
}
// bind eip
eipId, _ := task.GetParams().GetString("eip_id")
if len(eipId) > 0 {
eipBw, _ := task.GetParams().Int("eip_bw")
if eipBw > 0 && len(eipId) == 0 {
// create eip first
bgpType, _ := task.GetParams().GetString("eip_bgp_type")
chargeType, _ := task.GetParams().GetString("eip_charge_type")
autoDellocate := jsonutils.QueryBoolean(task.GetParams(), "eip_auto_dellocate", false)
eipPendingUsage := &models.SRegionQuota{Eip: 1}
eipPendingUsage.SetKeys(lb.GetQuotaKeys())
eip, err := models.ElasticipManager.NewEipForVMOnHost(ctx, userCred, &models.NewEipForVMOnHostArgs{
Bandwidth: int(eipBw),
BgpType: bgpType,
ChargeType: chargeType,
AutoDellocate: autoDellocate,
Loadbalancer: lb,
PendingUsage: eipPendingUsage,
})
if err != nil {
log.Errorf("NewEipForVMOnHost fail %s", err)
quotas.CancelPendingUsage(ctx, userCred, eipPendingUsage, eipPendingUsage, false)
} else {
opts := api.ElasticipAssociateInput{
InstanceId: lb.Id,
InstanceExternalId: lb.ExternalId,
InstanceType: api.EIP_ASSOCIATE_TYPE_LOADBALANCER,
}
err = eip.AllocateAndAssociateInstance(ctx, userCred, lb, opts, "")
if err != nil {
return nil, errors.Wrap(err, "AllocateAndAssociateInstance")
}
}
} else if len(eipId) > 0 {
_eip, err := models.ElasticipManager.FetchById(eipId)
if err != nil {
return nil, errors.Wrapf(err, "ElasticipManager.FetchById(%s)", eipId)
@@ -68,7 +68,8 @@ func (self *LoadbalancerDeleteTask) OnLoadbalancerDeleteComplete(ctx context.Con
Obj: lb,
Action: notifyclient.ActionDelete,
})
lb.DeleteEip(ctx, self.UserCred, false)
deleteEip := jsonutils.QueryBoolean(self.Params, "delete_eip", false)
lb.DeleteEip(ctx, self.UserCred, deleteEip)
lb.LBPendingDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
@@ -38,6 +38,12 @@ type LoadbalancerCreateOptions struct {
Cluster string `json:"cluster_id"`
Manager string
Tags []string `help:"Tags info,prefix with 'user:', eg: user:project=default" json:"-"`
Eip string `json:"eip" help:"Id or name of EIP to associate with"`
EipBw int `json:"eip_bw"`
EipChargeType string `json:"eip_charge_type"`
EipBgpType string `json:"eip_bgp_type"`
EipAutoDellocate *bool `json:"eip_auto_dellocate"`
}
func (opts *LoadbalancerCreateOptions) Params() (jsonutils.JSONObject, error) {