From 67e912ded7cacaaff4aefd87830296255165734b Mon Sep 17 00:00:00 2001 From: ioito Date: Wed, 26 Jun 2019 20:23:32 +0800 Subject: [PATCH] private cloud filter eip by zone --- cmd/climc/shell/elasticips.go | 6 ++- docs/instance/instances.yaml | 1 + docs/parameters/instance.yaml | 5 +++ pkg/apis/compute/elasticips_const.go | 4 ++ pkg/apis/compute/guest_const.go | 5 ++- pkg/compute/models/elasticips.go | 59 ++++++++++++++++++++++++++++ pkg/compute/models/guest_actions.go | 8 ++++ pkg/compute/models/guests.go | 32 +++++++++++++++ pkg/mcclient/options/servers.go | 35 +++++++++-------- 9 files changed, 135 insertions(+), 20 deletions(-) diff --git a/cmd/climc/shell/elasticips.go b/cmd/climc/shell/elasticips.go index e20fd0d62c..a32830f950 100644 --- a/cmd/climc/shell/elasticips.go +++ b/cmd/climc/shell/elasticips.go @@ -24,9 +24,11 @@ import ( func init() { type ElasticipListOptions struct { - Region string `help:"Show servers in cloudregion"` + Region string `help:"List eips in cloudregion"` - Usable *bool `help:"List all zones that is usable"` + Usable *bool `help:"List all zones that is usable"` + UsableEipForAssociateType string `help:"With associate id filter which eip can associate"` + UsableEipForAssociateId string `help:"With associate type filter which eip can associate"` options.BaseListOptions } diff --git a/docs/instance/instances.yaml b/docs/instance/instances.yaml index 28ebb7095a..c8ff829a58 100644 --- a/docs/instance/instances.yaml +++ b/docs/instance/instances.yaml @@ -23,6 +23,7 @@ get: - $ref: '../parameters/instance.yaml#/hypervisor' - $ref: '../parameters/instance.yaml#/secgroup' - $ref: '../parameters/instance.yaml#/disk' + - $ref: '../parameters/instance.yaml#/usable_server_for_eip' responses: 200: description: 实例列表信息 diff --git a/docs/parameters/instance.yaml b/docs/parameters/instance.yaml index 0646fdde58..929f5e1f01 100644 --- a/docs/parameters/instance.yaml +++ b/docs/parameters/instance.yaml @@ -60,3 +60,8 @@ order_by_host: type: string enum: [desc, asc] description: 根据宿主机名称排序 +usable_server_for_eip: + name: usable_server_for_eip + in: query + type: string + description: 过滤此EIP可绑定的server列表(实例和弹性IP属于同一个账号同一个区域,若是私有云则弹性IP和实例需要在同一个可用区) \ No newline at end of file diff --git a/pkg/apis/compute/elasticips_const.go b/pkg/apis/compute/elasticips_const.go index 841c88a7e6..2577bd3817 100644 --- a/pkg/apis/compute/elasticips_const.go +++ b/pkg/apis/compute/elasticips_const.go @@ -38,3 +38,7 @@ const ( EIP_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth" EIP_CHARGE_TYPE_DEFAULT = EIP_CHARGE_TYPE_BY_TRAFFIC ) + +var ( + EIP_ASSOCIATE_VALID_TYPES = []string{EIP_ASSOCIATE_TYPE_SERVER, EIP_ASSOCIATE_TYPE_NAT_GATEWAY} +) diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index 489470dd8a..172e8d5c9d 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -153,9 +153,12 @@ var PUBLIC_CLOUD_HYPERVISORS = []string{ HYPERVISOR_AZURE, HYPERVISOR_QCLOUD, HYPERVISOR_HUAWEI, - HYPERVISOR_OPENSTACK, HYPERVISOR_UCLOUD, +} + +var PRIVATE_CLOUD_HYPERVISORS = []string{ HYPERVISOR_ZSTACK, + HYPERVISOR_OPENSTACK, } // var HYPERVISORS = []string{HYPERVISOR_ALIYUN} diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index 10067b75e8..608dfb7f80 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -122,6 +122,38 @@ func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("cloudregion_id", regionObj.GetId()) } + associateType, _ := query.GetString("usable_eip_for_associate_type") + associateId, _ := query.GetString("usable_eip_for_associate_id") + if len(associateType) > 0 && len(associateId) > 0 { + switch associateType { + case api.EIP_ASSOCIATE_TYPE_SERVER: + serverObj, err := GuestManager.FetchByIdOrName(userCred, associateId) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError("server %s not found", regionFilter) + } + return nil, httperrors.NewGeneralError(err) + } + guest := serverObj.(*SGuest) + if utils.IsInStringArray(guest.Hypervisor, api.PRIVATE_CLOUD_HYPERVISORS) { + zone := guest.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)) + } else { + region := guest.getRegion() + q = q.Equals("cloudregion_id", region.Id) + } + managerId := guest.GetHost().ManagerId + q = q.Equals("manager_id", managerId) + default: + return nil, httperrors.NewInputParameterError("Not support associate type %s, only support %s", associateType, api.EIP_ASSOCIATE_VALID_TYPES) + } + } + /*accountStr := jsonutils.GetAnyString(query, []string{"account", "account_id", "cloudaccount", "cloudaccount_id"}) if len(accountStr) > 0 { account, err := CloudaccountManager.FetchByIdOrName(nil, accountStr) @@ -169,6 +201,25 @@ func (self *SElasticip) GetRegion() *SCloudregion { return CloudregionManager.FetchRegionById(self.CloudregionId) } +func (self *SElasticip) GetNetwork() (*SNetwork, error) { + network, err := NetworkManager.FetchById(self.NetworkId) + if err != nil { + return nil, err + } + return network.(*SNetwork), nil +} + +func (self *SElasticip) GetZone() *SZone { + if len(self.NetworkId) == 0 { + return nil + } + network, err := self.GetNetwork() + if err != nil { + return nil + } + return network.getZone() +} + func (self *SElasticip) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc := self.SVirtualResourceBase.GetShortDesc(ctx) @@ -750,6 +801,14 @@ func (self *SElasticip) PerformAssociate(ctx context.Context, userCred mcclient. return nil, httperrors.NewInputParameterError("eip and server are not in the same region") } + eipZone := self.GetZone() + if eipZone != nil { + serverZone := server.getZone() + if serverZone.Id != eipZone.Id { + return nil, httperrors.NewInputParameterError("eip and server are not in the same zone") + } + } + srvHost := server.GetHost() if srvHost == nil { return nil, httperrors.NewInputParameterError("server host is not found???") diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 0f8d49e6bd..98d876db9d 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -2440,6 +2440,14 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different region") } + eipZone := eip.GetZone() + if eipZone != nil { + insZone := self.getZone() + if eipZone.Id != insZone.Id { + return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different zone") + } + } + host := self.GetHost() if host == nil { return nil, httperrors.NewInputParameterError("server host is not found???") diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7494d2cbb5..cebc964e41 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -378,6 +378,38 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ } } + usableServerForEipFilter, _ := queryDict.GetString("usable_server_for_eip") + if len(usableServerForEipFilter) > 0 { + eipObj, err := ElasticipManager.FetchByIdOrName(userCred, usableServerForEipFilter) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError("eip %s not found", usableServerForEipFilter) + } + return nil, httperrors.NewGeneralError(err) + } + eip := eipObj.(*SElasticip) + hostTable := HostManager.Query().SubQuery() + zoneTable := ZoneManager.Query().SubQuery() + hostQ := hostTable.Query(hostTable.Field("id")).Join(zoneTable, + sqlchemy.Equals(zoneTable.Field("id"), hostTable.Field("zone_id"))).Equals("manager_id", eip.ManagerId) + + if len(eip.NetworkId) > 0 { + network, err := eip.GetNetwork() + if err != nil { + return nil, err + } + zone := network.getZone() + sq := hostQ.Filter(sqlchemy.Equals(zoneTable.Field("id"), zone.GetId())).SubQuery() + q = q.In("host_id", sq) + } else { + region := eip.GetRegion() + regionTable := CloudregionManager.Query().SubQuery() + sq := hostQ.Join(regionTable, sqlchemy.Equals(zoneTable.Field("cloudregion_id"), regionTable.Field("id"))). + Filter(sqlchemy.Equals(regionTable.Field("id"), region.GetId())).SubQuery() + q = q.In("host_id", sq) + } + } + zoneFilter, _ := queryDict.GetString("zone") if len(zoneFilter) > 0 { zone, _ := ZoneManager.FetchByIdOrName(nil, zoneFilter) diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index a7f94f6ca8..e05d5cf32c 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -30,23 +30,24 @@ import ( ) type ServerListOptions struct { - Zone string `help:"Zone ID or Name"` - Wire string `help:"Wire ID or Name"` - Network string `help:"Network ID or Name"` - Disk string `help:"Disk ID or Name"` - Host string `help:"Host ID or Name"` - Baremetal *bool `help:"Show baremetal servers"` - Gpu *bool `help:"Show gpu servers"` - Secgroup string `help:"Secgroup ID or Name"` - AdminSecgroup string `help:"AdminSecgroup ID or Name"` - Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud|zstack"` - Region string `help:"Show servers in cloudregion"` - WithEip *bool `help:"Show Servers with EIP"` - WithoutEip *bool `help:"Show Servers without EIP"` - OsType string `help:"OS Type" choices:"linux|windows|vmware"` - OrderByDisk string `help:"Order by disk size" choices:"asc|desc"` - OrderByHost string `help:"Order by host name" choices:"asc|desc"` - Vpc string `help:"Vpc id or name"` + Zone string `help:"Zone ID or Name"` + Wire string `help:"Wire ID or Name"` + Network string `help:"Network ID or Name"` + Disk string `help:"Disk ID or Name"` + Host string `help:"Host ID or Name"` + Baremetal *bool `help:"Show baremetal servers"` + Gpu *bool `help:"Show gpu servers"` + Secgroup string `help:"Secgroup ID or Name"` + AdminSecgroup string `help:"AdminSecgroup ID or Name"` + Hypervisor string `help:"Show server of hypervisor" choices:"kvm|esxi|container|baremetal|aliyun|azure|aws|huawei|ucloud|zstack"` + Region string `help:"Show servers in cloudregion"` + WithEip *bool `help:"Show Servers with EIP"` + WithoutEip *bool `help:"Show Servers without EIP"` + OsType string `help:"OS Type" choices:"linux|windows|vmware"` + OrderByDisk string `help:"Order by disk size" choices:"asc|desc"` + OrderByHost string `help:"Order by host name" choices:"asc|desc"` + Vpc string `help:"Vpc id or name"` + UsableServerForEip string `help:"Eip id or name"` ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"`