From cf5498ac240e388223f6763e81fb10a0d6eecc8e Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Wed, 26 Feb 2020 15:04:49 +0800 Subject: [PATCH] feature: recode structuralized GetExtraDetails and ListItemFilter --- cmd/climc/shell/buckets.go | 10 + cmd/climc/shell/cloudaccounts.go | 11 + cmd/climc/shell/cloudregions.go | 13 + go.mod | 4 +- go.sum | 10 +- pkg/apis/billing/billing.go | 21 ++ pkg/apis/compute/baremetalagent.go | 6 +- pkg/apis/compute/bucket.go | 8 +- pkg/apis/compute/cachedimage.go | 1 + pkg/apis/compute/cachedloadbalanceracl.go | 11 +- .../compute/cachedloadbalancercertificate.go | 30 +- pkg/apis/compute/cloudaccount.go | 112 +++++- pkg/apis/compute/cloudprovider.go | 194 ++++------ pkg/apis/compute/cloudproviderregion.go | 2 +- pkg/apis/compute/cloudregion.go | 18 +- pkg/apis/compute/dbinstance.go | 59 +-- pkg/apis/compute/dbinstance_account.go | 4 +- pkg/apis/compute/dbinstance_backup.go | 10 +- pkg/apis/compute/dbinstance_database.go | 11 +- pkg/apis/compute/disk.go | 40 +- pkg/apis/compute/dynamicschedtag.go | 5 +- pkg/apis/compute/elasticcache.go | 59 ++- pkg/apis/compute/elasticcache_const.go | 13 +- pkg/apis/compute/elasticcachebackup.go | 11 +- pkg/apis/compute/elasticcachesku.go | 5 +- pkg/apis/compute/elasticip.go | 5 +- pkg/apis/compute/externalproject.go | 5 +- pkg/apis/compute/geo_input.go | 42 ++- pkg/apis/compute/globalvpc.go | 16 +- pkg/apis/compute/groupguest.go | 16 +- pkg/apis/compute/groupnetwork.go | 9 +- pkg/apis/compute/guest_disk.go | 9 +- pkg/apis/compute/guestnetwork.go | 22 +- pkg/apis/compute/guests.go | 79 +++- pkg/apis/compute/host.go | 63 +++- pkg/apis/compute/hostjoin.go | 11 +- pkg/apis/compute/hostnetwork.go | 8 +- pkg/apis/compute/hostschedtag.go | 10 +- pkg/apis/compute/hoststorage.go | 5 +- pkg/apis/compute/hostwire.go | 6 +- pkg/apis/compute/input.go | 22 +- pkg/apis/compute/instance_group.go | 6 + pkg/apis/compute/instance_snapshot.go | 2 +- pkg/apis/compute/isolated_device.go | 4 +- pkg/apis/compute/keypair.go | 2 - pkg/apis/compute/loadbalancer.go | 77 ++-- pkg/apis/compute/loadbalanceracl.go | 3 + pkg/apis/compute/loadbalanceragent.go | 5 +- pkg/apis/compute/loadbalancerbackend.go | 6 +- pkg/apis/compute/loadbalancerbackendgroup.go | 29 +- pkg/apis/compute/loadbalancercluster.go | 37 +- pkg/apis/compute/loadbalancerlistener.go | 28 +- pkg/apis/compute/loadbalancerlistenerrule.go | 4 +- pkg/apis/compute/loadbalancernetwork.go | 3 +- pkg/apis/compute/nat.go | 23 +- pkg/apis/compute/natgateway.go | 39 +- pkg/apis/compute/network.go | 77 ++-- pkg/apis/compute/networkinterface.go | 7 +- pkg/apis/compute/networkschedtag.go | 8 +- pkg/apis/compute/reservedip.go | 6 +- pkg/apis/compute/routetable.go | 8 +- pkg/apis/compute/schedpolicy.go | 5 +- pkg/apis/compute/schedtag.go | 27 ++ pkg/apis/compute/secgroup.go | 10 + pkg/apis/compute/secgroupcache.go | 7 +- pkg/apis/compute/serversku.go | 17 +- pkg/apis/compute/service_catalog.go | 10 +- pkg/apis/compute/sku_const.go | 8 +- pkg/apis/compute/snapshot.go | 8 +- pkg/apis/compute/snapshotpolicy.go | 5 +- pkg/apis/compute/snapshotpolicycache.go | 7 +- pkg/apis/compute/snapshotpolicydisk.go | 2 +- pkg/apis/compute/storage.go | 32 +- pkg/apis/compute/storage_const.go | 13 +- pkg/apis/compute/storagecache.go | 2 + pkg/apis/compute/storagecachedimage.go | 2 +- pkg/apis/compute/storageschedtag.go | 8 +- pkg/apis/compute/vpc.go | 25 +- pkg/apis/compute/vpcs_const.go | 13 +- pkg/apis/compute/wire.go | 32 +- pkg/apis/compute/zone.go | 49 ++- pkg/apis/compute/zz_generated.model.go | 309 ++++++++++------ pkg/apis/desc.go | 21 ++ pkg/apis/identity/domain.go | 2 + pkg/apis/identity/endpoint.go | 6 + pkg/apis/identity/group.go | 7 +- pkg/apis/identity/identityprovider.go | 44 ++- pkg/apis/identity/input.go | 8 +- pkg/apis/identity/output.go | 29 ++ pkg/apis/identity/policy.go | 5 +- pkg/apis/identity/project.go | 5 +- pkg/apis/identity/role.go | 5 +- pkg/apis/identity/user.go | 6 +- pkg/apis/image/image.go | 6 +- pkg/apis/input.go | 144 +++++--- pkg/apis/list.go | 88 ++++- pkg/apis/monitor/alert.go | 4 +- pkg/apis/notify/contact.go | 2 +- pkg/apis/notify/notification.go | 2 +- pkg/apis/output.go | 70 +++- pkg/apis/owner.go | 22 ++ pkg/apis/yunionconf/doc.go | 1 + pkg/apis/yunionconf/input.go | 39 ++ pkg/apis/zz_generated.model.go | 33 +- pkg/cloudcommon/db/adminsharablevirtual.go | 56 ++- pkg/cloudcommon/db/caller.go | 73 +++- pkg/cloudcommon/db/db_dispatcher.go | 30 +- pkg/cloudcommon/db/domain.go | 85 +++++ pkg/cloudcommon/db/domainresource.go | 273 ++++++++++++++ pkg/cloudcommon/db/enabledbase.go | 89 +++++ .../db/enabledstatusdomainresource.go | 148 ++++++++ pkg/cloudcommon/db/enabledstatusstandalone.go | 162 ++++----- pkg/cloudcommon/db/external.go | 2 +- pkg/cloudcommon/db/fetch.go | 124 +++++++ pkg/cloudcommon/db/interface.go | 28 +- pkg/cloudcommon/db/jointbase.go | 28 ++ pkg/cloudcommon/db/metadata.go | 18 +- pkg/cloudcommon/db/metadata_test.go | 14 +- pkg/cloudcommon/db/modelbase.go | 54 ++- pkg/cloudcommon/db/opslog.go | 7 +- pkg/cloudcommon/db/orderby.go | 48 +++ pkg/cloudcommon/db/project.go | 140 ++++++- pkg/cloudcommon/db/project_resources.go | 28 +- pkg/cloudcommon/db/resourcebase.go | 61 +++- pkg/cloudcommon/db/sharablebase.go | 27 +- pkg/cloudcommon/db/sharablevirtual.go | 98 +++-- pkg/cloudcommon/db/sharedresource.go | 8 +- pkg/cloudcommon/db/standalone.go | 123 +++++-- pkg/cloudcommon/db/statusbase.go | 120 ++++++ pkg/cloudcommon/db/statusdomainresource.go | 148 ++++++++ pkg/cloudcommon/db/statusstandalone.go | 130 ++++--- pkg/cloudcommon/db/tenantcache.go | 20 +- pkg/cloudcommon/db/virtualjointbase.go | 29 ++ pkg/cloudcommon/db/virtualresource.go | 174 +++------ pkg/cloudcommon/policy/resources.go | 3 +- pkg/cloudevent/models/cloudevents.go | 7 +- pkg/cloudevent/models/cloudproviders.go | 2 +- pkg/compute/guestdrivers/baremetals.go | 4 +- pkg/compute/guestdrivers/virtualization.go | 2 +- pkg/compute/hostdrivers/base.go | 4 +- pkg/compute/models/baremetalagents.go | 104 ++++-- pkg/compute/models/billingresource.go | 79 +++- pkg/compute/models/buckets.go | 86 +++-- pkg/compute/models/cachedimages.go | 107 ++++-- pkg/compute/models/cloudaccounts.go | 174 ++++----- pkg/compute/models/cloudproviderregions.go | 4 +- pkg/compute/models/cloudproviders.go | 246 ++++++------- pkg/compute/models/cloudregionresource.go | 109 +++++- pkg/compute/models/cloudregions.go | 103 +++++- pkg/compute/models/dbinstance_accounts.go | 88 +++-- pkg/compute/models/dbinstance_backups.go | 218 +++++++---- pkg/compute/models/dbinstance_databases.go | 105 ++++-- pkg/compute/models/dbinstance_parameters.go | 108 ++++-- pkg/compute/models/dbinstance_privileges.go | 20 - pkg/compute/models/dbinstance_skus.go | 34 +- pkg/compute/models/dbinstanceresource.go | 244 +++++++++++++ pkg/compute/models/dbinstances.go | 227 +++++++----- .../models/deletepreventableresource.go | 2 +- pkg/compute/models/diskresource.go | 217 +++++++++++ pkg/compute/models/disks.go | 165 +++++---- pkg/compute/models/dnsrecords.go | 109 ++++-- pkg/compute/models/dynamicschedtags.go | 133 ++++--- pkg/compute/models/elasticcache_accounts.go | 101 +++-- pkg/compute/models/elasticcache_acls.go | 112 ++++-- pkg/compute/models/elasticcache_backups.go | 148 +++++--- pkg/compute/models/elasticcache_instances.go | 249 +++++++++---- pkg/compute/models/elasticcache_parameters.go | 110 +++++- pkg/compute/models/elasticcache_skus.go | 117 ++++-- pkg/compute/models/elasticcacheresource.go | 260 +++++++++++++ pkg/compute/models/elasticips.go | 118 ++++-- pkg/compute/models/external_projects.go | 115 ++++-- pkg/compute/models/filters.go | 2 +- pkg/compute/models/globalvpcresource.go | 126 +++++++ pkg/compute/models/globalvpcs.go | 63 +++- pkg/compute/models/groupguests.go | 53 ++- pkg/compute/models/groupjoints.go | 61 +++- pkg/compute/models/groupnetworks.go | 49 ++- pkg/compute/models/groups.go | 165 ++++++--- pkg/compute/models/guest_actions.go | 18 +- pkg/compute/models/guest_queries.go | 152 ++++---- pkg/compute/models/guest_template.go | 105 +++++- pkg/compute/models/guestdisks.go | 66 +++- pkg/compute/models/guestjoints.go | 62 +++- pkg/compute/models/guestnetworks.go | 64 +++- pkg/compute/models/guests.go | 344 +++++++----------- pkg/compute/models/helper.go | 2 +- pkg/compute/models/host_recycle.go | 6 +- pkg/compute/models/hostjoints.go | 32 ++ pkg/compute/models/hostnetworks.go | 75 +++- pkg/compute/models/hostresource.go | 225 ++++++++++++ pkg/compute/models/hosts.go | 180 +++++---- pkg/compute/models/hostschedtags.go | 50 ++- pkg/compute/models/hoststorages.go | 66 +++- pkg/compute/models/hostwires.go | 54 ++- pkg/compute/models/instance_snapshots.go | 67 +++- pkg/compute/models/isolated_devices.go | 137 ++++--- pkg/compute/models/keypairs.go | 87 ++++- .../models/loadbalancer_backendstatus.go | 6 +- pkg/compute/models/loadbalanceracls.go | 101 ++++- pkg/compute/models/loadbalanceragents.go | 125 ++++--- .../models/loadbalancerawscachedlbbg.go | 28 +- .../loadbalancerbackendgroupresource.go | 251 +++++++++++++ .../models/loadbalancerbackendgroups.go | 144 ++++++-- pkg/compute/models/loadbalancerbackends.go | 137 ++++--- pkg/compute/models/loadbalancercachedacls.go | 124 ++++++- .../models/loadbalancercachedcertificates.go | 140 ++++++- .../models/loadbalancercertificateresource.go | 156 ++++++++ .../models/loadbalancercertificates.go | 78 +++- .../models/loadbalancerclusterresource.go | 219 +++++++++++ pkg/compute/models/loadbalancerclusters.go | 148 +++++--- .../models/loadbalancerhuaweicachedlbb.go | 20 +- .../models/loadbalancerhuaweicachedlbbg.go | 34 +- .../models/loadbalancerlistenerresource.go | 216 +++++++++++ .../models/loadbalancerlistenerrules.go | 147 ++++++-- pkg/compute/models/loadbalancerlisteners.go | 150 +++++--- pkg/compute/models/loadbalancernetworks.go | 61 +++- .../models/loadbalancerqcloudcachedlbbg.go | 29 +- pkg/compute/models/loadbalancerresource.go | 302 +++++++++++++++ pkg/compute/models/loadbalancers.go | 250 ++++++++----- pkg/compute/models/managedresource.go | 217 ++++++++++- pkg/compute/models/natdtable.go | 79 ++-- pkg/compute/models/natgatewayresource.go | 213 +++++++++++ pkg/compute/models/natgateways.go | 291 ++++++++------- pkg/compute/models/natstable.go | 134 ++++--- pkg/compute/models/networkinterfaces.go | 124 +++++-- pkg/compute/models/networkresource.go | 225 ++++++++++++ pkg/compute/models/networks.go | 256 +++++-------- pkg/compute/models/networkschedtags.go | 48 ++- pkg/compute/models/purge.go | 5 +- pkg/compute/models/quotas.go | 32 +- pkg/compute/models/reservedips.go | 106 ++++-- pkg/compute/models/routetables.go | 134 ++++--- pkg/compute/models/schedpolicies.go | 114 ++++-- pkg/compute/models/schedtagjoint.go | 59 ++- pkg/compute/models/schedtagresource.go | 157 ++++++++ pkg/compute/models/schedtags.go | 78 +++- pkg/compute/models/secgroupcache.go | 109 +++++- pkg/compute/models/secgrouprules.go | 36 +- pkg/compute/models/secgroups.go | 93 ++++- pkg/compute/models/service_catalog.go | 62 +++- pkg/compute/models/skus.go | 95 +++-- pkg/compute/models/snapshotpolicy.go | 78 +++- pkg/compute/models/snapshotpolicycache.go | 129 +++++-- pkg/compute/models/snapshotpolicydisks.go | 63 +++- pkg/compute/models/snapshots.go | 116 +++++- pkg/compute/models/storagecachedimages.go | 37 +- pkg/compute/models/storagecaches.go | 141 ++++--- pkg/compute/models/storageresource.go | 226 ++++++++++++ pkg/compute/models/storages.go | 134 ++++--- pkg/compute/models/storageschedtags.go | 49 ++- pkg/compute/models/vpcresource.go | 268 ++++++++++++++ pkg/compute/models/vpcs.go | 220 ++++++----- pkg/compute/models/wireresource.go | 263 +++++++++++++ pkg/compute/models/wires.go | 211 ++++++----- pkg/compute/models/zoneresource.go | 148 +++++++- pkg/compute/models/zones.go | 142 ++++---- pkg/compute/regiondrivers/aliyun.go | 10 +- pkg/compute/regiondrivers/aws.go | 40 +- pkg/compute/regiondrivers/huawei.go | 49 ++- pkg/compute/regiondrivers/kvm.go | 26 +- pkg/compute/regiondrivers/managedvirtual.go | 20 +- pkg/compute/regiondrivers/qcloud.go | 28 +- .../baremetal_server_sync_status_task.go | 13 +- pkg/compute/tasks/disk_delete_task.go | 2 +- pkg/compute/tasks/guest_delete_task.go | 2 +- .../tasks/guest_detach_all_disks_task.go | 2 +- pkg/compute/tasks/guest_detach_disk_task.go | 6 +- pkg/compute/tasks/guest_syncstatus_task.go | 8 +- pkg/compute/tasks/host_maintenance_task.go | 5 +- pkg/image/models/image_guest.go | 84 ++++- pkg/image/models/images.go | 116 ++++-- pkg/keystone/models/credentials.go | 77 +++- pkg/keystone/models/domains.go | 97 +++-- pkg/keystone/models/endpoints.go | 83 ++++- pkg/keystone/models/expandidps.go | 27 +- pkg/keystone/models/groups.go | 82 ++++- pkg/keystone/models/identity_provider.go | 87 ++++- pkg/keystone/models/identitybase.go | 161 ++++++-- pkg/keystone/models/policies.go | 71 +++- pkg/keystone/models/projects.go | 76 +++- pkg/keystone/models/regions.go | 60 ++- pkg/keystone/models/roles.go | 88 ++++- pkg/keystone/models/services.go | 71 +++- pkg/keystone/models/users.go | 84 ++++- pkg/logger/models/baremetalevents.go | 7 +- pkg/mcclient/options/servers.go | 6 +- pkg/monitor/models/alert.go | 51 ++- pkg/notify/models/mod_contact.go | 37 +- pkg/notify/models/mod_notification.go | 33 +- .../predicates/k8s/host_status_predicate.go | 2 +- pkg/scheduler/cache/candidate/base.go | 4 +- pkg/util/stringutils2/sortedstrings.go | 3 + pkg/yunionconf/models/parameters.go | 50 ++- vendor/modules.txt | 4 +- vendor/yunion.io/x/jsonutils/go.mod | 4 +- vendor/yunion.io/x/jsonutils/go.sum | 6 +- vendor/yunion.io/x/jsonutils/unmarshal.go | 23 +- vendor/yunion.io/x/sqlchemy/query.go | 18 +- vendor/yunion.io/x/sqlchemy/table.go | 4 +- 299 files changed, 16056 insertions(+), 4629 deletions(-) create mode 100644 pkg/apis/billing/billing.go create mode 100644 pkg/apis/desc.go create mode 100644 pkg/apis/identity/output.go create mode 100644 pkg/apis/owner.go create mode 100644 pkg/apis/yunionconf/doc.go create mode 100644 pkg/apis/yunionconf/input.go create mode 100644 pkg/cloudcommon/db/domainresource.go create mode 100644 pkg/cloudcommon/db/enabledbase.go create mode 100644 pkg/cloudcommon/db/enabledstatusdomainresource.go create mode 100644 pkg/cloudcommon/db/orderby.go create mode 100644 pkg/cloudcommon/db/statusbase.go create mode 100644 pkg/cloudcommon/db/statusdomainresource.go create mode 100644 pkg/compute/models/dbinstanceresource.go create mode 100644 pkg/compute/models/diskresource.go create mode 100644 pkg/compute/models/elasticcacheresource.go create mode 100644 pkg/compute/models/globalvpcresource.go create mode 100644 pkg/compute/models/hostresource.go create mode 100644 pkg/compute/models/loadbalancerbackendgroupresource.go create mode 100644 pkg/compute/models/loadbalancercertificateresource.go create mode 100644 pkg/compute/models/loadbalancerclusterresource.go create mode 100644 pkg/compute/models/loadbalancerlistenerresource.go create mode 100644 pkg/compute/models/loadbalancerresource.go create mode 100644 pkg/compute/models/natgatewayresource.go create mode 100644 pkg/compute/models/networkresource.go create mode 100644 pkg/compute/models/schedtagresource.go create mode 100644 pkg/compute/models/storageresource.go create mode 100644 pkg/compute/models/vpcresource.go create mode 100644 pkg/compute/models/wireresource.go diff --git a/cmd/climc/shell/buckets.go b/cmd/climc/shell/buckets.go index f3fef34d73..83d2f8c590 100644 --- a/cmd/climc/shell/buckets.go +++ b/cmd/climc/shell/buckets.go @@ -32,12 +32,22 @@ import ( func init() { type BucketListOptions struct { options.BaseListOptions + DistinctField string `help:"query specified distinct field"` } R(&BucketListOptions{}, "bucket-list", "List all buckets", func(s *mcclient.ClientSession, args *BucketListOptions) error { params, err := options.ListStructToParams(args) if err != nil { return err } + if len(args.DistinctField) > 0 { + params.Add(jsonutils.NewString(args.DistinctField), "extra_field") + result, err := modules.Buckets.Get(s, "distinct-field", params) + if err != nil { + return err + } + fmt.Println(result) + return nil + } result, err := modules.Buckets.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/cloudaccounts.go b/cmd/climc/shell/cloudaccounts.go index 1aa62ea1f9..b7846c8b39 100644 --- a/cmd/climc/shell/cloudaccounts.go +++ b/cmd/climc/shell/cloudaccounts.go @@ -31,6 +31,8 @@ func init() { type CloudaccountListOptions struct { options.BaseListOptions Capability []string `help:"capability filter" choices:"project|compute|network|loadbalancer|objectstore|rds|cache|event"` + + DistinctField string `help:"distinct field"` } R(&CloudaccountListOptions{}, "cloud-account-list", "List cloud accounts", func(s *mcclient.ClientSession, args *CloudaccountListOptions) error { var params *jsonutils.JSONDict @@ -44,6 +46,15 @@ func init() { params.Add(jsonutils.NewStringArray(args.Capability), "capability") } } + if len(args.DistinctField) > 0 { + params.Add(jsonutils.NewString(args.DistinctField), "extra_field") + result, err := modules.Cloudaccounts.Get(s, "distinct-field", params) + if err != nil { + return err + } + fmt.Println(result) + return nil + } result, err := modules.Cloudaccounts.List(s, params) if err != nil { return err diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go index 153e3797dc..e39cbe5bd0 100644 --- a/cmd/climc/shell/cloudregions.go +++ b/cmd/climc/shell/cloudregions.go @@ -15,6 +15,8 @@ package shell import ( + "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" @@ -32,12 +34,23 @@ func init() { Service string `help:"List regions which service has available skus" choices:"dbinstances|servers"` City string `help:"List regions in the specified city"` + + DistinctField string `help:"list the specified distinct field, e.g. city, region"` } R(&CloudregionListOptions{}, "cloud-region-list", "List cloud regions", func(s *mcclient.ClientSession, opts *CloudregionListOptions) error { params, err := options.ListStructToParams(opts) if err != nil { return err } + if len(opts.DistinctField) > 0 { + params.Add(jsonutils.NewString(opts.DistinctField), "extra_field") + result, err := modules.Cloudregions.Get(s, "distinct-field", params) + if err != nil { + return err + } + fmt.Println(result) + return nil + } result, err := modules.Cloudregions.List(s, params) if err != nil { return err diff --git a/go.mod b/go.mod index bb45ac765e..8bc99ce838 100644 --- a/go.mod +++ b/go.mod @@ -141,11 +141,11 @@ require ( k8s.io/klog v0.1.0 // indirect k8s.io/kubernetes v1.12.3 yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 - yunion.io/x/jsonutils v0.0.0-20200113074440-9297fd00ba07 + yunion.io/x/jsonutils v0.0.0-20200303051356-aa609aba0cda yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070 yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e - yunion.io/x/sqlchemy v0.0.0-20200221103553-6a98f7f8ab92 + yunion.io/x/sqlchemy v0.0.0-20200303101347-d1e82c81b4e1 yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3 ) diff --git a/go.sum b/go.sum index e16c5276c9..a29da3c6ab 100644 --- a/go.sum +++ b/go.sum @@ -701,8 +701,8 @@ yunion.io/x/executor v0.0.0-20200227030256-a18417815e74 h1:A15C6VdVRWvmQ9pAJHrUs yunion.io/x/executor v0.0.0-20200227030256-a18417815e74/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws= yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051 h1:vtZw2iwGrsARNSwRTREGjmr2BWPdxbmXVkb3kI1qu28= yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634= -yunion.io/x/jsonutils v0.0.0-20200113074440-9297fd00ba07 h1:i6Im3w4UoyCIKOEtr0Y3aAPGrL9FYAzeFXoj3daXXt0= -yunion.io/x/jsonutils v0.0.0-20200113074440-9297fd00ba07/go.mod h1:NpWHLv3D1iMpsp1Kv6o1ASPZmuSKutE3RIMhxKSOeAM= +yunion.io/x/jsonutils v0.0.0-20200303051356-aa609aba0cda h1:wSwQj3MDGchGYM2RAo1riYhrTz4apH+5XyBnchuDi84= +yunion.io/x/jsonutils v0.0.0-20200303051356-aa609aba0cda/go.mod h1:T7kxQJR13+t7z0TuT+Wzd7MTxBOk2H9c0pO1ONQSv90= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b h1:Z9z+7iegu0HXuL+S8taVWRd1P4b9JJOgPXIeoqYrj7c= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE= yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d h1:59zrDL7Ft+hDukguJRmLr/Gdu/9V75x+yX99ovZwfaA= @@ -710,13 +710,11 @@ yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2 yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf h1:OsKC+2ghZHwp+Ztm/MwKlLKKRiE7QcPG8eTp0GmsHbg= yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= -yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa h1:+7zYi8MhaOW/53/7FOERnhQqAU4UhgaOVIS+AMzTKNU= -yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070 h1:rKnYgtvMHKmzPEUTkyNjyKOG7wzjpUvI7fcZwLNGQXw= yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo= yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo= -yunion.io/x/sqlchemy v0.0.0-20200221103553-6a98f7f8ab92 h1:Iz70/alKMAW3KeePhmExuhWsYw1MGTcMr5ewAL5lj1I= -yunion.io/x/sqlchemy v0.0.0-20200221103553-6a98f7f8ab92/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI= +yunion.io/x/sqlchemy v0.0.0-20200303101347-d1e82c81b4e1 h1:OJrTCU1YooMykhSIsYvvJsOE+BdXIVXf4LgfDP7mibE= +yunion.io/x/sqlchemy v0.0.0-20200303101347-d1e82c81b4e1/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI= yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3 h1:bfC8EhXYvyGYldRWlzxiCM39Zfj3s3+zham9mW2h2LE= yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng= diff --git a/pkg/apis/billing/billing.go b/pkg/apis/billing/billing.go new file mode 100644 index 0000000000..a45b7bfd2c --- /dev/null +++ b/pkg/apis/billing/billing.go @@ -0,0 +1,21 @@ +package billing + +import "time" + +type BillingDetailsInfo struct { +} + +type BillingResourceListInput struct { + // 计费类型,按需计费和预付费 + // pattern:prepaid|postpaid + BillingType string `json:"billing_type"` + + // 计费过期时间的查询起始时间 + BillingExpireSince time.Time `json:"billing_expire_since"` + // 计费过期时间的查询终止时间 + BillingExpireBefore time.Time `json:"billing_expire_before"` + + // 计费周期 + // example:7d + BillingCycle string `json:"billing_cycle"` +} diff --git a/pkg/apis/compute/baremetalagent.go b/pkg/apis/compute/baremetalagent.go index 69de0cbf23..86ebc6f16d 100644 --- a/pkg/apis/compute/baremetalagent.go +++ b/pkg/apis/compute/baremetalagent.go @@ -18,9 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type BaremetalagentDetails struct { apis.StandaloneResourceDetails - SBaremetalagent + ZoneResourceInfo - // 裸金属代理程序所在的可用区 - // example: zone1 - Zone string `json:"zone"` + SBaremetalagent } diff --git a/pkg/apis/compute/bucket.go b/pkg/apis/compute/bucket.go index b9110d194c..0a50452711 100644 --- a/pkg/apis/compute/bucket.go +++ b/pkg/apis/compute/bucket.go @@ -51,10 +51,12 @@ type BucketCreateInput struct { type BucketDetails struct { apis.VirtualResourceDetails + ManagedResourceInfo + CloudregionResourceInfo + SBucket - CloudproviderInfo - + // 访问URL列表 AccessUrls []cloudprovider.SBucketAccessUrl `json:"access_urls"` } @@ -96,6 +98,6 @@ func (input *BucketMetadataInput) Validate() error { type BucketListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput + RegionalFilterListInput } diff --git a/pkg/apis/compute/cachedimage.go b/pkg/apis/compute/cachedimage.go index 3e505a3a0c..70ada4b2bc 100644 --- a/pkg/apis/compute/cachedimage.go +++ b/pkg/apis/compute/cachedimage.go @@ -28,6 +28,7 @@ type CachedImageUncacheImageInput struct { type CachedimageDetails struct { apis.StandaloneResourceDetails + SCachedimage // 镜像状态, 和info里面的status一致 diff --git a/pkg/apis/compute/cachedloadbalanceracl.go b/pkg/apis/compute/cachedloadbalanceracl.go index 4ef1bda3c0..36d3a53f80 100644 --- a/pkg/apis/compute/cachedloadbalanceracl.go +++ b/pkg/apis/compute/cachedloadbalanceracl.go @@ -18,7 +18,14 @@ import "yunion.io/x/onecloud/pkg/apis" type CachedLoadbalancerAclDetails struct { apis.SharableVirtualResourceDetails - SCachedLoadbalancerAcl + CloudregionResourceInfo + ManagedResourceInfo - CloudproviderInfo + SCachedLoadbalancerAcl +} + +type CachedLoadbalancerAclListInput struct { + apis.SharableVirtualResourceListInput + RegionalFilterListInput + ManagedResourceListInput } diff --git a/pkg/apis/compute/cachedloadbalancercertificate.go b/pkg/apis/compute/cachedloadbalancercertificate.go index 15034e2361..7f9db9bdac 100644 --- a/pkg/apis/compute/cachedloadbalancercertificate.go +++ b/pkg/apis/compute/cachedloadbalancercertificate.go @@ -18,7 +18,33 @@ import "yunion.io/x/onecloud/pkg/apis" type CachedLoadbalancerCertificateDetails struct { apis.VirtualResourceDetails - SCachedLoadbalancerCertificate + ManagedResourceInfo + CloudregionResourceInfo + LoadbalancerCertificateResourceInfo - CloudproviderInfo + SCachedLoadbalancerCertificate +} + +type CachedLoadbalancerCertificateListInput struct { + apis.VirtualResourceListInput + ManagedResourceListInput + RegionalFilterListInput + LoadbalancerCertificateFilterListInput +} + +type LoadbalancerCertificateResourceInfo struct { + // 负载均衡证书名称 + Certificate string `json:"certificate"` +} + +type LoadbalancerCertificateFilterListInput struct { + // 证书名称或ID + Certificate string `json:"certificate"` + + // swagger:ignore + // Deprecated + CertificateId string `json:"certificate_id" deprecated-by:"certificate"` + + // 以证书名称排序 + OrderByCertificate string `json:"order_by_certificate"` } diff --git a/pkg/apis/compute/cloudaccount.go b/pkg/apis/compute/cloudaccount.go index f66cd08cad..5378d7e04e 100644 --- a/pkg/apis/compute/cloudaccount.go +++ b/pkg/apis/compute/cloudaccount.go @@ -23,8 +23,114 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" ) +type CloudenvResourceInfo struct { + // 云平台名称 + // example: Google + Provider string `json:"provider,omitempty"` + + // 云平台品牌 + // example: Google + Brand string `json:"brand,omitempty"` + + // 云环境 + // example: public + CloudEnv string `json:"cloud_env,omitempty"` + + // Environment + Environment string `json:"environment,omitempty"` +} + +type CloudenvResourceListInput struct { + // 列出指定云平台的资源,支持的云平台如下 + // + // | Provider | 开始支持版本 | 平台 | + // |-----------|------------|-------------------------------------| + // | OneCloud | 0.0 | OneCloud内置私有云,包括KVM和裸金属管理 | + // | VMware | 1.2 | VMware vCenter | + // | OpenStack | 2.6 | OpenStack M版本以上私有云 | + // | ZStack | 2.10 | ZStack私有云 | + // | Aliyun | 2.0 | 阿里云 | + // | Aws | 2.3 | Amazon AWS | + // | Azure | 2.2 | Microsoft Azure | + // | Google | 2.13 | Google Cloud Platform | + // | Qcloud | 2.3 | 腾讯云 | + // | Huawei | 2.5 | 华为公有云 | + // | Ucloud | 2.7 | UCLOUD | + // | Ctyun | 2.13 | 天翼云 | + // | S3 | 2.11 | 通用s3对象存储 | + // | Ceph | 2.11 | Ceph对象存储 | + // | Xsky | 2.11 | XSKY启明星辰Ceph对象存储 | + // + // enum: OneCloud,VMware,Aliyun,Qcloud,Azure,Aws,Huawei,OpenStack,Ucloud,ZStack,Google,Ctyun,S3,Ceph,Xsky" + Providers []string `json:"providers"` + // swagger:ignore + // Deprecated + Provider []string `json:"provider" deprecated-by:"providers"` + + // 列出指定云平台品牌的资源,一般来说brand和provider相同,除了以上支持的provider之外,还支持以下band + // + // | Brand | Provider | 说明 | + // |----------|----------|------------| + // | DStack | ZStack | 滴滴云私有云 | + // + Brands []string `json:"brands"` + // swagger:ignore + // Deprecated + Brand []string `json:"brand" deprecated-by:"brands"` + + // 列出指定云环境的资源,支持云环境如下: + // + // | CloudEnv | 说明 | + // |-----------|--------| + // | public | 公有云 | + // | private | 私有云 | + // | onpremise | 本地IDC | + // + // enum: public,private,onpremise + CloudEnv string `json:"cloud_env"` + + // swagger:ignore + // Deprecated + // description: this param will be deprecate at 3.0 + PublicCloud bool `json:"public_cloud"` + // swagger:ignore + // Deprecated + // description: this param will be deprecate at 3.0 + IsPublic bool `json:"is_public"` + + // swagger:ignore + // Deprecated + // description: this param will be deprecate at 3.0 + PrivateCloud bool `json:"private_cloud"` + // swagger:ignore + // Deprecated + // description: this param will be deprecate at 3.0 + IsPrivate bool `json:"is_private"` + + // swagger:ignore + // Deprecated + // description: this param will be deprecate at 3.0 + IsOnPremise bool `json:"is_on_premise"` + + // 以平台名称排序 + // pattern:asc|desc + OrderByProvider string `json:"order_by_provider"` + + // 以平台品牌排序 + // pattern:asc|desc + OrderByBrand string `json:"order_by_brand"` +} + +type CloudaccountResourceInfo struct { + CloudenvResourceInfo + + // 云账号名称 + // example: google-account + Account string `json:"account,omitempty"` +} + type CloudaccountCreateInput struct { - apis.EnabledStatusStandaloneResourceCreateInput + apis.EnabledStatusDomainLevelResourceCreateInput // 指定云平台 // Qcloud: 腾讯云 @@ -100,7 +206,7 @@ func (i CloudaccountShareModeInput) Validate() error { } type CloudaccountListInput struct { - apis.EnabledStatusStandaloneResourceListInput + apis.EnabledStatusDomainLevelResourceListInput ManagedResourceListInput @@ -118,7 +224,7 @@ type ProviderProject struct { } type CloudaccountDetail struct { - apis.StandaloneResourceDetails + apis.EnabledStatusDomainLevelResourceDetails SCloudaccount // 子订阅项目信息 diff --git a/pkg/apis/compute/cloudprovider.go b/pkg/apis/compute/cloudprovider.go index cfbe6f9ea1..cb511dd06b 100644 --- a/pkg/apis/compute/cloudprovider.go +++ b/pkg/apis/compute/cloudprovider.go @@ -21,31 +21,17 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" ) -type CloudproviderInfo struct { - // 云平台 - // example: Google - Provider string `json:"provider,omitempty"` - - // 云平台品牌 - // example: Google - Brand string `json:"brand,omitempty"` - - // 云账号名称 - // example: google-account - Account string `json:"account,omitempty"` +type ManagedResourceInfo struct { + CloudaccountResourceInfo // 云账号Id // example: 4d3c8979-9dd0-439b-8d78-36fe1ab1666c AccountId string `json:"account_id,omitempty"` - // 子订阅名称 + // 云订阅名称 // example: google-account Manager string `json:"manager,omitempty"` - // 子订阅Id - // example: fa4aaf88-aed8-422d-84e7-56dea533b364 - ManagerId string `json:"manager_id,omitempty"` - // 子订阅所在项目名称 // example: system ManagerProject string `json:"manager_project,omitempty"` @@ -60,50 +46,9 @@ type CloudproviderInfo struct { // 子订阅所在域Id // example: default ManagerDomainId string `json:"manager_domain_id,omitempty"` - - // 区域名称 - // example: 腾讯云 华南地区(广州) - Region string `json:"region,omitempty"` - // 区域Id - // example: 6151c89b-77f2-4d43-8ef9-cd03d604a16b - RegionId string `json:"region_id,omitempty"` - // 区域Id - // example: 6151c89b-77f2-4d43-8ef9-cd03d604a16b - CloudregionId string `json:"cloudregion_id,omitempty"` - // 区域外部Id - // Qcloud/ap-guangzhou - RegionExternalId string `json:"region_external_id,omitempty"` - // 区域外部Id(不携带平台信息) - // example: ap-guangzhou - RegionExtId string `json:"region_ext_id,omitempty"` - - // 可用区名称 - // example: 腾讯云 广州四区 - Zone string `json:"zone,omitempty"` - // 可用区Id - // example: 336ac6d2-b80d-43bb-86d5-1ebf474da8d4 - ZoneId string `json:"zone_id,omitempty"` - // 可用区外部Id - // example: ap-guangzhou-4 - ZoneExtId string `json:"zone_ext_id,omitempty"` - - // 云环境 - // example: public - CloudEnv string `json:"cloud_env,omitempty"` } -type CloudproviderDetails struct { - apis.StandaloneResourceDetails - SCloudprovider - - // 云账号名称 - // example: google-account - Cloudaccount string `json:"cloudaccount"` - // 子订阅同步状态 - SyncStatus2 string `json:"sync_status2"` - // 支持服务列表 - Capabilities []string `json:"capabilities"` - +type SCloudproviderUsage struct { // 云主机数量 // example: 1 GuestCount int `json:"guest_count"` @@ -132,12 +77,63 @@ type CloudproviderDetails struct { ProjectCount int `json:"project_count"` // 同步区域数量 SyncRegionCount int `json:"sync_region_count"` +} + +func (usage *SCloudproviderUsage) IsEmpty() bool { + if usage.HostCount > 0 { + return false + } + if usage.VpcCount > 0 { + return false + } + if usage.StorageCount > 0 { + return false + } + if usage.StorageCacheCount > 0 { + return false + } + if usage.EipCount > 0 { + return false + } + if usage.SnapshotCount > 0 { + return false + } + if usage.LoadbalancerCount > 0 { + return false + } + /*if usage.ProjectCount > 0 { + return false + } + if usage.SyncRegionCount > 0 { + return false + }*/ + return true +} + +type CloudproviderDetails struct { + apis.EnabledStatusStandaloneResourceDetails + apis.ProjectizedResourceInfo + + SCloudprovider + + // 云账号名称 + // example: google-account + Cloudaccount string `json:"cloudaccount"` + // 子订阅同步状态 + SyncStatus2 string `json:"sync_status2"` + // 支持服务列表 + Capabilities []string `json:"capabilities"` + + SCloudproviderUsage // 子订阅品牌信息 Brand string `json:"brand"` } type ManagedResourceListInput struct { + apis.DomainizedResourceListInput + CloudenvResourceListInput + // 列出关联指定云订阅(ID或Name)的资源 Cloudprovider string `json:"cloudprovider"` // List objects belonging to the cloud provider @@ -169,80 +165,17 @@ type ManagedResourceListInput struct { // description: this param will be deprecate at 3.0 AccountId string `json:"account_id" deprecated-by:"cloudaccount"` - // 列出指定云平台的资源,支持的云平台如下 - // - // | Provider | 开始支持版本 | 平台 | - // |-----------|------------|-------------------------------------| - // | OneCloud | 0.0 | OneCloud内置私有云,包括KVM和裸金属管理 | - // | VMware | 1.2 | VMware vCenter | - // | OpenStack | 2.6 | OpenStack M版本以上私有云 | - // | ZStack | 2.10 | ZStack私有云 | - // | Aliyun | 2.0 | 阿里云 | - // | Aws | 2.3 | Amazon AWS | - // | Azure | 2.2 | Microsoft Azure | - // | Google | 2.13 | Google Cloud Platform | - // | Qcloud | 2.3 | 腾讯云 | - // | Huawei | 2.5 | 华为公有云 | - // | Ucloud | 2.7 | UCLOUD | - // | Ctyun | 2.13 | 天翼云 | - // | S3 | 2.11 | 通用s3对象存储 | - // | Ceph | 2.11 | Ceph对象存储 | - // | Xsky | 2.11 | XSKY启明星辰Ceph对象存储 | - // - // enum: OneCloud,VMware,Aliyun,Qcloud,Azure,Aws,Huawei,OpenStack,Ucloud,ZStack,Google,Ctyun,S3,Ceph,Xsky" - Providers []string `json:"providers"` - // swagger:ignore - // Deprecated - Provider []string `json:"provider" deprecated-by:"providers"` - - // 列出指定云平台品牌的资源,一般来说brand和provider相同,除了以上支持的provider之外,还支持以下band - // - // | Brand | Provider | 说明 | - // |----------|----------|------------| - // | DStack | ZStack | 滴滴云私有云 | - // - Brands []string `json:"brands"` - // swagger:ignore - // Deprecated - Brand []string `json:"brand" deprecated-by:"brands"` - - // 列出指定云环境的资源,支持云环境如下: - // - // | CloudEnv | 说明 | - // |-----------|--------| - // | public | 公有云 | - // | private | 私有云 | - // | onpremise | 本地IDC | - // - // enum: public,private,onpremise - CloudEnv string `json:"cloud_env"` - - // swagger:ignore - // Deprecated - // description: this param will be deprecate at 3.0 - PublicCloud bool `json:"public_cloud"` - // swagger:ignore - // Deprecated - // description: this param will be deprecate at 3.0 - IsPublic bool `json:"is_public"` - - // swagger:ignore - // Deprecated - // description: this param will be deprecate at 3.0 - PrivateCloud bool `json:"private_cloud"` - // swagger:ignore - // Deprecated - // description: this param will be deprecate at 3.0 - IsPrivate bool `json:"is_private"` - - // swagger:ignore - // Deprecated - // description: this param will be deprecate at 3.0 - IsOnPremise bool `json:"is_on_premise"` - // 过滤资源,是否为非OneCloud内置私有云管理的资源 // default: false IsManaged bool `json:"is_managed"` + + // 以云账号名称排序 + // pattern:asc|desc + OrderByAccount string `json:"order_by_account"` + + // 以云订阅名称排序 + // pattern:asc|desc + OrderByManager string `json:"order_by_manager"` } func (input *ManagedResourceListInput) AfterUnmarshal() { @@ -271,6 +204,7 @@ type CloudproviderListInput struct { apis.EnabledStatusStandaloneResourceListInput ManagedResourceListInput + apis.ProjectizedResourceListInput UsableResourceListInput diff --git a/pkg/apis/compute/cloudproviderregion.go b/pkg/apis/compute/cloudproviderregion.go index 2be032a818..a76d6f0496 100644 --- a/pkg/apis/compute/cloudproviderregion.go +++ b/pkg/apis/compute/cloudproviderregion.go @@ -17,7 +17,7 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type CloudproviderregionDetails struct { - apis.JoinModelBaseDetails + apis.JointResourceBaseDetails Cloudprovider string Cloudregion string diff --git a/pkg/apis/compute/cloudregion.go b/pkg/apis/compute/cloudregion.go index a00e77fef2..0a47806a6a 100644 --- a/pkg/apis/compute/cloudregion.go +++ b/pkg/apis/compute/cloudregion.go @@ -16,10 +16,7 @@ package compute import "yunion.io/x/onecloud/pkg/apis" -type CloudregionDetails struct { - apis.StandaloneResourceDetails - SCloudregion - +type SCloudregionUsage struct { // 虚拟私有网络数量 // example: 2 VpcCount int `json:"vpc_count,allowempty"` @@ -37,11 +34,22 @@ type CloudregionDetails struct { GuestIncrementCount int `json:"guest_increment_count,allowempty"` } -type CloudregionInfo struct { +type CloudregionDetails struct { + apis.EnabledStatusStandaloneResourceDetails + + SCloudregionUsage + + SCloudregion +} + +type CloudregionResourceInfo struct { // 区域的名称 // example: Default Region string `json:"region"` + // 区域的名称 + Cloudregion string `json:"cloudregion"` + // 区域的Id // example: default RegionId string `json:"region_id"` diff --git a/pkg/apis/compute/dbinstance.go b/pkg/apis/compute/dbinstance.go index c2214d2d38..69c7b21a65 100644 --- a/pkg/apis/compute/dbinstance.go +++ b/pkg/apis/compute/dbinstance.go @@ -165,18 +165,18 @@ type SDBInstanceRecoveryConfigInput struct { type DBInstanceListInput struct { apis.VirtualResourceListInput - ZonalFilterListInput - ManagedResourceListInput VpcFilterListInput + + // 以可用区过滤数据库实例 + Zone string `json:"zone"` } type DBInstanceBackupListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput RegionalFilterListInput - DbinstanceFilterListInput + DBInstanceFilterListInputBase } type DBInstancePrivilegeListInput struct { @@ -191,38 +191,27 @@ type DBInstancePrivilegeListInput struct { type DBInstanceParameterListInput struct { apis.StandaloneResourceListInput - DbinstanceFilterListInput + DBInstanceFilterListInput } type DBInstanceDatabaseListInput struct { apis.StatusStandaloneResourceListInput - DbinstanceFilterListInput + DBInstanceFilterListInput } type DBInstanceAccountListInput struct { apis.StatusStandaloneResourceListInput - DbinstanceFilterListInput -} - -type DbinstanceFilterListInput struct { - // filter by dbinstance - Dbinstance string `json:"dbinstance"` - // swagger:ignore - // Deprecated - // filter by dbinstance_id - DbinstanceId string `json:"dbinstance_id" deprecated-by:"dbinstance"` + DBInstanceFilterListInput } type DBInstanceDetails struct { apis.VirtualResourceDetails + VpcResourceInfo + SDBInstance - CloudproviderInfo - // 虚拟私有网络名称 - // example: test-vpc - Vpc string `json:"vpc"` // 安全组名称 // example: Default Secgroup string `json:"secgroup"` @@ -232,6 +221,32 @@ type DBInstanceDetails struct { // IP子网名称 // example: test-network Network string `json:"network"` - // 标签信息 - Metadata map[string]string `json:"metadata"` +} + +type DBInstanceResourceInfoBase struct { + // RDS实例名称 + DBInstance string `json:"dbinstance"` +} + +type DBInstanceResourceInfo struct { + DBInstanceResourceInfoBase + + // 归属VPC ID + VpcId string `json:"vpc_id"` + + VpcResourceInfo +} + +type DBInstanceFilterListInputBase struct { + // 以RDS实例过滤 + DBInstance string `json:"dbinstance"` + + // 以RDS实例名字排序 + OrderByDBInstance string `json:"order_by_dbinstance"` +} + +type DBInstanceFilterListInput struct { + DBInstanceFilterListInputBase + + VpcFilterListInput } diff --git a/pkg/apis/compute/dbinstance_account.go b/pkg/apis/compute/dbinstance_account.go index 1f6282cb0d..1e75374e0e 100644 --- a/pkg/apis/compute/dbinstance_account.go +++ b/pkg/apis/compute/dbinstance_account.go @@ -80,7 +80,9 @@ type DBInstancePrivilege struct { } type DBInstanceAccountDetails struct { - apis.StandaloneResourceDetails + apis.StatusStandaloneResourceDetails + DBInstanceResourceInfo + SDBInstanceAccount // 账号权限列表 diff --git a/pkg/apis/compute/dbinstance_backup.go b/pkg/apis/compute/dbinstance_backup.go index 706ec4bdb6..2f5e526a76 100644 --- a/pkg/apis/compute/dbinstance_backup.go +++ b/pkg/apis/compute/dbinstance_backup.go @@ -45,10 +45,10 @@ type DBInstanceBackupCreateInput struct { type DBInstanceBackupDetails struct { apis.VirtualResourceDetails + ManagedResourceInfo + CloudregionResourceInfo + + DBInstanceResourceInfoBase + SDBInstanceBackup - - // RDS实例名称 - DBInstance string `json:"dbinstance"` - - CloudproviderInfo } diff --git a/pkg/apis/compute/dbinstance_database.go b/pkg/apis/compute/dbinstance_database.go index 640948678e..51db7b5bd6 100644 --- a/pkg/apis/compute/dbinstance_database.go +++ b/pkg/apis/compute/dbinstance_database.go @@ -62,9 +62,18 @@ type DBInstanceDatabaseCreateInput struct { } type DBInstancedatabaseDetails struct { - apis.StandaloneResourceDetails + apis.StatusStandaloneResourceDetails + DBInstanceResourceInfo + SDBInstanceDatabase // 数据库权限 DBInstanceprivileges []DBInstancePrivilege `json:"dbinstanceprivileges"` } + +type DBInstanceparameterDetails struct { + apis.StandaloneResourceDetails + DBInstanceResourceInfo + + SDBInstanceParameter +} diff --git a/pkg/apis/compute/disk.go b/pkg/apis/compute/disk.go index d4a122dfbd..cf18298c74 100644 --- a/pkg/apis/compute/disk.go +++ b/pkg/apis/compute/disk.go @@ -18,6 +18,7 @@ import ( "time" "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/apis/billing" ) type DiskCreateInput struct { @@ -94,12 +95,9 @@ type SnapshotPolicyFilterListInput struct { type DiskListInput struct { apis.VirtualResourceListInput - - ManagedResourceListInput - - BillingFilterListInput + billing.BillingResourceListInput StorageFilterListInput - StorageShareFilterListInput + SnapshotPolicyFilterListInput ServerFilterListInput @@ -123,12 +121,18 @@ type DiskListInput struct { } type DiskFilterListInput struct { + StorageFilterListInput + // 以指定虚拟磁盘(ID或Name)过滤列表结果 Disk string `json:"disk"` // swagger:ignore // Deprecated // filter by disk_id DiskId string `json:"disk_id" deprecated-by:"disk"` + + // 以磁盘名称排序 + // pattern:asc|desc + OrderByDisk string `json:"order_by_disk"` } type SimpleGuest struct { @@ -144,17 +148,9 @@ type SimpleSnapshotPolicy struct { type DiskDetails struct { apis.VirtualResourceDetails - SDisk - CloudproviderInfo + StorageResourceInfo - // 云平台 - Provider string `json:"provider"` - // 存储名称 - Storage string `json:"storage"` - // 存储类型 - StorageType string `json:"storage_type"` - // 介质类型 - MediumType string `json:"medium_type"` + SDisk // 所挂载的虚拟机 Guests []SimpleGuest `json:"guests"` @@ -178,3 +174,17 @@ type DiskDetails struct { // 最多可创建手动快照数量 MaxManualSnapshotCount int `json:"max_manual_snapshot_count"` } + +type DiskResourceInfoBase struct { + // 磁盘名称 + Disk string `json:"disk"` +} + +type DiskResourceInfo struct { + DiskResourceInfoBase + + // 存储ID + StorageId string `json:"storage_id"` + + StorageResourceInfo +} diff --git a/pkg/apis/compute/dynamicschedtag.go b/pkg/apis/compute/dynamicschedtag.go index f29cdbca51..2e2e0bac8e 100644 --- a/pkg/apis/compute/dynamicschedtag.go +++ b/pkg/apis/compute/dynamicschedtag.go @@ -18,8 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type DynamicschedtagDetails struct { apis.StandaloneResourceDetails - SDynamicschedtag + SchedtagResourceInfo - Schedtag string `json:"schedtag"` - ResourceType string `json:"resource_type"` + SDynamicschedtag } diff --git a/pkg/apis/compute/elasticcache.go b/pkg/apis/compute/elasticcache.go index ffa08568f7..5e002da0ef 100644 --- a/pkg/apis/compute/elasticcache.go +++ b/pkg/apis/compute/elasticcache.go @@ -18,13 +18,64 @@ import "yunion.io/x/onecloud/pkg/apis" type ElasticcacheDetails struct { apis.VirtualResourceDetails + VpcResourceInfo + ZoneResourceInfoBase SElasticcache - CloudproviderInfo - - // 虚拟私有网络名称 - Vpc string `json:"vpc"` // IP子网名称 Network string `json:"network"` } + +type ElasticcacheResourceInfo struct { + // 弹性缓存实例名称 + Elasticcache string `json:"elasticcache"` + + // 引擎 + Engine string `json:"engine"` + // 引擎版本 + EngineVersion string `json:"engine_version"` + + // 归属VPC ID + VpcId string `json:"vpc_id"` + + VpcResourceInfo + + // 归属Zone ID + ZoneId string `json:"zone_id"` + + ZoneResourceInfoBase +} + +type ElasticcacheFilterListInput struct { + // 以弹性缓存实例过滤 + Elasticcache string `json:"elasticcache"` + + // 以弹性缓存实例名称排序 + OrderByElasticcache string `json:"order_by_elasticcache"` + + VpcFilterListInput + + ZonalFilterListBase +} + +type ElasticcacheAccountDetails struct { + apis.StatusStandaloneResourceDetails + ElasticcacheResourceInfo + + SElasticcacheAccount +} + +type ElasticcacheAclDetails struct { + apis.StandaloneResourceDetails + ElasticcacheResourceInfo + + SElasticcacheAcl +} + +type ElasticcacheParameterDetails struct { + apis.StandaloneResourceDetails + ElasticcacheResourceInfo + + SElasticcacheParameter +} diff --git a/pkg/apis/compute/elasticcache_const.go b/pkg/apis/compute/elasticcache_const.go index 39a89da1a7..01fdd75db1 100644 --- a/pkg/apis/compute/elasticcache_const.go +++ b/pkg/apis/compute/elasticcache_const.go @@ -109,25 +109,30 @@ const ( type ElasticcacheListInput struct { apis.VirtualResourceListInput - - ZonalFilterListInput VpcFilterListInput - - ManagedResourceListInput + ZonalFilterListBase } type ElasticcacheAccountListInput struct { apis.StatusStandaloneResourceListInput + + ElasticcacheFilterListInput } type ElasticcacheAclListInput struct { apis.StandaloneResourceListInput + + ElasticcacheFilterListInput } type ElasticcacheBackupListInput struct { apis.StatusStandaloneResourceListInput + + ElasticcacheFilterListInput } type ElasticcacheParameterListInput struct { apis.StandaloneResourceListInput + + ElasticcacheFilterListInput } diff --git a/pkg/apis/compute/elasticcachebackup.go b/pkg/apis/compute/elasticcachebackup.go index 938d13eb27..06f99573f5 100644 --- a/pkg/apis/compute/elasticcachebackup.go +++ b/pkg/apis/compute/elasticcachebackup.go @@ -17,13 +17,8 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type ElasticcacheBackupDetails struct { - apis.StandaloneResourceDetails + apis.StatusStandaloneResourceDetails + ElasticcacheResourceInfo + SElasticcacheBackup - - CloudproviderInfo - - // 引擎 - Engine string `json:"engine"` - // 引擎版本 - EngineVersion string `json:"engine_version"` } diff --git a/pkg/apis/compute/elasticcachesku.go b/pkg/apis/compute/elasticcachesku.go index 4aa40901ac..f0356f9e14 100644 --- a/pkg/apis/compute/elasticcachesku.go +++ b/pkg/apis/compute/elasticcachesku.go @@ -17,6 +17,9 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type ElasticcacheSkuDetails struct { - apis.StandaloneResourceDetails + apis.StatusStandaloneResourceDetails + CloudregionResourceInfo + ZoneResourceInfoBase + SElasticcacheSku } diff --git a/pkg/apis/compute/elasticip.go b/pkg/apis/compute/elasticip.go index b605e24464..703ce8280a 100644 --- a/pkg/apis/compute/elasticip.go +++ b/pkg/apis/compute/elasticip.go @@ -70,9 +70,10 @@ type SElasticipCreateInput struct { type ElasticipDetails struct { apis.VirtualResourceDetails - SElasticip + ManagedResourceInfo + CloudregionResourceInfo - CloudproviderInfo + SElasticip // 绑定资源名称 AssociateName string `json:"associate_name"` diff --git a/pkg/apis/compute/externalproject.go b/pkg/apis/compute/externalproject.go index 6de2f4d171..843d14f650 100644 --- a/pkg/apis/compute/externalproject.go +++ b/pkg/apis/compute/externalproject.go @@ -18,9 +18,8 @@ import "yunion.io/x/onecloud/pkg/apis" type ExternalProjectDetails struct { apis.StandaloneResourceDetails + apis.ProjectizedResourceInfo + ManagedResourceInfo SExternalProject - CloudproviderInfo - - Tenant string `json:"tenant"` } diff --git a/pkg/apis/compute/geo_input.go b/pkg/apis/compute/geo_input.go index a08e7172b1..4695a8c34f 100644 --- a/pkg/apis/compute/geo_input.go +++ b/pkg/apis/compute/geo_input.go @@ -36,19 +36,28 @@ type RegionalFilterListInput struct { // Deprecated // description: this param will be deprecate at 3.0 RegionId string `json:"region_id" deprecated-by:"cloudregion"` + + // 按区域名称过滤 + OrderByRegion string `json:"order_by_region"` + // 按城市过滤 + OrderByCity string `json:"order_by_city"` } type ZonalFilterListInput struct { RegionalFilterListInput - // 过滤处于指定可用区内的资源 - Zone string `json:"zone"` - // swagger:ignore - // Deprecated - // filter by zone_id - ZoneId string `json:"zone_id" deprecated-by:"zone"` + ZonalFilterListBase +} + +type ZonalFilterListBase struct { + ZoneResourceInput + // 过滤处于多个指定可用区内的资源 Zones []string `json:"zones"` + + // 按可用区名称排序 + // pattern:asc|desc + OrderByZone string `json:"order_by_zone"` } func (input ZonalFilterListInput) ZoneList() []string { @@ -59,17 +68,6 @@ func (input ZonalFilterListInput) ZoneList() []string { return input.Zones } -type HostFilterListInput struct { - ZonalFilterListInput - - // 过滤关联指定宿主机(ID或Name)的列表结果 - Host string `json:"host"` - // swagger:ignore - // Deprecated - // filter by host_id - HostId string `json:"host_id" deprecated-by:"host"` -} - type CloudregionListInput struct { apis.EnabledStatusStandaloneResourceListInput apis.DomainizedResourceListInput @@ -98,3 +96,13 @@ type ZoneListInput struct { // 过滤提供特定服务的可用区 Service string `json:"service"` } + +type ZoneResourceInput struct { + // 可用区ID或名称 + // example:zone1 + Zone string `json:"zone"` + + // swagger:ignore + // Deprecated + ZoneId string `json:"zone_id" deprecated-by:"zone"` +} diff --git a/pkg/apis/compute/globalvpc.go b/pkg/apis/compute/globalvpc.go index 132985e715..5227426848 100644 --- a/pkg/apis/compute/globalvpc.go +++ b/pkg/apis/compute/globalvpc.go @@ -23,6 +23,20 @@ type GlobalVpcCreateInput struct { } type GlobalVpcDetails struct { - apis.StandaloneResourceDetails + apis.EnabledStatusStandaloneResourceDetails + SGlobalVpc } + +type GlobalVpcResourceInfo struct { + // 全局VPC名称 + Globalvpc string `json:"globalvpc"` +} + +type GlobalVpcResourceListInput struct { + // 以GlobalVpc的过滤 + Globalvpc string `json:"globalvpc"` + + // 以GlobalVpc的名称排序 + OrderByGlobalvpc string `json:"order_by_globalvpc"` +} diff --git a/pkg/apis/compute/groupguest.go b/pkg/apis/compute/groupguest.go index ce7b0dcd03..6f2ebc039c 100644 --- a/pkg/apis/compute/groupguest.go +++ b/pkg/apis/compute/groupguest.go @@ -18,12 +18,18 @@ import ( "yunion.io/x/onecloud/pkg/apis" ) -type GroupguestDetails struct { - apis.JoinModelBaseDetails +type GroupJointResourceDetails struct { + apis.VirtualJointResourceBaseDetails - Instancegroup string - Server string - Guest string + // 主机组的名称 + Instancegroup string `json:"instance_group"` +} + +type GroupguestDetails struct { + GroupJointResourceDetails + + Server string + Guest string SGroupguest } diff --git a/pkg/apis/compute/groupnetwork.go b/pkg/apis/compute/groupnetwork.go index 33115ec6e1..7a868d464e 100644 --- a/pkg/apis/compute/groupnetwork.go +++ b/pkg/apis/compute/groupnetwork.go @@ -14,16 +14,11 @@ package compute -import ( - "yunion.io/x/onecloud/pkg/apis" -) - type GroupnetworkDetails struct { - apis.JoinModelBaseDetails + GroupJointResourceDetails + SGroupnetwork - // 主机组名称 - Instancegroup string // IP子网名称 Network string } diff --git a/pkg/apis/compute/guest_disk.go b/pkg/apis/compute/guest_disk.go index 1599d3318a..e95076ae9f 100644 --- a/pkg/apis/compute/guest_disk.go +++ b/pkg/apis/compute/guest_disk.go @@ -14,16 +14,11 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type GuestDiskDetails struct { - apis.JoinModelBaseDetails + GuestJointResourceDetails + SGuestdisk - // 云主机名称 - Guest string - // 云主机名称 - Server string // 磁盘名称 Disk string diff --git a/pkg/apis/compute/guestnetwork.go b/pkg/apis/compute/guestnetwork.go index ac9d396609..38a602ebbc 100644 --- a/pkg/apis/compute/guestnetwork.go +++ b/pkg/apis/compute/guestnetwork.go @@ -14,16 +14,24 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type GuestnetworkDetails struct { - apis.JoinModelBaseDetails + GuestJointResourceDetails + SGuestnetwork - // 云主机名称 - Guest string - // 云主机名称 - Server string // IP子网名称 Network string } + +type GuestnetworkShortDesc struct { + // IP地址 + IpAddr string `json:"ip_addr"` + // 是否为外网网卡 + IsExit bool `json:"is_exit"` + // IPv6地址 + Ip6Addr string `json:"ip6_addr"` + // Mac地址 + Mac string `json:"mac"` + // Bonding的配对网卡MAC + TeamWith string `json:"team_with"` +} diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index cc1e9712a2..88cda89ac0 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -20,6 +20,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/apis/billing" ) type ServerFilterListInput struct { @@ -42,10 +43,12 @@ type ServerFilterListInput struct { type ServerListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput HostFilterListInput + NetworkFilterListInput - BillingFilterListInput + + billing.BillingResourceListInput + GroupFilterListInput SecgroupFilterListInput DiskFilterListInput @@ -66,12 +69,11 @@ type ServerListInput struct { // 列出操作系统为指定值的主机 // enum: linux,windows,vmware OsType string `json:"os_type"` + // 对列表结果按照磁盘进行排序 // enum: asc,desc OrderByDisk string `json:"order_by_disk"` - // 对主机列表结果按照宿主机名称进行排序 - // enum: asc,desc - OrderByHost string `json:"order_by_host"` + // 列出可以挂载指定EIP的主机 UsableServerForEip string `json:"usable_server_for_eip"` @@ -80,8 +82,9 @@ type ServerListInput struct { ResourceType string `json:"resource_type"` // 返回开启主备机功能的主机 GetBackupGuestsOnHost *bool `json:"get_backup_guests_on_host"` + // 根据宿主机 SN 过滤 - HostSn string `json:"host_sn"` + // HostSn string `json:"host_sn"` } func (input *ServerListInput) AfterUnmarshal() { @@ -132,14 +135,17 @@ type ServerResumeInput struct { type ServerDetails struct { apis.VirtualResourceDetails + SGuest - CloudproviderInfo + + HostResourceInfo // details // 网络概要 Networks string `json:"networks"` // 磁盘概要 Disks string `json:"disks"` + // 磁盘详情 DisksInfo *jsonutils.JSONArray `json:"disks_info"` // 虚拟机Ip列表 @@ -159,21 +165,62 @@ type ServerDetails struct { // common IsPrepaidRecycle bool `json:"is_prepaid_recycle"` - // 备机所在宿主机名称 + // 备份主机所在宿主机名称 BackupHostName string `json:"backup_host_name"` - // 北京所在宿主机状态 + // 备份主机所在宿主机状态 BackupHostStatus string `json:"backup_host_status"` - // 宿主机名称 - Host string `json:"host"` - // 宿主机SN - HostSN string `json:"host_sn"` - CanRecycle bool `json:"can_recycle"` + + // 是否可以回收 + CanRecycle bool `json:"can_recycle"` + // 自动释放时间 AutoDeleteAt time.Time `json:"auto_delete_at"` - // 标签 - Metadata map[string]string `json:"metadata"` // 磁盘数量 DiskCount int `json:"disk_count"` // 是否支持ISO启动 CdromSupport bool `json:"cdrom_support"` + + // 磁盘大小 + // example:30720 + DiskSizeMb int64 `json:"disk"` + // IP地址列表字符串 + // example: 10.165.2.1,172.16.8.1 + IPs string `json:"ips"` + // 网卡信息 + Nics []GuestnetworkShortDesc `json:"nics"` + + // 归属VPC + Vpc string `json:"vpc"` + // 归属VPC ID + VpcId string `json:"vpc_id"` + + // 关联安全组列表 + Secgroups []apis.StandaloneShortDesc `json:"secgroups"` + // 关联主安全组 + Secgroup string `json:"secgroup"` + + // 浮动IP + Eip string `json:"eip"` + // 浮动IP类型 + EipMode string `json:"eip_mode"` + + // 密钥对 + Keypair string `json:"keypair"` + + // 直通设备(GPU)列表 + IsolatedDevices []SIsolatedDevice `json:"isolated_devices"` + // 是否支持GPU + IsGpu bool `json:"is_gpu"` + + // Cdrom信息 + Cdrom string `json:"cdrom,allowempty"` +} + +type GuestJointResourceDetails struct { + apis.VirtualJointResourceBaseDetails + + // 云主机名称 + Guest string `json:"guest"` + // 云主机名称 + Server string `json:"server"` } diff --git a/pkg/apis/compute/host.go b/pkg/apis/compute/host.go index b1f08aa656..9935a58ad5 100644 --- a/pkg/apis/compute/host.go +++ b/pkg/apis/compute/host.go @@ -73,10 +73,11 @@ type HostListInput struct { } type HostDetails struct { - apis.StandaloneResourceDetails - SHost + apis.EnabledStatusStandaloneResourceDetails + ManagedResourceInfo + ZoneResourceInfo - CloudproviderInfo + SHost Schedtags []SchedtagShortDescDetails `json:"schedtags"` @@ -124,3 +125,59 @@ type HostDetails struct { // 标签 Metadata map[string]string `json:"metadata"` } + +type HostResourceInfo struct { + // 归属云订阅ID + ManagerId string `json:"manager_id"` + + ManagedResourceInfo + + // 归属可用区ID + ZoneId string `json:"zone_id"` + + ZoneResourceInfo + + // 宿主机名称 + Host string `json:"host"` + + // 宿主机序列号 + HostSN string `json:"host_sn"` + + // 宿主机状态 + HostStatus string `json:"host_status"` + + // 宿主机服务状态` + HostServiceStatus string `json:"host_service_status"` + + // 宿主机类型 + HostType string `json:"host_type"` +} + +type HostFilterListInput struct { + ZonalFilterListInput + ManagedResourceListInput + + HostFilterListInputBase +} + +type HostFilterListInputBase struct { + HostResourceInput + + // 以宿主机序列号过滤 + HostSN string `json:"host_sn"` + + // 以宿主机名称排序 + OrderByHost string `json:"order_by_host"` + + // 以宿主机序列号名称排序 + OrderByHostSN string `json:"order_by_host_sn"` +} + +type HostResourceInput struct { + // 宿主机或物理机(ID或Name) + Host string `json:"host"` + // swagger:ignore + // Deprecated + // filter by host_id + HostId string `json:"host_id" deprecated-by:"host"` +} diff --git a/pkg/apis/compute/hostjoin.go b/pkg/apis/compute/hostjoin.go index 6a6bbfb650..e3586fe941 100644 --- a/pkg/apis/compute/hostjoin.go +++ b/pkg/apis/compute/hostjoin.go @@ -14,9 +14,18 @@ package compute -type HostJointsDetails struct { +import "yunion.io/x/onecloud/pkg/apis" + +type HostJointResourceDetailsBase struct { // 宿主机名称 Host string `json:"host"` // 裸金属服务器名称 + // Deprecated Baremetal string `json:"baremetal"` } + +type HostJointResourceDetails struct { + apis.JointResourceBaseDetails + + HostJointResourceDetailsBase +} diff --git a/pkg/apis/compute/hostnetwork.go b/pkg/apis/compute/hostnetwork.go index 77032ca984..4e9b7f6dee 100644 --- a/pkg/apis/compute/hostnetwork.go +++ b/pkg/apis/compute/hostnetwork.go @@ -14,12 +14,10 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type HostnetworkDetails struct { - apis.JoinModelBaseDetails - HostJointsDetails - SHostwire + HostJointResourceDetails + + SHostnetwork // IP子网名称 Network string `json:"network"` diff --git a/pkg/apis/compute/hostschedtag.go b/pkg/apis/compute/hostschedtag.go index b1b8b53999..1b34ea90d6 100644 --- a/pkg/apis/compute/hostschedtag.go +++ b/pkg/apis/compute/hostschedtag.go @@ -14,12 +14,10 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type HostschedtagDetails struct { - apis.JoinModelBaseDetails - HostJointsDetails - SHostschedtag + SchedtagJointResourceDetails - Schedtag string `json:"string"` + HostJointResourceDetailsBase + + SHostschedtag } diff --git a/pkg/apis/compute/hoststorage.go b/pkg/apis/compute/hoststorage.go index 9b4db63c64..be283eb53e 100644 --- a/pkg/apis/compute/hoststorage.go +++ b/pkg/apis/compute/hoststorage.go @@ -16,13 +16,10 @@ package compute import ( "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/apis" ) type HoststorageDetails struct { - apis.JoinModelBaseDetails - HostJointsDetails + HostJointResourceDetails SHoststorage diff --git a/pkg/apis/compute/hostwire.go b/pkg/apis/compute/hostwire.go index 2564328123..d1530469db 100644 --- a/pkg/apis/compute/hostwire.go +++ b/pkg/apis/compute/hostwire.go @@ -14,11 +14,9 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type HostwireDetails struct { - apis.JoinModelBaseDetails - HostJointsDetails + HostJointResourceDetails + SHostwire // 二层网络名称 diff --git a/pkg/apis/compute/input.go b/pkg/apis/compute/input.go index f89e9e1a65..fd1fd3f428 100644 --- a/pkg/apis/compute/input.go +++ b/pkg/apis/compute/input.go @@ -52,6 +52,7 @@ type CachedimageListInput struct { type ExternalProjectListInput struct { apis.StandaloneResourceListInput + apis.ProjectizedResourceListInput ManagedResourceListInput } @@ -59,31 +60,28 @@ type ExternalProjectListInput struct { type RouteTableListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput - RegionalFilterListInput VpcFilterListInput } type SnapshotPolicyCacheListInput struct { - apis.ResourceBaseListInput + apis.StatusStandaloneResourceListInput + ManagedResourceListInput + RegionalFilterListInput // filter by snapshotpolicy Id or Name Snapshotpolicy string `json:"snapshotpolicy"` } -type BillingFilterListInput struct { - // filter by billing_type - BillingType string `json:"billing_type"` -} - type NetworkInterfaceListInput struct { apis.StatusStandaloneResourceListInput ManagedResourceListInput + RegionalFilterListInput } type BaremetalagentListInput struct { apis.StandaloneResourceListInput + ZonalFilterListInput } type DnsRecordListInput struct { @@ -92,6 +90,7 @@ type DnsRecordListInput struct { type DynamicschedtagListInput struct { apis.StandaloneResourceListInput + SchedtagFilterListInput } type GuestTemplateListInput struct { @@ -100,6 +99,7 @@ type GuestTemplateListInput struct { type SchedpolicyListInput struct { apis.StandaloneResourceListInput + SchedtagFilterListInput } type ServiceCatalogListInput struct { @@ -109,3 +109,9 @@ type ServiceCatalogListInput struct { type SnapshotPolicyListInput struct { apis.VirtualResourceListInput } + +type DnsRecordDetails struct { + apis.AdminSharableVirtualResourceDetails + + SDnsRecord +} diff --git a/pkg/apis/compute/instance_group.go b/pkg/apis/compute/instance_group.go index 157fb3b5cd..cfd14b326c 100644 --- a/pkg/apis/compute/instance_group.go +++ b/pkg/apis/compute/instance_group.go @@ -18,7 +18,11 @@ import "yunion.io/x/onecloud/pkg/apis" type InstanceGroupListInput struct { apis.VirtualResourceListInput + + apis.EnabledResourceBaseListInput + ZonalFilterListInput + ServerFilterListInput // 以service_type过滤列表结果 @@ -29,6 +33,8 @@ type InstanceGroupListInput struct { type InstanceGroupDetail struct { apis.VirtualResourceDetails + ZoneResourceInfo + SGroup // 云主机数量 diff --git a/pkg/apis/compute/instance_snapshot.go b/pkg/apis/compute/instance_snapshot.go index 022838fa93..36457e69f7 100644 --- a/pkg/apis/compute/instance_snapshot.go +++ b/pkg/apis/compute/instance_snapshot.go @@ -31,7 +31,7 @@ type SimpleSnapshot struct { Size int `json:"size"` } -type InstnaceSnapshotDetails struct { +type InstanceSnapshotDetails struct { apis.VirtualResourceDetails SInstanceSnapshot diff --git a/pkg/apis/compute/isolated_device.go b/pkg/apis/compute/isolated_device.go index a834dc62c5..40c6c07a59 100644 --- a/pkg/apis/compute/isolated_device.go +++ b/pkg/apis/compute/isolated_device.go @@ -18,10 +18,10 @@ import "yunion.io/x/onecloud/pkg/apis" type IsolateDeviceDetails struct { apis.StandaloneResourceDetails + HostResourceInfo + SIsolatedDevice - // 宿主机名称 - Host string `json:"host"` // 云主机名称 Guest string `json:"guest"` // 云主机状态 diff --git a/pkg/apis/compute/keypair.go b/pkg/apis/compute/keypair.go index 8adbfc2382..0c51b7926d 100644 --- a/pkg/apis/compute/keypair.go +++ b/pkg/apis/compute/keypair.go @@ -50,8 +50,6 @@ type KeypairDetails struct { // 关联云主机次数 LinkedGuestCount int `json:"linked_guest_count"` - // 用户Id - OwnerId string `json:"owner_id"` // 用户名称 OwnerName string `json:"owner_name"` } diff --git a/pkg/apis/compute/loadbalancer.go b/pkg/apis/compute/loadbalancer.go index d4ad21ed0c..3879890f57 100644 --- a/pkg/apis/compute/loadbalancer.go +++ b/pkg/apis/compute/loadbalancer.go @@ -33,12 +33,8 @@ const ( type LoadbalancerListenerListInput struct { apis.VirtualResourceListInput + LoadbalancerFilterListInput - ManagedResourceListInput - RegionalFilterListInput - - // filter by loadbalancer - Loadbalancer string `json:"loadbalancer"` // filter by backend_group BackendGroup string `json:"backend_group"` // filter by acl @@ -47,19 +43,17 @@ type LoadbalancerListenerListInput struct { type LoadbalancerListenerRuleListInput struct { apis.VirtualResourceListInput + LoadbalancerListenerFilterListInput - // filter by listener - Listener string `json:"listener"` // filter by backend_group BackendGroup string `json:"backend_group"` } type LoadbalancerListInput struct { apis.VirtualResourceListInput - - ManagedResourceListInput - ZonalFilterListInput - NetworkFilterListInput + VpcFilterListInput + ZonalFilterListBase + NetworkFilterListBase // filter by cluster Cluster string `json:"cluster"` @@ -67,9 +61,7 @@ type LoadbalancerListInput struct { type LoadbalancerAgentListInput struct { apis.StandaloneResourceListInput - - // filter by loadbalancercluster - Cluster string `json:"cluster"` + LoadbalancerClusterFilterListInput } type LoadbalancerCertificateListInput struct { @@ -83,23 +75,20 @@ type LoadbalancerCertificateListInput struct { type LoadbalancerBackendListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput - RegionalFilterListInput + LoadbalancerBackendGroupFilterListInput // filter by backend server Backend string `json:"backend"` + // filter by backend group - BackendGroup string `json:"backend_group"` + // BackendGroup string `json:"backend_group"` } type LoadbalancerBackendGroupListInput struct { apis.VirtualResourceListInput - RegionalFilterListInput - ManagedResourceListInput + LoadbalancerFilterListInput - // filter by loadbalancer - Loadbalancer string `json:"loadbalancer"` // filter LoadbalancerBackendGroup with no reference NoRef *bool `json:"no_ref"` } @@ -108,26 +97,62 @@ type LoadbalancerClusterListInput struct { apis.StandaloneResourceListInput ZonalFilterListInput - WireFilterListInput + WireFilterListBase } type LoadbalancerAclListInput struct { apis.SharableVirtualResourceListInput + + ManagedResourceListInput + RegionalFilterListInput } type LoadbalancerDetails struct { apis.VirtualResourceDetails - SLoadbalancer + VpcResourceInfo + ZoneResourceInfoBase + NetworkResourceInfoBase - CloudproviderInfo + SLoadbalancer // 公网IP地址 Eip string `json:"eip"` + // 公网IP地址类型: 弹性、非弹性 // example: public_ip EipMode string `json:"eip_mode"` - // 虚拟私有网络名称 - Vpc string `json:"vpc"` + // 后端服务器组名称 BackendGroup string `json:"backend_group"` } + +type LoadbalancerResourceInfo struct { + // 负载均衡名称 + Loadbalancer string `json:"loadbalancer"` + + // VPC ID + VpcId string `json:"vpc_id"` + + VpcResourceInfo + + // 可用区ID + ZoneId string `json:"zone_id"` + + ZoneResourceInfoBase +} + +type LoadbalancerFilterListInput struct { + VpcFilterListInput + + ZonalFilterListBase + + // 负载均衡名称 + Loadbalancer string `json:"loadbalancer"` + + // swagger:ignore + // Deprecated + LoadbalancerId string `json:"loadbalancer_id" deprecated-by:"loadbalancer"` + + // 以负载均衡名称排序 + OrderByLoadbalancer string `json:"order_by_loadbalancer"` +} diff --git a/pkg/apis/compute/loadbalanceracl.go b/pkg/apis/compute/loadbalanceracl.go index 66a23b36b9..d666f6784c 100644 --- a/pkg/apis/compute/loadbalanceracl.go +++ b/pkg/apis/compute/loadbalanceracl.go @@ -18,5 +18,8 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerAclDetails struct { apis.SharableVirtualResourceDetails + ManagedResourceInfo + CloudregionResourceInfo + SLoadbalancerAcl } diff --git a/pkg/apis/compute/loadbalanceragent.go b/pkg/apis/compute/loadbalanceragent.go index 879adf125a..f654c8cfdd 100644 --- a/pkg/apis/compute/loadbalanceragent.go +++ b/pkg/apis/compute/loadbalanceragent.go @@ -18,8 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerAgentDetails struct { apis.StandaloneResourceDetails - SLoadbalancerAgent + LoadbalancerClusterResourceInfo - ZoneInfo ZoneInfo - Cluster string `json:"cluster"` + SLoadbalancerAgent } diff --git a/pkg/apis/compute/loadbalancerbackend.go b/pkg/apis/compute/loadbalancerbackend.go index 7b47b92924..74245d823b 100644 --- a/pkg/apis/compute/loadbalancerbackend.go +++ b/pkg/apis/compute/loadbalancerbackend.go @@ -18,9 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerBackendDetails struct { apis.VirtualResourceDetails + LoadbalancerBackendGroupResourceInfo + SLoadbalancerBackend - - CloudproviderInfo - - VpcId string `json:"vpc_id"` } diff --git a/pkg/apis/compute/loadbalancerbackendgroup.go b/pkg/apis/compute/loadbalancerbackendgroup.go index 7f26a6db40..b307a73553 100644 --- a/pkg/apis/compute/loadbalancerbackendgroup.go +++ b/pkg/apis/compute/loadbalancerbackendgroup.go @@ -18,8 +18,31 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerBackendGroupDetails struct { apis.VirtualResourceDetails - SLoadbalancerBackendGroup + LoadbalancerResourceInfo - Loadbalancer string `json:"loadbalancer"` - CloudregionInfo + SLoadbalancerBackendGroup +} + +type LoadbalancerBackendGroupResourceInfo struct { + LoadbalancerResourceInfo + + // 负载均衡后端组名称 + BackendGroup string `json:"backend_group"` + + // 负载均衡ID + LoadbalancerId string `json:"loadbalancer_id"` +} + +type LoadbalancerBackendGroupFilterListInput struct { + LoadbalancerFilterListInput + + // 负载均衡后端组ID或名称 + BackendGroup string `json:"backend_group"` + + // swagger:ignore + // Deprecated + BackendGroupId string `json:"backend_group_id" deprecated-by:"backend_group"` + + // 以负载均衡后端组名称排序 + OrderByBackendGroup string `json:"order_by_backend_group"` } diff --git a/pkg/apis/compute/loadbalancercluster.go b/pkg/apis/compute/loadbalancercluster.go index 5c76a8732e..355960933b 100644 --- a/pkg/apis/compute/loadbalancercluster.go +++ b/pkg/apis/compute/loadbalancercluster.go @@ -16,9 +16,40 @@ package compute import "yunion.io/x/onecloud/pkg/apis" -type LoadbalancerCusterDetails struct { +type LoadbalancerClusterDetails struct { apis.StandaloneResourceDetails - SLoadbalancerCluster + ZoneResourceInfo + WireResourceInfoBase - ZoneInfo + SLoadbalancerCluster +} + +type LoadbalancerClusterResourceInfo struct { + ZoneResourceInfo + + WireResourceInfoBase + + // VPC ID + VpcId string `json:"vpc_id"` + + // VPC名称 + Vpc string `json:"vpc"` + + // 负载均衡集群名称 + Cluster string `json:"cluster"` +} + +type LoadbalancerClusterFilterListInput struct { + ZonalFilterListInput + WireFilterListBase + + // 负载均衡集群ID或名称 + Cluster string `json:"cluster"` + + // swagger:ignore + // Deprecated + ClusterId string `json:"cluster_id" deprecated-by:"cluster"` + + // 以负载均衡集群排序 + OrderByCluster string `json:"order_by_cluster"` } diff --git a/pkg/apis/compute/loadbalancerlistener.go b/pkg/apis/compute/loadbalancerlistener.go index 7ba7e0dc7c..2b0b3b8d74 100644 --- a/pkg/apis/compute/loadbalancerlistener.go +++ b/pkg/apis/compute/loadbalancerlistener.go @@ -18,13 +18,37 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerListenerDetails struct { apis.VirtualResourceDetails + LoadbalancerResourceInfo + SLoadbalancerListener BackendGroup string `json:"backend_group"` - Loadbalancer string `json:"loadbalancer"` AclName string `json:"acl_name"` CertificateName string `json:"certificate_name"` OriginCertificateId string `json:"origin_certificate_id"` +} - CloudregionInfo +type LoadbalancerListenerResourceInfo struct { + // 负载均衡监听器名称 + Listener string `json:"listener"` + + // 负载均衡ID + LoadbalancerId string `json:"loadbalancer_id"` + + LoadbalancerResourceInfo +} + +type LoadbalancerListenerFilterListInput struct { + LoadbalancerFilterListInput + + // 负载均衡监听器 + Listener string `json:"listener"` + + // 负载均衡监听器ID + // swagger:ignore + // Deprecated + ListenerId string `json:"listener_id" deprecated-by:"listener"` + + // 以负载均衡监听器名称排序 + OrderByListener string `json:"order_by_listener"` } diff --git a/pkg/apis/compute/loadbalancerlistenerrule.go b/pkg/apis/compute/loadbalancerlistenerrule.go index 8727d5131d..2630f8ced7 100644 --- a/pkg/apis/compute/loadbalancerlistenerrule.go +++ b/pkg/apis/compute/loadbalancerlistenerrule.go @@ -18,9 +18,9 @@ import "yunion.io/x/onecloud/pkg/apis" type LoadbalancerListenerRuleDetails struct { apis.VirtualResourceDetails + LoadbalancerListenerResourceInfo + SLoadbalancerListenerRule BackendGroup string `json:"backend_group"` - - CloudregionInfo } diff --git a/pkg/apis/compute/loadbalancernetwork.go b/pkg/apis/compute/loadbalancernetwork.go index d18c2fbe50..c9b658110f 100644 --- a/pkg/apis/compute/loadbalancernetwork.go +++ b/pkg/apis/compute/loadbalancernetwork.go @@ -17,7 +17,8 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type LoadbalancernetworkDetails struct { - apis.JoinModelBaseDetails + apis.VirtualJointResourceBaseDetails + SLoadbalancerNetwork // 负载均衡器名称 diff --git a/pkg/apis/compute/nat.go b/pkg/apis/compute/nat.go index e7cf73ec3c..69d18460ab 100644 --- a/pkg/apis/compute/nat.go +++ b/pkg/apis/compute/nat.go @@ -41,21 +41,18 @@ type SNatDCreateInput struct { } type NatDEntryDetails struct { - apis.StandaloneResourceDetails - // SNatDEntry + NatEntryDetails - Natgateway string `json:"natgateway"` - RealName string `json:"real_name"` + // SNatDEntry } type NatSEntryDetails struct { - apis.StandaloneResourceDetails + NatEntryDetails + // SNatSEntry - Natgateway string `json:"natgateway"` - // RealName identifies the local name of SNAT record - RealName string `json:"real_name"` - Network SimpleNetwork `json:"network"` + // SNAT归属网络 + Network SimpleNetwork `json:"network"` } type SimpleNetwork struct { @@ -68,11 +65,11 @@ type SimpleNetwork struct { } type NatgatewayDetails struct { - apis.StandaloneResourceDetails - SNatGateway + apis.StatusStandaloneResourceDetails - CloudproviderInfo - Vpc string `json:"vpc"` + VpcResourceInfo + + SNatGateway NatSpec string `json:"nat_spec"` } diff --git a/pkg/apis/compute/natgateway.go b/pkg/apis/compute/natgateway.go index e962b1bbb5..3b952bc3ac 100644 --- a/pkg/apis/compute/natgateway.go +++ b/pkg/apis/compute/natgateway.go @@ -39,7 +39,7 @@ const ( ) type NatGetewayListInput struct { - apis.StandaloneResourceListInput + apis.StatusStandaloneResourceListInput VpcFilterListInput RegionalFilterListInput @@ -47,23 +47,44 @@ type NatGetewayListInput struct { } type NatEntryListInput struct { - apis.StandaloneResourceListInput - + apis.StatusStandaloneResourceListInput + NatGatewayFilterListInput ManagedResourceListInput } type NatDEntryListInput struct { NatEntryListInput - - // filter by natgateway - Natgateway string `json:"natgateway"` } type NatSEntryListInput struct { NatEntryListInput + NetworkFilterListBase +} - // filter by natgateway +type NatGatewayResourceInfo struct { + // NAT网关名称 Natgateway string `json:"natgateway"` - // filter by network - Network string `json:"network"` + + // 归属VPC ID + VpcId string `json:"vpc_id"` + + VpcResourceInfo +} + +type NatGatewayFilterListInput struct { + // 以NAT网关过滤 + Natgateway string `json:"natgateway"` + + // 以NAT网关名字排序 + OrderByNatgateway string `json:"order_by_natgateway"` + + VpcFilterListInput +} + +type NatEntryDetails struct { + apis.StatusStandaloneResourceDetails + NatGatewayResourceInfo + + // NAT ENTRY的真实名称?? + RealName string `json:"real_name"` } diff --git a/pkg/apis/compute/network.go b/pkg/apis/compute/network.go index 286c053a7f..c387725cbc 100644 --- a/pkg/apis/compute/network.go +++ b/pkg/apis/compute/network.go @@ -18,53 +18,88 @@ import ( "yunion.io/x/onecloud/pkg/apis" ) -type VpcFilterListInput struct { +type VpcFilterListInputBase struct { // 过滤关联此VPC(ID或Name)的资源 Vpc string `json:"vpc"` // swagger:ignore // Deprecated // filter by vpc Id VpcId string `json:"vpc_id" deprecated-by:"vpc"` + + // 按VPC名称排序 + // pattern:asc|desc + OrderByVpc string `json:"order_by_vpc"` } -type WireFilterListInput struct { - VpcFilterListInput +type VpcFilterListInput struct { + VpcFilterListInputBase + RegionalFilterListInput + ManagedResourceListInput +} +type WireFilterListBase struct { // 过滤连接此二层网络(ID或Name)的资源 Wire string `json:"wire"` // swagger:ignore // Deprecated // fitler by wire id WireId string `json:"wire_id" deprecated-by:"wire"` + + // 以二层网络名称排序 + OrderByWire string `json:"order_by_wire"` } -type NetworkFilterListInput struct { - WireFilterListInput +type WireFilterListInput struct { + VpcFilterListInput + ZonalFilterListBase - // 过滤关联此网络(ID或Name)的资源 + WireFilterListBase +} + +type NetworkFilterListBase struct { + // 过滤关联此IP子网(ID或Name)的资源 Network string `json:"network"` // swagger:ignore // Deprecated // filter by networkId NetworkId string `json:"network_id" deprecated-by:"network"` + + // 以IP子网的名称排序 + OrderByNetwork string `json:"order_by_network"` +} + +type NetworkFilterListInput struct { + WireFilterListInput + NetworkFilterListBase } type NetworkListInput struct { apis.SharableVirtualResourceListInput + WireFilterListInput - HostFilterListInput - - ManagedResourceListInput + HostResourceInput UsableResourceListInput - WireFilterListInput - // description: search ip address in network. // example: 10.168.222.1 Ip string `json:"ip"` } +type NetworkResourceInfoBase struct { + // IP子网名称 + Network string `json:"network"` +} + +type NetworkResourceInfo struct { + NetworkResourceInfoBase + + // 二层网络ID + WireId string `json:"wire_id"` + + WireResourceInfo +} + type NetworkCreateInput struct { apis.SharableVirtualResourceCreateInput @@ -120,12 +155,10 @@ type NetworkCreateInput struct { type NetworkDetails struct { apis.SharableVirtualResourceDetails + WireResourceInfo - CloudproviderInfo SNetwork - // 二层网络名称 - Wire string `json:"wire"` // 是否是内网 Exit bool `json:"exit"` // 端口数量 @@ -143,12 +176,6 @@ type NetworkDetails struct { GroupVnics int `json:"group_vnics"` // 预留IP数量 ReserveVnics int `json:"reserve_vnics"` - // 虚拟私有网络名称 - Vpc string `json:"vpc"` - // 虚拟私有网络Id - VpcId string `json:"vpc_id"` - // 虚拟私有网络外部Id - VpcExtId string `json:"vpc_ext_id"` // 路由信息 Routes [][]string `json:"routes"` @@ -219,13 +246,3 @@ type NetworkTryCreateNetworkInput struct { type NetworkSyncInput struct { apis.Meta } - -type NetworkStatusInput struct { - apis.Meta - - // description: network status - // required: true - // example: available - // enum: available,unavailable - Status string `json:"status"` -} diff --git a/pkg/apis/compute/networkinterface.go b/pkg/apis/compute/networkinterface.go index 7bc3039494..802bba1c6a 100644 --- a/pkg/apis/compute/networkinterface.go +++ b/pkg/apis/compute/networkinterface.go @@ -30,10 +30,11 @@ type NetworkInterfaceNetworkInfo struct { } type NetworkInterfaceDetails struct { - apis.StandaloneResourceDetails - SNetworkInterface + apis.StatusStandaloneResourceDetails + ManagedResourceInfo + CloudregionResourceInfo - CloudproviderInfo + SNetworkInterface // 弹性网卡网络信息 Networks []NetworkInterfaceNetworkInfo `json:"networks"` diff --git a/pkg/apis/compute/networkschedtag.go b/pkg/apis/compute/networkschedtag.go index 8157b92a61..f365360190 100644 --- a/pkg/apis/compute/networkschedtag.go +++ b/pkg/apis/compute/networkschedtag.go @@ -14,13 +14,11 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type NetworkschedtagDetails struct { - apis.JoinModelBaseDetails + SchedtagJointResourceDetails + SNetworkschedtag // IP子网名称 - Network string `json:"network"` - Schedtag string `json:"schedtag"` + Network string `json:"network"` } diff --git a/pkg/apis/compute/reservedip.go b/pkg/apis/compute/reservedip.go index 307f816b13..25bf8a4b90 100644 --- a/pkg/apis/compute/reservedip.go +++ b/pkg/apis/compute/reservedip.go @@ -38,11 +38,11 @@ type ReservedipListInput struct { } type ReservedipDetails struct { - apis.ModelBaseDetails + apis.ResourceBaseDetails + NetworkResourceInfo + SReservedip - // IP子网名称 - Network string `json:"network"` // 是否过期 Expired bool `json:"expired"` } diff --git a/pkg/apis/compute/routetable.go b/pkg/apis/compute/routetable.go index cb5f97f41c..7f78aa0b89 100644 --- a/pkg/apis/compute/routetable.go +++ b/pkg/apis/compute/routetable.go @@ -18,11 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type RouteTableDetails struct { apis.VirtualResourceDetails - SRouteTable - CloudproviderInfo + VpcResourceInfo - // 虚拟私有网络名称 - Vpc string `json:"vpc"` - // 区域名称 - Cloudregion string `json:"cloudregion"` + SRouteTable } diff --git a/pkg/apis/compute/schedpolicy.go b/pkg/apis/compute/schedpolicy.go index 1877230e98..36cdc65d01 100644 --- a/pkg/apis/compute/schedpolicy.go +++ b/pkg/apis/compute/schedpolicy.go @@ -18,8 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis" type SchedpolicyDetails struct { apis.StandaloneResourceDetails - SSchedpolicy + SchedtagResourceInfo - Schedtag string `json:"schedtag"` - ResourceType string `json:"resource_type"` + SSchedpolicy } diff --git a/pkg/apis/compute/schedtag.go b/pkg/apis/compute/schedtag.go index 75d8a46b2c..9800773a6f 100644 --- a/pkg/apis/compute/schedtag.go +++ b/pkg/apis/compute/schedtag.go @@ -46,6 +46,14 @@ type SchedtagFilterListInput struct { // Deprecated // filter by schedtag_id SchedtagId string `json:"schedtag_id" deprecated-by:"schedtag"` + + // 按调度标签名称排序 + // pattern:asc|desc + OrderBySchedtag string `json:"order_by_schedtag"` + + // 按调度标签资源类型排序 + // pattern:asc|desc + OrderByResourceType string `json:"order_by_resource_type"` } type SchedtagListInput struct { @@ -71,3 +79,22 @@ type SchedtagDetails struct { OtherCount int `json:"other_count"` JoinModelKeyword string `json:"join_model_keyword"` } + +type SchedtagResourceInfo struct { + + // 调度标签名称 + Schedtag string `json:"schedtag"` + + // 调度标签管理的资源类型 + ResourceType string `json:"resource_type"` +} + +type SchedtagJointResourceDetails struct { + apis.JointResourceBaseDetails + + // 调度标签名称 + Schedtag string `json:"schedtag"` + + // 调度标签管理的资源类型 + ResourceType string `json:"resource_type"` +} diff --git a/pkg/apis/compute/secgroup.go b/pkg/apis/compute/secgroup.go index 9354dce306..2b154bb44b 100644 --- a/pkg/apis/compute/secgroup.go +++ b/pkg/apis/compute/secgroup.go @@ -136,10 +136,20 @@ type SecgroupListInput struct { Equals string ServerFilterListInput + + // 按缓存数量排序 + // pattern:asc|desc + OrderByCacheCnt string `json:"order_by_cache_cnt"` + + // 按缓存关联主机数排序 + // pattern:asc|desc + OrderByGuestCnt string `json:"order_by_guest_cnt"` } type SecurityGroupCacheListInput struct { apis.StatusStandaloneResourceListInput + ManagedResourceListInput + RegionalFilterListInput SecgroupFilterListInput } diff --git a/pkg/apis/compute/secgroupcache.go b/pkg/apis/compute/secgroupcache.go index 87da42c0a6..af4a418bcd 100644 --- a/pkg/apis/compute/secgroupcache.go +++ b/pkg/apis/compute/secgroupcache.go @@ -17,10 +17,11 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type SecurityGroupCacheDetails struct { - apis.StandaloneResourceDetails - SSecurityGroupCache + apis.StatusStandaloneResourceDetails + ManagedResourceInfo + CloudregionResourceInfo - CloudproviderInfo + SSecurityGroupCache // 虚拟私有网络名称 Vpc string `json:"vpc"` diff --git a/pkg/apis/compute/serversku.go b/pkg/apis/compute/serversku.go index 825bfc863b..5735414507 100644 --- a/pkg/apis/compute/serversku.go +++ b/pkg/apis/compute/serversku.go @@ -130,21 +130,12 @@ type ServerSkuCreateInput struct { } type ServerSkuDetails struct { - apis.StandaloneResourceDetails + apis.StatusStandaloneResourceDetails + + ZoneResourceInfo + SServerSku // 绑定云主机数量 TotalGuestCount int `json:"total_guest_count"` - // 可用区名称 - Zone string `json:"zone"` - // 可用区外部Id - ZoneExtId string `json:"zone_ext_id"` - // 区域名称 - Region string `json:"region"` - // 区域Id - RegionId string `json:"region_id"` - // 区域外部Id - RegionExternalId string `json:"region_external_id"` - // 区域外部Id(不携带平台信息) - RegionExtId string `json:"region_ext_id"` } diff --git a/pkg/apis/compute/service_catalog.go b/pkg/apis/compute/service_catalog.go index 12534d2180..150aa7b482 100644 --- a/pkg/apis/compute/service_catalog.go +++ b/pkg/apis/compute/service_catalog.go @@ -14,7 +14,9 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" +import ( + "yunion.io/x/onecloud/pkg/apis" +) type ServiceCatalogCreateInput struct { apis.SharableVirtualResourceCreateInput @@ -58,3 +60,9 @@ type ServiceCatalogDeploy struct { // example: 1 Count int `json:"count"` } + +type ServiceCatalogDetails struct { + apis.SharableVirtualResourceDetails + + SServiceCatalog +} diff --git a/pkg/apis/compute/sku_const.go b/pkg/apis/compute/sku_const.go index 9bde562b02..ce4ac1c5b6 100644 --- a/pkg/apis/compute/sku_const.go +++ b/pkg/apis/compute/sku_const.go @@ -16,6 +16,7 @@ package compute import ( "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/apis/billing" ) const ( @@ -69,7 +70,7 @@ type ServerSkuListInput struct { ManagedResourceListInput ZonalFilterListInput - BillingFilterListInput + billing.BillingResourceListInput UsableResourceListInput // filter sku by memory size in MB @@ -83,7 +84,8 @@ type ElasticcacheSkuListInput struct { ManagedResourceListInput UsableResourceListInput - BillingFilterListInput + billing.BillingResourceListInput + ZonalFilterListInput // filter sku by memory size in MB @@ -97,5 +99,5 @@ type DBInstanceSkuListInput struct { ManagedResourceListInput RegionalFilterListInput - BillingFilterListInput + billing.BillingResourceListInput } diff --git a/pkg/apis/compute/snapshot.go b/pkg/apis/compute/snapshot.go index bf44f817e1..efce2baf11 100644 --- a/pkg/apis/compute/snapshot.go +++ b/pkg/apis/compute/snapshot.go @@ -69,8 +69,9 @@ type SSnapshotPolicyCreateInternalInput struct { type SnapshotListInput struct { apis.VirtualResourceListInput - ManagedResourceListInput + RegionalFilterListInput + StorageShareFilterListInput // filter snapshot that is fake deleted @@ -89,9 +90,10 @@ type InstanceSnapshotListInput struct { type SnapshotDetails struct { apis.VirtualResourceDetails - SSnapshot + ManagedResourceInfo + CloudregionResourceInfo - CloudproviderInfo + SSnapshot // 存储类型 StorageType string `json:"storage_type"` diff --git a/pkg/apis/compute/snapshotpolicy.go b/pkg/apis/compute/snapshotpolicy.go index b2ca569ba5..1ab5ef338e 100644 --- a/pkg/apis/compute/snapshotpolicy.go +++ b/pkg/apis/compute/snapshotpolicy.go @@ -18,8 +18,9 @@ import "yunion.io/x/onecloud/pkg/apis" type SnapshotPolicyDetails struct { apis.VirtualResourceDetails - //SSnapshotPolicy - apis.SVirtualResourceBase + + SSnapshotPolicy + RetentionDays int `json:"retention_days"` RepeatWeekdays []int `json:"repeat_weekdays"` TimePoints []int `json:"time_points"` diff --git a/pkg/apis/compute/snapshotpolicycache.go b/pkg/apis/compute/snapshotpolicycache.go index 4a24b2e9e3..224b754b4f 100644 --- a/pkg/apis/compute/snapshotpolicycache.go +++ b/pkg/apis/compute/snapshotpolicycache.go @@ -17,8 +17,9 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type SnapshotPolicyCacheDetails struct { - apis.StandaloneResourceDetails - SSnapshotPolicyCache + apis.StatusStandaloneResourceDetails + ManagedResourceInfo + CloudregionResourceInfo - CloudproviderInfo + SSnapshotPolicyCache } diff --git a/pkg/apis/compute/snapshotpolicydisk.go b/pkg/apis/compute/snapshotpolicydisk.go index 17b7f7963e..3d70a75453 100644 --- a/pkg/apis/compute/snapshotpolicydisk.go +++ b/pkg/apis/compute/snapshotpolicydisk.go @@ -19,7 +19,7 @@ import ( ) type SnapshotPolicyDiskDetails struct { - apis.JoinModelBaseDetails + apis.VirtualJointResourceBaseDetails // 快照策略名称 Snapshotpolicy string `json:"snapshotpolicy"` diff --git a/pkg/apis/compute/storage.go b/pkg/apis/compute/storage.go index 3c8da6f9c7..12b0e54814 100644 --- a/pkg/apis/compute/storage.go +++ b/pkg/apis/compute/storage.go @@ -21,7 +21,7 @@ import ( ) type StorageCreateInput struct { - apis.StandaloneResourceCreateInput + apis.EnabledStatusStandaloneResourceCreateInput // 存储类型 // @@ -113,7 +113,10 @@ type StorageCreateInput struct { } type StorageDetails struct { - apis.StandaloneResourceDetails + apis.EnabledStatusStandaloneResourceDetails + ManagedResourceInfo + ZoneResourceInfo + SStorage // 容量大小, 单位Mb @@ -129,9 +132,32 @@ type StorageDetails struct { // 可使用容量 FreeCapacity int64 `json:"free_capacity"` - CloudproviderInfo Schedtags []SchedtagShortDescDetails `json:"schedtags"` // 超分比 CommitBound float32 `json:"commit_bound"` } + +type StorageResourceInfo struct { + // 归属云订阅ID + ManagerId string `json:"manager_id"` + + ManagedResourceInfo + + // 归属可用区ID + ZoneId string `json:"zone_id"` + + ZoneResourceInfo + + // 存储名称 + Storage string `json:"storage"` + + // 存储类型 + StorageType string `json:"storage_type"` + + // 存储介质类型 + MediumType string `json:"medium_type"` + + // 存储状态 + StorageStatus string `json:"storage_status"` +} diff --git a/pkg/apis/compute/storage_const.go b/pkg/apis/compute/storage_const.go index 37a0bacd1b..4c1de6f346 100644 --- a/pkg/apis/compute/storage_const.go +++ b/pkg/apis/compute/storage_const.go @@ -145,6 +145,15 @@ type StorageFilterListInput struct { // Deprecated // filter by storage_id StorageId string `json:"storage_id" deprecated-by:"storage"` + + // 以存储名称排序 + // pattern:asc|desc + OrderByStorage string `json:"order_by_storage"` + + StorageShareFilterListInput + + ZonalFilterListInput + ManagedResourceListInput } type StorageShareFilterListInput struct { @@ -155,11 +164,11 @@ type StorageShareFilterListInput struct { } type StorageListInput struct { - apis.StandaloneResourceListInput - apis.DomainizedResourceListInput + apis.EnabledStatusStandaloneResourceListInput ManagedResourceListInput ZonalFilterListInput + UsableResourceListInput StorageShareFilterListInput } diff --git a/pkg/apis/compute/storagecache.go b/pkg/apis/compute/storagecache.go index 2c055e32dc..dbc8bc03c1 100644 --- a/pkg/apis/compute/storagecache.go +++ b/pkg/apis/compute/storagecache.go @@ -22,6 +22,8 @@ import ( type StoragecacheDetails struct { apis.StandaloneResourceDetails + ManagedResourceInfo + SStoragecache // 存储列表 diff --git a/pkg/apis/compute/storagecachedimage.go b/pkg/apis/compute/storagecachedimage.go index 1635373e2a..b5cd634b77 100644 --- a/pkg/apis/compute/storagecachedimage.go +++ b/pkg/apis/compute/storagecachedimage.go @@ -21,7 +21,7 @@ import ( ) type StoragecachedimageDetails struct { - apis.JoinModelBaseDetails + apis.JointResourceBaseDetails // 存储缓存名称 Storagecache string `json:"storagecache"` diff --git a/pkg/apis/compute/storageschedtag.go b/pkg/apis/compute/storageschedtag.go index 7b8e07199a..479e9bf165 100644 --- a/pkg/apis/compute/storageschedtag.go +++ b/pkg/apis/compute/storageschedtag.go @@ -14,13 +14,11 @@ package compute -import "yunion.io/x/onecloud/pkg/apis" - type StorageschedtagDetails struct { - apis.JoinModelBaseDetails + SchedtagJointResourceDetails + SStorageschedtag // 存储名称 - Storage string `json:"storage"` - Schedtag string `json:"schedtag"` + Storage string `json:"storage"` } diff --git a/pkg/apis/compute/vpc.go b/pkg/apis/compute/vpc.go index 68630c206d..a953fc5ad7 100644 --- a/pkg/apis/compute/vpc.go +++ b/pkg/apis/compute/vpc.go @@ -17,9 +17,12 @@ package compute import "yunion.io/x/onecloud/pkg/apis" type VpcDetails struct { - apis.StandaloneResourceDetails SVpc - CloudproviderInfo + + apis.EnabledStatusStandaloneResourceDetails + ManagedResourceInfo + CloudregionResourceInfo + GlobalVpcResourceInfo // 二层网络数量 // example: 1 @@ -34,3 +37,21 @@ type VpcDetails struct { // example: 0 NatgatewayCount int `json:"natgateway_count"` } + +type VpcResourceInfo struct { + // Vpc Name + Vpc string `json:"vpc"` + + // VPC外部Id + VpcExtId string `json:"vpc_ext_id"` + + // VPC归属区域ID + CloudregionId string `json:"cloudregion_id"` + + CloudregionResourceInfo + + // VPC归属云订阅ID + ManagerId string `json:"manager_id"` + + ManagedResourceInfo +} diff --git a/pkg/apis/compute/vpcs_const.go b/pkg/apis/compute/vpcs_const.go index d914ac4b29..74e99195e1 100644 --- a/pkg/apis/compute/vpcs_const.go +++ b/pkg/apis/compute/vpcs_const.go @@ -48,10 +48,12 @@ type UsableVpcResourceListInput struct { } type VpcListInput struct { - apis.StatusStandaloneResourceListInput - apis.DomainizedResourceListInput + apis.EnabledStatusStandaloneResourceListInput ManagedResourceListInput + RegionalFilterListInput + GlobalVpcResourceListInput + UsableResourceListInput UsableVpcResourceListInput @@ -61,11 +63,12 @@ type VpcListInput struct { type WireListInput struct { apis.StandaloneResourceListInput - apis.DomainizedResourceListInput - ManagedResourceListInput VpcFilterListInput - HostFilterListInput + + ZonalFilterListBase + + HostResourceInput } type GlobalVpcListInput struct { diff --git a/pkg/apis/compute/wire.go b/pkg/apis/compute/wire.go index cb50903fac..4d257f0bf2 100644 --- a/pkg/apis/compute/wire.go +++ b/pkg/apis/compute/wire.go @@ -33,7 +33,8 @@ type WireCreateInput struct { // required: true Vpc string `json:"vpc"` // swagger:ignore - VpcId string + // Deprecated + VpcId string `json:"vpc_id" deprecated-by:"vpc"` // 可用区名称或Id // required: true @@ -44,18 +45,33 @@ type WireCreateInput struct { type WireDetails struct { apis.StandaloneResourceDetails + VpcResourceInfo + ZoneResourceInfoBase + SWire - // 可用区Id - // exampe: zone1 - Zone string `json:"zone"` // IP子网数量 // example: 1 Networks int `json:"networks"` // VPC名称 - Vpc string `json:"vpc'` - // VPC外部Id - VpcExtId string `json:"vpc_ext_id"` +} - CloudproviderInfo +type WireResourceInfoBase struct { + // 二层网络(WIRE)的名称 + Wire string `json:"wire"` +} + +type WireResourceInfo struct { + WireResourceInfoBase + + // VPC ID + VpcId string `json:"vpc_id"` + + VpcResourceInfo + + // 可用区ID + ZoneId string `json:"zone_id"` + + // 可用区 + Zone string `json:"zone"` } diff --git a/pkg/apis/compute/zone.go b/pkg/apis/compute/zone.go index 6712b2f0e5..21d20502ef 100644 --- a/pkg/apis/compute/zone.go +++ b/pkg/apis/compute/zone.go @@ -30,16 +30,7 @@ type ZoneCreateInput struct { CloudregionId string } -type ZoneDetails struct { - apis.StandaloneResourceDetails - SZone - - // 区域名称 - Cloudregion string `json:"cloudregion"` - // 平台 - // example: OneCloud - Provider string `json:"provider"` - +type ZoneGeneralUsage struct { // 可用区底下的宿主机数量 // example: 3 Hosts int `json:"hosts"` @@ -69,12 +60,46 @@ type ZoneDetails struct { Storages int `json:"storages"` } -type ZoneInfo struct { +func (usage *ZoneGeneralUsage) IsEmpty() bool { + if usage.Hosts > 0 { + return false + } + if usage.Wires > 0 { + return false + } + if usage.Networks > 0 { + return false + } + if usage.Storages > 0 { + return false + } + return true +} + +type ZoneDetails struct { + apis.StatusStandaloneResourceDetails + CloudregionResourceInfo + CloudenvResourceInfo + + ZoneGeneralUsage + + SZone +} + +type ZoneResourceInfoBase struct { // 可用区名称 // example: zone1 Zone string `json:"zone"` // 纳管云的zoneId ZoneExtId string `json:"zone_ext_id"` - CloudregionInfo +} + +type ZoneResourceInfo struct { + ZoneResourceInfoBase + + // 可用区的区域ID + CloudregionId string `json:"cloudregion_id"` + + CloudregionResourceInfo } diff --git a/pkg/apis/compute/zz_generated.model.go b/pkg/apis/compute/zz_generated.model.go index 92b1a3964f..6d7424123f 100644 --- a/pkg/apis/compute/zz_generated.model.go +++ b/pkg/apis/compute/zz_generated.model.go @@ -50,10 +50,10 @@ type SAwsCachedLbbg struct { // SBaremetalagent is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SBaremetalagent. type SBaremetalagent struct { apis.SStandaloneResourceBase + SZoneResourceBase Status string `json:"status"` AccessIp string `json:"access_ip"` ManagerUri string `json:"manager_uri"` - ZoneId string `json:"zone_id"` AgentType string `json:"agent_type"` Version string `json:"version"` StoragecacheId string `json:"storagecache_id"` @@ -70,8 +70,8 @@ type SBillingResourceBase struct { type SBucket struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase + SCloudregionResourceBase SManagedResourceBase - CloudregionId string `json:"cloudregion_id"` StorageClass string `json:"storage_class"` Location string `json:"location"` Acl string `json:"acl"` @@ -98,7 +98,7 @@ type SCachedLoadbalancerCertificate struct { apis.SExternalizedResourceBase SManagedResourceBase SCloudregionResourceBase - CertificateId string `json:"certificate_id"` + SLoadbalancerCertificateResourceBase } // SCachedimage is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCachedimage. @@ -115,8 +115,7 @@ type SCachedimage struct { // SCloudaccount is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SCloudaccount. type SCloudaccount struct { - apis.SEnabledStatusStandaloneResourceBase - apis.SDomainizedResourceBase + apis.SEnabledStatusDomainLevelResourceBase SSyncableBaseResource LastAutoSync time.Time `json:"last_auto_sync"` ProjectId string `json:"project_id"` @@ -221,8 +220,8 @@ type SDBInstance struct { type SDBInstanceAccount struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - Secret string `json:"secret"` - DBInstanceId string `json:"db_instance_id"` + SDBInstanceResourceBase + Secret string `json:"secret"` } // SDBInstanceBackup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstanceBackup. @@ -231,6 +230,7 @@ type SDBInstanceBackup struct { SCloudregionResourceBase SManagedResourceBase apis.SExternalizedResourceBase + SDBInstanceResourceBase Engine string `json:"engine"` EngineVersion string `json:"engine_version"` StartTime time.Time `json:"start_time"` @@ -238,15 +238,14 @@ type SDBInstanceBackup struct { BackupMode string `json:"backup_mode"` DBNames string `json:"db_names"` BackupSizeMb int `json:"backup_size_mb"` - DBInstanceId string `json:"db_instance_id"` } // SDBInstanceDatabase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstanceDatabase. type SDBInstanceDatabase struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase + SDBInstanceResourceBase CharacterSet string `json:"character_set"` - DBInstanceId string `json:"db_instance_id"` } // SDBInstanceJointsBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstanceJointsBase. @@ -266,9 +265,9 @@ type SDBInstanceNetwork struct { type SDBInstanceParameter struct { apis.SStandaloneResourceBase apis.SExternalizedResourceBase - DBInstanceId string `json:"db_instance_id"` - Key string `json:"key"` - Value string `json:"value"` + SDBInstanceResourceBase + Key string `json:"key"` + Value string `json:"value"` } // SDBInstancePrivilege is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstancePrivilege. @@ -281,6 +280,11 @@ type SDBInstancePrivilege struct { DBInstancedatabaseId string `json:"db_instancedatabase_id"` } +// SDBInstanceResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstanceResourceBase. +type SDBInstanceResourceBase struct { + DBInstanceId string `json:"db_instance_id"` +} + // SDBInstanceSku is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDBInstanceSku. type SDBInstanceSku struct { apis.SEnabledStatusStandaloneResourceBase @@ -316,11 +320,11 @@ type SDisk struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase SBillingResourceBase + SStorageResourceBase DiskFormat string `json:"disk_format"` DiskSize int `json:"disk_size"` AccessPath string `json:"access_path"` AutoDelete bool `json:"auto_delete"` - StorageId string `json:"storage_id"` BackupStorageId string `json:"backup_storage_id"` TemplateId string `json:"template_id"` SnapshotId string `json:"snapshot_id"` @@ -332,16 +336,16 @@ type SDisk struct { // SDnsRecord is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDnsRecord. type SDnsRecord struct { apis.SAdminSharableVirtualResourceBase - Ttl int `json:"ttl"` - Enabled *bool `json:"enabled,omitempty"` + apis.SEnabledResourceBase + Ttl int `json:"ttl"` } // SDynamicschedtag is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SDynamicschedtag. type SDynamicschedtag struct { apis.SStandaloneResourceBase - Condition string `json:"condition"` - SchedtagId string `json:"schedtag_id"` - Enabled *bool `json:"enabled,omitempty"` + SSchedtagResourceBase + Condition string `json:"condition"` + Enabled *bool `json:"enabled,omitempty"` } // SElasticcache is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SElasticcache. @@ -349,9 +353,8 @@ type SElasticcache struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase SBillingResourceBase - SManagedResourceBase SDeletePreventableResourceBase - SCloudregionResourceBase + SVpcResourceBase SZoneResourceBase SlaveZones string `json:"slave_zones"` InstanceType string `json:"instance_type"` @@ -360,7 +363,6 @@ type SElasticcache struct { NodeType string `json:"node_type"` Engine string `json:"engine"` EngineVersion string `json:"engine_version"` - VpcId string `json:"vpc_id"` NetworkType string `json:"network_type"` NetworkId string `json:"network_id"` SecurityGroupId string `json:"security_group_id"` @@ -379,7 +381,7 @@ type SElasticcache struct { type SElasticcacheAccount struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - ElasticcacheId string `json:"elasticcache_id"` + SElasticcacheResourceBase AccountType string `json:"account_type"` AccountPrivilege string `json:"account_privilege"` Password string `json:"password"` @@ -389,33 +391,38 @@ type SElasticcacheAccount struct { type SElasticcacheAcl struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - ElasticcacheId string `json:"elasticcache_id"` - IpList string `json:"ip_list"` + SElasticcacheResourceBase + IpList string `json:"ip_list"` } // SElasticcacheBackup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SElasticcacheBackup. type SElasticcacheBackup struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - ElasticcacheId string `json:"elasticcache_id"` - BackupSizeMb int `json:"backup_size_mb"` - BackupType string `json:"backup_type"` - BackupMode string `json:"backup_mode"` - DownloadURL string `json:"download_url"` - StartTime time.Time `json:"start_time"` - EndTime time.Time `json:"end_time"` + SElasticcacheResourceBase + BackupSizeMb int `json:"backup_size_mb"` + BackupType string `json:"backup_type"` + BackupMode string `json:"backup_mode"` + DownloadURL string `json:"download_url"` + StartTime time.Time `json:"start_time"` + EndTime time.Time `json:"end_time"` } // SElasticcacheParameter is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SElasticcacheParameter. type SElasticcacheParameter struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase + SElasticcacheResourceBase + Key string `json:"key"` + Value string `json:"value"` + ValueRange string `json:"value_range"` + Modifiable bool `json:"modifiable"` + ForceRestart bool `json:"force_restart"` +} + +// SElasticcacheResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SElasticcacheResourceBase. +type SElasticcacheResourceBase struct { ElasticcacheId string `json:"elasticcache_id"` - Key string `json:"key"` - Value string `json:"value"` - ValueRange string `json:"value_range"` - Modifiable bool `json:"modifiable"` - ForceRestart bool `json:"force_restart"` } // SElasticcacheSku is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SElasticcacheSku. @@ -455,6 +462,7 @@ type SElasticip struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase SManagedResourceBase + SCloudregionResourceBase SBillingResourceBase NetworkId string `json:"network_id"` Mode string `json:"mode"` @@ -465,15 +473,14 @@ type SElasticip struct { ChargeType string `json:"charge_type"` BgpType string `json:"bgp_type"` AutoDellocate *bool `json:"auto_dellocate,omitempty"` - CloudregionId string `json:"cloudregion_id"` } // SExternalProject is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SExternalProject. type SExternalProject struct { apis.SStandaloneResourceBase - SManagedResourceBase apis.SProjectizedResourceBase apis.SExternalizedResourceBase + SManagedResourceBase } // SGlobalVpc is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SGlobalVpc. @@ -481,16 +488,21 @@ type SGlobalVpc struct { apis.SEnabledStatusStandaloneResourceBase } +// SGlobalVpcResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SGlobalVpcResourceBase. +type SGlobalVpcResourceBase struct { + GlobalvpcId string `json:"globalvpc_id"` +} + // SGroup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SGroup. type SGroup struct { apis.SVirtualResourceBase + SZoneResourceBase + apis.SEnabledResourceBase ServiceType string `json:"service_type"` ParentId string `json:"parent_id"` - ZoneId string `json:"zone_id"` SchedStrategy string `json:"sched_strategy"` Granularity int `json:"granularity"` ForceDispersion *bool `json:"force_dispersion,omitempty"` - Enabled *bool `json:"enabled,omitempty"` } // SGroupJointsBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SGroupJointsBase. @@ -521,12 +533,12 @@ type SGuest struct { apis.SExternalizedResourceBase SBillingResourceBase SDeletePreventableResourceBase + SHostResourceBase VcpuCount int `json:"vcpu_count"` VmemSize int `json:"vmem_size"` BootOrder string `json:"boot_order"` ShutdownBehavior string `json:"shutdown_behavior"` KeypairId string `json:"keypair_id"` - HostId string `json:"host_id"` BackupHostId string `json:"backup_host_id"` Vga string `json:"vga"` Vdi string `json:"vdi"` @@ -599,6 +611,7 @@ type SGuestsecgroup struct { type SHost struct { apis.SEnabledStatusStandaloneResourceBase apis.SExternalizedResourceBase + SZoneResourceBase SManagedResourceBase SBillingResourceBase Rack string `json:"rack"` @@ -627,9 +640,9 @@ type SHost struct { IpmiIp string `json:"ipmi_ip"` IpmiInfo interface{} `json:"ipmi_info"` HostStatus string `json:"host_status"` - ZoneId string `json:"zone_id"` HostType string `json:"host_type"` Version string `json:"version"` + OvnVersion string `json:"ovn_version"` IsBaremetal bool `json:"is_baremetal"` IsMaintenance bool `json:"is_maintenance"` LastPingAt time.Time `json:"last_ping_at"` @@ -646,6 +659,11 @@ type SHostJointsBase struct { apis.SJointResourceBase } +// SHostResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SHostResourceBase. +type SHostResourceBase struct { + HostId string `json:"host_id"` +} + // SHostnetwork is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SHostnetwork. type SHostnetwork struct { SHostJointsBase @@ -730,7 +748,7 @@ type SInstanceSnapshotJoint struct { // SIsolatedDevice is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SIsolatedDevice. type SIsolatedDevice struct { apis.SStandaloneResourceBase - HostId string `json:"host_id"` + SHostResourceBase DevType string `json:"dev_type"` Model string `json:"model"` GuestId string `json:"guest_id"` @@ -752,15 +770,13 @@ type SKeypair struct { type SLoadbalancer struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + SVpcResourceBase SZoneResourceBase + SNetworkResourceBase SLoadbalancerRateLimiter Address string `json:"address"` AddressType string `json:"address_type"` NetworkType string `json:"network_type"` - NetworkId string `json:"network_id"` - VpcId string `json:"vpc_id"` ClusterId string `json:"cluster_id"` ChargeType string `json:"charge_type"` LoadbalancerSpec string `json:"loadbalancer_spec"` @@ -790,6 +806,7 @@ type SLoadbalancerAclEntry struct { // SLoadbalancerAgent is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerAgent. type SLoadbalancerAgent struct { apis.SStandaloneResourceBase + SLoadbalancerClusterResourceBase Version string `json:"version"` IP string `json:"ip"` HaState string `json:"ha_state"` @@ -804,7 +821,6 @@ type SLoadbalancerAgent struct { LoadbalancerAcls time.Time `json:"loadbalancer_acls"` LoadbalancerCertificates time.Time `json:"loadbalancer_certificates"` Deployment *SLoadbalancerAgentDeployment `json:"deployment"` - ClusterId string `json:"cluster_id"` } // SLoadbalancerAgentDeployment is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerAgentDeployment. @@ -831,6 +847,7 @@ type SLoadbalancerAgentParamsHaproxy struct { LogHttp bool `json:"log_http"` LogTcp bool `json:"log_tcp"` LogNormal bool `json:"log_normal"` + TuneHttpMaxhdr int `json:"tune_http_maxhdr"` } // SLoadbalancerAgentParamsTelegraf is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerAgentParamsTelegraf. @@ -856,34 +873,34 @@ type SLoadbalancerAgentParamsVrrp struct { type SLoadbalancerBackend struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase - BackendGroupId string `json:"backend_group_id"` - BackendId string `json:"backend_id"` - BackendType string `json:"backend_type"` - BackendRole string `json:"backend_role"` - Weight int `json:"weight"` - Address string `json:"address"` - Port int `json:"port"` - SendProxy string `json:"send_proxy"` + SLoadbalancerBackendgroupResourceBase + BackendId string `json:"backend_id"` + BackendType string `json:"backend_type"` + BackendRole string `json:"backend_role"` + Weight int `json:"weight"` + Address string `json:"address"` + Port int `json:"port"` + SendProxy string `json:"send_proxy"` + Ssl string `json:"ssl"` } // SLoadbalancerBackendGroup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerBackendGroup. type SLoadbalancerBackendGroup struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase - Type string `json:"type"` - LoadbalancerId string `json:"loadbalancer_id"` + SLoadbalancerResourceBase + Type string `json:"type"` +} + +// SLoadbalancerBackendgroupResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerBackendgroupResourceBase. +type SLoadbalancerBackendgroupResourceBase struct { + BackendGroupId string `json:"backend_group_id"` } // SLoadbalancerCertificate is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerCertificate. type SLoadbalancerCertificate struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase Certificate string `json:"certificate"` PrivateKey string `json:"private_key"` PublicKeyAlgorithm string `json:"public_key_algorithm"` @@ -896,11 +913,21 @@ type SLoadbalancerCertificate struct { SubjectAlternativeNames string `json:"subject_alternative_names"` } +// SLoadbalancerCertificateResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerCertificateResourceBase. +type SLoadbalancerCertificateResourceBase struct { + CertificateId string `json:"certificate_id"` +} + // SLoadbalancerCluster is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerCluster. type SLoadbalancerCluster struct { apis.SStandaloneResourceBase SZoneResourceBase - WireId string `json:"wire_id"` + SWireResourceBase +} + +// SLoadbalancerClusterResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerClusterResourceBase. +type SLoadbalancerClusterResourceBase struct { + ClusterId string `json:"cluster_id"` } // SLoadbalancerHTTPListener is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerHTTPListener. @@ -919,6 +946,15 @@ type SLoadbalancerHTTPRateLimiter struct { HTTPRequestRatePerSrc int `json:"http_request_rate_per_src"` } +// SLoadbalancerHTTPRedirect is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerHTTPRedirect. +type SLoadbalancerHTTPRedirect struct { + Redirect string `json:"redirect"` + RedirectCode int `json:"redirect_code"` + RedirectScheme string `json:"redirect_scheme"` + RedirectHost string `json:"redirect_host"` + RedirectPath string `json:"redirect_path"` +} + // SLoadbalancerHTTPSListener is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerHTTPSListener. type SLoadbalancerHTTPSListener struct { CertificateId string `json:"certificate_id"` @@ -946,9 +982,7 @@ type SLoadbalancerHealthCheck struct { type SLoadbalancerListener struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase - LoadbalancerId string `json:"loadbalancer_id"` + SLoadbalancerResourceBase ListenerType string `json:"listener_type"` ListenerPort int `json:"listener_port"` BackendGroupId string `json:"backend_group_id"` @@ -970,22 +1004,27 @@ type SLoadbalancerListener struct { SLoadbalancerHTTPSListener SLoadbalancerHealthCheck SLoadbalancerHTTPRateLimiter + SLoadbalancerHTTPRedirect +} + +// SLoadbalancerListenerResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerListenerResourceBase. +type SLoadbalancerListenerResourceBase struct { + ListenerId string `json:"listener_id"` } // SLoadbalancerListenerRule is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerListenerRule. type SLoadbalancerListenerRule struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + SLoadbalancerListenerResourceBase IsDefault bool `json:"is_default"` - ListenerId string `json:"listener_id"` BackendGroupId string `json:"backend_group_id"` Domain string `json:"domain"` Path string `json:"path"` Condition string `json:"condition"` SLoadbalancerHealthCheck SLoadbalancerHTTPRateLimiter + SLoadbalancerHTTPRedirect } // SLoadbalancerNetwork is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerNetwork. @@ -1001,6 +1040,11 @@ type SLoadbalancerRateLimiter struct { EgressMbps int `json:"egress_mbps"` } +// SLoadbalancerResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerResourceBase. +type SLoadbalancerResourceBase struct { + LoadbalancerId string `json:"loadbalancer_id"` +} + // SLoadbalancerTCPListener is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SLoadbalancerTCPListener. type SLoadbalancerTCPListener struct { } @@ -1018,24 +1062,36 @@ type SManagedResourceBase struct { type SNatEntry struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - NatgatewayId string `json:"natgateway_id"` + SNatgatewayResourceBase } // SNatGateway is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNatGateway. type SNatGateway struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase SBillingResourceBase - VpcId string `json:"vpc_id"` + SVpcResourceBase NatSpec string `json:"nat_spec"` } +// SNatSEntry is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNatSEntry. +type SNatSEntry struct { + SNatEntry + SNetworkResourceBase + IP string `json:"ip"` + SourceCIDR string `json:"source_cidr"` +} + +// SNatgatewayResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNatgatewayResourceBase. +type SNatgatewayResourceBase struct { + NatgatewayId string `json:"natgateway_id"` +} + // SNetwork is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNetwork. type SNetwork struct { apis.SSharableVirtualResourceBase apis.SExternalizedResourceBase + SWireResourceBase IfnameHint string `json:"ifname_hint"` GuestIpStart string `json:"guest_ip_start"` GuestIpEnd string `json:"guest_ip_end"` @@ -1051,7 +1107,6 @@ type SNetwork struct { GuestDns6 string `json:"guest_dns6"` GuestDomain6 string `json:"guest_domain6"` VlanId int `json:"vlan_id"` - WireId string `json:"wire_id"` ServerType string `json:"server_type"` AllocPolicy string `json:"alloc_policy"` AllocTimoutSeconds int `json:"alloc_timout_seconds"` @@ -1068,6 +1123,11 @@ type SNetworkInterface struct { AssociateId string `json:"associate_id"` } +// SNetworkResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNetworkResourceBase. +type SNetworkResourceBase struct { + NetworkId string `json:"network_id"` +} + // SNetworkinterfacenetwork is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SNetworkinterfacenetwork. type SNetworkinterfacenetwork struct { apis.SJointResourceBase @@ -1083,11 +1143,34 @@ type SNetworkschedtag struct { NetworkId string `json:"network_id"` } +// SQcloudCachedLb is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SQcloudCachedLb. +type SQcloudCachedLb struct { + apis.SVirtualResourceBase + apis.SExternalizedResourceBase + SManagedResourceBase + SCloudregionResourceBase + BackendServerId string `json:"backend_server_id"` + BackendId string `json:"backend_id"` + CachedBackendGroupId string `json:"cached_backend_group_id"` +} + +// SQcloudCachedLbbg is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SQcloudCachedLbbg. +type SQcloudCachedLbbg struct { + apis.SVirtualResourceBase + apis.SExternalizedResourceBase + SManagedResourceBase + SCloudregionResourceBase + LoadbalancerId string `json:"loadbalancer_id"` + BackendGroupId string `json:"backend_group_id"` + AssociatedId string `json:"associated_id"` + AssociatedType string `json:"associated_type"` +} + // SReservedip is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SReservedip. type SReservedip struct { apis.SResourceBase + SNetworkResourceBase Id int64 `json:"id"` - NetworkId string `json:"network_id"` IpAddr string `json:"ip_addr"` Notes string `json:"notes"` ExpiredAt time.Time `json:"expired_at"` @@ -1106,11 +1189,9 @@ type SRoute struct { type SRouteTable struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase - SManagedResourceBase - VpcId string `json:"vpc_id"` - CloudregionId string `json:"cloudregion_id"` - Type string `json:"type"` - Routes *SRoutes `json:"routes"` + SVpcResourceBase + Type string `json:"type"` + Routes *SRoutes `json:"routes"` } // SRoutes is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SRoutes. @@ -1119,10 +1200,10 @@ type SRoutes []*SRoute // SSchedpolicy is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SSchedpolicy. type SSchedpolicy struct { apis.SStandaloneResourceBase - Condition string `json:"condition"` - SchedtagId string `json:"schedtag_id"` - Strategy string `json:"strategy"` - Enabled *bool `json:"enabled,omitempty"` + SSchedtagResourceBase + Condition string `json:"condition"` + Strategy string `json:"strategy"` + Enabled *bool `json:"enabled,omitempty"` } // SSchedtag is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SSchedtag. @@ -1139,6 +1220,11 @@ type SSchedtagJointsBase struct { SchedtagId string `json:"schedtag_id"` } +// SSchedtagResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SSchedtagResourceBase. +type SSchedtagResourceBase struct { + SchedtagId string `json:"schedtag_id"` +} + // SSecurityGroup is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SSecurityGroup. type SSecurityGroup struct { apis.SSharableVirtualResourceBase @@ -1214,6 +1300,7 @@ type SSnapshot struct { apis.SVirtualResourceBase apis.SExternalizedResourceBase SManagedResourceBase + SCloudregionResourceBase DiskId string `json:"disk_id"` StorageId string `json:"storage_id"` CreatedBy string `json:"created_by"` @@ -1224,7 +1311,6 @@ type SSnapshot struct { DiskType string `json:"disk_type"` OsType string `json:"os_type"` RefCount int `json:"ref_count"` - CloudregionId string `json:"cloudregion_id"` BackingDiskId string `json:"backing_disk_id"` ExpiredAt time.Time `json:"expired_at"` } @@ -1257,22 +1343,25 @@ type SSnapshotPolicyDisk struct { // SStorage is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SStorage. type SStorage struct { - apis.SStandaloneResourceBase + apis.SEnabledStatusStandaloneResourceBase apis.SExternalizedResourceBase SManagedResourceBase + SZoneResourceBase Capacity int64 `json:"capacity"` Reserved int64 `json:"reserved"` StorageType string `json:"storage_type"` MediumType string `json:"medium_type"` Cmtbound float32 `json:"cmtbound"` StorageConf interface{} `json:"storage_conf"` - ZoneId string `json:"zone_id"` StoragecacheId string `json:"storagecache_id"` - Enabled *bool `json:"enabled,omitempty"` - Status string `json:"status"` IsSysDiskStore *bool `json:"is_sys_disk_store,omitempty"` } +// SStorageResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SStorageResourceBase. +type SStorageResourceBase struct { + StorageId string `json:"storage_id"` +} + // SStoragecache is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SStoragecache. type SStoragecache struct { apis.SStandaloneResourceBase @@ -1323,32 +1412,42 @@ type SVpc struct { apis.SEnabledStatusStandaloneResourceBase apis.SExternalizedResourceBase SManagedResourceBase - IsDefault bool `json:"is_default"` - CidrBlock string `json:"cidr_block"` - CloudregionId string `json:"cloudregion_id"` - GlobalvpcId string `json:"globalvpc_id"` + SCloudregionResourceBase + SGlobalVpcResourceBase + IsDefault bool `json:"is_default"` + CidrBlock string `json:"cidr_block"` +} + +// SVpcResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SVpcResourceBase. +type SVpcResourceBase struct { + VpcId string `json:"vpc_id"` } // SWire is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SWire. type SWire struct { apis.SStandaloneResourceBase apis.SExternalizedResourceBase - Bandwidth int `json:"bandwidth"` - Mtu int `json:"mtu"` - ScheduleRank int `json:"schedule_rank"` - ZoneId string `json:"zone_id"` - VpcId string `json:"vpc_id"` + SVpcResourceBase + SZoneResourceBase + Bandwidth int `json:"bandwidth"` + Mtu int `json:"mtu"` + ScheduleRank int `json:"schedule_rank"` +} + +// SWireResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SWireResourceBase. +type SWireResourceBase struct { + WireId string `json:"wire_id"` } // SZone is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SZone. type SZone struct { apis.SStatusStandaloneResourceBase apis.SExternalizedResourceBase - Location string `json:"location"` - Contacts string `json:"contacts"` - NameCn string `json:"name_cn"` - ManagerUri string `json:"manager_uri"` - CloudregionId string `json:"cloudregion_id"` + SCloudregionResourceBase + Location string `json:"location"` + Contacts string `json:"contacts"` + NameCn string `json:"name_cn"` + ManagerUri string `json:"manager_uri"` } // SZoneResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/compute/models.SZoneResourceBase. diff --git a/pkg/apis/desc.go b/pkg/apis/desc.go new file mode 100644 index 0000000000..db66a13415 --- /dev/null +++ b/pkg/apis/desc.go @@ -0,0 +1,21 @@ +// 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 apis + +type StandaloneShortDesc struct { + Id string `json:"id"` + + Name string `json:"name"` +} diff --git a/pkg/apis/identity/domain.go b/pkg/apis/identity/domain.go index c6291dff55..1d0e60d1cb 100644 --- a/pkg/apis/identity/domain.go +++ b/pkg/apis/identity/domain.go @@ -18,6 +18,8 @@ import "yunion.io/x/onecloud/pkg/apis" type DomainDetails struct { apis.StandaloneResourceDetails + IdpResourceInfo + SDomain UserCout int `json:"user_count"` diff --git a/pkg/apis/identity/endpoint.go b/pkg/apis/identity/endpoint.go index d80854ce06..2e7c675ab3 100644 --- a/pkg/apis/identity/endpoint.go +++ b/pkg/apis/identity/endpoint.go @@ -19,4 +19,10 @@ import "yunion.io/x/onecloud/pkg/apis" type EndpointDetails struct { apis.StandaloneResourceDetails SEndpoint + + // 服务名称,例如keystone, glance, region等 + ServiceName string `json:"service_name"` + + // 服务类型,例如identity, image, compute等 + ServiceType string `json:"service_type"` } diff --git a/pkg/apis/identity/group.go b/pkg/apis/identity/group.go index 765167b96d..5fa3dbafb4 100644 --- a/pkg/apis/identity/group.go +++ b/pkg/apis/identity/group.go @@ -14,10 +14,11 @@ package identity -import "yunion.io/x/onecloud/pkg/apis" - type GroupDetails struct { - apis.StandaloneResourceDetails + IdentityBaseResourceDetails + + IdpResourceInfo + SGroup // 用户数量 diff --git a/pkg/apis/identity/identityprovider.go b/pkg/apis/identity/identityprovider.go index e991796105..3896e4e5ad 100644 --- a/pkg/apis/identity/identityprovider.go +++ b/pkg/apis/identity/identityprovider.go @@ -17,15 +17,43 @@ package identity import "yunion.io/x/onecloud/pkg/apis" type IdentityProviderDetails struct { - apis.StandaloneResourceDetails + apis.EnabledStatusStandaloneResourceDetails - SyncIntervalSeconds int `json:"sync_interval_seconds"` - TargetDomain string `json:"target_domain"` + // 认证源账号信息同步周期 + SyncIntervalSeconds int `json:"sync_interval_seconds"` - RoleCount int `json:"role_count,allowempty"` - UserCount int `json:"user_count,allowempty"` - PolicyCount int `json:"policy_count,allowempty"` - DomainCount int `json:"domain_count,allowempty"` + // 认证源的目标域名称 + TargetDomain string `json:"target_domain"` + + // 该认证源关联的所有域的角色数量 + RoleCount int `json:"role_count,allowempty"` + + // 该认证源关联的所有域的用户数量 + UserCount int `json:"user_count,allowempty"` + + // 该认证源关联的所有域的权限策略数量 + PolicyCount int `json:"policy_count,allowempty"` + + // 该认证源关联的所有域的数量 + DomainCount int `json:"domain_count,allowempty"` + + // 该认证源关联的所有域的项目数量 ProjectCount int `json:"project_count,allowempty"` - GroupCount int `json:"group_count,allowempty"` + + // 该认证源关联的所有域的组数量 + GroupCount int `json:"group_count,allowempty"` +} + +type IdpResourceInfo struct { + // 认证源ID + IdpId string `json:"idp_id"` + + // 认证源名称 + Idp string `json:"idp"` + + // 该资源在认证源的原始ID + IdpEntityId string `json:"idp_entity_id"` + + // 认证源类型, 例如sql, cas, ldap等 + IdpDriver string `json:"idp_driver"` } diff --git a/pkg/apis/identity/input.go b/pkg/apis/identity/input.go index f99d691b44..3d08c79d2f 100644 --- a/pkg/apis/identity/input.go +++ b/pkg/apis/identity/input.go @@ -87,16 +87,20 @@ type RoleFilterListInput struct { } type ServiceFilterListInput struct { - // filter by service, either id or name + // 服务名称或ID过滤 Service string `json:"service"` // swagger:ignore // Deprecated // filter by service_id ServiceId string `json:"service_id" deprecated-by:"service"` + + // 以服务名称排序 + OrderByService string `json:"order_by_service"` } type RoleListInput struct { IdentityBaseResourceListInput + apis.SharableResourceBaseListInput ProjectFilterListInput UserFilterListInput @@ -236,7 +240,7 @@ type CredentialListInput struct { type PolicyListInput struct { EnabledIdentityBaseResourceListInput - apis.SharableResourceListInput + apis.SharableResourceBaseListInput } type RegionListInput struct { diff --git a/pkg/apis/identity/output.go b/pkg/apis/identity/output.go new file mode 100644 index 0000000000..894351d824 --- /dev/null +++ b/pkg/apis/identity/output.go @@ -0,0 +1,29 @@ +// 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 identity + +import ( + "yunion.io/x/onecloud/pkg/apis" +) + +type IdentityBaseResourceDetails struct { + apis.StandaloneResourceDetails + + apis.DomainizedResourceInfo +} + +type EnabledIdentityBaseResourceDetails struct { + IdentityBaseResourceDetails +} diff --git a/pkg/apis/identity/policy.go b/pkg/apis/identity/policy.go index afb88ec6b5..ec82d823ca 100644 --- a/pkg/apis/identity/policy.go +++ b/pkg/apis/identity/policy.go @@ -14,9 +14,8 @@ package identity -import "yunion.io/x/onecloud/pkg/apis" - type PolicyDetails struct { - apis.StandaloneResourceDetails + EnabledIdentityBaseResourceDetails + SPolicy } diff --git a/pkg/apis/identity/project.go b/pkg/apis/identity/project.go index 9a2c47240f..fa3a9fe39f 100644 --- a/pkg/apis/identity/project.go +++ b/pkg/apis/identity/project.go @@ -18,12 +18,11 @@ import ( "time" "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/apis" ) type ProjectDetails struct { - apis.StandaloneResourceDetails + IdentityBaseResourceDetails + SProject GroupCount int `json:"group_count"` diff --git a/pkg/apis/identity/role.go b/pkg/apis/identity/role.go index c0d2c87500..7d1567464a 100644 --- a/pkg/apis/identity/role.go +++ b/pkg/apis/identity/role.go @@ -14,10 +14,9 @@ package identity -import "yunion.io/x/onecloud/pkg/apis" - type RoleDetails struct { - apis.StandaloneResourceDetails + IdentityBaseResourceDetails + SRole UserCount int `json:"user_count"` diff --git a/pkg/apis/identity/user.go b/pkg/apis/identity/user.go index 02b104c569..ad2801482b 100644 --- a/pkg/apis/identity/user.go +++ b/pkg/apis/identity/user.go @@ -16,12 +16,12 @@ package identity import ( "time" - - "yunion.io/x/onecloud/pkg/apis" ) type UserDetails struct { - apis.StandaloneResourceDetails + EnabledIdentityBaseResourceDetails + IdpResourceInfo + SUser GroupCount int `json:"group_count"` diff --git a/pkg/apis/image/image.go b/pkg/apis/image/image.go index 0bdc180052..1861b4e915 100644 --- a/pkg/apis/image/image.go +++ b/pkg/apis/image/image.go @@ -17,8 +17,6 @@ package image import ( "time" - "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/apis" ) @@ -37,11 +35,11 @@ type GuestImageListInput struct { type ImageDetails struct { apis.SharableVirtualResourceDetails + SImage // 镜像属性信息 - Properties *jsonutils.JSONDict `json:"properties"` - + Properties map[string]string `json:"properties"` // 自动清除时间 AutoDeleteAt time.Time `json:"auto_delete_at"` // 删除保护 diff --git a/pkg/apis/input.go b/pkg/apis/input.go index bbf2e856df..7a24809568 100644 --- a/pkg/apis/input.go +++ b/pkg/apis/input.go @@ -14,17 +14,14 @@ package apis -type DomainizedResourceListInput struct { - // swagger:ignore - // Is an admin call? equivalent to scope=system - // Deprecated - Admin *bool `json:"admin"` - - // 指定查询的权限范围,可能值为project, domain or system - Scope string `json:"scope"` - - // 查询指定的域(ID或名称)拥有的资源 +type DomainizedResourceInput struct { + // 指定项目归属域名称或ID + // required: false ProjectDomain string `json:"project_domain"` + + // swagger:ignore + // Deprecated + Domain string `json:"domain" deprecated-by:"project_domain"` // swagger:ignore // Deprecated // Project domain Id filter, alias for project_domain @@ -35,20 +32,9 @@ type DomainizedResourceListInput struct { DomainId string `json:"domain_id" deprecated-by:"project_domain"` } -type DomainizedResourceCreateInput struct { - // description: the owner domain name or id +type ProjectizedResourceInput struct { + // 指定项目的名称或ID // required: false - Domain string `json:"project_domain"` - - // description: the owner domain name or id, alias field of domain - // required: false - DomainId string `json:"domain_id"` -} - -type ProjectizedResourceListInput struct { - DomainizedResourceListInput - - // 查询指定的项目(ID或名称)拥有的资源 Project string `json:"project"` // swagger:ignore // Deprecated @@ -64,35 +50,13 @@ type ProjectizedResourceListInput struct { TenantId string `json:"tenant_id" deprecated-by:"project"` } +type DomainizedResourceCreateInput struct { + DomainizedResourceInput +} + type ProjectizedResourceCreateInput struct { - DomainizedResourceCreateInput - - // description: the owner project name or id - // required: false - Project string `json:"project"` - - // description: the owner project name or id, alias field of project - // required: false - ProjectId string `json:"project_id"` -} - -type UserResourceListInput struct { - // 查询指定的用户(ID或名称)拥有的资源 - User string `json:"user"` - // swagger:ignore - // Deprecated - // Filter by userId - UserId string `json:"user_id" deprecated-by:"user"` -} - -func (input UserResourceListInput) UserStr() string { - if len(input.User) > 0 { - return input.User - } - if len(input.UserId) > 0 { - return input.UserId - } - return "" + DomainizedResourceInput + ProjectizedResourceInput } type SharableVirtualResourceCreateInput struct { @@ -116,22 +80,43 @@ type VirtualResourceCreateInput struct { IsSystem *bool `json:"is_system"` } -type EnabledStatusStandaloneResourceCreateInput struct { - StatusStandaloneResourceCreateInput - - // description: indicate the resource is enabled/disabled by administrator +type EnabledBaseResourceCreateInput struct { + // 该资源是否被管理员*人为*启用或者禁用 // required: false Enabled *bool `json:"enabled"` } -type StatusStandaloneResourceCreateInput struct { - StandaloneResourceCreateInput - - // description: the status of the resource +type StatusBaseResourceCreateInput struct { + // 用来存储资源的状态 // required: false Status string `json:"status"` } +type EnabledStatusDomainLevelResourceCreateInput struct { + StatusDomainLevelResourceCreateInput + EnabledBaseResourceCreateInput +} + +type StatusDomainLevelResourceCreateInput struct { + DomainLevelResourceCreateInput + StatusBaseResourceCreateInput +} + +type DomainLevelResourceCreateInput struct { + StandaloneResourceCreateInput + DomainizedResourceCreateInput +} + +type EnabledStatusStandaloneResourceCreateInput struct { + StatusStandaloneResourceCreateInput + EnabledBaseResourceCreateInput +} + +type StatusStandaloneResourceCreateInput struct { + StandaloneResourceCreateInput + StatusBaseResourceCreateInput +} + type StandaloneResourceCreateInput struct { ResourceBaseCreateInput @@ -172,3 +157,44 @@ type ResourceBaseCreateInput struct { type ModelBaseCreateInput struct { Meta } + +type PerformStatusInput struct { + // 更改的目标状态值 + // required:true + Status string `json:"status"` + + // 更改状态的原因描述 + // required:false + Reason string `json:"reason"` +} + +type GetDetailsStatusOutput struct { + // 状态 + Status string `json:"status"` +} + +type PerformProjectPublicInput struct { + // 共享项目资源的共享范围,可能的值为:project, domain和system + // pattern: project|domain|system + Scope string `json:"scope"` + + // 如果共享范围为项目,则在此列表中指定共享的目标项目 + SharedProjects []string `json:"shared_projects"` +} + +type PerformProjectPrivateInput struct { +} + +type PerformChangeProjectOwnerInput struct { + ProjectizedResourceInput +} + +type PerformChangeDomainOwnerInput struct { + DomainizedResourceInput +} + +type PerformEnableInput struct { +} + +type PerformDisableInput struct { +} diff --git a/pkg/apis/list.go b/pkg/apis/list.go index 365a24afcf..c4487c650b 100644 --- a/pkg/apis/list.go +++ b/pkg/apis/list.go @@ -14,6 +14,50 @@ package apis +type DomainizedResourceListInput struct { + // swagger:ignore + // Is an admin call? equivalent to scope=system + // Deprecated + Admin *bool `json:"admin"` + + // 指定查询的权限范围,可能值为project, domain or system + Scope string `json:"scope"` + + DomainizedResourceInput + + // 对具有域属性的资源,严格匹配域ID + ProjectDomains []string `json:"project_domains"` + + // 按domain名称排序,可能值为asc|desc + // pattern: asc|desc + OrderByDomain string `json:"order_by_domain"` +} + +type ProjectizedResourceListInput struct { + DomainizedResourceListInput + + ProjectizedResourceInput + + // 对具有项目属性的资源,严格匹配项目ID + Projects []string `json:"projects"` + + // 按project名称排序,可能值为asc|desc + // pattern: asc|desc + OrderByProject string `json:"order_by_project"` + // swagger:ignore + // Deprecated + OrderByTenant string `json:"order_by_tenant" deprecated-by:"order_by_project"` +} + +type UserResourceListInput struct { + // 查询指定的用户(ID或名称)拥有的资源 + User string `json:"user"` + // swagger:ignore + // Deprecated + // Filter by userId + UserId string `json:"user_id" deprecated-by:"user"` +} + type ModelBaseListInput struct { Meta @@ -80,7 +124,6 @@ type IncrementalListInput struct { type VirtualResourceListInput struct { StatusStandaloneResourceListInput - ProjectizedResourceListInput // 列表中包含标记为"系统资源"的资源 @@ -96,11 +139,6 @@ type ResourceBaseListInput struct { ModelBaseListInput } -type SharableResourceListInput struct { - // 根据资源是否共享过滤列表 - IsPublic *bool `json:"is_public"` -} - type SharableVirtualResourceListInput struct { VirtualResourceListInput @@ -137,16 +175,42 @@ type StandaloneResourceListInput struct { Ids []string `json:"id"` } -type StatusStandaloneResourceListInput struct { - StandaloneResourceListInput - +type StatusResourceBaseListInput struct { // 以资源的状态过滤列表 Status []string `json:"status"` } -type EnabledStatusStandaloneResourceListInput struct { - StatusStandaloneResourceListInput - +type EnabledResourceBaseListInput struct { // 以资源是否启用/禁用过滤列表 Enabled *bool `json:"enabled"` } + +type SharableResourceBaseListInput struct { + // 以资源是否共享过滤列表 + IsPublic *bool `json:"is_public"` +} + +type DomainLevelResourceListInput struct { + StandaloneResourceListInput + DomainizedResourceListInput +} + +type StatusStandaloneResourceListInput struct { + StandaloneResourceListInput + StatusResourceBaseListInput +} + +type EnabledStatusStandaloneResourceListInput struct { + StatusStandaloneResourceListInput + EnabledResourceBaseListInput +} + +type StatusDomainLevelResourceListInput struct { + DomainLevelResourceListInput + StatusResourceBaseListInput +} + +type EnabledStatusDomainLevelResourceListInput struct { + StatusDomainLevelResourceListInput + EnabledResourceBaseListInput +} diff --git a/pkg/apis/monitor/alert.go b/pkg/apis/monitor/alert.go index 57e93405da..8a3ef6e2b2 100644 --- a/pkg/apis/monitor/alert.go +++ b/pkg/apis/monitor/alert.go @@ -121,9 +121,11 @@ type AlertUpdateInput struct { type AlertListInput struct { apis.VirtualResourceListInput + apis.EnabledResourceBaseListInput // 监控指标名称 Metric string `json:"metric"` + // 以报警是否启用/禁用过滤列表 - Enabled *bool `json:"enabled"` + // Enabled *bool `json:"enabled"` } diff --git a/pkg/apis/notify/contact.go b/pkg/apis/notify/contact.go index b30695d6ca..e244031f8a 100644 --- a/pkg/apis/notify/contact.go +++ b/pkg/apis/notify/contact.go @@ -17,7 +17,7 @@ package notify import "yunion.io/x/onecloud/pkg/apis" type ContactDetails struct { - apis.ModelBaseDetails + apis.ResourceBaseDetails Id string `json:"id"` Name string `json:"name"` diff --git a/pkg/apis/notify/notification.go b/pkg/apis/notify/notification.go index 47b62073c0..a51ddf3b93 100644 --- a/pkg/apis/notify/notification.go +++ b/pkg/apis/notify/notification.go @@ -21,7 +21,7 @@ import ( ) type NotificationDetails struct { - apis.ModelBaseDetails + apis.ResourceBaseDetails Id string `json:"id"` Name string `json:"name"` diff --git a/pkg/apis/output.go b/pkg/apis/output.go index 132521ff29..1eea1f132c 100644 --- a/pkg/apis/output.go +++ b/pkg/apis/output.go @@ -32,10 +32,6 @@ type ModelBaseDetails struct { UpdateFailReason string `json:"update_fail_reason"` } -type JoinModelBaseDetails struct { - ModelBaseDetails -} - type ModelBaseShortDescDetail struct { ResName string `json:"res_name"` } @@ -51,6 +47,10 @@ type SharableVirtualResourceDetails struct { SharedProjects []SharedProject `json:"shared_projects"` } +type AdminSharableVirtualResourceDetails struct { + SharableVirtualResourceDetails +} + type StandaloneResourceShortDescDetail struct { ModelBaseShortDescDetail @@ -58,10 +58,70 @@ type StandaloneResourceShortDescDetail struct { Name string `json:"name"` } +type EnabledStatusDomainLevelResourceDetails struct { + StatusDomainLevelResourceDetails +} + +type StatusDomainLevelResourceDetails struct { + DomainLevelResourceDetails +} + +type DomainLevelResourceDetails struct { + StandaloneResourceDetails + + DomainizedResourceInfo +} + type VirtualResourceDetails struct { + StatusStandaloneResourceDetails + + ProjectizedResourceInfo +} + +type VirtualJointResourceBaseDetails struct { + JointResourceBaseDetails +} + +type JointResourceBaseDetails struct { + ResourceBaseDetails +} + +type ResourceBaseDetails struct { + ModelBaseDetails +} + +type EnabledStatusStandaloneResourceDetails struct { + StatusStandaloneResourceDetails +} + +type StatusStandaloneResourceDetails struct { StandaloneResourceDetails } type StandaloneResourceDetails struct { - ModelBaseDetails + ResourceBaseDetails + + // 标签 + Metadata map[string]string `json:"metadata"` +} + +type DomainizedResourceInfo struct { + // 资源归属项目的域名称 + ProjectDomain string `json:"project_domain"` +} + +type ProjectizedResourceInfo struct { + DomainizedResourceInfo + + // 资源归属项目的名称 + // alias:project + Project string `json:"tenant"` + + // 资源归属项目的ID(向后兼容别名) + // Deprecated + TenantId string `json:"project_id"` + + // 资源归属项目的名称(向后兼容别名) + // Deprecated + Tenant string `json:"project"` } diff --git a/pkg/apis/owner.go b/pkg/apis/owner.go new file mode 100644 index 0000000000..5eeda4d79b --- /dev/null +++ b/pkg/apis/owner.go @@ -0,0 +1,22 @@ +// 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 apis + +type TOwnerSource string + +const ( + OWNER_SOURCE_LOCAL = TOwnerSource("local") + OWNER_SOURCE_CLOUD = TOwnerSource("cloud") +) diff --git a/pkg/apis/yunionconf/doc.go b/pkg/apis/yunionconf/doc.go new file mode 100644 index 0000000000..ddc1f2711e --- /dev/null +++ b/pkg/apis/yunionconf/doc.go @@ -0,0 +1 @@ +package yunionconf // import "yunion.io/x/onecloud/pkg/apis/yunionconf" diff --git a/pkg/apis/yunionconf/input.go b/pkg/apis/yunionconf/input.go new file mode 100644 index 0000000000..caa53bfe73 --- /dev/null +++ b/pkg/apis/yunionconf/input.go @@ -0,0 +1,39 @@ +// 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 yunionconf + +import ( + "yunion.io/x/onecloud/pkg/apis" +) + +type ParameterListInput struct { + apis.ResourceBaseListInput + + NamespaceId string `json:"namespace_id"` + + // 服务名称或ID + Service string `json:"service"` + + // Deprecated + // swagger:ignore + ServiceId string `json:"service_id" deprecated-by:"service"` + + // 用户名称或ID + User string `json:"user"` + + // Deprecated + // swagger:ignore + UserId string `json:"user_id" deprecated-by:"user"` +} diff --git a/pkg/apis/zz_generated.model.go b/pkg/apis/zz_generated.model.go index 4608572323..65fc9e13dd 100644 --- a/pkg/apis/zz_generated.model.go +++ b/pkg/apis/zz_generated.model.go @@ -24,15 +24,33 @@ type SAdminSharableVirtualResourceBase struct { Records string `json:"records"` } +// SDomainLevelResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SDomainLevelResourceBase. +type SDomainLevelResourceBase struct { + SStandaloneResourceBase + SDomainizedResourceBase + DomainSrc string `json:"domain_src"` +} + // SDomainizedResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SDomainizedResourceBase. type SDomainizedResourceBase struct { DomainId string `json:"domain_id"` } +// SEnabledResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SEnabledResourceBase. +type SEnabledResourceBase struct { + Enabled *bool `json:"enabled,omitempty"` +} + +// SEnabledStatusDomainLevelResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SEnabledStatusDomainLevelResourceBase. +type SEnabledStatusDomainLevelResourceBase struct { + SStatusDomainLevelResourceBase + SEnabledResourceBase +} + // SEnabledStatusStandaloneResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SEnabledStatusStandaloneResourceBase. type SEnabledStatusStandaloneResourceBase struct { SStatusStandaloneResourceBase - Enabled bool `json:"enabled"` + SEnabledResourceBase } // SExternalizedResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SExternalizedResourceBase. @@ -106,10 +124,21 @@ type SStandaloneResourceBase struct { IsEmulated bool `json:"is_emulated"` } +// SStatusDomainLevelResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SStatusDomainLevelResourceBase. +type SStatusDomainLevelResourceBase struct { + SDomainLevelResourceBase + SStatusResourceBase +} + +// SStatusResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SStatusResourceBase. +type SStatusResourceBase struct { + Status string `json:"status"` +} + // SStatusStandaloneResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SStatusStandaloneResourceBase. type SStatusStandaloneResourceBase struct { SStandaloneResourceBase - Status string `json:"status"` + SStatusResourceBase } // SVirtualJointResourceBase is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudcommon/db.SVirtualJointResourceBase. diff --git a/pkg/cloudcommon/db/adminsharablevirtual.go b/pkg/cloudcommon/db/adminsharablevirtual.go index f3f9667a26..d0dd78c306 100644 --- a/pkg/cloudcommon/db/adminsharablevirtual.go +++ b/pkg/cloudcommon/db/adminsharablevirtual.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SAdminSharableVirtualResourceBase struct { @@ -165,10 +166,63 @@ func (model *SAdminSharableVirtualResourceBase) GetIAdminSharableVirtualModel() return model.GetVirtualObject().(IAdminSharableVirtualModel) } -func (manager *SAdminSharableVirtualResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input apis.AdminSharableVirtualResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SAdminSharableVirtualResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.AdminSharableVirtualResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SAdminSharableVirtualResourceBaseManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SAdminSharableVirtualResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.AdminSharableVirtualResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (model *SAdminSharableVirtualResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.AdminSharableVirtualResourceDetails, error) { + return apis.AdminSharableVirtualResourceDetails{}, nil +} + +func (manager *SAdminSharableVirtualResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.AdminSharableVirtualResourceDetails { + rows := make([]apis.AdminSharableVirtualResourceDetails, len(objs)) + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.AdminSharableVirtualResourceDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + } + return rows +} diff --git a/pkg/cloudcommon/db/caller.go b/pkg/cloudcommon/db/caller.go index d8b21a7612..d115a29e4b 100644 --- a/pkg/cloudcommon/db/caller.go +++ b/pkg/cloudcommon/db/caller.go @@ -25,6 +25,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type Caller struct { @@ -122,12 +123,24 @@ func (p *param) convert() reflect.Value { } func ValueToJSONObject(out reflect.Value) jsonutils.JSONObject { + if gotypes.IsNil(out.Interface()) { + return nil + } + if obj, ok := isJSONObject(out); ok { return obj } return jsonutils.Marshal(out.Interface()) } +func ValueToJSONDict(out reflect.Value) *jsonutils.JSONDict { + jsonObj := ValueToJSONObject(out) + if jsonObj == nil { + return nil + } + return jsonObj.(*jsonutils.JSONDict) +} + func ValueToError(out reflect.Value) error { errVal := out.Interface() if !gotypes.IsNil(errVal) { @@ -137,7 +150,7 @@ func ValueToError(out reflect.Value) error { } func mergeInputOutputData(data *jsonutils.JSONDict, resVal reflect.Value) *jsonutils.JSONDict { - retJson := ValueToJSONObject(resVal).(*jsonutils.JSONDict) + retJson := ValueToJSONDict(resVal) // preserve the input info not returned by caller data.Update(retJson) return data @@ -164,7 +177,27 @@ func ListItemFilter(manager IModelManager, ctx context.Context, q *sqlchemy.SQue return nil, httperrors.NewGeneralError(err) } if len(ret) != 2 { - return nil, httperrors.NewInternalServerError("Invald ListItemFilter return value") + return nil, httperrors.NewInternalServerError("Invald ListItemFilter return value count %d", len(ret)) + } + if err := ValueToError(ret[1]); err != nil { + return nil, err + } + return ret[0].Interface().(*sqlchemy.SQuery), nil +} + +func OrderByExtraFields( + manager IModelManager, + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) (*sqlchemy.SQuery, error) { + ret, err := call(manager, "OrderByExtraFields", ctx, q, userCred, query) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + if len(ret) != 2 { + return nil, httperrors.NewInternalServerError("Invald OrderByExtraFields return value count %d", len(ret)) } if err := ValueToError(ret[1]); err != nil { return nil, err @@ -178,12 +211,44 @@ func GetExtraDetails(model IModel, ctx context.Context, userCred mcclient.TokenC return nil, httperrors.NewGeneralError(err) } if len(ret) != 2 { - return nil, httperrors.NewInternalServerError("Invald GetExtraDetails return value") + return nil, httperrors.NewInternalServerError("Invalid GetExtraDetails return value count %d", len(ret)) } if err := ValueToError(ret[1]); err != nil { return nil, err } - return ValueToJSONObject(ret[0]).(*jsonutils.JSONDict), nil + return ValueToJSONDict(ret[0]), nil +} + +func FetchCustomizeColumns( + manager IModelManager, + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) ([]*jsonutils.JSONDict, error) { + ret, err := call(manager, "FetchCustomizeColumns", ctx, userCred, query, objs, fields, isList) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + if len(ret) != 1 { + return nil, httperrors.NewInternalServerError("Invalid FetchCustomizeColumns return value count %d", len(ret)) + } + if ret[0].IsNil() { + return nil, nil + } + if ret[0].Kind() != reflect.Slice { + return nil, httperrors.NewInternalServerError("Invalid FetchCustomizeColumns return value type, not a slice!") + } + if ret[0].Len() != len(objs) { + return nil, httperrors.NewInternalServerError("Invalid FetchCustomizeColumns return value, inconsistent obj count: input %d != output %d", len(objs), ret[0].Len()) + } + retVal := make([]*jsonutils.JSONDict, ret[0].Len()) + for i := 0; i < ret[0].Len(); i += 1 { + retVal[i] = ValueToJSONDict(ret[0].Index(i)) + } + return retVal, nil } func ValidateUpdateData(model IModel, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { diff --git a/pkg/cloudcommon/db/db_dispatcher.go b/pkg/cloudcommon/db/db_dispatcher.go index c48520bdd6..acfd235f9c 100644 --- a/pkg/cloudcommon/db/db_dispatcher.go +++ b/pkg/cloudcommon/db/db_dispatcher.go @@ -270,10 +270,13 @@ func listItemQueryFiltersRaw(manager IModelManager, return nil, err } } - q, err = listItemsQueryByColumn(manager, q, userCred, query) + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + // TURN OFF automatic query by column name!!!! + // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + /*q, err = listItemsQueryByColumn(manager, q, userCred, query) if err != nil { return nil, err - } + }*/ searches := jsonutils.GetQueryStringArray(query, "search") if len(searches) > 0 { q, err = applyListItemsSearchFilters(manager, ctx, q, userCred, searches) @@ -332,7 +335,7 @@ func Query2List(manager IModelManager, ctx context.Context, userCred mcclient.To } else { showDetails = true } - items := make([]IModel, 0) + items := make([]interface{}, 0) results := make([]jsonutils.JSONObject, 0) rows, err := q.Rows() if err != nil && err != sql.ErrNoRows { @@ -375,7 +378,8 @@ func Query2List(manager IModelManager, ctx context.Context, userCred mcclient.To jsonDict := jsonutils.Marshal(item).(*jsonutils.JSONDict) jsonDict = jsonDict.CopyIncludes([]string(listF)...) jsonDict.Update(extraData) - if showDetails && !query.Contains("export_keys") { + // ignore GetExtraDetails + /*if showDetails && !query.Contains("export_keys") { extraDict, _ := GetExtraDetails(item, ctx, userCred, query, true) if extraDict != nil { // Fix for Now @@ -383,16 +387,21 @@ func Query2List(manager IModelManager, ctx context.Context, userCred mcclient.To jsonDict = extraDict } // jsonDict = getModelExtraDetails(item, ctx, jsonDict) - } + }*/ results = append(results, jsonDict) items = append(items, item) } if showDetails && !query.Contains("export_keys") { - extraRows := manager.FetchCustomizeColumns(ctx, userCred, query, items, stringutils2.NewSortedStrings(fieldFilter)) + extraRows, err := FetchCustomizeColumns(manager, ctx, userCred, query, items, stringutils2.NewSortedStrings(fieldFilter), true) + + if err != nil { + return nil, errors.Wrap(err, "FetchCustomizeColumns") + } // log.Debugf("manager.FetchCustomizeColumns: %s %s", extraRows, listF) if len(extraRows) == len(results) { for i := range results { - results[i].(*jsonutils.JSONDict).Update(extraRows[i]) + extraRows[i].Update(results[i]) + results[i] = extraRows[i] } } } @@ -568,7 +577,7 @@ func ListItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok orderQuery.Set(fmt.Sprintf("order_by_%s", orderByField), jsonutils.NewString(string(order))) } } - q, err = manager.OrderByExtraFields(ctx, q, userCred, orderQuery) + q, err = OrderByExtraFields(manager, ctx, q, userCred, orderQuery) if err != nil { return nil, err } @@ -774,7 +783,10 @@ func getItemDetails(manager IModelManager, item IModel, ctx context.Context, use extraDict.Update(jsonDict) // jsonDict = getModelExtraDetails(item, ctx, jsonDict) - extraRows := manager.FetchCustomizeColumns(ctx, userCred, query, []IModel{item}, stringutils2.NewSortedStrings(fieldFilter)) + extraRows, err := FetchCustomizeColumns(manager, ctx, userCred, query, []interface{}{item}, stringutils2.NewSortedStrings(fieldFilter), false) + if err != nil { + return nil, errors.Wrap(err, "FetchCustomizeColumns") + } if len(extraRows) == 1 { extraDict.Update(extraRows[0]) } diff --git a/pkg/cloudcommon/db/domain.go b/pkg/cloudcommon/db/domain.go index 2aaca646f4..3eed14c827 100644 --- a/pkg/cloudcommon/db/domain.go +++ b/pkg/cloudcommon/db/domain.go @@ -18,13 +18,16 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDomainizedResourceBaseManager struct { @@ -64,3 +67,85 @@ func ValidateCreateDomainId(domainId string) error { } return nil } + +func (manager *SDomainizedResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "domain": + tenantCacheQuery := TenantCacheManager.GetDomainQuery("name", "id").SubQuery() + q = q.AppendField(tenantCacheQuery.Field("name", "domain")).Distinct() + q = q.Join(tenantCacheQuery, sqlchemy.Equals(q.Field("domain_id"), tenantCacheQuery.Field("id"))) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SDomainizedResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.DomainizedResourceListInput, +) (*sqlchemy.SQuery, error) { + if len(query.ProjectDomains) > 0 { + tenants := TenantCacheManager.GetDomainQuery().SubQuery() + subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR( + sqlchemy.In(tenants.Field("id"), query.ProjectDomains), + sqlchemy.In(tenants.Field("name"), query.ProjectDomains), + )).SubQuery() + q = q.In("domain_id", subq) + } + return q, nil +} + +func (manager *SDomainizedResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.DomainizedResourceListInput, +) (*sqlchemy.SQuery, error) { + subq := TenantCacheManager.GetDomainQuery("id", "name").SubQuery() + if NeedOrderQuery([]string{query.OrderByDomain}) { + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("domain_id"), subq.Field("id"))) + q = OrderByFields(q, []string{query.OrderByDomain}, []sqlchemy.IQueryField{subq.Field("name")}) + return q, nil + } + return q, nil +} + +func (manager *SDomainizedResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.DomainizedResourceInfo { + ret := make([]apis.DomainizedResourceInfo, len(objs)) + for i := range objs { + ret[i] = apis.DomainizedResourceInfo{} + } + if len(fields) == 0 || fields.Contains("project_domain") { + domainIds := stringutils2.SSortedStrings{} + for i := range objs { + var base *SDomainizedResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.DomainId) > 0 { + domainIds = stringutils2.Append(domainIds, base.DomainId) + } + } + domains := FetchProjects(domainIds, true) + if domains != nil { + for i := range objs { + var base *SDomainizedResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.DomainId) > 0 { + if proj, ok := domains[base.DomainId]; ok { + if len(fields) == 0 || fields.Contains("project_domain") { + ret[i].ProjectDomain = proj.Name + } + } + } + } + } + } + return ret +} diff --git a/pkg/cloudcommon/db/domainresource.go b/pkg/cloudcommon/db/domainresource.go new file mode 100644 index 0000000000..8e040bb313 --- /dev/null +++ b/pkg/cloudcommon/db/domainresource.go @@ -0,0 +1,273 @@ +// 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 db + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SDomainLevelResourceBaseManager struct { + SStandaloneResourceBaseManager + SDomainizedResourceBaseManager +} + +func NewDomainLevelResourceBaseManager( + dt interface{}, + tableName string, + keyword string, + keywordPlural string, +) SDomainLevelResourceBaseManager { + return SDomainLevelResourceBaseManager{ + SStandaloneResourceBaseManager: NewStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural), + } +} + +type SDomainLevelResourceBase struct { + SStandaloneResourceBase + SDomainizedResourceBase + + // 归属Domain信息的来源, local: 本地设置, cloud: 从云上同步过来 + // example: local + DomainSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"" json:"domain_src"` +} + +func (self *SDomainLevelResourceBaseManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return IsDomainAllowList(userCred, self) +} + +func (self *SDomainLevelResourceBaseManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return IsDomainAllowCreate(userCred, self) +} + +func (self *SDomainLevelResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return IsDomainAllowGet(userCred, self) +} + +func (self *SDomainLevelResourceBase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { + return IsDomainAllowUpdate(userCred, self) +} + +func (self *SDomainLevelResourceBase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return IsDomainAllowDelete(userCred, self) +} + +func (manager *SDomainLevelResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.DomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + } + q, err = manager.SDomainizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SDomainLevelResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SDomainizedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SDomainLevelResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.DomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SDomainizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DomainizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (model *SDomainLevelResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + model.DomainId = ownerId.GetProjectDomainId() + model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL) + return model.SStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) +} + +func (model *SDomainLevelResourceBase) AllowPerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) bool { + return IsAdminAllowPerform(userCred, model, "change-owner") +} + +func (model *SDomainLevelResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) { + manager := model.GetModelManager() + + data := jsonutils.Marshal(input) + log.Debugf("SDomainLevelResourceBase change_owner %s %s %#v", query, data, manager) + ownerId, err := manager.FetchOwnerId(ctx, data) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + if len(ownerId.GetProjectDomainId()) == 0 { + return nil, httperrors.NewInputParameterError("missing new domain") + } + if ownerId.GetProjectDomainId() == model.DomainId { + // do nothing + Update(model, func() error { + model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL) + return nil + }) + return nil, nil + } + q := manager.Query().Equals("name", model.GetName()) + q = manager.FilterByOwner(q, ownerId, manager.NamespaceScope()) + q = manager.FilterBySystemAttributes(q, nil, nil, manager.ResourceScope()) + q = q.NotEquals("id", model.GetId()) + cnt, err := q.CountWithError() + if err != nil { + return nil, httperrors.NewInternalServerError("check name duplication error: %s", err) + } + if cnt > 0 { + return nil, httperrors.NewDuplicateNameError("name", model.GetName()) + } + former, _ := TenantCacheManager.FetchDomainById(ctx, model.DomainId) + if former == nil { + log.Warningf("domain_id %s not found", model.DomainId) + formerObj := NewDomain(model.DomainId, "unknown") + former = &formerObj + } + + // clean shared projects before update project id + // if err := SharedResourceManager.CleanModelSharedProjects(ctx, userCred, model); err != nil { + // return nil, err + // } + + _, err = Update(model, func() error { + model.DomainId = ownerId.GetProjectDomainId() + model.DomainSrc = string(apis.OWNER_SOURCE_LOCAL) + return nil + }) + if err != nil { + return nil, errors.Wrap(err, "Update") + } + + OpsLog.SyncOwner(model, former, userCred) + notes := struct { + OldDomainId string + OldDomain string + NewDomainId string + NewDomain string + }{ + OldDomainId: former.DomainId, + OldDomain: former.Domain, + NewDomainId: ownerId.GetProjectDomainId(), + NewDomain: ownerId.GetProjectDomain(), + } + logclient.AddActionLogWithContext(ctx, model, logclient.ACT_CHANGE_OWNER, notes, userCred, true) + return nil, nil +} + +func (manager *SDomainLevelResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.DomainLevelResourceDetails { + rows := make([]apis.DomainLevelResourceDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + domainRows := manager.SDomainizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.DomainLevelResourceDetails{ + StandaloneResourceDetails: stdRows[i], + DomainizedResourceInfo: domainRows[i], + } + } + return rows +} + +func (model *SDomainLevelResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.DomainLevelResourceDetails, error) { + return apis.DomainLevelResourceDetails{}, nil +} + +func (manager *SDomainLevelResourceBaseManager) GetIDomainLevelModelManager() IDomainLevelModelManager { + return manager.GetVirtualObject().(IDomainLevelModelManager) +} + +func (manager *SDomainLevelResourceBaseManager) ValidateCreateData( + ctx context.Context, + userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, + query jsonutils.JSONObject, + input apis.DomainLevelResourceCreateInput, +) (apis.DomainLevelResourceCreateInput, error) { + var err error + input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput) + if err != nil { + return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData") + } + return input, nil +} + +func (model *SDomainLevelResourceBase) DomainLevelModelManager() IDomainLevelModelManager { + return model.GetModelManager().(IDomainLevelModelManager) +} + +func (model *SDomainLevelResourceBase) IsOwner(userCred mcclient.TokenCredential) bool { + return model.DomainId == userCred.GetProjectDomainId() +} + +func (model *SDomainLevelResourceBase) SyncCloudDomainId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) { + if model.DomainSrc != string(apis.OWNER_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectDomainId()) > 0 { + diff, _ := Update(model, func() error { + model.DomainSrc = string(apis.OWNER_SOURCE_CLOUD) + model.DomainId = ownerId.GetProjectDomainId() + return nil + }) + if len(diff) > 0 { + OpsLog.LogEvent(model, ACT_SYNC_OWNER, diff, userCred) + } + } +} + +func (model *SDomainLevelResourceBase) GetIDomainLevelModel() IDomainLevelModel { + return model.GetVirtualObject().(IDomainLevelModel) +} diff --git a/pkg/cloudcommon/db/enabledbase.go b/pkg/cloudcommon/db/enabledbase.go new file mode 100644 index 0000000000..a6ac8a13d0 --- /dev/null +++ b/pkg/cloudcommon/db/enabledbase.go @@ -0,0 +1,89 @@ +// 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 db + +import ( + "context" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/tristate" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type SEnabledResourceBaseManager struct{} + +type SEnabledResourceBase struct { + // 资源是否启用 + Enabled tristate.TriState `nullable:"false" default:"false" list:"user" create:"optional"` +} + +type IEnabledBase interface { + IModel + SetEnabled(enabled bool) + GetEnabled() bool +} + +func (m *SEnabledResourceBase) SetEnabled(enabled bool) { + if enabled { + m.Enabled = tristate.True + } else { + m.Enabled = tristate.False + } +} + +func (m *SEnabledResourceBase) GetEnabled() bool { + return m.Enabled.Bool() +} + +func EnabledPerformEnable(model IEnabledBase, ctx context.Context, userCred mcclient.TokenCredential, enabled bool) error { + if model.GetEnabled() == enabled { + return nil + } + _, err := Update(model, func() error { + model.SetEnabled(enabled) + return nil + }) + if err != nil { + return errors.Wrap(err, "Update") + } + if enabled { + OpsLog.LogEvent(model, ACT_ENABLE, "", userCred) + logclient.AddSimpleActionLog(model, logclient.ACT_ENABLE, nil, userCred, true) + } else { + OpsLog.LogEvent(model, ACT_DISABLE, "", userCred) + logclient.AddSimpleActionLog(model, logclient.ACT_DISABLE, nil, userCred, true) + } + return nil +} + +func (manager *SEnabledResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.EnabledResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + if query.Enabled != nil { + if *query.Enabled { + q = q.IsTrue("enabled") + } else { + q = q.IsFalse("enabled") + } + } + return q, nil +} diff --git a/pkg/cloudcommon/db/enabledstatusdomainresource.go b/pkg/cloudcommon/db/enabledstatusdomainresource.go new file mode 100644 index 0000000000..b6fc814edf --- /dev/null +++ b/pkg/cloudcommon/db/enabledstatusdomainresource.go @@ -0,0 +1,148 @@ +// 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 db + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SEnabledStatusDomainLevelResourceBase struct { + SStatusDomainLevelResourceBase + SEnabledResourceBase +} + +type SEnabledStatusDomainLevelResourceBaseManager struct { + SStatusDomainLevelResourceBaseManager + SEnabledResourceBaseManager +} + +func NewEnabledStatusDomainLevelResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SEnabledStatusDomainLevelResourceBaseManager { + return SEnabledStatusDomainLevelResourceBaseManager{ + SStatusDomainLevelResourceBaseManager: NewStatusDomainLevelResourceBaseManager(dt, tableName, keyword, keywordPlural), + } +} + +func (self *SEnabledStatusDomainLevelResourceBase) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) bool { + return IsDomainAllowPerform(userCred, self, "enable") +} + +func (self *SEnabledStatusDomainLevelResourceBase) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + err := EnabledPerformEnable(self, ctx, userCred, true) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") + } + return nil, nil +} + +func (self *SEnabledStatusDomainLevelResourceBase) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) bool { + return IsDomainAllowPerform(userCred, self, "disable") +} + +func (self *SEnabledStatusDomainLevelResourceBase) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + err := EnabledPerformEnable(self, ctx, userCred, false) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") + } + return nil, nil +} + +func (manager *SEnabledStatusDomainLevelResourceBaseManager) ValidateCreateData( + ctx context.Context, + userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, + query jsonutils.JSONObject, + input apis.EnabledStatusDomainLevelResourceCreateInput, +) (apis.EnabledStatusDomainLevelResourceCreateInput, error) { + var err error + input.StatusDomainLevelResourceCreateInput, err = manager.SStatusDomainLevelResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusDomainLevelResourceCreateInput) + if err != nil { + return input, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ValidateCreateData") + } + return input, nil +} + +func (manager *SEnabledStatusDomainLevelResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.EnabledStatusDomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusDomainLevelResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.ListItemFilter") + } + q, err = manager.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SEnabledStatusDomainLevelResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SEnabledStatusDomainLevelResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.EnabledStatusDomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusDomainLevelResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusDomainLevelResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SEnabledStatusDomainLevelResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.EnabledStatusDomainLevelResourceDetails { + rows := make([]apis.EnabledStatusDomainLevelResourceDetails, len(objs)) + domainRows := manager.SStatusDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.EnabledStatusDomainLevelResourceDetails{ + StatusDomainLevelResourceDetails: domainRows[i], + } + } + return rows +} + +func (model *SEnabledStatusDomainLevelResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.EnabledStatusDomainLevelResourceDetails, error) { + return apis.EnabledStatusDomainLevelResourceDetails{}, nil +} diff --git a/pkg/cloudcommon/db/enabledstatusstandalone.go b/pkg/cloudcommon/db/enabledstatusstandalone.go index 5fe50a6804..f598cd6b7b 100644 --- a/pkg/cloudcommon/db/enabledstatusstandalone.go +++ b/pkg/cloudcommon/db/enabledstatusstandalone.go @@ -18,107 +18,51 @@ import ( "context" "yunion.io/x/jsonutils" - "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/util/logclient" - "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SEnabledStatusStandaloneResourceBase struct { SStatusStandaloneResourceBase - - Enabled bool `nullable:"false" default:"false" list:"user" create:"optional"` // = Column(Boolean, nullable=False, default=False) + SEnabledResourceBase } type SEnabledStatusStandaloneResourceBaseManager struct { SStatusStandaloneResourceBaseManager + SEnabledResourceBaseManager } func NewEnabledStatusStandaloneResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SEnabledStatusStandaloneResourceBaseManager { - return SEnabledStatusStandaloneResourceBaseManager{SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural)} + return SEnabledStatusStandaloneResourceBaseManager{ + SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural), + } } -type IEnableModel interface { - IModel - IsEnable() bool - SetEnable() error - SetDisable() error +func (self *SEnabledStatusStandaloneResourceBase) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) bool { + return IsAdminAllowPerform(userCred, self, "enable") } -func (self *SEnabledStatusStandaloneResourceBase) IsEnable() bool { - return self.Enabled -} - -func (self *SEnabledStatusStandaloneResourceBase) SetEnable() error { - self.Enabled = true - return nil -} - -func (self *SEnabledStatusStandaloneResourceBase) SetDisable() error { - self.Enabled = false - return nil -} - -func (self *SEnabledStatusStandaloneResourceBase) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return AllowPerformEnable(self, rbacutils.ScopeSystem, userCred) -} - -func AllowPerformEnable(obj IEnableModel, scope rbacutils.TRbacScope, userCred mcclient.TokenCredential) bool { - return IsAllowPerform(scope, userCred, obj, "enable") -} - -func (self *SEnabledStatusStandaloneResourceBase) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return PerformEnable(self, userCred) -} - -func PerformEnable(obj IEnableModel, userCred mcclient.TokenCredential) (jsonutils.JSONObject, error) { - if !obj.IsEnable() { - _, err := Update(obj, func() error { - if err := obj.SetEnable(); err != nil { - return err - } - return nil - }) - if err != nil { - log.Errorf("PerformEnable save update fail %s", err) - return nil, err - } - OpsLog.LogEvent(obj, ACT_ENABLE, "", userCred) - logclient.AddSimpleActionLog(obj, logclient.ACT_ENABLE, nil, userCred, true) +func (self *SEnabledStatusStandaloneResourceBase) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + err := EnabledPerformEnable(self, ctx, userCred, true) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") } return nil, nil } -func (self *SEnabledStatusStandaloneResourceBase) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return AllowPerformDisable(self, rbacutils.ScopeSystem, userCred) +func (self *SEnabledStatusStandaloneResourceBase) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) bool { + return IsAdminAllowPerform(userCred, self, "disable") } -func AllowPerformDisable(obj IEnableModel, scope rbacutils.TRbacScope, userCred mcclient.TokenCredential) bool { - return IsAllowPerform(scope, userCred, obj, "disable") -} - -func (self *SEnabledStatusStandaloneResourceBase) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return PerformDisable(self, userCred) -} - -func PerformDisable(obj IEnableModel, userCred mcclient.TokenCredential) (jsonutils.JSONObject, error) { - if obj.IsEnable() { - _, err := Update(obj, func() error { - if err := obj.SetDisable(); err != nil { - return err - } - return nil - }) - if err != nil { - log.Errorf("PerformDisable save update fail %s", err) - return nil, err - } - OpsLog.LogEvent(obj, ACT_DISABLE, "", userCred) - logclient.AddSimpleActionLog(obj, logclient.ACT_DISABLE, nil, userCred, true) +func (self *SEnabledStatusStandaloneResourceBase) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + err := EnabledPerformEnable(self, ctx, userCred, false) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") } return nil, nil } @@ -132,21 +76,67 @@ func (manager *SEnabledStatusStandaloneResourceBaseManager) ValidateCreateData(c return input, nil } -func (manager *SEnabledStatusStandaloneResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.EnabledStatusStandaloneResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SEnabledStatusStandaloneResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.EnabledStatusStandaloneResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } - return ListEnableItemFilter(q, query.Enabled) -} - -func ListEnableItemFilter(q *sqlchemy.SQuery, enabled *bool) (*sqlchemy.SQuery, error) { - if enabled != nil { - if *enabled { - q = q.IsTrue("enabled") - } else { - q = q.IsFalse("enabled") - } + q, err = manager.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SEnabledStatusStandaloneResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SEnabledStatusStandaloneResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.EnabledStatusStandaloneResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SEnabledStatusStandaloneResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.EnabledStatusStandaloneResourceDetails { + rows := make([]apis.EnabledStatusStandaloneResourceDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.EnabledStatusStandaloneResourceDetails{ + StatusStandaloneResourceDetails: stdRows[i], + } + } + return rows +} + +func (model *SEnabledStatusStandaloneResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.EnabledStatusStandaloneResourceDetails, error) { + return apis.EnabledStatusStandaloneResourceDetails{}, nil +} diff --git a/pkg/cloudcommon/db/external.go b/pkg/cloudcommon/db/external.go index 7efb8c60a8..350abc30c4 100644 --- a/pkg/cloudcommon/db/external.go +++ b/pkg/cloudcommon/db/external.go @@ -24,7 +24,7 @@ import ( type SExternalizedResourceBase struct { // 外部Id, 对用公有云私有资源自身的Id - ExternalId string `width:"256" charset:"utf8" index:"true" list:"user" create:"admin_optional" update:"admin"` + ExternalId string `width:"256" charset:"utf8" index:"true" list:"user" create:"admin_optional" update:"admin" json:"external_id"` } func (model SExternalizedResourceBase) GetExternalId() string { diff --git a/pkg/cloudcommon/db/fetch.go b/pkg/cloudcommon/db/fetch.go index 901e70cdc4..9735eb40a1 100644 --- a/pkg/cloudcommon/db/fetch.go +++ b/pkg/cloudcommon/db/fetch.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" "fmt" + "reflect" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -390,3 +391,126 @@ func FetchCheckQueryOwnerScope(ctx context.Context, userCred mcclient.TokenCrede } return ownerId, queryScope, nil } + +func mapKeys(idMap map[string]string) []string { + keys := make([]string, len(idMap)) + idx := 0 + for k := range idMap { + keys[idx] = k + idx += 1 + } + return keys +} + +func FetchIdNameMap2(manager IStandaloneModelManager, ids []string) (map[string]string, error) { + idMap := make(map[string]string, len(ids)) + for _, id := range ids { + idMap[id] = "" + } + return FetchIdNameMap(manager, idMap) +} + +func FetchIdNameMap(manager IStandaloneModelManager, idMap map[string]string) (map[string]string, error) { + q := manager.Query("id", "name").In("id", mapKeys(idMap)) + rows, err := q.Rows() + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return idMap, nil + } else { + return idMap, errors.Wrap(err, "Query") + } + } + defer rows.Close() + for rows.Next() { + var id string + var name string + err := rows.Scan(&id, &name) + if err != nil { + return idMap, errors.Wrap(err, "rows.Scan") + } + idMap[id] = name + } + return idMap, nil +} + +func FetchModelObjectsByIds(modelManager IModelManager, fieldName string, ids []string, targets interface{}) error { + err := FetchQueryObjectsByIds(modelManager.Query(), fieldName, ids, targets) + if err != nil { + return errors.Wrap(err, "FetchQueryObjectsByIds") + } + // try to call model's SetModelManager + targetValue := reflect.Indirect(reflect.ValueOf(targets)) + for _, key := range targetValue.MapKeys() { + modelValueV := targetValue.MapIndex(key) + if modelValueV.Kind() != reflect.Struct { + break + } + newModelValue := reflect.New(modelValueV.Type()).Elem() + newModelValue.Set(modelValueV) + modelValue := newModelValue.Addr().Interface() + if model, ok := modelValue.(IModel); ok { + model.SetModelManager(modelManager, model) + targetValue.SetMapIndex(key, reflect.Indirect(reflect.ValueOf(model))) + } + } + return nil +} + +func FetchQueryObjectsByIds(q *sqlchemy.SQuery, fieldName string, ids []string, targets interface{}) error { + if len(ids) == 0 { + return nil + } + + targetValue := reflect.Indirect(reflect.ValueOf(targets)) + if targetValue.Kind() != reflect.Map { + return errors.Wrap(httperrors.ErrBadRequest, "receiver should be a map") + } + + isTargetSlice := false + modelType := targetValue.Type().Elem() + if modelType.Kind() == reflect.Slice { + isTargetSlice = true + modelType = modelType.Elem() + } + + query := q.In(fieldName, ids) + rows, err := query.Rows() + if err != nil { + if err == sql.ErrNoRows { + return nil + } + return err + } + defer rows.Close() + + targetsValue := reflect.Indirect(reflect.ValueOf(targets)) + for rows.Next() { + mMap, err := query.Row2Map(rows) + if err != nil { + return errors.Wrap(err, "query.Row2Map") + } + fieldValue := mMap[fieldName] + m := reflect.New(modelType).Interface() // a pointer + err = query.RowMap2Struct(mMap, m) + if err != nil { + return errors.Wrap(err, "query.RowMap2Struct") + } + keyValue := reflect.ValueOf(fieldValue) + valValue := reflect.Indirect(reflect.ValueOf(m)) + if isTargetSlice { + sliceValue := targetValue.MapIndex(keyValue) + if !sliceValue.IsValid() { + sliceValue = reflect.New(reflect.SliceOf(modelType)).Elem() + } + sliceValue = reflect.Append(sliceValue, valValue) + targetsValue.SetMapIndex(keyValue, sliceValue) + } else { + targetsValue.SetMapIndex(keyValue, valValue) + } + } + return nil +} + +func FetchStandaloneObjectsByIds(modelManager IModelManager, ids []string, targets interface{}) error { + return FetchModelObjectsByIds(modelManager, "id", ids, targets) +} diff --git a/pkg/cloudcommon/db/interface.go b/pkg/cloudcommon/db/interface.go index 9ee24e792d..e6f3feb808 100644 --- a/pkg/cloudcommon/db/interface.go +++ b/pkg/cloudcommon/db/interface.go @@ -27,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/object" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" - "yunion.io/x/onecloud/pkg/util/stringutils2" ) type IModelManager interface { @@ -59,7 +58,8 @@ type IModelManager interface { ExtraSearchConditions(ctx context.Context, q *sqlchemy.SQuery, like string) []sqlchemy.ICondition GetExportExtraKeys(ctx context.Context, query jsonutils.JSONObject, rowMap map[string]string) *jsonutils.JSONDict ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) - OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) + // OrderByExtraFields dynmically called by dispatcher + // OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) // fetch hook Query(val ...string) *sqlchemy.SQuery @@ -110,7 +110,8 @@ type IModelManager interface { GetSkipLog(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool // list extend colums hook - FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict + // FetchCustomizeColumns dynamically called by dispatcher + // FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []interface{}, fields stringutils2.SSortedStrings, isList bool) []*jsonutils.JSONDict // fetch owner Id from query when create resource FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) @@ -120,6 +121,7 @@ type IModelManager interface { NamespaceScope() rbacutils.TRbacScope ResourceScope() rbacutils.TRbacScope + // 如果error为非空,说明没有匹配的field,如果为空,说明匹配上了 QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) GetPagingConfig() *SPagingConfig @@ -249,6 +251,8 @@ type IStandaloneModelManager interface { // IsNewNameUnique(name string, projectId string) bool // FetchByExternalId(idStr string) (IStandaloneModel, error) + + GetMetadataHiddenKeys() []string } type IStandaloneModel interface { @@ -256,6 +260,8 @@ type IStandaloneModel interface { // IsAlterNameUnique(name string, projectId string) bool // GetExternalId() string + StandaloneModelManager() IStandaloneModelManager + GetIStandaloneModel() IStandaloneModel ClearSchedDescCache() error @@ -271,11 +277,21 @@ type IStandaloneModel interface { GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) } -type IMetadataModel interface { +type IDomainLevelModelManager interface { + IStandaloneModelManager + + GetIDomainLevelModelManager() IDomainLevelModelManager + GetResourceCount() ([]SProjectResourceCount, error) +} + +type IDomainLevelModel interface { IStandaloneModel - // GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) - GetMetadataHideKeys() []string + IsOwner(userCred mcclient.TokenCredential) bool + + SyncCloudDomainId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) + + GetIDomainLevelModel() IDomainLevelModel } type IVirtualModelManager interface { diff --git a/pkg/cloudcommon/db/jointbase.go b/pkg/cloudcommon/db/jointbase.go index fe1ad9a17a..7658696dc7 100644 --- a/pkg/cloudcommon/db/jointbase.go +++ b/pkg/cloudcommon/db/jointbase.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SJointResourceBase struct { @@ -228,3 +229,30 @@ func (manager *SJointResourceBaseManager) ValidateCreateData(ctx context.Context } return input, nil } + +func (model *SJointResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.JointResourceBaseDetails, error) { + return apis.JointResourceBaseDetails{}, nil +} + +func (manager *SJointResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.JointResourceBaseDetails { + ret := make([]apis.JointResourceBaseDetails, len(objs)) + upperRet := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + ret[i] = apis.JointResourceBaseDetails{ + ResourceBaseDetails: upperRet[i], + } + } + return ret +} diff --git a/pkg/cloudcommon/db/metadata.go b/pkg/cloudcommon/db/metadata.go index 62a5244bf5..2fc5c23191 100644 --- a/pkg/cloudcommon/db/metadata.go +++ b/pkg/cloudcommon/db/metadata.go @@ -24,6 +24,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/util/stringutils" + "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -445,12 +446,12 @@ func IsMetadataKeyVisiable(key string) bool { return !(IsMetadataKeySysTag(key) || IsMetadataKeySystemAdmin(key)) } -func GetVisiableMetadata(model IMetadataModel, userCred mcclient.TokenCredential) (map[string]string, error) { +func GetVisiableMetadata(model IStandaloneModel, userCred mcclient.TokenCredential) (map[string]string, error) { metaData, err := model.GetAllMetadata(userCred) if err != nil { return nil, err } - for _, key := range model.GetMetadataHideKeys() { + for _, key := range model.StandaloneModelManager().GetMetadataHiddenKeys() { delete(metaData, key) } for key := range metaData { @@ -460,3 +461,16 @@ func GetVisiableMetadata(model IMetadataModel, userCred mcclient.TokenCredential } return metaData, nil } + +func metaList2Map(manager IStandaloneModelManager, userCred mcclient.TokenCredential, metaList []SMetadata) map[string]string { + metaMap := make(map[string]string) + + hiddenKeys := manager.GetMetadataHiddenKeys() + for _, meta := range metaList { + if IsMetadataKeyVisiable(meta.Key) && !utils.IsInStringArray(meta.Key, hiddenKeys) { + metaMap[meta.Key] = meta.Value + } + } + + return metaMap +} diff --git a/pkg/cloudcommon/db/metadata_test.go b/pkg/cloudcommon/db/metadata_test.go index 6cf61e6894..6816c479e5 100644 --- a/pkg/cloudcommon/db/metadata_test.go +++ b/pkg/cloudcommon/db/metadata_test.go @@ -106,6 +106,11 @@ func TestIsMetadataKeyVisiable(t *testing.T) { } } +type MockMetadataModelManager struct { + mock.Mock + SStandaloneResourceBaseManager +} + type MockMetadataModel struct { mock.Mock SStandaloneResourceBase @@ -116,12 +121,13 @@ func (m *MockMetadataModel) GetAllMetadata(userCred mcclient.TokenCredential) (m return args.Get(0).(map[string]string), args.Error(1) } -func (m *MockMetadataModel) GetMetadataHideKeys() []string { +func (m *MockMetadataModelManager) GetMetadataHiddenKeys() []string { args := m.Called() return args.Get(0).([]string) } func TestGetVisiableMetadata(t *testing.T) { + testManager := new(MockMetadataModelManager) testObj := new(MockMetadataModel) testObj.On("GetAllMetadata", nil).Return( map[string]string{ @@ -132,11 +138,13 @@ func TestGetVisiableMetadata(t *testing.T) { }, nil, ) - testObj.On("GetMetadataHideKeys").Return([]string{"login_account"}) + testManager.On("GetMetadataHiddenKeys").Return([]string{"login_account"}) + + testObj.SetModelManager(testManager, testObj) tests := []struct { name string - model IMetadataModel + model IStandaloneModel want map[string]string wantErr bool }{ diff --git a/pkg/cloudcommon/db/modelbase.go b/pkg/cloudcommon/db/modelbase.go index 104228725f..e124987009 100644 --- a/pkg/cloudcommon/db/modelbase.go +++ b/pkg/cloudcommon/db/modelbase.go @@ -123,10 +123,29 @@ func (manager *SModelBaseManager) ValidateListConditions(ctx context.Context, us return query, nil } -func (manager *SModelBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.ModelBaseListInput) (*sqlchemy.SQuery, error) { +func (manager *SModelBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.ModelBaseListInput, +) (*sqlchemy.SQuery, error) { return q, nil } +func (manager *SModelBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.ModelBaseListInput, +) (*sqlchemy.SQuery, error) { + return q, nil +} + +func (manager *SModelBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + // no field match + return q, httperrors.ErrNotFound +} + func (manager *SModelBaseManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*CustomizeListFilters, error) { return NewCustomizeListFilters(), nil } @@ -227,10 +246,6 @@ func (manager *SModelBaseManager) ListItemExportKeys(ctx context.Context, q *sql return q, nil } -func (manager *SModelBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - return q, nil -} - func (manager *SModelBaseManager) GetExportExtraKeys(ctx context.Context, query jsonutils.JSONObject, rowMap map[string]string) *jsonutils.JSONDict { return jsonutils.NewDict() } @@ -266,10 +281,21 @@ func (manager *SModelBaseManager) GetSkipLog(ctx context.Context, userCred mccli return false } -func (manager *SModelBaseManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - ret := make([]*jsonutils.JSONDict, len(objs)) +func (model *SModelBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.ModelBaseDetails, error) { + return apis.ModelBaseDetails{}, nil +} + +func (manager *SModelBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.ModelBaseDetails { + ret := make([]apis.ModelBaseDetails, len(objs)) for i := range objs { - ret[i] = jsonutils.NewDict() + ret[i] = getModelExtraDetails(objs[i].(IModel), ctx) } return ret } @@ -290,10 +316,6 @@ func (manager *SModelBaseManager) ResourceScope() rbacutils.TRbacScope { return rbacutils.ScopeSystem } -func (manager *SModelBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { - return q, httperrors.NewBadRequestError("unsupport field %s", field) -} - func (manager *SModelBaseManager) AllowGetPropertyDistinctField(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } @@ -361,10 +383,10 @@ func (manager *SModelBaseManager) GetPropertyDistinctField(ctx context.Context, fe, _ := efs[i].GetString() nqp, err := im.QueryDistinctExtraField(&nq, fe) if err != nil { - return nil, err + continue } ef, err := nqp.AllStringMap() - if err == sql.ErrNoRows { + if errors.Cause(err) == sql.ErrNoRows { continue } efa := make([]string, len(ef)) @@ -456,10 +478,6 @@ func (model *SModelBase) AllowGetDetails(ctx context.Context, userCred mcclient. return false } -func (model *SModelBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.ModelBaseDetails, error) { - return getModelExtraDetails(model.GetIModel(), ctx), nil -} - func (model *SModelBase) GetExtraDetailsHeaders(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) map[string]string { return nil } diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 48147308a7..61fcd8504b 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -438,7 +438,12 @@ func (manager *SOpsLogManager) LogDetachEvent(ctx context.Context, m1, m2 IModel } // 操作日志列表 -func (manager *SOpsLogManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { +func (manager *SOpsLogManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) (*sqlchemy.SQuery, error) { userStrs := jsonutils.GetQueryStringArray(query, "user") if len(userStrs) > 0 { for i := range userStrs { diff --git a/pkg/cloudcommon/db/orderby.go b/pkg/cloudcommon/db/orderby.go new file mode 100644 index 0000000000..0a5f9cecdc --- /dev/null +++ b/pkg/cloudcommon/db/orderby.go @@ -0,0 +1,48 @@ +// 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 db + +import "yunion.io/x/sqlchemy" + +func NeedOrderQuery(fieldOrders []string) bool { + for _, field := range fieldOrders { + if sqlchemy.SQL_ORDER_ASC.Equals(field) || sqlchemy.SQL_ORDER_DESC.Equals(field) { + return true + break + } + } + return false +} + +func OrderByFields(q *sqlchemy.SQuery, fieldOrders []string, fields []sqlchemy.IQueryField) *sqlchemy.SQuery { + for i := range fields { + if sqlchemy.SQL_ORDER_ASC.Equals(fieldOrders[i]) { + q = q.Asc(fields[i]) + } else { + q = q.Desc(fields[i]) + } + } + return q +} + +func OrderByStandaloneResourceName(q *sqlchemy.SQuery, modelManager IStandaloneModelManager, fieldName string, orderBy string) *sqlchemy.SQuery { + subq := modelManager.Query("id", "name").SubQuery() + orders := []string{orderBy} + if NeedOrderQuery(orders) { + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field(fieldName), subq.Field("id"))) + q = OrderByFields(q, orders, []sqlchemy.IQueryField{subq.Field("name")}) + } + return q +} diff --git a/pkg/cloudcommon/db/project.go b/pkg/cloudcommon/db/project.go index 35950b578b..f201d133d4 100644 --- a/pkg/cloudcommon/db/project.go +++ b/pkg/cloudcommon/db/project.go @@ -16,16 +16,24 @@ package db import ( "context" + "time" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" + identityapi "yunion.io/x/onecloud/pkg/apis/identity" + "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SProjectizedResourceBaseManager struct { + SDomainizedResourceBaseManager } type SProjectizedResourceBase struct { @@ -68,12 +76,134 @@ func (manager *SProjectizedResourceBaseManager) FetchOwnerId(ctx context.Context func (manager *SProjectizedResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { switch field { case "tenant": - tenantCacheQuery := TenantCacheManager.Query("name", "id").Distinct().SubQuery() - q.AppendField(tenantCacheQuery.Field("name", "tenant")) + tenantCacheQuery := TenantCacheManager.GetTenantQuery("name", "id").Distinct().SubQuery() + q.AppendField(tenantCacheQuery.Field("name", "tenant")).Distinct() q = q.Join(tenantCacheQuery, sqlchemy.Equals(q.Field("tenant_id"), tenantCacheQuery.Field("id"))) - q.GroupBy(tenantCacheQuery.Field("name")) - default: - return q, httperrors.NewBadRequestError("unsupport field %s", field) + return q, nil + } + q, err := manager.SDomainizedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SProjectizedResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.ProjectizedResourceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SDomainizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainizedResourceBaseManager.ListItemFilter") + } + if len(query.Projects) > 0 { + tenants := TenantCacheManager.GetTenantQuery().SubQuery() + subq := tenants.Query(tenants.Field("id")).Filter(sqlchemy.OR( + sqlchemy.In(tenants.Field("id"), query.Projects), + sqlchemy.In(tenants.Field("name"), query.Projects), + )).SubQuery() + q = q.In("tenant_id", subq) } return q, nil } + +func (manager *SProjectizedResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.ProjectizedResourceListInput, +) (*sqlchemy.SQuery, error) { + orders := []string{query.OrderByProject, query.OrderByDomain} + if NeedOrderQuery(orders) { + subq := TenantCacheManager.GetTenantQuery("id", "name", "domain").SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("tenant_id"), subq.Field("id"))) + q = OrderByFields(q, orders, []sqlchemy.IQueryField{subq.Field("name"), subq.Field("domain")}) + } + return q, nil +} + +func (manager *SProjectizedResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.ProjectizedResourceInfo { + ret := make([]apis.ProjectizedResourceInfo, len(objs)) + for i := range ret { + ret[i] = apis.ProjectizedResourceInfo{} + var base *SProjectizedResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.ProjectId) > 0 { + ret[i].TenantId = base.ProjectId + } + } + if len(fields) == 0 || fields.Contains("project_domain") || fields.Contains("tenant") { + projectIds := stringutils2.SSortedStrings{} + for i := range objs { + var base *SProjectizedResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.ProjectId) > 0 { + projectIds = stringutils2.Append(projectIds, base.ProjectId) + } + } + projects := FetchProjects(projectIds, false) + if projects != nil { + for i := range objs { + var base *SProjectizedResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.ProjectId) > 0 { + if proj, ok := projects[base.ProjectId]; ok { + if len(fields) == 0 || fields.Contains("project_domain") { + ret[i].ProjectDomain = proj.Domain + } + if len(fields) == 0 || fields.Contains("tenant") { + ret[i].Project = proj.Name + ret[i].Tenant = proj.Name + } + } + } + } + } + } + return ret +} + +func FetchProjects(projectIds []string, isDomain bool) map[string]STenant { + deadline := time.Now().UTC().Add(-consts.GetTenantCacheExpireSeconds()) + q := TenantCacheManager.Query().In("id", projectIds).GT("last_check", deadline) + if isDomain { + q = q.Equals("domain_id", identityapi.KeystoneDomainRoot) + } else { + q = q.NotEquals("domain_id", identityapi.KeystoneDomainRoot) + } + projects := make([]STenant, 0) + err := FetchModelObjects(TenantCacheManager, q, &projects) + if err != nil { + return nil + } + ret := make(map[string]STenant) + for i := range projects { + ret[projects[i].Id] = projects[i] + } + ctx := context.Background() + for _, pid := range projectIds { + if _, ok := ret[pid]; !ok { + // not found + var t *STenant + if isDomain { + t, _ = TenantCacheManager.fetchDomainFromKeystone(ctx, pid) + } else { + t, _ = TenantCacheManager.fetchTenantFromKeystone(ctx, pid) + } + if t != nil { + ret[t.Id] = *t + } + } + } + return ret +} diff --git a/pkg/cloudcommon/db/project_resources.go b/pkg/cloudcommon/db/project_resources.go index eaac0fd240..7e73e74221 100644 --- a/pkg/cloudcommon/db/project_resources.go +++ b/pkg/cloudcommon/db/project_resources.go @@ -59,8 +59,8 @@ func getAllProjectResourceCounts() (map[string][]SProjectResourceCount, error) { } type SProjectResourceCount struct { - TenantId string - ResCount int + TenantId string `json:"tenant_id"` + ResCount int `json:"res_count"` } func (virtman *SVirtualResourceBaseManager) GetResourceCount() ([]SProjectResourceCount, error) { @@ -81,3 +81,27 @@ func CalculateProjectResourceCount(query *sqlchemy.SQuery) ([]SProjectResourceCo } return cnts, nil } + +type SDomainResourceCount struct { + DomainId string `json:"domain_id"` + ResCount int `json:"res_count"` +} + +func (domainman *SDomainLevelResourceBaseManager) GetResourceCount() ([]SDomainResourceCount, error) { + virts := domainman.GetIDomainLevelModelManager().Query() + // log.Debugf("GetResourceCount: %s", virtman.keywordPlural) + return CalculateDomainResourceCount(virts) +} + +func CalculateDomainResourceCount(query *sqlchemy.SQuery) ([]SDomainResourceCount, error) { + virts := query.SubQuery() + q := virts.Query(virts.Field("domain_id"), sqlchemy.COUNT("res_count")) + q = q.IsNotEmpty("domain_id") + q = q.GroupBy(virts.Field("domain_id")) + cnts := make([]SDomainResourceCount, 0) + err := q.All(&cnts) + if err != nil && err != sql.ErrNoRows { + return nil, errors.Wrap(err, "q.All") + } + return cnts, nil +} diff --git a/pkg/cloudcommon/db/resourcebase.go b/pkg/cloudcommon/db/resourcebase.go index 2316387a14..193b736cd6 100644 --- a/pkg/cloudcommon/db/resourcebase.go +++ b/pkg/cloudcommon/db/resourcebase.go @@ -24,7 +24,9 @@ import ( "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SResourceBase struct { @@ -116,7 +118,12 @@ func (manager *SResourceBaseManager) ValidateCreateData(ctx context.Context, use return input, nil } -func (manager *SResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.ResourceBaseListInput) (*sqlchemy.SQuery, error) { +func (manager *SResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.ResourceBaseListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SModelBaseManager.ListItemFilter(ctx, q, userCred, query.ModelBaseListInput) if err != nil { return nil, errors.Wrap(err, "SModelBaseManager.ListItemFilter") @@ -124,6 +131,30 @@ func (manager *SResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlc return q, nil } +func (manager *SResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.ResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SModelBaseManager.OrderByExtraFields(ctx, q, userCred, query.ModelBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SModelBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SModelBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (model *SResourceBase) GetUpdateVersion() int { return model.UpdateVersion } @@ -135,3 +166,31 @@ func (model *SResourceBase) GetUpdatedAt() time.Time { func (model *SResourceBase) GetDeleted() bool { return model.Deleted } + +func (manager *SResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.ResourceBaseDetails { + ret := make([]apis.ResourceBaseDetails, len(objs)) + upperRet := manager.SModelBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + ret[i] = apis.ResourceBaseDetails{ + ModelBaseDetails: upperRet[i], + } + } + return ret +} + +func (model *SResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.ResourceBaseDetails, error) { + var err error + out := apis.ResourceBaseDetails{} + out.ModelBaseDetails, err = model.SModelBase.GetExtraDetails(ctx, userCred, query, isList) + if err != nil { + return out, errors.Wrap(err, "SModelBase.GetExtraDetails") + } + return out, nil +} diff --git a/pkg/cloudcommon/db/sharablebase.go b/pkg/cloudcommon/db/sharablebase.go index 34fedfd38e..fb71e9e889 100644 --- a/pkg/cloudcommon/db/sharablebase.go +++ b/pkg/cloudcommon/db/sharablebase.go @@ -20,6 +20,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/httperrors" @@ -48,7 +49,7 @@ type SSharableBaseResource struct { IsPublic bool `default:"false" nullable:"false" list:"user"` } -type SSharableBaseInterface interface { +type ISharableBase interface { IModel SetIsPublic(pub bool) GetIsPublic() bool @@ -66,11 +67,11 @@ func (m SSharableBaseResource) GetIsPublic() bool { return m.IsPublic } -func SharableAllowPerformPublic(model SSharableBaseInterface, userCred mcclient.TokenCredential) bool { +func SharableAllowPerformPublic(model ISharableBase, userCred mcclient.TokenCredential) bool { return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "public") } -func SharablePerformPublic(model SSharableBaseInterface, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func SharablePerformPublic(model ISharableBase, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { if model.GetIsPublic() { return nil, nil } @@ -95,11 +96,11 @@ func SharablePerformPublic(model SSharableBaseInterface, ctx context.Context, us return nil, err } -func SharableAllowPerformPrivate(model SSharableBaseInterface, userCred mcclient.TokenCredential) bool { +func SharableAllowPerformPrivate(model ISharableBase, userCred mcclient.TokenCredential) bool { return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "private") } -func SharablePerformPrivate(model SSharableBaseInterface, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func SharablePerformPrivate(model ISharableBase, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { if !model.GetIsPublic() { return nil, nil } @@ -123,3 +124,19 @@ func SharablePerformPrivate(model SSharableBaseInterface, ctx context.Context, u } return nil, err } + +func (manager *SSharableBaseResourceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.SharableResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + if query.IsPublic != nil { + if *query.IsPublic == true { + q = q.IsTrue("is_public") + } else { + q = q.IsFalse("is_public") + } + } + return q, nil +} diff --git a/pkg/cloudcommon/db/sharablevirtual.go b/pkg/cloudcommon/db/sharablevirtual.go index 31b2a68a4f..fd365e03e9 100644 --- a/pkg/cloudcommon/db/sharablevirtual.go +++ b/pkg/cloudcommon/db/sharablevirtual.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSharableVirtualResourceBase struct { @@ -111,15 +112,14 @@ func (model *SSharableVirtualResourceBase) IsSharable(reqUsrId mcclient.IIdentit return false } -func (model *SSharableVirtualResourceBase) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (model *SSharableVirtualResourceBase) AllowPerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPublicInput) bool { return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "public") } -func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - targetScopeStr, _ := data.GetString("scope") - targetScope := rbacutils.String2ScopeDefault(targetScopeStr, rbacutils.ScopeSystem) +func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPublicInput) (jsonutils.JSONObject, error) { + targetScope := rbacutils.String2ScopeDefault(input.Scope, rbacutils.ScopeSystem) if targetScope == rbacutils.ScopeProject { - if sharedProjects, err := data.GetArray("shared_projects"); err == nil { + if len(input.SharedProjects) > 0 { delProjects := make([]*SSharedResource, 0) addProjects := make([]string, 0) ops := make(map[string]*SSharedResource, 0) @@ -137,8 +137,8 @@ func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, us for i := 0; i < len(srs); i++ { ops[srs[i].TargetProjectId] = &srs[i] } - for i := 0; i < len(sharedProjects); i++ { - sharedProject, _ := sharedProjects[i].GetString() + for i := 0; i < len(input.SharedProjects); i++ { + sharedProject := input.SharedProjects[i] tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, sharedProject) if err != nil { return nil, httperrors.NewBadRequestError("fetch tenant %s error %s", sharedProject, err) @@ -215,11 +215,11 @@ func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, us return nil, nil } -func (model *SSharableVirtualResourceBase) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (model *SSharableVirtualResourceBase) AllowPerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPrivateInput) bool { return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "private") } -func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformProjectPrivateInput) (jsonutils.JSONObject, error) { if model.IsPublic { allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private") requireScope := rbacutils.String2ScopeDefault(model.PublicScope, rbacutils.ScopeSystem) @@ -259,7 +259,7 @@ func (model *SSharableVirtualResourceBase) GetSharedProjects() []string { return res } -func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out apis.SharableVirtualResourceDetails) apis.SharableVirtualResourceDetails { +/*func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out apis.SharableVirtualResourceDetails) apis.SharableVirtualResourceDetails { out.SharedProjects = []apis.SharedProject{} projects := model.GetSharedProjects() for i := 0; i < len(projects); i++ { @@ -275,17 +275,7 @@ func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, u out.SharedProjects = append(out.SharedProjects, project) } return out -} - -func (model *SSharableVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.SharableVirtualResourceDetails, error) { - var err error - out := apis.SharableVirtualResourceDetails{} - out.VirtualResourceDetails, err = model.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return model.getMoreDetails(ctx, userCred, query, out), nil -} +}*/ func (manager *SSharableVirtualResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.SharableVirtualResourceCreateInput) (apis.SharableVirtualResourceCreateInput, error) { var err error @@ -296,10 +286,74 @@ func (manager *SSharableVirtualResourceBaseManager) ValidateCreateData(ctx conte return input, nil } -func (manager *SSharableVirtualResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.SharableVirtualResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SSharableVirtualResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.SharableVirtualResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SSharableVirtualResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SSharableVirtualResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.SharableVirtualResourceListInput) (*sqlchemy.SQuery, error) { + q, err := manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (model *SSharableVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.SharableVirtualResourceDetails, error) { + return apis.SharableVirtualResourceDetails{}, nil +} + +func (manager *SSharableVirtualResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.SharableVirtualResourceDetails { + + rows := make([]apis.SharableVirtualResourceDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + resIds := make([]string, len(objs)) + for i := range rows { + resIds[i] = objs[i].(ISharableVirtualModel).GetId() + rows[i] = apis.SharableVirtualResourceDetails{ + VirtualResourceDetails: virtRows[i], + } + } + + tenants := TenantCacheManager.GetTenantQuery().SubQuery() + resources := SharedResourceManager.Query().Equals("resource_type", manager.Keyword()).SubQuery() + q := tenants.Query(tenants.Field("id"), tenants.Field("name"), resources.Field("resource_id")) + q = q.Join(resources, sqlchemy.Equals(q.Field("id"), resources.Field("target_project_id"))) + projList := make(map[string][]apis.SharedProject) + err := FetchQueryObjectsByIds(q, "resource_id", resIds, &projList) + if err != nil { + log.Errorf("FetchQueryObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if projs, ok := projList[resIds[i]]; ok { + rows[i].SharedProjects = projs + } + } + + return rows +} diff --git a/pkg/cloudcommon/db/sharedresource.go b/pkg/cloudcommon/db/sharedresource.go index 28d925d28d..279235c93f 100644 --- a/pkg/cloudcommon/db/sharedresource.go +++ b/pkg/cloudcommon/db/sharedresource.go @@ -29,10 +29,10 @@ type SSharedResource struct { Id int64 `primary:"true" auto_increment:"true" list:"user"` - ResourceType string `width:"32" charset:"ascii" nullable:"false" list:"user"` - ResourceId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"` - OwnerProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"` - TargetProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"` + ResourceType string `width:"32" charset:"ascii" nullable:"false" list:"user" json:"resource_type"` + ResourceId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"resource_id"` + OwnerProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"owner_project_id"` + TargetProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user" json:"target_project_id"` } type SSharedResourceManager struct { diff --git a/pkg/cloudcommon/db/standalone.go b/pkg/cloudcommon/db/standalone.go index 50c6860bd9..0a96506f45 100644 --- a/pkg/cloudcommon/db/standalone.go +++ b/pkg/cloudcommon/db/standalone.go @@ -20,6 +20,7 @@ import ( "strings" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/util/stringutils" @@ -32,6 +33,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type UUIDGenerator func() string @@ -68,14 +70,41 @@ type SStandaloneResourceBaseManager struct { NameLength int } -func NewStandaloneResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SStandaloneResourceBaseManager { - return SStandaloneResourceBaseManager{SResourceBaseManager: NewResourceBaseManager(dt, tableName, keyword, keywordPlural)} +func NewStandaloneResourceBaseManager( + dt interface{}, + tableName string, + keyword string, + keywordPlural string, +) SStandaloneResourceBaseManager { + return SStandaloneResourceBaseManager{ + SResourceBaseManager: NewResourceBaseManager(dt, tableName, keyword, keywordPlural), + } } func (manager *SStandaloneResourceBaseManager) IsStandaloneManager() bool { return true } +func (self *SStandaloneResourceBaseManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return IsAdminAllowList(userCred, self) +} + +func (self *SStandaloneResourceBaseManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return IsAdminAllowCreate(userCred, self) +} + +func (self *SStandaloneResourceBase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return IsAdminAllowGet(userCred, self) +} + +func (self *SStandaloneResourceBase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { + return IsAdminAllowUpdate(userCred, self) +} + +func (self *SStandaloneResourceBase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return IsAdminAllowDelete(userCred, self) +} + func (manager *SStandaloneResourceBaseManager) GetIStandaloneModelManager() IStandaloneModelManager { return manager.GetVirtualObject().(IStandaloneModelManager) } @@ -139,12 +168,19 @@ func (manager *SStandaloneResourceBaseManager) FetchByIdOrName(userCred mcclient return FetchByIdOrName(manager.GetIStandaloneModelManager(), userCred, idStr) } -func (manager *SStandaloneResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input apis.StandaloneResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SStandaloneResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.StandaloneResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ResourceBaseListInput) if err != nil { return q, errors.Wrap(err, "SResourceBaseManager.ListItemFilte") } + // show_emulated is handled by FilterByHiddenSystemAttributes + if len(input.Names) > 0 { q = q.In("name", input.Names) } @@ -205,6 +241,27 @@ func (manager *SStandaloneResourceBaseManager) ListItemFilter(ctx context.Contex return q, nil } +func (manager *SStandaloneResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SStandaloneResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input apis.StandaloneResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + func (model *SStandaloneResourceBase) StandaloneModelManager() IStandaloneModelManager { return model.GetModelManager().(IStandaloneModelManager) } @@ -239,16 +296,6 @@ func (model *SStandaloneResourceBase) GetShortDescV2(ctx context.Context) *apis. return desc } -func (model *SStandaloneResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.StandaloneResourceDetails, error) { - var err error - out := apis.StandaloneResourceDetails{} - out.ModelBaseDetails, err = model.SResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return out, nil -} - /* * userCred: optional */ @@ -429,22 +476,46 @@ func (manager *SStandaloneResourceBaseManager) ValidateCreateData(ctx context.Co return input, nil } -/* -func (model SStandaloneResourceBase) GetExternalId() string { - return model.ExternalId +func (model *SStandaloneResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.StandaloneResourceDetails, error) { + return apis.StandaloneResourceDetails{}, nil } -func (model *SStandaloneResourceBase) SetExternalId(userCred mcclient.TokenCredential, idstr string) error { - if model.ExternalId != idstr { - diff, err := Update(model, func() error { - model.ExternalId = idstr - return nil - }) - if err == nil { - OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred) +func (manager *SStandaloneResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.StandaloneResourceDetails { + ret := make([]apis.StandaloneResourceDetails, len(objs)) + resIds := make([]string, len(objs)) + upperRet := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + ret[i] = apis.StandaloneResourceDetails{ + ResourceBaseDetails: upperRet[i], } - return err + resIds[i] = GetObjectIdstr(objs[i].(IModel)) } + + if fields == nil || fields.Contains("__meta__") { + q := Metadata.Query("id", "key", "value") + metaKeyValues := make(map[string][]SMetadata) + err := FetchQueryObjectsByIds(q, "id", resIds, &metaKeyValues) + if err != nil { + log.Errorf("FetchQueryObjectsByIds metadata fail %s", err) + return ret + } + + for i := range objs { + if metaList, ok := metaKeyValues[resIds[i]]; ok { + ret[i].Metadata = metaList2Map(manager.GetIStandaloneModelManager(), userCred, metaList) + } + } + } + return ret +} + +func (manager *SStandaloneResourceBaseManager) GetMetadataHiddenKeys() []string { return nil } -*/ diff --git a/pkg/cloudcommon/db/statusbase.go b/pkg/cloudcommon/db/statusbase.go new file mode 100644 index 0000000000..d97b3f07fb --- /dev/null +++ b/pkg/cloudcommon/db/statusbase.go @@ -0,0 +1,120 @@ +// 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 db + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/logclient" +) + +type SStatusResourceBaseManager struct{} + +type SStatusResourceBase struct { + // 资源状态 + Status string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional" json:"status"` +} + +type IStatusBase interface { + IModel + SetStatusValue(status string) + GetStatusValue() string +} + +func (model *SStatusResourceBase) SetStatusValue(status string) { + model.Status = status +} + +func (model SStatusResourceBase) GetStatusValue() string { + return model.Status +} + +func statusBaseSetStatus(model IStatusBase, userCred mcclient.TokenCredential, status string, reason string) error { + if model.GetStatusValue() == status { + return nil + } + oldStatus := model.GetStatusValue() + _, err := Update(model, func() error { + model.SetStatusValue(status) + return nil + }) + if err != nil { + return errors.Wrap(err, "Update") + } + if userCred != nil { + notes := fmt.Sprintf("%s=>%s", oldStatus, status) + if len(reason) > 0 { + notes = fmt.Sprintf("%s: %s", notes, reason) + } + OpsLog.LogEvent(model, ACT_UPDATE_STATUS, notes, userCred) + logclient.AddSimpleActionLog(model, logclient.ACT_DISABLE, nil, userCred, true) + } + return nil +} + +func StatusBasePerformStatus(model IStatusBase, userCred mcclient.TokenCredential, input apis.PerformStatusInput) error { + if len(input.Status) == 0 { + return httperrors.NewMissingParameterError("status") + } + err := statusBaseSetStatus(model, userCred, input.Status, input.Reason) + if err != nil { + return errors.Wrap(err, "statusBaseSetStatus") + } + return nil +} + +func (model *SStatusResourceBase) IsInStatus(status ...string) bool { + return utils.IsInStringArray(model.Status, status) +} + +/*func (model *SStatusStandaloneResourceBase) AllowGetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return IsAllowGetSpec(rbacutils.ScopeSystem, userCred, model, "status") +}*/ + +func (model *SStatusResourceBase) GetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (apis.GetDetailsStatusOutput, error) { + ret := apis.GetDetailsStatusOutput{} + ret.Status = model.Status + return ret, nil +} + +func (manager *SStatusResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.StatusResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Status) > 0 { + q = q.In("status", query.Status) + } + return q, nil +} + +func (manager *SStatusResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.StatusResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + return q, nil +} diff --git a/pkg/cloudcommon/db/statusdomainresource.go b/pkg/cloudcommon/db/statusdomainresource.go new file mode 100644 index 0000000000..782b9ea733 --- /dev/null +++ b/pkg/cloudcommon/db/statusdomainresource.go @@ -0,0 +1,148 @@ +// 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 db + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SStatusDomainLevelResourceBase struct { + SDomainLevelResourceBase + SStatusResourceBase +} + +type SStatusDomainLevelResourceBaseManager struct { + SDomainLevelResourceBaseManager + SStatusResourceBaseManager +} + +func NewStatusDomainLevelResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SStatusDomainLevelResourceBaseManager { + return SStatusDomainLevelResourceBaseManager{ + SDomainLevelResourceBaseManager: NewDomainLevelResourceBaseManager(dt, tableName, keyword, keywordPlural), + } +} + +func (model *SStatusDomainLevelResourceBase) AllowGetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return model.IsOwner(userCred) || IsDomainAllowGetSpec(userCred, model, "status") +} + +func (self *SStatusDomainLevelResourceBase) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) bool { + return IsDomainAllowPerform(userCred, self, "status") +} + +func (self *SStatusDomainLevelResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { + err := StatusBasePerformStatus(self, userCred, input) + if err != nil { + return nil, errors.Wrap(err, "StatusBasePerformStatus") + } + return nil, nil +} + +func (model *SStatusDomainLevelResourceBase) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error { + return statusBaseSetStatus(model, userCred, status, reason) +} + +func (manager *SStatusDomainLevelResourceBaseManager) ValidateCreateData( + ctx context.Context, + userCred mcclient.TokenCredential, + ownerId mcclient.IIdentityProvider, + query jsonutils.JSONObject, + input apis.StatusDomainLevelResourceCreateInput, +) (apis.StatusDomainLevelResourceCreateInput, error) { + var err error + input.DomainLevelResourceCreateInput, err = manager.SDomainLevelResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.DomainLevelResourceCreateInput) + if err != nil { + return input, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ValidateCreateData") + } + return input, nil +} + +func (manager *SStatusDomainLevelResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.StatusDomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DomainLevelResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.ListItemFilter") + } + q, err = manager.SStatusResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SStatusDomainLevelResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.StatusDomainLevelResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SDomainLevelResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DomainLevelResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SDomainLevelResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SStatusResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SStatusDomainLevelResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SStatusDomainLevelResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.StatusDomainLevelResourceDetails { + rows := make([]apis.StatusDomainLevelResourceDetails, len(objs)) + domainRows := manager.SDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.StatusDomainLevelResourceDetails{ + DomainLevelResourceDetails: domainRows[i], + } + } + return rows +} + +func (model *SStatusDomainLevelResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.StatusDomainLevelResourceDetails, error) { + return apis.StatusDomainLevelResourceDetails{}, nil +} diff --git a/pkg/cloudcommon/db/statusstandalone.go b/pkg/cloudcommon/db/statusstandalone.go index 24b0c0892c..ff8bb1a00d 100644 --- a/pkg/cloudcommon/db/statusstandalone.go +++ b/pkg/cloudcommon/db/statusstandalone.go @@ -16,82 +16,51 @@ package db import ( "context" - "fmt" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SStatusStandaloneResourceBase struct { SStandaloneResourceBase - - // 资源状态 - Status string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional" json:"status"` + SStatusResourceBase } type SStatusStandaloneResourceBaseManager struct { SStandaloneResourceBaseManager + SStatusResourceBaseManager } func NewStatusStandaloneResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SStatusStandaloneResourceBaseManager { - return SStatusStandaloneResourceBaseManager{SStandaloneResourceBaseManager: NewStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural)} -} - -func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error { - if model.Status == status { - return nil + return SStatusStandaloneResourceBaseManager{ + SStandaloneResourceBaseManager: NewStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural), } - oldStatus := model.Status - _, err := Update(model, func() error { - model.Status = status - return nil - }) - if err != nil { - return err - } - if userCred != nil { - notes := fmt.Sprintf("%s=>%s", oldStatus, status) - if len(reason) > 0 { - notes = fmt.Sprintf("%s: %s", notes, reason) - } - OpsLog.LogEvent(model, ACT_UPDATE_STATUS, notes, userCred) - } - return nil -} - -func (model *SStatusStandaloneResourceBase) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return IsAllowPerform(rbacutils.ScopeSystem, userCred, model, "status") -} - -func (model *SStatusStandaloneResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - status, _ := data.GetString("status") - if len(status) == 0 { - return nil, httperrors.NewMissingParameterError("status") - } - reason, _ := data.GetString("reason") - err := model.SetStatus(userCred, status, reason) - return nil, err -} - -func (model *SStatusStandaloneResourceBase) IsInStatus(status ...string) bool { - return utils.IsInStringArray(model.Status, status) } func (model *SStatusStandaloneResourceBase) AllowGetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return IsAllowGetSpec(rbacutils.ScopeSystem, userCred, model, "status") + return IsAdminAllowGetSpec(userCred, model, "status") } -func (model *SStatusStandaloneResourceBase) GetDetailsStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - ret := jsonutils.NewDict() - ret.Add(jsonutils.NewString(model.Status), "status") - return ret, nil +func (self *SStatusStandaloneResourceBase) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) bool { + return IsAdminAllowPerform(userCred, self, "status") +} + +func (self *SStatusStandaloneResourceBase) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { + err := StatusBasePerformStatus(self, userCred, input) + if err != nil { + return nil, errors.Wrap(err, "StatusBasePerformStatus") + } + return nil, nil +} + +func (model *SStatusStandaloneResourceBase) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error { + return statusBaseSetStatus(model, userCred, status, reason) } func (manager *SStatusStandaloneResourceBaseManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input apis.StatusStandaloneResourceCreateInput) (apis.StatusStandaloneResourceCreateInput, error) { @@ -103,13 +72,66 @@ func (manager *SStatusStandaloneResourceBaseManager) ValidateCreateData(ctx cont return input, nil } -func (manager *SStatusStandaloneResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.StatusStandaloneResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SStatusStandaloneResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.StatusStandaloneResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - if len(query.Status) > 0 { - q = q.In("status", query.Status) + q, err = manager.SStatusResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SStatusStandaloneResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.StatusStandaloneResourceListInput) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SStatusResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SStatusStandaloneResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SStatusStandaloneResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.StatusStandaloneResourceDetails { + rows := make([]apis.StatusStandaloneResourceDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = apis.StatusStandaloneResourceDetails{ + StandaloneResourceDetails: stdRows[i], + } + } + return rows +} + +func (model *SStatusStandaloneResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.StatusStandaloneResourceDetails, error) { + return apis.StatusStandaloneResourceDetails{}, nil +} diff --git a/pkg/cloudcommon/db/tenantcache.go b/pkg/cloudcommon/db/tenantcache.go index c1f87f10ec..e52c916c49 100644 --- a/pkg/cloudcommon/db/tenantcache.go +++ b/pkg/cloudcommon/db/tenantcache.go @@ -49,6 +49,10 @@ func NewTenant(idStr string, name string, domainId string, domainName string) ST return STenant{SKeystoneCacheObject: NewKeystoneCacheObject(idStr, name, domainId, domainName)} } +func NewDomain(idStr, name string) STenant { + return NewTenant(idStr, name, identityapi.KeystoneDomainRoot, identityapi.KeystoneDomainRoot) +} + func (tenant *STenant) GetModelManager() IModelManager { return TenantCacheManager } @@ -96,12 +100,20 @@ func (manager *STenantCacheManager) updateTenantCache(userCred mcclient.TokenCre userCred.GetProjectDomainId(), userCred.GetProjectDomain()) } +func (manager *STenantCacheManager) GetTenantQuery(fields ...string) *sqlchemy.SQuery { + return manager.Query(fields...).NotEquals("domain_id", identityapi.KeystoneDomainRoot) +} + +func (manager *STenantCacheManager) GetDomainQuery(fields ...string) *sqlchemy.SQuery { + return manager.Query(fields...).Equals("domain_id", identityapi.KeystoneDomainRoot) +} + func (manager *STenantCacheManager) fetchTenant(ctx context.Context, idStr string, isDomain bool, noExpireCheck bool, filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) (*STenant, error) { - q := manager.Query() + var q *sqlchemy.SQuery if isDomain { - q = q.Equals("domain_id", identityapi.KeystoneDomainRoot) + q = manager.GetDomainQuery() } else { - q = q.NotEquals("domain_id", identityapi.KeystoneDomainRoot) + q = manager.GetTenantQuery() } q = filter(q) tobj, err := NewModelObject(manager) @@ -226,7 +238,7 @@ func (manager *STenantCacheManager) FetchDomainByName(ctx context.Context, idStr func (manager *STenantCacheManager) fetchDomainFromKeystone(ctx context.Context, idStr string) (*STenant, error) { if len(idStr) == 0 { - log.Debugf("fetch empty tenant!!!!\n%s", debug.Stack()) + log.Debugf("fetch empty domain!!!!\n%s", debug.Stack()) return nil, fmt.Errorf("Empty idStr") } s := auth.GetAdminSession(ctx, consts.GetRegion(), "v1") diff --git a/pkg/cloudcommon/db/virtualjointbase.go b/pkg/cloudcommon/db/virtualjointbase.go index ad64ca7ca5..3b9e1b5e54 100644 --- a/pkg/cloudcommon/db/virtualjointbase.go +++ b/pkg/cloudcommon/db/virtualjointbase.go @@ -22,8 +22,10 @@ import ( "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SVirtualJointResourceBase struct { @@ -118,3 +120,30 @@ func (manager *SVirtualJointResourceBaseManager) FilterByHiddenSystemAttributes( q = q.In(iManager.GetSlaveFieldName(), slaveQ.SubQuery()) return q } + +func (model *SVirtualJointResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (apis.VirtualJointResourceBaseDetails, error) { + return apis.VirtualJointResourceBaseDetails{}, nil +} + +func (manager *SVirtualJointResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.VirtualJointResourceBaseDetails { + ret := make([]apis.VirtualJointResourceBaseDetails, len(objs)) + upperRet := manager.SJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + ret[i] = apis.VirtualJointResourceBaseDetails{ + JointResourceBaseDetails: upperRet[i], + } + } + return ret +} diff --git a/pkg/cloudcommon/db/virtualresource.go b/pkg/cloudcommon/db/virtualresource.go index 38642c7eb4..2a94c470cb 100644 --- a/pkg/cloudcommon/db/virtualresource.go +++ b/pkg/cloudcommon/db/virtualresource.go @@ -27,7 +27,6 @@ import ( "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" - identityapi "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/policy" @@ -38,21 +37,16 @@ import ( "yunion.io/x/onecloud/pkg/util/stringutils2" ) -type TProjectSource string - -const ( - PROJECT_SOURCE_LOCAL = TProjectSource("local") - PROJECT_SOURCE_CLOUD = TProjectSource("cloud") -) - type SVirtualResourceBaseManager struct { SStatusStandaloneResourceBaseManager SProjectizedResourceBaseManager } func NewVirtualResourceBaseManager(dt interface{}, tableName string, keyword string, keywordPlural string) SVirtualResourceBaseManager { - return SVirtualResourceBaseManager{SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt, - tableName, keyword, keywordPlural)} + return SVirtualResourceBaseManager{ + SStatusStandaloneResourceBaseManager: NewStatusStandaloneResourceBaseManager(dt, + tableName, keyword, keywordPlural), + } } type SVirtualResourceBase struct { @@ -189,8 +183,8 @@ func (model *SVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred } else { model.IsSystem = false } - model.ProjectSrc = string(PROJECT_SOURCE_LOCAL) - return model.SStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) + model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) + return model.SStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) } func (manager *SVirtualResourceBaseManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -209,63 +203,25 @@ func (manager *SVirtualResourceBaseManager) AllowCreateItem(ctx context.Context, return true } -func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - if len(fields) == 0 || fields.Contains("tenant") || fields.Contains("project_domain") { - projectIds := stringutils2.SSortedStrings{} - for i := range objs { - idStr := objs[i].GetOwnerId().GetProjectId() - projectIds = stringutils2.Append(projectIds, idStr) - } - projects := FetchProjects(projectIds, false) - if projects != nil { - for i := range rows { - idStr := objs[i].GetOwnerId().GetProjectId() - if proj, ok := projects[idStr]; ok { - if len(fields) == 0 || fields.Contains("project_domain") { - rows[i].Add(jsonutils.NewString(proj.Domain), "project_domain") - } - if len(fields) == 0 || fields.Contains("tenant") { - rows[i].Add(jsonutils.NewString(proj.Name), "tenant") - } - } - - } - } - } - return rows +func (model *SVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.VirtualResourceDetails, error) { + return apis.VirtualResourceDetails{}, nil } -func FetchProjects(projectIds []string, isDomain bool) map[string]STenant { - deadline := time.Now().UTC().Add(-consts.GetTenantCacheExpireSeconds()) - q := TenantCacheManager.Query().In("id", projectIds).GT("last_check", deadline) - if isDomain { - q = q.Equals("domain_id", identityapi.KeystoneDomainRoot) - } else { - q = q.NotEquals("domain_id", identityapi.KeystoneDomainRoot) - } - projects := make([]STenant, 0) - err := FetchModelObjects(TenantCacheManager, q, &projects) - if err != nil { - return nil - } - ret := make(map[string]STenant) - for i := range projects { - ret[projects[i].Id] = projects[i] - } - ctx := context.Background() - for _, pid := range projectIds { - if _, ok := ret[pid]; !ok { - // not found - var t *STenant - if isDomain { - t, _ = TenantCacheManager.fetchDomainFromKeystone(ctx, pid) - } else { - t, _ = TenantCacheManager.fetchTenantFromKeystone(ctx, pid) - } - if t != nil { - ret[t.Id] = *t - } +func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []apis.VirtualResourceDetails { + ret := make([]apis.VirtualResourceDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range objs { + ret[i] = apis.VirtualResourceDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ProjectizedResourceInfo: projRows[i], } } return ret @@ -296,23 +252,14 @@ func (model *SVirtualResourceBase) GetTenantCache(ctx context.Context) (*STenant return TenantCacheManager.FetchTenantById(ctx, model.ProjectId) } -func (model *SVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.VirtualResourceDetails, error) { - var err error - out := apis.VirtualResourceDetails{} - out.StandaloneResourceDetails, err = model.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return out, nil -} - -func (model *SVirtualResourceBase) AllowPerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (model *SVirtualResourceBase) AllowPerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) bool { return IsAdminAllowPerform(userCred, model, "change-owner") } -func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { manager := model.GetModelManager() + data := jsonutils.Marshal(input) log.Debugf("SVirtualResourceBase change_owner %s %s %#v", query, data, manager) ownerId, err := manager.FetchOwnerId(ctx, data) if err != nil { @@ -324,7 +271,7 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC if ownerId.GetProjectId() == model.ProjectId { // do nothing Update(model, func() error { - model.ProjectSrc = string(PROJECT_SOURCE_LOCAL) + model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) return nil }) return nil, nil @@ -355,11 +302,11 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC _, err = Update(model, func() error { model.DomainId = ownerId.GetProjectDomainId() model.ProjectId = ownerId.GetProjectId() - model.ProjectSrc = string(PROJECT_SOURCE_LOCAL) + model.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) return nil }) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Update") } OpsLog.SyncOwner(model, former, userCred) @@ -485,9 +432,9 @@ func (model *SVirtualResourceBase) GetShortDesc(ctx context.Context) *jsonutils. } func (model *SVirtualResourceBase) SyncCloudProjectId(userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider) { - if model.ProjectSrc != string(PROJECT_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectId()) > 0 { + if model.ProjectSrc != string(apis.OWNER_SOURCE_LOCAL) && ownerId != nil && len(ownerId.GetProjectId()) > 0 { diff, _ := Update(model, func() error { - model.ProjectSrc = string(PROJECT_SOURCE_CLOUD) + model.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD) model.ProjectId = ownerId.GetProjectId() model.DomainId = ownerId.GetProjectDomainId() return nil @@ -508,46 +455,43 @@ func (model *SVirtualResourceBase) GetPendingDeletedAt() time.Time { return model.PendingDeletedAt } -func (manager *SVirtualResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query) +func (manager *SVirtualResourceBaseManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.VirtualResourceListInput) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, err } - orderByTenant, _ := query.GetString("order_by_tenant") - if sqlchemy.SQL_ORDER_ASC.Equals(orderByTenant) || sqlchemy.SQL_ORDER_DESC.Equals(orderByTenant) { - tenantCaches := TenantCacheManager.Query().SubQuery() - q = q.LeftJoin(tenantCaches, sqlchemy.AND( - sqlchemy.Equals(q.Field("tenant_id"), tenantCaches.Field("id")), - sqlchemy.NotEquals(tenantCaches.Field("domain_id"), identityapi.KeystoneDomainRoot), - )) - if sqlchemy.SQL_ORDER_ASC.Equals(orderByTenant) { - q = q.Asc(tenantCaches.Field("name")) - } else { - q = q.Desc(tenantCaches.Field("name")) - } + q, err = manager.SProjectizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ProjectizedResourceListInput) + if err != nil { + return nil, err } - - orderByDomain, _ := query.GetString("order_by_domain") - if sqlchemy.SQL_ORDER_ASC.Equals(orderByDomain) || sqlchemy.SQL_ORDER_DESC.Equals(orderByDomain) { - tenantCaches := TenantCacheManager.Query().SubQuery() - q = q.LeftJoin(tenantCaches, sqlchemy.AND( - sqlchemy.Equals(q.Field("domain_id"), tenantCaches.Field("id")), - sqlchemy.Equals(tenantCaches.Field("domain_id"), identityapi.KeystoneDomainRoot), - )) - if sqlchemy.SQL_ORDER_ASC.Equals(orderByTenant) { - q = q.Asc(tenantCaches.Field("name")) - } else { - q = q.Desc(tenantCaches.Field("name")) - } - } - return q, nil } -func (manager *SVirtualResourceBaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query apis.VirtualResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SVirtualResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.VirtualResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { - return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + } + q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SVirtualResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} diff --git a/pkg/cloudcommon/policy/resources.go b/pkg/cloudcommon/policy/resources.go index 137e6b4c02..9f63225f04 100644 --- a/pkg/cloudcommon/policy/resources.go +++ b/pkg/cloudcommon/policy/resources.go @@ -23,7 +23,6 @@ var ( "storages", "wires", "globalvpcs", - "vpcs", "route_tables", "cloudregions", "serverskus", @@ -46,6 +45,8 @@ var ( "cloudaccounts", "cloudproviders", "recyclebins", + // migrate system resources to domain resources + "vpcs", } computeUserResources = []string{ "keypairs", diff --git a/pkg/cloudevent/models/cloudevents.go b/pkg/cloudevent/models/cloudevents.go index 7c7c48332a..8b21b55596 100644 --- a/pkg/cloudevent/models/cloudevents.go +++ b/pkg/cloudevent/models/cloudevents.go @@ -80,7 +80,12 @@ func (self *SCloudevent) AllowUpdateItem(ctx context.Context, userCred mcclient. } // 云平台操作日志列表 -func (manager *SCloudeventManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.CloudeventListInput) (*sqlchemy.SQuery, error) { +func (manager *SCloudeventManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.CloudeventListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SModelBaseManager.ListItemFilter(ctx, q, userCred, input.ModelBaseListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") diff --git a/pkg/cloudevent/models/cloudproviders.go b/pkg/cloudevent/models/cloudproviders.go index 2779d57b69..e93bbf6329 100644 --- a/pkg/cloudevent/models/cloudproviders.go +++ b/pkg/cloudevent/models/cloudproviders.go @@ -291,7 +291,7 @@ func (provider SCloudprovider) GetExternalId() string { } func (provider *SCloudprovider) GetProvider() (cloudprovider.ICloudProvider, error) { - if !provider.Enabled { + if !provider.GetEnabled() { return nil, errors.Error("Cloud provider is not enabled") } accessUrl := provider.getAccessUrl() diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index 3db1a67b4a..7a8f0e3ad8 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -316,7 +316,7 @@ func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context guestStatus, _ := task.GetParams().GetString("guest_status") overridePendingDelete := jsonutils.QueryBoolean(task.GetParams(), "override_pending_delete", false) purge := jsonutils.QueryBoolean(task.GetParams(), "purge", false) - if host != nil && host.Enabled && + if host != nil && host.GetEnabled() && (guestStatus == api.VM_RUNNING || strings.Index(guestStatus, "stop") >= 0) && options.Options.EnablePendingDelete && !guest.PendingDeleted && @@ -324,7 +324,7 @@ func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context !purge { return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, task.GetTaskId()) } - if host != nil && !host.Enabled && !purge { + if host != nil && !host.GetEnabled() && !purge { return fmt.Errorf("fail to contact baremetal") } task.ScheduleRun(nil) diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 794a6d128b..74b8a31cba 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -230,7 +230,7 @@ func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Conte if host == nil { host = guest.GetHost() } - if host != nil && host.Enabled && host.HostStatus == api.HOST_ONLINE { + if host != nil && host.GetEnabled() && host.HostStatus == api.HOST_ONLINE { return guest.StartGuestStopTask(ctx, task.GetUserCred(), true, task.GetTaskId()) } if host != nil && !jsonutils.QueryBoolean(task.GetParams(), "purge", false) { diff --git a/pkg/compute/hostdrivers/base.go b/pkg/compute/hostdrivers/base.go index a571bf0a8d..93815da22c 100644 --- a/pkg/compute/hostdrivers/base.go +++ b/pkg/compute/hostdrivers/base.go @@ -118,7 +118,7 @@ func (self *SBaseHostDriver) FinishUnconvert(ctx context.Context, userCred mccli } db.Update(host, func() error { host.AccessIp = adminNic.IpAddr - host.Enabled = true + host.SetEnabled(true) host.HostType = api.HOST_TYPE_BAREMETAL host.HostStatus = api.HOST_OFFLINE host.ManagerUri = "" @@ -156,7 +156,7 @@ func (self *SBaseHostDriver) FinishConvert(userCred mcclient.TokenCredential, ho host.CpuReserved = 0 host.MemReserved = 0 host.AccessIp = guest.GetRealIPs()[0] - host.Enabled = false + host.SetEnabled(false) host.HostStatus = api.HOST_OFFLINE host.HostType = hostType host.IsBaremetal = true diff --git a/pkg/compute/models/baremetalagents.go b/pkg/compute/models/baremetalagents.go index 29a7b26727..ef44702dbe 100644 --- a/pkg/compute/models/baremetalagents.go +++ b/pkg/compute/models/baremetalagents.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" "yunion.io/x/sqlchemy" @@ -29,19 +30,22 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SBaremetalagentManager struct { db.SStandaloneResourceBaseManager + SZoneResourceBaseManager } type SBaremetalagent struct { db.SStandaloneResourceBase + SZoneResourceBase Status string `width:"36" charset:"ascii" nullable:"false" default:"disable" list:"user" create:"optional"` AccessIp string `width:"16" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` ManagerUri string `width:"256" charset:"ascii" nullable:"true" list:"admin" update:"admin" create:"admin_required"` - ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` + // ZoneId string `width:"128" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` AgentType string `width:"32" charset:"ascii" nullable:"true" default:"baremetal" list:"admin" update:"admin" create:"admin_optional"` @@ -62,26 +66,6 @@ func init() { BaremetalagentManager.SetVirtualObject(BaremetalagentManager) } -func (self *SBaremetalagentManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SBaremetalagentManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SBaremetalagent) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SBaremetalagent) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SBaremetalagent) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SBaremetalagent) ValidateDeleteCondition(ctx context.Context) error { if self.Status == api.BAREMETAL_AGENT_ENABLED { return fmt.Errorf("Cannot delete in status %s", self.Status) @@ -200,22 +184,28 @@ func (self *SBaremetalagent) GetZone() *SZone { return nil } -func (self *SBaremetalagent) getMoreDetails(ctx context.Context, out api.BaremetalagentDetails) api.BaremetalagentDetails { - zone := self.GetZone() - if zone != nil { - out.Zone = zone.GetName() - } - return out +func (self *SBaremetalagent) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.BaremetalagentDetails, error) { + return api.BaremetalagentDetails{}, nil } -func (self *SBaremetalagent) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.BaremetalagentDetails, error) { - var err error - out := api.BaremetalagentDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SBaremetalagentManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.BaremetalagentDetails { + rows := make([]api.BaremetalagentDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.BaremetalagentDetails{ + StandaloneResourceDetails: stdRows[i], + ZoneResourceInfo: zoneRows[i], + } } - return self.getMoreDetails(ctx, out), nil + return rows } func (manager *SBaremetalagentManager) GetAgent(agentType api.TAgentType, zoneId string) *SBaremetalagent { @@ -274,6 +264,48 @@ func (agent *SBaremetalagent) setStoragecacheId(cacheId string) error { } // 管理代理服务列表 -func (manager *SBaremetalagentManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.BaremetalagentListInput) (*sqlchemy.SQuery, error) { - return manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (manager *SBaremetalagentManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.BaremetalagentListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + } + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SBaremetalagentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SBaremetalagentManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.BaremetalagentListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + return q, nil } diff --git a/pkg/compute/models/billingresource.go b/pkg/compute/models/billingresource.go index 6bb5862d01..75144fd254 100644 --- a/pkg/compute/models/billingresource.go +++ b/pkg/compute/models/billingresource.go @@ -15,22 +15,29 @@ package models import ( + "context" "time" + "yunion.io/x/jsonutils" + "yunion.io/x/sqlchemy" + api "yunion.io/x/onecloud/pkg/apis/billing" - "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SBillingResourceBase struct { // 计费类型, 按量、包年包月 // example: postpaid - BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional"` + BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional" json:"billing_type"` // 过期时间 - ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"` + ExpiredAt time.Time `nullable:"true" list:"user" create:"optional" json:"expired_at"` // 计费周期 - BillingCycle string `width:"10" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BillingCycle string `width:"10" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"billing_cycle"` } +type SBillingResourceBaseManager struct{} + func (self *SBillingResourceBase) GetChargeType() string { if len(self.BillingType) > 0 { return self.BillingType @@ -42,8 +49,8 @@ func (self *SBillingResourceBase) GetChargeType() string { func (self *SBillingResourceBase) getBillingBaseInfo() SBillingBaseInfo { info := SBillingBaseInfo{} info.ChargeType = self.GetChargeType() + info.ExpiredAt = self.ExpiredAt if self.GetChargeType() == api.BILLING_TYPE_PREPAID { - info.ExpiredAt = self.ExpiredAt info.BillingCycle = self.BillingCycle } return info @@ -76,10 +83,70 @@ type SBillingBaseInfo struct { } type SCloudBillingInfo struct { - compute.CloudproviderInfo + SCloudProviderInfo SBillingBaseInfo PriceKey string `json:",omitempty"` InternetChargeType string `json:",omitempty"` } + +func (self *SBillingResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) api.BillingDetailsInfo { + return api.BillingDetailsInfo{} +} + +func (manager *SBillingResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.BillingDetailsInfo { + rows := make([]api.BillingDetailsInfo, len(objs)) + for i := range rows { + rows[i] = api.BillingDetailsInfo{} + } + return rows +} + +func (manager *SBillingResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.BillingResourceListInput, +) (*sqlchemy.SQuery, error) { + if len(query.BillingType) > 0 { + if query.BillingType == api.BILLING_TYPE_POSTPAID { + q = q.Filter(sqlchemy.OR( + sqlchemy.IsNullOrEmpty(q.Field("billing_type")), + sqlchemy.Equals(q.Field("billing_type"), api.BILLING_TYPE_POSTPAID), + )) + } else { + q = q.Equals("billing_type", api.BILLING_TYPE_PREPAID) + } + } + if !query.BillingExpireBefore.IsZero() { + q = q.LT("expired_at", query.BillingExpireBefore) + } + if !query.BillingExpireSince.IsZero() { + q = q.GE("expired_at", query.BillingExpireBefore) + } + if len(query.BillingCycle) > 0 { + q = q.Equals("billing_cycle", query.BillingCycle) + } + return q, nil +} + +func (manager *SBillingResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.BillingResourceListInput, +) (*sqlchemy.SQuery, error) { + return q, nil +} diff --git a/pkg/compute/models/buckets.go b/pkg/compute/models/buckets.go index 55ba42284b..b78688e31b 100644 --- a/pkg/compute/models/buckets.go +++ b/pkg/compute/models/buckets.go @@ -45,10 +45,13 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SBucketManager struct { db.SVirtualResourceBaseManager + SCloudregionResourceBaseManager + SManagedResourceBaseManager } var BucketManager *SBucketManager @@ -68,10 +71,10 @@ func init() { type SBucket struct { db.SVirtualResourceBase db.SExternalizedResourceBase - + SCloudregionResourceBase SManagedResourceBase - CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + // CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` StorageClass string `width:"36" charset:"ascii" nullable:"false" list:"user"` Location string `width:"36" charset:"ascii" nullable:"false" list:"user"` @@ -519,13 +522,30 @@ func (bucket *SBucket) RemoteCreate(ctx context.Context, userCred mcclient.Token } func (bucket *SBucket) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.BucketDetails, error) { - var err error - out := api.BucketDetails{} - out.VirtualResourceDetails, err = bucket.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.BucketDetails{}, nil +} + +func (manager *SBucketManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.BucketDetails { + rows := make([]api.BucketDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.BucketDetails{ + VirtualResourceDetails: virtRows[i], + ManagedResourceInfo: managerRows[i], + CloudregionResourceInfo: regionRows[i], + } + rows[i] = objs[i].(*SBucket).getMoreDetails(rows[i]) } - return bucket.getMoreDetails(out), nil + return rows } func joinPath(ep, path string) string { @@ -533,8 +553,6 @@ func joinPath(ep, path string) string { } func (bucket *SBucket) getMoreDetails(out api.BucketDetails) api.BucketDetails { - out.CloudproviderInfo = bucket.getCloudProviderInfo() - s3gwUrl, _ := auth.GetServiceURL("s3gateway", options.Options.Region, "", "public") if len(s3gwUrl) > 0 { accessUrls := make([]cloudprovider.SBucketAccessUrl, 0) @@ -563,7 +581,7 @@ func (bucket *SBucket) getMoreDetails(out api.BucketDetails) api.BucketDetails { return out } -func (bucket *SBucket) getCloudProviderInfo() api.CloudproviderInfo { +func (bucket *SBucket) getCloudProviderInfo() SCloudProviderInfo { region, _ := bucket.GetRegion() provider := bucket.GetCloudprovider() return MakeCloudProviderInfo(region, nil, provider) @@ -573,14 +591,14 @@ func (bucket *SBucket) getCloudProviderInfo() api.CloudproviderInfo { func (manager *SBucketManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.BucketListInput) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) @@ -597,17 +615,35 @@ func (manager *SBucketManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field if err == nil { return q, nil } - switch field { - case "account": - cloudproviders := CloudproviderManager.Query().SubQuery() - cloudaccounts := CloudaccountManager.Query("name", "id").Distinct().SubQuery() - q = q.Join(cloudproviders, sqlchemy.Equals(q.Field("manager_id"), cloudproviders.Field("id"))) - q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id"))) - q.GroupBy(cloudaccounts.Field("name")) - q.AppendField(cloudaccounts.Field("name", "account")) - default: - return q, httperrors.NewBadRequestError("unsupport field %s", field) + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SBucketManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.BucketListInput) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil } diff --git a/pkg/compute/models/cachedimages.go b/pkg/compute/models/cachedimages.go index c059db9852..77decc1b26 100644 --- a/pkg/compute/models/cachedimages.go +++ b/pkg/compute/models/cachedimages.go @@ -36,6 +36,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCachedimageManager struct { @@ -85,26 +86,6 @@ type SCachedimage struct { ImageType string `width:"16" default:"customized" list:"user"` } -func (self *SCachedimageManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SCachedimageManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SCachedimage) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SCachedimage) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SCachedimage) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SCachedimage) ValidateDeleteCondition(ctx context.Context) error { cnt, err := self.getStoragecacheCount() if err != nil { @@ -163,6 +144,21 @@ func (self *SCachedimage) GetOSType() string { return osType } +func (self *SCachedimage) GetOSDistribution() string { + osType, _ := self.Info.GetString("properties", "os_distribution") + return osType +} + +func (self *SCachedimage) GetOSVersion() string { + osType, _ := self.Info.GetString("properties", "os_version") + return osType +} + +func (self *SCachedimage) GetHypervisor() string { + osType, _ := self.Info.GetString("properties", "hypervisor") + return osType +} + func (self *SCachedimage) getStoragecacheQuery() *sqlchemy.SQuery { q := StoragecachedimageManager.Query().Equals("cachedimage_id", self.Id) return q @@ -307,23 +303,32 @@ func (manager *SCachedimageManager) getImageInfo(ctx context.Context, userCred m } func (self *SCachedimage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CachedimageDetails, error) { - var err error - out := api.CachedimageDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return self.getMoreDetails(out), nil + return api.CachedimageDetails{}, nil } -func (self *SCachedimage) getMoreDetails(out api.CachedimageDetails) api.CachedimageDetails { - out.Status = self.GetStatus() - properties, _ := self.Info.Get("properties") - if properties != nil { - jsonutils.Update(&out, properties) +func (manager *SCachedimageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CachedimageDetails { + rows := make([]api.CachedimageDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + ci := objs[i].(*SCachedimage) + rows[i] = api.CachedimageDetails{ + StandaloneResourceDetails: stdRows[i], + Status: ci.GetStatus(), + OsType: ci.GetOSType(), + OsDistribution: ci.GetOSDistribution(), + OsVersion: ci.GetOSVersion(), + Hypervisor: ci.GetHypervisor(), + } + rows[i].CachedCount, _ = ci.getStoragecacheCount() } - out.CachedCount, _ = self.getStoragecacheCount() - return out + return rows } func (self *SCachedimage) AllowPerformRefresh(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -610,7 +615,12 @@ func (image *SCachedimage) GetCloudprovider() (*SCloudprovider, error) { } // 缓存镜像列表 -func (manager *SCachedimageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CachedimageListInput) (*sqlchemy.SQuery, error) { +func (manager *SCachedimageManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedimageListInput, +) (*sqlchemy.SQuery, error) { var err error q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "id", func() *sqlchemy.SQuery { @@ -666,3 +676,30 @@ func (manager *SCachedimageManager) ListItemFilter(ctx context.Context, q *sqlch return q, nil } + +func (manager *SCachedimageManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedimageListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SCachedimageManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index 621085f011..d5f519eea7 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -52,15 +53,14 @@ import ( ) type SCloudaccountManager struct { - db.SEnabledStatusStandaloneResourceBaseManager - db.SDomainizedResourceBaseManager + db.SEnabledStatusDomainLevelResourceBaseManager } var CloudaccountManager *SCloudaccountManager func init() { CloudaccountManager = &SCloudaccountManager{ - SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager( + SEnabledStatusDomainLevelResourceBaseManager: db.NewEnabledStatusDomainLevelResourceBaseManager( SCloudaccount{}, "cloudaccounts_tbl", "cloudaccount", @@ -71,8 +71,8 @@ func init() { } type SCloudaccount struct { - db.SEnabledStatusStandaloneResourceBase - db.SDomainizedResourceBase + db.SEnabledStatusDomainLevelResourceBase + SSyncableBaseResource // 上此同步时间 @@ -150,32 +150,12 @@ type SCloudaccount struct { ShareMode string `width:"32" charset:"ascii" nullable:"true" list:"domain"` } -func (self *SCloudaccountManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SCloudaccountManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SCloudaccount) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SCloudaccount) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SCloudaccount) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SCloudaccount) GetCloudproviders() []SCloudprovider { return self.getCloudprovidersInternal(tristate.None) } func (self *SCloudaccount) IsAvailable() bool { - if !self.Enabled { + if !self.GetEnabled() { return false } @@ -211,7 +191,7 @@ func (self *SCloudaccount) ValidateDeleteCondition(ctx context.Context) error { // if self.EnableAutoSync { // return httperrors.NewInvalidStatusError("automatic syncing is enabled") // } - if self.Enabled { + if self.GetEnabled() { return httperrors.NewInvalidStatusError("account is enabled") } if self.Status == api.CLOUD_PROVIDER_CONNECTED && self.getSyncStatus2() != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE { @@ -224,21 +204,21 @@ func (self *SCloudaccount) ValidateDeleteCondition(ctx context.Context) error { } } - return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx) + return self.SEnabledStatusDomainLevelResourceBase.ValidateDeleteCondition(ctx) } -func (self *SCloudaccount) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (self *SCloudaccount) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { if strings.Index(self.Status, "delet") >= 0 { return nil, httperrors.NewInvalidStatusError("Cannot enable deleting account") } - _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, data) + _, err := self.SEnabledStatusDomainLevelResourceBase.PerformEnable(ctx, userCred, query, input) if err != nil { return nil, err } cloudproviders := self.GetCloudproviders() for i := 0; i < len(cloudproviders); i++ { - if !cloudproviders[i].Enabled { - _, err := cloudproviders[i].PerformEnable(ctx, userCred, query, data) + if !cloudproviders[i].GetEnabled() { + _, err := cloudproviders[i].PerformEnable(ctx, userCred, query, input) if err != nil { return nil, err } @@ -247,15 +227,15 @@ func (self *SCloudaccount) PerformEnable(ctx context.Context, userCred mcclient. return nil, nil } -func (self *SCloudaccount) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, data) +func (self *SCloudaccount) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + _, err := self.SEnabledStatusDomainLevelResourceBase.PerformDisable(ctx, userCred, query, input) if err != nil { return nil, err } cloudproviders := self.GetCloudproviders() for i := 0; i < len(cloudproviders); i++ { - if cloudproviders[i].Enabled { - _, err := cloudproviders[i].PerformDisable(ctx, userCred, query, data) + if cloudproviders[i].GetEnabled() { + _, err := cloudproviders[i].PerformDisable(ctx, userCred, query, input) if err != nil { return nil, err } @@ -301,7 +281,7 @@ func (self *SCloudaccount) ValidateUpdateData(ctx context.Context, userCred mccl } data.Set("options", optionsJson) } - return self.SEnabledStatusStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) + return self.SEnabledStatusDomainLevelResourceBase.ValidateUpdateData(ctx, userCred, query, data) } func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.CloudaccountCreateInput) (api.CloudaccountCreateInput, error) { @@ -399,7 +379,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use } } - input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput) + input.EnabledStatusDomainLevelResourceCreateInput, err = manager.SEnabledStatusDomainLevelResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusDomainLevelResourceCreateInput) if err != nil { return input, err } @@ -408,18 +388,18 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use } func (self *SCloudaccount) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { - self.Enabled = true + self.SetEnabled(true) if len(self.Brand) == 0 { self.Brand = self.Provider } self.DomainId = ownerId.GetProjectDomainId() // self.EnableAutoSync = false self.ShareMode = api.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN - return self.SEnabledStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) + return self.SEnabledStatusDomainLevelResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) } func (self *SCloudaccount) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { - self.SEnabledStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + self.SEnabledStatusDomainLevelResourceBase.PostCreate(ctx, userCred, ownerId, query, data) self.savePassword(self.Secret) // if !self.EnableAutoSync { @@ -449,7 +429,7 @@ func (self *SCloudaccount) AllowPerformSync(ctx context.Context, userCred mcclie } func (self *SCloudaccount) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Account disabled") } if self.EnableAutoSync { @@ -474,7 +454,7 @@ func (self *SCloudaccount) AllowPerformUpdateCredential(ctx context.Context, use } func (self *SCloudaccount) PerformUpdateCredential(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Account disabled") } @@ -593,7 +573,7 @@ func (self *SCloudaccount) markStartSync(userCred mcclient.TokenCredential) erro } providers := self.GetCloudproviders() for i := range providers { - if providers[i].Enabled { + if providers[i].GetEnabled() { err := providers[i].markStartingSync(userCred) if err != nil { return errors.Wrap(err, "providers.markStartSync") @@ -658,7 +638,7 @@ func (self *SCloudaccount) GetProviderFactory() (cloudprovider.ICloudProviderFac } func (self *SCloudaccount) GetProvider() (cloudprovider.ICloudProvider, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, fmt.Errorf("Cloud provider is not enabled") } return self.getProviderInternal() @@ -721,7 +701,7 @@ func (self *SCloudaccount) importSubAccount(ctx context.Context, userCred mcclie newCloudprovider.CloudaccountId = self.Id newCloudprovider.Provider = self.Provider newCloudprovider.AccessUrl = self.AccessUrl - newCloudprovider.Enabled = true + newCloudprovider.SetEnabled(true) newCloudprovider.Status = api.CLOUD_PROVIDER_CONNECTED if !options.Options.CloudaccountHealthStatusCheck { self.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL @@ -849,7 +829,10 @@ func (self *SCloudaccount) GetEipCount() (int, error) { func (self *SCloudaccount) GetRoutetableCount() (int, error) { subq := CloudproviderManager.Query("id").Equals("cloudaccount_id", self.Id).SubQuery() - q := RouteTableManager.Query().In("manager_id", subq) + vpcs := VpcManager.Query("id", "manager_id").SubQuery() + q := RouteTableManager.Query() + q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id"))) + q = q.Filter(sqlchemy.In(vpcs.Field("manager_id"), subq)) return q.CountWithError() } @@ -898,6 +881,10 @@ func (self *SCloudaccount) GetCloudEnv() string { } } +func (self *SCloudaccount) GetEnvironment() string { + return self.AccessUrl +} + func (self *SCloudaccount) getMoreDetails(out api.CloudaccountDetail) api.CloudaccountDetail { out.EipCount, _ = self.GetEipCount() out.VpcCount, _ = self.GetVpcCount() @@ -931,13 +918,26 @@ func (self *SCloudaccount) getMoreDetails(out api.CloudaccountDetail) api.Clouda } func (self *SCloudaccount) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CloudaccountDetail, error) { - var err error - out := api.CloudaccountDetail{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.CloudaccountDetail{}, nil +} + +func (manager *SCloudaccountManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CloudaccountDetail { + rows := make([]api.CloudaccountDetail, len(objs)) + stdRows := manager.SEnabledStatusDomainLevelResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.CloudaccountDetail{ + EnabledStatusDomainLevelResourceDetails: stdRows[i], + } + rows[i] = objs[i].(*SCloudaccount).getMoreDetails(rows[i]) } - return self.getMoreDetails(out), nil + return rows } func migrateCloudprovider(cloudprovider *SCloudprovider) error { @@ -1171,7 +1171,12 @@ func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mc } // 云账号列表 -func (manager *SCloudaccountManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudaccountListInput) (*sqlchemy.SQuery, error) { +func (manager *SCloudaccountManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CloudaccountListInput, +) (*sqlchemy.SQuery, error) { accountStr := query.Cloudaccount if len(accountStr) > 0 { accountObj, err := manager.FetchByIdOrName(userCred, accountStr) @@ -1185,9 +1190,9 @@ func (manager *SCloudaccountManager) ListItemFilter(ctx context.Context, q *sqlc q = q.Equals("id", accountObj.GetId()) } - q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusDomainLevelResourceListInput) if err != nil { - return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager") + return nil, errors.Wrap(err, "SEnabledStatusDomainLevelResourceBaseManager") } managerStr := query.Cloudprovider if len(managerStr) > 0 { @@ -1229,6 +1234,32 @@ func (manager *SCloudaccountManager) ListItemFilter(ctx context.Context, q *sqlc return q, nil } +func (manager *SCloudaccountManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "account": + q = q.AppendField(q.Field("name").Label("account")).Distinct() + return q, nil + } + q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SCloudaccountManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CloudaccountListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusDomainLevelResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusDomainLevelResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusDomainLevelResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + func (self *SCloudaccount) AllowPerformEnableAutoSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowPerform(userCred, self, "enable-auto-sync") } @@ -1394,7 +1425,7 @@ func (manager *SCloudaccountManager) AutoSyncCloudaccountTask(ctx context.Contex } for i := range accounts { - if accounts[i].Enabled && accounts[i].shouldProbeStatus() && accounts[i].needSync() && accounts[i].CanSync() && rand.Float32() < 0.6 { + if accounts[i].GetEnabled() && accounts[i].shouldProbeStatus() && accounts[i].needSync() && accounts[i].CanSync() && rand.Float32() < 0.6 { accounts[i].SubmitSyncAccountTask(ctx, userCred, nil, true) } } @@ -1487,7 +1518,7 @@ func (account *SCloudaccount) syncAccountStatus(ctx context.Context, userCred mc account.markAccountConnected(ctx, userCred) providers := account.importAllSubaccounts(ctx, userCred, subaccounts) for i := range providers { - if providers[i].Enabled { + if providers[i].GetEnabled() { _, err := providers[i].prepareCloudproviderRegions(ctx, userCred) if err != nil { log.Errorf("syncCloudproviderRegion fail %s", err) @@ -1521,7 +1552,7 @@ func (account *SCloudaccount) SubmitSyncAccountTask(ctx context.Context, userCre waitChan <- err } else { syncCnt := 0 - if err == nil && autoSync && account.Enabled && account.EnableAutoSync { + if err == nil && autoSync && account.GetEnabled() && account.EnableAutoSync { syncRange := SSyncRange{FullSync: true} account.markAutoSync(userCred) providers := account.GetEnabledCloudproviders() @@ -1552,7 +1583,7 @@ func (self *SCloudaccount) Delete(ctx context.Context, userCred mcclient.TokenCr func (self *SCloudaccount) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error { self.SetStatus(userCred, api.CLOUD_PROVIDER_DELETED, "real delete") - return self.SEnabledStatusStandaloneResourceBase.Delete(ctx, userCred) + return self.SEnabledStatusDomainLevelResourceBase.Delete(ctx, userCred) } func (self *SCloudaccount) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { @@ -1591,27 +1622,6 @@ func (self *SCloudaccount) getSyncStatus2() string { } } -func (manager *SCloudaccountManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - if len(fields) == 0 || fields.Contains("domain") { - domainIds := stringutils2.SSortedStrings{} - for i := range objs { - idStr := objs[i].GetOwnerId().GetProjectDomainId() - domainIds = stringutils2.Append(domainIds, idStr) - } - domains := db.FetchProjects(domainIds, true) - if domains != nil { - for i := range rows { - idStr := objs[i].GetOwnerId().GetProjectDomainId() - if domain, ok := domains[idStr]; ok { - rows[i].Add(jsonutils.NewString(domain.Name), "domain") - } - } - } - } - return rows -} - func (account *SCloudaccount) setShareMode(userCred mcclient.TokenCredential, mode string) error { if account.ShareMode == mode { return nil @@ -1781,7 +1791,7 @@ func (account *SCloudaccount) AllowPerformSyncSkus(ctx context.Context, userCred } func (account *SCloudaccount) PerformSyncSkus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !account.Enabled { + if !account.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Account disabled") } diff --git a/pkg/compute/models/cloudproviderregions.go b/pkg/compute/models/cloudproviderregions.go index d44cf68f24..19bd719f8d 100644 --- a/pkg/compute/models/cloudproviderregions.go +++ b/pkg/compute/models/cloudproviderregions.go @@ -118,7 +118,7 @@ func (self *SCloudproviderregion) GetRegion() *SCloudregion { func (self *SCloudproviderregion) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CloudproviderregionDetails, error) { var err error out := api.CloudproviderregionDetails{} - out.ModelBaseDetails, err = self.SJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) + out.JointResourceBaseDetails, err = self.SJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) if err != nil { return out, err } @@ -140,7 +140,7 @@ func (self *SCloudproviderregion) getExtraDetails(out api.CloudproviderregionDet out.Cloudaccount = account.Name out.CloudaccountDomainId = account.DomainId out.EnableAutoSync = false - if account.Enabled && account.EnableAutoSync { + if account.GetEnabled() && account.EnableAutoSync { out.EnableAutoSync = true } out.SyncIntervalSeconds = self.getSyncIntervalSeconds(account) diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 45a979aa07..3b2aa3934d 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -92,7 +93,8 @@ type SCloudprovider struct { Account string `width:"128" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` // 云账号的密码信息,例如密码,access key secret等。该字段在数据库加密存储。Google需要存储秘钥证书,需要此字段比较长 Secret string `length:"0" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"` - // 该云账号在云平台的唯一账号ID + + // 归属云账号ID CloudaccountId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` // ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"true" list:"domain"` @@ -103,33 +105,13 @@ type SCloudprovider struct { Provider string `width:"64" charset:"ascii" list:"domain" create:"domain_required"` } -func (self *SCloudproviderManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SCloudproviderManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SCloudprovider) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SCloudprovider) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SCloudprovider) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SCloudprovider) ValidateDeleteCondition(ctx context.Context) error { // allow delete cloudprovider if it is disabled // account := self.GetCloudaccount() // if account != nil && account.EnableAutoSync { // return httperrors.NewInvalidStatusError("auto syncing is enabled on account") // } - if self.Enabled { + if self.GetEnabled() { return httperrors.NewInvalidStatusError("provider is enabled") } if self.SyncStatus != api.CLOUD_PROVIDER_SYNC_STATUS_IDLE { @@ -515,11 +497,11 @@ func (self *SCloudprovider) AllowPerformSync(ctx context.Context, userCred mccli } func (self *SCloudprovider) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cloudprovider disabled") } account := self.GetCloudaccount() - if !account.Enabled { + if !account.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cloudaccount disabled") } if account.EnableAutoSync { @@ -742,7 +724,7 @@ func (self *SCloudprovider) GetProviderFactory() (cloudprovider.ICloudProviderFa } func (self *SCloudprovider) GetProvider() (cloudprovider.ICloudProvider, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, errors.Wrap(httperrors.ErrInvalidStatus, "Cloud provider is not enabled") } @@ -791,14 +773,14 @@ func (manager *SCloudproviderManager) IsProviderAccountEnabled(providerId string if providerObj == nil { return false } - if !providerObj.Enabled { + if !providerObj.GetEnabled() { return false } account := providerObj.GetCloudaccount() if account == nil { return false } - return account.Enabled + return account.GetEnabled() } func (manager *SCloudproviderManager) FetchCloudproviderByIdOrName(providerId string) *SCloudprovider { @@ -812,52 +794,8 @@ func (manager *SCloudproviderManager) FetchCloudproviderByIdOrName(providerId st return providerObj.(*SCloudprovider) } -type SCloudproviderUsage struct { - GuestCount int - HostCount int - VpcCount int - StorageCount int - StorageCacheCount int - EipCount int - SnapshotCount int - LoadbalancerCount int - ProjectCount int - SyncRegionCount int -} - -func (usage *SCloudproviderUsage) isEmpty() bool { - if usage.HostCount > 0 { - return false - } - if usage.VpcCount > 0 { - return false - } - if usage.StorageCount > 0 { - return false - } - if usage.StorageCacheCount > 0 { - return false - } - if usage.EipCount > 0 { - return false - } - if usage.SnapshotCount > 0 { - return false - } - if usage.LoadbalancerCount > 0 { - return false - } - /*if usage.ProjectCount > 0 { - return false - } - if usage.SyncRegionCount > 0 { - return false - }*/ - return true -} - -func (self *SCloudprovider) getUsage() *SCloudproviderUsage { - usage := SCloudproviderUsage{} +func (self *SCloudprovider) getUsage() api.SCloudproviderUsage { + usage := api.SCloudproviderUsage{} usage.GuestCount, _ = self.GetGuestCount() usage.HostCount, _ = self.GetHostCount() @@ -870,7 +808,7 @@ func (self *SCloudprovider) getUsage() *SCloudproviderUsage { usage.ProjectCount, _ = self.getExternalProjectCount() usage.SyncRegionCount, _ = self.getSyncRegionCount() - return &usage + return usage } func (self *SCloudprovider) getProject(ctx context.Context) *db.STenant { @@ -878,30 +816,57 @@ func (self *SCloudprovider) getProject(ctx context.Context) *db.STenant { return proj } -func (self *SCloudprovider) getMoreDetails(ctx context.Context, out api.CloudproviderDetails) api.CloudproviderDetails { - jsonutils.Update(&out, self.getUsage()) - account := self.GetCloudaccount() - if account != nil { - // 此字段不能删除,公有云日志同步需要这个字段 - out.Brand = account.Brand - out.Cloudaccount = account.GetName() - } - out.SyncStatus2 = self.getSyncStatus2() - capabilities, _ := CloudproviderCapabilityManager.getCapabilities(self.Id) - if len(capabilities) > 0 { - out.Capabilities = capabilities - } - return out +func (self *SCloudprovider) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.CloudproviderDetails, error) { + return api.CloudproviderDetails{}, nil } -func (self *SCloudprovider) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CloudproviderDetails, error) { - var err error - out := api.CloudproviderDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SCloudproviderManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CloudproviderDetails { + rows := make([]api.CloudproviderDetails, len(objs)) + + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + accountIds := make([]string, len(objs)) + for i := range rows { + provider := objs[i].(*SCloudprovider) + rows[i] = api.CloudproviderDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + ProjectizedResourceInfo: projRows[i], + SCloudproviderUsage: provider.getUsage(), + SyncStatus2: provider.getSyncStatus2(), + } + capabilities, _ := CloudproviderCapabilityManager.getCapabilities(provider.Id) + if len(capabilities) > 0 { + rows[i].Capabilities = capabilities + } } - return self.getMoreDetails(ctx, out), nil + + accounts := make(map[string]SCloudaccount) + err := db.FetchStandaloneObjectsByIds(CloudaccountManager, accountIds, &accounts) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if account, ok := accounts[accountIds[i]]; ok { + rows[i].Cloudaccount = account.Name + rows[i].Brand = account.Brand + } + } + + return rows } func (manager *SCloudproviderManager) InitializeData() error { @@ -982,7 +947,12 @@ func (manager *SCloudproviderManager) migrateVCenterInfo(vc *SVCenter) error { } // 云订阅列表 -func (manager *SCloudproviderManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudproviderListInput) (*sqlchemy.SQuery, error) { +func (manager *SCloudproviderManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CloudproviderListInput, +) (*sqlchemy.SQuery, error) { accountStr := query.Cloudaccount if len(accountStr) > 0 { accountObj, err := CloudaccountManager.FetchByIdOrName(userCred, accountStr) @@ -1030,6 +1000,7 @@ func (manager *SCloudproviderManager) ListItemFilter(ctx context.Context, q *sql if err != nil { return nil, err } + managerStr := query.Cloudprovider if len(managerStr) > 0 { providerObj, err := manager.FetchByIdOrName(userCred, managerStr) @@ -1074,6 +1045,38 @@ func (manager *SCloudproviderManager) ListItemFilter(ctx context.Context, q *sql return q, nil } +func (manager *SCloudproviderManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CloudproviderListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SCloudproviderManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + if field == "manager" { + q = q.AppendField(q.Field("name").Label("manager")).Distinct() + return q, nil + } + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (provider *SCloudprovider) markProviderDisconnected(ctx context.Context, userCred mcclient.TokenCredential, reason string) error { _, err := db.UpdateWithLock(ctx, provider, func() error { provider.HealthStatus = api.CLOUD_PROVIDER_HEALTH_UNKNOWN @@ -1163,7 +1166,7 @@ func (provider *SCloudprovider) SyncCallSyncCloudproviderRegions(ctx context.Con } func (self *SCloudprovider) IsAvailable() bool { - if !self.Enabled { + if !self.GetEnabled() { return false } if !utils.IsInStringArray(self.Status, api.CLOUD_PROVIDER_VALID_STATUS) { @@ -1253,8 +1256,8 @@ func (self *SCloudprovider) ClearSchedDescCache() error { return nil } -func (self *SCloudprovider) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, data) +func (self *SCloudprovider) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input) if err != nil { return nil, err } @@ -1263,19 +1266,20 @@ func (self *SCloudprovider) PerformEnable(ctx context.Context, userCred mcclient allEnabled := true providers := account.GetCloudproviders() for i := range providers { - if !providers[i].Enabled { + if !providers[i].GetEnabled() { allEnabled = false + break } } - if allEnabled && !account.Enabled { - return account.PerformEnable(ctx, userCred, nil, nil) + if allEnabled && !account.GetEnabled() { + return account.PerformEnable(ctx, userCred, nil, input) } } return nil, nil } -func (self *SCloudprovider) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, data) +func (self *SCloudprovider) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input) if err != nil { return nil, err } @@ -1284,44 +1288,18 @@ func (self *SCloudprovider) PerformDisable(ctx context.Context, userCred mcclien allDisable := true providers := account.GetCloudproviders() for i := range providers { - if providers[i].Enabled { + if providers[i].GetEnabled() { allDisable = false + break } } - if allDisable && account.Enabled { - return account.PerformDisable(ctx, userCred, nil, nil) + if allDisable && account.GetEnabled() { + return account.PerformDisable(ctx, userCred, nil, input) } } return nil, nil } -func (manager *SCloudproviderManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - projectIds := stringutils2.SSortedStrings{} - for i := range objs { - idStr := objs[i].GetOwnerId().GetProjectId() - projectIds = stringutils2.Append(projectIds, idStr) - } - if len(fields) == 0 || fields.Contains("tenant") || fields.Contains("domain") { - projects := db.FetchProjects(projectIds, false) - if projects != nil { - for i := range rows { - idStr := objs[i].GetOwnerId().GetProjectId() - if proj, ok := projects[idStr]; ok { - if len(fields) == 0 || fields.Contains("domain") { - rows[i].Add(jsonutils.NewString(proj.Domain), "domain") - } - if len(fields) == 0 || fields.Contains("tenant") { - rows[i].Add(jsonutils.NewString(proj.Name), "tenant") - } - } - - } - } - } - return rows -} - func (manager *SCloudproviderManager) FilterByOwner(q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery { if owner != nil { switch scope { diff --git a/pkg/compute/models/cloudregionresource.go b/pkg/compute/models/cloudregionresource.go index d3f9c96c73..242cfe5c46 100644 --- a/pkg/compute/models/cloudregionresource.go +++ b/pkg/compute/models/cloudregionresource.go @@ -19,15 +19,23 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCloudregionResourceBase struct { - CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"default" create:"optional"` + // 归属区域ID + CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"default" create:"optional" json:"cloudregion_id"` } +type SCloudregionResourceBaseManager struct{} + func (self *SCloudregionResourceBase) GetRegion() *SCloudregion { region, err := CloudregionManager.FetchById(self.CloudregionId) if err != nil { @@ -37,11 +45,98 @@ func (self *SCloudregionResourceBase) GetRegion() *SCloudregion { return region.(*SCloudregion) } -func (self *SCloudregionResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.CloudregionInfo { - out := api.CloudregionInfo{} - region := self.GetRegion() - if region == nil { - return out +func (self *SCloudregionResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) api.CloudregionResourceInfo { + return api.CloudregionResourceInfo{} +} + +func (manager *SCloudregionResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CloudregionResourceInfo { + rows := make([]api.CloudregionResourceInfo, len(objs)) + regionIds := make([]string, len(objs)) + for i := range objs { + var base *SCloudregionResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.CloudregionId) > 0 { + regionIds[i] = base.CloudregionId + } } - return region.GetRegionInfo() + regions := make(map[string]SCloudregion) + err := db.FetchStandaloneObjectsByIds(CloudregionManager, regionIds, regions) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + for i := range rows { + if region, ok := regions[regionIds[i]]; ok { + rows[i] = region.GetRegionInfo() + } else { + rows[i] = api.CloudregionResourceInfo{} + } + } + return rows +} + +func (manager *SCloudregionResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionalFilterListInput, +) (*sqlchemy.SQuery, error) { + return managedResourceFilterByRegion(q, query, "", nil) +} + +func (manager *SCloudregionResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionalFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SCloudregionResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "region" { + regionQuery := CloudregionManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(regionQuery.Field("name", field)) + q = q.Join(regionQuery, sqlchemy.Equals(q.Field("cloudregion_id"), regionQuery.Field("id"))) + q.GroupBy(regionQuery.Field("name")) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SCloudregionResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionalFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + regionQ := CloudregionManager.Query("id", "name", "city") + var orders []string + var fields []sqlchemy.IQueryField + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := regionQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("cloudregion_id"), subq.Field("id"))) + orders = append(orders, query.OrderByRegion, query.OrderByCity) + fields = append(fields, subq.Field("name"), subq.Field("city")) + } + return q, orders, fields +} + +func (manager *SCloudregionResourceBaseManager) GetOrderByFields(query api.RegionalFilterListInput) []string { + return []string{query.OrderByRegion, query.OrderByCity} } diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index 308264ae92..21a30f2e15 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -33,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCloudregionManager struct { @@ -62,10 +64,10 @@ type SCloudregion struct { // 云环境 // example: ChinaCloud - Environment string `width:"32" charset:"ascii" list:"user"` + Environment string `width:"32" charset:"ascii" list:"user" json:"environment"` // 云平台 // example: Huawei - Provider string `width:"64" charset:"ascii" list:"user" nullable:"false" default:"OneCloud"` + Provider string `width:"64" charset:"ascii" list:"user" nullable:"false" default:"OneCloud" json:"provider"` } func (manager *SCloudregionManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -242,7 +244,8 @@ func (self *SCloudregion) GetDriver() IRegionDriver { return GetRegionDriver(provider) } -func (self *SCloudregion) getMoreDetails(out api.CloudregionDetails) api.CloudregionDetails { +func (self *SCloudregion) getUsage() api.SCloudregionUsage { + out := api.SCloudregionUsage{} out.VpcCount, _ = self.GetVpcCount() out.ZoneCount, _ = self.GetZoneCount() out.GuestCount, _ = self.GetGuestCount() @@ -252,13 +255,27 @@ func (self *SCloudregion) getMoreDetails(out api.CloudregionDetails) api.Cloudre } func (self *SCloudregion) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CloudregionDetails, error) { - var err error - out := api.CloudregionDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.CloudregionDetails{}, nil +} + +func (manager *SCloudregionManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CloudregionDetails { + rows := make([]api.CloudregionDetails, len(objs)) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + region := objs[i].(*SCloudregion) + rows[i] = api.CloudregionDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + SCloudregionUsage: region.getUsage(), + } } - return self.getMoreDetails(out), nil + return rows } func (self *SCloudregion) GetSkus() ([]SServerSku, error) { @@ -297,7 +314,7 @@ func (manager *SCloudregionManager) getCloudregionsByProviderId(providerId strin regions := []SCloudregion{} err := fetchByManagerId(manager, providerId, ®ions) if err != nil { - return nil, err + return nil, errors.Wrap(err, "fetchByManagerId") } return regions, nil } @@ -388,7 +405,7 @@ func (self *SCloudregion) syncRemoveCloudRegion(ctx context.Context, userCred mc err := self.SetStatus(userCred, api.CLOUD_REGION_STATUS_OUTOFSERVICE, "Out of sync") if err == nil { - _, err = self.PerformDisable(ctx, userCred, nil, nil) + _, err = self.PerformDisable(ctx, userCred, nil, apis.PerformDisableInput{}) } cpr := CloudproviderRegionManager.FetchByIds(cloudProvider.Id, self.Id) @@ -439,7 +456,7 @@ func (manager *SCloudregionManager) newFromCloudRegion(ctx context.Context, user region.Name = newName region.SGeographicInfo = cloudRegion.GetGeographicInfo() region.Status = cloudRegion.GetStatus() - region.Enabled = true + region.SetEnabled(true) region.Provider = cloudRegion.GetProvider() region.Environment = cloudRegion.GetCloudEnv() @@ -515,7 +532,7 @@ func (manager *SCloudregionManager) InitializeData() error { defRegion := SCloudregion{} defRegion.Id = api.DEFAULT_REGION_ID defRegion.Name = "Default" - defRegion.Enabled = true + defRegion.SetEnabled(true) defRegion.Description = "Default Region" defRegion.Status = api.CLOUD_REGION_STATUS_INSERVER defRegion.Provider = api.CLOUD_PROVIDER_ONECLOUD @@ -585,8 +602,33 @@ func queryCloudregionIdsByProviders(providerField string, providerStrs []string) return q } +func (manager *SCloudregionManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "region" { + q = q.AppendField(q.Field("name").Label("region")).Distinct() + return q, nil + } + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SCloudregionManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudregionListInput) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + // 云平台区域列表 -func (manager *SCloudregionManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CloudregionListInput) (*sqlchemy.SQuery, error) { +func (manager *SCloudregionManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CloudregionListInput, +) (*sqlchemy.SQuery, error) { providerStrs := query.Providers if len(providerStrs) > 0 { subq := queryCloudregionIdsByProviders("provider", providerStrs) @@ -724,9 +766,38 @@ func (self *SCloudregion) isManaged() bool { } } -func (self *SCloudregion) GetRegionInfo() api.CloudregionInfo { - return api.CloudregionInfo{ +func (self *SCloudregion) getCloudaccounts() []SCloudaccount { + providers := CloudproviderManager.Query().SubQuery() + providerregions := CloudproviderRegionManager.Query().SubQuery() + q := CloudaccountManager.Query() + q = q.Join(providers, sqlchemy.Equals(q.Field("id"), providers.Field("cloudaccount_id"))) + q = q.Join(providerregions, sqlchemy.Equals(providers.Field("id"), providerregions.Field("cloudprovider_id"))) + q = q.Filter(sqlchemy.Equals(providerregions.Field("cloudregion_id"), self.Id)) + q = q.Distinct() + + accounts := make([]SCloudaccount, 0) + err := db.FetchModelObjects(CloudaccountManager, q, &accounts) + if err != nil { + if errors.Cause(err) != sql.ErrNoRows { + log.Errorf("get cloudregion's cloudaccounts fail: %s", err) + } + return nil + } + return accounts +} + +func (self *SCloudregion) GetRegionCloudenvInfo() api.CloudenvResourceInfo { + info := api.CloudenvResourceInfo{ + Provider: self.Provider, + Environment: self.Environment, + } + return info +} + +func (self *SCloudregion) GetRegionInfo() api.CloudregionResourceInfo { + return api.CloudregionResourceInfo{ Region: self.Name, + Cloudregion: self.Name, RegionId: self.Id, RegionExtId: fetchExternalId(self.ExternalId), RegionExternalId: self.ExternalId, diff --git a/pkg/compute/models/dbinstance_accounts.go b/pkg/compute/models/dbinstance_accounts.go index 4b3e506de4..018babff6d 100644 --- a/pkg/compute/models/dbinstance_accounts.go +++ b/pkg/compute/models/dbinstance_accounts.go @@ -29,16 +29,17 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDBInstanceAccountManager struct { db.SStatusStandaloneResourceBaseManager + SDBInstanceResourceBaseManager } var DBInstanceAccountManager *SDBInstanceAccountManager @@ -59,10 +60,13 @@ type SDBInstanceAccount struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SDBInstanceResourceBase + // 数据库密码 Secret string `width:"256" charset:"ascii" nullable:"false" list:"domain" create:"optional"` + // RDS实例Id - DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` + // DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` } func (manager *SDBInstanceAccountManager) GetContextManagers() [][]db.IModelManager { @@ -160,25 +164,75 @@ func (self *SDBInstanceAccount) getMoreDetails(ctx context.Context, userCred mcc } func (self *SDBInstanceAccount) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DBInstanceAccountDetails, error) { - var err error - out := api.DBInstanceAccountDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.DBInstanceAccountDetails{}, nil +} + +func (manager *SDBInstanceAccountManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstanceAccountDetails { + rows := make([]api.DBInstanceAccountDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + dbRows := manager.SDBInstanceResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DBInstanceAccountDetails{ + StatusStandaloneResourceDetails: stdRows[i], + DBInstanceResourceInfo: dbRows[i], + } + rows[i], _ = objs[i].(*SDBInstanceAccount).getMoreDetails(ctx, userCred, rows[i]) } - return self.getMoreDetails(ctx, userCred, out) + return rows } // RDS账号列表 -func (manager *SDBInstanceAccountManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceAccountListInput) (*sqlchemy.SQuery, error) { +func (manager *SDBInstanceAccountManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceAccountListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "dbinstance", ModelKeyword: "dbinstance", OwnerId: userCred}, - }) + q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SDBInstanceAccountManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceAccountListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SDBInstanceResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SDBInstanceAccountManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SDBInstanceResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound } func (manager *SDBInstanceAccountManager) FetchParentId(ctx context.Context, data jsonutils.JSONObject) string { @@ -286,14 +340,6 @@ func (self *SDBInstanceAccount) StartDBInstanceAccountCreateTask(ctx context.Con return nil } -func (self *SDBInstanceAccount) GetDBInstance() (*SDBInstance, error) { - instance, err := DBInstanceManager.FetchById(self.DBInstanceId) - if err != nil { - return nil, err - } - return instance.(*SDBInstance), nil -} - func (self *SDBInstanceAccount) AllowPerformGrantPrivilege(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowPerform(userCred, self, "grant-privilege") } diff --git a/pkg/compute/models/dbinstance_backups.go b/pkg/compute/models/dbinstance_backups.go index 3e27f96510..ef6ceb29da 100644 --- a/pkg/compute/models/dbinstance_backups.go +++ b/pkg/compute/models/dbinstance_backups.go @@ -31,14 +31,17 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDBInstanceBackupManager struct { db.SVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager + SDBInstanceResourceBaseManager } var DBInstanceBackupManager *SDBInstanceBackupManager @@ -61,26 +64,29 @@ type SDBInstanceBackup struct { SManagedResourceBase db.SExternalizedResourceBase + SDBInstanceResourceBase + // RDS引擎 // example: MySQL - Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` + Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine"` // RDS引擎版本 // example: 5.7 - EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` + EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine_version"` // 备份开始时间 - StartTime time.Time `list:"user"` + StartTime time.Time `list:"user" json:"start_time"` // 备份结束时间 - EndTime time.Time `list:"user"` + EndTime time.Time `list:"user" json:"end_time"` // 备份模式 - BackupMode string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BackupMode string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"backup_mode"` // 备份数据库名称 - DBNames string `width:"512" charset:"ascii" nullable:"true" list:"user" create:"optional"` + DBNames string `width:"512" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"db_names"` // 备份大小 // example: 32 - BackupSizeMb int `nullable:"false" list:"user"` + BackupSizeMb int `nullable:"false" list:"user" json:"backup_size_mb"` + // RDS实例Id // example: 239b9663-6d06-4ef4-8cfc-320a7fb6660d - DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` + // DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` } func (manager *SDBInstanceBackupManager) GetContextManagers() [][]db.IModelManager { @@ -89,52 +95,89 @@ func (manager *SDBInstanceBackupManager) GetContextManagers() [][]db.IModelManag } } -func (self *SDBInstanceBackupManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SDBInstanceBackupManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SDBInstanceBackup) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDBInstanceBackup) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SDBInstanceBackup) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - // RDS备份列表 -func (manager *SDBInstanceBackupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceBackupListInput) (*sqlchemy.SQuery, error) { +func (manager *SDBInstanceBackupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceBackupListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) + dbQuery := api.DBInstanceFilterListInput{ + DBInstanceFilterListInputBase: query.DBInstanceFilterListInputBase, + } + q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, dbQuery) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "dbinstance", ModelKeyword: "dbinstance", OwnerId: userCred}, - }) + return q, nil +} + +func (manager *SDBInstanceBackupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceBackupListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + dbQuery := api.DBInstanceFilterListInput{ + DBInstanceFilterListInputBase: query.DBInstanceFilterListInputBase, + } + q, err = manager.SDBInstanceResourceBaseManager.OrderByExtraFields(ctx, q, userCred, dbQuery) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SDBInstanceBackupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SDBInstanceResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound } func (manager *SDBInstanceBackupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceBackupCreateInput) (*jsonutils.JSONDict, error) { @@ -160,7 +203,11 @@ func (manager *SDBInstanceBackupManager) ValidateCreateData(ctx context.Context, input.DBNames = strings.Join(input.Databases, ",") input.Engine = instance.Engine input.EngineVersion = instance.EngineVersion - input.ManagerId = instance.ManagerId + provider := instance.GetCloudprovider() + if provider == nil { + return nil, httperrors.NewInvalidStatusError("DBinstance has not valid cloudprovider") + } + input.ManagerId = provider.Id if instance.Status != api.DBINSTANCE_RUNNING { return nil, httperrors.NewInputParameterError("DBInstance %s(%s) status is %s require status is %s", instance.Name, instance.Id, instance.Status, api.DBINSTANCE_RUNNING) @@ -202,18 +249,6 @@ func (self *SDBInstanceBackup) StartDBInstanceBackupCreateTask(ctx context.Conte return nil } -func (self *SDBInstanceBackup) GetIRegion() (cloudprovider.ICloudRegion, error) { - driver, err := self.GetDriver() - if err != nil { - return nil, err - } - region := self.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to found region for rds backup %s(%s)", self.Name, self.Id) - } - return driver.GetIRegionById(region.ExternalId) -} - func (manager *SDBInstanceBackupManager) getDBInstanceBackupsByInstance(instance *SDBInstance) ([]SDBInstanceBackup, error) { backups := []SDBInstanceBackup{} q := manager.Query().Equals("dbinstance_id", instance.Id) @@ -244,22 +279,39 @@ func (self *SDBInstanceBackup) GetDBInstance() (*SDBInstance, error) { return nil, fmt.Errorf("empty dbinstance id") } -func (self *SDBInstanceBackup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DBInstanceBackupDetails, error) { - var err error - out := api.DBInstanceBackupDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - dbinstance, err := self.GetDBInstance() - if err == nil { - out.DBInstance = dbinstance.Name - } - region := self.GetRegion() - provider := self.GetCloudprovider() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) +func (self *SDBInstanceBackup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.DBInstanceBackupDetails, error) { + return api.DBInstanceBackupDetails{}, nil +} - return out, nil +func (manager *SDBInstanceBackupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstanceBackupDetails { + rows := make([]api.DBInstanceBackupDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + dbRows := manager.SDBInstanceResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DBInstanceBackupDetails{ + VirtualResourceDetails: virtRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regRows[i], + DBInstanceResourceInfoBase: dbRows[i].DBInstanceResourceInfoBase, + } + } + + return rows } func (manager *SDBInstanceBackupManager) SyncDBInstanceBackups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, instance *SDBInstance, region *SCloudregion, cloudBackups []cloudprovider.ICloudDBInstanceBackup) compare.SyncResult { @@ -292,7 +344,7 @@ func (manager *SDBInstanceBackupManager) SyncDBInstanceBackups(ctx context.Conte } for i := 0; i < len(commondb); i++ { - err := commondb[i].SyncWithCloudDBInstanceBackup(ctx, userCred, commonext[i]) + err := commondb[i].SyncWithCloudDBInstanceBackup(ctx, userCred, commonext[i], provider) if err != nil { result.UpdateError(err) } else { @@ -311,7 +363,12 @@ func (manager *SDBInstanceBackupManager) SyncDBInstanceBackups(ctx context.Conte return result } -func (self *SDBInstanceBackup) SyncWithCloudDBInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, extBackup cloudprovider.ICloudDBInstanceBackup) error { +func (self *SDBInstanceBackup) SyncWithCloudDBInstanceBackup( + ctx context.Context, + userCred mcclient.TokenCredential, + extBackup cloudprovider.ICloudDBInstanceBackup, + provider *SCloudprovider, +) error { _, err := db.UpdateWithLock(ctx, self, func() error { self.Status = extBackup.GetStatus() self.StartTime = extBackup.GetStartTime() @@ -341,14 +398,19 @@ func (self *SDBInstanceBackup) SyncWithCloudDBInstanceBackup(ctx context.Context } if len(self.ProjectId) == 0 { - provider := self.GetCloudprovider() - SyncCloudProject(userCred, self, provider.GetOwnerId(), extBackup, self.ManagerId) + SyncCloudProject(userCred, self, provider.GetOwnerId(), extBackup, provider.Id) } return nil } -func (manager *SDBInstanceBackupManager) newFromCloudDBInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, region *SCloudregion, extBackup cloudprovider.ICloudDBInstanceBackup) error { +func (manager *SDBInstanceBackupManager) newFromCloudDBInstanceBackup( + ctx context.Context, + userCred mcclient.TokenCredential, + provider *SCloudprovider, + region *SCloudregion, + extBackup cloudprovider.ICloudDBInstanceBackup, +) error { lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred)) defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred)) @@ -391,7 +453,7 @@ func (manager *SDBInstanceBackupManager) newFromCloudDBInstanceBackup(ctx contex } if len(backup.ProjectId) == 0 { - SyncCloudProject(userCred, &backup, provider.GetOwnerId(), extBackup, backup.ManagerId) + SyncCloudProject(userCred, &backup, provider.GetOwnerId(), extBackup, provider.Id) } return nil @@ -419,3 +481,11 @@ func (self *SDBInstanceBackup) StartDBInstanceBackupDeleteTask(ctx context.Conte task.ScheduleRun(nil) return nil } + +func (self *SDBInstanceBackup) GetCloudprovider() *SCloudprovider { + return self.SManagedResourceBase.GetCloudprovider() +} + +func (self *SDBInstanceBackup) GetRegion() *SCloudregion { + return self.SCloudregionResourceBase.GetRegion() +} diff --git a/pkg/compute/models/dbinstance_databases.go b/pkg/compute/models/dbinstance_databases.go index 44ae7214a9..d80f863406 100644 --- a/pkg/compute/models/dbinstance_databases.go +++ b/pkg/compute/models/dbinstance_databases.go @@ -28,15 +28,16 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDBInstanceDatabaseManager struct { db.SStatusStandaloneResourceBaseManager + SDBInstanceResourceBaseManager } var DBInstanceDatabaseManager *SDBInstanceDatabaseManager @@ -57,12 +58,15 @@ type SDBInstanceDatabase struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SDBInstanceResourceBase + // 字符集 // example: utf-8 - CharacterSet string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional"` + CharacterSet string `width:"32" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"character_set"` + // RDS实例Id // example: 7d07e867-37d1-4754-865d-80f88ad0f982 - DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` + // DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` } func (manager *SDBInstanceDatabaseManager) GetContextManagers() [][]db.IModelManager { @@ -118,33 +122,62 @@ func (manager *SDBInstanceDatabaseManager) FilterByOwner(q *sqlchemy.SQuery, use return q } -func (self *SDBInstanceDatabaseManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} +//func (self *SDBInstanceDatabase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { +//只能创建或删除,避免update name后造成登录数据库名称异常 +// return false +//} -func (self *SDBInstanceDatabase) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDBInstanceDatabase) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - //只能创建或删除,避免update name后造成登录数据库名称异常 - return false -} - -func (self *SDBInstanceDatabase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) +func (self *SDBInstanceDatabase) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return nil, httperrors.ErrForbidden } // RDS数据库列表 -func (manager *SDBInstanceDatabaseManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceDatabaseListInput) (*sqlchemy.SQuery, error) { +func (manager *SDBInstanceDatabaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceDatabaseListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "dbinstance", ModelKeyword: "dbinstance", OwnerId: userCred}, - }) + q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SDBInstanceDatabaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceDatabaseListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SDBInstanceResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SDBInstanceDatabaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SDBInstanceResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound } func (self *SDBInstanceDatabase) GetParentId() string { @@ -245,14 +278,28 @@ func (self *SDBInstanceDatabase) GetDBInstance() (*SDBInstance, error) { } func (self *SDBInstanceDatabase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DBInstancedatabaseDetails, error) { - var err error - out := api.DBInstancedatabaseDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } + return api.DBInstancedatabaseDetails{}, nil +} - return self.getMoreDetails(ctx, userCred, out) +func (manager *SDBInstanceDatabaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstancedatabaseDetails { + rows := make([]api.DBInstancedatabaseDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + dbRows := manager.SDBInstanceResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DBInstancedatabaseDetails{ + StatusStandaloneResourceDetails: stdRows[i], + DBInstanceResourceInfo: dbRows[i], + } + rows[i], _ = objs[i].(*SDBInstanceDatabase).getMoreDetails(ctx, userCred, rows[i]) + } + return rows } func (self *SDBInstanceDatabase) getPrivilegesDetails() ([]api.DBInstancePrivilege, error) { diff --git a/pkg/compute/models/dbinstance_parameters.go b/pkg/compute/models/dbinstance_parameters.go index f7326c694d..f09632d01b 100644 --- a/pkg/compute/models/dbinstance_parameters.go +++ b/pkg/compute/models/dbinstance_parameters.go @@ -26,14 +26,15 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDBInstanceParameterManager struct { db.SStandaloneResourceBaseManager + SDBInstanceResourceBaseManager } var DBInstanceParameterManager *SDBInstanceParameterManager @@ -53,10 +54,14 @@ func init() { type SDBInstanceParameter struct { db.SStandaloneResourceBase db.SExternalizedResourceBase - DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` + SDBInstanceResourceBase + // DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true"` - Key string `width:"64" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` - Value string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + // 数据库参数名称 + Key string `width:"64" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required" json:"key"` + + // 数据库参数值 + Value string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required" json:"value"` } func (manager *SDBInstanceParameterManager) GetContextManagers() [][]db.IModelManager { @@ -65,35 +70,53 @@ func (manager *SDBInstanceParameterManager) GetContextManagers() [][]db.IModelMa } } -func (self *SDBInstanceParameterManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SDBInstanceParameterManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SDBInstanceParameter) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDBInstanceParameter) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SDBInstanceParameter) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - -func (manager *SDBInstanceParameterManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceParameterListInput) (*sqlchemy.SQuery, error) { +// 列出数据参数 +func (manager *SDBInstanceParameterManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceParameterListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "dbinstance", ModelKeyword: "dbinstance", OwnerId: userCred}, - }) + q, err = manager.SDBInstanceResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SDBInstanceParameterManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceParameterListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SDBInstanceResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DBInstanceFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDBInstanceResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SDBInstanceParameterManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SDBInstanceResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound } func (manager *SDBInstanceParameterManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { @@ -181,3 +204,30 @@ func (manager *SDBInstanceParameterManager) newFromCloudDBInstanceParameter(ctx } return nil } + +func (self *SDBInstanceParameter) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DBInstanceparameterDetails, error) { + return api.DBInstanceparameterDetails{}, nil +} + +func (manager *SDBInstanceParameterManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstanceparameterDetails { + rows := make([]api.DBInstanceparameterDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + dbRows := manager.SDBInstanceResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.DBInstanceparameterDetails{ + StandaloneResourceDetails: stdRows[i], + DBInstanceResourceInfo: dbRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/dbinstance_privileges.go b/pkg/compute/models/dbinstance_privileges.go index a56a2db2ac..a5befcfc14 100644 --- a/pkg/compute/models/dbinstance_privileges.go +++ b/pkg/compute/models/dbinstance_privileges.go @@ -71,26 +71,6 @@ func (manager *SDBInstancePrivilegeManager) GetContextManagers() [][]db.IModelMa } } -func (self *SDBInstancePrivilegeManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SDBInstancePrivilegeManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SDBInstancePrivilege) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDBInstancePrivilege) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SDBInstancePrivilege) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SDBInstancePrivilege) GetDBInstanceAccount() (*SDBInstanceAccount, error) { account, err := db.FetchById(DBInstanceAccountManager, self.DBInstanceaccountId) if err != nil { diff --git a/pkg/compute/models/dbinstance_skus.go b/pkg/compute/models/dbinstance_skus.go index 0302ec0724..ff13a723c9 100644 --- a/pkg/compute/models/dbinstance_skus.go +++ b/pkg/compute/models/dbinstance_skus.go @@ -109,7 +109,12 @@ func (manager *SDBInstanceSkuManager) fetchDBInstanceSkus(provider string, regio } // RDS套餐类型列表 -func (manager *SDBInstanceSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceSkuListInput) (*sqlchemy.SQuery, error) { +func (manager *SDBInstanceSkuManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceSkuListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter") @@ -136,6 +141,33 @@ func (manager *SDBInstanceSkuManager) ListItemFilter(ctx context.Context, q *sql return q, nil } +func (manager *SDBInstanceSkuManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceSkuListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SDBInstanceSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (manager *SDBInstanceSkuManager) GetDBStringArray(q *sqlchemy.SQuery) ([]string, error) { array := []string{} rows, err := q.Rows() diff --git a/pkg/compute/models/dbinstanceresource.go b/pkg/compute/models/dbinstanceresource.go new file mode 100644 index 0000000000..fd36fb0414 --- /dev/null +++ b/pkg/compute/models/dbinstanceresource.go @@ -0,0 +1,244 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SDBInstanceResourceBase struct { + DBInstanceId string `width:"36" charset:"ascii" name:"dbinstance_id" nullable:"false" list:"user" create:"required" index:"true" json:"dbinstance_id"` +} + +type SDBInstanceResourceBaseManager struct { + SVpcResourceBaseManager +} + +func (self *SDBInstanceResourceBase) GetDBInstance() (*SDBInstance, error) { + instance, err := DBInstanceManager.FetchById(self.DBInstanceId) + if err != nil { + return nil, errors.Wrap(err, "DBInstanceManager.FetchById") + } + return instance.(*SDBInstance), nil +} + +func (self *SDBInstanceResourceBase) GetVpc() (*SVpc, error) { + nat, err := self.GetDBInstance() + if err != nil { + return nil, errors.Wrap(err, "GetDBInstance") + } + return nat.GetVpc() +} + +func (self *SDBInstanceResourceBase) GetRegion() (*SCloudregion, error) { + vpc, err := self.GetVpc() + if err != nil { + return nil, errors.Wrap(err, "GetVpc") + } + return vpc.GetRegion() +} + +func (self *SDBInstanceResourceBase) GetIRegion() (cloudprovider.ICloudRegion, error) { + vpc, err := self.GetVpc() + if err != nil { + return nil, errors.Wrap(err, "GetVpc") + } + return vpc.GetIRegion() +} + +func (self *SDBInstanceResourceBase) GetCloudprovider() *SCloudprovider { + vpc, err := self.GetVpc() + if err != nil { + return nil + } + return vpc.GetCloudprovider() +} + +func (self *SDBInstanceResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) api.DBInstanceResourceInfo { + return api.DBInstanceResourceInfo{} +} + +func (manager *SDBInstanceResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstanceResourceInfo { + rows := make([]api.DBInstanceResourceInfo, len(objs)) + dbinstanceIds := make([]string, len(objs)) + for i := range objs { + var base *SDBInstanceDatabase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + dbinstanceIds[i] = base.DBInstanceId + } + } + dbInstances := make(map[string]SDBInstance) + err := db.FetchStandaloneObjectsByIds(DBInstanceManager, dbinstanceIds, &dbInstances) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + vpcList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.DBInstanceResourceInfo{} + if dbInstance, ok := dbInstances[dbinstanceIds[i]]; ok { + rows[i].DBInstance = dbInstance.Name + rows[i].VpcId = dbInstance.VpcId + } + vpcList[i] = &SVpcResourceBase{rows[i].VpcId} + } + + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList) + for i := range rows { + rows[i].VpcResourceInfo = vpcRows[i] + } + + return rows +} + +func (manager *SDBInstanceResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.DBInstance) > 0 { + dbObj, err := DBInstanceManager.FetchByIdOrName(userCred, query.DBInstance) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(DBInstanceManager.Keyword(), query.DBInstance) + } else { + return nil, errors.Wrap(err, "DBInstanceManager.FetchByIdOrName") + } + } + q = q.Equals("dbinstance_id", dbObj.GetId()) + } + + subq := DBInstanceManager.Query("id").Snapshot() + + subq, err := manager.SVpcResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("dbinstance_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SDBInstanceResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "dbinstance": + dbQuery := DBInstanceManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(dbQuery.Field("name", field)) + q = q.Join(dbQuery, sqlchemy.Equals(q.Field("dbinstance_id"), dbQuery.Field("id"))) + q.GroupBy(dbQuery.Field("name")) + return q, nil + } + dbInstances := DBInstanceManager.Query("id", "vpc_id").SubQuery() + q = q.LeftJoin(dbInstances, sqlchemy.Equals(q.Field("dbinstance_id"), dbInstances.Field("id"))) + q, err := manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SDBInstanceResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SDBInstanceResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + dbQ := DBInstanceManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput)) { + var vpcOrders []string + var vpcFields []sqlchemy.IQueryField + dbQ, vpcOrders, vpcFields = manager.SVpcResourceBaseManager.GetOrderBySubQuery(dbQ, userCred, query.VpcFilterListInput) + if len(vpcOrders) > 0 { + orders = append(orders, vpcOrders...) + fields = append(fields, vpcFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := dbQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("dbinstance_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByDBInstance}) { + orders = append(orders, query.OrderByDBInstance) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SDBInstanceResourceBaseManager) GetOrderByFields(query api.DBInstanceFilterListInput) []string { + fields := make([]string, 0) + vpcFields := manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput) + fields = append(fields, vpcFields...) + fields = append(fields, query.OrderByDBInstance) + return fields +} + +/* +func (manager *SDBInstanceResourceBaseManager) FetchParentId(ctx context.Context, data jsonutils.JSONObject) string { + parentId, _ := data.GetString("dbinstance_id") + return parentId +} + +func (manager *SDBInstanceResourceBaseManager) FilterByParentId(q *sqlchemy.SQuery, parentId string) *sqlchemy.SQuery { + if len(parentId) > 0 { + q = q.Equals("dbinstance_id", parentId) + } + return q +} +*/ diff --git a/pkg/compute/models/dbinstances.go b/pkg/compute/models/dbinstances.go index 8afcf0d611..881fe9c5e9 100644 --- a/pkg/compute/models/dbinstances.go +++ b/pkg/compute/models/dbinstances.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -47,6 +48,9 @@ import ( type SDBInstanceManager struct { db.SVirtualResourceBaseManager + SCloudregionResourceBaseManager + SManagedResourceBaseManager + SVpcResourceBaseManager } var DBInstanceManager *SDBInstanceManager @@ -109,9 +113,11 @@ type SDBInstance struct { // 安全组Id // example: default SecgroupId string `width:"128" charset:"ascii" list:"user" default:"default" create:"optional"` + // 虚拟私有网络Id // example: ed20d84e-3158-41b1-870c-1725e412e8b6 VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` + // 外部连接地址 ConnectionStr string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 内部连接地址 @@ -130,65 +136,102 @@ type SDBInstance struct { func (manager *SDBInstanceManager) GetContextManagers() [][]db.IModelManager { return [][]db.IModelManager{ - {CloudregionManager}, + {VpcManager}, } } -func (self *SDBInstanceManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SDBInstanceManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SDBInstance) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDBInstance) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SDBInstance) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - // RDS实例列表 -func (man *SDBInstanceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DBInstanceListInput) (*sqlchemy.SQuery, error) { - q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) +func (man *SDBInstanceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "vpc", ModelKeyword: "vpc", OwnerId: userCred}, - }) + + q, err = man.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, err - } - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = man.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) + q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) + if len(query.Zone) > 0 { + zoneObj, err := ZoneManager.FetchByIdOrName(userCred, query.Zone) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), query.Zone) + } else { + return nil, errors.Wrap(err, "ZoneManager.FetchByIdOrName") + } + } + q = q.Filter(sqlchemy.OR( + sqlchemy.Equals(q.Field("zone1"), zoneObj.GetId()), + sqlchemy.Equals(q.Field("zone2"), zoneObj.GetId()), + sqlchemy.Equals(q.Field("zone3"), zoneObj.GetId()), + )) + } + + return q, nil +} + +func (man *SDBInstanceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DBInstanceListInput, +) (*sqlchemy.SQuery, error) { + q, err := man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + q, err = man.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") } return q, nil } +func (man *SDBInstanceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.DBInstanceCreateInput) (*jsonutils.JSONDict, error) { data := input.JSON(input) networkV := validators.NewModelIdOrNameValidator("network", "network", ownerId) @@ -235,7 +278,7 @@ func (man *SDBInstanceManager) ValidateCreateData(ctx context.Context, userCred if cloudprovider == nil { return nil, httperrors.NewGeneralError(fmt.Errorf("failed to get vpc %s(%s) cloudprovider", vpc.Name, vpc.Id)) } - if !cloudprovider.Enabled { + if !cloudprovider.GetEnabled() { return nil, httperrors.NewInputParameterError("cloudprovider %s(%s) disabled", cloudprovider.Name, cloudprovider.Id) } @@ -365,14 +408,38 @@ func (self *SDBInstance) PostCreate(ctx context.Context, userCred mcclient.Token task.ScheduleRun(nil) } -func (self *SDBInstance) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DBInstanceDetails, error) { - var err error - out := api.DBInstanceDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SDBInstance) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.DBInstanceDetails, error) { + return api.DBInstanceDetails{}, nil +} + +func (manager *SDBInstanceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DBInstanceDetails { + rows := make([]api.DBInstanceDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DBInstanceDetails{ + VirtualResourceDetails: virtRows[i], + VpcResourceInfo: vpcRows[i], + } + rows[i].ManagedResourceInfo = manRows[i] + rows[i].CloudregionResourceInfo = regRows[i] + rows[i] = objs[i].(*SDBInstance).getMoreDetails(rows[i]) } - return self.getMoreDetails(ctx, userCred, query, out), nil + return rows } func (self *SDBInstance) GetVpc() (*SVpc, error) { @@ -457,39 +524,14 @@ func fetchDBInstanceZones(rdsIds []string) map[string][]sDBInstanceZone { return result } -func (manager *SDBInstanceManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - rdsIds := make([]string, len(objs)) - for i := range objs { - rdsIds[i] = objs[i].GetId() - } - if len(fields) == 0 || fields.Contains("zone") { - zoneInfo := fetchDBInstanceZones(rdsIds) - if zoneInfo != nil { - for i := range rows { - if zones, ok := zoneInfo[objs[i].GetId()]; ok { - for _, zone := range zones { - rows[i].Add(jsonutils.NewString(zone.Name), zone.Id) - } - } - } - } - } - return rows -} - -func (self *SDBInstance) getProviderInfo() api.CloudproviderInfo { - provider := self.GetCloudprovider() +func (self *SDBInstance) getProviderInfo() SCloudProviderInfo { + vpc, _ := self.GetVpc() + provider := vpc.GetCloudprovider() region := self.GetRegion() return MakeCloudProviderInfo(region, nil, provider) } -func (self *SDBInstance) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out api.DBInstanceDetails) api.DBInstanceDetails { - out.CloudproviderInfo = self.getProviderInfo() - vpc, _ := self.GetVpc() - if vpc != nil { - out.Vpc = vpc.Name - } +func (self *SDBInstance) getMoreDetails(out api.DBInstanceDetails) api.DBInstanceDetails { if len(self.SecgroupId) > 0 { if secgroup, _ := self.GetSecgroup(); secgroup != nil { out.Secgroup = secgroup.Name @@ -504,8 +546,6 @@ func (self *SDBInstance) getMoreDetails(ctx context.Context, userCred mcclient.T if network != nil { out.Network = network.Name } - - out.Metadata, _ = self.GetAllMetadata(userCred) return out } @@ -525,18 +565,6 @@ func (self *SDBInstance) GetMasterInstance() (*SDBInstance, error) { return instance.(*SDBInstance), nil } -func (self *SDBInstance) GetIRegion() (cloudprovider.ICloudRegion, error) { - driver, err := self.GetDriver() - if err != nil { - return nil, err - } - region := self.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to found region for rds %s(%s)", self.Name, self.Id) - } - return driver.GetIRegionById(region.ExternalId) -} - func (self *SDBInstance) GetIDBInstance() (cloudprovider.ICloudDBInstance, error) { iregion, err := self.GetIRegion() if err != nil { @@ -545,19 +573,18 @@ func (self *SDBInstance) GetIDBInstance() (cloudprovider.ICloudDBInstance, error return iregion.GetIDBInstanceById(self.ExternalId) } -func (self *SDBInstance) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - dataCopy := jsonutils.DeepCopy(data) +func (self *SDBInstance) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { backups, err := self.GetDBInstanceBackups() if err != nil { return nil, httperrors.NewGeneralError(fmt.Errorf("failed get backups: %v", err)) } for i := range backups { - _, err := backups[i].PerformChangeOwner(ctx, userCred, query, dataCopy) + _, err := backups[i].PerformChangeOwner(ctx, userCred, query, input) if err != nil { return nil, err } } - return self.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, data) + return self.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input) } func (self *SDBInstance) AllowPerformRecovery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -1417,7 +1444,7 @@ func (manager *SDBInstanceManager) newFromCloudDBInstance(ctx context.Context, u return nil, errors.Wrapf(err, "newFromCloudDBInstance.Insert") } - SyncCloudProject(userCred, &instance, ownerId, extInstance, instance.ManagerId) + SyncCloudProject(userCred, &instance, ownerId, extInstance, provider.Id) db.OpsLog.LogEvent(&instance, db.ACT_CREATE, instance.GetShortDesc(ctx), userCred) @@ -1457,3 +1484,15 @@ func (dbinstance *SDBInstance) GetUsages() []db.IUsage { &usage, } } + +func (dbinstance *SDBInstance) GetIRegion() (cloudprovider.ICloudRegion, error) { + region := dbinstance.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid cloudregion") + } + provider, err := dbinstance.GetDriver() + if err != nil { + return nil, err + } + return provider.GetIRegionById(region.GetExternalId()) +} diff --git a/pkg/compute/models/deletepreventableresource.go b/pkg/compute/models/deletepreventableresource.go index 52bd51359f..57d44d9e10 100644 --- a/pkg/compute/models/deletepreventableresource.go +++ b/pkg/compute/models/deletepreventableresource.go @@ -24,7 +24,7 @@ import ( type SDeletePreventableResourceBase struct { // 是否开启删除保护 // example: true - DisableDelete tristate.TriState `nullable:"false" default:"true" list:"user" update:"user" create:"optional"` + DisableDelete tristate.TriState `nullable:"false" default:"true" list:"user" update:"user" create:"optional" json:"disable_delete"` } func (lock *SDeletePreventableResourceBase) MarkDeletePreventionOff() { diff --git a/pkg/compute/models/diskresource.go b/pkg/compute/models/diskresource.go new file mode 100644 index 0000000000..1cc1aa39e6 --- /dev/null +++ b/pkg/compute/models/diskresource.go @@ -0,0 +1,217 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SDiskResourceBase struct { + DiskId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` +} + +type SDiskResourceBaseManager struct { + SStorageResourceBaseManager +} + +func (self *SDiskResourceBase) GetDisk() *SDisk { + obj, _ := DiskManager.FetchById(self.DiskId) + if obj != nil { + return obj.(*SDisk) + } + return nil +} + +func (self *SDiskResourceBase) GetStorage() *SStorage { + disk := self.GetDisk() + if disk != nil { + return disk.GetStorage() + } + return nil +} + +func (self *SDiskResourceBase) GetZone() *SZone { + storage := self.GetStorage() + if storage != nil { + return storage.GetZone() + } + return nil +} + +func (self *SDiskResourceBase) GetRegion() *SCloudregion { + storage := self.GetStorage() + if storage == nil { + return nil + } + region := storage.GetRegion() + return region +} + +func (self *SDiskResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.DiskResourceInfo { + return api.DiskResourceInfo{} +} + +func (manager *SDiskResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DiskResourceInfo { + rows := make([]api.DiskResourceInfo, len(objs)) + diskIds := make([]string, len(objs)) + for i := range objs { + var base *SDiskResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find DiskResourceBase in object %s", objs[i]) + continue + } + diskIds[i] = base.DiskId + } + disks := make(map[string]SDisk) + err := db.FetchStandaloneObjectsByIds(DiskManager, diskIds, disks) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + storageList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.DiskResourceInfo{} + if disk, ok := disks[diskIds[i]]; ok { + rows[i].Disk = disk.Name + rows[i].StorageId = disk.StorageId + } + storageList[i] = &SStorageResourceBase{rows[i].StorageId} + } + + storageRows := manager.SStorageResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, storageList, fields, isList) + for i := range rows { + rows[i].StorageResourceInfo = storageRows[i] + } + return rows +} + +func (manager *SDiskResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DiskFilterListInput, +) (*sqlchemy.SQuery, error) { + var err error + if len(query.Disk) > 0 { + diskObj, err := DiskManager.FetchByIdOrName(userCred, query.Disk) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(DiskManager.Keyword(), query.Disk) + } else { + return nil, errors.Wrap(err, "DiskManager.FetchByIdOrName") + } + } + q = q.Equals("disk_id", diskObj.GetId()) + } + diskQ := DiskManager.Query("id").Snapshot() + diskQ, err = manager.SStorageResourceBaseManager.ListItemFilter(ctx, diskQ, userCred, query.StorageFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SStorageResourceBaseManager.ListItemFilter") + } + if diskQ.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("disk_id"), diskQ.SubQuery())) + } + return q, nil +} + +func (manager *SDiskResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "disk": + diskQuery := DiskManager.Query("name", "id").SubQuery() + q = q.AppendField(diskQuery.Field("name", field)).Distinct() + q = q.Join(diskQuery, sqlchemy.Equals(q.Field("disk_id"), diskQuery.Field("id"))) + return q, nil + default: + disks := DiskManager.Query("id", "storage_id").SubQuery() + q = q.LeftJoin(disks, sqlchemy.Equals(q.Field("disk_id"), disks.Field("id"))) + q, err := manager.SStorageResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SDiskResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DiskFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SDiskResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DiskFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + diskQ := DiskManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SStorageResourceBaseManager.GetOrderByFields(query.StorageFilterListInput)) { + var storageOrders []string + var storageFields []sqlchemy.IQueryField + diskQ, storageOrders, storageFields = manager.SStorageResourceBaseManager.GetOrderBySubQuery(diskQ, userCred, query.StorageFilterListInput) + if len(storageOrders) > 0 { + orders = append(orders, storageOrders...) + fields = append(fields, storageFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := diskQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("disk_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByDisk}) { + orders = append(orders, query.OrderByDisk) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SDiskResourceBaseManager) GetOrderByFields(query api.DiskFilterListInput) []string { + orders := make([]string, 0) + storageOrders := manager.SStorageResourceBaseManager.GetOrderByFields(query.StorageFilterListInput) + orders = append(orders, storageOrders...) + orders = append(orders, query.OrderByDisk) + return orders +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index a2d996d10c..73f5263712 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -31,6 +31,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" imageapi "yunion.io/x/onecloud/pkg/apis/image" @@ -49,10 +50,13 @@ import ( "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/rand" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDiskManager struct { db.SVirtualResourceBaseManager + SStorageResourceBaseManager + SBillingResourceBaseManager } var DiskManager *SDiskManager @@ -74,39 +78,44 @@ type SDisk struct { db.SExternalizedResourceBase SBillingResourceBase + SStorageResourceBase // 磁盘存储类型 // example: qcow2 - DiskFormat string `width:"32" charset:"ascii" nullable:"false" default:"qcow2" list:"user"` + DiskFormat string `width:"32" charset:"ascii" nullable:"false" default:"qcow2" list:"user" json:"disk_format"` // 磁盘大小, 单位Mb // example: 10240 - DiskSize int `nullable:"false" list:"user"` + DiskSize int `nullable:"false" list:"user" json:"disk_size"` // 磁盘路径 - AccessPath string `width:"256" charset:"ascii" nullable:"true" get:"user"` + AccessPath string `width:"256" charset:"ascii" nullable:"true" get:"user" json:"access_path"` // 是否跟随云主机自动删除, 仅绑定到云主机时才生效 // example: false - AutoDelete bool `nullable:"false" default:"false" get:"user" update:"user"` + AutoDelete bool `nullable:"false" default:"false" get:"user" update:"user" json:"auto_delete"` // 存储Id - StorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional"` - BackupStorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin"` + // StorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional"` + + // 备份磁盘实例的存储ID + BackupStorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" json:"backup_storage_id"` // 镜像Id - TemplateId string `width:"256" charset:"ascii" nullable:"true" list:"user"` + TemplateId string `width:"256" charset:"ascii" nullable:"true" list:"user" json:"template_id"` // 快照Id - SnapshotId string `width:"256" charset:"ascii" nullable:"true" list:"user"` + SnapshotId string `width:"256" charset:"ascii" nullable:"true" list:"user" json:"snapshot_id"` // 文件系统 - FsFormat string `width:"32" charset:"ascii" nullable:"true" list:"user"` + FsFormat string `width:"32" charset:"ascii" nullable:"true" list:"user" json:"fs_format"` + // 磁盘类型 // sys: 系统盘 // data: 数据盘 // swap: 交换盘 // example: sys - DiskType string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"admin"` + DiskType string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"admin" json:"disk_type"` + // # is persistent - Nonpersistent bool `default:"false" list:"user"` + Nonpersistent bool `default:"false" list:"user" json:"nonpersistent"` } func (manager *SDiskManager) GetContextManagers() [][]db.IModelManager { @@ -125,28 +134,22 @@ func (manager *SDiskManager) FetchDiskById(diskId string) *SDisk { } // 磁盘列表 -func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DiskListInput) (*sqlchemy.SQuery, error) { +func (manager *SDiskManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DiskListInput, +) (*sqlchemy.SQuery, error) { var err error - storages := StorageManager.Query().SubQuery() - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "storage_id", func() *sqlchemy.SQuery { - return storages.Query(storages.Field("id")) - }) + + q, err = manager.SStorageResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StorageFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SStorageResourceBaseManager.ListItemFilter") } - billingTypeStr := query.BillingType - if len(billingTypeStr) > 0 { - if billingTypeStr == billing_api.BILLING_TYPE_POSTPAID { - q = q.Filter( - sqlchemy.OR( - sqlchemy.IsNullOrEmpty(q.Field("billing_type")), - sqlchemy.Equals(q.Field("billing_type"), billingTypeStr), - ), - ) - } else { - q = q.Equals("billing_type", billingTypeStr) - } + q, err = manager.SBillingResourceBaseManager.ListItemFilter(ctx, q, userCred, query.BillingResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SBillingResourceBaseManager.ListItemFilter") } q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) @@ -164,16 +167,6 @@ func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu } } - if query.Share != nil && *query.Share { - sq := storages.Query(storages.Field("id")).Filter(sqlchemy.NotIn(storages.Field("storage_type"), api.STORAGE_LOCAL_TYPES)) - q = q.Filter(sqlchemy.In(q.Field("storage_id"), sq)) - } - - if query.Local != nil && *query.Local { - sq := storages.Query(storages.Field("id")).Filter(sqlchemy.In(storages.Field("storage_type"), api.STORAGE_LOCAL_TYPES)) - q = q.Filter(sqlchemy.In(q.Field("storage_id"), sq)) - } - guestId := query.Server if len(guestId) > 0 { iGuest, err := GuestManager.FetchByIdOrName(userCred, guestId) @@ -190,15 +183,6 @@ func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu )) } - storageStr := query.Storage - if len(storageStr) > 0 { - storageObj, err := StorageManager.FetchByIdOrName(userCred, storageStr) - if err != nil { - return nil, httperrors.NewResourceNotFoundError("storage %s not found: %s", storageStr, err) - } - q = q.Filter(sqlchemy.Equals(q.Field("storage_id"), storageObj.GetId())) - } - if diskType := query.DiskType; diskType != "" { q = q.Filter(sqlchemy.Equals(q.Field("disk_type"), diskType)) } @@ -217,6 +201,47 @@ func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } +func (manager *SDiskManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DiskListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStorageResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StorageFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SStorageResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SBillingResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.BillingResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SBillingResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SDiskManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SStorageResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SDisk) GetGuestDiskCount() (int, error) { guestdisks := GuestdiskManager.Query() return guestdisks.Equals("disk_id", self.Id).CountWithError() @@ -383,7 +408,7 @@ func (manager *SDiskManager) ValidateCreateData(ctx context.Context, userCred mc provider := storage.GetCloudprovider() if provider != nil { - if !provider.Enabled { + if !provider.GetEnabled() { return nil, httperrors.NewInputParameterError("provider %s(%s) is disabled, you need enable provider first", provider.Name, provider.Id) } if !utils.IsInStringArray(provider.Status, api.CLOUD_PROVIDER_VALID_STATUS) { @@ -1745,13 +1770,6 @@ func (self *SDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenC } func (self *SDisk) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, out api.DiskDetails) api.DiskDetails { - if storage := self.GetStorage(); storage != nil { - out.Storage = storage.Name - out.StorageType = storage.StorageType - out.MediumType = storage.MediumType - out.CloudproviderInfo = storage.getCloudProviderInfo() - } - out.Guests = []api.SimpleGuest{} guests, guestStatus := []string{}, []string{} for _, guest := range self.GetGuests() { @@ -1810,13 +1828,28 @@ func (self *SDisk) getMoreDetails(ctx context.Context, userCred mcclient.TokenCr } func (self *SDisk) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DiskDetails, error) { - var err error - out := api.DiskDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.DiskDetails{}, nil +} + +func (manager *SDiskManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DiskDetails { + rows := make([]api.DiskDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + storeRows := manager.SStorageResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DiskDetails{ + VirtualResourceDetails: virtRows[i], + StorageResourceInfo: storeRows[i], + } + rows[i] = objs[i].(*SDisk).getMoreDetails(ctx, userCred, rows[i]) } - return self.getMoreDetails(ctx, userCred, out), nil + return rows } func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int64, parentTaskId string, pendingUsage quotas.IQuota) error { @@ -1938,7 +1971,7 @@ func (self *SDisk) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { var billingInfo SCloudBillingInfo if storage != nil { - billingInfo.CloudproviderInfo = storage.getCloudProviderInfo() + billingInfo.SCloudProviderInfo = storage.getCloudProviderInfo() } if priceKey := self.GetMetadata("ext:price_key", nil); len(priceKey) > 0 { @@ -2368,9 +2401,9 @@ func (self *SDisk) GetSnapshotsNotInInstanceSnapshot() ([]SSnapshot, error) { } func (self *SDisk) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { - _, err := self.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, data) + _, err := self.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input) if err != nil { return nil, err } @@ -2383,7 +2416,7 @@ func (self *SDisk) PerformChangeOwner(ctx context.Context, userCred mcclient.Tok for i := range snapshots { snapshot := snapshots[i] lockman.LockObject(ctx, &snapshot) - _, err := snapshot.PerformChangeOwner(ctx, userCred, query, data) + _, err := snapshot.PerformChangeOwner(ctx, userCred, query, input) if err != nil { lockman.ReleaseObject(ctx, &snapshot) return nil, errors.Wrapf(err, "fail to change owner of this disk(%s)'s snapshot %s", self.Id, snapshot.Id) diff --git a/pkg/compute/models/dnsrecords.go b/pkg/compute/models/dnsrecords.go index 00b397f54c..66de03b96c 100644 --- a/pkg/compute/models/dnsrecords.go +++ b/pkg/compute/models/dnsrecords.go @@ -21,20 +21,21 @@ import ( "strings" "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/tristate" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SDnsRecordManager struct { db.SAdminSharableVirtualResourceBaseManager + db.SEnabledResourceBaseManager } var DnsRecordManager *SDnsRecordManager @@ -55,8 +56,13 @@ const DNS_RECORDS_SEPARATOR = "," type SDnsRecord struct { db.SAdminSharableVirtualResourceBase - Ttl int `nullable:"true" default:"1" create:"optional" list:"user" update:"user"` - Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user"` + db.SEnabledResourceBase + + // DNS记录的过期时间,单位为秒 + // example: 60 + Ttl int `nullable:"true" default:"1" create:"optional" list:"user" update:"user" json:"ttl"` + + //Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user"` } // GetRecordsSeparator implements IAdminSharableVirtualModelManager @@ -452,18 +458,10 @@ func (rec *SDnsRecord) AllowPerformEnable(ctx context.Context, userCred mcclient return rec.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, rec, "enable") } -func (rec *SDnsRecord) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if rec.Enabled.IsFalse() { - diff, err := db.Update(rec, func() error { - rec.Enabled = tristate.True - return nil - }) - if err != nil { - log.Errorf("enabling dnsrecords for %s failed: %s", rec.Name, err) - return nil, err - } - db.OpsLog.LogEvent(rec, db.ACT_ENABLE, diff, userCred) - logclient.AddActionLogWithContext(ctx, rec, logclient.ACT_ENABLE, diff, userCred, true) +func (rec *SDnsRecord) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(rec, ctx, userCred, true) + if err != nil { + return nil, errors.Wrap(err, "db.EnabledPerformEnable") } return nil, nil } @@ -472,23 +470,72 @@ func (rec *SDnsRecord) AllowPerformDisable(ctx context.Context, userCred mcclien return rec.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, rec, "disable") } -func (rec *SDnsRecord) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if rec.Enabled.IsTrue() { - diff, err := db.Update(rec, func() error { - rec.Enabled = tristate.False - return nil - }) - if err != nil { - log.Errorf("disabling dnsrecords for %s failed: %s", rec.Name, err) - return nil, err - } - db.OpsLog.LogEvent(rec, db.ACT_DISABLE, diff, userCred) - logclient.AddActionLogWithContext(ctx, rec, logclient.ACT_DISABLE, diff, userCred, true) +func (rec *SDnsRecord) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(rec, ctx, userCred, false) + if err != nil { + return nil, errors.Wrap(err, "db.EnabledPerformEnable") } return nil, nil } // 域名记录列表 -func (manager *SDnsRecordManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DnsRecordListInput) (*sqlchemy.SQuery, error) { - return manager.SAdminSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AdminSharableVirtualResourceListInput) +func (manager *SDnsRecordManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DnsRecordListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SAdminSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AdminSharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SAdminSharableVirtualResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SDnsRecordManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DnsRecordListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SAdminSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.AdminSharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SAdminSharableVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SDnsRecordManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SAdminSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (record *SDnsRecord) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DnsRecordDetails, error) { + return api.DnsRecordDetails{}, nil +} + +func (manager *SDnsRecordManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DnsRecordDetails { + rows := make([]api.DnsRecordDetails, len(objs)) + + virtRows := manager.SAdminSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.DnsRecordDetails{ + AdminSharableVirtualResourceDetails: virtRows[i], + } + } + + return rows } diff --git a/pkg/compute/models/dynamicschedtags.go b/pkg/compute/models/dynamicschedtags.go index c8cab97fc5..966076dc69 100644 --- a/pkg/compute/models/dynamicschedtags.go +++ b/pkg/compute/models/dynamicschedtags.go @@ -31,6 +31,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/conditionparser" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type IDynamicResourceManager interface { @@ -44,6 +45,7 @@ type IDynamicResource interface { type SDynamicschedtagManager struct { db.SStandaloneResourceBaseManager + SSchedtagResourceBaseManager StandaloneResourcesManager map[string]IDynamicResourceManager VirtualResourcesManager map[string]IDynamicResourceManager @@ -99,33 +101,18 @@ func (man *SDynamicschedtagManager) InitializeData() error { // type SDynamicschedtag struct { db.SStandaloneResourceBase + SSchedtagResourceBase - Condition string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"required" update:"admin"` - SchedtagId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" update:"admin"` + // 动态调度标间的匹配条件 + // example: host.sys_load > 1.5 || host.mem_used_percent > 0.7 => "high_load" + Condition string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"required" update:"admin"` + + // 动态调度标签对应的调度标签 + // SchedtagId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" update:"admin"` Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user" update:"user"` } -func (self *SDynamicschedtagManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SDynamicschedtagManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SDynamicschedtag) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SDynamicschedtag) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SDynamicschedtag) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func validateDynamicSchedtagInputData(data *jsonutils.JSONDict, create bool) error { condStr := jsonutils.GetAnyString(data, []string{"condition"}) if len(condStr) == 0 && create { @@ -183,36 +170,36 @@ func (self *SDynamicschedtag) ValidateUpdateData(ctx context.Context, userCred m return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) } -func (self *SDynamicschedtag) GetSchedtag() *SSchedtag { - return self.getSchedtag() +func (self *SDynamicschedtag) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.DynamicschedtagDetails, error) { + return api.DynamicschedtagDetails{}, nil } -func (self *SDynamicschedtag) getSchedtag() *SSchedtag { - obj, err := SchedtagManager.FetchById(self.SchedtagId) - if err != nil { - log.Errorf("fail to fetch sched tag by id %s", err) - return nil - } - return obj.(*SSchedtag) -} +func (manager *SDynamicschedtagManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DynamicschedtagDetails { + rows := make([]api.DynamicschedtagDetails, len(objs)) -func (self *SDynamicschedtag) getMoreColumns(out api.DynamicschedtagDetails) api.DynamicschedtagDetails { - schedtag := self.getSchedtag() - if schedtag != nil { - out.Schedtag = schedtag.GetName() - out.ResourceType = schedtag.ResourceType - } - return out -} + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + tagRows := manager.SSchedtagResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) -func (self *SDynamicschedtag) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DynamicschedtagDetails, error) { - var err error - out := api.DynamicschedtagDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + for i := range rows { + rows[i] = api.DynamicschedtagDetails{ + StandaloneResourceDetails: stdRows[i], + SchedtagResourceInfo: tagRows[i], + } } - return self.getMoreColumns(out), nil + + return rows } func (manager *SDynamicschedtagManager) GetEnabledDynamicSchedtagsByResource(resType string) []SDynamicschedtag { @@ -303,10 +290,58 @@ func FetchDynamicResourceObject(man IDynamicResourceManager, userCred mcclient.T } // 动态调度标签列表 -func (manager *SDynamicschedtagManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.DynamicschedtagListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) +func (manager *SDynamicschedtagManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.DynamicschedtagListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SSchedtagResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SchedtagFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SSchedtagResourceBaseManager.ListItemFilter") + } + return q, nil } + +func (manager *SDynamicschedtagManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.DynamicschedtagListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SSchedtagResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SchedtagFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SSchedtagResourceBaseManager.OrderByExtraFields(") + } + + return q, nil +} + +func (manager *SDynamicschedtagManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SSchedtagResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/elasticcache_accounts.go b/pkg/compute/models/elasticcache_accounts.go index d8288ee99d..4a04c1d90d 100644 --- a/pkg/compute/models/elasticcache_accounts.go +++ b/pkg/compute/models/elasticcache_accounts.go @@ -37,11 +37,13 @@ import ( "yunion.io/x/onecloud/pkg/util/choices" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) // SElasticcache.Account type SElasticcacheAccountManager struct { db.SStatusStandaloneResourceBaseManager + SElasticcacheResourceBaseManager } var ElasticcacheAccountManager *SElasticcacheAccountManager @@ -62,7 +64,9 @@ type SElasticcacheAccount struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase - ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id + SElasticcacheResourceBase + + // ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id AccountType string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"optional"` // 账号类型 normal |admin AccountPrivilege string `width:"16" charset:"ascii" nullable:"false" list:"user" update:"user" create:"optional"` // 账号权限 read | write | repl(复制, 复制权限支持读写,且开放SYNC/PSYNC命令) @@ -388,24 +392,6 @@ func (self *SElasticcacheAccount) Delete(ctx context.Context, userCred mcclient. return nil } -func (self *SElasticcacheAccount) GetIRegion() (cloudprovider.ICloudRegion, error) { - _ec, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) - if err != nil { - return nil, err - } - - ec := _ec.(*SElasticcache) - provider, err := ec.GetDriver() - if err != nil { - return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", ec.Name, err) - } - region := self.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) - } - return provider.GetIRegionById(region.ExternalId) -} - func (self *SElasticcacheAccount) AllowPerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowPerform(userCred, self, "reset_password") } @@ -466,10 +452,83 @@ func (self *SElasticcacheAccount) ValidatePurgeCondition(ctx context.Context) er } // 弹性缓存账号列表 -func (manager *SElasticcacheAccountManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ElasticcacheAccountListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StatusStandaloneResourceListInput) +func (manager *SElasticcacheAccountManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheAccountListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SElasticcacheResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.ListItemFilter") + } return q, nil } + +func (manager *SElasticcacheAccountManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheAccountListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SElasticcacheResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SElasticcacheAccountManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SElasticcacheResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (self *SElasticcacheAccount) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ElasticcacheAccountDetails, error) { + return api.ElasticcacheAccountDetails{}, nil +} + +func (manager *SElasticcacheAccountManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheAccountDetails { + rows := make([]api.ElasticcacheAccountDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + cacheRows := manager.SElasticcacheResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ElasticcacheAccountDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ElasticcacheResourceInfo: cacheRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/elasticcache_acls.go b/pkg/compute/models/elasticcache_acls.go index d7ca3354f5..9209d46e6f 100644 --- a/pkg/compute/models/elasticcache_acls.go +++ b/pkg/compute/models/elasticcache_acls.go @@ -35,11 +35,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) // SElasticcache.Acl type SElasticcacheAclManager struct { db.SStandaloneResourceBaseManager + SElasticcacheResourceBaseManager } var ElasticcacheAclManager *SElasticcacheAclManager @@ -59,10 +61,12 @@ func init() { type SElasticcacheAcl struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SElasticcacheResourceBase - ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id + // ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id - IpList string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + // Ip地址白名单列表 + IpList string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required" json:"ip_list"` } func (manager *SElasticcacheAclManager) SyncElasticcacheAcls(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, cloudElasticcacheAcls []cloudprovider.ICloudElasticcacheAcl) compare.SyncResult { @@ -241,24 +245,6 @@ func (self *SElasticcacheAcl) StartElasticcacheAclCreateTask(ctx context.Context return nil } -func (self *SElasticcacheAcl) GetIRegion() (cloudprovider.ICloudRegion, error) { - _ec, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) - if err != nil { - return nil, err - } - - ec := _ec.(*SElasticcache) - provider, err := ec.GetDriver() - if err != nil { - return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", ec.Name, err) - } - region := ec.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) - } - return provider.GetIRegionById(region.ExternalId) -} - func (self *SElasticcacheAcl) GetRegion() *SCloudregion { ieb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) if err != nil { @@ -344,10 +330,92 @@ func (self *SElasticcacheAcl) Delete(ctx context.Context, userCred mcclient.Toke } // 弹性缓存ACL规则列表 -func (manager *SElasticcacheAclManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ElasticcacheAclListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) +func (manager *SElasticcacheAclManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + + q, err = manager.SElasticcacheResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.ListItemFilter") + } + return q, nil } + +func (manager *SElasticcacheAclManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SElasticcacheResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SElasticcacheAclManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SElasticcacheResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (self *SElasticcacheAcl) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ElasticcacheAclDetails, error) { + return api.ElasticcacheAclDetails{}, nil +} + +func (manager *SElasticcacheAclManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheAclDetails { + rows := make([]api.ElasticcacheAclDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + elasticRows := manager.SElasticcacheResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ElasticcacheAclDetails{ + StandaloneResourceDetails: stdRows[i], + ElasticcacheResourceInfo: elasticRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/elasticcache_backups.go b/pkg/compute/models/elasticcache_backups.go index 3be5e4b4b5..9dddf5cac8 100644 --- a/pkg/compute/models/elasticcache_backups.go +++ b/pkg/compute/models/elasticcache_backups.go @@ -34,11 +34,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) // SElasticcache.Backup type SElasticcacheBackupManager struct { db.SStatusStandaloneResourceBaseManager + SElasticcacheResourceBaseManager } var ElasticcacheBackupManager *SElasticcacheBackupManager @@ -58,16 +60,26 @@ func init() { type SElasticcacheBackup struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SElasticcacheResourceBase - ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id + // ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id - BackupSizeMb int `nullable:"false" list:"user" create:"optional"` - BackupType string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` // 全量|增量额 - BackupMode string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` // 自动|手动 - DownloadURL string `width:"512" charset:"ascii" nullable:"true" create:"optional" list:"user"` + // 备份大小 + BackupSizeMb int `nullable:"false" list:"user" create:"optional"` + // 备份类型, 全量|增量额 + BackupType string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` + + // 备份模式,自动|手动 + BackupMode string `width:"32" charset:"ascii" nullable:"true" create:"optional" list:"user"` + + // 下载地址 + DownloadURL string `width:"512" charset:"ascii" nullable:"true" create:"optional" list:"user"` + + // 开始备份时间 StartTime time.Time `list:"user" create:"optional"` - EndTime time.Time `list:"user" create:"optional"` + // 结束备份时间 + EndTime time.Time `list:"user" create:"optional"` } func (manager *SElasticcacheBackupManager) SyncElasticcacheBackups(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, cloudElasticcacheBackups []cloudprovider.ICloudElasticcacheBackup) compare.SyncResult { @@ -122,27 +134,6 @@ func (manager *SElasticcacheBackupManager) SyncElasticcacheBackups(ctx context.C return syncResult } -func (self *SElasticcacheBackup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ElasticcacheBackupDetails, error) { - var err error - out := api.ElasticcacheBackupDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - icache, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) - if err == nil { - ec := icache.(*SElasticcache) - provider := ec.GetCloudprovider() - region := ec.GetRegion() - zone := ec.GetZone() - out.CloudproviderInfo = MakeCloudProviderInfo(region, zone, provider) - - out.Engine = ec.Engine - out.EngineVersion = ec.EngineVersion - } - return out, nil -} - func (self *SElasticcacheBackup) syncRemoveCloudElasticcacheBackup(ctx context.Context, userCred mcclient.TokenCredential) error { lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) @@ -286,24 +277,6 @@ func (self *SElasticcacheBackup) StartElasticcacheBackupCreateTask(ctx context.C return nil } -func (self *SElasticcacheBackup) GetIRegion() (cloudprovider.ICloudRegion, error) { - _eb, err := db.FetchById(ElasticcacheManager, self.ElasticcacheId) - if err != nil { - return nil, err - } - - eb := _eb.(*SElasticcache) - provider, err := eb.GetDriver() - if err != nil { - return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", eb.Name, err) - } - region := eb.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) - } - return provider.GetIRegionById(region.ExternalId) -} - func (self *SElasticcacheBackup) AllowPerformRestoreInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { // todo : fix me self.IsOwner(userCred) || return db.IsAdminAllowPerform(userCred, self, "restore_instance") @@ -369,10 +342,91 @@ func (self *SElasticcacheBackup) ValidatePurgeCondition(ctx context.Context) err } // 弹性缓存备份列表 -func (manager *SElasticcacheBackupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ElasticcacheBackupListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StatusStandaloneResourceListInput) +func (manager *SElasticcacheBackupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheBackupListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + + q, err = manager.SElasticcacheResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.ListItemFilter") + } + return q, nil } + +func (manager *SElasticcacheBackupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheBackupListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SElasticcacheResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SElasticcacheBackupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SElasticcacheResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (self *SElasticcacheBackup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ElasticcacheBackupDetails, error) { + return api.ElasticcacheBackupDetails{}, nil +} + +func (manager *SElasticcacheBackupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheBackupDetails { + rows := make([]api.ElasticcacheBackupDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + cacheRows := manager.SElasticcacheResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ElasticcacheBackupDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ElasticcacheResourceInfo: cacheRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/elasticcache_instances.go b/pkg/compute/models/elasticcache_instances.go index 824a534e4f..5ec34f7e48 100644 --- a/pkg/compute/models/elasticcache_instances.go +++ b/pkg/compute/models/elasticcache_instances.go @@ -44,10 +44,13 @@ import ( "yunion.io/x/onecloud/pkg/util/choices" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SElasticcacheManager struct { db.SVirtualResourceBaseManager + SVpcResourceBaseManager + SZoneResourceBaseManager } var ElasticcacheManager *SElasticcacheManager @@ -68,36 +71,77 @@ type SElasticcache struct { db.SVirtualResourceBase db.SExternalizedResourceBase SBillingResourceBase - SManagedResourceBase SDeletePreventableResourceBase + SVpcResourceBase + SZoneResourceBase - SCloudregionResourceBase - SZoneResourceBase // 主可用区. - SlaveZones string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 备可用区 + // 备可用区 + SlaveZones string `width:"128" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"slave_zones"` - InstanceType string `width:"96" charset:"ascii" nullable:"true" list:"user" create:"optional"` // redis.master.micro.default - CapacityMB int `nullable:"false" list:"user" create:"optional"` // 1024 - LocalCategory string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 对应Sku local_category - NodeType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读) - Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // Redis | Memcache - EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` // 4.0 5.0 + // 实例规格 + // example: redis.master.micro.default + InstanceType string `width:"96" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"instance_type"` - VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` - NetworkType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional"` // CLASSIC(经典网络) VPC(专有网络) - NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` - SecurityGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` + // 容量 + // example: 1024 + CapacityMB int `nullable:"false" list:"user" create:"optional" json:"capacity_mb"` - PrivateDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 内网DNS - PrivateIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional"` // 内网IP地址 - PrivateConnectPort int `nullable:"true" list:"user" create:"optional"` // 内网访问端口 - PublicDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional"` - PublicIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional"` // - PublicConnectPort int `nullable:"true" list:"user" create:"optional"` // 外网访问端口 + // 对应Sku + LocalCategory string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"local_category"` - MaintainStartTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional"` // HH:mmZ eg. 02:00Z - MaintainEndTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // 类型 + // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读) + NodeType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"node_type"` + + // 后端存储引擎 + // Redis | Memcache + // example: redis + Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine"` + + // 后端存储引擎版本 + // example: 4.0 + EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine_version"` + + // VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"` + + // 网络类型, CLASSIC(经典网络) VPC(专有网络) + // example: CLASSIC + NetworkType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"network_type"` + + // 所属网络ID + NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"network_id"` + + // 安全组 + SecurityGroupId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"security_group_id"` + + // 内网DNS + PrivateDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"private_dns"` + + // 内网IP地址 + PrivateIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional" json:"private_ip_addr"` + + // 内网访问端口 + PrivateConnectPort int `nullable:"true" list:"user" create:"optional" json:"private_connect_port"` + + // 公网DNS + PublicDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"public_dns"` + + // 公网IP地址 + PublicIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional" json:"public_ip_addr"` + + // 外网访问端口 + PublicConnectPort int `nullable:"true" list:"user" create:"optional" json:"public_connect_port"` + + // 维护开始时间,格式为HH:mmZ + // example: 02:00Z + MaintainStartTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"maintain_start_time"` + + // 维护结束时间 + MaintainEndTime string `width:"8" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"maintain_end_time"` + + // 访问密码? on (开启密码)|off (免密码访问) + AuthMode string `width:"8" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"auth_mode"` - AuthMode string `width:"8" charset:"ascii" nullable:"false" list:"user" create:"optional"` // 访问密码? on (开启密码)|off (免密码访问) // AutoRenew // 自动续费 // AutoRenewPeriod // 自动续费周期 } @@ -140,38 +184,55 @@ func elasticcacheSubResourceFetchOwner(q *sqlchemy.SQuery, userCred mcclient.IId return q } -func (self *SElasticcache) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SElasticcache) getCloudProviderInfo() SCloudProviderInfo { region := self.GetRegion() provider := self.GetCloudprovider() zone := self.GetZone() return MakeCloudProviderInfo(region, zone, provider) } -func (self *SElasticcache) updateExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, out api.ElasticcacheDetails) api.ElasticcacheDetails { - out.CloudproviderInfo = self.getCloudProviderInfo() - - vpc, err := VpcManager.FetchById(self.VpcId) - if err == nil { - out.Vpc = vpc.GetName() - } - - network, err := NetworkManager.FetchById(self.NetworkId) - if err == nil { - out.Network = network.GetName() - } - - return out +func (self *SElasticcache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ElasticcacheDetails, error) { + return api.ElasticcacheDetails{}, nil } -func (self *SElasticcache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ElasticcacheDetails, error) { - var err error - out := api.ElasticcacheDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SElasticcacheManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheDetails { + rows := make([]api.ElasticcacheDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + netIds := make([]string, len(objs)) + for i := range rows { + rows[i] = api.ElasticcacheDetails{ + VirtualResourceDetails: virtRows[i], + VpcResourceInfo: vpcRows[i], + ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase, + } + netIds[i] = objs[i].(*SElasticcache).NetworkId } - return self.updateExtraDetails(ctx, userCred, out), nil + networks := make(map[string]SNetwork) + err := db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if net, ok := networks[netIds[i]]; ok { + rows[i].Network = net.Name + } + } + + return rows } func (self *SElasticcache) GetElasticcacheParameters() ([]SElasticcacheParameter, error) { @@ -242,27 +303,78 @@ func (manager *SElasticcacheManager) GetOwnerIdByElasticcacheId(elasticcacheId s } // 列出弹性缓存(redis等) -func (manager *SElasticcacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ElasticcacheListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) +func (manager *SElasticcacheManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "vpc", ModelKeyword: "vpc", OwnerId: userCred}, - {Key: "zone", ModelKeyword: "zone", OwnerId: userCred}, - {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, - }) + q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } + return q, nil } +func (manager *SElasticcacheManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") + } + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SElasticcacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (manager *SElasticcacheManager) SyncElasticcaches(ctx context.Context, userCred mcclient.TokenCredential, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider, region *SCloudregion, cloudElasticcaches []cloudprovider.ICloudElasticcache) ([]SElasticcache, []cloudprovider.ICloudElasticcache, compare.SyncResult) { lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) @@ -376,8 +488,8 @@ func (manager *SElasticcacheManager) newFromCloudElasticcache(ctx context.Contex } instance.Name = newName instance.ExternalId = extInstance.GetGlobalId() - instance.CloudregionId = region.Id - instance.ManagerId = provider.Id + // instance.CloudregionId = region.Id + // instance.ManagerId = provider.Id instance.IsEmulated = extInstance.IsEmulated() instance.Status = extInstance.GetStatus() @@ -442,7 +554,7 @@ func (manager *SElasticcacheManager) newFromCloudElasticcache(ctx context.Contex return nil, errors.Wrapf(err, "newFromCloudElasticcache.Insert") } - SyncCloudProject(userCred, &instance, ownerId, extInstance, instance.ManagerId) + SyncCloudProject(userCred, &instance, ownerId, extInstance, provider.Id) db.OpsLog.LogEvent(&instance, db.ACT_CREATE, instance.GetShortDesc(ctx), userCred) return &instance, nil @@ -477,7 +589,7 @@ func (manager *SElasticcacheManager) ValidateCreateData(ctx context.Context, use if err != nil { return nil, fmt.Errorf("getting network failed") } - region = network.(*SNetwork).getRegion() + region = network.(*SNetwork).GetRegion() } if region == nil { @@ -524,7 +636,7 @@ func (self *SElasticcache) StartElasticcacheCreateTask(ctx context.Context, user return nil } -func (self *SElasticcache) GetIRegion() (cloudprovider.ICloudRegion, error) { +/*func (self *SElasticcache) GetIRegion() (cloudprovider.ICloudRegion, error) { provider, err := self.GetDriver() if err != nil { return nil, fmt.Errorf("No cloudprovider for elastic cache %s: %s", self.Name, err) @@ -534,7 +646,7 @@ func (self *SElasticcache) GetIRegion() (cloudprovider.ICloudRegion, error) { return nil, fmt.Errorf("failed to find region for elastic cache %s", self.Name) } return provider.GetIRegionById(region.ExternalId) -} +}*/ func (self *SElasticcache) GetCreateAliyunElasticcacheParams(data *jsonutils.JSONDict) (*cloudprovider.SCloudElasticCacheInput, error) { input := &cloudprovider.SCloudElasticCacheInput{} @@ -698,7 +810,7 @@ func (self *SElasticcache) GetCreateHuaweiElasticcacheParams(data *jsonutils.JSO // fill security group here if len(self.SecurityGroupId) > 0 { - sgCache, err := SecurityGroupCacheManager.GetSecgroupCache(context.Background(), nil, self.SecurityGroupId, self.VpcId, self.CloudregionId, self.ManagerId) + sgCache, err := SecurityGroupCacheManager.GetSecgroupCache(context.Background(), nil, self.SecurityGroupId, self.VpcId, self.GetRegion().Id, self.GetCloudprovider().Id) if err != nil { return nil, errors.Wrap(err, "elasticcache.GetCreateHuaweiElasticcacheParams.SecurityGroup") } @@ -786,8 +898,9 @@ func (self *SElasticcache) ValidatorChangeSpecData(ctx context.Context, userCred return nil, httperrors.NewInputParameterError("provider mismatch: %s instance can't use %s sku", self.GetProviderName(), sku.Provider) } - if sku.CloudregionId != self.CloudregionId { - return nil, httperrors.NewInputParameterError("region mismatch: instance region %s, sku region %s", self.CloudregionId, sku.CloudregionId) + region := self.GetRegion() + if sku.CloudregionId != region.Id { + return nil, httperrors.NewInputParameterError("region mismatch: instance region %s, sku region %s", region.Id, sku.CloudregionId) } if sku.ZoneId != "" && sku.ZoneId != self.ZoneId { @@ -1254,9 +1367,11 @@ func (man *SElasticcacheManager) TotalCount( providers []string, brands []string, cloudEnv string, ) (int, error) { q := man.Query() + vpcs := VpcManager.Query().SubQuery() + q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id"))) q = scopeOwnerIdFilter(q, scope, ownerId) - q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv) - q = rangeObjectsFilter(q, rangeObjs, q.Field("cloudregion_id"), nil, q.Field("manager_id")) + q = CloudProviderFilter(q, vpcs.Field("manager_id"), providers, brands, cloudEnv) + q = rangeObjectsFilter(q, rangeObjs, vpcs.Field("cloudregion_id"), nil, vpcs.Field("manager_id")) return q.CountWithError() } diff --git a/pkg/compute/models/elasticcache_parameters.go b/pkg/compute/models/elasticcache_parameters.go index 5e8cac89b6..75fce760bd 100644 --- a/pkg/compute/models/elasticcache_parameters.go +++ b/pkg/compute/models/elasticcache_parameters.go @@ -31,11 +31,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) // SElasticcache.Parameter type SElasticcacheParameterManager struct { db.SStandaloneResourceBaseManager + SElasticcacheResourceBaseManager } var ElasticcacheParameterManager *SElasticcacheParameterManager @@ -55,14 +57,24 @@ func init() { type SElasticcacheParameter struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SElasticcacheResourceBase - ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id + // ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"` // elastic cache instance id - Key string `width:"64" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` - Value string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` - ValueRange string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 校验代码,参数的可选范围。 - Modifiable bool `nullable:"true" list:"user" create:"optional"` // True(可修改) False(不可修改) - ForceRestart bool `nullable:"true" list:"user" create:"optional"` // True(重启生效) False(无需重启,提交后即生效) + // Parameter KEY + Key string `width:"64" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + + // Parameter Value + Value string `width:"256" charset:"ascii" nullable:"false" list:"user" update:"user" create:"required"` + + // 校验代码,参数的可选范围。 + ValueRange string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional"` + + // True(可修改) False(不可修改) + Modifiable bool `nullable:"true" list:"user" create:"optional"` + + // True(重启生效) False(无需重启,提交后即生效) + ForceRestart bool `nullable:"true" list:"user" create:"optional"` } func (manager *SElasticcacheParameterManager) SyncElasticcacheParameters(ctx context.Context, userCred mcclient.TokenCredential, elasticcache *SElasticcache, cloudElasticcacheParameters []cloudprovider.ICloudElasticcacheParameter) compare.SyncResult { @@ -236,10 +248,92 @@ func (self *SElasticcacheParameter) ValidatePurgeCondition(ctx context.Context) return nil } -func (manager *SElasticcacheParameterManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ElasticcacheParameterListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) +// 列出弹性缓存参数 +func (manager *SElasticcacheParameterManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheParameterListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + + q, err = manager.SElasticcacheResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.ListItemFilter") + } + return q, nil } + +func (manager *SElasticcacheParameterManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.ElasticcacheParameterListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SElasticcacheResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ElasticcacheFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SElasticcacheResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SElasticcacheParameterManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SElasticcacheResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (self *SElasticcacheParameter) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ElasticcacheParameterDetails, error) { + return api.ElasticcacheParameterDetails{}, nil +} + +func (manager *SElasticcacheParameterManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheParameterDetails { + rows := make([]api.ElasticcacheParameterDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + cacheRows := manager.SElasticcacheResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ElasticcacheParameterDetails{ + StandaloneResourceDetails: stdRows[i], + ElasticcacheResourceInfo: cacheRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/elasticcache_skus.go b/pkg/compute/models/elasticcache_skus.go index 6d0290d12a..6297f77998 100644 --- a/pkg/compute/models/elasticcache_skus.go +++ b/pkg/compute/models/elasticcache_skus.go @@ -17,7 +17,6 @@ package models import ( "context" "database/sql" - "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -38,6 +37,8 @@ import ( type SElasticcacheSkuManager struct { db.SStatusStandaloneResourceBaseManager + SCloudregionResourceBaseManager + SZoneResourceBaseManager } var ElasticcacheSkuManager *SElasticcacheSkuManager @@ -59,9 +60,10 @@ type SElasticcacheSku struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase - SCloudregionResourceBase // 区域 - SZoneResourceBase // 主可用区 - SlaveZoneId string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 备可用区 + SCloudregionResourceBase // 区域 + SZoneResourceBase // 主可用区 + + SlaveZoneId string `width:"64" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` // 备可用区 InstanceSpec string `width:"96" charset:"ascii" nullable:"false" list:"user" create:"admin_optional" update:"admin"` EngineArch string `width:"32" charset:"utf8" nullable:"false" list:"user" create:"admin_optional" update:"admin"` @@ -98,10 +100,32 @@ func (self SElasticcacheSku) GetGlobalId() string { } func (self *SElasticcacheSku) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ElasticcacheSkuDetails, error) { - var err error - out := api.ElasticcacheSkuDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - return out, err + return api.ElasticcacheSkuDetails{}, nil +} + +func (manager *SElasticcacheSkuManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheSkuDetails { + rows := make([]api.ElasticcacheSkuDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ElasticcacheSkuDetails{ + StatusStandaloneResourceDetails: stdRows[i], + CloudregionResourceInfo: regRows[i], + ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase, + } + } + + return rows } func (manager *SElasticcacheSkuManager) GetSkuCountByRegion(regionId string) (int, error) { @@ -110,7 +134,7 @@ func (manager *SElasticcacheSkuManager) GetSkuCountByRegion(regionId string) (in return q.CountWithError() } -func (manager *SElasticcacheSkuManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { +/*func (manager *SElasticcacheSkuManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { regions := map[string]string{} for i := range objs { cloudregionId := objs[i].(*SElasticcacheSku).CloudregionId @@ -169,15 +193,33 @@ func (manager *SElasticcacheSkuManager) FetchCustomizeColumns(ctx context.Contex } return ret -} +}*/ // 弹性缓存套餐规格列表 -func (manager *SElasticcacheSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ElasticcacheSkuListInput) (*sqlchemy.SQuery, error) { +func (manager *SElasticcacheSkuManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheSkuListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + if query.Usable != nil && *query.Usable { q = usableFilter(q, true) sq := sqlchemy.OR(sqlchemy.Equals(q.Field("prepaid_status"), api.SkuStatusAvailable), sqlchemy.Equals(q.Field("postpaid_status"), api.SkuStatusAvailable)) @@ -193,11 +235,6 @@ func (manager *SElasticcacheSkuManager) ListItemFilter(ctx context.Context, q *s } } - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") - } - if domainStr := query.ProjectDomain; len(domainStr) > 0 { domain, err := db.TenantCacheManager.FetchDomainByIdOrName(context.Background(), domainStr) if err != nil { @@ -210,11 +247,6 @@ func (manager *SElasticcacheSkuManager) ListItemFilter(ctx context.Context, q *s } q = listItemDomainFilter(q, query.Providers, query.ProjectDomain) - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - // 按区间查询内存, 避免0.75G这样的套餐不好过滤 memSizeMB := query.MemorySizeMb if memSizeMB > 0 { @@ -226,6 +258,49 @@ func (manager *SElasticcacheSkuManager) ListItemFilter(ctx context.Context, q *s return q, nil } +func (manager *SElasticcacheSkuManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheSkuListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SElasticcacheSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + // 获取region下所有Available状态的sku id func (manager *SElasticcacheSkuManager) FetchSkusByRegion(regionID string) ([]SElasticcacheSku, error) { q := manager.Query() diff --git a/pkg/compute/models/elasticcacheresource.go b/pkg/compute/models/elasticcacheresource.go new file mode 100644 index 0000000000..b623f285e8 --- /dev/null +++ b/pkg/compute/models/elasticcacheresource.go @@ -0,0 +1,260 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SElasticcacheResourceBase struct { + // 弹性缓存ID + ElasticcacheId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true" json:"elasticcache_id"` +} + +type SElasticcacheResourceBaseManager struct { + SVpcResourceBaseManager + SZoneResourceBaseManager +} + +func (self *SElasticcacheResourceBase) GetElasticcache() (*SElasticcache, error) { + instance, err := ElasticcacheManager.FetchById(self.ElasticcacheId) + if err != nil { + return nil, errors.Wrap(err, "DBInstanceManager.FetchById") + } + return instance.(*SElasticcache), nil +} + +func (self *SElasticcacheResourceBase) GetVpc() *SVpc { + cache, err := self.GetElasticcache() + if err != nil { + log.Errorf("GetElasticcache fail %s", err) + return nil + } + return cache.GetVpc() +} + +func (self *SElasticcacheResourceBase) GetIRegion() (cloudprovider.ICloudRegion, error) { + vpc := self.GetVpc() + if vpc == nil { + return nil, errors.Wrap(httperrors.ErrNotFound, "no vpc found") + } + return vpc.GetIRegion() +} + +func (self *SElasticcacheResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) api.ElasticcacheResourceInfo { + return api.ElasticcacheResourceInfo{} +} + +func (manager *SElasticcacheResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticcacheResourceInfo { + rows := make([]api.ElasticcacheResourceInfo, len(objs)) + elasticcacheIds := make([]string, len(objs)) + for i := range objs { + var base *SElasticcacheResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + elasticcacheIds[i] = base.ElasticcacheId + } + } + elasticcaches := make(map[string]SElasticcache) + err := db.FetchStandaloneObjectsByIds(ElasticcacheManager, elasticcacheIds, &elasticcaches) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + vpcList := make([]interface{}, len(rows)) + zoneList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.ElasticcacheResourceInfo{} + if elasticache, ok := elasticcaches[elasticcacheIds[i]]; ok { + rows[i].Elasticcache = elasticache.Name + rows[i].Engine = elasticache.Engine + rows[i].EngineVersion = elasticache.EngineVersion + rows[i].VpcId = elasticache.VpcId + rows[i].ZoneId = elasticache.ZoneId + } + vpcList[i] = &SVpcResourceBase{rows[i].VpcId} + zoneList[i] = &SZoneResourceBase{rows[i].ZoneId} + } + + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList) + for i := range rows { + rows[i].VpcResourceInfo = vpcRows[i] + rows[i].ZoneResourceInfoBase = zoneRows[i].ZoneResourceInfoBase + } + + return rows +} + +func (manager *SElasticcacheResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Elasticcache) > 0 { + dbObj, err := ElasticcacheManager.FetchByIdOrName(userCred, query.Elasticcache) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(ElasticcacheManager.Keyword(), query.Elasticcache) + } else { + return nil, errors.Wrap(err, "ElasticcacheManager.FetchByIdOrName") + } + } + q = q.Equals("elasticcache_id", dbObj.GetId()) + } + + subq := ElasticcacheManager.Query("id").Snapshot() + subq, err := manager.SVpcResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + subq, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, subq, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("elasticcache_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SElasticcacheResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "elasticcache": + dbQuery := ElasticcacheManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(dbQuery.Field("name", field)) + q = q.Join(dbQuery, sqlchemy.Equals(q.Field("elasticcache_id"), dbQuery.Field("id"))) + q.GroupBy(dbQuery.Field("name")) + return q, nil + } + elasticcaches := ElasticcacheManager.Query("id", "vpc_id").SubQuery() + q = q.LeftJoin(elasticcaches, sqlchemy.Equals(q.Field("elasticcache_id"), elasticcaches.Field("id"))) + q, err := manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SElasticcacheResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SElasticcacheResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticcacheFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + cacheQ := ElasticcacheManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput)) { + var vpcOrders []string + var vpcFields []sqlchemy.IQueryField + cacheQ, vpcOrders, vpcFields = manager.SVpcResourceBaseManager.GetOrderBySubQuery(cacheQ, userCred, query.VpcFilterListInput) + if len(vpcOrders) > 0 { + orders = append(orders, vpcOrders...) + fields = append(fields, vpcFields...) + } + } + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + cacheQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(cacheQ, userCred, zoneQuery) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := cacheQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("elasticcache_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByElasticcache}) { + orders = append(orders, query.OrderByElasticcache) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SElasticcacheResourceBaseManager) GetOrderByFields(query api.ElasticcacheFilterListInput) []string { + fields := make([]string, 0) + vpcFields := manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput) + fields = append(fields, vpcFields...) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery) + fields = append(fields, zoneFields...) + fields = append(fields, query.OrderByElasticcache) + return fields +} + +/* +func (manager *SElasticcacheResourceBaseManager) FetchParentId(ctx context.Context, data jsonutils.JSONObject) string { + parentId, _ := data.GetString("dbinstance_id") + return parentId +} + +func (manager *SElasticcacheResourceBaseManager) FilterByParentId(q *sqlchemy.SQuery, parentId string) *sqlchemy.SQuery { + if len(parentId) > 0 { + q = q.Equals("dbinstance_id", parentId) + } + return q +} +*/ diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index c520dd0932..d83c1460ba 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -36,10 +37,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SElasticipManager struct { db.SVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } var ElasticipManager *SElasticipManager @@ -63,6 +67,8 @@ type SElasticip struct { db.SExternalizedResourceBase SManagedResourceBase + SCloudregionResourceBase + SBillingResourceBase // IP子网Id, 仅私有云不为空 @@ -94,25 +100,31 @@ type SElasticip struct { AutoDellocate tristate.TriState `default:"false" get:"user" create:"optional" update:"user"` // 区域Id - CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + // CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` } // 弹性公网IP列表 -func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ElasticipListInput) (*sqlchemy.SQuery, error) { +func (manager *SElasticipManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticipListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") } associateType := query.UsableEipForAssociateType @@ -155,6 +167,45 @@ func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchem return q, nil } +func (manager *SElasticipManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ElasticipListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (manager *SElasticipManager) getEipsByRegion(region *SCloudregion, provider *SCloudprovider) ([]SElasticip, error) { eips := make([]SElasticip, 0) q := manager.Query().Equals("cloudregion_id", region.Id) @@ -188,7 +239,7 @@ func (self *SElasticip) GetZone() *SZone { if err != nil { return nil } - return network.getZone() + return network.GetZone() } func (self *SElasticip) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { @@ -211,7 +262,7 @@ func (self *SElasticip) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { billingInfo := SCloudBillingInfo{} - billingInfo.CloudproviderInfo = self.getCloudProviderInfo() + billingInfo.SCloudProviderInfo = self.getCloudProviderInfo() billingInfo.SBillingBaseInfo = self.getBillingBaseInfo() @@ -1079,18 +1130,39 @@ func (self *SElasticip) StartEipSyncstatusTask(ctx context.Context, userCred mcc return nil } -func (self *SElasticip) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ElasticipDetails, error) { - var err error - out := api.ElasticipDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SElasticip) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ElasticipDetails, error) { + return api.ElasticipDetails{}, nil +} + +func (manager *SElasticipManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ElasticipDetails { + rows := make([]api.ElasticipDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.ElasticipDetails{ + VirtualResourceDetails: virtRows[i], + ManagedResourceInfo: managerRows[i], + CloudregionResourceInfo: regionRows[i], + } + rows[i] = objs[i].(*SElasticip).getMoreDetails(rows[i]) } - return self.getMoreDetails(out), nil + return rows } func (self *SElasticip) getMoreDetails(out api.ElasticipDetails) api.ElasticipDetails { - out.CloudproviderInfo = self.getCloudProviderInfo() instance := self.GetAssociateResource() if instance != nil { out.AssociateName = instance.GetName() @@ -1115,7 +1187,7 @@ func (manager *SElasticipManager) NewEipForVMOnHost(ctx context.Context, userCre eip.ChargeType = chargeType eip.DomainId = vm.DomainId eip.ProjectId = vm.ProjectId - eip.ProjectSrc = string(db.PROJECT_SOURCE_LOCAL) + eip.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) eip.ManagerId = host.ManagerId eip.CloudregionId = region.Id eip.Name = fmt.Sprintf("eip-for-%s", vm.GetName()) @@ -1285,7 +1357,7 @@ func (self *SElasticip) PerformPurge(ctx context.Context, userCred mcclient.Toke } provider := self.GetCloudprovider() if provider != nil { - if provider.Enabled { + if provider.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge elastic_ip on enabled cloud provider") } } @@ -1301,7 +1373,7 @@ func (self *SElasticip) DoPendingDelete(ctx context.Context, userCred mcclient.T self.Dissociate(ctx, userCred) } -func (self *SElasticip) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SElasticip) getCloudProviderInfo() SCloudProviderInfo { region := self.GetRegion() provider := self.GetCloudprovider() return MakeCloudProviderInfo(region, nil, provider) @@ -1323,7 +1395,7 @@ func (eip *SElasticip) GetUsages() []db.IUsage { } } -func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { +/*func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { var err error q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { @@ -1341,4 +1413,4 @@ func (manager *SElasticipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fi return q, httperrors.NewBadRequestError("unsupport field %s", field) } return q, nil -} +}*/ diff --git a/pkg/compute/models/external_projects.go b/pkg/compute/models/external_projects.go index ca6a0b4fdc..dd75a53b98 100644 --- a/pkg/compute/models/external_projects.go +++ b/pkg/compute/models/external_projects.go @@ -31,12 +31,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SExternalProjectManager struct { db.SStandaloneResourceBaseManager - db.SProjectizedResourceBaseManager + SManagedResourceBaseManager } var ExternalProjectManager *SExternalProjectManager @@ -55,11 +56,9 @@ func init() { type SExternalProject struct { db.SStandaloneResourceBase - SManagedResourceBase - db.SProjectizedResourceBase - db.SExternalizedResourceBase + SManagedResourceBase } func (manager *SExternalProjectManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -79,29 +78,43 @@ func (manager *SExternalProjectManager) getProjectsByProviderId(providerId strin return projects, nil } -func (self *SExternalProject) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SExternalProject) getCloudProviderInfo() SCloudProviderInfo { provider := self.GetCloudprovider() return MakeCloudProviderInfo(nil, nil, provider) } -func (self *SExternalProject) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out api.ExternalProjectDetails) api.ExternalProjectDetails { - out.CloudproviderInfo = self.getCloudProviderInfo() - - tenant, err := db.TenantCacheManager.FetchTenantById(ctx, self.ProjectId) - if err == nil { - out.Tenant = tenant.GetName() - } - return out +func (self *SExternalProject) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ExternalProjectDetails, error) { + return api.ExternalProjectDetails{}, nil } -func (self *SExternalProject) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ExternalProjectDetails, error) { - var err error - out := api.ExternalProjectDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SExternalProjectManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ExternalProjectDetails { + rows := make([]api.ExternalProjectDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ExternalProjectDetails{ + StandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: manRows[i], + ProjectizedResourceInfo: projRows[i], + } } - return self.getMoreDetails(ctx, userCred, query, out), nil + + return rows } func (manager *SExternalProjectManager) GetProject(externalId string, providerId string) (*SExternalProject, error) { @@ -272,17 +285,69 @@ func (self *SExternalProject) PerformChangeProject(ctx context.Context, userCred } // 云平台导入项目列表 -func (manager *SExternalProjectManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ExternalProjectListInput) (*sqlchemy.SQuery, error) { +func (manager *SExternalProjectManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ExternalProjectListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemFilter") + } return q, nil } + +func (manager *SExternalProjectManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ExternalProjectListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SProjectizedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ProjectizedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SExternalProjectManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SProjectizedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/filters.go b/pkg/compute/models/filters.go index a06f2edbf9..1fbefcdc3b 100644 --- a/pkg/compute/models/filters.go +++ b/pkg/compute/models/filters.go @@ -45,7 +45,7 @@ func rangeObjFilter(q *sqlchemy.SQuery, rangeObj db.IStandaloneModel, regionFiel case "wire": wire := rangeObj.(*SWire) if regionField != nil { - vpc := wire.getVpc() + vpc := wire.GetVpc() q = q.Filter(sqlchemy.Equals(regionField, vpc.CloudregionId)) } else if zoneField != nil { q = q.Filter(sqlchemy.Equals(zoneField, wire.ZoneId)) diff --git a/pkg/compute/models/globalvpcresource.go b/pkg/compute/models/globalvpcresource.go new file mode 100644 index 0000000000..6bf5ddd612 --- /dev/null +++ b/pkg/compute/models/globalvpcresource.go @@ -0,0 +1,126 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SGlobalVpcResourceBase struct { + GlobalvpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"globalvpc_id"` +} + +type SGlobalVpcResourceBaseManager struct{} + +func (self *SGlobalVpcResourceBase) GetGlobalVpc() (*SGlobalVpc, error) { + if len(self.GlobalvpcId) == 0 { + return nil, nil + } + gv, err := GlobalVpcManager.FetchById(self.GlobalvpcId) + if err != nil { + return nil, err + } + return gv.(*SGlobalVpc), nil +} + +func (self *SGlobalVpcResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) api.GlobalVpcResourceInfo { + return api.GlobalVpcResourceInfo{} +} + +func (manager *SGlobalVpcResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GlobalVpcResourceInfo { + rows := make([]api.GlobalVpcResourceInfo, len(objs)) + globalVpcIds := make([]string, len(objs)) + for i := range objs { + var base *SGlobalVpcResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + globalVpcIds[i] = base.GlobalvpcId + } + } + globalVpcs := make(map[string]SGlobalVpc) + err := db.FetchStandaloneObjectsByIds(GlobalVpcManager, globalVpcIds, globalVpcs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + for i := range rows { + rows[i] = api.GlobalVpcResourceInfo{} + if _, ok := globalVpcs[globalVpcIds[i]]; ok { + rows[i].Globalvpc = globalVpcs[globalVpcIds[i]].Name + } + } + return rows +} + +func (manager *SGlobalVpcResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GlobalVpcResourceListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Globalvpc) > 0 { + globalVpcObj, err := GlobalVpcManager.FetchByIdOrName(userCred, query.Globalvpc) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(GlobalVpcManager.Keyword(), query.Globalvpc) + } else { + return nil, errors.Wrap(err, "GlobalVpcManager.FetchByIdOrName") + } + } + q = q.Equals("globalvpc_id", globalVpcObj.GetId()) + } + return q, nil +} + +func (manager *SGlobalVpcResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "globalvpc" { + globalvpcs := GlobalVpcManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(globalvpcs.Field("name", field)) + q = q.Join(globalvpcs, sqlchemy.Equals(q.Field("globalvpc_id"), globalvpcs.Field("id"))) + q.GroupBy(globalvpcs.Field("name")) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SGlobalVpcResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GlobalVpcResourceListInput, +) (*sqlchemy.SQuery, error) { + q = db.OrderByStandaloneResourceName(q, GlobalVpcManager, "globalvpc_id", query.OrderByGlobalvpc) + return q, nil +} diff --git a/pkg/compute/models/globalvpcs.go b/pkg/compute/models/globalvpcs.go index 87e770a645..1c2e826152 100644 --- a/pkg/compute/models/globalvpcs.go +++ b/pkg/compute/models/globalvpcs.go @@ -24,7 +24,9 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SGlobalVpcManager struct { @@ -75,13 +77,25 @@ func (self *SGlobalVpc) GetVpcs() ([]SVpc, error) { } func (self *SGlobalVpc) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GlobalVpcDetails, error) { - var err error - out := api.GlobalVpcDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.GlobalVpcDetails{}, nil +} + +func (manager *SGlobalVpcManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GlobalVpcDetails { + rows := make([]api.GlobalVpcDetails, len(objs)) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.GlobalVpcDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + } } - return out, nil + return rows } func (manager *SGlobalVpcManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.GlobalVpcCreateInput) (api.GlobalVpcCreateInput, error) { @@ -99,8 +113,41 @@ func (self *SGlobalVpc) ValidateUpdateData(ctx context.Context, userCred mcclien } // 全局VPC列表 -func (manager *SGlobalVpcManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.GlobalVpcListInput) (*sqlchemy.SQuery, error) { - return manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) +func (manager *SGlobalVpcManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GlobalVpcListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SGlobalVpcManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GlobalVpcListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SGlobalVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } func (self *SGlobalVpc) ValidateUpdateCondition(ctx context.Context) error { diff --git a/pkg/compute/models/groupguests.go b/pkg/compute/models/groupguests.go index 915397a720..9012311886 100644 --- a/pkg/compute/models/groupguests.go +++ b/pkg/compute/models/groupguests.go @@ -18,11 +18,13 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SGroupguestManager struct { @@ -65,16 +67,49 @@ func (joint *SGroupguest) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (self *SGroupguest) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GroupguestDetails, error) { - var err error - out := api.GroupguestDetails{} - out.ModelBaseDetails, err = self.SGroupJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SGroupguest) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GroupguestDetails, error) { + return api.GroupguestDetails{}, nil +} + +func (manager *SGroupguestManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GroupguestDetails { + rows := make([]api.GroupguestDetails, len(objs)) + + groupRows := manager.SGroupJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + guestIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GroupguestDetails{ + GroupJointResourceDetails: groupRows[i], + } + guestIds[i] = objs[i].(SGroupguest).GuestId } - out.Instancegroup, out.Server = db.JointModelExtra(self) - out.Guest = out.Server - return out, nil + + guestIdMaps, err := db.FetchIdNameMap2(GuestManager, guestIds) + if err != nil { + log.Errorf("FetchIdNameMap2 fail %s", err) + return rows + } + + for i := range rows { + if name, ok := guestIdMaps[guestIds[i]]; ok { + rows[i].Guest = name + rows[i].Server = name + } + } + + return rows } func (self *SGroupguest) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/groupjoints.go b/pkg/compute/models/groupjoints.go index a617d8bd55..230a8f4b7d 100644 --- a/pkg/compute/models/groupjoints.go +++ b/pkg/compute/models/groupjoints.go @@ -14,7 +14,18 @@ package models -import "yunion.io/x/onecloud/pkg/cloudcommon/db" +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/reflectutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) type SGroupJointsManager struct { db.SVirtualJointResourceBaseManager @@ -47,3 +58,51 @@ func (self *SGroupJointsBase) GetGroup() *SGroup { guest, _ := GroupManager.FetchById(self.GroupId) return guest.(*SGroup) } + +func (self *SGroupJointsBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GroupJointResourceDetails, error) { + return api.GroupJointResourceDetails{}, nil +} + +func (manager *SGroupJointsManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GroupJointResourceDetails { + rows := make([]api.GroupJointResourceDetails, len(objs)) + + jointRows := manager.SVirtualJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + groupIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GroupJointResourceDetails{ + VirtualJointResourceBaseDetails: jointRows[i], + } + var base *SGroupJointsBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.GroupId) > 0 { + groupIds[i] = base.GroupId + } + } + + groupIdMaps, err := db.FetchIdNameMap2(GroupManager, groupIds) + if err != nil { + log.Errorf("db.FetchIdNameMap2 fail %s", err) + return rows + } + + for i := range rows { + if name, ok := groupIdMaps[groupIds[i]]; ok { + rows[i].Instancegroup = name + } + } + + return rows +} diff --git a/pkg/compute/models/groupnetworks.go b/pkg/compute/models/groupnetworks.go index 7934e23764..b4899af67b 100644 --- a/pkg/compute/models/groupnetworks.go +++ b/pkg/compute/models/groupnetworks.go @@ -23,6 +23,7 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SGroupnetworkManager struct { @@ -71,15 +72,47 @@ func (joint *SGroupnetwork) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (self *SGroupnetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GroupnetworkDetails, error) { - var err error - out := api.GroupnetworkDetails{} - out.ModelBaseDetails, err = self.SGroupJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SGroupnetwork) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GroupnetworkDetails, error) { + return api.GroupnetworkDetails{}, nil +} + +func (manager *SGroupnetworkManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GroupnetworkDetails { + rows := make([]api.GroupnetworkDetails, len(objs)) + + groupRows := manager.SGroupJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + netIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GroupnetworkDetails{ + GroupJointResourceDetails: groupRows[i], + } + netIds[i] = objs[i].(*SGroupnetwork).NetworkId } - out.Instancegroup, out.Network = db.JointModelExtra(self) - return out, nil + + netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds) + if err != nil { + log.Errorf("FetchIdNameMap2 fail %s", err) + return rows + } + + for i := range rows { + if name, ok := netIdMaps[netIds[i]]; ok { + rows[i].Network = name + } + } + + return rows } func (self *SGroupnetwork) GetNetwork() *SNetwork { diff --git a/pkg/compute/models/groups.go b/pkg/compute/models/groups.go index aaaf7723bc..0e2248c53c 100644 --- a/pkg/compute/models/groups.go +++ b/pkg/compute/models/groups.go @@ -27,11 +27,13 @@ import ( "yunion.io/x/pkg/util/sets" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -41,6 +43,8 @@ const ( type SGroupManager struct { db.SVirtualResourceBaseManager + db.SEnabledResourceBaseManager + SZoneResourceBaseManager } var GroupManager *SGroupManager @@ -62,25 +66,51 @@ func init() { type SGroup struct { db.SVirtualResourceBase + SZoneResourceBase + + db.SEnabledResourceBase + // 服务类型 - ServiceType string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"` - ParentId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"` + ServiceType string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional" json:"service_type"` + ParentId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional" json:"parent_id"` + // 可用区Id // example: zone1 - ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"` + // ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional" json:"zone_id"` + // 调度策略 - SchedStrategy string `width:"16" charset:"ascii" nullable:"true" default:"" list:"user" update:"user" create:"optional"` + SchedStrategy string `width:"16" charset:"ascii" nullable:"true" default:"" list:"user" update:"user" create:"optional" json:"sched_strategy"` // the upper limit number of guests with this group in a host - Granularity int `nullable:"false" list:"user" get:"user" create:"optional" update:"user" default:"1"` - ForceDispersion tristate.TriState `list:"user" get:"user" create:"optional" update:"user" default:"true"` + Granularity int `nullable:"false" list:"user" get:"user" create:"optional" update:"user" default:"1" json:"granularity"` + ForceDispersion tristate.TriState `list:"user" get:"user" create:"optional" update:"user" default:"true" json:"force_dispersion"` // 是否启用 - Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user" update:"user"` + // Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user" update:"user" json:"enabled"` } // 主机组列表 -func (sm *SGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, - input api.InstanceGroupListInput) (*sqlchemy.SQuery, error) { +func (sm *SGroupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.InstanceGroupListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = sm.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") + } + + q, err = sm.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, input.EnabledResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter") + } + + q, err = sm.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + guestFilter := input.Server if len(guestFilter) != 0 { guestObj, err := GuestManager.FetchByIdOrName(userCred, guestFilter) @@ -96,25 +126,82 @@ func (sm *SGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, if len(input.ServiceType) > 0 { q = q.Equals("service_type", input.ServiceType) } + return q, nil } -func (group *SGroup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (api.InstanceGroupDetail, error) { +func (sm *SGroupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.InstanceGroupListInput, +) (*sqlchemy.SQuery, error) { var err error - out := api.InstanceGroupDetail{} - out.VirtualResourceDetails, err = group.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) + + q, err = sm.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.VirtualResourceListInput) if err != nil { - return out, err + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") } - return group.getMoreDetails(ctx, userCred, out) + q, err = sm.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + + return q, nil } -func (group *SGroup) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, - out api.InstanceGroupDetail) (api.InstanceGroupDetail, error) { +func (sm *SGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = sm.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = sm.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (sm *SGroupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.InstanceGroupDetail { + rows := make([]api.InstanceGroupDetail, len(objs)) + + virtRows := sm.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := sm.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.InstanceGroupDetail{ + VirtualResourceDetails: virtRows[i], + ZoneResourceInfo: zoneRows[i], + } + rows[i].GuestCount = objs[i].(*SGroup).GetGuestCount() + } + + return rows +} + +func (group *SGroup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.InstanceGroupDetail, error) { + return api.InstanceGroupDetail{}, nil +} + +func (group *SGroup) GetGuestCount() int { q := GroupguestManager.Query().Equals("group_id", group.Id) - out.GuestCount, _ = q.CountWithError() - return out, nil + count, _ := q.CountWithError() + return count } func (group *SGroup) ValidateDeleteCondition(ctx context.Context) error { @@ -256,46 +343,26 @@ func (group *SGroup) checkGuests(ctx context.Context, userCred mcclient.TokenCre return } -func (group *SGroup) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (group *SGroup) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) bool { return group.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, group, "enable") } -func (group *SGroup) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !group.Enabled.IsTrue() { - _, err := db.Update(group, func() error { - group.Enabled = tristate.True - return nil - }) - if err != nil { - logclient.AddSimpleActionLog(group, logclient.ACT_ENABLE, nil, userCred, false) - return nil, err - } - err = group.ClearAllScheDescCache() - if err != nil { - log.Errorf("fail to clean all sche desc cache: %s", err.Error()) - } - db.OpsLog.LogEvent(group, db.ACT_ENABLE, "", userCred) - logclient.AddSimpleActionLog(group, logclient.ACT_ENABLE, nil, userCred, true) +func (group *SGroup) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(group, ctx, userCred, true) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") } return nil, nil } -func (group *SGroup) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (group *SGroup) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) bool { return group.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, group, "disable") } -func (group *SGroup) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if group.Enabled.IsTrue() { - _, err := db.Update(group, func() error { - group.Enabled = tristate.False - return nil - }) - if err != nil { - logclient.AddSimpleActionLog(group, logclient.ACT_DISABLE, nil, userCred, false) - return nil, err - } - db.OpsLog.LogEvent(group, db.ACT_DISABLE, "", userCred) - logclient.AddSimpleActionLog(group, logclient.ACT_DISABLE, nil, userCred, true) +func (group *SGroup) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(group, ctx, userCred, false) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") } return nil, nil } diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 54f74e6243..4e45e789b8 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -35,6 +35,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" billing_api "yunion.io/x/onecloud/pkg/apis/billing" api "yunion.io/x/onecloud/pkg/apis/compute" imageapi "yunion.io/x/onecloud/pkg/apis/image" @@ -1317,7 +1318,7 @@ func (self *SGuest) PerformPurge(ctx context.Context, userCred mcclient.TokenCre return nil, err } host := self.GetHost() - if host != nil && host.Enabled { + if host != nil && host.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge server on enabled host") } err = self.StartDeleteGuestTask(ctx, userCred, "", true, false, false) @@ -2637,14 +2638,14 @@ func (self *SGuest) isNotRunningStatus(status string) bool { return false } -func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (self *SGuest) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { preStatus := self.Status - _, err := self.SVirtualResourceBase.PerformStatus(ctx, userCred, query, data) + _, err := self.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input) if err != nil { return nil, err } - status, _ := data.GetString("status") + status := input.Status if len(self.BackupHostId) > 0 && status == api.VM_RUNNING { if len(self.GetMetadata("__mirror_job_status", userCred)) == 0 { self.SetMetadata(ctx, "__mirror_job_status", "ready", userCred) @@ -3980,27 +3981,26 @@ func (self *SGuest) PerformSyncFixNics(ctx context.Context, return nil, nil } -func (guest *SGuest) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { +func (guest *SGuest) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { guestdisks := guest.GetDisks() - dataCopy := jsonutils.DeepCopy(data) for i := range guestdisks { disk := guestdisks[i].GetDisk() if disk == nil { return nil, httperrors.NewInternalServerError("some disk missing!!!") } - _, err := disk.PerformChangeOwner(ctx, userCred, query, dataCopy) + _, err := disk.PerformChangeOwner(ctx, userCred, query, input) if err != nil { return nil, err } } if eip, _ := guest.GetEip(); eip != nil { - _, err := eip.PerformChangeOwner(ctx, userCred, query, dataCopy) + _, err := eip.PerformChangeOwner(ctx, userCred, query, input) if err != nil { return nil, err } } - return guest.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, data) + return guest.SVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input) } func (guest *SGuest) AllowPerformResizeDisk(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { diff --git a/pkg/compute/models/guest_queries.go b/pkg/compute/models/guest_queries.go index 577beb4875..2092bc4983 100644 --- a/pkg/compute/models/guest_queries.go +++ b/pkg/compute/models/guest_queries.go @@ -24,23 +24,40 @@ import ( "yunion.io/x/pkg/tristate" "yunion.io/x/sqlchemy" - "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/apis" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) -func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) +func (manager *SGuestManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ServerDetails { + rows := make([]api.ServerDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + hostRows := manager.SHostResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) guestIds := make([]string, len(objs)) for i := range objs { - guestIds[i] = objs[i].GetId() + rows[i] = api.ServerDetails{ + VirtualResourceDetails: virtRows[i], + HostResourceInfo: hostRows[i], + } + guestIds[i] = objs[i].(*SGuest).GetId() } + if len(fields) == 0 || fields.Contains("disk") { gds := fetchGuestDiskSizes(guestIds) if gds != nil { for i := range rows { - if gd, ok := gds[objs[i].GetId()]; ok { - rows[i].Add(jsonutils.NewInt(gd.DiskSizeMb), "disk") + if gd, ok := gds[guestIds[i]]; ok { + rows[i].DiskSizeMb = gd.DiskSizeMb + rows[i].DiskCount = gd.DiskCount } } } @@ -49,8 +66,8 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gips := fetchGuestIPs(guestIds, tristate.False) if gips != nil { for i := range rows { - if gip, ok := gips[objs[i].GetId()]; ok { - rows[i].Add(jsonutils.NewString(strings.Join(gip, ",")), "ips") + if gip, ok := gips[guestIds[i]]; ok { + rows[i].IPs = strings.Join(gip, ",") } } } @@ -59,8 +76,8 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre nicsMap := fetchGuestNICs(ctx, guestIds, tristate.False) if nicsMap != nil { for i := range rows { - if nics, ok := nicsMap[objs[i].GetId()]; ok { - rows[i].Add(nics, "nics") + if nics, ok := nicsMap[guestIds[i]]; ok { + rows[i].Nics = nics } } } @@ -69,12 +86,12 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gvpcs := fetchGuestVpcs(guestIds) if gvpcs != nil { for i := range rows { - if gvpc, ok := gvpcs[objs[i].GetId()]; ok { + if gvpc, ok := gvpcs[guestIds[i]]; ok { if len(fields) == 0 || fields.Contains("vpc") { - rows[i].Add(jsonutils.NewString(strings.Join(gvpc.Vpc, ",")), "vpc") + rows[i].Vpc = strings.Join(gvpc.Vpc, ",") } if len(fields) == 0 || fields.Contains("vpc_id") { - rows[i].Add(jsonutils.NewString(strings.Join(gvpc.VpcId, ",")), "vpc_id") + rows[i].VpcId = strings.Join(gvpc.VpcId, ",") } } } @@ -84,12 +101,12 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gsgs := fetchSecgroups(guestIds) if gsgs != nil { for i := range rows { - if gsg, ok := gsgs[objs[i].GetId()]; ok { + if gsg, ok := gsgs[guestIds[i]]; ok { if len(fields) == 0 || fields.Contains("secgroups") { - rows[i].Add(jsonutils.Marshal(gsg), "secgroups") + rows[i].Secgroups = gsg } if len(fields) == 0 || fields.Contains("secgroup") { - rows[i].Add(jsonutils.NewString(gsg[0].Name), "secgroup") + rows[i].Secgroup = gsg[0].Name } } } @@ -99,12 +116,12 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre geips := fetchGuestEips(guestIds) if geips != nil { for i := range rows { - if eip, ok := geips[objs[i].GetId()]; ok { + if eip, ok := geips[guestIds[i]]; ok { if len(fields) == 0 || fields.Contains("eip") { - rows[i].Add(jsonutils.NewString(eip.IpAddr), "eip") + rows[i].Eip = eip.IpAddr } if len(fields) == 0 || fields.Contains("eip_mode") { - rows[i].Add(jsonutils.NewString(eip.Mode), "eip_mode") + rows[i].EipMode = eip.Mode } } } @@ -114,8 +131,8 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gkps := fetchGuestKeypairs(guestIds) if gkps != nil { for i := range rows { - if kps, ok := gkps[objs[i].GetId()]; ok { - rows[i].Add(jsonutils.NewString(kps.Keypair), "keypair") + if kps, ok := gkps[guestIds[i]]; ok { + rows[i].Keypair = kps.Keypair } } } @@ -124,20 +141,20 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gdevs := fetchGuestIsolatedDevices(guestIds) if gdevs != nil { for i := range rows { - if gdev, ok := gdevs[objs[i].GetId()]; ok { + if gdev, ok := gdevs[guestIds[i]]; ok { if len(fields) == 0 || fields.Contains("isolated_devices") { - rows[i].Add(jsonutils.Marshal(getIsolatedDeviceDetails(gdev)), "isolated_devices") + rows[i].IsolatedDevices = gdev } if len(fields) == 0 || fields.Contains("is_gpu") { if len(gdev) > 0 { - rows[i].Add(jsonutils.JSONTrue, "is_gpu") + rows[i].IsGpu = true } else { - rows[i].Add(jsonutils.JSONFalse, "is_gpu") + rows[i].IsGpu = false } } } else { if len(fields) == 0 || fields.Contains("is_gpu") { - rows[i].Add(jsonutils.JSONFalse, "is_gpu") + rows[i].IsGpu = false } } } @@ -147,27 +164,31 @@ func (manager *SGuestManager) FetchCustomizeColumns(ctx context.Context, userCre gcds := fetchGuestCdroms(guestIds) if gcds != nil { for i := range rows { - if gcd, ok := gcds[objs[i].GetId()]; ok { - rows[i].Add(jsonutils.NewString(gcd.GetDetails()), "cdrom") - } else { - rows[i].Add(jsonutils.NewString(""), "cdrom") + if gcd, ok := gcds[guestIds[i]]; ok { + rows[i].Cdrom = gcd.GetDetails() } } } } + + for i := range rows { + rows[i] = objs[i].(*SGuest).moreExtraInfo(rows[i], userCred, query, fields, isList) + } + return rows } type sGustDiskSize struct { GuestId string DiskSizeMb int64 + DiskCount int } func fetchGuestDiskSizes(guestIds []string) map[string]sGustDiskSize { disks := DiskManager.Query().SubQuery() guestdisks := GuestdiskManager.Query().SubQuery() - q := disks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("disk_size_mb", disks.Field("disk_size"))) + q := disks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("disk_size_mb", disks.Field("disk_size")), sqlchemy.COUNT("disk_count")) q = q.Join(guestdisks, sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id"))) q = q.Filter(sqlchemy.In(guestdisks.Field("guest_id"), guestIds)) q = q.GroupBy(guestdisks.Field("guest_id")) @@ -228,21 +249,21 @@ func fetchGuestIPs(guestIds []string, virtual tristate.TriState) map[string][]st return ret } -func fetchGuestNICs(ctx context.Context, guestIds []string, virtual tristate.TriState) map[string]*jsonutils.JSONArray { +func fetchGuestNICs(ctx context.Context, guestIds []string, virtual tristate.TriState) map[string][]api.GuestnetworkShortDesc { q := GuestnetworkManager.Query().In("guest_id", guestIds) nics := make([]SGuestnetwork, 0) if err := q.All(&nics); err != nil { return nil } - ret := make(map[string]*jsonutils.JSONArray) + ret := make(map[string][]api.GuestnetworkShortDesc) for i := range nics { - desc := nics[i].GetShortDesc(ctx) - li := ret[nics[i].GuestId] - if li == nil { - li = jsonutils.NewArray(desc) - ret[nics[i].GuestId] = li + desc := api.GuestnetworkShortDesc{} + jsonDesc := nics[i].GetShortDesc(ctx) + jsonDesc.Unmarshal(&desc) + if _, ok := ret[nics[i].GuestId]; !ok { + ret[nics[i].GuestId] = []api.GuestnetworkShortDesc{desc} } else { - li.Add(desc) + ret[nics[i].GuestId] = append(ret[nics[i].GuestId], desc) } } return ret @@ -307,12 +328,7 @@ func fetchGuestVpcs(guestIds []string) map[string]sGuestVpcsInfo { return ret } -type sSecgroupInfo struct { - Id string - Name string -} - -func fetchSecgroups(guestIds []string) map[string][]sSecgroupInfo { +func fetchSecgroups(guestIds []string) map[string][]apis.StandaloneShortDesc { secgroups := SecurityGroupManager.Query().SubQuery() guestsecgroups := GuestsecgroupManager.Query().SubQuery() guests := GuestManager.Query().SubQuery() @@ -338,13 +354,13 @@ func fetchSecgroups(guestIds []string) map[string][]sSecgroupInfo { return nil } - ret := make(map[string][]sSecgroupInfo) + ret := make(map[string][]apis.StandaloneShortDesc) for i := range gsgs { gsg, ok := ret[gsgs[i].GuestId] if !ok { - gsg = make([]sSecgroupInfo, 0) + gsg = make([]apis.StandaloneShortDesc, 0) } - gsg = append(gsg, sSecgroupInfo{ + gsg = append(gsg, apis.StandaloneShortDesc{ Id: gsgs[i].SecgroupId, Name: gsgs[i].SecgroupName, }) @@ -405,49 +421,33 @@ func fetchGuestKeypairs(guestIds []string) map[string]sGuestKeypair { return ret } -func fetchGuestIsolatedDevices(guestIds []string) map[string][]SIsolatedDevice { +func fetchGuestIsolatedDevices(guestIds []string) map[string][]api.SIsolatedDevice { q := IsolatedDeviceManager.Query().In("guest_id", guestIds) devs := make([]SIsolatedDevice, 0) err := q.All(&devs) if err != nil { return nil } - ret := make(map[string][]SIsolatedDevice) + ret := make(map[string][]api.SIsolatedDevice) for i := range devs { + dev := api.SIsolatedDevice{} + dev.Id = devs[i].Id + dev.HostId = devs[i].HostId + dev.DevType = devs[i].DevType + dev.Model = devs[i].Model + dev.GuestId = devs[i].GuestId + dev.Addr = devs[i].Addr + dev.VendorDeviceId = devs[i].VendorDeviceId gdevs, ok := ret[devs[i].GuestId] if !ok { - gdevs = make([]SIsolatedDevice, 0) + gdevs = make([]api.SIsolatedDevice, 0) } - gdevs = append(gdevs, devs[i]) + gdevs = append(gdevs, dev) ret[devs[i].GuestId] = gdevs } return ret } -type isolatedDeviceInfo struct { - Id string - HostId string - Model string - DevType string - Addr string - VendorDeviceId string -} - -func getIsolatedDeviceDetails(devs []SIsolatedDevice) []isolatedDeviceInfo { - var res = make([]isolatedDeviceInfo, len(devs)) - for i, dev := range devs { - res[i] = isolatedDeviceInfo{ - Id: dev.Id, - HostId: dev.HostId, - Model: dev.Model, - DevType: dev.DevType, - Addr: dev.Addr, - VendorDeviceId: dev.VendorDeviceId, - } - } - return res -} - func fetchGuestCdroms(guestIds []string) map[string]SGuestcdrom { q := GuestcdromManager.Query().In("id", guestIds) gcds := make([]SGuestcdrom, 0) diff --git a/pkg/compute/models/guest_template.go b/pkg/compute/models/guest_template.go index d738b97ae0..f1070d16b5 100644 --- a/pkg/compute/models/guest_template.go +++ b/pkg/compute/models/guest_template.go @@ -23,6 +23,7 @@ import ( "yunion.io/x/pkg/util/sets" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" computeapis "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/cmdline" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -33,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -47,14 +49,27 @@ type SGuestTemplateManager struct { type SGuestTemplate struct { db.SSharableVirtualResourceBase - VcpuCount int `nullable:"false" default:"1" create:"optional"` - VmemSize int `nullable:"false" create:"optional"` - OsType string `width:"36" charset:"ascii" nullable:"true" create:"optional"` - ImageType string `width:"10" charset:"ascii" nullabel:"true" default:"normal" create:"optional"` - ImageId string `width:"128" charset:"ascii" create:"optional"` - Hypervisor string `width:"16" charset:"ascii" default:"kvm" create:"optional"` + // 虚拟机CPU数量 + VcpuCount int `nullable:"false" default:"1" create:"optional" json:"vcpu_count"` - Content jsonutils.JSONObject `nullable:"false" list:"user" update:"user" create:"optional"` + // 虚拟机内存大小(MB) + VmemSize int `nullable:"false" create:"optional" json:"vmem_size"` + + // 虚拟机操作系统类型 + // pattern:Linux|Windows|VMWare + OsType string `width:"36" charset:"ascii" nullable:"true" create:"optional" json:"os_type"` + + // 镜像类型 + ImageType string `width:"10" charset:"ascii" nullabel:"true" default:"normal" create:"optional" json:"image_type"` + + // 镜像ID + ImageId string `width:"128" charset:"ascii" create:"optional" json:"image_id"` + + // 虚拟机技术 + Hypervisor string `width:"16" charset:"ascii" default:"kvm" create:"optional" json:"hypervisor"` + + // 其他配置信息 + Content jsonutils.JSONObject `nullable:"false" list:"user" update:"user" create:"optional" json:"content"` } var GuestTemplateManager *SGuestTemplateManager @@ -177,15 +192,34 @@ func (gt *SGuestTemplate) ValidateUpdateData(ctx context.Context, userCred mccli return gt.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data) } -func (gt *SGuestTemplate) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (computeapis.GuesttemplateDetails, error) { - var err error - out := computeapis.GuesttemplateDetails{} - out.SharableVirtualResourceDetails, err = gt.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SGuestTemplateManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []computeapis.GuesttemplateDetails { + rows := make([]computeapis.GuesttemplateDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = computeapis.GuesttemplateDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + rows[i], _ = objs[i].(*SGuestTemplate).getMoreDetails(ctx, userCred, rows[i]) } - return gt.getMoreDetails(ctx, userCred, out) + + return rows +} + +func (gt *SGuestTemplate) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (computeapis.GuesttemplateDetails, error) { + return computeapis.GuesttemplateDetails{}, nil } func (gt *SGuestTemplate) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, @@ -331,7 +365,7 @@ func (gt *SGuestTemplate) getMoreDetails(ctx context.Context, userCred mcclient. } func (gt *SGuestTemplate) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + query jsonutils.JSONObject, data apis.PerformProjectPublicInput) (jsonutils.JSONObject, error) { // image, network, secgroup, instancegroup input, err := cmdline.FetchServerCreateInputByJSON(gt.Content) @@ -351,7 +385,7 @@ func (gt *SGuestTemplate) PerformPublic(ctx context.Context, userCred mcclient.T } } - targetScopeStr, _ := data.GetString("scope") + targetScopeStr := data.Scope targetScope := rbacutils.String2ScopeDefault(targetScopeStr, rbacutils.ScopeSystem) // check if secgroup is public @@ -443,10 +477,43 @@ func (gt *SGuestTemplate) ValidateDeleteCondition(ctx context.Context) error { } // 主机模板列表 -func (manager *SGuestTemplateManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input computeapis.GuestTemplateListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) +func (manager *SGuestTemplateManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input computeapis.GuestTemplateListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SGuestTemplateManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input computeapis.GuestTemplateListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SGuestTemplateManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/guestdisks.go b/pkg/compute/models/guestdisks.go index 32bca2910a..1f3a2f7bf6 100644 --- a/pkg/compute/models/guestdisks.go +++ b/pkg/compute/models/guestdisks.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SGuestdiskManager struct { @@ -109,28 +110,55 @@ func (joint *SGuestdisk) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (self *SGuestdisk) getExtraInfo(out api.GuestDiskDetails) api.GuestDiskDetails { - disk := self.GetDisk() - if storage := disk.GetStorage(); storage != nil { - out.StorageType = storage.StorageType - out.MediumType = storage.MediumType - } - out.DiskSize = disk.DiskSize - out.Status = disk.Status - out.DiskType = disk.DiskType - return out +func (self *SGuestdisk) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GuestDiskDetails, error) { + return api.GuestDiskDetails{}, nil } -func (self *SGuestdisk) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GuestDiskDetails, error) { - var err error - out := api.GuestDiskDetails{} - out.ModelBaseDetails, err = self.SGuestJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SGuestdiskManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GuestDiskDetails { + rows := make([]api.GuestDiskDetails, len(objs)) + + guestRows := manager.SGuestJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + diskIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GuestDiskDetails{ + GuestJointResourceDetails: guestRows[i], + } + diskIds[i] = objs[i].(*SGuestdisk).DiskId } - out.Guest, out.Disk = db.JointModelExtra(self) - out.Server = out.Guest - return self.getExtraInfo(out), nil + + disks := make(map[string]SDisk) + err := db.FetchStandaloneObjectsByIds(DiskManager, diskIds, &disks) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if disk, ok := disks[diskIds[i]]; ok { + rows[i].Disk = disk.Name + rows[i].DiskSize = disk.DiskSize + rows[i].DiskType = disk.DiskType + storage := disk.GetStorage() + if storage != nil { + rows[i].StorageType = storage.StorageType + rows[i].MediumType = storage.MediumType + } + } + } + + return rows } func (self *SGuestdisk) DoSave(driver string, cache string, mountpoint string) error { diff --git a/pkg/compute/models/guestjoints.go b/pkg/compute/models/guestjoints.go index 648f27a0c4..610b5e6630 100644 --- a/pkg/compute/models/guestjoints.go +++ b/pkg/compute/models/guestjoints.go @@ -14,7 +14,18 @@ package models -import "yunion.io/x/onecloud/pkg/cloudcommon/db" +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/reflectutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) type SGuestJointsManager struct { db.SVirtualJointResourceBaseManager @@ -47,3 +58,52 @@ func (self *SGuestJointsBase) getGuest() *SGuest { func (manager *SGuestJointsManager) GetMasterFieldName() string { return "guest_id" } + +func (self *SGuestJointsBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GuestJointResourceDetails, error) { + return api.GuestJointResourceDetails{}, nil +} + +func (manager *SGuestJointsManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GuestJointResourceDetails { + rows := make([]api.GuestJointResourceDetails, len(objs)) + + jointRows := manager.SVirtualJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + guestIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GuestJointResourceDetails{ + VirtualJointResourceBaseDetails: jointRows[i], + } + var base *SGuestJointsBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.GuestId) > 0 { + guestIds[i] = base.GuestId + } + } + + guestIdMaps, err := db.FetchIdNameMap2(GuestManager, guestIds) + if err != nil { + log.Errorf("db.FetchIdNameMap2 fail %s", err) + return rows + } + + for i := range rows { + if name, ok := guestIdMaps[guestIds[i]]; ok { + rows[i].Guest = name + rows[i].Server = name + } + } + + return rows +} diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index 1f1a61c8bb..2e7ea325bb 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -38,6 +38,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -99,16 +100,47 @@ func (joint *SGuestnetwork) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (self *SGuestnetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GuestnetworkDetails, error) { - var err error - out := api.GuestnetworkDetails{} - out.ModelBaseDetails, err = self.SGuestJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SGuestnetwork) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GuestnetworkDetails, error) { + return api.GuestnetworkDetails{}, nil +} + +func (manager SGuestnetworkManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GuestnetworkDetails { + rows := make([]api.GuestnetworkDetails, len(objs)) + + guestRows := manager.SGuestJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + netIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GuestnetworkDetails{ + GuestJointResourceDetails: guestRows[i], + } + netIds[i] = objs[i].(*SGuestnetwork).NetworkId } - out.Server, out.Network = db.JointModelExtra(self) - out.Guest = out.Server - return out, nil + + netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds) + if err != nil { + log.Errorf("FetchIdNameMap2 fail %s", err) + return rows + } + + for i := range rows { + if name, ok := netIdMaps[netIds[i]]; ok { + rows[i].Network = name + } + } + + return rows } func (manager *SGuestnetworkManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -766,19 +798,19 @@ func (manager *SGuestnetworkManager) FetchByIdsAndIpMac(guestId string, netId st } func (self *SGuestnetwork) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { - desc := jsonutils.NewDict() + desc := api.GuestnetworkShortDesc{} if len(self.IpAddr) > 0 { - desc.Add(jsonutils.NewString(self.IpAddr), "ip_addr") - desc.Add(jsonutils.NewBool(self.IsExit()), "is_exit") + desc.IpAddr = self.IpAddr + desc.IsExit = self.IsExit() } if len(self.Ip6Addr) > 0 { - desc.Add(jsonutils.NewString(self.Ip6Addr), "ip6_addr") + desc.Ip6Addr = self.Ip6Addr } - desc.Add(jsonutils.NewString(self.MacAddr), "mac") + desc.Mac = self.MacAddr if len(self.TeamWith) > 0 { - desc.Add(jsonutils.NewString(self.TeamWith), "team_with") + desc.TeamWith = self.TeamWith } - return desc + return jsonutils.Marshal(desc).(*jsonutils.JSONDict) } func (self *SGuestnetwork) ToNetworkConfig() *api.NetworkConfig { diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index cb54d43da8..b9c305d9c2 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -66,6 +66,11 @@ import ( type SGuestManager struct { db.SVirtualResourceBaseManager + + SHostResourceBaseManager + SBillingResourceBaseManager + SNetworkResourceBaseManager + SDiskResourceBaseManager } var GuestManager *SGuestManager @@ -91,6 +96,8 @@ type SGuest struct { SBillingResourceBase SDeletePreventableResourceBase + SHostResourceBase + // CPU大小 VcpuCount int `nullable:"false" default:"1" list:"user" create:"optional"` // 内存大小, 单位Mb @@ -107,7 +114,8 @@ type SGuest struct { KeypairId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 宿主机Id - HostId string `width:"36" charset:"ascii" nullable:"true" list:"admin" get:"admin" index:"true"` + //HostId string `width:"36" charset:"ascii" nullable:"true" list:"admin" get:"admin" index:"true"` + // 备份机所在宿主机Id BackupHostId string `width:"36" charset:"ascii" nullable:"true" list:"user" get:"user"` @@ -147,28 +155,22 @@ func (manager *SGuestManager) AllowListItems(ctx context.Context, userCred mccli } // 云主机实例列表 -func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ServerListInput) (*sqlchemy.SQuery, error) { +func (manager *SGuestManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ServerListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "host_id", func() *sqlchemy.SQuery { - hosts := HostManager.Query().SubQuery() - return hosts.Query(hosts.Field("id")) - }) + + q, err = manager.SHostResourceBaseManager.ListItemFilter(ctx, q, userCred, query.HostFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SHostResourceBaseManager.ListItemFilter") } - billingTypeStr := query.BillingType - if len(billingTypeStr) > 0 { - if billingTypeStr == billing_api.BILLING_TYPE_POSTPAID { - q = q.Filter( - sqlchemy.OR( - sqlchemy.IsNullOrEmpty(q.Field("billing_type")), - sqlchemy.Equals(q.Field("billing_type"), billingTypeStr), - ), - ) - } else { - q = q.Equals("billing_type", billingTypeStr) - } + q, err = manager.SBillingResourceBaseManager.ListItemFilter(ctx, q, userCred, query.BillingResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SBillingResourceBaseManager.ListItemFilter") } q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) @@ -176,6 +178,24 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } + netQ := GuestnetworkManager.Query("guest_id").Snapshot() + netQ, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, netQ, userCred, query.NetworkFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter") + } + if netQ.IsAltered() { + q = q.In("id", netQ.SubQuery()) + } + + diskQ := GuestdiskManager.Query("guest_id").Snapshot() + diskQ, err = manager.SDiskResourceBaseManager.ListItemFilter(ctx, diskQ, userCred, query.DiskFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDiskResourceBaseManager.ListItemFilter") + } + if diskQ.IsAltered() { + q = q.In("id", diskQ.SubQuery()) + } + hypervisorList := query.Hypervisor if len(hypervisorList) > 0 { q = q.In("hypervisor", hypervisorList) @@ -238,7 +258,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ } isAdmin := false - admin := (query.Admin != nil && *query.Admin) + admin := (query.VirtualResourceListInput.Admin != nil && *query.VirtualResourceListInput.Admin) if consts.IsRbacEnabled() { allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList) if allowScope == rbacutils.ScopeSystem || allowScope == rbacutils.ScopeDomain { @@ -294,69 +314,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ q = q.In("host_id", sq) } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "host_id", func() *sqlchemy.SQuery { - hostTable := HostManager.Query().SubQuery() - zoneTable := ZoneManager.Query().SubQuery() - sq := hostTable.Query(hostTable.Field("id")) - sq = sq.Join(zoneTable, sqlchemy.Equals(zoneTable.Field("id"), hostTable.Field("zone_id"))) - return sq - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "host_id", func() *sqlchemy.SQuery { - hostTable := HostManager.Query().SubQuery() - return hostTable.Query(hostTable.Field("id")) - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") - } - - wireFilter := query.Wire - if len(wireFilter) > 0 { - wire, _ := WireManager.FetchByIdOrName(nil, wireFilter) - if wire == nil { - return nil, httperrors.NewResourceNotFoundError("wire %s not found", wireFilter) - } - hostTable := HostManager.Query().SubQuery() - hostWire := HostwireManager.Query().SubQuery() - sq := hostTable.Query(hostTable.Field("id")).Join(hostWire, sqlchemy.Equals(hostWire.Field("host_id"), hostTable.Field("id"))).Filter(sqlchemy.Equals(hostWire.Field("wire_id"), wire.GetId())).SubQuery() - q = q.In("host_id", sq) - } - - networkFilter := query.Network - if len(networkFilter) > 0 { - netI, _ := NetworkManager.FetchByIdOrName(userCred, networkFilter) - if netI == nil { - return nil, httperrors.NewResourceNotFoundError("network %s not found", networkFilter) - } - net := netI.(*SNetwork) - hostTable := HostManager.Query().SubQuery() - hostWire := HostwireManager.Query().SubQuery() - sq := hostTable.Query(hostTable.Field("id")).Join(hostWire, - sqlchemy.Equals(hostWire.Field("host_id"), hostTable.Field("id"))).Filter(sqlchemy.Equals(hostWire.Field("wire_id"), net.WireId)).SubQuery() - q = q.In("host_id", sq) - } - - vpcFilter := query.Vpc - if len(vpcFilter) > 0 { - IVpc, err := VpcManager.FetchByIdOrName(userCred, vpcFilter) - if err != nil { - return nil, httperrors.NewResourceNotFoundError("Vpc %s not found", vpcFilter) - } - vpc := IVpc.(*SVpc) - guestnetwork := GuestnetworkManager.Query().SubQuery() - network := NetworkManager.Query().SubQuery() - wire := WireManager.Query().SubQuery() - sq := guestnetwork.Query(guestnetwork.Field("guest_id")).Join(network, - sqlchemy.Equals(guestnetwork.Field("network_id"), network.Field("id"))). - Join(wire, sqlchemy.Equals(network.Field("wire_id"), wire.Field("id"))). - Filter(sqlchemy.Equals(wire.Field("vpc_id"), vpc.Id)).SubQuery() - q = q.In("id", sq) - } - - diskFilter := query.Disk + /*diskFilter := query.Disk if len(diskFilter) > 0 { diskI, _ := DiskManager.FetchByIdOrName(userCred, diskFilter) if diskI == nil { @@ -381,7 +339,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ Filter(sqlchemy.Equals(storages.Field("id"), disk.StorageId)).SubQuery() q = q.In("host_id", sq) } - } + }*/ withEip := (query.WithEip != nil && *query.WithEip) withoutEip := (query.WithoutEip != nil && *query.WithoutEip) @@ -421,7 +379,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ q = q.Join(ggSub, sqlchemy.Equals(ggSub.Field("guest_id"), q.Field("id"))) } - orderByDisk := query.OrderByDisk + /*orderByDisk := query.OrderByDisk if orderByDisk == "asc" || orderByDisk == "desc" { guestdisks := GuestdiskManager.Query().SubQuery() disks := DiskManager.Query().SubQuery() @@ -440,24 +398,10 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ case "desc": q = q.Desc(guestdiskSQ.Field("disks_size")) } - } + }*/ - hostSNFilter := query.HostSn - if len(hostSNFilter) > 0 { - hosts := HostManager.Query().SubQuery() - sq := hosts.Query(hosts.Field("id")).Filter(sqlchemy.Equals(hosts.Field("sn"), hostSNFilter)).SubQuery() - q = q.In("host_id", sq) - } - - orderByHost := query.OrderByHost - if orderByHost == "asc" { - hosts := HostManager.Query().SubQuery() - q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))). - Asc(hosts.Field("name")) - } else if orderByHost == "desc" { - hosts := HostManager.Query().SubQuery() - q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))). - Desc(hosts.Field("name")) + if len(query.OsType) > 0 { + q = q.Equals("os_type", query.OsType) } return q, nil @@ -476,25 +420,36 @@ func (manager *SGuestManager) ExtraSearchConditions(ctx context.Context, q *sqlc return nil } -func (manager *SGuestManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - q, err := manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query) +func (manager *SGuestManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ServerListInput) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") } - orderByAccount, _ := query.GetString("order_by_account") - if sqlchemy.SQL_ORDER_ASC.Equals(orderByAccount) || sqlchemy.SQL_ORDER_DESC.Equals(orderByAccount) { - hosts := HostManager.Query().SubQuery() - cloudproviders := CloudproviderManager.Query().SubQuery() - cloudaccounts := CloudaccountManager.Query().SubQuery() - q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))) - q = q.Join(cloudproviders, sqlchemy.Equals(hosts.Field("manager_id"), cloudproviders.Field("id"))) - q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id"))) - if sqlchemy.SQL_ORDER_ASC.Equals(orderByAccount) { - q = q.Asc(cloudaccounts.Field("name")) - } else { - q = q.Desc(cloudaccounts.Field("name")) + q, err = manager.SHostResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.HostFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SHostResourceBaseManager.OrderByExtraFields") + } + fields := manager.SNetworkResourceBaseManager.GetOrderByFields(query.NetworkFilterListInput) + if db.NeedOrderQuery(fields) { + netQ := GuestnetworkManager.Query("guest_id", "network_id").SubQuery() + q = q.LeftJoin(netQ, sqlchemy.Equals(q.Field("id"), netQ.Field("guest_id"))).Distinct() + q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields") } } + fields = manager.SDiskResourceBaseManager.GetOrderByFields(query.DiskFilterListInput) + if db.NeedOrderQuery(fields) { + diskQ := GuestdiskManager.Query("guest_id", "disk_id").SubQuery() + q = q.LeftJoin(diskQ, sqlchemy.Equals(q.Field("id"), diskQ.Field("guest_id"))).Distinct() + q, err = manager.SDiskResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.DiskFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SDiskResourceBaseManager.OrderByExtraFields") + } + } + return q, nil } @@ -504,20 +459,23 @@ func (manager *SGuestManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field if err == nil { return q, nil } - switch field { - case "account": - hosts := HostManager.Query().SubQuery() - cloudproviders := CloudproviderManager.Query().SubQuery() - cloudaccounts := CloudaccountManager.Query("name", "id").Distinct().SubQuery() - q = q.Join(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))) - q = q.Join(cloudproviders, sqlchemy.Equals(hosts.Field("manager_id"), cloudproviders.Field("id"))) - q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id"))) - q.GroupBy(cloudaccounts.Field("name")) - q.AppendField(cloudaccounts.Field("name", "account")) - default: - return q, httperrors.NewBadRequestError("unsupport field %s", field) + q, err = manager.SHostResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil } - return q, nil + guestnets := GuestnetworkManager.Query("guest_id", "network_id").SubQuery() + q = q.LeftJoin(guestnets, sqlchemy.Equals(q.Field("id"), guestnets.Field("guest_id"))) + q, err = manager.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + guestdisks := GuestdiskManager.Query("guest_id", "disk_id").SubQuery() + q = q.LeftJoin(guestdisks, sqlchemy.Equals(q.Field("id"), guestdisks.Field("guest_id"))) + q, err = manager.SDiskResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound } func (guest *SGuest) GetHypervisor() string { @@ -557,7 +515,7 @@ func (guest *SGuest) ValidatePurgeCondition(ctx context.Context) error { func (guest *SGuest) ValidateDeleteCondition(ctx context.Context) error { host := guest.GetHost() if host != nil && guest.GetHypervisor() != api.HYPERVISOR_BAREMETAL { - if !host.Enabled { + if !host.GetEnabled() { return httperrors.NewInputParameterError("Cannot delete server on disabled host") } if host.HostStatus != api.HOST_ONLINE { @@ -1611,79 +1569,16 @@ func (self *SGuest) getExtBandwidth() int { return self.getBandwidth(true) } -func (self *SGuest) moreExtraInfo(out api.ServerDetails, fields stringutils2.SSortedStrings) api.ServerDetails { +func (self *SGuest) moreExtraInfo( + out api.ServerDetails, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + fields stringutils2.SSortedStrings, + isList bool, +) api.ServerDetails { // extra.Add(jsonutils.NewInt(int64(self.getExtBandwidth())), "ext_bw") - out.IsPrepaidRecycle = self.IsPrepaidRecycle() - - if len(self.BackupHostId) > 0 && (len(fields) == 0 || fields.Contains("backup_host_name") || fields.Contains("backup_host_status")) { - backupHost := HostManager.FetchHostById(self.BackupHostId) - if len(fields) == 0 || fields.Contains("backup_host_name") { - out.BackupHostName = backupHost.Name - } - if len(fields) == 0 || fields.Contains("backup_host_status") { - out.BackupHostStatus = backupHost.HostStatus - } - } - - if len(fields) == 0 || fields.Contains("host") || fields.ContainsAny(providerInfoFields...) || fields.Contains("host_sn") { - host := self.GetHost() - if host != nil { - if len(fields) == 0 || fields.Contains("host") { - out.Host = host.Name - } - if len(fields) == 0 || fields.ContainsAny(providerInfoFields...) { - info := host.getCloudProviderInfo() - if len(fields) == 0 { - out.CloudproviderInfo = info - } else { - jsonutils.Update(&out, jsonutils.Marshal(&info).(*jsonutils.JSONDict).CopyIncludes([]string(fields)...)) - } - } - if len(fields) == 0 || fields.Contains("host_sn") { - out.HostSN = host.SN - } - } - } - - if len(fields) == 0 || fields.Contains("can_recycle") { - err := self.CanPerformPrepaidRecycle() - if err == nil { - out.CanRecycle = true - } - } - - if len(fields) == 0 || fields.Contains("auto_delete_at") { - if self.PendingDeleted { - pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) - out.AutoDeleteAt = pendingDeletedAt - } - } - - out.Metadata, _ = db.GetVisiableMetadata(self, nil) - out.DiskCount = self.GetDisksQuery().Count() - out.CdromSupport, _ = self.GetDriver().IsSupportCdrom(self) - - return out -} - -func (self *SGuest) GetMetadataHideKeys() []string { - return []string{ - api.VM_METADATA_CREATE_PARAMS, - } -} - -func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ServerDetails, error) { - var err error - out := api.ServerDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - - var fields stringutils2.SSortedStrings if isList { - fields = stringutils2.NewSortedStrings(jsonutils.GetQueryStringArray(query, "field")) if query.Contains("group") { groupId, _ := query.GetString("group") q := GroupguestManager.Query().Equals("group_id", groupId).Equals("guest_id", self.Id) @@ -1713,12 +1608,51 @@ func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.Token } } - return self.moreExtraInfo(out, fields), nil + + out.IsPrepaidRecycle = self.IsPrepaidRecycle() + + if len(self.BackupHostId) > 0 && (len(fields) == 0 || fields.Contains("backup_host_name") || fields.Contains("backup_host_status")) { + backupHost := HostManager.FetchHostById(self.BackupHostId) + if len(fields) == 0 || fields.Contains("backup_host_name") { + out.BackupHostName = backupHost.Name + } + if len(fields) == 0 || fields.Contains("backup_host_status") { + out.BackupHostStatus = backupHost.HostStatus + } + } + + if len(fields) == 0 || fields.Contains("can_recycle") { + err := self.CanPerformPrepaidRecycle() + if err == nil { + out.CanRecycle = true + } + } + + if len(fields) == 0 || fields.Contains("auto_delete_at") { + if self.PendingDeleted { + pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) + out.AutoDeleteAt = pendingDeletedAt + } + } + + out.CdromSupport, _ = self.GetDriver().IsSupportCdrom(self) + + return out +} + +func (self *SGuestManager) GetMetadataHiddenKeys() []string { + return []string{ + api.VM_METADATA_CREATE_PARAMS, + } +} + +func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ServerDetails, error) { + return api.ServerDetails{}, nil } func (manager *SGuestManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { var err error - q, err = manager.SModelBaseManager.ListItemExportKeys(ctx, q, userCred, query) + q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, query) if err != nil { return nil, err } @@ -1809,7 +1743,7 @@ func (manager *SGuestManager) ListItemExportKeys(ctx context.Context, q *sqlchem } func (manager *SGuestManager) GetExportExtraKeys(ctx context.Context, query jsonutils.JSONObject, rowMap map[string]string) *jsonutils.JSONDict { - res := manager.SStatusStandaloneResourceBaseManager.GetExportExtraKeys(ctx, query, rowMap) + res := manager.SVirtualResourceBaseManager.GetExportExtraKeys(ctx, query, rowMap) exportKeys, _ := query.GetString("export_keys") keys := strings.Split(exportKeys, ",") if ips, ok := rowMap["concat_ip_addr"]; ok && len(ips) > 0 { @@ -4030,7 +3964,7 @@ func (self *SGuest) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { if host != nil { desc.Set("host", jsonutils.NewString(host.Name)) desc.Set("host_id", jsonutils.NewString(host.Id)) - billingInfo.CloudproviderInfo = host.getCloudProviderInfo() + billingInfo.SCloudProviderInfo = host.getCloudProviderInfo() } if priceKey := self.GetMetadata("ext:price_key", nil); len(priceKey) > 0 { diff --git a/pkg/compute/models/helper.go b/pkg/compute/models/helper.go index 0c317f1ecc..d0fb998445 100644 --- a/pkg/compute/models/helper.go +++ b/pkg/compute/models/helper.go @@ -90,7 +90,7 @@ func ValidateScheduleCreateData(ctx context.Context, userCred mcclient.TokenCred } } baremetal := bmObj.(*SHost) - if !baremetal.Enabled { + if !baremetal.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Baremetal %s not enabled", bmName) } diff --git a/pkg/compute/models/host_recycle.go b/pkg/compute/models/host_recycle.go index 4e96cfe972..92c8a1355e 100644 --- a/pkg/compute/models/host_recycle.go +++ b/pkg/compute/models/host_recycle.go @@ -166,7 +166,7 @@ func (self *SGuest) doPrepaidRecycleNoLock(ctx context.Context, userCred mcclien fakeHost.Status = api.HOST_STATUS_RUNNING fakeHost.HostStatus = api.HOST_ONLINE - fakeHost.Enabled = true + fakeHost.SetEnabled(true) fakeHost.HostType = oHost.HostType fakeHost.ExternalId = oHost.ExternalId fakeHost.RealExternalId = self.ExternalId @@ -311,7 +311,7 @@ func (self *SGuest) PerformUndoPrepaidRecycle(ctx context.Context, userCred mccl return nil, httperrors.NewInvalidStatusError("no valid host") } - if host.Enabled { + if host.GetEnabled() { return nil, httperrors.NewInvalidStatusError("host should be disabled") } @@ -336,7 +336,7 @@ func (self *SHost) AllowPerformUndoPrepaidRecycle(ctx context.Context, userCred } func (self *SHost) PerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if self.Enabled { + if self.GetEnabled() { return nil, httperrors.NewInvalidStatusError("host should be disabled") } diff --git a/pkg/compute/models/hostjoints.go b/pkg/compute/models/hostjoints.go index 6c97d88fce..7c14d9bc01 100644 --- a/pkg/compute/models/hostjoints.go +++ b/pkg/compute/models/hostjoints.go @@ -19,8 +19,10 @@ import ( "yunion.io/x/jsonutils" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostJointsManager struct { @@ -71,3 +73,33 @@ func (self *SHostJointsBase) AllowUpdateItem(ctx context.Context, userCred mccli func (self *SHostJointsBase) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowDelete(userCred, self) } + +func (self *SHostJointsBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.HostJointResourceDetails, error) { + return api.HostJointResourceDetails{}, nil +} + +func (manager *SHostJointsManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostJointResourceDetails { + rows := make([]api.HostJointResourceDetails, len(objs)) + + jointRows := manager.SJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.HostJointResourceDetails{ + JointResourceBaseDetails: jointRows[i], + } + } + + return rows +} diff --git a/pkg/compute/models/hostnetworks.go b/pkg/compute/models/hostnetworks.go index bde1ddbdeb..6d16700781 100644 --- a/pkg/compute/models/hostnetworks.go +++ b/pkg/compute/models/hostnetworks.go @@ -18,11 +18,13 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostnetworkManager struct { @@ -71,20 +73,71 @@ func (bn *SHostnetwork) Slave() db.IStandaloneModel { return db.JointSlave(bn) } -func (bn *SHostnetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HostnetworkDetails, error) { - var err error - out := api.HostnetworkDetails{} - out.ModelBaseDetails, err = bn.SHostJointsBase.GetExtraDetails(ctx, userCred, query, isList) +func (bn *SHostnetwork) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.HostnetworkDetails, error) { + return api.HostnetworkDetails{}, nil +} + +func (manager *SHostnetworkManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostnetworkDetails { + rows := make([]api.HostnetworkDetails, len(objs)) + + hostRows := manager.SHostJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + hostIds := make([]string, len(rows)) + netIds := make([]string, len(rows)) + macIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = api.HostnetworkDetails{ + HostJointResourceDetails: hostRows[i], + } + hostIds[i] = objs[i].(*SHostnetwork).BaremetalId + netIds[i] = objs[i].(*SHostnetwork).NetworkId + macIds[i] = objs[i].(*SHostnetwork).MacAddr + } + + hostIdMaps, err := db.FetchIdNameMap2(HostManager, hostIds) if err != nil { - return out, err + log.Errorf("FetchIdNameMap2 hostIds fail %s", err) + return rows } - out.Host, out.Network = db.JointModelExtra(bn) - out.Baremetal = out.Host - netif := bn.GetNetInterface() - if netif != nil { - out.NicType = netif.NicType + netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds) + if err != nil { + log.Errorf("FetchIdNameMap2 netIds fail %s", err) + return rows } - return out, nil + netifs := make(map[string]SNetInterface) + netifQ := NetInterfaceManager.Query("mac", "nic_type") + err = db.FetchQueryObjectsByIds(netifQ, "mac", macIds, &netifs) + if err != nil { + log.Errorf("FetchQueryObjectsByIds macIds fail %s", err) + return rows + } + + for i := range rows { + if name, ok := hostIdMaps[hostIds[i]]; ok { + rows[i].Host = name + rows[i].Baremetal = name + } + if name, ok := netIdMaps[netIds[i]]; ok { + rows[i].Network = name + } + if netif, ok := netifs[macIds[i]]; ok { + rows[i].NicType = netif.NicType + } + } + + return rows } func (bn *SHostnetwork) GetHost() *SHost { diff --git a/pkg/compute/models/hostresource.go b/pkg/compute/models/hostresource.go new file mode 100644 index 0000000000..4bb98bea2b --- /dev/null +++ b/pkg/compute/models/hostresource.go @@ -0,0 +1,225 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SHostResourceBase struct { + HostId string `width:"36" charset:"ascii" nullable:"true" list:"user" index:"true" create:"optional"` +} + +type SHostResourceBaseManager struct { + SZoneResourceBaseManager + SManagedResourceBaseManager +} + +func (self *SHostResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.HostResourceInfo { + return api.HostResourceInfo{} +} + +func (manager *SHostResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostResourceInfo { + rows := make([]api.HostResourceInfo, len(objs)) + hostIds := make([]string, len(objs)) + for i := range objs { + var base *SHostResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + hostIds[i] = base.HostId + } + } + + hosts := make(map[string]SHost) + err := db.FetchStandaloneObjectsByIds(HostManager, hostIds, hosts) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + zoneList := make([]interface{}, len(rows)) + managerList := make([]interface{}, len(rows)) + + for i := range rows { + rows[i] = api.HostResourceInfo{} + if _, ok := hosts[hostIds[i]]; ok { + host := hosts[hostIds[i]] + rows[i].Host = host.Name + rows[i].HostSN = host.SN + rows[i].HostStatus = host.Status + rows[i].HostServiceStatus = host.HostStatus + rows[i].HostType = host.HostType + rows[i].ManagerId = host.ManagerId + rows[i].ZoneId = host.ZoneId + } + zoneList[i] = &SZoneResourceBase{rows[i].ZoneId} + managerList[i] = &SManagedResourceBase{rows[i].ManagerId} + } + + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList) + for i := range rows { + rows[i].ZoneResourceInfo = zoneRows[i] + rows[i].ManagedResourceInfo = managerRows[i] + } + + return rows +} + +func (manager *SHostResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.HostFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Host) > 0 { + hostObj, err := HostManager.FetchByIdOrName(userCred, query.Host) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), query.Host) + } else { + return nil, errors.Wrap(err, "HostManager.FetchByIdOrName") + } + } + q = q.Equals("host_id", hostObj.GetId()) + } + if len(query.HostSN) > 0 { + sq := HostManager.Query("id").Equals("sn", query.HostSN).SubQuery() + q = q.In("host_id", sq) + } + subq := HostManager.Query("id").Snapshot() + subq, err := manager.SZoneResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + subq, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("host_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SHostResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "host": + hostQuery := HostManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(hostQuery.Field("name", field)) + q = q.Join(hostQuery, sqlchemy.Equals(q.Field("host_id"), hostQuery.Field("id"))) + q.GroupBy(hostQuery.Field("name")) + return q, nil + case "host_type": + hostQuery := HostManager.Query(field, "id").Distinct().SubQuery() + q.AppendField(hostQuery.Field(field)) + q = q.Join(hostQuery, sqlchemy.Equals(q.Field("host_id"), hostQuery.Field("id"))) + q.GroupBy(hostQuery.Field(field)) + return q, nil + case "manager", "account", "provider", "brand": + hosts := HostManager.Query("id", "manager_id").SubQuery() + q = q.LeftJoin(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))) + return manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + default: + hosts := HostManager.Query("id", "zone_id").SubQuery() + q = q.LeftJoin(hosts, sqlchemy.Equals(q.Field("host_id"), hosts.Field("id"))) + q, err := manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SHostResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.HostFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SHostResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.HostFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + hostQ := HostManager.Query("id", "name", "sn") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + hostQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(hostQ, userCred, query.ZonalFilterListInput) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + if db.NeedOrderQuery(manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput)) { + var manOrders []string + var manFields []sqlchemy.IQueryField + hostQ, manOrders, manFields = manager.SManagedResourceBaseManager.GetOrderBySubQuery(hostQ, userCred, query.ManagedResourceListInput) + if len(manOrders) > 0 { + orders = append(orders, manOrders...) + fields = append(fields, manFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := hostQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("host_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByHost, query.OrderByHostSN}) { + orders = append(orders, query.OrderByHost, query.OrderByHostSN) + fields = append(fields, subq.Field("name"), subq.Field("sn")) + } + } + return q, orders, fields +} + +func (manager *SHostResourceBaseManager) GetOrderByFields(query api.HostFilterListInput) []string { + fields := make([]string, 0) + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput) + fields = append(fields, zoneFields...) + manFields := manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput) + fields = append(fields, manFields...) + fields = append(fields, query.OrderByHost, query.OrderByHostSN) + return fields +} diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 09f59c08bc..641df3f8e7 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -54,10 +54,13 @@ import ( "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/redfish/bmconsole" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostManager struct { db.SEnabledStatusStandaloneResourceBaseManager + SZoneResourceBaseManager + SManagedResourceBaseManager } var HostManager *SHostManager @@ -78,7 +81,7 @@ func init() { type SHost struct { db.SEnabledStatusStandaloneResourceBase db.SExternalizedResourceBase - + SZoneResourceBase SManagedResourceBase SBillingResourceBase @@ -146,7 +149,7 @@ type SHost struct { // 可用区Id // example: zone1 - ZoneId string `width:"128" charset:"ascii" nullable:"true" list:"admin" update:"admin" create:"admin_optional"` + // ZoneId string `width:"128" charset:"ascii" nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // 宿主机类型 HostType string `width:"36" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"admin_required"` @@ -179,37 +182,23 @@ func (manager *SHostManager) GetContextManagers() [][]db.IModelManager { } } -func (self *SHostManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SHostManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SHost) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SHost) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SHost) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - // 宿主机/物理机列表 -func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.HostListInput) (*sqlchemy.SQuery, error) { +func (manager *SHostManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.HostListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } resType := query.ResourceType @@ -285,18 +274,6 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu } } - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") - } - - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "zone_id", func() *sqlchemy.SQuery { - return ZoneManager.Query("id") - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - hypervisorStr := query.Hypervisor if len(hypervisorStr) > 0 { hostType, ok := api.HYPERVISOR_HOSTTYPE[hypervisorStr] @@ -374,6 +351,45 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } +func (manager *SHostManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.HostListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SHostManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (manager *SHostManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*db.CustomizeListFilters, error) { filters := db.NewCustomizeListFilters() @@ -493,7 +509,7 @@ func (self *SHost) validateDeleteCondition(ctx context.Context, purge bool) erro if !purge && self.IsBaremetal && self.HostType != api.HOST_TYPE_BAREMETAL { return httperrors.NewInvalidStatusError("Host is a converted baremetal, should be unconverted before delete") } - if self.Enabled { + if self.GetEnabled() { return httperrors.NewInvalidStatusError("Host is not disabled") } cnt, err := self.GetGuestCount() @@ -902,7 +918,7 @@ func (man *SHostManager) GetSpecShouldCheckStatus(query *jsonutils.JSONDict) (bo func (self *SHost) GetSpec(statusCheck bool) *jsonutils.JSONDict { if statusCheck { - if !self.Enabled { + if !self.GetEnabled() { return nil } if utils.IsInStringArray(self.Status, []string{api.BAREMETAL_INIT, api.BAREMETAL_PREPARE_FAIL, api.BAREMETAL_PREPARE}) || @@ -1436,7 +1452,7 @@ func (self *SHost) syncRemoveCloudHost(ctx context.Context, userCred mcclient.To if err != nil { err = self.SetStatus(userCred, api.HOST_OFFLINE, "sync to delete") if err == nil { - _, err = self.PerformDisable(ctx, userCred, nil, nil) + _, err = self.PerformDisable(ctx, userCred, nil, apis.PerformDisableInput{}) } guests := self.GetGuests() for _, guest := range guests { @@ -1483,7 +1499,7 @@ func (self *SHost) syncWithCloudHost(ctx context.Context, userCred mcclient.Toke } self.IsEmulated = extHost.IsEmulated() - self.Enabled = extHost.GetEnabled() + self.SetEnabled(extHost.GetEnabled()) self.IsMaintenance = extHost.GetIsMaintenance() self.Version = extHost.GetVersion() @@ -1561,7 +1577,7 @@ func (manager *SHostManager) newFromCloudHost(ctx context.Context, userCred mccl host.Status = extHost.GetStatus() host.HostStatus = extHost.GetHostStatus() - host.Enabled = extHost.GetEnabled() + host.SetEnabled(extHost.GetEnabled()) host.AccessIp = extHost.GetAccessIp() host.AccessMac = extHost.GetAccessMac() @@ -2351,7 +2367,6 @@ func (self *SHost) getGuestsResource(status string) *SHostGuestResourceUsage { } func (self *SHost) getMoreDetails(ctx context.Context, out api.HostDetails) api.HostDetails { - out.CloudproviderInfo = self.getCloudProviderInfo() server := self.GetBaremetalServer() if server != nil { @@ -2434,22 +2449,35 @@ func (self *SHost) getMoreDetails(ctx context.Context, out api.HostDetails) api. return out } -func (self *SHost) GetMetadataHideKeys() []string { +func (self *SHost) GetMetadataHiddenKeys() []string { return []string{} } func (self *SHost) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HostDetails, error) { - var err error - out := api.HostDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.HostDetails{}, nil +} + +func (manager *SHostManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostDetails { + rows := make([]api.HostDetails, len(objs)) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.HostDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: managerRows[i], + ZoneResourceInfo: zoneRows[i], + } + rows[i] = objs[i].(*SHost).getMoreDetails(ctx, rows[i]) } - out.Metadata, err = db.GetVisiableMetadata(self, nil) - if err != nil { - return out, err - } - return self.getMoreDetails(ctx, out), nil + return rows } func (self *SHost) AllowGetDetailsVnc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -2728,7 +2756,7 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc return nil, errors.Wrap(err, "net.reserveIpWithDuration") } } - zoneObj := net.getZone() + zoneObj := net.GetZone() if zoneObj == nil { return nil, httperrors.NewInputParameterError("IPMI network has no zone???") } @@ -2794,7 +2822,7 @@ func (manager *SHostManager) ValidateCreateData(ctx context.Context, userCred mc return nil, httperrors.NewConflictError("Access ip %s has been used", accessIpAddr) } - zoneObj := accessNet.getZone() + zoneObj := accessNet.GetZone() if zoneObj == nil { return nil, httperrors.NewInputParameterError("Access network has no zone???") } @@ -2868,7 +2896,7 @@ func (self *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.Tok if net == nil { return nil, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr) } - zoneObj := net.getZone() + zoneObj := net.GetZone() if zoneObj == nil { return nil, httperrors.NewInputParameterError("IPMI network has not zone???") } @@ -3872,21 +3900,21 @@ func (self *SHost) AllowPerformEnable( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject, + input apis.PerformEnableInput, ) bool { - return self.SEnabledStatusStandaloneResourceBase.AllowPerformEnable(ctx, userCred, query, data) + return self.SEnabledStatusStandaloneResourceBase.AllowPerformEnable(ctx, userCred, query, input) } func (self *SHost) PerformEnable( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject, + input apis.PerformEnableInput, ) (jsonutils.JSONObject, error) { - if !self.Enabled { - _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, data) + if !self.GetEnabled() { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformEnable") } self.SyncAttachedStorageStatus() } @@ -3897,16 +3925,16 @@ func (self *SHost) AllowPerformDisable( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject, + input apis.PerformDisableInput, ) bool { - return self.SEnabledStatusStandaloneResourceBase.AllowPerformDisable(ctx, userCred, query, data) + return self.SEnabledStatusStandaloneResourceBase.AllowPerformDisable(ctx, userCred, query, input) } -func (self *SHost) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if self.Enabled { - _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, data) +func (self *SHost) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + if self.GetEnabled() { + _, err := self.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformDisable") } self.SyncAttachedStorageStatus() } @@ -4052,7 +4080,7 @@ func (self *SHost) PerformUndoConvert(ctx context.Context, userCred mcclient.Tok if self.HostType == api.HOST_TYPE_BAREMETAL { return nil, httperrors.NewNotAcceptableError("Not being convert to hypervisor") } - if self.Enabled { + if self.GetEnabled() { return nil, httperrors.NewNotAcceptableError("Host should be disabled") } if !utils.IsInStringArray(self.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) { @@ -4326,7 +4354,7 @@ func (manager *SHostManager) GetHostByIp(hostIp string) (*SHost, error) { return host.(*SHost), nil } -func (self *SHost) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SHost) getCloudProviderInfo() SCloudProviderInfo { var region *SCloudregion zone := self.GetZone() if zone != nil { @@ -4392,10 +4420,10 @@ func (host *SHost) GetDynamicConditionInput() *jsonutils.JSONDict { return jsonutils.Marshal(host).(*jsonutils.JSONDict) } -func (host *SHost) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - ret, err := host.SEnabledStatusStandaloneResourceBase.PerformStatus(ctx, userCred, query, data) +func (host *SHost) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { + ret, err := host.SEnabledStatusStandaloneResourceBase.PerformStatus(ctx, userCred, query, input) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformStatus") } host.ClearSchedDescCache() return ret, nil diff --git a/pkg/compute/models/hostschedtags.go b/pkg/compute/models/hostschedtags.go index 24fa13c7ef..39146de855 100644 --- a/pkg/compute/models/hostschedtags.go +++ b/pkg/compute/models/hostschedtags.go @@ -18,10 +18,12 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostschedtagManager struct { @@ -70,12 +72,48 @@ func (self *SHostschedtag) Master() db.IStandaloneModel { return self.SSchedtagJointsBase.master(self) } -func (self *SHostschedtag) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HostschedtagDetails, error) { - out := api.HostschedtagDetails{} - out.JoinModelBaseDetails, _ = self.SSchedtagJointsBase.getExtraDetails(self, ctx, userCred, query, isList) - out.Host, out.Schedtag = db.JointModelExtra(self) - out.Baremetal = out.Host - return out, nil +func (self *SHostschedtag) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.HostschedtagDetails, error) { + return api.HostschedtagDetails{}, nil +} + +func (manager *SHostschedtagManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostschedtagDetails { + rows := make([]api.HostschedtagDetails, len(objs)) + + schedRows := manager.SSchedtagJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + hostIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.HostschedtagDetails{ + SchedtagJointResourceDetails: schedRows[i], + } + hostIds[i] = objs[i].(*SHostschedtag).HostId + } + + hostIdMaps, err := db.FetchIdNameMap2(HostManager, hostIds) + if err != nil { + log.Errorf("FetchIdNameMap2 hostIds fail %s", err) + return rows + } + + for i := range rows { + if name, ok := hostIdMaps[hostIds[i]]; ok { + rows[i].Host = name + rows[i].Baremetal = name + } + } + + return rows } func (self *SHostschedtag) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/hoststorages.go b/pkg/compute/models/hoststorages.go index 1acd8c10b5..0b2125ee87 100644 --- a/pkg/compute/models/hoststorages.go +++ b/pkg/compute/models/hoststorages.go @@ -30,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ErrStorageInUse = errors.Error("StorageInUse") @@ -59,17 +60,17 @@ type SHoststorage struct { SHostJointsBase // 挂载点 - MountPoint string `width:"256" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"required"` + MountPoint string `width:"256" charset:"ascii" nullable:"false" list:"admin" update:"admin" create:"required" json:"mount_point"` // 宿主机Id - HostId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"required"` + HostId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"required" json:"host_id"` // 存储Id - StorageId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"required"` + StorageId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"required" json:"storage_id"` // 配置信息 - Config *jsonutils.JSONArray `nullable:"true" get:"admin"` + Config *jsonutils.JSONArray `nullable:"true" get:"admin" json:"config"` // 真实容量大小 - RealCapacity int64 `nullable:"true" list:"admin"` + RealCapacity int64 `nullable:"true" list:"admin" json:"real_capacity"` } func (manager *SHoststorageManager) GetMasterFieldName() string { @@ -88,15 +89,49 @@ func (joint *SHoststorage) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (self *SHoststorage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HoststorageDetails, error) { - var err error - out := api.HoststorageDetails{} - out.ModelBaseDetails, err = self.SHostJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SHoststorage) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.HoststorageDetails, error) { + return api.HoststorageDetails{}, nil +} + +func (manager *SHoststorageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HoststorageDetails { + rows := make([]api.HoststorageDetails, len(objs)) + + hostRows := manager.SHostJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + storageIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = api.HoststorageDetails{ + HostJointResourceDetails: hostRows[i], + } + storageIds[i] = objs[i].(*SHoststorage).StorageId } - out.Baremetal, out.Storage = db.JointModelExtra(self) - return self.getExtraDetails(out), nil + + storages := make(map[string]SStorage) + err := db.FetchStandaloneObjectsByIds(StorageManager, storageIds, &storages) + if err != nil { + log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if storage, ok := storages[storageIds[i]]; ok { + rows[i] = objs[i].(*SHoststorage).getExtraDetails(storage, rows[i]) + } + } + + return rows } func (self *SHoststorage) GetHost() *SHost { @@ -206,10 +241,7 @@ func (self *SHoststorage) SyncStorageStatus(userCred mcclient.TokenCredential) { } } -func (self *SHoststorage) getExtraDetails(out api.HoststorageDetails) api.HoststorageDetails { - host := self.GetHost() - out.Host = host.Name - storage := self.GetStorage() +func (self *SHoststorage) getExtraDetails(storage SStorage, out api.HoststorageDetails) api.HoststorageDetails { out.Storage = storage.Name out.Capacity = storage.Capacity if storage.StorageConf != nil { diff --git a/pkg/compute/models/hostwires.go b/pkg/compute/models/hostwires.go index 54bf018fa2..06f49b096b 100644 --- a/pkg/compute/models/hostwires.go +++ b/pkg/compute/models/hostwires.go @@ -18,12 +18,14 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SHostwireManager struct { @@ -81,14 +83,44 @@ func (joint *SHostwire) Slave() db.IStandaloneModel { } func (self *SHostwire) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.HostwireDetails, error) { - var err error - out := api.HostwireDetails{} - out.ModelBaseDetails, err = self.SHostJointsBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.HostwireDetails{}, nil +} + +func (manager *SHostwireManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.HostwireDetails { + rows := make([]api.HostwireDetails, len(objs)) + + hostRows := manager.SHostJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + wireIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = api.HostwireDetails{ + HostJointResourceDetails: hostRows[i], + } + wireIds[i] = objs[i].(*SHostwire).WireId } - out.Baremetal, out.Wire = db.JointModelExtra(self) - return self.getExtraDetails(out), nil + + wires := make(map[string]SWire) + err := db.FetchStandaloneObjectsByIds(WireManager, wireIds, &wires) + if err != nil { + log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if wire, ok := wires[wireIds[i]]; ok { + rows[i].Wire = wire.Name + rows[i].Bandwidth = wire.Bandwidth + } + } + + return rows } func (hw *SHostwire) GetWire() *SWire { @@ -107,14 +139,6 @@ func (hw *SHostwire) GetHost() *SHost { return nil } -func (hw *SHostwire) getExtraDetails(out api.HostwireDetails) api.HostwireDetails { - wire := hw.GetWire() - if wire != nil { - out.Bandwidth = wire.Bandwidth - } - return out -} - func (self *SHostwire) GetGuestnicsCount() (int, error) { guestnics := GuestnetworkManager.Query().SubQuery() guests := GuestManager.Query().SubQuery() diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index edc9636c1a..b68fc324ba 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) func init() { @@ -80,7 +81,12 @@ func (manager *SInstanceSnapshotManager) AllowCreateItem( } // 主机快照列表 -func (manager *SInstanceSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.InstanceSnapshotListInput) (*sqlchemy.SQuery, error) { +func (manager *SInstanceSnapshotManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.InstanceSnapshotListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") @@ -102,11 +108,38 @@ func (manager *SInstanceSnapshotManager) ListItemFilter(ctx context.Context, q * return q, nil } +func (manager *SInstanceSnapshotManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.InstanceSnapshotListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SInstanceSnapshotManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SInstanceSnapshot) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { return false } -func (self *SInstanceSnapshot) getMoreDetails(userCred mcclient.TokenCredential, out api.InstnaceSnapshotDetails) api.InstnaceSnapshotDetails { +func (self *SInstanceSnapshot) getMoreDetails(userCred mcclient.TokenCredential, out api.InstanceSnapshotDetails) api.InstanceSnapshotDetails { if guest := GuestManager.FetchGuestById(self.GuestId); guest != nil { out.Guest = guest.Name out.GuestStatus = guest.Status @@ -140,14 +173,30 @@ func (self *SInstanceSnapshot) getMoreDetails(userCred mcclient.TokenCredential, return out } -func (self *SInstanceSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.InstnaceSnapshotDetails, error) { - var err error - out := api.InstnaceSnapshotDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SInstanceSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.InstanceSnapshotDetails, error) { + return api.InstanceSnapshotDetails{}, nil +} + +func (manager *SInstanceSnapshotManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.InstanceSnapshotDetails { + rows := make([]api.InstanceSnapshotDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.InstanceSnapshotDetails{ + VirtualResourceDetails: virtRows[i], + } + rows[i] = objs[i].(*SInstanceSnapshot).getMoreDetails(userCred, rows[i]) } - return self.getMoreDetails(userCred, out), nil + + return rows } func (self *SInstanceSnapshot) StartCreateInstanceSnapshotTask( diff --git a/pkg/compute/models/isolated_devices.go b/pkg/compute/models/isolated_devices.go index 7cc1a25b65..5880bba605 100644 --- a/pkg/compute/models/isolated_devices.go +++ b/pkg/compute/models/isolated_devices.go @@ -31,6 +31,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -54,6 +55,7 @@ var VENDOR_ID_MAP = api.VENDOR_ID_MAP type SIsolatedDeviceManager struct { db.SStandaloneResourceBaseManager + SHostResourceBaseManager } var IsolatedDeviceManager *SIsolatedDeviceManager @@ -72,9 +74,10 @@ func init() { type SIsolatedDevice struct { db.SStandaloneResourceBase + SHostResourceBase // 宿主机Id - HostId string `width:"36" charset:"ascii" nullable:"false" default:"" index:"true" list:"admin" create:"admin_required"` + // HostId string `width:"36" charset:"ascii" nullable:"false" default:"" index:"true" list:"admin" create:"admin_required"` // # PCI / GPU-HPC / GPU-VGA / USB / NIC // 设备类型 @@ -138,17 +141,19 @@ func (self *SIsolatedDevice) AllowUpdateItem(ctx context.Context, userCred mccli } // 直通设备(GPU等)列表 -func (manager *SIsolatedDeviceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.IsolatedDeviceListInput) (*sqlchemy.SQuery, error) { +func (manager *SIsolatedDeviceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IsolatedDeviceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "host_id", func() *sqlchemy.SQuery { - return HostManager.Query("id") - }) + q, err = manager.SHostResourceBaseManager.ListItemFilter(ctx, q, userCred, query.HostFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SHostResourceBaseManager.ListItemFilter") } if query.Gpu != nil && *query.Gpu { @@ -157,43 +162,44 @@ func (manager *SIsolatedDeviceManager) ListItemFilter(ctx context.Context, q *sq if query.Usb != nil && *query.Usb { q = q.Equals("dev_type", "USB") } - hostStr := query.Host - var sq *sqlchemy.SSubQuery - if len(hostStr) > 0 { - hosts := HostManager.Query().SubQuery() - sq = hosts.Query(hosts.Field("id")).Filter(sqlchemy.OR( - sqlchemy.Equals(hosts.Field("id"), hostStr), - sqlchemy.Equals(hosts.Field("name"), hostStr))).SubQuery() - } - if sq != nil { - q = q.Filter(sqlchemy.In(q.Field("host_id"), sq)) - } if query.Unused != nil && *query.Unused { q = q.IsEmpty("guest_id") } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "host_id", func() *sqlchemy.SQuery { - hosts := HostManager.Query().SubQuery() - zones := ZoneManager.Query().SubQuery() - - q := hosts.Query(hosts.Field("id")) - q = q.Join(zones, sqlchemy.Equals(hosts.Field("zone_id"), zones.Field("id"))) - return q - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "host_id", func() *sqlchemy.SQuery { - return HostManager.Query("id") - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") - } - return q, nil } +func (manager *SIsolatedDeviceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IsolatedDeviceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SHostResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.HostFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SHostResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SIsolatedDeviceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SHostResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + /* func (self *SIsolatedDevice) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { return userCred.IsSystemAdmin() @@ -539,7 +545,7 @@ func (self *SIsolatedDevice) GetSpec(statusCheck bool) *jsonutils.JSONDict { return nil } host := self.getHost() - if host.Status != api.BAREMETAL_RUNNING || !host.Enabled { + if host.Status != api.BAREMETAL_RUNNING || !host.GetEnabled() { return nil } } @@ -591,27 +597,46 @@ func (self *SIsolatedDevice) getGuest() *SGuest { return nil } -func (self *SIsolatedDevice) getMoreDetails(out api.IsolateDeviceDetails) api.IsolateDeviceDetails { - host := self.getHost() - if host != nil { - out.Host = host.Name - } - guest := self.getGuest() - if guest != nil { - out.Guest = guest.Name - out.GuestStatus = guest.Status - } - return out +func (self *SIsolatedDevice) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.IsolateDeviceDetails, error) { + return api.IsolateDeviceDetails{}, nil } -func (self *SIsolatedDevice) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.IsolateDeviceDetails, error) { - var err error - out := api.IsolateDeviceDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SIsolatedDeviceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.IsolateDeviceDetails { + rows := make([]api.IsolateDeviceDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + hostRows := manager.SHostResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + guestIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.IsolateDeviceDetails{ + StandaloneResourceDetails: stdRows[i], + HostResourceInfo: hostRows[i], + } + guestIds[i] = objs[i].(*SIsolatedDevice).GuestId } - return self.getMoreDetails(out), nil + + guests := make(map[string]SGuest) + err := db.FetchStandaloneObjectsByIds(GuestManager, guestIds, &guests) + if err != nil { + log.Errorf("db.FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if guest, ok := guests[guestIds[i]]; ok { + rows[i].Guest = guest.Name + rows[i].GuestStatus = guest.Status + } + } + + return rows } func (self *SIsolatedDevice) ClearSchedDescCache() error { diff --git a/pkg/compute/models/keypairs.go b/pkg/compute/models/keypairs.go index d3c8c1f90f..1b9d6fbd84 100644 --- a/pkg/compute/models/keypairs.go +++ b/pkg/compute/models/keypairs.go @@ -20,6 +20,7 @@ import ( "golang.org/x/crypto/ssh" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -31,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SKeypairManager struct { @@ -69,13 +71,18 @@ type SKeypair struct { } // 列出ssh密钥对 -func (manager *SKeypairManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.KeypairListInput) (*sqlchemy.SQuery, error) { +func (manager *SKeypairManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.KeypairListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, err } if query.Admin != nil && *query.Admin && db.IsAdminAllowList(userCred, manager) { - user := query.UserStr() + user := query.User if len(user) > 0 { uc, _ := db.UserCacheManager.FetchUserByIdOrName(ctx, user) if uc == nil { @@ -89,6 +96,29 @@ func (manager *SKeypairManager) ListItemFilter(ctx context.Context, q *sqlchemy. return q, nil } +func (manager *SKeypairManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.KeypairListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SKeypairManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (manager *SKeypairManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } @@ -101,25 +131,50 @@ func (self *SKeypair) AllowGetDetails(ctx context.Context, userCred mcclient.Tok return self.IsOwner(userCred) || db.IsAdminAllowGet(userCred, self) } -func (self *SKeypair) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.KeypairDetails, error) { - var err error - out := api.KeypairDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SKeypair) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.KeypairDetails, error) { + return api.KeypairDetails{}, nil +} + +func (manager *SKeypairManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.KeypairDetails { + rows := make([]api.KeypairDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + userIds := make([]string, len(objs)) + for i := range rows { + keypair := objs[i].(*SKeypair) + rows[i] = api.KeypairDetails{ + StandaloneResourceDetails: stdRows[i], + PrivateKeyLen: len(keypair.PrivateKey), + } + rows[i].LinkedGuestCount, _ = keypair.GetLinkedGuestsCount() + userIds[i] = keypair.OwnerId } - out.PrivateKeyLen = len(self.PrivateKey) - out.LinkedGuestCount, _ = self.GetLinkedGuestsCount() + users := make(map[string]db.SUser) + err := db.FetchStandaloneObjectsByIds(db.UserCacheManager, userIds, &users) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds for users fail %s", err) + return rows + } - if !isList && db.IsAdminAllowGet(userCred, self) { - out.OwnerId = self.OwnerId - uc, _ := db.UserCacheManager.FetchUserById(ctx, self.OwnerId) - if uc != nil { - out.OwnerName = uc.Name + for i := range rows { + if owner, ok := users[userIds[i]]; ok { + rows[i].OwnerName = owner.Name } } - return out, nil + + return rows } func (manager *SKeypairManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { diff --git a/pkg/compute/models/loadbalancer_backendstatus.go b/pkg/compute/models/loadbalancer_backendstatus.go index a58a7ab007..08d872d610 100644 --- a/pkg/compute/models/loadbalancer_backendstatus.go +++ b/pkg/compute/models/loadbalancer_backendstatus.go @@ -34,7 +34,8 @@ func (lblis *SLoadbalancerListener) AllowGetDetailsBackendStatus(ctx context.Con } func (lblis *SLoadbalancerListener) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if lblis.ManagerId != "" { + provider := lblis.GetCloudprovider() + if provider != nil { return jsonutils.NewArray(), nil } if lblis.BackendGroupId == "" { @@ -55,7 +56,8 @@ func (lbr *SLoadbalancerListenerRule) AllowGetDetailsBackendStatus(ctx context.C } func (lbr *SLoadbalancerListenerRule) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if lbr.ManagerId != "" { + provider := lbr.GetCloudprovider() + if provider != nil { return jsonutils.NewArray(), nil } lblis := lbr.GetLoadbalancerListener() diff --git a/pkg/compute/models/loadbalanceracls.go b/pkg/compute/models/loadbalanceracls.go index 4243ff9679..728b88e14a 100644 --- a/pkg/compute/models/loadbalanceracls.go +++ b/pkg/compute/models/loadbalanceracls.go @@ -39,6 +39,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerAclEntry struct { @@ -115,6 +116,8 @@ func (aclEntries *SLoadbalancerAclEntries) Fingerprint() string { type SLoadbalancerAclManager struct { SLoadbalancerLogSkipper db.SSharableVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } var LoadbalancerAclManager *SLoadbalancerAclManager @@ -252,11 +255,38 @@ func (lbacl *SLoadbalancerAcl) PostCreate(ctx context.Context, userCred mcclient lbacl.SetStatus(userCred, api.LB_STATUS_ENABLED, "") } -func (lbacl *SLoadbalancerAcl) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerAclDetails, error) { - var err error - out := api.LoadbalancerAclDetails{} - out.SharableVirtualResourceDetails, err = lbacl.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - return out, err +func (lbacl *SLoadbalancerAcl) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerAclDetails, error) { + return api.LoadbalancerAclDetails{}, nil +} + +func (manager *SLoadbalancerAclManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerAclDetails { + rows := make([]api.LoadbalancerAclDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerAclDetails{ + SharableVirtualResourceDetails: virtRows[i], + ManagedResourceInfo: managerRows[i], + CloudregionResourceInfo: regionRows[i], + } + } + + return rows } func (lbacl *SLoadbalancerAcl) AllowPerformPatch(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool { @@ -413,10 +443,67 @@ func (manager *SLoadbalancerAclManager) InitializeData() error { } // 负载均衡ACL规则列表 -func (manager *SLoadbalancerAclManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.LoadbalancerAclListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) +func (manager *SLoadbalancerAclManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.LoadbalancerAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, input.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } return q, nil } + +func (manager *SLoadbalancerAclManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.LoadbalancerAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SLoadbalancerAclManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/loadbalanceragents.go b/pkg/compute/models/loadbalanceragents.go index 9b41d33e0c..4fb47505ad 100644 --- a/pkg/compute/models/loadbalanceragents.go +++ b/pkg/compute/models/loadbalanceragents.go @@ -37,11 +37,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerAgentManager struct { SLoadbalancerLogSkipper db.SStandaloneResourceBaseManager + SLoadbalancerClusterResourceBaseManager } var LoadbalancerAgentManager *SLoadbalancerAgentManager @@ -68,6 +70,7 @@ func init() { // type SLoadbalancerAgent struct { db.SStandaloneResourceBase + SLoadbalancerClusterResourceBase Version string `width:"64" nullable:"true" list:"admin" update:"admin"` IP string `width:"32" nullable:"true" list:"admin" update:"admin"` @@ -85,7 +88,7 @@ type SLoadbalancerAgent struct { LoadbalancerCertificates time.Time `nullable:"true" list:"admin" update:"admin"` Deployment *SLoadbalancerAgentDeployment `create:"optional" list:"admin" get:"admin"` - ClusterId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + // ClusterId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` } type SLoadbalancerAgentParamsVrrp struct { @@ -313,26 +316,6 @@ func (p *SLoadbalancerAgentParams) IsZero() bool { return false } -func (self *SLoadbalancerAgentManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SLoadbalancerAgentManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SLoadbalancerAgent) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SLoadbalancerAgent) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SLoadbalancerAgent) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (man *SLoadbalancerAgentManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { clusterV := validators.NewModelIdOrNameValidator("cluster", "loadbalancercluster", ownerId) paramsV := validators.NewStructValidator("params", &SLoadbalancerAgentParams{}) @@ -388,21 +371,58 @@ func (man *SLoadbalancerAgentManager) ValidateCreateData(ctx context.Context, us } // 负载均衡Agent列表 -func (man *SLoadbalancerAgentManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerAgentListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerAgentManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerAgentListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "cluster", ModelKeyword: "loadbalancercluster", OwnerId: userCred}, - }) + q, err = man.SLoadbalancerClusterResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerClusterFilterListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SLoadbalancerClusterResourceBaseManager.ListItemFilter") } return q, nil } +func (man *SLoadbalancerAgentManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerAgentListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerClusterResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerClusterFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerClusterResourceBaseManager.ListItemFilter") + } + + return q, nil +} + +func (man *SLoadbalancerAgentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerClusterResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerAgentManager) CleanPendingDeleteLoadbalancers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) { agents := []SLoadbalancerAgent{} { @@ -547,26 +567,39 @@ func (lbagent *SLoadbalancerAgent) ValidateUpdateData(ctx context.Context, userC return data, nil } -func (lbagent *SLoadbalancerAgent) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerAgentDetails, error) { - var err error - out := api.LoadbalancerAgentDetails{} - out.StandaloneResourceDetails, err = lbagent.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - m, err := LoadbalancerClusterManager.FetchById(lbagent.ClusterId) - if err != nil { - log.Errorf("loadbalancer agent %s(%s): fetch cluster (%s) error: %s", - lbagent.Name, lbagent.Id, lbagent.ClusterId, err) - return out, err - } - lbcluster := m.(*SLoadbalancerCluster) - out.Cluster = lbcluster.GetName() - out.ZoneInfo = lbcluster.SZoneResourceBase.GetExtraDetails(ctx, userCred, query) - return out, nil +func (lbagent *SLoadbalancerAgent) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerAgentDetails, error) { + return api.LoadbalancerAgentDetails{}, nil } -func (manager *SLoadbalancerAgentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { +func (manager *SLoadbalancerAgentManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerAgentDetails { + rows := make([]api.LoadbalancerAgentDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + clusterRows := manager.SLoadbalancerClusterResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerAgentDetails{ + StandaloneResourceDetails: stdRows[i], + LoadbalancerClusterResourceInfo: clusterRows[i], + } + } + + return rows +} + +/*func (manager *SLoadbalancerAgentManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { var err error q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { @@ -582,7 +615,7 @@ func (manager *SLoadbalancerAgentManager) QueryDistinctExtraField(q *sqlchemy.SQ return q, httperrors.NewBadRequestError("unsupport field %s", field) } return q, nil -} +}*/ func (man *SLoadbalancerAgentManager) getByClusterId(clusterId string) ([]SLoadbalancerAgent, error) { r := []SLoadbalancerAgent{} diff --git a/pkg/compute/models/loadbalancerawscachedlbbg.go b/pkg/compute/models/loadbalancerawscachedlbbg.go index df128655f8..efeb0951da 100644 --- a/pkg/compute/models/loadbalancerawscachedlbbg.go +++ b/pkg/compute/models/loadbalancerawscachedlbbg.go @@ -246,11 +246,11 @@ func (man *SAwsCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.Cont if elb == nil { elb = &SLoadbalancer{} elb.Id = "" - elb.CloudregionId = region.GetId() - elb.ManagerId = provider.GetId() + // elb.CloudregionId = region.GetId() + // elb.ManagerId = provider.GetId() } - err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, elb, commonext[i], provider.GetOwnerId()) + err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, elb, commonext[i], provider.GetOwnerId(), provider) if err != nil { syncResult.UpdateError(err) } else { @@ -279,11 +279,11 @@ func (man *SAwsCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.Cont if elb == nil { elb = &SLoadbalancer{} elb.Id = "" - elb.CloudregionId = region.GetId() - elb.ManagerId = provider.GetId() + // elb.CloudregionId = region.GetId() + // elb.ManagerId = provider.GetId() } - new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, elb, added[i], syncOwnerId) + new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, elb, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -342,7 +342,7 @@ func (lbbg *SAwsCachedLbbg) isBackendsMatch(backends []SLoadbalancerBackend, iba return true } -func (lbbg *SAwsCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) error { +func (lbbg *SAwsCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { lbbg.SetModelManager(AwsCachedLbbgManager, lbbg) ibackends, err := extLoadbalancerBackendgroup.GetILoadbalancerBackends() @@ -362,7 +362,7 @@ func (lbbg *SAwsCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Co var newLocalLbbg *SLoadbalancerBackendGroup if !lbbg.isBackendsMatch(backends, ibackends) { - newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) + newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return errors.Wrap(err, "HuaweiCachedLbbg.SyncWithCloudLoadbalancerBackendgroup.newLocalBackendgroupFromCloudLoadbalancerBackendgroup") } @@ -390,12 +390,12 @@ func (lbbg *SAwsCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Co } db.OpsLog.LogSyncUpdate(lbbg, diff, userCred) - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) return err } -func (man *SAwsCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SAwsCachedLbbg, error) { - LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) +func (man *SAwsCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SAwsCachedLbbg, error) { + LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return nil, err } @@ -403,8 +403,8 @@ func (man *SAwsCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx conte lbbg := &SAwsCachedLbbg{} lbbg.SetModelManager(man, lbbg) - lbbg.ManagerId = lb.ManagerId - lbbg.CloudregionId = lb.CloudregionId + // lbbg.ManagerId = lb.ManagerId + // lbbg.CloudregionId = lb.CloudregionId lbbg.LoadbalancerId = lb.Id lbbg.BackendGroupId = LocalLbbg.GetId() lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId() @@ -439,7 +439,7 @@ func (man *SAwsCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx conte return nil, err } - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred) return lbbg, nil diff --git a/pkg/compute/models/loadbalancerbackendgroupresource.go b/pkg/compute/models/loadbalancerbackendgroupresource.go new file mode 100644 index 0000000000..c4003d4d2f --- /dev/null +++ b/pkg/compute/models/loadbalancerbackendgroupresource.go @@ -0,0 +1,251 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SLoadbalancerBackendgroupResourceBase struct { + // 负载均衡后端组ID + BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"backend_group_id"` +} + +type SLoadbalancerBackendgroupResourceBaseManager struct { + SLoadbalancerResourceBaseManager +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetLoadbalancerBackendGroup() *SLoadbalancerBackendGroup { + w, _ := LoadbalancerBackendGroupManager.FetchById(self.BackendGroupId) + if w != nil { + return w.(*SLoadbalancerBackendGroup) + } + return nil +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetLoadbalancer() *SLoadbalancer { + lbbg := self.GetLoadbalancerBackendGroup() + if lbbg != nil { + return lbbg.GetLoadbalancer() + } + return nil +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetVpc() *SVpc { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetVpc() + } + return nil +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetCloudprovider() *SCloudprovider { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetCloudprovider() + } + return nil +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetProviderName() string { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetProviderName() + } + return "" +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetRegion() *SCloudregion { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + region, _ := vpc.GetRegion() + return region +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetZone() *SZone { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetZone() + } + return nil +} + +func (self *SLoadbalancerBackendgroupResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, +) api.LoadbalancerBackendGroupResourceInfo { + return api.LoadbalancerBackendGroupResourceInfo{} +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerBackendGroupResourceInfo { + rows := make([]api.LoadbalancerBackendGroupResourceInfo, len(objs)) + + lbbgIds := make([]string, len(objs)) + for i := range objs { + var base *SLoadbalancerBackendgroupResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + lbbgIds[i] = base.BackendGroupId + } + } + + lbbgs := make(map[string]SLoadbalancerBackendGroup) + err := db.FetchStandaloneObjectsByIds(LoadbalancerBackendGroupManager, lbbgIds, &lbbgs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + lbList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.LoadbalancerBackendGroupResourceInfo{} + if lbbg, ok := lbbgs[lbbgIds[i]]; ok { + rows[i].BackendGroup = lbbg.Name + rows[i].LoadbalancerId = lbbg.LoadbalancerId + } + lbList[i] = &SLoadbalancerResourceBase{rows[i].LoadbalancerId} + } + + lbRows := manager.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, lbList, fields, isList) + + for i := range rows { + rows[i].LoadbalancerResourceInfo = lbRows[i] + } + return rows +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendGroupFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.BackendGroup) > 0 { + lbbgObj, err := LoadbalancerBackendGroupManager.FetchByIdOrName(userCred, query.BackendGroup) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(LoadbalancerBackendGroupManager.Keyword(), query.BackendGroup) + } else { + return nil, errors.Wrap(err, "LoadbalancerBackendGroupManager.FetchByIdOrName") + } + } + q = q.Equals("backend_group_id", lbbgObj.GetId()) + } + + lbbgQ := LoadbalancerBackendGroupManager.Query("id").Snapshot() + + lbbgQ, err := manager.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, lbbgQ, userCred, query.LoadbalancerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter") + } + + if lbbgQ.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("backend_group_id"), lbbgQ.SubQuery())) + } + return q, nil +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "backend_group" { + lbbgQuery := LoadbalancerBackendGroupManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(lbbgQuery.Field("name", field)) + q = q.Join(lbbgQuery, sqlchemy.Equals(q.Field("backend_group_id"), lbbgQuery.Field("id"))) + q.GroupBy(lbbgQuery.Field("name")) + return q, nil + } else { + lbbgs := LoadbalancerBackendGroupManager.Query("id", "loadbalancer_id").SubQuery() + q = q.LeftJoin(lbbgs, sqlchemy.Equals(q.Field("backend_id"), lbbgs.Field("id"))) + q, err := manager.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendGroupFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendGroupFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + lbbgQ := LoadbalancerBackendGroupManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SLoadbalancerResourceBaseManager.GetOrderByFields(query.LoadbalancerFilterListInput)) { + var lbOrders []string + var lbFields []sqlchemy.IQueryField + lbbgQ, lbOrders, lbFields = manager.SLoadbalancerResourceBaseManager.GetOrderBySubQuery(lbbgQ, userCred, query.LoadbalancerFilterListInput) + if len(lbOrders) > 0 { + orders = append(orders, lbOrders...) + fields = append(fields, lbFields...) + } + } + + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := lbbgQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("backend_group_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByBackendGroup}) { + orders = append(orders, query.OrderByBackendGroup) + fields = append(fields, subq.Field("name")) + } + } + + return q, orders, fields +} + +func (manager *SLoadbalancerBackendgroupResourceBaseManager) GetOrderByFields(query api.LoadbalancerBackendGroupFilterListInput) []string { + fields := make([]string, 0) + lbFields := manager.SLoadbalancerResourceBaseManager.GetOrderByFields(query.LoadbalancerFilterListInput) + fields = append(fields, lbFields...) + fields = append(fields, query.OrderByBackendGroup) + return fields +} diff --git a/pkg/compute/models/loadbalancerbackendgroups.go b/pkg/compute/models/loadbalancerbackendgroups.go index fd1ba63412..d900bc9283 100644 --- a/pkg/compute/models/loadbalancerbackendgroups.go +++ b/pkg/compute/models/loadbalancerbackendgroups.go @@ -35,11 +35,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rand" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerBackendGroupManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SLoadbalancerResourceBaseManager } var LoadbalancerBackendGroupManager *SLoadbalancerBackendGroupManager @@ -60,11 +62,11 @@ type SLoadbalancerBackendGroup struct { db.SVirtualResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + SLoadbalancerResourceBase - Type string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"normal" create:"optional"` - LoadbalancerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + Type string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"normal" create:"optional"` + + //LoadbalancerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` } func (man *SLoadbalancerBackendGroupManager) pendingDeleteSubs(ctx context.Context, userCred mcclient.TokenCredential, q *sqlchemy.SQuery) { @@ -76,13 +78,24 @@ func (man *SLoadbalancerBackendGroupManager) pendingDeleteSubs(ctx context.Conte } // 负载均衡后端服务器组列表 -func (man *SLoadbalancerBackendGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerBackendGroupListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerBackendGroupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendGroupListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } + + q, err = man.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter") + } + // userProjId := userCred.GetProjectId() - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) + /*data := jsonutils.Marshal(query).(*jsonutils.JSONDict) q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ {Key: "loadbalancer", ModelKeyword: "loadbalancer", OwnerId: userCred}, {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, @@ -90,7 +103,7 @@ func (man *SLoadbalancerBackendGroupManager) ListItemFilter(ctx context.Context, }) if err != nil { return nil, err - } + }*/ if query.NoRef != nil && *query.NoRef { q, err = man.FilterZeroRefBackendGroup(q) @@ -102,6 +115,41 @@ func (man *SLoadbalancerBackendGroupManager) ListItemFilter(ctx context.Context, return q, nil } +func (man *SLoadbalancerBackendGroupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendGroupListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerBackendGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerBackendGroupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { lbV := validators.NewModelIdOrNameValidator("loadbalancer", "loadbalancer", ownerId) err := lbV.Validate(data) @@ -121,8 +169,8 @@ func (man *SLoadbalancerBackendGroupManager) ValidateCreateData(ctx context.Cont data.Update(jsonutils.Marshal(input)) lb := lbV.Model.(*SLoadbalancer) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + // data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) + // data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) backends := []cloudprovider.SLoadbalancerBackend{} if data.Contains("backends") { if err := data.Unmarshal(&backends, "backends"); err != nil { @@ -386,22 +434,36 @@ func (lbbg *SLoadbalancerBackendGroup) ValidatePurgeCondition(ctx context.Contex return nil } -func (lbbg *SLoadbalancerBackendGroup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerBackendGroupDetails, error) { - var err error - out := api.LoadbalancerBackendGroupDetails{} - out.VirtualResourceDetails, err = lbbg.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (lbbg *SLoadbalancerBackendGroup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerBackendGroupDetails, error) { + return api.LoadbalancerBackendGroupDetails{}, nil +} + +func (man *SLoadbalancerBackendGroupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerBackendGroupDetails { + rows := make([]api.LoadbalancerBackendGroupDetails, len(objs)) + + virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + lbRows := man.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerBackendGroupDetails{ + VirtualResourceDetails: virtRows[i], + LoadbalancerResourceInfo: lbRows[i], + } } - lb, err := LoadbalancerManager.FetchById(lbbg.LoadbalancerId) - if err != nil { - log.Errorf("loadbalancer backend group %s(%s): fetch loadbalancer (%s) error: %s", - lbbg.Name, lbbg.Id, lbbg.LoadbalancerId, err) - return out, err - } - out.Loadbalancer = lb.GetName() - out.CloudregionInfo = lbbg.SCloudregionResourceBase.GetExtraDetails(ctx, userCred, query) - return out, nil + + return rows } func (lbbg *SLoadbalancerBackendGroup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { @@ -784,7 +846,7 @@ func (man *SLoadbalancerBackendGroupManager) SyncLoadbalancerBackendgroups(ctx c } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId()) + err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId(), provider) if err != nil { syncResult.UpdateError(err) } else { @@ -795,7 +857,7 @@ func (man *SLoadbalancerBackendGroupManager) SyncLoadbalancerBackendgroups(ctx c } } for i := 0; i < len(added); i++ { - new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId) + new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -831,7 +893,14 @@ func (lbbg *SLoadbalancerBackendGroup) syncRemoveCloudLoadbalancerBackendgroup(c return err } -func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) error { +func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup( + ctx context.Context, + userCred mcclient.TokenCredential, + lb *SLoadbalancer, + extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, + syncOwnerId mcclient.IIdentityProvider, + provider *SCloudprovider, +) error { diff, err := db.UpdateWithLock(ctx, lbbg, func() error { lbbg.Type = extLoadbalancerBackendgroup.GetType() lbbg.Status = extLoadbalancerBackendgroup.GetStatus() @@ -842,7 +911,7 @@ func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(ctx } db.OpsLog.LogSyncUpdate(lbbg, diff, userCred) - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) if extLoadbalancerBackendgroup.IsDefault() { diff, err := db.UpdateWithLock(ctx, lb, func() error { @@ -859,15 +928,22 @@ func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(ctx return err } -func (man *SLoadbalancerBackendGroupManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SLoadbalancerBackendGroup, error) { +func (man *SLoadbalancerBackendGroupManager) newFromCloudLoadbalancerBackendgroup( + ctx context.Context, + userCred mcclient.TokenCredential, + lb *SLoadbalancer, + extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, + syncOwnerId mcclient.IIdentityProvider, + provider *SCloudprovider, +) (*SLoadbalancerBackendGroup, error) { lbbg := &SLoadbalancerBackendGroup{} lbbg.SetModelManager(man, lbbg) lbbg.LoadbalancerId = lb.Id lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId() - lbbg.CloudregionId = lb.CloudregionId - lbbg.ManagerId = lb.ManagerId + // lbbg.CloudregionId = lb.CloudregionId + // lbbg.ManagerId = lb.ManagerId /*lbbg.constructFieldsFromCloudBackendgroup(lb, extLoadbalancerBackendgroup) if lbbg.GetProviderName() != CLOUD_PROVIDER_QCLOUD || len(lbbg.Name) == 0 { @@ -888,7 +964,7 @@ func (man *SLoadbalancerBackendGroupManager) newFromCloudLoadbalancerBackendgrou return nil, err } - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred) @@ -924,7 +1000,7 @@ func (man *SLoadbalancerBackendGroupManager) initBackendGroupType() error { return nil } -func (man *SLoadbalancerBackendGroupManager) InitializeData() error { +/*func (man *SLoadbalancerBackendGroupManager) InitializeData() error { if err := man.initBackendGroupType(); err != nil { return err } @@ -952,7 +1028,7 @@ func (manager *SLoadbalancerBackendGroupManager) initBackendGroupRegion() error } } return nil -} +}*/ func (manager *SLoadbalancerBackendGroupManager) GetResourceCount() ([]db.SProjectResourceCount, error) { virts := manager.Query().IsFalse("pending_deleted") diff --git a/pkg/compute/models/loadbalancerbackends.go b/pkg/compute/models/loadbalancerbackends.go index 9c009b56db..ff9a4e8e7a 100644 --- a/pkg/compute/models/loadbalancerbackends.go +++ b/pkg/compute/models/loadbalancerbackends.go @@ -35,11 +35,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerBackendManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SLoadbalancerBackendgroupResourceBaseManager } var LoadbalancerBackendManager *SLoadbalancerBackendManager @@ -60,16 +62,17 @@ type SLoadbalancerBackend struct { db.SVirtualResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + //SManagedResourceBase + //SCloudregionResourceBase + SLoadbalancerBackendgroupResourceBase - BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - BackendId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - BackendType string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - BackendRole string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"default" create:"optional"` - Weight int `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user"` - Address string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - Port int `nullable:"false" list:"user" create:"required" update:"user"` + // BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BackendId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BackendType string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BackendRole string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"default" create:"optional"` + Weight int `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user"` + Address string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + Port int `nullable:"false" list:"user" create:"required" update:"user"` SendProxy string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" update:"user" default:"off"` Ssl string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user" default:"off"` @@ -84,18 +87,28 @@ func (man *SLoadbalancerBackendManager) pendingDeleteSubs(ctx context.Context, u } // 负载均衡后端列表 -func (man *SLoadbalancerBackendManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerBackendListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerBackendManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } + q, err = man.SLoadbalancerBackendgroupResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerBackendGroupFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerBackendgroupResourceBaseManager.ListItemFilter") + } + // userProjId := userCred.GetProjectId() data := jsonutils.Marshal(query).(*jsonutils.JSONDict) q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "backend_group", ModelKeyword: "loadbalancerbackendgroup", OwnerId: userCred}, + // {Key: "backend_group", ModelKeyword: "loadbalancerbackendgroup", OwnerId: userCred}, {Key: "backend", ModelKeyword: "server", OwnerId: userCred}, // NOTE extend this when new backend_type was added - {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, - {Key: "manager", ModelKeyword: "cloudprovider", OwnerId: userCred}, + // {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, + // {Key: "manager", ModelKeyword: "cloudprovider", OwnerId: userCred}, }) if err != nil { return nil, err @@ -103,6 +116,41 @@ func (man *SLoadbalancerBackendManager) ListItemFilter(ctx context.Context, q *s return q, nil } +func (man *SLoadbalancerBackendManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerBackendListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerBackendgroupResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerBackendGroupFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerBackendgroupResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerBackendManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerBackendgroupResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerBackendManager) ValidateBackendVpc(lb *SLoadbalancer, guest *SGuest, backendgroup *SLoadbalancerBackendGroup) error { region := lb.GetRegion() if region == nil { @@ -294,26 +342,33 @@ func (lbb *SLoadbalancerBackend) getVpc(ctx context.Context) (*SVpc, error) { return vpc, nil } -func (lbb *SLoadbalancerBackend) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerBackendDetails, error) { - var err error - out := api.LoadbalancerBackendDetails{} - out.VirtualResourceDetails, err = lbb.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } +func (lbb *SLoadbalancerBackend) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerBackendDetails, error) { + return api.LoadbalancerBackendDetails{}, nil +} - provider := lbb.GetCloudprovider() - region := lbb.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) - - vpc, err := lbb.getVpc(ctx) - if err != nil { - log.Warningf("loadbalancer backend %s(%s): get vpc: %v", lbb.Name, lbb.Id, err) - return out, err - } else if vpc != nil { - out.VpcId = vpc.Id +func (manager *SLoadbalancerBackendManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerBackendDetails { + rows := make([]api.LoadbalancerBackendDetails, len(objs)) + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + lbbgRows := manager.SLoadbalancerBackendgroupResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.LoadbalancerBackendDetails{ + VirtualResourceDetails: virtRows[i], + LoadbalancerBackendGroupResourceInfo: lbbgRows[i], + } } - return out, nil + return rows } func (lbb *SLoadbalancerBackend) StartLoadBalancerBackendCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error { @@ -401,7 +456,7 @@ func (man *SLoadbalancerBackendManager) SyncLoadbalancerBackends(ctx context.Con } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerBackend(ctx, userCred, commonext[i], syncOwnerId) + err = commondb[i].SyncWithCloudLoadbalancerBackend(ctx, userCred, commonext[i], syncOwnerId, provider) if err != nil { syncResult.UpdateError(err) } else { @@ -410,7 +465,7 @@ func (man *SLoadbalancerBackendManager) SyncLoadbalancerBackends(ctx context.Con } } for i := 0; i < len(added); i++ { - local, err := man.newFromCloudLoadbalancerBackend(ctx, userCred, loadbalancerBackendgroup, added[i], syncOwnerId) + local, err := man.newFromCloudLoadbalancerBackend(ctx, userCred, loadbalancerBackendgroup, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -460,7 +515,7 @@ func (lbb *SLoadbalancerBackend) syncRemoveCloudLoadbalancerBackend(ctx context. return err } -func (lbb *SLoadbalancerBackend) SyncWithCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) error { +func (lbb *SLoadbalancerBackend) SyncWithCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { diff, err := db.UpdateWithLock(ctx, lbb, func() error { return lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend) }) @@ -469,7 +524,7 @@ func (lbb *SLoadbalancerBackend) SyncWithCloudLoadbalancerBackend(ctx context.Co } db.OpsLog.LogSyncUpdate(lbb, diff, userCred) - SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, lbb.ManagerId) + SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, provider.Id) return nil } @@ -496,15 +551,15 @@ func (lbb *SLoadbalancerBackend) GetHuaweiCachedlbb() ([]SHuaweiCachedLb, error) return ret, nil } -func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, loadbalancerBackendgroup *SLoadbalancerBackendGroup, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) (*SLoadbalancerBackend, error) { +func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, loadbalancerBackendgroup *SLoadbalancerBackendGroup, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SLoadbalancerBackend, error) { lbb := &SLoadbalancerBackend{} lbb.SetModelManager(man, lbb) lbb.BackendGroupId = loadbalancerBackendgroup.Id lbb.ExternalId = extLoadbalancerBackend.GetGlobalId() - lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId - lbb.ManagerId = loadbalancerBackendgroup.ManagerId + // lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId + // lbb.ManagerId = loadbalancerBackendgroup.ManagerId newName, err := db.GenerateName(man, syncOwnerId, extLoadbalancerBackend.GetName()) if err != nil { @@ -522,7 +577,7 @@ func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx cont return nil, err } - SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, loadbalancerBackendgroup.ManagerId) + SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, provider.Id) db.OpsLog.LogEvent(lbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred) @@ -530,7 +585,7 @@ func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx cont } func (manager *SLoadbalancerBackendManager) InitializeData() error { - backends := []SLoadbalancerBackend{} + /*backends := []SLoadbalancerBackend{} q := manager.Query() q = q.Filter(sqlchemy.IsNullOrEmpty(q.Field("cloudregion_id"))) if err := db.FetchModelObjects(manager, q, &backends); err != nil { @@ -548,7 +603,7 @@ func (manager *SLoadbalancerBackendManager) InitializeData() error { log.Errorf("failed to update loadbalancer backend %s cloudregion_id", group.Name) } } - } + }*/ manager.initializeJanitor() return nil } diff --git a/pkg/compute/models/loadbalancercachedacls.go b/pkg/compute/models/loadbalancercachedacls.go index 210c9c7bfb..786be325d2 100644 --- a/pkg/compute/models/loadbalancercachedacls.go +++ b/pkg/compute/models/loadbalancercachedacls.go @@ -33,11 +33,14 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCachedLoadbalancerAclManager struct { SLoadbalancerLogSkipper db.SSharableVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } var CachedLoadbalancerAclManager *SCachedLoadbalancerAclManager @@ -202,18 +205,38 @@ func (lbacl *SCachedLoadbalancerAcl) GetListener() (*SLoadbalancerListener, erro return listener.(*SLoadbalancerListener), nil } -func (lbacl *SCachedLoadbalancerAcl) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CachedLoadbalancerAclDetails, error) { - var err error - out := api.CachedLoadbalancerAclDetails{} - out.SharableVirtualResourceDetails, err = lbacl.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - provider := lbacl.GetCloudprovider() - region := lbacl.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) +func (lbacl *SCachedLoadbalancerAcl) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.CachedLoadbalancerAclDetails, error) { + return api.CachedLoadbalancerAclDetails{}, nil +} - return out, nil +func (man *SCachedLoadbalancerAclManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CachedLoadbalancerAclDetails { + rows := make([]api.CachedLoadbalancerAclDetails, len(objs)) + + virtRows := man.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := man.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := man.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.CachedLoadbalancerAclDetails{ + SharableVirtualResourceDetails: virtRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regionRows[i], + } + } + + return rows } func (lbacl *SCachedLoadbalancerAcl) AllowPerformPatch(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool { @@ -321,7 +344,11 @@ func (man *SCachedLoadbalancerAclManager) GetOrCreateCachedAcl(ctx context.Conte listenerId = lblis.Id } - lbacl, err := man.getLoadbalancerAclByRegion(provider, lblis.CloudregionId, acl.Id, listenerId) + region := lblis.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "Loadbalancer listenser is not attached region") + } + lbacl, err := man.getLoadbalancerAclByRegion(provider, region.Id, acl.Id, listenerId) if err == nil { if lbacl.Id != acl.Id { _, err := man.TableSpec().Update(&lbacl, func() error { @@ -342,8 +369,8 @@ func (man *SCachedLoadbalancerAclManager) GetOrCreateCachedAcl(ctx context.Conte } lbacl = SCachedLoadbalancerAcl{} - lbacl.ManagerId = lblis.ManagerId - lbacl.CloudregionId = lblis.CloudregionId + lbacl.ManagerId = provider.Id + lbacl.CloudregionId = region.Id lbacl.ProjectId = lblis.ProjectId lbacl.ProjectSrc = lblis.ProjectSrc lbacl.Name = acl.Name @@ -474,7 +501,7 @@ func (man *SCachedLoadbalancerAclManager) newFromCloudLoadbalancerAcl(ctx contex // usercread localAcl.DomainId = userCred.GetProjectDomainId() localAcl.ProjectId = userCred.GetProjectId() - localAcl.ProjectSrc = string(db.PROJECT_SOURCE_CLOUD) + localAcl.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD) err := LoadbalancerAclManager.TableSpec().Insert(&localAcl) if err != nil { return nil, errors.Wrap(err, "cachedLoadbalancerAclManager.new.InsertAcl") @@ -507,3 +534,70 @@ func (manager *SCachedLoadbalancerAclManager) InitializeData() error { // todo: sync old data from acls return nil } + +func (manager *SCachedLoadbalancerAclManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedLoadbalancerAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") + } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + + return q, nil +} + +func (manager *SCachedLoadbalancerAclManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedLoadbalancerAclListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SCachedLoadbalancerAclManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/loadbalancercachedcertificates.go b/pkg/compute/models/loadbalancercachedcertificates.go index 7cfe895780..ee54cf36a3 100644 --- a/pkg/compute/models/loadbalancercachedcertificates.go +++ b/pkg/compute/models/loadbalancercachedcertificates.go @@ -34,11 +34,15 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCachedLoadbalancerCertificateManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager + SLoadbalancerCertificateResourceBaseManager } var CachedLoadbalancerCertificateManager *SCachedLoadbalancerCertificateManager @@ -62,7 +66,8 @@ type SCachedLoadbalancerCertificate struct { SManagedResourceBase // 云账号ID SCloudregionResourceBase // Region ID - CertificateId string `width:"128" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user"` // 本地证书ID + SLoadbalancerCertificateResourceBase + // CertificateId string `width:"128" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user" json:"certificate_id"` // 本地证书ID } func (self *SCachedLoadbalancerCertificate) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -189,18 +194,40 @@ func (self *SCachedLoadbalancerCertificate) PostCreate(ctx context.Context, user return } -func (self *SCachedLoadbalancerCertificate) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CachedLoadbalancerCertificateDetails, error) { - var err error - out := api.CachedLoadbalancerCertificateDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - provider := self.GetCloudprovider() - region := self.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) +func (self *SCachedLoadbalancerCertificate) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.CachedLoadbalancerCertificateDetails, error) { + return api.CachedLoadbalancerCertificateDetails{}, nil +} - return out, nil +func (man *SCachedLoadbalancerCertificateManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CachedLoadbalancerCertificateDetails { + rows := make([]api.CachedLoadbalancerCertificateDetails, len(objs)) + + virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := man.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := man.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + certRows := man.SLoadbalancerCertificateResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.CachedLoadbalancerCertificateDetails{ + VirtualResourceDetails: virtRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regionRows[i], + LoadbalancerCertificateResourceInfo: certRows[i], + } + } + + return rows } func (lbcert *SCachedLoadbalancerCertificate) GetIRegion() (cloudprovider.ICloudRegion, error) { @@ -230,7 +257,11 @@ func (man *SCachedLoadbalancerCertificateManager) GetOrCreateCachedCertificate(c lockman.LockClass(ctx, man, ownerProjId) defer lockman.ReleaseClass(ctx, man, ownerProjId) - lbcert, err := man.getLoadbalancerCertificateByRegion(provider, lblis.CloudregionId, cert.Id) + region := lblis.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancer listener is not attached to any region?") + } + lbcert, err := man.getLoadbalancerCertificateByRegion(provider, region.Id, cert.Id) if err == nil { return &lbcert, nil } @@ -240,8 +271,8 @@ func (man *SCachedLoadbalancerCertificateManager) GetOrCreateCachedCertificate(c } lbcert = SCachedLoadbalancerCertificate{} - lbcert.ManagerId = lblis.ManagerId - lbcert.CloudregionId = lblis.CloudregionId + lbcert.ManagerId = provider.Id + lbcert.CloudregionId = region.Id lbcert.ProjectId = lblis.ProjectId lbcert.ProjectSrc = lblis.ProjectSrc lbcert.Name = cert.Name @@ -428,3 +459,82 @@ func (man *SCachedLoadbalancerCertificateManager) SyncLoadbalancerCertificates(c } return syncResult } + +func (man *SCachedLoadbalancerCertificateManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedLoadbalancerCertificateListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") + } + q, err = man.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = man.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + q, err = man.SLoadbalancerCertificateResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerCertificateFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerCertificateResourceBaseManager.ListItemFilter") + } + + return q, nil +} + +func (man *SCachedLoadbalancerCertificateManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CachedLoadbalancerCertificateListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = man.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerCertificateResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerCertificateFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerCertificateResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SCachedLoadbalancerCertificateManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerCertificateResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/loadbalancercertificateresource.go b/pkg/compute/models/loadbalancercertificateresource.go new file mode 100644 index 0000000000..fee578352a --- /dev/null +++ b/pkg/compute/models/loadbalancercertificateresource.go @@ -0,0 +1,156 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SLoadbalancerCertificateResourceBase struct { + // 本地负载均衡证书ID + CertificateId string `width:"36" charset:"ascii" nullable:"false" create:"required" index:"true" list:"user" json:"certificate_id"` +} + +type SLoadbalancerCertificateResourceBaseManager struct{} + +func (self *SLoadbalancerCertificateResourceBase) GetCertificate() *SLoadbalancerCertificate { + cert, err := LoadbalancerCertificateManager.FetchById(self.CertificateId) + if err != nil { + log.Errorf("failed to find certificate %s error: %v", self.CertificateId, err) + return nil + } + return cert.(*SLoadbalancerCertificate) +} + +func (self *SLoadbalancerCertificateResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) api.LoadbalancerCertificateResourceInfo { + return api.LoadbalancerCertificateResourceInfo{} +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerCertificateResourceInfo { + rows := make([]api.LoadbalancerCertificateResourceInfo, len(objs)) + certIds := make([]string, len(objs)) + for i := range objs { + var base *SLoadbalancerCertificateResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + certIds[i] = base.CertificateId + } + certs := make(map[string]SLoadbalancerCertificate) + err := db.FetchStandaloneObjectsByIds(LoadbalancerCertificateManager, certIds, &certs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + for i := range rows { + rows[i] = api.LoadbalancerCertificateResourceInfo{} + if cert, ok := certs[certIds[i]]; ok { + rows[i].Certificate = cert.Name + } + } + return rows +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerCertificateFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Certificate) > 0 { + certObj, err := LoadbalancerCertificateManager.FetchByIdOrName(userCred, query.Certificate) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(LoadbalancerCertificateManager.Keyword(), query.Certificate) + } else { + return nil, errors.Wrap(err, "LoadbalancerCertificateManager.FetchByIdOrName") + } + } + q = q.Equals("certificate_id", certObj.GetId()) + } + return q, nil +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerCertificateFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "certificate" { + certQuery := LoadbalancerCertificateManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(certQuery.Field("name", field)) + q = q.Join(certQuery, sqlchemy.Equals(q.Field("certificate_id"), certQuery.Field("id"))) + q.GroupBy(certQuery.Field("name")) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerCertificateFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + certQ := LoadbalancerCertificateManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := certQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("certificate_id"), subq.Field("id"))) + orders = append(orders, query.OrderByCertificate) + fields = append(fields, subq.Field("name")) + } + return q, orders, fields +} + +func (manager *SLoadbalancerCertificateResourceBaseManager) GetOrderByFields(query api.LoadbalancerCertificateFilterListInput) []string { + return []string{query.Certificate} +} diff --git a/pkg/compute/models/loadbalancercertificates.go b/pkg/compute/models/loadbalancercertificates.go index 0e615641b5..7ddd3d0866 100644 --- a/pkg/compute/models/loadbalancercertificates.go +++ b/pkg/compute/models/loadbalancercertificates.go @@ -36,6 +36,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerCertificateManager struct { @@ -65,8 +66,8 @@ type SLoadbalancerCertificate struct { db.SVirtualResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + // SManagedResourceBase + // SCloudregionResourceBase Certificate string `create:"required" list:"user" update:"user"` PrivateKey string `create:"required" list:"admin" update:"user"` @@ -122,11 +123,34 @@ func (lbcert *SLoadbalancerCertificate) PostCreate(ctx context.Context, userCred lbcert.SetStatus(userCred, api.LB_STATUS_ENABLED, "") } -func (lbcert *SLoadbalancerCertificate) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerCertificateDetails, error) { - var err error - out := api.LoadbalancerCertificateDetails{} - out.VirtualResourceDetails, err = lbcert.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - return out, err +func (lbcert *SLoadbalancerCertificate) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerCertificateDetails, error) { + return api.LoadbalancerCertificateDetails{}, nil +} + +func (manager *SLoadbalancerCertificateManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerCertificateDetails { + rows := make([]api.LoadbalancerCertificateDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerCertificateDetails{ + VirtualResourceDetails: virtRows[i], + } + } + + return rows } func (lbcert *SLoadbalancerCertificate) ValidateDeleteCondition(ctx context.Context) error { @@ -217,7 +241,12 @@ func (man *SLoadbalancerCertificateManager) validateCertKey(ctx context.Context, return data, nil } -func (man *SLoadbalancerCertificateManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerCertificateListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerCertificateManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerCertificateListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") @@ -258,6 +287,33 @@ func (man *SLoadbalancerCertificateManager) ListItemFilter(ctx context.Context, return q, nil } +func (man *SLoadbalancerCertificateManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerCertificateListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerCertificateManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerCertificateManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { data, err := man.validateCertKey(ctx, data) if err != nil { @@ -316,7 +372,7 @@ func (man *SLoadbalancerCertificateManager) InitializeData() error { } // sync certificate to certificate cache - lbcerts = []SLoadbalancerCertificate{} + /*lbcerts = []SLoadbalancerCertificate{} cachedCerts := CachedLoadbalancerCertificateManager.Query("certificate_id").SubQuery() q2 := man.Query().IsNotEmpty("external_id").IsNotEmpty("cloudregion_id").NotIn("id", cachedCerts) if err := q2.All(&lbcerts); err != nil { @@ -337,7 +393,7 @@ func (man *SLoadbalancerCertificateManager) InitializeData() error { if err != nil { return err } - } + }*/ return nil } @@ -368,7 +424,7 @@ func (man *SLoadbalancerCertificateManager) CreateCertificate(userCred mcclient. // usercred cert.DomainId = userCred.GetProjectDomainId() cert.ProjectId = userCred.GetProjectId() - cert.ProjectSrc = string(db.PROJECT_SOURCE_CLOUD) + cert.ProjectSrc = string(apis.OWNER_SOURCE_CLOUD) err = man.TableSpec().Insert(cert) if err != nil { diff --git a/pkg/compute/models/loadbalancerclusterresource.go b/pkg/compute/models/loadbalancerclusterresource.go new file mode 100644 index 0000000000..d7f9cd6203 --- /dev/null +++ b/pkg/compute/models/loadbalancerclusterresource.go @@ -0,0 +1,219 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SLoadbalancerClusterResourceBase struct { + // 归属LB集群 + ClusterId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" json:"cluster_id"` +} + +type SLoadbalancerClusterResourceBaseManager struct { + SZoneResourceBaseManager + SWireResourceBaseManager +} + +func (self *SLoadbalancerClusterResourceBase) GetLoadbalancerCluster() *SLoadbalancerCluster { + cluster, err := LoadbalancerClusterManager.FetchById(self.ClusterId) + if err != nil { + log.Errorf("failed to find LoadbalancerCluster %s error: %v", self.ClusterId, err) + return nil + } + return cluster.(*SLoadbalancerCluster) +} + +func (self *SLoadbalancerClusterResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) api.LoadbalancerClusterResourceInfo { + return api.LoadbalancerClusterResourceInfo{} +} + +func (manager *SLoadbalancerClusterResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerClusterResourceInfo { + rows := make([]api.LoadbalancerClusterResourceInfo, len(objs)) + clusterIds := make([]string, len(objs)) + for i := range objs { + var base *SLoadbalancerClusterResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + clusterIds[i] = base.ClusterId + } + clusters := make(map[string]SLoadbalancerCluster) + err := db.FetchStandaloneObjectsByIds(LoadbalancerClusterManager, clusterIds, clusters) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + zones := make([]interface{}, len(rows)) + wires := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.LoadbalancerClusterResourceInfo{} + if cluster, ok := clusters[clusterIds[i]]; ok { + rows[i].Cluster = cluster.Name + zones[i] = SZoneResourceBase{cluster.ZoneId} + wires[i] = SWireResourceBase{cluster.WireId} + } else { + zones[i] = SZoneResourceBase{} + wires[i] = SWireResourceBase{} + } + } + + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zones, fields, isList) + wireRows := manager.SWireResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, wires, fields, isList) + + for i := range rows { + rows[i].ZoneResourceInfo = zoneRows[i] + rows[i].WireResourceInfoBase = wireRows[i].WireResourceInfoBase + rows[i].VpcId = wireRows[i].VpcId + rows[i].Vpc = wireRows[i].Vpc + } + + return rows +} + +func (manager *SLoadbalancerClusterResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerClusterFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Cluster) > 0 { + clusterObj, err := LoadbalancerClusterManager.FetchByIdOrName(userCred, query.Cluster) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(LoadbalancerClusterManager.Keyword(), query.Cluster) + } else { + return nil, errors.Wrap(err, "LoadbalancerClusterManager.FetchByIdOrName") + } + } + q = q.Equals("cluster_id", clusterObj.GetId()) + } + subq := LoadbalancerClusterManager.Query("id").Snapshot() + subq, err := manager.SZoneResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + wireQuery := api.WireFilterListInput{ + WireFilterListBase: query.WireFilterListBase, + } + subq, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, subq, userCred, wireQuery) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("cluster_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SLoadbalancerClusterResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerClusterFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SLoadbalancerClusterResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "cluster" { + clusterQuery := LoadbalancerClusterManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(clusterQuery.Field("name", field)) + q = q.Join(clusterQuery, sqlchemy.Equals(q.Field("cluster_id"), clusterQuery.Field("id"))) + q.GroupBy(clusterQuery.Field("name")) + return q, nil + } + clusters := LoadbalancerClusterManager.Query("id", "zone_id", "wire_id").SubQuery() + q = q.LeftJoin(clusters, sqlchemy.Equals(q.Field("cluster_id"), clusters.Field("id"))) + q, err := manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SWireResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SLoadbalancerClusterResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerClusterFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + clusterQ := LoadbalancerClusterManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + clusterQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(clusterQ, userCred, query.ZonalFilterListInput) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := clusterQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("cluster_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByCluster}) { + orders = append(orders, query.OrderByCluster) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SLoadbalancerClusterResourceBaseManager) GetOrderByFields(query api.LoadbalancerClusterFilterListInput) []string { + fields := make([]string, 0) + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput) + fields = append(fields, zoneFields...) + fields = append(fields, query.OrderByCluster) + return fields +} diff --git a/pkg/compute/models/loadbalancerclusters.go b/pkg/compute/models/loadbalancerclusters.go index 64ee79e5f1..382eb09714 100644 --- a/pkg/compute/models/loadbalancerclusters.go +++ b/pkg/compute/models/loadbalancerclusters.go @@ -28,10 +28,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerClusterManager struct { db.SStandaloneResourceBaseManager + SZoneResourceBaseManager + SWireResourceBaseManager } var LoadbalancerClusterManager *SLoadbalancerClusterManager @@ -51,46 +54,84 @@ func init() { type SLoadbalancerCluster struct { db.SStandaloneResourceBase SZoneResourceBase - WireId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"optional" update:"admin"` -} - -func (man *SLoadbalancerClusterManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, man) -} - -func (man *SLoadbalancerClusterManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, man) -} - -func (lbc *SLoadbalancerCluster) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, lbc) -} - -func (lbc *SLoadbalancerCluster) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, lbc) -} - -func (lbc *SLoadbalancerCluster) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, lbc) + SWireResourceBase + //WireId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"optional" update:"admin"` } // 负载均衡集群列表 -func (man *SLoadbalancerClusterManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerClusterListInput) (*sqlchemy.SQuery, error) { - q, err := man.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (man *SLoadbalancerClusterManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerClusterListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "zone", ModelKeyword: "zone", OwnerId: userCred}, - {Key: "wire", ModelKeyword: "wire", OwnerId: userCred}, - }) + q, err = man.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } + wireQuery := api.WireFilterListInput{ + WireFilterListBase: query.WireFilterListBase, + } + q, err = man.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, wireQuery) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter") + } + return q, nil } +func (man *SLoadbalancerClusterManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerClusterListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = man.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + wireQuery := api.WireFilterListInput{ + WireFilterListBase: query.WireFilterListBase, + } + q, err = man.SWireResourceBaseManager.OrderByExtraFields(ctx, q, userCred, wireQuery) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerClusterManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SWireResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerClusterManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { zoneV := validators.NewModelIdOrNameValidator("zone", "zone", ownerId) wireV := validators.NewModelIdOrNameValidator("wire", "wire", ownerId) @@ -172,15 +213,38 @@ func (lbc *SLoadbalancerCluster) ValidateDeleteCondition(ctx context.Context) er return lbc.SStandaloneResourceBase.ValidateDeleteCondition(ctx) } -func (lbc *SLoadbalancerCluster) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerCusterDetails, error) { - var err error - out := api.LoadbalancerCusterDetails{} - out.StandaloneResourceDetails, err = lbc.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (lbc *SLoadbalancerCluster) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerClusterDetails, error) { + return api.LoadbalancerClusterDetails{}, nil +} + +func (man *SLoadbalancerClusterManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerClusterDetails { + rows := make([]api.LoadbalancerClusterDetails, len(objs)) + + stdRows := man.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := man.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + wireRows := man.SWireResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerClusterDetails{ + StandaloneResourceDetails: stdRows[i], + ZoneResourceInfo: zoneRows[i], + WireResourceInfoBase: wireRows[i].WireResourceInfoBase, + } } - out.ZoneInfo = lbc.SZoneResourceBase.GetExtraDetails(ctx, userCred, query) - return out, nil + + return rows } func (lbc *SLoadbalancerCluster) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { @@ -253,10 +317,12 @@ func (man *SLoadbalancerClusterManager) getLoadbalancerAgents(clusterId string) func (man *SLoadbalancerClusterManager) InitializeData() error { // find existing lb with empty clusterid lbs := []SLoadbalancer{} - lbQ := LoadbalancerManager.Query(). - IsFalse("pending_deleted"). - IsNullOrEmpty("manager_id"). - IsNullOrEmpty("cluster_id") + lbQ := LoadbalancerManager.Query() + vpcs := VpcManager.Query().SubQuery() + lbQ = lbQ.Join(vpcs, sqlchemy.Equals(lbQ.Field("vpc_id"), vpcs.Field("id"))) + lbQ = lbQ.Filter(sqlchemy.IsFalse(lbQ.Field("pending_deleted"))) + lbQ = lbQ.Filter(sqlchemy.IsNullOrEmpty(vpcs.Field("manager_id"))) + lbQ = lbQ.Filter(sqlchemy.IsNullOrEmpty(lbQ.Field("cluster_id"))) if err := db.FetchModelObjects(LoadbalancerManager, lbQ, &lbs); err != nil { return errors.Wrap(err, "find lb with empty cluster_id") } diff --git a/pkg/compute/models/loadbalancerhuaweicachedlbb.go b/pkg/compute/models/loadbalancerhuaweicachedlbb.go index eb79b5078e..b4a043f7a0 100644 --- a/pkg/compute/models/loadbalancerhuaweicachedlbb.go +++ b/pkg/compute/models/loadbalancerhuaweicachedlbb.go @@ -27,6 +27,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -295,9 +296,18 @@ func newLocalBackendFromCloudLoadbalancerBackend(ctx context.Context, userCred m // return nil, err //} + lbbgRegion := loadbalancerBackendgroup.GetRegion() + if lbbgRegion == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancerBackendgroup is not attached to any region") + } + lbbgProvider := loadbalancerBackendgroup.GetCloudprovider() + if lbbgProvider == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancerBackendgroup is not attached to any cloudprovider") + } + man := LoadbalancerBackendManager - q := man.Query().IsFalse("pending_deleted").Equals("backend_group_id", loadbalancerBackendgroup.Id).Equals("cloudregion_id", loadbalancerBackendgroup.CloudregionId) - q = q.Equals("manager_id", loadbalancerBackendgroup.ManagerId).Equals("weight", extLoadbalancerBackend.GetWeight()).Equals("port", extLoadbalancerBackend.GetPort()) + q := man.Query().IsFalse("pending_deleted").Equals("backend_group_id", loadbalancerBackendgroup.Id).Equals("cloudregion_id", lbbgRegion.Id) + q = q.Equals("manager_id", lbbgProvider.Id).Equals("weight", extLoadbalancerBackend.GetWeight()).Equals("port", extLoadbalancerBackend.GetPort()) q = q.Equals("backend_id", guest.Id) //q = q.Equals("address", address) lbbs := []SLoadbalancerBackend{} @@ -315,8 +325,8 @@ func newLocalBackendFromCloudLoadbalancerBackend(ctx context.Context, userCred m lbb.BackendGroupId = loadbalancerBackendgroup.Id lbb.ExternalId = "" - lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId - lbb.ManagerId = loadbalancerBackendgroup.ManagerId + // lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId + // lbb.ManagerId = loadbalancerBackendgroup.ManagerId baseName := extLoadbalancerBackend.GetName() if len(baseName) == 0 { @@ -339,7 +349,7 @@ func newLocalBackendFromCloudLoadbalancerBackend(ctx context.Context, userCred m return nil, err } - SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, loadbalancerBackendgroup.ManagerId) + SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, lbbgProvider.Id) db.OpsLog.LogEvent(lbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred) return lbb, nil diff --git a/pkg/compute/models/loadbalancerhuaweicachedlbbg.go b/pkg/compute/models/loadbalancerhuaweicachedlbbg.go index 8f0c493279..cbb63de004 100644 --- a/pkg/compute/models/loadbalancerhuaweicachedlbbg.go +++ b/pkg/compute/models/loadbalancerhuaweicachedlbbg.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -216,7 +217,7 @@ func (man *SHuaweiCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.C } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId()) + err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId(), provider) if err != nil { syncResult.UpdateError(err) } else { @@ -227,7 +228,7 @@ func (man *SHuaweiCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.C } } for i := 0; i < len(added); i++ { - new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId) + new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -286,7 +287,7 @@ func (lbbg *SHuaweiCachedLbbg) isBackendsMatch(backends []SLoadbalancerBackend, return true } -func (lbbg *SHuaweiCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) error { +func (lbbg *SHuaweiCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { lbbg.SetModelManager(HuaweiCachedLbbgManager, lbbg) ibackends, err := extLoadbalancerBackendgroup.GetILoadbalancerBackends() @@ -306,7 +307,7 @@ func (lbbg *SHuaweiCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context var newLocalLbbg *SLoadbalancerBackendGroup if !lbbg.isBackendsMatch(backends, ibackends) { - newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) + newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return errors.Wrap(err, "HuaweiCachedLbbg.SyncWithCloudLoadbalancerBackendgroup.newLocalBackendgroupFromCloudLoadbalancerBackendgroup") } @@ -324,12 +325,12 @@ func (lbbg *SHuaweiCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context } db.OpsLog.LogSyncUpdate(lbbg, diff, userCred) - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) return err } -func (man *SHuaweiCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SHuaweiCachedLbbg, error) { - LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) +func (man *SHuaweiCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SHuaweiCachedLbbg, error) { + LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return nil, err } @@ -337,8 +338,13 @@ func (man *SHuaweiCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx co lbbg := &SHuaweiCachedLbbg{} lbbg.SetModelManager(man, lbbg) - lbbg.ManagerId = lb.ManagerId - lbbg.CloudregionId = lb.CloudregionId + region := lb.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancer is not attached to any region") + } + + lbbg.ManagerId = provider.Id + lbbg.CloudregionId = region.Id lbbg.LoadbalancerId = lb.Id lbbg.BackendGroupId = LocalLbbg.GetId() lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId() @@ -357,20 +363,20 @@ func (man *SHuaweiCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx co return nil, err } - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred) return lbbg, nil } -func newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SLoadbalancerBackendGroup, error) { +func newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SLoadbalancerBackendGroup, error) { localman := LoadbalancerBackendGroupManager lbbg := &SLoadbalancerBackendGroup{} lbbg.SetModelManager(localman, lbbg) lbbg.LoadbalancerId = lb.Id - lbbg.CloudregionId = lb.CloudregionId - lbbg.ManagerId = lb.ManagerId + // lbbg.CloudregionId = lb.CloudregionId + // lbbg.ManagerId = lb.ManagerId lbbg.ExternalId = "" newName, err := db.GenerateName(localman, syncOwnerId, extLoadbalancerBackendgroup.GetName()) @@ -387,7 +393,7 @@ func newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx context.Context, return nil, err } - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred) diff --git a/pkg/compute/models/loadbalancerlistenerresource.go b/pkg/compute/models/loadbalancerlistenerresource.go new file mode 100644 index 0000000000..fb058aa078 --- /dev/null +++ b/pkg/compute/models/loadbalancerlistenerresource.go @@ -0,0 +1,216 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SLoadbalancerListenerResourceBase struct { + // 负载均衡监听器ID + ListenerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"listener_id"` +} + +type SLoadbalancerListenerResourceBaseManager struct { + SLoadbalancerResourceBaseManager +} + +func (self *SLoadbalancerListenerResourceBase) GetLoadbalancerListener() *SLoadbalancerListener { + listener, err := LoadbalancerListenerManager.FetchById(self.ListenerId) + if err != nil { + log.Errorf("failed to find LoadbalancerCluster %s error: %v", self.ListenerId, err) + return nil + } + return listener.(*SLoadbalancerListener) +} + +func (self *SLoadbalancerListenerResourceBase) GetCloudprovider() *SCloudprovider { + listener := self.GetLoadbalancerListener() + if listener != nil { + return listener.GetCloudprovider() + } + return nil +} + +func (self *SLoadbalancerListenerResourceBase) GetProviderName() string { + listener := self.GetLoadbalancerListener() + if listener != nil { + return listener.GetProviderName() + } + return "" +} + +func (self *SLoadbalancerListenerResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) api.LoadbalancerListenerResourceInfo { + return api.LoadbalancerListenerResourceInfo{} +} + +func (manager *SLoadbalancerListenerResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerListenerResourceInfo { + rows := make([]api.LoadbalancerListenerResourceInfo, len(objs)) + listenerIds := make([]string, len(objs)) + for i := range objs { + var base *SLoadbalancerListenerResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + listenerIds[i] = base.ListenerId + } + listeners := make(map[string]SLoadbalancerListener) + err := db.FetchStandaloneObjectsByIds(LoadbalancerListenerManager, listenerIds, listeners) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + lbs := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.LoadbalancerListenerResourceInfo{} + if listener, ok := listeners[listenerIds[i]]; ok { + rows[i].Listener = listener.Name + rows[i].LoadbalancerId = listener.LoadbalancerId + } + lbs[i] = SLoadbalancerResourceBase{rows[i].LoadbalancerId} + } + + lbRows := manager.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, lbs, fields, isList) + + for i := range rows { + rows[i].LoadbalancerResourceInfo = lbRows[i] + } + + return rows +} + +func (manager *SLoadbalancerListenerResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Listener) > 0 { + listenerObj, err := LoadbalancerListenerManager.FetchByIdOrName(userCred, query.Listener) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(LoadbalancerListenerManager.Keyword(), query.Listener) + } else { + return nil, errors.Wrap(err, "LoadbalancerListenerManager.FetchByIdOrName") + } + } + q = q.Equals("listener_id", listenerObj.GetId()) + } + subq := LoadbalancerListenerManager.Query("id").Snapshot() + subq, err := manager.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.LoadbalancerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("listener_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SLoadbalancerListenerResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SLoadbalancerListenerResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "listener" { + listenerQuery := LoadbalancerListenerManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(listenerQuery.Field("name", field)) + q = q.Join(listenerQuery, sqlchemy.Equals(q.Field("listener_id"), listenerQuery.Field("id"))) + q.GroupBy(listenerQuery.Field("name")) + return q, nil + } + listeners := LoadbalancerListenerManager.Query("id", "loadbalancer_id").SubQuery() + q = q.LeftJoin(listeners, sqlchemy.Equals(q.Field("listener_id"), listeners.Field("id"))) + q, err := manager.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SLoadbalancerListenerResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + listenerQ := LoadbalancerListenerManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SLoadbalancerResourceBaseManager.GetOrderByFields(query.LoadbalancerFilterListInput)) { + var lbOrders []string + var lbFields []sqlchemy.IQueryField + listenerQ, lbOrders, lbFields = manager.SLoadbalancerResourceBaseManager.GetOrderBySubQuery(listenerQ, userCred, query.LoadbalancerFilterListInput) + if len(lbOrders) > 0 { + orders = append(orders, lbOrders...) + fields = append(fields, lbFields...) + } + } + + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := listenerQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("listener_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByListener}) { + orders = append(orders, query.OrderByListener) + fields = append(fields, subq.Field("name")) + } + } + + return q, orders, fields +} + +func (manager *SLoadbalancerListenerResourceBaseManager) GetOrderByFields(query api.LoadbalancerListenerFilterListInput) []string { + fields := make([]string, 0) + lbFields := manager.SLoadbalancerResourceBaseManager.GetOrderByFields(query.LoadbalancerFilterListInput) + fields = append(fields, lbFields...) + fields = append(fields, query.OrderByListener) + return fields +} diff --git a/pkg/compute/models/loadbalancerlistenerrules.go b/pkg/compute/models/loadbalancerlistenerrules.go index 9501ed86f6..7b9a2bff03 100644 --- a/pkg/compute/models/loadbalancerlistenerrules.go +++ b/pkg/compute/models/loadbalancerlistenerrules.go @@ -34,11 +34,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerListenerRuleManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SLoadbalancerListenerResourceBaseManager } var LoadbalancerListenerRuleManager *SLoadbalancerListenerRuleManager @@ -59,11 +61,13 @@ type SLoadbalancerListenerRule struct { db.SVirtualResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + SLoadbalancerListenerResourceBase + + // 默认转发策略,目前只有aws用到其它云都是false + IsDefault bool `default:"false" nullable:"true" list:"user" create:"optional"` + + // ListenerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - IsDefault bool `default:"false" nullable:"true" list:"user" create:"optional"` // 默认转发策略,目前只有aws用到其它云都是false - ListenerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user"` Domain string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional"` @@ -380,15 +384,26 @@ func (man *SLoadbalancerListenerRuleManager) pendingDeleteSubs(ctx context.Conte } } -func (man *SLoadbalancerListenerRuleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerListenerRuleListInput) (*sqlchemy.SQuery, error) { +// 负载均衡监听器规则列表 +func (man *SLoadbalancerListenerRuleManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerRuleListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } + q, err = man.SLoadbalancerListenerResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerListenerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerListenerResourceBaseManager.ListItemFilter") + } + // userProjId := userCred.GetProjectId() data := jsonutils.Marshal(query).(*jsonutils.JSONDict) q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "listener", ModelKeyword: "loadbalancerlistener", OwnerId: userCred}, + // {Key: "listener", ModelKeyword: "loadbalancerlistener", OwnerId: userCred}, {Key: "backend_group", ModelKeyword: "loadbalancerbackendgroup", OwnerId: userCred}, }) if err != nil { @@ -397,6 +412,41 @@ func (man *SLoadbalancerListenerRuleManager) ListItemFilter(ctx context.Context, return q, nil } +func (man *SLoadbalancerListenerRuleManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerRuleListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerListenerResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerListenerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerListenerResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerListenerRuleManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerListenerResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerListenerRuleManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { input := apis.VirtualResourceCreateInput{} err := data.Unmarshal(&input) @@ -498,14 +548,16 @@ func (lbr *SLoadbalancerListenerRule) ValidateUpdateData(ctx context.Context, us return region.GetDriver().ValidateUpdateLoadbalancerListenerRuleData(ctx, userCred, data, backendGroupV.Model) } -func (lbr *SLoadbalancerListenerRule) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerListenerRuleDetails, error) { - var err error - out := api.LoadbalancerListenerRuleDetails{} - out.VirtualResourceDetails, err = lbr.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - out.CloudregionInfo = lbr.SCloudregionResourceBase.GetExtraDetails(ctx, userCred, query) +func (lbr *SLoadbalancerListenerRule) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerListenerRuleDetails, error) { + return api.LoadbalancerListenerRuleDetails{}, nil +} + +func (lbr *SLoadbalancerListenerRule) getMoreDetails(out api.LoadbalancerListenerRuleDetails) (api.LoadbalancerListenerRuleDetails, error) { if lbr.BackendGroupId == "" { log.Errorf("loadbalancer listener rule %s(%s): empty backend group field", lbr.Name, lbr.Id) return out, nil @@ -521,14 +573,38 @@ func (lbr *SLoadbalancerListenerRule) GetExtraDetails(ctx context.Context, userC return out, nil } -func (lbr *SLoadbalancerListenerRule) GetLoadbalancerListener() *SLoadbalancerListener { +func (man *SLoadbalancerListenerRuleManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerListenerRuleDetails { + rows := make([]api.LoadbalancerListenerRuleDetails, len(objs)) + + virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + listenerRows := man.SLoadbalancerListenerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerListenerRuleDetails{ + VirtualResourceDetails: virtRows[i], + LoadbalancerListenerResourceInfo: listenerRows[i], + } + rows[i], _ = objs[i].(*SLoadbalancerListenerRule).getMoreDetails(rows[i]) + } + + return rows +} + +/*func (lbr *SLoadbalancerListenerRule) GetLoadbalancerListener() *SLoadbalancerListener { listener, err := LoadbalancerListenerManager.FetchById(lbr.ListenerId) if err != nil { log.Errorf("failed to find listener for loadbalancer listener rule %s", lbr.Name) return nil } return listener.(*SLoadbalancerListener) -} +}*/ func (lbr *SLoadbalancerListenerRule) GetRegion() *SCloudregion { if listener := lbr.GetLoadbalancerListener(); listener != nil { @@ -595,7 +671,7 @@ func (man *SLoadbalancerListenerRuleManager) SyncLoadbalancerListenerRules(ctx c } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerListenerRule(ctx, userCred, commonext[i], syncOwnerId) + err = commondb[i].SyncWithCloudLoadbalancerListenerRule(ctx, userCred, commonext[i], syncOwnerId, provider) if err != nil { syncResult.UpdateError(err) } else { @@ -604,7 +680,7 @@ func (man *SLoadbalancerListenerRuleManager) SyncLoadbalancerListenerRules(ctx c } } for i := 0; i < len(added); i++ { - local, err := man.newFromCloudLoadbalancerListenerRule(ctx, userCred, listener, added[i], syncOwnerId) + local, err := man.newFromCloudLoadbalancerListenerRule(ctx, userCred, listener, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -717,14 +793,21 @@ func (lbr *SLoadbalancerListenerRule) updateCachedLoadbalancerBackendGroupAssoci return nil } -func (man *SLoadbalancerListenerRuleManager) newFromCloudLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, listener *SLoadbalancerListener, extRule cloudprovider.ICloudLoadbalancerListenerRule, syncOwnerId mcclient.IIdentityProvider) (*SLoadbalancerListenerRule, error) { +func (man *SLoadbalancerListenerRuleManager) newFromCloudLoadbalancerListenerRule( + ctx context.Context, + userCred mcclient.TokenCredential, + listener *SLoadbalancerListener, + extRule cloudprovider.ICloudLoadbalancerListenerRule, + syncOwnerId mcclient.IIdentityProvider, + provider *SCloudprovider, +) (*SLoadbalancerListenerRule, error) { lbr := &SLoadbalancerListenerRule{} lbr.SetModelManager(man, lbr) lbr.ExternalId = extRule.GetGlobalId() lbr.ListenerId = listener.Id - lbr.ManagerId = listener.ManagerId - lbr.CloudregionId = listener.CloudregionId + //lbr.ManagerId = listener.ManagerId + //lbr.CloudregionId = listener.CloudregionId newName, err := db.GenerateName(man, syncOwnerId, extRule.GetName()) if err != nil { @@ -744,7 +827,7 @@ func (man *SLoadbalancerListenerRuleManager) newFromCloudLoadbalancerListenerRul return nil, errors.Wrap(err, "LoadbalancerListenerRuleManager.newFromCloudLoadbalancerListenerRule") } - SyncCloudProject(userCred, lbr, syncOwnerId, extRule, listener.ManagerId) + SyncCloudProject(userCred, lbr, syncOwnerId, extRule, provider.Id) db.OpsLog.LogEvent(lbr, db.ACT_CREATE, lbr.GetShortDesc(ctx), userCred) @@ -764,12 +847,18 @@ func (lbr *SLoadbalancerListenerRule) syncRemoveCloudLoadbalancerListenerRule(ct return err } -func (lbr *SLoadbalancerListenerRule) SyncWithCloudLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, extRule cloudprovider.ICloudLoadbalancerListenerRule, syncOwnerId mcclient.IIdentityProvider) error { - listener := lbr.GetLoadbalancerListener() +func (lbr *SLoadbalancerListenerRule) SyncWithCloudLoadbalancerListenerRule( + ctx context.Context, + userCred mcclient.TokenCredential, + extRule cloudprovider.ICloudLoadbalancerListenerRule, + syncOwnerId mcclient.IIdentityProvider, + provider *SCloudprovider, +) error { + // listener := lbr.GetLoadbalancerListener() diff, err := db.UpdateWithLock(ctx, lbr, func() error { lbr.constructFieldsFromCloudListenerRule(userCred, extRule) - lbr.ManagerId = listener.ManagerId - lbr.CloudregionId = listener.CloudregionId + // lbr.ManagerId = provider.Id + // lbr.CloudregionId = listener.CloudregionId return nil }) if err != nil { @@ -783,12 +872,12 @@ func (lbr *SLoadbalancerListenerRule) SyncWithCloudLoadbalancerListenerRule(ctx db.OpsLog.LogSyncUpdate(lbr, diff, userCred) - SyncCloudProject(userCred, lbr, syncOwnerId, extRule, listener.ManagerId) + SyncCloudProject(userCred, lbr, syncOwnerId, extRule, provider.Id) return nil } -func (manager *SLoadbalancerListenerRuleManager) InitializeData() error { +/*func (manager *SLoadbalancerListenerRuleManager) InitializeData() error { rules := []SLoadbalancerListenerRule{} q := manager.Query() q = q.Filter(sqlchemy.IsNullOrEmpty(q.Field("cloudregion_id"))) @@ -809,7 +898,7 @@ func (manager *SLoadbalancerListenerRuleManager) InitializeData() error { } } return nil -} +}*/ func (manager *SLoadbalancerListenerRuleManager) GetResourceCount() ([]db.SProjectResourceCount, error) { virts := manager.Query().IsFalse("pending_deleted") diff --git a/pkg/compute/models/loadbalancerlisteners.go b/pkg/compute/models/loadbalancerlisteners.go index 0e38ba8380..f54c46da9b 100644 --- a/pkg/compute/models/loadbalancerlisteners.go +++ b/pkg/compute/models/loadbalancerlisteners.go @@ -35,11 +35,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerListenerManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SLoadbalancerResourceBaseManager } var LoadbalancerListenerManager *SLoadbalancerListenerManager @@ -62,7 +64,7 @@ type SLoadbalancerHTTPRateLimiter struct { } type SLoadbalancerRateLimiter struct { - EgressMbps int `nullable:"true" list:"user" get:"user" create:"optional" update:"user"` + EgressMbps int `nullable:"true" list:"user" get:"user" create:"optional" update:"user" json:"egress_mbps"` } type SLoadbalancerHealthCheck struct { @@ -121,10 +123,9 @@ type SLoadbalancerListener struct { db.SVirtualResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + SLoadbalancerResourceBase + //LoadbalancerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - LoadbalancerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` ListenerType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required"` ListenerPort int `nullable:"false" list:"user" create:"required"` BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user"` @@ -205,24 +206,25 @@ func (man *SLoadbalancerListenerManager) pendingDeleteSubs(ctx context.Context, } // 负载均衡监听器Listener列表 -func (man *SLoadbalancerListenerManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerListenerListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerListenerManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + q, err = man.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter") } // userProjId := userCred.GetProjectId() data := jsonutils.Marshal(query).(*jsonutils.JSONDict) q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "loadbalancer", ModelKeyword: "loadbalancer", OwnerId: userCred}, + // {Key: "loadbalancer", ModelKeyword: "loadbalancer", OwnerId: userCred}, {Key: "backend_group", ModelKeyword: "loadbalancerbackendgroup", OwnerId: userCred}, {Key: "acl", ModelKeyword: "cachedloadbalanceracl", OwnerId: userCred}, // {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, @@ -234,6 +236,41 @@ func (man *SLoadbalancerListenerManager) ListItemFilter(ctx context.Context, q * return q, nil } +func (man *SLoadbalancerListenerManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListenerListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SLoadbalancerResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerListenerManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { lbV := validators.NewModelIdOrNameValidator("loadbalancer", "loadbalancer", ownerId) if err := lbV.Validate(data); err != nil { @@ -262,9 +299,9 @@ func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context, return nil, httperrors.NewResourceNotFoundError("failed to find region for loadbalancer %s", lb.Name) } - if len(lb.ManagerId) > 0 { - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - } + // if len(lb.ManagerId) > 0 { + // data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) + // } return region.GetDriver().ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroupV.Model) } @@ -299,12 +336,12 @@ func (man *SLoadbalancerListenerManager) ValidateAcl(aclStatusV *validators.Vali return nil } -func (lblis *SLoadbalancerListener) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (lblis *SLoadbalancerListener) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) bool { return lblis.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, lblis, "status") } -func (lblis *SLoadbalancerListener) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if _, err := lblis.SVirtualResourceBase.PerformStatus(ctx, userCred, query, data); err != nil { +func (lblis *SLoadbalancerListener) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { + if _, err := lblis.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input); err != nil { return nil, err } if lblis.Status == api.LB_STATUS_ENABLED { @@ -405,23 +442,16 @@ func (lblis *SLoadbalancerListener) StartLoadBalancerListenerSyncTask(ctx contex return nil } -func (lblis *SLoadbalancerListener) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerListenerDetails, error) { - var err error - out := api.LoadbalancerListenerDetails{} - out.VirtualResourceDetails, err = lblis.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } +func (lblis *SLoadbalancerListener) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerListenerDetails, error) { + return api.LoadbalancerListenerDetails{}, nil +} - { - lb, err := LoadbalancerManager.FetchById(lblis.LoadbalancerId) - if err != nil { - log.Errorf("loadbalancer listener %s(%s): fetch loadbalancer (%s) error: %s", - lblis.Name, lblis.Id, lblis.LoadbalancerId, err) - return out, err - } - out.Loadbalancer = lb.GetName() - } +func (lblis *SLoadbalancerListener) getMoreDetails(out api.LoadbalancerListenerDetails) (api.LoadbalancerListenerDetails, error) { { if lblis.BackendGroupId != "" { lbbg, err := LoadbalancerBackendGroupManager.FetchById(lblis.BackendGroupId) @@ -445,11 +475,34 @@ func (lblis *SLoadbalancerListener) GetExtraDetails(ctx context.Context, userCre out.OriginCertificateId = cert.CertificateId } } - out.CloudregionInfo = lblis.SCloudregionResourceBase.GetExtraDetails(ctx, userCred, query) return out, nil } +func (manager *SLoadbalancerListenerManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerListenerDetails { + rows := make([]api.LoadbalancerListenerDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + lbRows := manager.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerListenerDetails{ + VirtualResourceDetails: virtRows[i], + LoadbalancerResourceInfo: lbRows[i], + } + rows[i], _ = objs[i].(*SLoadbalancerListener).getMoreDetails(rows[i]) + } + + return rows +} + func (lblis *SLoadbalancerListener) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { lblis.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data) @@ -690,8 +743,13 @@ func (lblis *SLoadbalancerListener) GetLoadbalancerCertificate() (*SCachedLoadba return nil, nil } + region := lblis.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancer listener is not attached to any region") + } + ret := &SCachedLoadbalancerCertificate{} - err := CachedLoadbalancerCertificateManager.Query().Equals("id", lblis.CachedCertificateId).Equals("cloudregion_id", lblis.CloudregionId).IsFalse("pending_deleted").First(ret) + err := CachedLoadbalancerCertificateManager.Query().Equals("id", lblis.CachedCertificateId).Equals("cloudregion_id", region.Id).IsFalse("pending_deleted").First(ret) if err != nil { if err == sql.ErrNoRows { return nil, nil @@ -813,7 +871,7 @@ func (man *SLoadbalancerListenerManager) SyncLoadbalancerListeners(ctx context.C } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerListener(ctx, userCred, lb, commonext[i], syncOwnerId) + err = commondb[i].SyncWithCloudLoadbalancerListener(ctx, userCred, lb, commonext[i], syncOwnerId, provider) if err != nil { syncResult.UpdateError(err) } else { @@ -824,7 +882,7 @@ func (man *SLoadbalancerListenerManager) SyncLoadbalancerListeners(ctx context.C } } for i := 0; i < len(added); i++ { - new, err := man.newFromCloudLoadbalancerListener(ctx, userCred, lb, added[i], syncOwnerId) + new, err := man.newFromCloudLoadbalancerListener(ctx, userCred, lb, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { @@ -838,8 +896,8 @@ func (man *SLoadbalancerListenerManager) SyncLoadbalancerListeners(ctx context.C } func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener) { - lblis.ManagerId = lb.ManagerId - lblis.CloudregionId = lb.CloudregionId + // lblis.ManagerId = lb.ManagerId + // lblis.CloudregionId = lb.CloudregionId // lblis.Name = extListener.GetName() lblis.ListenerType = extListener.GetListenerType() lblis.EgressMbps = extListener.GetEgressMbps() @@ -1058,7 +1116,7 @@ func (lblis *SLoadbalancerListener) syncRemoveCloudLoadbalancerListener(ctx cont return err } -func (lblis *SLoadbalancerListener) SyncWithCloudLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener, syncOwnerId mcclient.IIdentityProvider) error { +func (lblis *SLoadbalancerListener) SyncWithCloudLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { diff, err := db.UpdateWithLock(ctx, lblis, func() error { lblis.constructFieldsFromCloudListener(userCred, lb, extListener) return nil @@ -1074,12 +1132,12 @@ func (lblis *SLoadbalancerListener) SyncWithCloudLoadbalancerListener(ctx contex db.OpsLog.LogSyncUpdate(lblis, diff, userCred) - SyncCloudProject(userCred, lblis, syncOwnerId, extListener, lblis.ManagerId) + SyncCloudProject(userCred, lblis, syncOwnerId, extListener, provider.Id) return nil } -func (man *SLoadbalancerListenerManager) newFromCloudLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener, syncOwnerId mcclient.IIdentityProvider) (*SLoadbalancerListener, error) { +func (man *SLoadbalancerListenerManager) newFromCloudLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SLoadbalancerListener, error) { lblis := &SLoadbalancerListener{} lblis.SetModelManager(man, lblis) @@ -1104,7 +1162,7 @@ func (man *SLoadbalancerListenerManager) newFromCloudLoadbalancerListener(ctx co return nil, errors.Wrap(err, "LoadbalancerListener.newFromCloudLoadbalancerListener") } - SyncCloudProject(userCred, lblis, syncOwnerId, extListener, lblis.ManagerId) + SyncCloudProject(userCred, lblis, syncOwnerId, extListener, provider.Id) db.OpsLog.LogEvent(lblis, db.ACT_CREATE, lblis.GetShortDesc(ctx), userCred) @@ -1112,7 +1170,7 @@ func (man *SLoadbalancerListenerManager) newFromCloudLoadbalancerListener(ctx co } func (manager *SLoadbalancerListenerManager) InitializeData() error { - listeners := []SLoadbalancerListener{} + /*listeners := []SLoadbalancerListener{} q := manager.Query() q = q.Filter(sqlchemy.IsNullOrEmpty(q.Field("cloudregion_id"))) if err := db.FetchModelObjects(manager, q, &listeners); err != nil { @@ -1130,7 +1188,7 @@ func (manager *SLoadbalancerListenerManager) InitializeData() error { log.Errorf("failed to update loadbalancer listener %s cloudregion_id", listener.Name) } } - } + }*/ return nil } diff --git a/pkg/compute/models/loadbalancernetworks.go b/pkg/compute/models/loadbalancernetworks.go index 2569911c1b..2e6f85a7a3 100644 --- a/pkg/compute/models/loadbalancernetworks.go +++ b/pkg/compute/models/loadbalancernetworks.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancernetworkManager struct { @@ -213,15 +214,59 @@ func (ln *SLoadbalancerNetwork) Detach(ctx context.Context, userCred mcclient.To return db.DetachJoint(ctx, userCred, ln) } -func (ln *SLoadbalancerNetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancernetworkDetails, error) { - var err error - out := api.LoadbalancernetworkDetails{} - out.ModelBaseDetails, err = ln.SVirtualJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (ln *SLoadbalancerNetwork) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancernetworkDetails, error) { + return api.LoadbalancernetworkDetails{}, nil +} + +func (manager *SLoadbalancernetworkManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancernetworkDetails { + rows := make([]api.LoadbalancernetworkDetails, len(objs)) + + jointRows := manager.SVirtualJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + lbIds := make([]string, len(rows)) + netIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = api.LoadbalancernetworkDetails{ + VirtualJointResourceBaseDetails: jointRows[i], + } + lbIds[i] = objs[i].(*SLoadbalancerNetwork).LoadbalancerId + netIds[i] = objs[i].(*SLoadbalancerNetwork).NetworkId } - out.Loadbalancer, out.Network = db.JointModelExtra(ln) - return out, nil + + lbIdMaps, err := db.FetchIdNameMap2(LoadbalancerManager, lbIds) + if err != nil { + log.Errorf("db.FetchIdNameMap2 for lbIds fail %s", err) + return rows + } + netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds) + if err != nil { + log.Errorf("db.FetchIdNameMap2 for netIds fail %s", err) + return rows + } + + for i := range rows { + if name, ok := lbIdMaps[lbIds[i]]; ok { + rows[i].Loadbalancer = name + } + if name, ok := netIdMaps[netIds[i]]; ok { + rows[i].Network = name + } + } + + return rows } func totalLBNicCount( diff --git a/pkg/compute/models/loadbalancerqcloudcachedlbbg.go b/pkg/compute/models/loadbalancerqcloudcachedlbbg.go index b01045d8d3..91f0832cf2 100644 --- a/pkg/compute/models/loadbalancerqcloudcachedlbbg.go +++ b/pkg/compute/models/loadbalancerqcloudcachedlbbg.go @@ -30,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -179,7 +180,7 @@ func (lbbg *SQcloudCachedLbbg) isBackendsMatch(backends []SLoadbalancerBackend, return true } -func (lbbg *SQcloudCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) error { +func (lbbg *SQcloudCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { lbbg.SetModelManager(QcloudCachedLbbgManager, lbbg) ibackends, err := extLoadbalancerBackendgroup.GetILoadbalancerBackends() @@ -199,7 +200,7 @@ func (lbbg *SQcloudCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context var newLocalLbbg *SLoadbalancerBackendGroup if !lbbg.isBackendsMatch(backends, ibackends) { - newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) + newLocalLbbg, err = newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return errors.Wrap(err, "QcloudCachedLbbg.SyncWithCloudLoadbalancerBackendgroup.newLocalBackendgroupFromCloudLoadbalancerBackendgroup") } @@ -217,7 +218,7 @@ func (lbbg *SQcloudCachedLbbg) SyncWithCloudLoadbalancerBackendgroup(ctx context } db.OpsLog.LogSyncUpdate(lbbg, diff, userCred) - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) return err } @@ -288,7 +289,7 @@ func (man *SQcloudCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.C } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId()) + err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i], provider.GetOwnerId(), provider) if err != nil { syncResult.UpdateError(err) } else { @@ -299,12 +300,12 @@ func (man *SQcloudCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.C } } for i := 0; i < len(added); i++ { - new, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId) + newlbbg, err := man.newFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, added[i], syncOwnerId, provider) if err != nil { syncResult.AddError(err) } else { - syncMetadata(ctx, userCred, new, added[i]) - localLbgs = append(localLbgs, *new) + syncMetadata(ctx, userCred, newlbbg, added[i]) + localLbgs = append(localLbgs, *newlbbg) remoteLbbgs = append(remoteLbbgs, added[i]) syncResult.Add() } @@ -312,8 +313,8 @@ func (man *SQcloudCachedLbbgManager) SyncLoadbalancerBackendgroups(ctx context.C return localLbgs, remoteLbbgs, syncResult } -func (man *SQcloudCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider) (*SQcloudCachedLbbg, error) { - LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId) +func (man *SQcloudCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extLoadbalancerBackendgroup cloudprovider.ICloudLoadbalancerBackendGroup, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SQcloudCachedLbbg, error) { + LocalLbbg, err := newLocalBackendgroupFromCloudLoadbalancerBackendgroup(ctx, userCred, lb, extLoadbalancerBackendgroup, syncOwnerId, provider) if err != nil { return nil, err } @@ -321,8 +322,12 @@ func (man *SQcloudCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx co lbbg := &SQcloudCachedLbbg{} lbbg.SetModelManager(man, lbbg) - lbbg.ManagerId = lb.ManagerId - lbbg.CloudregionId = lb.CloudregionId + region := lb.GetRegion() + if region == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "loadbalancer is not attached to any region") + } + lbbg.ManagerId = provider.Id + lbbg.CloudregionId = region.Id lbbg.LoadbalancerId = lb.Id lbbg.BackendGroupId = LocalLbbg.GetId() lbbg.ExternalId = extLoadbalancerBackendgroup.GetGlobalId() @@ -340,7 +345,7 @@ func (man *SQcloudCachedLbbgManager) newFromCloudLoadbalancerBackendgroup(ctx co return nil, err } - SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, lb.ManagerId) + SyncCloudProject(userCred, lbbg, syncOwnerId, extLoadbalancerBackendgroup, provider.Id) db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred) return lbbg, nil diff --git a/pkg/compute/models/loadbalancerresource.go b/pkg/compute/models/loadbalancerresource.go new file mode 100644 index 0000000000..04e902e581 --- /dev/null +++ b/pkg/compute/models/loadbalancerresource.go @@ -0,0 +1,302 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SLoadbalancerResourceBase struct { + // 负载均衡ID + LoadbalancerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` +} + +type SLoadbalancerResourceBaseManager struct { + SVpcResourceBaseManager + SZoneResourceBaseManager +} + +func (self *SLoadbalancerResourceBase) GetLoadbalancer() *SLoadbalancer { + w, _ := LoadbalancerManager.FetchById(self.LoadbalancerId) + if w != nil { + return w.(*SLoadbalancer) + } + return nil +} + +func (self *SLoadbalancerResourceBase) GetVpc() *SVpc { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetVpc() + } + return nil +} + +func (self *SLoadbalancerResourceBase) GetCloudprovider() *SCloudprovider { + vpc := self.GetVpc() + if vpc != nil { + return vpc.GetCloudprovider() + } + return nil +} + +func (self *SLoadbalancerResourceBase) GetCloudproviderId() string { + cloudprovider := self.GetCloudprovider() + if cloudprovider != nil { + return cloudprovider.Id + } + return "" +} + +func (self *SLoadbalancerResourceBase) GetProviderName() string { + vpc := self.GetVpc() + if vpc != nil { + return vpc.GetProviderName() + } + return "" +} + +func (self *SLoadbalancerResourceBase) GetCloudaccount() *SCloudaccount { + vpc := self.GetVpc() + if vpc != nil { + return vpc.GetCloudaccount() + } + return nil +} + +func (self *SLoadbalancerResourceBase) GetRegion() *SCloudregion { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + region, _ := vpc.GetRegion() + return region +} + +func (self *SLoadbalancerResourceBase) GetRegionId() string { + region := self.GetRegion() + if region != nil { + return region.Id + } + return "" +} + +func (self *SLoadbalancerResourceBase) GetZone() *SZone { + lb := self.GetLoadbalancer() + if lb != nil { + return lb.GetZone() + } + return nil +} + +func (self *SLoadbalancerResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.LoadbalancerResourceInfo { + return api.LoadbalancerResourceInfo{} +} + +func (manager *SLoadbalancerResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerResourceInfo { + rows := make([]api.LoadbalancerResourceInfo, len(objs)) + + lbIds := make([]string, len(objs)) + for i := range objs { + var base *SLoadbalancerResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + lbIds[i] = base.LoadbalancerId + } + + lbs := make(map[string]SLoadbalancer) + err := db.FetchStandaloneObjectsByIds(LoadbalancerManager, lbIds, &lbs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + + vpcList := make([]interface{}, len(rows)) + zoneList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.LoadbalancerResourceInfo{} + if lb, ok := lbs[lbIds[i]]; ok { + rows[i].Loadbalancer = lb.Name + rows[i].VpcId = lb.VpcId + rows[i].ZoneId = lb.ZoneId + } + vpcList[i] = &SVpcResourceBase{rows[i].VpcId} + zoneList[i] = &SZoneResourceBase{rows[i].ZoneId} + } + + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList) + + for i := range rows { + rows[i].VpcResourceInfo = vpcRows[i] + rows[i].ZoneResourceInfoBase = zoneRows[i].ZoneResourceInfoBase + } + return rows +} + +func (manager *SLoadbalancerResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Loadbalancer) > 0 { + lbObj, err := LoadbalancerManager.FetchByIdOrName(userCred, query.Loadbalancer) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(LoadbalancerManager.Keyword(), query.Loadbalancer) + } else { + return nil, errors.Wrap(err, "LoadbalancerManager.FetchByIdOrName") + } + } + q = q.Equals("loadbalancer_id", lbObj.GetId()) + } + + lbQ := LoadbalancerManager.Query("id").Snapshot() + + lbQ, err := manager.SVpcResourceBaseManager.ListItemFilter(ctx, lbQ, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + lbQ, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, lbQ, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + + if lbQ.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("loadbalancer_id"), lbQ.SubQuery())) + } + return q, nil +} + +func (manager *SLoadbalancerResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "loadbalancer" { + lbQuery := LoadbalancerManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(lbQuery.Field("name", field)) + q = q.Join(lbQuery, sqlchemy.Equals(q.Field("loadbalancer_id"), lbQuery.Field("id"))) + q.GroupBy(lbQuery.Field("name")) + return q, nil + } else { + lbs := LoadbalancerManager.Query("id", "zone_id", "vpc_id").SubQuery() + q = q.LeftJoin(lbs, sqlchemy.Equals(q.Field("loadbalancer_id"), lbs.Field("id"))) + q, err := manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound + } +} + +func (manager *SLoadbalancerResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SLoadbalancerResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + lbQ := LoadbalancerManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + lbQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(lbQ, userCred, zoneQuery) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + + if db.NeedOrderQuery(manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput)) { + var vpcOrders []string + var vpcFields []sqlchemy.IQueryField + lbQ, vpcOrders, vpcFields = manager.SVpcResourceBaseManager.GetOrderBySubQuery(lbQ, userCred, query.VpcFilterListInput) + if len(vpcOrders) > 0 { + orders = append(orders, vpcOrders...) + fields = append(fields, vpcFields...) + } + } + + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := lbQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("loadbalancer_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByLoadbalancer}) { + orders = append(orders, query.OrderByLoadbalancer) + fields = append(fields, subq.Field("name")) + } + } + + return q, orders, fields +} + +func (manager *SLoadbalancerResourceBaseManager) GetOrderByFields(query api.LoadbalancerFilterListInput) []string { + fields := make([]string, 0) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery) + fields = append(fields, zoneFields...) + vpcFields := manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput) + fields = append(fields, vpcFields...) + fields = append(fields, query.OrderByLoadbalancer) + return fields +} diff --git a/pkg/compute/models/loadbalancers.go b/pkg/compute/models/loadbalancers.go index ca665c45f4..a941265dd0 100644 --- a/pkg/compute/models/loadbalancers.go +++ b/pkg/compute/models/loadbalancers.go @@ -37,11 +37,15 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SLoadbalancerManager struct { SLoadbalancerLogSkipper db.SVirtualResourceBaseManager + SVpcResourceBaseManager + SZoneResourceBaseManager + SNetworkResourceBaseManager } var LoadbalancerManager *SLoadbalancerManager @@ -71,71 +75,146 @@ func init() { type SLoadbalancer struct { db.SVirtualResourceBase db.SExternalizedResourceBase - - SManagedResourceBase - SCloudregionResourceBase + // LB must be in a VPC, vpc_id, manager_id, cloudregion_id + SVpcResourceBase + // zone_id SZoneResourceBase + // optional network_id + SNetworkResourceBase + SLoadbalancerRateLimiter // IP地址 - Address string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional"` + Address string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"address"` // 地址类型 - AddressType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` + AddressType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"address_type"` // 网络类型 - NetworkType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional"` + NetworkType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"network_type"` + // 子网Id - NetworkId string `width:"147" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // NetworkId string `width:"147" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // 虚拟私有网络Id - VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // 负载均衡集群Id - ClusterId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + ClusterId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"cluster_id"` // 计费类型 - ChargeType string `list:"user" get:"user" create:"optional" update:"user"` + ChargeType string `list:"user" get:"user" create:"optional" update:"user" json:"charge_type"` // 套餐名称 - LoadbalancerSpec string `list:"user" get:"user" list:"user" create:"optional"` + LoadbalancerSpec string `list:"user" get:"user" list:"user" create:"optional" json:"loadbalancer_spec"` - // 后端服务器组Id - BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user"` - LBInfo jsonutils.JSONObject `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional"` + // 默认后端服务器组Id + BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" json:"backend_group_id"` + + // LB的其他配置信息 + LBInfo jsonutils.JSONObject `charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional" json:"lb_info"` } // 负载均衡实例列表 -func (man *SLoadbalancerManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.LoadbalancerListInput) (*sqlchemy.SQuery, error) { +func (man *SLoadbalancerManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "", nil) + q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } - - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = man.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + netQuery := api.NetworkFilterListInput{ + NetworkFilterListBase: query.NetworkFilterListBase, + } + q, err = man.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, netQuery) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter") } ownerId := userCred data := jsonutils.Marshal(query).(*jsonutils.JSONDict) q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "network", ModelKeyword: "network", OwnerId: ownerId}, - {Key: "cluster", ModelKeyword: "loadbalancercluster", OwnerId: userCred}, + // {Key: "network", ModelKeyword: "network", OwnerId: ownerId}, + {Key: "cluster", ModelKeyword: "loadbalancercluster", OwnerId: ownerId}, }) if err != nil { return nil, err } + return q, nil } +func (man *SLoadbalancerManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.LoadbalancerListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") + } + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = man.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + netQuery := api.NetworkFilterListInput{ + NetworkFilterListBase: query.NetworkFilterListBase, + } + q, err = man.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, netQuery) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SLoadbalancerManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SLoadbalancerManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { var region *SCloudregion if id, _ := data.GetString("vpc"); len(id) > 0 { @@ -157,7 +236,7 @@ func (man *SLoadbalancerManager) ValidateCreateData(ctx context.Context, userCre if err != nil { return nil, httperrors.NewBadRequestError("getting network failed: %v", err) } - region = network.(*SNetwork).getRegion() + region = network.(*SNetwork).GetRegion() } if region == nil { @@ -185,8 +264,8 @@ func (lb *SLoadbalancer) AllowPerformStatus(ctx context.Context, userCred mcclie return lb.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, lb, "status") } -func (lb *SLoadbalancer) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if _, err := lb.SVirtualResourceBase.PerformStatus(ctx, userCred, query, data); err != nil { +func (lb *SLoadbalancer) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { + if _, err := lb.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input); err != nil { return nil, err } if lb.Status == api.LB_STATUS_ENABLED { @@ -246,36 +325,19 @@ func (lb *SLoadbalancer) PostCreate(ctx context.Context, userCred mcclient.Token } func (lb *SLoadbalancer) GetCloudprovider() *SCloudprovider { - cloudprovider, err := CloudproviderManager.FetchById(lb.ManagerId) - if err != nil { - return nil - } - return cloudprovider.(*SCloudprovider) + return lb.SVpcResourceBase.GetCloudprovider() } func (lb *SLoadbalancer) GetRegion() *SCloudregion { - region, err := CloudregionManager.FetchById(lb.CloudregionId) - if err != nil { - log.Errorf("failed to find region for loadbalancer %s", lb.Name) - return nil - } - return region.(*SCloudregion) + return lb.SVpcResourceBase.GetRegion() } func (lb *SLoadbalancer) GetZone() *SZone { - zone, err := ZoneManager.FetchById(lb.ZoneId) - if err != nil { - return nil - } - return zone.(*SZone) + return lb.SZoneResourceBase.GetZone() } func (lb *SLoadbalancer) GetVpc() *SVpc { - vpc, err := VpcManager.FetchById(lb.VpcId) - if err != nil { - return nil - } - return vpc.(*SVpc) + return lb.SVpcResourceBase.GetVpc() } func (lb *SLoadbalancer) GetNetworks() ([]SNetwork, error) { @@ -298,15 +360,7 @@ func (lb *SLoadbalancer) GetNetworks() ([]SNetwork, error) { } func (lb *SLoadbalancer) GetIRegion() (cloudprovider.ICloudRegion, error) { - provider, err := lb.GetDriver() - if err != nil { - return nil, fmt.Errorf("No cloudprovider for lb %s: %s", lb.Name, err) - } - region := lb.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to find region for lb %s", lb.Name) - } - return provider.GetIRegionById(region.ExternalId) + return lb.SVpcResourceBase.GetIRegion() } func (lb *SLoadbalancer) GetCreateLoadbalancerParams(iRegion cloudprovider.ICloudRegion) (*cloudprovider.SLoadbalancer, error) { @@ -409,31 +463,49 @@ func (lb *SLoadbalancer) ValidateUpdateData(ctx context.Context, userCred mcclie return lb.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, data) } -func (lb *SLoadbalancer) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.LoadbalancerDetails, error) { - var err error - out := api.LoadbalancerDetails{} - out.VirtualResourceDetails, err = lb.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (man *SLoadbalancerManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.LoadbalancerDetails { + rows := make([]api.LoadbalancerDetails, len(objs)) + + virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := man.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := man.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + netRows := man.SNetworkResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.LoadbalancerDetails{ + VirtualResourceDetails: virtRows[i], + VpcResourceInfo: vpcRows[i], + ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase, + NetworkResourceInfoBase: netRows[i].NetworkResourceInfoBase, + } + rows[i], _ = objs[i].(*SLoadbalancer).getMoreDetails(rows[i]) } - provider := lb.GetCloudprovider() - zone := lb.GetZone() - region := lb.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, zone, provider) + return rows +} +func (lb *SLoadbalancer) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.LoadbalancerDetails, error) { + return api.LoadbalancerDetails{}, nil +} +func (lb *SLoadbalancer) getMoreDetails(out api.LoadbalancerDetails) (api.LoadbalancerDetails, error) { eip, _ := lb.GetEip() if eip != nil { out.Eip = eip.IpAddr out.EipMode = eip.Mode } - if len(lb.VpcId) > 0 { - if vpc := lb.GetVpc(); vpc != nil { - out.Vpc = vpc.Name - } - } - if lb.BackendGroupId != "" { lbbg, err := LoadbalancerBackendGroupManager.FetchById(lb.BackendGroupId) if err != nil { @@ -562,7 +634,7 @@ func (man *SLoadbalancerManager) SyncLoadbalancers(ctx context.Context, userCred } } for i := 0; i < len(commondb); i++ { - err = commondb[i].SyncWithCloudLoadbalancer(ctx, userCred, commonext[i], syncOwnerId) + err = commondb[i].SyncWithCloudLoadbalancer(ctx, userCred, commonext[i], syncOwnerId, provider) if err != nil { syncResult.UpdateError(err) } else { @@ -590,8 +662,8 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u lb := SLoadbalancer{} lb.SetModelManager(man, &lb) - lb.ManagerId = provider.Id - lb.CloudregionId = region.Id + // lb.ManagerId = provider.Id + // lb.CloudregionId = region.Id lb.Address = extLb.GetAddress() lb.AddressType = extLb.GetAddressType() lb.NetworkType = extLb.GetNetworkType() @@ -635,7 +707,7 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u return nil, err } - SyncCloudProject(userCred, &lb, syncOwnerId, extLb, lb.ManagerId) + SyncCloudProject(userCred, &lb, syncOwnerId, extLb, provider.Id) db.OpsLog.LogEvent(&lb, db.ACT_CREATE, lb.GetShortDesc(ctx), userCred) @@ -776,7 +848,7 @@ func (self *SLoadbalancer) SyncLoadbalancerEip(ctx context.Context, userCred mcc return result } -func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, extLb cloudprovider.ICloudLoadbalancer, syncOwnerId mcclient.IIdentityProvider) error { +func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, extLb cloudprovider.ICloudLoadbalancer, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) error { lockman.LockObject(ctx, lb) defer lockman.ReleaseObject(ctx, lb) @@ -797,13 +869,13 @@ func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred db.OpsLog.LogSyncUpdate(lb, diff, userCred) - SyncCloudProject(userCred, lb, syncOwnerId, extLb, lb.ManagerId) + SyncCloudProject(userCred, lb, syncOwnerId, extLb, provider.Id) lb.syncLoadbalancerNetwork(ctx, userCred, extLb.GetNetworkIds()) return err } -func (lb *SLoadbalancer) setCloudregionId() error { +/*func (lb *SLoadbalancer) setCloudregionId() error { zone := ZoneManager.FetchZoneById(lb.ZoneId) if zone == nil { return fmt.Errorf("failed to find zone %s", lb.ZoneId) @@ -817,10 +889,10 @@ func (lb *SLoadbalancer) setCloudregionId() error { return nil }) return err -} +}*/ func (man *SLoadbalancerManager) InitializeData() error { - lbs := []SLoadbalancer{} + /*lbs := []SLoadbalancer{} q := LoadbalancerManager.Query() q = q.Filter(sqlchemy.IsNullOrEmpty(q.Field("cloudregion_id"))) if err := db.FetchModelObjects(LoadbalancerManager, q, &lbs); err != nil { @@ -831,7 +903,7 @@ func (man *SLoadbalancerManager) InitializeData() error { if err := lbs[i].setCloudregionId(); err != nil { log.Errorf("failed setting lb %s(%s) cloud region error: %v", lbs[i].Name, lbs[i].Id, err) } - } + }*/ return nil } @@ -890,9 +962,11 @@ func (man *SLoadbalancerManager) TotalCount( providers []string, brands []string, cloudEnv string, ) (int, error) { q := man.Query() + vpcs := VpcManager.Query().SubQuery() + q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id"))) q = scopeOwnerIdFilter(q, scope, ownerId) - q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv) - q = rangeObjectsFilter(q, rangeObjs, nil, q.Field("zone_id"), q.Field("manager_id")) + q = CloudProviderFilter(q, vpcs.Field("manager_id"), providers, brands, cloudEnv) + q = rangeObjectsFilter(q, rangeObjs, nil, q.Field("zone_id"), vpcs.Field("manager_id")) return q.CountWithError() } diff --git a/pkg/compute/models/managedresource.go b/pkg/compute/models/managedresource.go index 1e2456b8af..ad20161912 100644 --- a/pkg/compute/models/managedresource.go +++ b/pkg/compute/models/managedresource.go @@ -20,6 +20,10 @@ import ( "fmt" "strings" + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/apis" @@ -28,12 +32,17 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SManagedResourceBase struct { - ManagerId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional"` // Column(VARCHAR(ID_LENGTH, charset='ascii'), nullable=True) + // 云订阅ID + ManagerId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional" json:"manager_id"` } +type SManagedResourceBaseManager struct{} + func (self *SManagedResourceBase) GetCloudprovider() *SCloudprovider { if len(self.ManagerId) > 0 { return CloudproviderManager.FetchCloudproviderById(self.ManagerId) @@ -104,7 +113,178 @@ func (self *SManagedResourceBase) IsManaged() bool { return len(self.ManagerId) > 0 } -func managedResourceFilterByDomain(q *sqlchemy.SQuery, query apis.DomainizedResourceListInput, filterField string, subqFunc func() *sqlchemy.SQuery) (*sqlchemy.SQuery, error) { +func (self *SManagedResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) api.ManagedResourceInfo { + return api.ManagedResourceInfo{} +} + +func (manager *SManagedResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ManagedResourceInfo { + rows := make([]api.ManagedResourceInfo, len(objs)) + managerIds := make([]string, len(objs)) + managerCnt := 0 + for i := range objs { + rows[i] = api.ManagedResourceInfo{} + rows[i].CloudEnv = api.CLOUD_ENV_ON_PREMISE + rows[i].Provider = api.CLOUD_PROVIDER_ONECLOUD + rows[i].Brand = api.CLOUD_PROVIDER_ONECLOUD + var base *SManagedResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + if base != nil && len(base.ManagerId) > 0 { + managerIds[i] = base.ManagerId + managerCnt += 1 + } + } + + if managerCnt == 0 { + return rows + } + + managers := make(map[string]SCloudprovider) + err := db.FetchStandaloneObjectsByIds(CloudproviderManager, managerIds, &managers) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + accountIds := make([]string, 0) + projectIds := make([]string, 0) + for i := range rows { + if _, ok := managers[managerIds[i]]; ok { + manager := managers[managerIds[i]] + rows[i].Manager = manager.Name + rows[i].ManagerDomainId = manager.DomainId + rows[i].ManagerProjectId = manager.ProjectId + rows[i].AccountId = manager.CloudaccountId + if len(manager.ProjectId) > 0 { + projectIds = append(projectIds, manager.ProjectId) + } + if len(manager.CloudaccountId) > 0 { + accountIds = append(accountIds, manager.CloudaccountId) + } + } + } + + accounts := make(map[string]SCloudaccount) + err = db.FetchStandaloneObjectsByIds(CloudaccountManager, accountIds, &accounts) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds for accounts fail %s", err) + return nil + } + + projects := db.FetchProjects(projectIds, false) + + for i := range rows { + if account, ok := accounts[rows[i].AccountId]; ok { + rows[i].Account = account.Name + rows[i].Brand = account.Brand + rows[i].Provider = account.Provider + rows[i].CloudEnv = account.GetCloudEnv() + rows[i].Environment = account.GetEnvironment() + } + if project, ok := projects[rows[i].ManagerProjectId]; ok { + rows[i].ManagerProject = project.Name + rows[i].ManagerDomain = project.Domain + rows[i].ManagerDomainId = project.DomainId + } + } + + return rows +} + +func (manager *SManagedResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ManagedResourceListInput, +) (*sqlchemy.SQuery, error) { + return managedResourceFilterByAccount(q, query, "", nil) +} + +func (manager *SManagedResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "manager": + managerQuery := CloudproviderManager.Query("name", "id").SubQuery() + q.AppendField(managerQuery.Field("name", field)).Distinct() + q = q.Join(managerQuery, sqlchemy.Equals(q.Field("manager_id"), managerQuery.Field("id"))) + return q, nil + case "account": + accountQuery := CloudaccountManager.Query("name", "id").SubQuery() + providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery() + q.AppendField(accountQuery.Field("name", field)).Distinct() + q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id"))) + q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id"))) + return q, nil + case "provider", "brand": + accountQuery := CloudaccountManager.Query(field, "id").Distinct().SubQuery() + providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery() + q.AppendField(accountQuery.Field(field)).Distinct() + q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id"))) + q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id"))) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SManagedResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ManagedResourceListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SManagedResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ManagedResourceListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + var orders []string + var fields []sqlchemy.IQueryField + orders = manager.GetOrderByFields(query) + if db.NeedOrderQuery(orders) { + providers := CloudproviderManager.Query("id", "name", "cloudaccount_id").SubQuery() + accounts := CloudaccountManager.Query("id", "name", "provider", "brand").SubQuery() + subq := providers.Query( + providers.Field("id"), + providers.Field("name"), + accounts.Field("name").Label("account"), + accounts.Field("provider"), + accounts.Field("brand"), + ).Join( + accounts, + sqlchemy.Equals(providers.Field("cloudaccount_id"), accounts.Field("id")), + ).SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("manager_id"), subq.Field("id"))) + fields = []sqlchemy.IQueryField{ + subq.Field("name"), + subq.Field("account"), + subq.Field("provider"), + subq.Field("brand"), + } + } + return q, orders, fields +} + +func (manager *SManagedResourceBaseManager) GetOrderByFields(query api.ManagedResourceListInput) []string { + return []string{query.OrderByManager, query.OrderByAccount, query.OrderByProvider, query.OrderByBrand} +} + +func _managedResourceFilterByDomain(q *sqlchemy.SQuery, query apis.DomainizedResourceListInput, filterField string, subqFunc func() *sqlchemy.SQuery) (*sqlchemy.SQuery, error) { domainStr := query.ProjectDomain if len(domainStr) > 0 { domain, err := db.TenantCacheManager.FetchDomainByIdOrName(context.Background(), domainStr) @@ -237,16 +417,34 @@ func managedResourceFilterByAccount(q *sqlchemy.SQuery, input api.ManagedResourc q = filterByCloudType(q, input, filterField, subqFunc) + q, err := _managedResourceFilterByDomain(q, input.DomainizedResourceListInput, filterField, subqFunc) + if err != nil { + return nil, errors.Wrap(err, "managedResourceFilterByDomain") + } + return q, nil } func managedResourceFilterByZone(q *sqlchemy.SQuery, query api.ZonalFilterListInput, filterField string, subqFunc func() *sqlchemy.SQuery) (*sqlchemy.SQuery, error) { - zoneStr := query.Zone - if len(zoneStr) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(nil, zoneStr) + zoneList := query.ZoneList() + if len(zoneList) > 1 { + zoneQ := ZoneManager.Query("id") + zoneQ = zoneQ.Filter(sqlchemy.OR( + sqlchemy.In(zoneQ.Field("id"), zoneList), + sqlchemy.In(zoneQ.Field("name"), zoneList), + )) + if len(filterField) == 0 { + q = q.Filter(sqlchemy.In(q.Field("zone_id"), zoneQ.SubQuery())) + } else { + sq := subqFunc() + sq = sq.Filter(sqlchemy.In(sq.Field("zone_id"), zoneQ.SubQuery())) + q = q.Filter(sqlchemy.In(q.Field(filterField), sq.SubQuery())) + } + } else if len(query.Zone) > 0 { + zoneObj, err := ZoneManager.FetchByIdOrName(nil, query.Zone) if err != nil { if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), zoneStr) + return nil, httperrors.NewResourceNotFoundError2(ZoneManager.Keyword(), query.Zone) } else { return nil, httperrors.NewGeneralError(err) } @@ -410,6 +608,9 @@ var ( ) func fetchExternalId(extId string) string { + if len(extId) == 0 { + return "" + } pos := strings.LastIndexByte(extId, '/') if pos > 0 { return extId[pos+1:] @@ -418,8 +619,8 @@ func fetchExternalId(extId string) string { } } -func MakeCloudProviderInfo(region *SCloudregion, zone *SZone, provider *SCloudprovider) api.CloudproviderInfo { - info := api.CloudproviderInfo{} +func MakeCloudProviderInfo(region *SCloudregion, zone *SZone, provider *SCloudprovider) SCloudProviderInfo { + info := SCloudProviderInfo{} if zone != nil { info.Zone = zone.GetName() diff --git a/pkg/compute/models/natdtable.go b/pkg/compute/models/natdtable.go index 6619192978..51ae030592 100644 --- a/pkg/compute/models/natdtable.go +++ b/pkg/compute/models/natdtable.go @@ -29,10 +29,10 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SNatDEntryManager struct { @@ -65,15 +65,41 @@ type SNatDEntry struct { } // NAT网关的目的地址转换规则列表 -func (man *SNatDEntryManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NatDEntryListInput) (*sqlchemy.SQuery, error) { +func (man *SNatDEntryManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatDEntryListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SNatEntryManager.ListItemFilter(ctx, q, userCred, query.NatEntryListInput) if err != nil { return nil, errors.Wrap(err, "SNatEntryManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "natgateway", ModelKeyword: "natgateway", OwnerId: userCred}, - }) + return q, nil +} + +func (manager *SNatDEntryManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatDEntryListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SNatEntryManager.OrderByExtraFields(ctx, q, userCred, query.NatEntryListInput) + if err != nil { + return nil, errors.Wrap(err, "SNatEntryManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SNatDEntryManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SNatEntryManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } func (man *SNatDEntryManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { @@ -246,28 +272,31 @@ func (manager *SNatDEntryManager) newFromCloudNatDTable(ctx context.Context, use return &table, nil } -func (self *SNatDEntry) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NatDEntryDetails, error) { - var err error - out := api.NatDEntryDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - - return self.getMoreDetails(ctx, userCred, out), nil +func (self *SNatDEntry) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NatDEntryDetails, error) { + return api.NatDEntryDetails{}, nil } -func (self *SNatDEntry) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, - out api.NatDEntryDetails) api.NatDEntryDetails { - - natgateway, err := self.GetNatgateway() - if err != nil { - log.Errorf("failed to get naggateway %s for dtable %s(%s) error: %v", self.NatgatewayId, self.Name, self.Id, err) - return out +func (manager *SNatDEntryManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NatDEntryDetails { + rows := make([]api.NatDEntryDetails, len(objs)) + entryRows := manager.SNatEntryManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.NatDEntryDetails{ + NatEntryDetails: entryRows[i], + } } - out.Natgateway = natgateway.Name - out.RealName = NatGatewayManager.NatNameToReal(self.Name, natgateway.GetId()) - return out + return rows } func (self *SNatDEntry) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { diff --git a/pkg/compute/models/natgatewayresource.go b/pkg/compute/models/natgatewayresource.go new file mode 100644 index 0000000000..302e3c36fd --- /dev/null +++ b/pkg/compute/models/natgatewayresource.go @@ -0,0 +1,213 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SNatgatewayResourceBase struct { + NatgatewayId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` +} + +type SNatgatewayResourceBaseManager struct { + SVpcResourceBaseManager +} + +func (self *SNatgatewayResourceBase) GetNatgateway() (*SNatGateway, error) { + obj, err := NatGatewayManager.FetchById(self.NatgatewayId) + if err != nil { + return nil, errors.Wrap(err, "NatGatewayManager.FetchById") + } + return obj.(*SNatGateway), nil +} + +func (self *SNatgatewayResourceBase) GetVpc() *SVpc { + nat, _ := self.GetNatgateway() + if nat != nil { + return nat.GetVpc() + } + return nil +} + +func (self *SNatgatewayResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.NatGatewayResourceInfo { + return api.NatGatewayResourceInfo{} +} + +func (manager *SNatgatewayResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NatGatewayResourceInfo { + rows := make([]api.NatGatewayResourceInfo, len(objs)) + natIds := make([]string, len(objs)) + for i := range objs { + var base *SNatgatewayResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + natIds[i] = base.NatgatewayId + } + } + nats := make(map[string]SNatGateway) + err := db.FetchStandaloneObjectsByIds(NatGatewayManager, natIds, &nats) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + vpcList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.NatGatewayResourceInfo{} + if _, ok := nats[natIds[i]]; ok { + rows[i].Natgateway = nats[natIds[i]].Name + rows[i].VpcId = nats[natIds[i]].VpcId + } + vpcList[i] = &SVpcResourceBase{rows[i].VpcId} + } + + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList) + for i := range rows { + rows[i].VpcResourceInfo = vpcRows[i] + } + + return rows +} + +func (manager *SNatgatewayResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatGatewayFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Natgateway) > 0 { + natObj, err := NatGatewayManager.FetchByIdOrName(userCred, query.Natgateway) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(NatGatewayManager.Keyword(), query.Natgateway) + } else { + return nil, errors.Wrap(err, "NatGatewayManager.FetchByIdOrName") + } + } + q = q.Equals("natgateway_id", natObj.GetId()) + } + + subq := NatGatewayManager.Query("id").Snapshot() + subq, err := manager.SVpcResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("natgateway_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SNatgatewayResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "natgateway": + natQuery := NatGatewayManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(natQuery.Field("name", field)) + q = q.Join(natQuery, sqlchemy.Equals(q.Field("natgateway_id"), natQuery.Field("id"))) + q.GroupBy(natQuery.Field("name")) + return q, nil + } + nats := NatGatewayManager.Query("id", "vpc_id").SubQuery() + q = q.LeftJoin(nats, sqlchemy.Equals(q.Field("natgateway_id"), nats.Field("id"))) + q, err := manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SNatgatewayResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatGatewayFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SNatgatewayResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatGatewayFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + natQ := NatGatewayManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput)) { + var vpcOrders []string + var vpcFields []sqlchemy.IQueryField + natQ, vpcOrders, vpcFields = manager.SVpcResourceBaseManager.GetOrderBySubQuery(natQ, userCred, query.VpcFilterListInput) + if len(vpcOrders) > 0 { + orders = append(orders, vpcOrders...) + fields = append(fields, vpcFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := natQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("natgateway_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByNatgateway}) { + orders = append(orders, query.OrderByNatgateway) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SNatgatewayResourceBaseManager) GetOrderByFields(query api.NatGatewayFilterListInput) []string { + fields := make([]string, 0) + vpcFields := manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput) + fields = append(fields, vpcFields...) + fields = append(fields, query.OrderByNatgateway) + return fields +} + +/* +func (manager *SNatgatewayResourceBaseManager) FetchParentId(ctx context.Context, data jsonutils.JSONObject) string { + parentId, _ := data.GetString("nategateway_id") + return parentId +} + +func (manager *SNatgatewayResourceBaseManager) FilterByParentId(q *sqlchemy.SQuery, parentId string) *sqlchemy.SQuery { + if len(parentId) > 0 { + q = q.Equals("nategateway_id", parentId) + } + return q +} +*/ diff --git a/pkg/compute/models/natgateways.go b/pkg/compute/models/natgateways.go index 0e0dc3994f..678d11498b 100644 --- a/pkg/compute/models/natgateways.go +++ b/pkg/compute/models/natgateways.go @@ -23,25 +23,28 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) -type SNatGetewayManager struct { +type SNatGatewayManager struct { db.SStatusStandaloneResourceBaseManager + SVpcResourceBaseManager + // SManagedResourceBaseManager } -var NatGatewayManager *SNatGetewayManager +var NatGatewayManager *SNatGatewayManager func init() { - NatGatewayManager = &SNatGetewayManager{ + NatGatewayManager = &SNatGatewayManager{ SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager( SNatGateway{}, "natgateways_tbl", @@ -55,62 +58,65 @@ func init() { type SNatGateway struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase - SManagedResourceBase - SCloudregionResourceBase + // SManagedResourceBase SBillingResourceBase + SVpcResourceBase - VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` NatSpec string `list:"user" create:"optional"` // NAT规格 } -func (manager *SNatGetewayManager) GetContextManagers() [][]db.IModelManager { +func (manager *SNatGatewayManager) GetContextManagers() [][]db.IModelManager { return [][]db.IModelManager{ - {CloudregionManager}, + {CloudregionManager, VpcManager}, } } -func (self *SNatGetewayManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SNatGetewayManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SNatGateway) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SNatGateway) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SNatGateway) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - // NAT网关列表 -func (man *SNatGetewayManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NatGetewayListInput) (*sqlchemy.SQuery, error) { - q, err := man.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (man *SNatGatewayManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NatGetewayListInput) (*sqlchemy.SQuery, error) { + q, err := man.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { - return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + return nil, errors.Wrap(err, "SStatusDomainLevelResourceBaseManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "vpc", ModelKeyword: "vpc", OwnerId: userCred}, - {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, - }) + q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, err - } - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } return q, nil } -func (man *SNatGetewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { +// NAT网关列表 +func (man *SNatGatewayManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatGetewayListInput, +) (*sqlchemy.SQuery, error) { + q, err := man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusDomainLevelResourceBaseManager.OrderByExtraFields") + } + q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (man *SNatGatewayManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = man.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (man *SNatGatewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { return nil, httperrors.NewNotImplementedError("Not Implemented") } @@ -194,15 +200,7 @@ func (self *SNatGateway) extractEipAddr(q *sqlchemy.SQuery) ([]string, error) { return ips, nil } -func (self *SNatGateway) GetVpc() (*SVpc, error) { - _vpc, err := VpcManager.FetchById(self.VpcId) - if err != nil { - return nil, err - } - return _vpc.(*SVpc), nil -} - -func (manager *SNatGetewayManager) getNatgatewaysByProviderId(providerId string) ([]SNatGateway, error) { +func (manager *SNatGatewayManager) getNatgatewaysByProviderId(providerId string) ([]SNatGateway, error) { nats := []SNatGateway{} err := fetchByManagerId(manager, providerId, &nats) if err != nil { @@ -244,26 +242,28 @@ func (self *SNatGateway) GetDTableSize(filter func(q *sqlchemy.SQuery) *sqlchemy } func (self *SNatGateway) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NatgatewayDetails, error) { - var err error - out := api.NatgatewayDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - if isList { - region := self.GetRegion() - provider := self.GetCloudprovider() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) + return api.NatgatewayDetails{}, nil +} - vpc, err := self.GetVpc() - if err != nil { - log.Errorf("failed to found vpc info for nat gateway %s(%s) error: %v", self.Name, self.Id, err) - return out, err +func (manager SNatGatewayManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NatgatewayDetails { + rows := make([]api.NatgatewayDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.NatgatewayDetails{ + StatusStandaloneResourceDetails: stdRows[i], + VpcResourceInfo: vpcRows[i], } - out.Vpc = vpc.Name + rows[i], _ = objs[i].(*SNatGateway).getMoreDetails(ctx, userCred, rows[i]) } - - return self.getMoreDetails(ctx, userCred, out) + return rows } func (self *SNatGateway) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, @@ -274,7 +274,7 @@ func (self *SNatGateway) getMoreDetails(ctx context.Context, userCred mcclient.T return out, nil } -func (manager *SNatGetewayManager) SyncNatGateways(ctx context.Context, userCred mcclient.TokenCredential, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider, vpc *SVpc, cloudNatGateways []cloudprovider.ICloudNatGateway) ([]SNatGateway, []cloudprovider.ICloudNatGateway, compare.SyncResult) { +func (manager *SNatGatewayManager) SyncNatGateways(ctx context.Context, userCred mcclient.TokenCredential, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider, vpc *SVpc, cloudNatGateways []cloudprovider.ICloudNatGateway) ([]SNatGateway, []cloudprovider.ICloudNatGateway, compare.SyncResult) { lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, provider.GetOwnerId())) @@ -363,18 +363,18 @@ func (self *SNatGateway) SyncWithCloudNatGateway(ctx context.Context, userCred m return nil } -func (manager *SNatGetewayManager) newFromCloudNatGateway(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, provider *SCloudprovider, vpc *SVpc, extNat cloudprovider.ICloudNatGateway) (*SNatGateway, error) { +func (manager *SNatGatewayManager) newFromCloudNatGateway(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, provider *SCloudprovider, vpc *SVpc, extNat cloudprovider.ICloudNatGateway) (*SNatGateway, error) { nat := SNatGateway{} nat.SetModelManager(manager, &nat) - region, err := vpc.GetRegion() + /*region, err := vpc.GetRegion() if err != nil { - return nil, err - } + return nil, errors.Wrap(err, "vpc.GetRegion") + }*/ newName, err := db.GenerateName(manager, ownerId, extNat.GetName()) if err != nil { - return nil, err + return nil, errors.Wrap(err, "db.GenerateName") } nat.Name = newName nat.VpcId = vpc.Id @@ -384,8 +384,8 @@ func (manager *SNatGetewayManager) newFromCloudNatGateway(ctx context.Context, u nat.CreatedAt = extNat.GetCreatedAt() } nat.ExternalId = extNat.GetGlobalId() - nat.CloudregionId = region.Id - nat.ManagerId = provider.Id + // nat.CloudregionId = region.Id + // nat.ManagerId = provider.Id nat.IsEmulated = extNat.IsEmulated() factory, _ := provider.GetProviderFactory() @@ -397,7 +397,7 @@ func (manager *SNatGetewayManager) newFromCloudNatGateway(ctx context.Context, u err = manager.TableSpec().Insert(&nat) if err != nil { log.Errorf("newFromCloudNatGateway fail %s", err) - return nil, err + return nil, errors.Wrap(err, "Insert") } db.OpsLog.LogEvent(&nat, db.ACT_CREATE, nat.GetShortDesc(ctx), userCred) @@ -511,19 +511,7 @@ func (self *SNatGateway) RealDelete(ctx context.Context, userCred mcclient.Token return self.Delete(ctx, userCred) } -func (self *SNatGateway) GetIRegion() (cloudprovider.ICloudRegion, error) { - provider, err := self.GetDriver() - if err != nil { - return nil, fmt.Errorf("No cloudprovider for sp %s: %s", self.Name, err) - } - region := self.GetRegion() - if region == nil { - return nil, fmt.Errorf("failed to find region for sp %s", self.Name) - } - return provider.GetIRegionById(region.ExternalId) -} - -func (nm *SNatGetewayManager) NatNameToReal(name string, natgatewayId string) string { +func (nm *SNatGatewayManager) NatNameToReal(name string, natgatewayId string) string { index := strings.Index(name, natgatewayId) if index < 0 { return name @@ -531,7 +519,7 @@ func (nm *SNatGetewayManager) NatNameToReal(name string, natgatewayId string) st return name[:index-1] } -func (nm *SNatGetewayManager) NatNameFromReal(name string, natgatewayId string) string { +func (nm *SNatGatewayManager) NatNameFromReal(name string, natgatewayId string) string { return fmt.Sprintf("%s-%s", name, natgatewayId) } @@ -544,17 +532,21 @@ type INatHelper interface { type SNatEntryManager struct { db.SStatusStandaloneResourceBaseManager + SNatgatewayResourceBaseManager } func NewNatEntryManager(dt interface{}, tableName string, keyword string, keywordPlural string) SNatEntryManager { - return SNatEntryManager{db.NewStatusStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural)} + return SNatEntryManager{ + SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(dt, tableName, keyword, keywordPlural), + } } type SNatEntry struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase - NatgatewayId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + SNatgatewayResourceBase + // NatgatewayId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` } func (manager *SNatEntryManager) GetContextManagers() [][]db.IModelManager { @@ -563,49 +555,100 @@ func (manager *SNatEntryManager) GetContextManagers() [][]db.IModelManager { } } -func (self *SNatEntryManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SNatEntryManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SNatEntry) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SNatEntry) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SNatEntry) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - -func (self *SNatEntry) GetNatgateway() (*SNatGateway, error) { - model, err := NatGatewayManager.FetchById(self.NatgatewayId) - if err != nil { - return nil, err - } - return model.(*SNatGateway), nil -} - // NAT网关转发规则列表 -func (man *SNatEntryManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NatEntryListInput) (*sqlchemy.SQuery, error) { - q, err := man.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (man *SNatEntryManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatEntryListInput, +) (*sqlchemy.SQuery, error) { + q, err := man.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + q, err = man.SNatgatewayResourceBaseManager.ListItemFilter(ctx, q, userCred, query.NatGatewayFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNatgatewayResourceBaseManager.ListItemFilter") + } + q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "natgateway_id", func() *sqlchemy.SQuery { natgateways := NatGatewayManager.Query().SubQuery() return natgateways.Query(natgateways.Field("id")) }) + if err != nil { + return nil, errors.Wrap(err, "managedResourceFilterByAccount") + } return q, nil } +func (man *SNatEntryManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatEntryListInput, +) (*sqlchemy.SQuery, error) { + q, err := man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = man.SNatgatewayResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NatGatewayFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNatgatewayResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (man *SNatEntryManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SNatgatewayResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (entry *SNatEntry) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NatEntryDetails, error) { + return api.NatEntryDetails{}, nil +} + +func (manager *SNatEntryManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NatEntryDetails { + rows := make([]api.NatEntryDetails, len(objs)) + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + natRows := manager.SNatgatewayResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.NatEntryDetails{ + StatusStandaloneResourceDetails: stdRows[i], + NatGatewayResourceInfo: natRows[i], + } + var base *SNatEntry + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && base.NatgatewayId != "" { + rows[i].RealName = NatGatewayManager.NatNameToReal(base.Name, base.NatgatewayId) + } + } + return rows +} + func (self *SNatEntry) GetINatGateway() (cloudprovider.ICloudNatGateway, error) { model, err := NatGatewayManager.FetchById(self.NatgatewayId) if err != nil { diff --git a/pkg/compute/models/natstable.go b/pkg/compute/models/natstable.go index c7ba0c49ef..7df4a3c426 100644 --- a/pkg/compute/models/natstable.go +++ b/pkg/compute/models/natstable.go @@ -30,14 +30,15 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SNatSEntryManager struct { SNatEntryManager + SNetworkResourceBaseManager } var NatSEntryManager *SNatSEntryManager @@ -56,11 +57,10 @@ func init() { type SNatSEntry struct { SNatEntry + SNetworkResourceBase IP string `charset:"ascii" list:"user" create:"required"` SourceCIDR string `width:"22" charset:"ascii" list:"user" create:"required"` - - NetworkId string `width:"36" charset:"ascii" list:"user" create:"optional"` } func (self *SNatSEntry) GetNetwork() (*SNetwork, error) { @@ -75,16 +75,60 @@ func (self *SNatSEntry) GetNetwork() (*SNetwork, error) { } // NAT网关的源地址转换规则列表 -func (man *SNatSEntryManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NatSEntryListInput) (*sqlchemy.SQuery, error) { +func (man *SNatSEntryManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatSEntryListInput, +) (*sqlchemy.SQuery, error) { q, err := man.SNatEntryManager.ListItemFilter(ctx, q, userCred, query.NatEntryListInput) if err != nil { return nil, errors.Wrap(err, "SNatEntryManager.ListItemFilter") } - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - return validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "network", ModelKeyword: "network", OwnerId: userCred}, - {Key: "natgateway", ModelKeyword: "natgateway", OwnerId: userCred}, - }) + netQuery := api.NetworkFilterListInput{ + NetworkFilterListBase: query.NetworkFilterListBase, + } + q, err = man.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, netQuery) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SNatSEntryManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NatSEntryListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SNatEntryManager.OrderByExtraFields(ctx, q, userCred, query.NatEntryListInput) + if err != nil { + return nil, errors.Wrap(err, "SNatEntryManager.OrderByExtraFields") + } + netQuery := api.NetworkFilterListInput{ + NetworkFilterListBase: query.NetworkFilterListBase, + } + q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, netQuery) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SNatSEntryManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SNatEntryManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, @@ -117,10 +161,11 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m } natgateway := model.(*SNatGateway) // get vpc - vpc, err := natgateway.GetVpc() - if err != nil { - return nil, err + vpc := natgateway.GetVpc() + if vpc == nil { + return nil, errors.Wrap(httperrors.ErrBadRequest, "invalid natgateway vpc") } + vpcIPV4Range, err := newIPv4RangeFromCIDR(vpc.CidrBlock) if err != nil { return nil, errors.Wrap(err, "convert vpc cidr to ipv4range error") @@ -303,41 +348,48 @@ func (manager *SNatSEntryManager) checkNetWorkId(networkId string) (*SNetwork, e } func (self *SNatSEntry) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NatSEntryDetails, error) { - var err error - out := api.NatSEntryDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return self.getMoreDetails(ctx, userCred, out), nil + return api.NatSEntryDetails{}, nil } -func (self *SNatSEntry) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, - out api.NatSEntryDetails) api.NatSEntryDetails { +func (manager *SNatSEntryManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NatSEntryDetails { + rows := make([]api.NatSEntryDetails, len(objs)) - network, err := self.GetNetwork() + netIds := make([]string, len(objs)) + entryRows := manager.SNatEntryManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.NatSEntryDetails{ + NatEntryDetails: entryRows[i], + } + netIds[i] = objs[i].(*SNatSEntry).NetworkId + } + + nets := make(map[string]SNetwork) + err := db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &nets) if err != nil { - return out + return rows } - if network == nil { - return out + + for i := range rows { + if net, ok := nets[netIds[i]]; ok { + rows[i].Network = api.SimpleNetwork{ + Id: net.Id, + Name: net.Name, + GuestIpStart: net.GuestIpStart, + GuestIpEnd: net.GuestIpEnd, + GuestIp6Start: net.GuestIp6Start, + GuestIp6End: net.GuestIp6End, + } + } } - out.Network = api.SimpleNetwork{ - Id: network.Id, - Name: network.Name, - GuestIpStart: network.GuestIpStart, - GuestIpEnd: network.GuestIpEnd, - GuestIp6Start: network.GuestIp6Start, - GuestIp6End: network.GuestIp6End, - } - natgateway, err := self.GetNatgateway() - if err != nil { - log.Errorf("failed to get naggateway %s for stable %s(%s) error: %v", self.NatgatewayId, self.Name, self.Id, err) - return out - } - out.Natgateway = natgateway.Name - out.RealName = NatGatewayManager.NatNameToReal(self.Name, natgateway.GetId()) - return out + + return rows } func (self *SNatSEntry) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { diff --git a/pkg/compute/models/networkinterfaces.go b/pkg/compute/models/networkinterfaces.go index 8af55fcd93..cb637046ad 100644 --- a/pkg/compute/models/networkinterfaces.go +++ b/pkg/compute/models/networkinterfaces.go @@ -27,11 +27,15 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SNetworkInterfaceManager struct { db.SStatusStandaloneResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } var NetworkInterfaceManager *SNetworkInterfaceManager @@ -68,54 +72,84 @@ func (manager *SNetworkInterfaceManager) GetContextManagers() [][]db.IModelManag } } -func (self *SNetworkInterfaceManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SNetworkInterfaceManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SNetworkInterface) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SNetworkInterface) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SNetworkInterface) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - // 虚拟网卡列表 -func (manager *SNetworkInterfaceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.NetworkInterfaceListInput) (*sqlchemy.SQuery, error) { +func (manager *SNetworkInterfaceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NetworkInterfaceListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } return q, nil } -func (self *SNetworkInterface) GetExterDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NetworkInterfaceDetails, error) { +func (manager *SNetworkInterfaceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NetworkInterfaceListInput, +) (*sqlchemy.SQuery, error) { var err error - out := api.NetworkInterfaceDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) + + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { - return out, err + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") } - provider := self.GetCloudprovider() - region := self.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) + return q, nil +} +func (manager *SNetworkInterfaceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (self *SNetworkInterface) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NetworkInterfaceDetails, error) { + return api.NetworkInterfaceDetails{}, nil +} + +func (self *SNetworkInterface) getMoreDetails(out api.NetworkInterfaceDetails) (api.NetworkInterfaceDetails, error) { networks, err := self.GetNetworks() if err != nil { log.Errorf("failed to get network for networkinterface %s(%s) error: %v", self.Name, self.Id, err) @@ -138,6 +172,32 @@ func (self *SNetworkInterface) GetExterDetails(ctx context.Context, userCred mcc return out, nil } +func (manager *SNetworkInterfaceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NetworkInterfaceDetails { + rows := make([]api.NetworkInterfaceDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.NetworkInterfaceDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regRows[i], + } + rows[i], _ = objs[i].(*SNetworkInterface).getMoreDetails(rows[i]) + } + + return rows +} + func (manager *SNetworkInterfaceManager) getNetworkInterfacesByProviderId(providerId string) ([]SNetworkInterface, error) { nics := []SNetworkInterface{} err := fetchByManagerId(manager, providerId, &nics) diff --git a/pkg/compute/models/networkresource.go b/pkg/compute/models/networkresource.go new file mode 100644 index 0000000000..170569f149 --- /dev/null +++ b/pkg/compute/models/networkresource.go @@ -0,0 +1,225 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SNetworkResourceBase struct { + NetworkId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"network_id"` +} + +type SNetworkResourceBaseManager struct { + SWireResourceBaseManager +} + +func (self *SNetworkResourceBase) GetNetwork() *SNetwork { + obj, _ := NetworkManager.FetchById(self.NetworkId) + if obj != nil { + return obj.(*SNetwork) + } + return nil +} + +func (self *SNetworkResourceBase) GetWire() *SWire { + net := self.GetNetwork() + if net != nil { + return net.GetWire() + } + return nil +} + +func (self *SNetworkResourceBase) GetZone() *SZone { + wire := self.GetWire() + if wire != nil { + return wire.GetZone() + } + return nil +} + +func (self *SNetworkResourceBase) GetVpc() *SVpc { + wire := self.GetWire() + if wire != nil { + return wire.GetVpc() + } + return nil +} + +func (self *SNetworkResourceBase) GetRegion() *SCloudregion { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + region, _ := vpc.GetRegion() + return region +} + +func (self *SNetworkResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.NetworkResourceInfo { + return api.NetworkResourceInfo{} +} + +func (manager *SNetworkResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NetworkResourceInfo { + rows := make([]api.NetworkResourceInfo, len(objs)) + netIds := make([]string, len(objs)) + for i := range objs { + var base *SNetworkResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + netIds[i] = base.NetworkId + } + networks := make(map[string]SNetwork) + err := db.FetchStandaloneObjectsByIds(NetworkManager, netIds, networks) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + wireList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.NetworkResourceInfo{} + if _, ok := networks[netIds[i]]; ok { + network := networks[netIds[i]] + rows[i].Network = network.Name + rows[i].WireId = network.WireId + } + wireList[i] = &SWireResourceBase{rows[i].WireId} + } + + wireRows := manager.SWireResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, wireList, fields, isList) + for i := range rows { + rows[i].WireResourceInfo = wireRows[i] + } + return rows +} + +func (manager *SNetworkResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NetworkFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Network) > 0 { + netObj, err := NetworkManager.FetchByIdOrName(userCred, query.Network) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(NetworkManager.Keyword(), query.Network) + } else { + return nil, errors.Wrap(err, "NetworkManager.FetchByIdOrName") + } + } + q = q.Equals("network_id", netObj.GetId()) + } + netQ := NetworkManager.Query("id").Snapshot() + netQ, err := manager.SWireResourceBaseManager.ListItemFilter(ctx, netQ, userCred, query.WireFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter") + } + if netQ.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("network_id"), netQ.SubQuery())) + } + return q, nil +} + +func (manager *SNetworkResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "network": + netQuery := NetworkManager.Query("name", "id").SubQuery() + q = q.AppendField(netQuery.Field("name", field)).Distinct() + q = q.Join(netQuery, sqlchemy.Equals(q.Field("network_id"), netQuery.Field("id"))) + return q, nil + default: + nets := NetworkManager.Query("id", "wire_id").SubQuery() + q = q.LeftJoin(nets, sqlchemy.Equals(q.Field("network_id"), nets.Field("id"))) + q, err := manager.SWireResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SNetworkResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NetworkFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SNetworkResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.NetworkFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + netQ := NetworkManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SWireResourceBaseManager.GetOrderByFields(query.WireFilterListInput)) { + var wireOrders []string + var wireFields []sqlchemy.IQueryField + netQ, wireOrders, wireFields = manager.SWireResourceBaseManager.GetOrderBySubQuery(netQ, userCred, query.WireFilterListInput) + if len(wireOrders) > 0 { + orders = append(orders, wireOrders...) + fields = append(fields, wireFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := netQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("network_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByNetwork}) { + orders = append(orders, query.OrderByNetwork) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SNetworkResourceBaseManager) GetOrderByFields(query api.NetworkFilterListInput) []string { + orders := make([]string, 0) + wireOrders := manager.SWireResourceBaseManager.GetOrderByFields(query.WireFilterListInput) + orders = append(orders, wireOrders...) + orders = append(orders, query.OrderByNetwork) + return orders +} diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index a43ac94910..2ce244a4a2 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -34,6 +34,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -48,6 +49,7 @@ import ( "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rand" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) var ( @@ -56,6 +58,7 @@ var ( type SNetworkManager struct { db.SSharableVirtualResourceBaseManager + SWireResourceBaseManager } var NetworkManager *SNetworkManager @@ -75,6 +78,7 @@ func init() { type SNetwork struct { db.SSharableVirtualResourceBase db.SExternalizedResourceBase + SWireResourceBase IfnameHint string `width:"9" charset:"ascii" nullable:"true" list:"user" create:"optional"` @@ -104,7 +108,7 @@ type SNetwork struct { VlanId int `nullable:"false" default:"1" list:"user" update:"user" create:"optional"` // 二层网络Id - WireId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` + // WireId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` // 服务器类型 // example: server @@ -122,22 +126,6 @@ func (manager *SNetworkManager) GetContextManagers() [][]db.IModelManager { } } -func (self *SNetwork) GetWire() *SWire { - w, _ := WireManager.FetchById(self.WireId) - if w != nil { - return w.(*SWire) - } - return nil -} - -func (self *SNetwork) GetVpc() *SVpc { - wire := self.GetWire() - if wire != nil { - return wire.getVpc() - } - return nil -} - func (manager *SNetworkManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowCreate(userCred, manager) } @@ -251,7 +239,7 @@ func (self *SNetwork) ValidateElbNetwork(ipAddr net.IP) (*SCloudregion, *SZone, return nil, nil, nil, nil, fmt.Errorf("getting wire failed") } - vpc := wire.getVpc() + vpc := wire.GetVpc() if vpc == nil { return nil, nil, nil, nil, fmt.Errorf("getting vpc failed") } @@ -264,7 +252,7 @@ func (self *SNetwork) ValidateElbNetwork(ipAddr net.IP) (*SCloudregion, *SZone, } } - region := wire.getRegion() + region := wire.GetRegion() if region == nil { return nil, nil, nil, nil, fmt.Errorf("getting region failed") } @@ -314,9 +302,9 @@ func (manager *SNetworkManager) NewClassicNetwork(wire *SWire) (*SNetwork, error GuestIpEnd: "255.255.255.255", GuestIpMask: 0, GuestGateway: "0.0.0.0", - WireId: wire.Id, ServerType: api.NETWORK_TYPE_GUEST, } + network.WireId = wire.Id network.SetModelManager(manager, &network) network.Name = fmt.Sprintf("emulate network for classic network with wire %s", wire.Id) network.ExternalId = wire.Id @@ -662,7 +650,7 @@ func (self *SNetwork) syncRemoveCloudNetwork(ctx context.Context, userCred mccli } func (self *SNetwork) SyncWithCloudNetwork(ctx context.Context, userCred mcclient.TokenCredential, extNet cloudprovider.ICloudNetwork, syncOwnerId mcclient.IIdentityProvider) error { - vpc := self.GetWire().getVpc() + vpc := self.GetVpc() diff, err := db.UpdateWithLock(ctx, self, func() error { extNet.Refresh() self.Status = extNet.GetStatus() @@ -719,7 +707,7 @@ func (manager *SNetworkManager) newFromCloudNetwork(ctx context.Context, userCre return nil, err } - vpc := wire.getVpc() + vpc := wire.GetVpc() SyncCloudProject(userCred, &net, syncOwnerId, extNet, vpc.ManagerId) db.OpsLog.LogEvent(&net, db.ACT_CREATE, net.GetShortDesc(ctx), userCred) @@ -961,39 +949,11 @@ func IsExitNetworkInfo(netConfig *api.NetworkConfig) bool { return false } -func (self *SNetwork) getZone() *SZone { - wire := self.GetWire() - if wire != nil { - return wire.GetZone() - } - return nil -} - -func (self *SNetwork) getVpc() *SVpc { - wire := self.GetWire() - if wire != nil { - return wire.getVpc() - } - return nil -} - -func (self *SNetwork) getRegion() *SCloudregion { - wire := self.GetWire() - if wire != nil { - return wire.getRegion() - } - return nil -} - func (self *SNetwork) GetPorts() int { return self.getIPRange().AddressCount() } func (self *SNetwork) getMoreDetails(ctx context.Context, out api.NetworkDetails, isList bool) (api.NetworkDetails, error) { - wire := self.GetWire() - if wire != nil { - out.Wire = wire.Name - } out.Exit = false if self.IsExitNetwork() { out.Exit = true @@ -1008,33 +968,42 @@ func (self *SNetwork) getMoreDetails(ctx context.Context, out api.NetworkDetails out.GroupVnics, _ = self.GetGroupNicsCount() out.ReserveVnics, _ = self.GetReservedNicsCount() - vpc := self.getVpc() - if vpc != nil { - out.Vpc = vpc.Name - out.VpcId = vpc.Id - out.VpcExtId = vpc.ExternalId - out.CloudproviderInfo = vpc.getCloudProviderInfo() - } - if len(out.Zone) == 0 { - zone := self.getZone() - if zone != nil { - out.Zone = zone.Name - out.ZoneId = zone.Id - } - } out.Routes = self.GetRoutes() out.Schedtags = GetSchedtagsDetailsToResourceV2(self, ctx) return out, nil } -func (self *SNetwork) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NetworkDetails, error) { - var err error - out := api.NetworkDetails{} - out.SharableVirtualResourceDetails, err = self.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SNetwork) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NetworkDetails, error) { + return api.NetworkDetails{}, nil +} + +func (manager *SNetworkManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NetworkDetails { + rows := make([]api.NetworkDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + wireRows := manager.SWireResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.NetworkDetails{ + SharableVirtualResourceDetails: virtRows[i], + WireResourceInfo: wireRows[i], + } + rows[i], _ = objs[i].(*SNetwork).getMoreDetails(ctx, rows[i], isList) } - return self.getMoreDetails(ctx, out, isList) + + return rows } func (self *SNetwork) AllowPerformReserveIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -1210,7 +1179,7 @@ func (manager *SNetworkManager) validateEnsureWire(ctx context.Context, userCred return } w = wObj.(*SWire) - v = w.getVpc() + v = w.GetVpc() crObj, err := CloudregionManager.FetchById(v.CloudregionId) if err != nil { err = errors.Wrapf(err, "cloudregion %s", v.CloudregionId) @@ -1646,8 +1615,8 @@ func (self *SNetwork) isManaged() bool { } func (self *SNetwork) isOneCloudVpcNetwork() bool { - vpc := self.getVpc() - region := self.getRegion() + vpc := self.GetVpc() + region := self.GetRegion() if region.Provider == api.CLOUD_PROVIDER_ONECLOUD && vpc.Id != api.DEFAULT_VPC_ID { return true } @@ -1674,93 +1643,24 @@ func parseIpToIntArray(ip string) ([]int, error) { } // IP子网列表 -func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.NetworkListInput) (*sqlchemy.SQuery, error) { +func (manager *SNetworkManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.NetworkListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, input.ManagedResourceListInput, "wire_id", func() *sqlchemy.SQuery { - wires := WireManager.Query().SubQuery() - vpcs := VpcManager.Query().SubQuery() - - subq := wires.Query(wires.Field("id")) - subq = subq.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id"))) - return subq - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } - q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } - zoneList := input.ZoneList() - if len(zoneList) > 0 { - zq := ZoneManager.Query().SubQuery() - regions := CloudregionManager.Query().SubQuery() - zoneQ := zq.Query(zq.Field("id"), regions.Field("id"), regions.Field("provider")). - Join(regions, sqlchemy.Equals(zq.Field("cloudregion_id"), regions.Field("id"))). - Filter( - sqlchemy.OR( - sqlchemy.In(zq.Field("id"), zoneList), - sqlchemy.In(zq.Field("name"), zoneList), - ), - ) - rows, err := zoneQ.Rows() - if err != nil { - return nil, err - } - - defer rows.Close() - - regionIds := []string{} - zoneIds := []string{} - for rows.Next() { - var zoneId, regionId, provider sql.NullString - err = rows.Scan(&zoneId, ®ionId, &provider) - if err != nil { - return nil, err - } - if len(provider.String) > 0 && utils.IsInStringArray(provider.String, api.REGIONAL_NETWORK_PROVIDERS) { - if !utils.IsInStringArray(regionId.String, regionIds) { - regionIds = append(regionIds, regionId.String) - } - } else { - zoneIds = append(zoneIds, zoneId.String) - } - } - - wires := WireManager.Query().SubQuery() - vpcs := VpcManager.Query().SubQuery() - sq := wires.Query(wires.Field("id")). - Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))). - Filter( - sqlchemy.OR( - sqlchemy.In(wires.Field("zone_id"), zoneIds), - sqlchemy.In(vpcs.Field("cloudregion_id"), regionIds), - ), - ) - q = q.In("wire_id", sq.SubQuery()) + q, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, input.WireFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter") } - vpcStr := input.Vpc - if len(vpcStr) > 0 { - vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr) - if err != nil { - return nil, httperrors.NewNotFoundError("VPC %s not found", vpcStr) - } - sq := WireManager.Query("id").Equals("vpc_id", vpcObj.GetId()) - q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery())) - } - - q, err = managedResourceFilterByRegion(q, input.RegionalFilterListInput, "wire_id", func() *sqlchemy.SQuery { - wires := WireManager.Query().SubQuery() - vpcs := VpcManager.Query().SubQuery() - sq := wires.Query(wires.Field("id")). - Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))) - return sq - }) - if input.Usable != nil && *input.Usable { wires := WireManager.Query().SubQuery() zones := ZoneManager.Query().SubQuery() @@ -1824,29 +1724,37 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy. return q, nil } +func (manager *SNetworkManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.NetworkListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SWireResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.WireFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SWireResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + func (manager *SNetworkManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { var err error q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { return q, nil } - switch field { - case "account": - vpcs := VpcManager.Query().SubQuery() - wires := WireManager.Query().SubQuery() - cloudproviders := CloudproviderManager.Query().SubQuery() - cloudaccounts := CloudaccountManager.Query("name", "id").Distinct().SubQuery() - q = q.Join(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id"))) - q = q.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id"))) - q = q.Join(cloudproviders, sqlchemy.Equals(vpcs.Field("manager_id"), cloudproviders.Field("id"))) - q = q.Join(cloudaccounts, sqlchemy.Equals(cloudproviders.Field("cloudaccount_id"), cloudaccounts.Field("id"))) - q.GroupBy(cloudaccounts.Field("name")) - q.AppendField(cloudaccounts.Field("name", "account")) - default: - return q, httperrors.NewBadRequestError("unsupport field %s", field) + q, err = manager.SWireResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil } - - return q, nil + return q, httperrors.ErrNotFound } func (manager *SNetworkManager) InitializeData() error { @@ -1906,7 +1814,7 @@ func (self *SNetwork) PerformPurge(ctx context.Context, userCred mcclient.TokenC vpc := self.GetVpc() if vpc != nil && len(vpc.ExternalId) > 0 { provider := vpc.GetCloudprovider() - if provider != nil && provider.Enabled { + if provider != nil && provider.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge network on enabled cloud provider") } } @@ -2268,8 +2176,8 @@ func (network *SNetwork) ClearSchedDescCache() error { return wire.clearHostSchedDescCache() } -func (network *SNetwork) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - ret, err := network.SSharableVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, data) +func (network *SNetwork) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) { + ret, err := network.SSharableVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input) if err != nil { return nil, err } @@ -2510,12 +2418,12 @@ func (net *SNetwork) StartNetworkSyncstatusTask(ctx context.Context, userCred mc return nil } -func (net *SNetwork) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (net *SNetwork) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) bool { return net.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, net, "status") } // 更改IP子网状态 -func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkStatusInput) (jsonutils.JSONObject, error) { +func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) { if len(input.Status) == 0 { return nil, httperrors.NewMissingParameterError("status") } @@ -2526,5 +2434,5 @@ func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenC if !utils.IsInStringArray(input.Status, []string{api.NETWORK_STATUS_AVAILABLE, api.NETWORK_STATUS_UNAVAILABLE}) { return nil, httperrors.NewInputParameterError("invalid status %s", input.Status) } - return net.SSharableVirtualResourceBase.PerformStatus(ctx, userCred, query, input.JSON(input)) + return net.SSharableVirtualResourceBase.PerformStatus(ctx, userCred, query, input) } diff --git a/pkg/compute/models/networkschedtags.go b/pkg/compute/models/networkschedtags.go index b305d4f1c3..83c153bf18 100644 --- a/pkg/compute/models/networkschedtags.go +++ b/pkg/compute/models/networkschedtags.go @@ -18,10 +18,12 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SNetworkschedtagManager struct { @@ -70,13 +72,47 @@ func (s *SNetworkschedtag) Master() db.IStandaloneModel { return s.SSchedtagJointsBase.master(s) } -func (s *SNetworkschedtag) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NetworkschedtagDetails, error) { - var err error - out := api.NetworkschedtagDetails{} - out.JoinModelBaseDetails, err = s.SSchedtagJointsBase.getExtraDetails(s, ctx, userCred, query, isList) - out.Network, out.Schedtag = db.JointModelExtra(s) - return out, err +func (s *SNetworkschedtag) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NetworkschedtagDetails, error) { + return api.NetworkschedtagDetails{}, nil +} +func (manager *SNetworkschedtagManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NetworkschedtagDetails { + rows := make([]api.NetworkschedtagDetails, len(objs)) + + schedRows := manager.SSchedtagJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + netIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.NetworkschedtagDetails{ + SchedtagJointResourceDetails: schedRows[i], + } + netIds[i] = objs[i].(*SNetworkschedtag).NetworkId + } + + netIdMaps, err := db.FetchIdNameMap2(NetworkManager, netIds) + if err != nil { + log.Errorf("FetchIdNameMap2 netIds fail %s", err) + return rows + } + + for i := range rows { + if name, ok := netIdMaps[netIds[i]]; ok { + rows[i].Network = name + } + } + + return rows } func (s *SNetworkschedtag) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/purge.go b/pkg/compute/models/purge.go index 203748d3a7..65c6ca75f6 100644 --- a/pkg/compute/models/purge.go +++ b/pkg/compute/models/purge.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -78,7 +79,7 @@ func (host *SHost) purge(ctx context.Context, userCred mcclient.TokenCredential) lockman.LockObject(ctx, host) defer lockman.ReleaseObject(ctx, host) - _, err := host.PerformDisable(ctx, userCred, nil, nil) + _, err := host.PerformDisable(ctx, userCred, nil, apis.PerformDisableInput{}) if err != nil { return err } @@ -1184,7 +1185,7 @@ func (nat *SNatGateway) purge(ctx context.Context, userCred mcclient.TokenCreden return nat.Delete(ctx, userCred) } -func (manager *SNatGetewayManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error { +func (manager *SNatGatewayManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error { nats, err := manager.getNatgatewaysByProviderId(providerId) if err != nil { return err diff --git a/pkg/compute/models/quotas.go b/pkg/compute/models/quotas.go index 755c2e4c0d..5f7a0fc43a 100644 --- a/pkg/compute/models/quotas.go +++ b/pkg/compute/models/quotas.go @@ -16,7 +16,6 @@ package models import ( "context" - "database/sql" "fmt" "yunion.io/x/jsonutils" @@ -402,43 +401,20 @@ func (manager *SQuotaManager) FetchIdNames(ctx context.Context, idMap map[string return idMap, nil } -func dbFetchIdNameMap(manager db.IStandaloneModelManager, idMap map[string]string) (map[string]string, error) { - q := manager.Query("id", "name").In("id", utils.MapKeys(idMap)) - rows, err := q.Rows() - if err != nil { - if errors.Cause(err) == sql.ErrNoRows { - return idMap, nil - } else { - return idMap, errors.Wrap(err, "Query") - } - } - defer rows.Close() - for rows.Next() { - var id string - var name string - err := rows.Scan(&id, &name) - if err != nil { - return idMap, errors.Wrap(err, "rows.Scan") - } - idMap[id] = name - } - return idMap, nil -} - func fetchRegionNames(idMap map[string]string) (map[string]string, error) { - return dbFetchIdNameMap(CloudregionManager, idMap) + return db.FetchIdNameMap(CloudregionManager, idMap) } func fetchZoneNames(idMap map[string]string) (map[string]string, error) { - return dbFetchIdNameMap(ZoneManager, idMap) + return db.FetchIdNameMap(ZoneManager, idMap) } func fetchAccountNames(idMap map[string]string) (map[string]string, error) { - return dbFetchIdNameMap(CloudaccountManager, idMap) + return db.FetchIdNameMap(CloudaccountManager, idMap) } func fetchManagerNames(idMap map[string]string) (map[string]string, error) { - return dbFetchIdNameMap(CloudproviderManager, idMap) + return db.FetchIdNameMap(CloudproviderManager, idMap) } type SComputeResourceKeys struct { diff --git a/pkg/compute/models/reservedips.go b/pkg/compute/models/reservedips.go index c485b8af8f..859c620087 100644 --- a/pkg/compute/models/reservedips.go +++ b/pkg/compute/models/reservedips.go @@ -29,10 +29,12 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SReservedipManager struct { db.SResourceBaseManager + SNetworkResourceBaseManager } var ReservedipManager *SReservedipManager @@ -51,11 +53,14 @@ func init() { type SReservedip struct { db.SResourceBase + SNetworkResourceBase // 自增Id Id int64 `primary:"true" auto_increment:"true" list:"admin"` + // IP子网Id - NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"admin"` + // NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"admin"` + // IP地址 IpAddr string `width:"16" charset:"ascii" list:"admin"` @@ -104,7 +109,8 @@ func (manager *SReservedipManager) ReserveIPWithDurationAndStatus(userCred mccli } rip := manager.getReservedIP(network, ip) if rip == nil { - rip := SReservedip{NetworkId: network.Id, IpAddr: ip, Notes: notes, ExpiredAt: expiredAt, Status: status} + rip := SReservedip{IpAddr: ip, Notes: notes, ExpiredAt: expiredAt, Status: status} + rip.NetworkId = network.Id err := manager.TableSpec().Insert(&rip) if err != nil { log.Errorf("ReserveIP fail: %s", err) @@ -190,43 +196,97 @@ func (self *SReservedip) Release(ctx context.Context, userCred mcclient.TokenCre } func (self *SReservedip) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ReservedipDetails, error) { - var err error - out := api.ReservedipDetails{} - out.ModelBaseDetails, err = self.SResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.ReservedipDetails{}, nil +} + +func (manager *SReservedipManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ReservedipDetails { + rows := make([]api.ReservedipDetails, len(objs)) + + resRows := manager.SResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + netRows := manager.SNetworkResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ReservedipDetails{ + ResourceBaseDetails: resRows[i], + NetworkResourceInfo: netRows[i], + } + rows[i].Expired = objs[i].(*SReservedip).IsExpired() } - net := self.GetNetwork() - if net != nil { - out.Network = net.Name - } - out.Expired = self.IsExpired() - return out, nil + + return rows } // 预留IP地址列表 -func (manager *SReservedipManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ReservedipListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput) +func (manager *SReservedipManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ReservedipListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput) if err != nil { return nil, errors.Wrap(err, "SResourceBaseManager.ListItemFilter") } + q, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, query.NetworkFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter") + } + if query.All == nil || *query.All == false { q = q.Filter(sqlchemy.OR( sqlchemy.IsNullOrEmpty(q.Field("expired_at")), sqlchemy.GT(q.Field("expired_at"), time.Now().UTC()), )) } - network := query.Network - if len(network) > 0 { - netObj, _ := NetworkManager.FetchByIdOrName(userCred, network) - if netObj == nil { - return nil, httperrors.NewResourceNotFoundError("network %s not found", network) - } - q = q.Equals("network_id", netObj.GetId()) - } + return q, nil } +func (manager *SReservedipManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ReservedipListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SReservedipManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (rip *SReservedip) GetId() string { return strconv.FormatInt(rip.Id, 10) } diff --git a/pkg/compute/models/routetables.go b/pkg/compute/models/routetables.go index 17ead50642..5b46e0e7c5 100644 --- a/pkg/compute/models/routetables.go +++ b/pkg/compute/models/routetables.go @@ -35,6 +35,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SRoute struct { @@ -96,6 +97,7 @@ func (routes *SRoutes) Validate(data *jsonutils.JSONDict) error { type SRouteTableManager struct { db.SVirtualResourceBaseManager + SVpcResourceBaseManager } var RouteTableManager *SRouteTableManager @@ -118,41 +120,70 @@ func init() { type SRouteTable struct { db.SVirtualResourceBase db.SExternalizedResourceBase + SVpcResourceBase - SManagedResourceBase - - VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` - CloudregionId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` - Type string `width:"16" charset:"ascii" nullable:"false" list:"user"` - Routes *SRoutes `list:"user" update:"user" create:"required"` + Type string `width:"16" charset:"ascii" nullable:"false" list:"user"` + Routes *SRoutes `list:"user" update:"user" create:"required"` } // VPC虚拟路由表列表 -func (man *SRouteTableManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.RouteTableListInput) (*sqlchemy.SQuery, error) { +func (man *SRouteTableManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RouteTableListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - // userProjId := userCred.GetProjectId() - data := jsonutils.Marshal(query).(*jsonutils.JSONDict) - q, err = validators.ApplyModelFilters(q, data, []*validators.ModelFilterOptions{ - {Key: "vpc", ModelKeyword: "vpc", OwnerId: userCred}, - {Key: "cloudregion", ModelKeyword: "cloudregion", OwnerId: userCred}, - {Key: "manager", ModelKeyword: "cloudprovider", OwnerId: userCred}, - }) + + q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } return q, nil } +func (man *SRouteTableManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RouteTableListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (man *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (man *SRouteTableManager) validateRoutes(data *jsonutils.JSONDict, update bool) (*jsonutils.JSONDict, error) { routes := SRoutes{} routesV := validators.NewStructValidator("routes", &routes) @@ -195,7 +226,7 @@ func (man *SRouteTableManager) ValidateCreateData(ctx context.Context, userCred return data, nil } -func (manager *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { +/*func (manager *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { var err error q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { @@ -213,7 +244,7 @@ func (manager *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, f return q, httperrors.NewBadRequestError("unsupport field %s", field) } return q, nil -} +}*/ func (rt *SRouteTable) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return db.IsAdminAllowPerform(userCred, rt, "purge") @@ -226,7 +257,7 @@ func (rt *SRouteTable) PerformPurge(ctx context.Context, userCred mcclient.Token } provider := rt.GetCloudprovider() if provider != nil { - if provider.Enabled { + if provider.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge route_table on enabled cloud provider") } } @@ -329,28 +360,30 @@ func (rt *SRouteTable) PerformDelRoutes(ctx context.Context, userCred mcclient.T } func (rt *SRouteTable) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.RouteTableDetails, error) { - var err error - out := api.RouteTableDetails{} - out.VirtualResourceDetails, err = rt.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.RouteTableDetails{}, nil +} + +func (manager *SRouteTableManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.RouteTableDetails { + rows := make([]api.RouteTableDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.RouteTableDetails{ + VirtualResourceDetails: virtRows[i], + VpcResourceInfo: vpcRows[i], + } } - vpcM, err := VpcManager.FetchById(rt.VpcId) - if err != nil { - log.Errorf("route table %s(%s): fetch vpc (%s) error: %s", - rt.Name, rt.Id, rt.VpcId, err) - return out, err - } - out.Vpc = vpcM.GetName() - cloudregionM, err := CloudregionManager.FetchById(rt.CloudregionId) - if err != nil { - log.Errorf("route table %s(%s): fetch cloud region (%s) error: %s", - rt.Name, rt.Id, rt.CloudregionId, err) - return out, err - } - out.Cloudregion = cloudregionM.GetName() - out.CloudproviderInfo = rt.getCloudProviderInfo() - return out, nil + + return rows } func (man *SRouteTableManager) SyncRouteTables(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTables []cloudprovider.ICloudRouteTable) ([]SRouteTable, []cloudprovider.ICloudRouteTable, compare.SyncResult) { @@ -428,11 +461,10 @@ func (man *SRouteTableManager) newRouteTableFromCloud(userCred mcclient.TokenCre } } routeTable := &SRouteTable{ - CloudregionId: vpc.CloudregionId, - VpcId: vpc.Id, - Type: cloudRouteTable.GetType(), - Routes: &routes, + Type: cloudRouteTable.GetType(), + Routes: &routes, } + routeTable.VpcId = vpc.Id { basename := routeTableBasename(cloudRouteTable.GetName(), vpc.Name) newName, err := db.GenerateName(man, userCred, basename) @@ -441,7 +473,7 @@ func (man *SRouteTableManager) newRouteTableFromCloud(userCred mcclient.TokenCre } routeTable.Name = newName } - routeTable.ManagerId = vpc.ManagerId + // routeTable.ManagerId = vpc.ManagerId routeTable.ExternalId = cloudRouteTable.GetGlobalId() routeTable.Description = cloudRouteTable.GetDescription() routeTable.ProjectId = userCred.GetProjectId() @@ -491,7 +523,7 @@ func (self *SRouteTable) SyncWithCloudRouteTable(ctx context.Context, userCred m return err } diff, err := db.UpdateWithLock(ctx, self, func() error { - self.CloudregionId = routeTable.CloudregionId + // self.CloudregionId = routeTable.CloudregionId self.VpcId = vpc.Id self.Type = routeTable.Type self.Routes = routeTable.Routes @@ -521,7 +553,7 @@ func (self *SRouteTable) getRegion() (*SCloudregion, error) { return vpc.GetRegion() } -func (self *SRouteTable) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SRouteTable) getCloudProviderInfo() SCloudProviderInfo { region, _ := self.getRegion() provider := self.GetCloudprovider() return MakeCloudProviderInfo(region, nil, provider) diff --git a/pkg/compute/models/schedpolicies.go b/pkg/compute/models/schedpolicies.go index 8662457a4b..327cad181c 100644 --- a/pkg/compute/models/schedpolicies.go +++ b/pkg/compute/models/schedpolicies.go @@ -31,10 +31,12 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/conditionparser" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSchedpolicyManager struct { db.SStandaloneResourceBaseManager + SSchedtagResourceBaseManager } var SchedpolicyManager *SSchedpolicyManager @@ -54,10 +56,10 @@ func init() { // sched policy is called before calling scheduler, add additional preferences for schedtags type SSchedpolicy struct { db.SStandaloneResourceBase + SSchedtagResourceBase - Condition string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user"` - SchedtagId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user"` - Strategy string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user"` + Condition string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user"` + Strategy string `width:"32" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user"` Enabled tristate.TriState `nullable:"false" default:"true" create:"optional" list:"user" update:"user"` } @@ -80,26 +82,6 @@ func validateSchedpolicyInputData(data *jsonutils.JSONDict, create bool) error { return nil } -func (self *SSchedpolicyManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SSchedpolicyManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SSchedpolicy) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SSchedpolicy) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SSchedpolicy) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (manager *SSchedpolicyManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { err := validateSchedpolicyInputData(data, true) if err != nil { @@ -137,23 +119,30 @@ func (self *SSchedpolicy) getSchedtag() *SSchedtag { return obj.(*SSchedtag) } -func (self *SSchedpolicy) getMoreColumns(out api.SchedpolicyDetails) api.SchedpolicyDetails { - schedtag := self.getSchedtag() - if schedtag != nil { - out.Schedtag = schedtag.Name - out.ResourceType = schedtag.ResourceType - } - return out +func (self *SSchedpolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SchedpolicyDetails, error) { + return api.SchedpolicyDetails{}, nil } -func (self *SSchedpolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SchedpolicyDetails, error) { - var err error - out := api.SchedpolicyDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SSchedpolicyManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SchedpolicyDetails { + rows := make([]api.SchedpolicyDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + tagRows := manager.SSchedtagResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.SchedpolicyDetails{ + StandaloneResourceDetails: stdRows[i], + SchedtagResourceInfo: tagRows[i], + } } - return self.getMoreColumns(out), nil + + return rows } func (manager *SSchedpolicyManager) getAllEnabledPoliciesByResource(resType string) []SSchedpolicy { @@ -317,10 +306,57 @@ func ApplySchedPolicies(input *schedapi.ScheduleInput) *schedapi.ScheduleInput { } // 动态调度策略列表 -func (manager *SSchedpolicyManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.SchedpolicyListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) +func (manager *SSchedpolicyManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SchedpolicyListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SSchedtagResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SchedtagFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SSchedtagResourceBaseManager.ListItemFilter") + } + return q, nil } + +func (manager *SSchedpolicyManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SchedpolicyListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SSchedtagResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SchedtagFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SSchedtagResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSchedpolicyManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SSchedtagResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/schedtagjoint.go b/pkg/compute/models/schedtagjoint.go index 14cc447a06..fefe67861c 100644 --- a/pkg/compute/models/schedtagjoint.go +++ b/pkg/compute/models/schedtagjoint.go @@ -19,12 +19,16 @@ import ( "fmt" "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSchedtagJointsManager struct { @@ -147,14 +151,55 @@ func (joint *SSchedtagJointsBase) Slave() db.IStandaloneModel { return db.JointSlave(joint) } -func (joint *SSchedtagJointsBase) getExtraDetails(obj db.IJointModel, ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (apis.JoinModelBaseDetails, error) { - var err error - out := apis.JoinModelBaseDetails{} - out.ModelBaseDetails, err = joint.SJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (joint *SSchedtagJointsBase) GetExtraDetails( + obj db.IJointModel, + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SchedtagJointResourceDetails, error) { + return api.SchedtagJointResourceDetails{}, nil +} + +func (manager *SSchedtagJointsManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SchedtagJointResourceDetails { + rows := make([]api.SchedtagJointResourceDetails, len(objs)) + + jointRows := manager.SJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + tagIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.SchedtagJointResourceDetails{ + JointResourceBaseDetails: jointRows[i], + } + var base *SSchedtagJointsBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.SchedtagId) > 0 { + tagIds[i] = base.SchedtagId + } } - return out, nil + + tags := make(map[string]SSchedtag) + err := db.FetchStandaloneObjectsByIds(SchedtagManager, tagIds, &tags) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + for i := range rows { + if schedtag, ok := tags[tagIds[i]]; ok { + rows[i].Schedtag = schedtag.Name + rows[i].ResourceType = schedtag.ResourceType + } + } + + return rows } func (joint *SSchedtagJointsBase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/schedtagresource.go b/pkg/compute/models/schedtagresource.go new file mode 100644 index 0000000000..5ac9c3e4a4 --- /dev/null +++ b/pkg/compute/models/schedtagresource.go @@ -0,0 +1,157 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SSchedtagResourceBase struct { + // 归属调度标签ID + SchedtagId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" update:"user" json:"schedtag_id"` +} + +type SSchedtagResourceBaseManager struct{} + +func (self *SSchedtagResourceBase) GetSchedtag() *SSchedtag { + obj, err := SchedtagManager.FetchById(self.SchedtagId) + if err != nil { + log.Errorf("fail to fetch sched tag by id %s", err) + return nil + } + return obj.(*SSchedtag) +} + +func (self *SSchedtagResourceBase) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) api.SchedtagResourceInfo { + return api.SchedtagResourceInfo{} +} + +func (manager *SSchedtagResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SchedtagResourceInfo { + rows := make([]api.SchedtagResourceInfo, len(objs)) + schedTagIds := make([]string, len(objs)) + for i := range objs { + var base *SSchedtagResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SSchedtagResourceBase in object %s", objs[i]) + continue + } + schedTagIds[i] = base.SchedtagId + } + tags := make(map[string]SSchedtag) + err := db.FetchStandaloneObjectsByIds(SchedtagManager, schedTagIds, tags) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + for i := range rows { + rows[i] = api.SchedtagResourceInfo{} + if tag, ok := tags[schedTagIds[i]]; ok { + rows[i].Schedtag = tag.Name + rows[i].ResourceType = tag.ResourceType + } + } + return rows +} + +func (manager *SSchedtagResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SchedtagFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Schedtag) > 0 { + tagObj, err := SchedtagManager.FetchByIdOrName(userCred, query.Schedtag) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(SchedtagManager.Keyword(), query.Schedtag) + } else { + return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName") + } + } + q = q.Equals("schedtag_id", tagObj.GetId()) + } + return q, nil +} + +func (manager *SSchedtagResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SchedtagFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SSchedtagResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "schedtag" { + tagQuery := SchedtagManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(tagQuery.Field("name", field)) + q = q.Join(tagQuery, sqlchemy.Equals(q.Field("schedtag_id"), tagQuery.Field("id"))) + q.GroupBy(tagQuery.Field("name")) + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SSchedtagResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SchedtagFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + tagQ := SchedtagManager.Query("id", "name", "resource_type") + var orders []string + var fields []sqlchemy.IQueryField + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := tagQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("schedtag_id"), subq.Field("id"))) + orders = append(orders, query.OrderBySchedtag, query.OrderByResourceType) + fields = append(fields, subq.Field("name"), subq.Field("resource_type")) + } + return q, orders, fields +} + +func (manager *SSchedtagResourceBaseManager) GetOrderByFields(query api.SchedtagFilterListInput) []string { + return []string{query.OrderBySchedtag, query.OrderByResourceType} +} diff --git a/pkg/compute/models/schedtags.go b/pkg/compute/models/schedtags.go index 1b25a176a8..36df25fecd 100644 --- a/pkg/compute/models/schedtags.go +++ b/pkg/compute/models/schedtags.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -29,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SchedStrategyType string @@ -133,11 +135,48 @@ func (manager *SSchedtagManager) AllowListItems(ctx context.Context, userCred mc } // 调度标签列表 -func (manager *SSchedtagManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SchedtagListInput) (*sqlchemy.SQuery, error) { +func (manager *SSchedtagManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SchedtagListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + } if resType := query.ResourceType; resType != "" { q = q.Equals("resource_type", resType) } - return manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + return q, nil +} + +func (manager *SSchedtagManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SchedtagListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSchedtagManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } func (self *SSchedtag) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -334,14 +373,35 @@ func (self *SSchedtag) getMoreColumns(out api.SchedtagDetails) api.SchedtagDetai return out } -func (self *SSchedtag) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SchedtagDetails, error) { - var err error - out := api.SchedtagDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SSchedtag) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SchedtagDetails, error) { + return api.SchedtagDetails{}, nil +} + +func (manager *SSchedtagManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SchedtagDetails { + rows := make([]api.SchedtagDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SchedtagDetails{ + StandaloneResourceDetails: stdRows[i], + } + rows[i] = objs[i].(*SSchedtag).getMoreColumns(rows[i]) } - return self.getMoreColumns(out), nil + + return rows } /*func (self *SSchedtag) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 0a8f0ad6ec..faf7187c4d 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -32,10 +32,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSecurityGroupCacheManager struct { db.SStatusStandaloneResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } type SSecurityGroupCache struct { @@ -77,11 +80,25 @@ func (self *SSecurityGroupCache) AllowUpdateItem(ctx context.Context, userCred m } // 安全组缓存列表 -func (manager *SSecurityGroupCacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SecurityGroupCacheListInput) (*sqlchemy.SQuery, error) { +func (manager *SSecurityGroupCacheManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SecurityGroupCacheListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + if defsecgroup := query.Secgroup; len(defsecgroup) > 0 { secgroup, err := SecurityGroupManager.FetchByIdOrName(userCred, defsecgroup) if err != nil { @@ -96,6 +113,49 @@ func (manager *SSecurityGroupCacheManager) ListItemFilter(ctx context.Context, q return q, nil } +func (manager *SSecurityGroupCacheManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SecurityGroupCacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSecurityGroupCacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SSecurityGroupCache) GetIRegion() (cloudprovider.ICloudRegion, error) { provider, err := self.GetDriver() if err != nil { @@ -115,23 +175,42 @@ func (self *SSecurityGroupCache) GetVpc() (*SVpc, error) { return vpc.(*SVpc), nil } -func (self *SSecurityGroupCache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SecurityGroupCacheDetails, error) { - var err error - out := api.SecurityGroupCacheDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - provider := self.GetCloudprovider() - region := self.GetRegion() +func (self *SSecurityGroupCache) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SecurityGroupCacheDetails, error) { + return api.SecurityGroupCacheDetails{}, nil +} - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) +func (manager *SSecurityGroupCacheManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SecurityGroupCacheDetails { + rows := make([]api.SecurityGroupCacheDetails, len(objs)) - vpc, _ := self.GetVpc() - if vpc != nil { - out.Vpc = vpc.Name + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SecurityGroupCacheDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regRows[i], + } + vpc, _ := objs[i].(*SSecurityGroupCache).GetVpc() + if vpc != nil { + rows[i].Vpc = vpc.Name + } } - return out, nil + + return rows } func (manager *SSecurityGroupCacheManager) GetSecgroupCache(ctx context.Context, userCred mcclient.TokenCredential, secgroupId, vpcId string, regionId string, providerId string) (*SSecurityGroupCache, error) { diff --git a/pkg/compute/models/secgrouprules.go b/pkg/compute/models/secgrouprules.go index 89b92a800b..83041d5c8d 100644 --- a/pkg/compute/models/secgrouprules.go +++ b/pkg/compute/models/secgrouprules.go @@ -159,7 +159,12 @@ func (manager *SSecurityGroupRuleManager) FilterById(q *sqlchemy.SQuery, idStr s } // 安全组规则列表 -func (manager *SSecurityGroupRuleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SecurityGroupRuleListInput) (*sqlchemy.SQuery, error) { +func (manager *SSecurityGroupRuleManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SecurityGroupRuleListInput, +) (*sqlchemy.SQuery, error) { sql, err := manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput) if err != nil { return nil, errors.Wrap(err, "SResourceBaseManager.ListItemFilter") @@ -180,7 +185,34 @@ func (manager *SSecurityGroupRuleManager) ListItemFilter(ctx context.Context, q if len(query.Protocol) > 0 { sql = sql.Equals("protocol", query.Protocol) } - return sql, err + return sql, nil +} + +func (manager *SSecurityGroupRuleManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SecurityGroupRuleListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSecurityGroupRuleManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } func (self *SSecurityGroupRule) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index 1d498eaa4c..b144d027ff 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -43,6 +43,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSecurityGroupManager struct { @@ -75,7 +76,19 @@ type SSecurityGroup struct { } // 安全组列表 -func (manager *SSecurityGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.SecgroupListInput) (*sqlchemy.SQuery, error) { +func (manager *SSecurityGroupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SecgroupListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") + } + if len(input.Equals) > 0 { _secgroup, err := manager.FetchByIdOrName(userCred, input.Equals) if err != nil { @@ -138,12 +151,20 @@ func (manager *SSecurityGroupManager) ListItemFilter(ctx context.Context, q *sql return q, nil } -func (manager *SSecurityGroupManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - q, err := manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query) +func (manager *SSecurityGroupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SecgroupListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") } - orderByCache, _ := query.GetString("order_by_cache_cnt") + + orderByCache := input.OrderByCacheCnt if sqlchemy.SQL_ORDER_ASC.Equals(orderByCache) || sqlchemy.SQL_ORDER_DESC.Equals(orderByCache) { caches := SecurityGroupCacheManager.Query().SubQuery() cacheQ := caches.Query( @@ -158,7 +179,7 @@ func (manager *SSecurityGroupManager) OrderByExtraFields(ctx context.Context, q q = q.Desc(cacheSQ.Field("cache_cnt")) } } - orderByGuest, _ := query.GetString("order_by_guest_cnt") + orderByGuest := input.OrderByGuestCnt if sqlchemy.SQL_ORDER_ASC.Equals(orderByGuest) || sqlchemy.SQL_ORDER_DESC.Equals(orderByGuest) { guests := GuestManager.Query().SubQuery() guestsecgroups := GuestsecgroupManager.Query().SubQuery() @@ -186,6 +207,17 @@ func (manager *SSecurityGroupManager) OrderByExtraFields(ctx context.Context, q return q, nil } +func (manager *SSecurityGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SSecurityGroup) GetGuestsQuery() *sqlchemy.SQuery { guests := GuestManager.Query().SubQuery() return guests.Query().Filter( @@ -228,21 +260,42 @@ func (self *SSecurityGroup) getDesc() jsonutils.JSONObject { return desc } -func (self *SSecurityGroup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SecgroupDetails, error) { - var err error - out := api.SecgroupDetails{} - out.SharableVirtualResourceDetails, err = self.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SSecurityGroupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SecgroupDetails { + rows := make([]api.SecgroupDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SecgroupDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + sg := objs[i].(*SSecurityGroup) + rows[i].GuestCnt = len(sg.GetGuests()) + rows[i].CacheCnt, _ = sg.GetSecgroupCacheCount() + if !isList { + rows[i].Rules = sg.getSecurityRuleString("") + rows[i].InRules = sg.getSecurityRuleString("in") + rows[i].OutRules = sg.getSecurityRuleString("out") + } } - out.GuestCnt = len(self.GetGuests()) - out.CacheCnt, _ = self.GetSecgroupCacheCount() - if !isList { - out.Rules = self.getSecurityRuleString("") - out.InRules = self.getSecurityRuleString("in") - out.OutRules = self.getSecurityRuleString("out") - } - return out, nil + + return rows +} + +func (self *SSecurityGroup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SecgroupDetails, error) { + return api.SecgroupDetails{}, nil } func (manager *SSecurityGroupManager) ValidateCreateData( diff --git a/pkg/compute/models/service_catalog.go b/pkg/compute/models/service_catalog.go index cb864970fc..533fa4016c 100644 --- a/pkg/compute/models/service_catalog.go +++ b/pkg/compute/models/service_catalog.go @@ -30,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SServiceCatalogManager struct { @@ -170,10 +171,69 @@ func (sc *SServiceCatalog) PerformDeploy(ctx context.Context, userCred mcclient. } // 服务目录列表 -func (manager *SServiceCatalogManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input computeapis.ServiceCatalogListInput) (*sqlchemy.SQuery, error) { +func (manager *SServiceCatalogManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input computeapis.ServiceCatalogListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SServiceCatalogManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input computeapis.ServiceCatalogListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SServiceCatalogManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (manager *SServiceCatalogManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []computeapis.ServiceCatalogDetails { + rows := make([]computeapis.ServiceCatalogDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = computeapis.ServiceCatalogDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + } + + return rows +} + +func (self *SServiceCatalog) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (computeapis.ServiceCatalogDetails, error) { + return computeapis.ServiceCatalogDetails{}, nil +} diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index b9b79a78d5..bf9a6ca749 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -47,12 +47,15 @@ import ( "yunion.io/x/onecloud/pkg/util/hashcache" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) var Cache *hashcache.Cache type SServerSkuManager struct { db.SStatusStandaloneResourceBaseManager + SCloudregionResourceBaseManager + SZoneResourceBaseManager } var ServerSkuManager *SServerSkuManager @@ -256,12 +259,10 @@ func (self *SServerSku) AllowGetDetails(ctx context.Context, userCred mcclient.T } func (self *SServerSku) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ServerSkuDetails, error) { - var err error - out := api.ServerSkuDetails{} - out.StandaloneResourceDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } + return api.ServerSkuDetails{}, nil +} + +func (self *SServerSku) getTotalGuestCount() int { // count var count int countKey := self.GetId() + ".total_guest_count" @@ -272,23 +273,35 @@ func (self *SServerSku) GetExtraDetails(ctx context.Context, userCred mcclient.T } else { count = v.(int) } - out.TotalGuestCount = count + return count +} - zone := self.GetZone() - if zone != nil { - out.Zone = zone.Name - out.ZoneExtId = fetchExternalId(zone.ExternalId) +func (manager *SServerSkuManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ServerSkuDetails { + rows := make([]api.ServerSkuDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ServerSkuDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ZoneResourceInfo: zoneRows[i], + } + if len(rows[i].Zone) == 0 { + rows[i].CloudregionResourceInfo = regRows[i] + } + rows[i].TotalGuestCount = objs[i].(*SServerSku).getTotalGuestCount() } - region, _ := self.GetRegion() - if region != nil { - out.Region = region.Name - out.RegionId = region.Id - out.RegionExternalId = region.ExternalId - out.RegionExtId = fetchExternalId(region.ExternalId) - } - - return out, nil + return rows } func (manager *SServerSkuManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { @@ -707,7 +720,12 @@ func listItemDomainFilter(q *sqlchemy.SQuery, providers []string, domainId strin } // 主机套餐规格列表 -func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ServerSkuListInput) (*sqlchemy.SQuery, error) { +func (manager *SServerSkuManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ServerSkuListInput, +) (*sqlchemy.SQuery, error) { publicCloud := false cloudEnvStr := query.CloudEnv @@ -807,6 +825,39 @@ func (manager *SServerSkuManager) ListItemFilter(ctx context.Context, q *sqlchem return q, err } +func (manager *SServerSkuManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ServerSkuListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SServerSkuManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (manager *SServerSkuManager) GetMatchedSku(regionId string, cpu int64, memMB int64) (*SServerSku, error) { ret := &SServerSku{} @@ -974,7 +1025,7 @@ func (self *SServerSku) PerformCacheSku(ctx context.Context, userCred mcclient.T return nil, httperrors.NewInputParameterError("failed to get cloudprovider for region %s(%s)", cloudregion.Name, cloudregion.Id) } - if !cloudprovider.Enabled { + if !cloudprovider.GetEnabled() { return nil, httperrors.NewInputParameterError("cloudprovider %s(%s) disabled", cloudprovider.Name, cloudprovider.Id) } diff --git a/pkg/compute/models/snapshotpolicy.go b/pkg/compute/models/snapshotpolicy.go index 311c10c592..7bdf9858ed 100644 --- a/pkg/compute/models/snapshotpolicy.go +++ b/pkg/compute/models/snapshotpolicy.go @@ -34,6 +34,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/bitmap" + "yunion.io/x/onecloud/pkg/util/stringutils2" "yunion.io/x/onecloud/pkg/util/validate" ) @@ -313,25 +314,42 @@ func (sp *SSnapshotPolicy) StartSnapshotPolicyDeleteTask(ctx context.Context, us return nil } -func (sp *SSnapshotPolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (api.SnapshotPolicyDetails, error) { - var err error - out := api.SnapshotPolicyDetails{} - out.VirtualResourceDetails, err = sp.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SSnapshotPolicyManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SnapshotPolicyDetails { + rows := make([]api.SnapshotPolicyDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SnapshotPolicyDetails{ + VirtualResourceDetails: virtRows[i], + } + rows[i] = objs[i].(*SSnapshotPolicy).getMoreDetails(rows[i]) } - return sp.getMoreDetails(ctx, userCred, out) + + return rows } -func (sp *SSnapshotPolicy) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, - out api.SnapshotPolicyDetails) (api.SnapshotPolicyDetails, error) { +func (sp *SSnapshotPolicy) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SnapshotPolicyDetails, error) { + return api.SnapshotPolicyDetails{}, nil +} - var err error +func (sp *SSnapshotPolicy) getMoreDetails(out api.SnapshotPolicyDetails) api.SnapshotPolicyDetails { out.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysToIntArray(sp.RepeatWeekdays) out.TimePoints = SnapshotPolicyManager.TimePointsToIntArray(sp.TimePoints) - out.BindingDiskCount, err = SnapshotPolicyDiskManager.FetchDiskCountBySPID(sp.Id) - return out, err + out.BindingDiskCount, _ = SnapshotPolicyDiskManager.FetchDiskCountBySPID(sp.Id) + return out } // ==================================================== sync =========================================================== @@ -835,10 +853,42 @@ func (sp *SSnapshotPolicy) PerformUnbindDisks(ctx context.Context, userCred mccl } // 快照策略列表 -func (manager *SSnapshotPolicyManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.SnapshotPolicyListInput) (*sqlchemy.SQuery, error) { +func (manager *SSnapshotPolicyManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SnapshotPolicyListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SSnapshotPolicyManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + input api.SnapshotPolicyListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.VirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSnapshotPolicyManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/compute/models/snapshotpolicycache.go b/pkg/compute/models/snapshotpolicycache.go index 7c532bd0b5..04034ae1ee 100644 --- a/pkg/compute/models/snapshotpolicycache.go +++ b/pkg/compute/models/snapshotpolicycache.go @@ -33,10 +33,13 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSnapshotPolicyCacheManager struct { db.SStatusStandaloneResourceBaseManager + SCloudregionResourceBaseManager + SManagedResourceBaseManager } type SSnapshotPolicyCache struct { @@ -52,7 +55,7 @@ var SnapshotPolicyCacheManager *SSnapshotPolicyCacheManager func init() { SnapshotPolicyCacheManager = &SSnapshotPolicyCacheManager{ - db.NewStatusStandaloneResourceBaseManager( + SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager( SSnapshotPolicyCache{}, "snapshotpolicycache_tbl", "snapshotpolicycache", @@ -62,21 +65,40 @@ func init() { SnapshotPolicyCacheManager.SetVirtualObject(SnapshotPolicyCacheManager) } -func NewSSnapshotPolicyCache(snapshotpolicyId, cloudregionId, externalId string) SSnapshotPolicyCache { - return SSnapshotPolicyCache{ +func NewSSnapshotPolicyCache(snapshotpolicyId, cloudregionId, externalId string) *SSnapshotPolicyCache { + cache := SSnapshotPolicyCache{ SnapshotpolicyId: snapshotpolicyId, SCloudregionResourceBase: SCloudregionResourceBase{cloudregionId}, SExternalizedResourceBase: db.SExternalizedResourceBase{externalId}, } + cache.SetModelManager(SnapshotPolicyCacheManager, &cache) + return &cache } // 快照策略缓存列表 -func (spcm *SSnapshotPolicyCacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, - query api.SnapshotPolicyCacheListInput) (*sqlchemy.SQuery, error) { - q, err := spcm.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput) +func (spcm *SSnapshotPolicyCacheManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SnapshotPolicyCacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = spcm.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) if err != nil { - return nil, errors.Wrap(err, "SResourceBaseManager.ListItemFilter") + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } + + q, err = spcm.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + + q, err = spcm.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + if snapshotpolicyIden := query.Snapshotpolicy; len(snapshotpolicyIden) > 0 { snapshotpolicy, err := SnapshotPolicyManager.FetchByIdOrName(userCred, snapshotpolicyIden) if err != nil { @@ -91,6 +113,49 @@ func (spcm *SSnapshotPolicyCacheManager) ListItemFilter(ctx context.Context, q * return q, nil } +func (spcm *SSnapshotPolicyCacheManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SnapshotPolicyCacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = spcm.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = spcm.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = spcm.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (spcm *SSnapshotPolicyCacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = spcm.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = spcm.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = spcm.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (spc *SSnapshotPolicyCache) GetIRegion() (cloudprovider.ICloudRegion, error) { provider, err := spc.GetDriver() if err != nil { @@ -111,18 +176,38 @@ func (spc *SSnapshotPolicyCache) GetSnapshotPolicy() (*SSnapshotPolicy, error) { return model.(*SSnapshotPolicy), nil } -func (spc *SSnapshotPolicyCache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (api.SnapshotPolicyCacheDetails, error) { - var err error - out := api.SnapshotPolicyCacheDetails{} - out.StandaloneResourceDetails, err = spc.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (spcm *SSnapshotPolicyCacheManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SnapshotPolicyCacheDetails { + rows := make([]api.SnapshotPolicyCacheDetails, len(objs)) + + stdRows := spcm.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := spcm.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := spcm.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SnapshotPolicyCacheDetails{ + StatusStandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regionRows[i], + } } - provider := spc.GetCloudprovider() - region := spc.GetRegion() - out.CloudproviderInfo = MakeCloudProviderInfo(region, nil, provider) - return out, nil + + return rows +} + +func (spc *SSnapshotPolicyCache) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SnapshotPolicyCacheDetails, error) { + return api.SnapshotPolicyCacheDetails{}, nil } // =============================================== detach and delete =================================================== @@ -161,10 +246,10 @@ func (spcm *SSnapshotPolicyCacheManager) NewCache(ctx context.Context, userCred snapshotPolicyCache.Status = api.SNAPSHOT_POLICY_CACHE_STATUS_READY // should have lock - if err := spcm.TableSpec().Insert(&snapshotPolicyCache); err != nil { + if err := spcm.TableSpec().Insert(snapshotPolicyCache); err != nil { return nil, errors.Wrapf(err, "insert snapshotpolicycache failed") } - return &snapshotPolicyCache, nil + return snapshotPolicyCache, nil } func (spcm *SSnapshotPolicyCacheManager) NewCacheWithExternalId(ctx context.Context, userCred mcclient.TokenCredential, @@ -176,10 +261,10 @@ func (spcm *SSnapshotPolicyCacheManager) NewCacheWithExternalId(ctx context.Cont snapshotPolicyCache.Status = api.SNAPSHOT_POLICY_CACHE_STATUS_READY snapshotPolicyCache.Name = name // should have lock - if err := spcm.TableSpec().Insert(&snapshotPolicyCache); err != nil { + if err := spcm.TableSpec().Insert(snapshotPolicyCache); err != nil { return nil, errors.Wrapf(err, "insert snapshotpolicycache failed") } - return &snapshotPolicyCache, nil + return snapshotPolicyCache, nil } func (spcm *SSnapshotPolicyCacheManager) Register(ctx context.Context, userCred mcclient.TokenCredential, snapshotPolicyId, diff --git a/pkg/compute/models/snapshotpolicydisks.go b/pkg/compute/models/snapshotpolicydisks.go index 89c5cd1f17..fae8d60aed 100644 --- a/pkg/compute/models/snapshotpolicydisks.go +++ b/pkg/compute/models/snapshotpolicydisks.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSnapshotPolicyDiskManager struct { @@ -95,20 +96,60 @@ func (sd *SSnapshotPolicyDisk) SetStatus(userCred mcclient.TokenCredential, stat return nil } -func (self *SSnapshotPolicyDisk) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (compute.SnapshotPolicyDiskDetails, error) { - var err error - out := compute.SnapshotPolicyDiskDetails{} - out.ModelBaseDetails, err = self.SVirtualJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SSnapshotPolicyDisk) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (compute.SnapshotPolicyDiskDetails, error) { + return compute.SnapshotPolicyDiskDetails{}, nil +} + +func (manager *SSnapshotPolicyDiskManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []compute.SnapshotPolicyDiskDetails { + rows := make([]compute.SnapshotPolicyDiskDetails, len(objs)) + + virtRows := manager.SVirtualJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + snapIds := make([]string, len(rows)) + diskIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = compute.SnapshotPolicyDiskDetails{ + VirtualJointResourceBaseDetails: virtRows[i], + } + snapIds[i] = objs[i].(*SSnapshotPolicyDisk).SnapshotpolicyId + diskIds[i] = objs[i].(*SSnapshotPolicyDisk).DiskId } - _, out.Snapshotpolicy = db.JointModelExtra(self) - disk := DiskManager.FetchDiskById(self.DiskId) - out.Disk, err = disk.GetExtraDetails(ctx, userCred, query, isList) + + snapIdMaps, err := db.FetchIdNameMap2(SnapshotPolicyManager, snapIds) if err != nil { - return out, nil + log.Errorf("FetchIdNameMap2 fail for snapshot Ids %s", err) + return rows } - return out, nil + + disks := make(map[string]SDisk) + err = db.FetchStandaloneObjectsByIds(DiskManager, diskIds, &disks) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds for disks fail %s", err) + return rows + } + + for i := range rows { + if name, ok := snapIdMaps[snapIds[i]]; ok { + rows[i].Snapshotpolicy = name + } + if disk, ok := disks[diskIds[i]]; ok { + rows[i].Disk, _ = disk.GetExtraDetails(ctx, userCred, query, isList) + } + } + + return rows } // ==================================================== fetch ========================================================== diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index b79215c585..4e0712418e 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -38,10 +38,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SSnapshotManager struct { db.SVirtualResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager } type SSnapshot struct { @@ -49,12 +52,14 @@ type SSnapshot struct { db.SExternalizedResourceBase SManagedResourceBase + SCloudregionResourceBase // 磁盘Id DiskId string `width:"36" charset:"ascii" nullable:"true" create:"required" list:"user" index:"true"` // Only onecloud has StorageId StorageId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"optional"` + CreatedBy string `width:"36" charset:"ascii" nullable:"false" default:"manual" list:"user" create:"optional"` Location string `charset:"ascii" nullable:"true" list:"admin" create:"optional"` // 快照大小,单位Mb @@ -69,7 +74,8 @@ type SSnapshot struct { RefCount int `nullable:"false" default:"0" list:"user"` // 区域Id - CloudregionId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + // CloudregionId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + BackingDiskId string `width:"36" charset:"ascii" nullable:"true" default:""` ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"` } @@ -93,18 +99,29 @@ func (self *SSnapshotManager) AllowListItems(ctx context.Context, userCred mccli } // 快照列表 -func (manager *SSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.SnapshotListInput) (*sqlchemy.SQuery, error) { +func (manager *SSnapshotManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SnapshotListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + if query.FakeDeleted != nil && *query.FakeDeleted { q = q.IsTrue("fake_deleted") } else { @@ -142,14 +159,86 @@ func (manager *SSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy return q, nil } -func (self *SSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.SnapshotDetails, error) { +func (manager *SSnapshotManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.SnapshotListInput, +) (*sqlchemy.SQuery, error) { var err error - out := api.SnapshotDetails{} - out.VirtualResourceDetails, err = self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) + + q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput) if err != nil { - return out, err + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields") } - return self.getMoreDetails(out), nil + + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SSnapshotManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (manager *SSnapshotManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.SnapshotDetails { + rows := make([]api.SnapshotDetails, len(objs)) + + virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.SnapshotDetails{ + VirtualResourceDetails: virtRows[i], + ManagedResourceInfo: manRows[i], + CloudregionResourceInfo: regionRows[i], + } + rows[i] = objs[i].(*SSnapshot).getMoreDetails(rows[i]) + } + + return rows +} + +func (self *SSnapshot) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.SnapshotDetails, error) { + return api.SnapshotDetails{}, nil } func (self *SSnapshot) getMoreDetails(out api.SnapshotDetails) api.SnapshotDetails { @@ -172,7 +261,6 @@ func (self *SSnapshot) getMoreDetails(out api.SnapshotDetails) api.SnapshotDetai out.IsSubSnapshot = true } - out.CloudproviderInfo = self.getCloudProviderInfo() return out } @@ -841,7 +929,7 @@ func (self *SSnapshot) PerformPurge(ctx context.Context, userCred mcclient.Token } provider := self.GetCloudprovider() if provider != nil { - if provider.Enabled { + if provider.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge snapshot on enabled cloud provider") } } @@ -849,7 +937,7 @@ func (self *SSnapshot) PerformPurge(ctx context.Context, userCred mcclient.Token return nil, err } -func (self *SSnapshot) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SSnapshot) getCloudProviderInfo() SCloudProviderInfo { region := self.GetRegion() provider := self.GetCloudprovider() return MakeCloudProviderInfo(region, nil, provider) diff --git a/pkg/compute/models/storagecachedimages.go b/pkg/compute/models/storagecachedimages.go index fb0bbbf4c5..725857f0f5 100644 --- a/pkg/compute/models/storagecachedimages.go +++ b/pkg/compute/models/storagecachedimages.go @@ -35,6 +35,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SStoragecachedimageManager struct { @@ -145,17 +146,37 @@ func (self *SStoragecachedimage) GetHost() (*SHost, error) { return sc.GetHost() } -func (self *SStoragecachedimage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.StoragecachedimageDetails, error) { - var err error +func (self *SStoragecachedimage) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.StoragecachedimageDetails, error) { out := api.StoragecachedimageDetails{} - out.ModelBaseDetails, err = self.SJointResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - out.Storagecache, out.Cachedimage = db.JointModelExtra(self) return self.getExtraDetails(ctx, out), nil } +func (manager *SStoragecachedimageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.StoragecachedimageDetails { + rows := make([]api.StoragecachedimageDetails, len(objs)) + + jointRows := manager.SJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.StoragecachedimageDetails{ + JointResourceBaseDetails: jointRows[i], + } + } + + return rows +} + func (manager *SStoragecachedimageManager) AllowListDescendent(ctx context.Context, userCred mcclient.TokenCredential, model db.IStandaloneModel, query jsonutils.JSONObject) bool { return db.IsAdminAllowList(userCred, manager) } @@ -179,6 +200,7 @@ func (self *SStoragecachedimage) GetStoragecache() (*SStoragecache, error) { func (self *SStoragecachedimage) getExtraDetails(ctx context.Context, out api.StoragecachedimageDetails) api.StoragecachedimageDetails { storagecache, _ := self.GetStoragecache() if storagecache != nil { + out.Storagecache = storagecache.Name out.Storages = storagecache.getStorageNames() host, _ := storagecache.GetHost() if host != nil { @@ -187,6 +209,7 @@ func (self *SStoragecachedimage) getExtraDetails(ctx context.Context, out api.St } cachedImage := self.GetCachedimage() if cachedImage != nil { + out.Cachedimage = cachedImage.Name out.Image = cachedImage.GetName() out.Size = cachedImage.Size } diff --git a/pkg/compute/models/storagecaches.go b/pkg/compute/models/storagecaches.go index 97f39f4d34..a89beb3ba7 100644 --- a/pkg/compute/models/storagecaches.go +++ b/pkg/compute/models/storagecaches.go @@ -35,10 +35,12 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SStoragecacheManager struct { db.SStandaloneResourceBaseManager + SManagedResourceBaseManager } var StoragecacheManager *SStoragecacheManager @@ -65,26 +67,6 @@ type SStoragecache struct { Path string `width:"256" charset:"utf8" nullable:"true" list:"user" update:"admin" create:"admin_optional"` // = Column(VARCHAR(256, charset='utf8'), nullable=True) } -func (self *SStoragecacheManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SStoragecacheManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SStoragecache) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SStoragecache) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SStoragecache) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SStoragecache) getStorages() []SStorage { storages := make([]SStorage, 0) q := StorageManager.Query().Equals("storagecache_id", self.Id) @@ -254,14 +236,49 @@ func (self *SStoragecache) syncWithCloudStoragecache(ctx context.Context, userCr return nil } -func (self *SStoragecache) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.StoragecacheDetails, error) { - var err error - out := api.StoragecacheDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SStoragecacheManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.StoragecacheDetails { + rows := make([]api.StoragecacheDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.StoragecacheDetails{ + StandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: manRows[i], + } + rows[i] = objs[i].(*SStoragecache).getMoreDetails(ctx, rows[i]) } - return self.getMoreDetails(ctx, out), nil + + return rows +} + +func (self *SStoragecache) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.StoragecacheDetails, error) { + return api.StoragecacheDetails{}, nil +} + +func (self *SStoragecache) getMoreDetails(ctx context.Context, out api.StoragecacheDetails) api.StoragecacheDetails { + out.Storages = self.getStorageNames() + out.Size = self.getCachedImageSize() + out.Count = self.getCachedImageCount() + + host, _ := self.GetHost() + if host != nil { + out.Host = host.GetShortDesc(ctx) + } + return out } func (self *SStoragecache) getCachedImageList(excludeIds []string, imageType string, status []string) []SCachedimage { @@ -325,18 +342,6 @@ func (self *SStoragecache) getCachedImageSize() int64 { return size } -func (self *SStoragecache) getMoreDetails(ctx context.Context, out api.StoragecacheDetails) api.StoragecacheDetails { - out.Storages = self.getStorageNames() - out.Size = self.getCachedImageSize() - out.Count = self.getCachedImageCount() - - host, _ := self.GetHost() - if host != nil { - out.Host = host.GetShortDesc(ctx) - } - return out -} - func (self *SStoragecache) StartImageCacheTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, format string, isForce bool, parentTaskId string) error { StoragecachedimageManager.Register(ctx, userCred, self.Id, imageId, "") data := jsonutils.NewDict() @@ -400,26 +405,64 @@ func (self *SStoragecache) GetIStorageCache() (cloudprovider.ICloudStoragecache, } // 镜像缓存存储列表 -func (manager *SStoragecacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.StoragecacheListInput) (*sqlchemy.SQuery, error) { +func (manager *SStoragecacheManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StoragecacheListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") - } - - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") - } q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + return q, nil } +func (manager *SStoragecacheManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StoragecacheListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SStoragecacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (manager *SStoragecacheManager) FetchStoragecacheById(storageCacheId string) *SStoragecache { iStorageCache, _ := manager.FetchById(storageCacheId) if iStorageCache == nil { diff --git a/pkg/compute/models/storageresource.go b/pkg/compute/models/storageresource.go new file mode 100644 index 0000000000..4bb32db822 --- /dev/null +++ b/pkg/compute/models/storageresource.go @@ -0,0 +1,226 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SStorageResourceBase struct { + StorageId string `width:"36" charset:"ascii" nullable:"true" list:"user" index:"true" create:"optional"` +} + +type SStorageResourceBaseManager struct { + SZoneResourceBaseManager + SManagedResourceBaseManager +} + +func (self *SStorageResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.StorageResourceInfo { + return api.StorageResourceInfo{} +} + +func (manager *SStorageResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.StorageResourceInfo { + rows := make([]api.StorageResourceInfo, len(objs)) + storageIds := make([]string, len(objs)) + for i := range objs { + var base *SStorageResourceBase + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil { + storageIds[i] = base.StorageId + } + } + + storages := make(map[string]SStorage) + err := db.FetchStandaloneObjectsByIds(StorageManager, storageIds, storages) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + + zoneList := make([]interface{}, len(rows)) + managerList := make([]interface{}, len(rows)) + + for i := range rows { + rows[i] = api.StorageResourceInfo{} + if _, ok := storages[storageIds[i]]; ok { + storage := storages[storageIds[i]] + rows[i].Storage = storage.Name + rows[i].StorageStatus = storage.Status + rows[i].StorageType = storage.StorageType + rows[i].MediumType = storage.MediumType + rows[i].ManagerId = storage.ManagerId + rows[i].ZoneId = storage.ZoneId + } + zoneList[i] = &SZoneResourceBase{rows[i].ZoneId} + managerList[i] = &SManagedResourceBase{rows[i].ManagerId} + } + + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList) + for i := range rows { + rows[i].ZoneResourceInfo = zoneRows[i] + rows[i].ManagedResourceInfo = managerRows[i] + } + + return rows +} + +func (manager *SStorageResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StorageFilterListInput, +) (*sqlchemy.SQuery, error) { + if len(query.Storage) > 0 { + storageObj, err := StorageManager.FetchByIdOrName(userCred, query.Storage) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(StorageManager.Keyword(), query.Storage) + } else { + return nil, errors.Wrap(err, "StorageManager.FetchByIdOrName") + } + } + q = q.Equals("storage_id", storageObj.GetId()) + } + subq := StorageManager.Query("id").Snapshot() + subq, err := manager.SZoneResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + subq, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + if query.Share != nil && *query.Share { + subq = subq.Filter(sqlchemy.NotIn(subq.Field("storage_type"), api.STORAGE_LOCAL_TYPES)) + } + if query.Local != nil && *query.Local { + subq = subq.Filter(sqlchemy.In(subq.Field("storage_type"), api.STORAGE_LOCAL_TYPES)) + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("storage_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SStorageResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "storage": + storages := StorageManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(storages.Field("name", field)) + q = q.Join(storages, sqlchemy.Equals(q.Field("storage_id"), storages.Field("id"))) + q.GroupBy(storages.Field("name")) + return q, nil + case "storage_type", "medium_type": + storages := StorageManager.Query(field, "id").Distinct().SubQuery() + q.AppendField(storages.Field(field)) + q = q.Join(storages, sqlchemy.Equals(q.Field("storage_id"), storages.Field("id"))) + q.GroupBy(storages.Field(field)) + return q, nil + case "manager", "account", "provider", "brand": + storages := StorageManager.Query("id", "manager_id").SubQuery() + q = q.LeftJoin(storages, sqlchemy.Equals(q.Field("storage_id"), storages.Field("id"))) + return manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + default: + storages := StorageManager.Query("id", "zone_id").SubQuery() + q = q.LeftJoin(storages, sqlchemy.Equals(q.Field("storage_id"), storages.Field("id"))) + q, err := manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SStorageResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StorageFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SStorageResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StorageFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + storageQ := StorageManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + storageQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(storageQ, userCred, query.ZonalFilterListInput) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + if db.NeedOrderQuery(manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput)) { + var manOrders []string + var manFields []sqlchemy.IQueryField + storageQ, manOrders, manFields = manager.SManagedResourceBaseManager.GetOrderBySubQuery(storageQ, userCred, query.ManagedResourceListInput) + if len(manOrders) > 0 { + orders = append(orders, manOrders...) + fields = append(fields, manFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := storageQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("storage_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByStorage}) { + orders = append(orders, query.OrderByStorage) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SStorageResourceBaseManager) GetOrderByFields(query api.StorageFilterListInput) []string { + fields := make([]string, 0) + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(query.ZonalFilterListInput) + fields = append(fields, zoneFields...) + managerFields := manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput) + fields = append(fields, managerFields...) + fields = append(fields, query.OrderByStorage) + return fields +} diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 4a7bdcfeaf..8e509e0d79 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -28,6 +28,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -38,17 +39,20 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SStorageManager struct { - db.SStandaloneResourceBaseManager + db.SEnabledStatusStandaloneResourceBaseManager + SManagedResourceBaseManager + SZoneResourceBaseManager } var StorageManager *SStorageManager func init() { StorageManager = &SStorageManager{ - SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager( + SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager( SStorage{}, "storages_tbl", "storage", @@ -59,10 +63,11 @@ func init() { } type SStorage struct { - db.SStandaloneResourceBase + db.SEnabledStatusStandaloneResourceBase db.SExternalizedResourceBase SManagedResourceBase + SZoneResourceBase // 容量大小,单位Mb Capacity int64 `nullable:"false" list:"admin" update:"admin" create:"admin_required"` @@ -79,16 +84,13 @@ type SStorage struct { // 存储配置信息 StorageConf jsonutils.JSONObject `nullable:"true" get:"admin" update:"admin"` - // 可用区Id - ZoneId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"admin_required"` - // 存储缓存Id StoragecacheId string `width:"36" charset:"ascii" nullable:"true" list:"admin" get:"admin" update:"admin" create:"optional"` // 是否启用 - Enabled tristate.TriState `nullable:"false" default:"true" list:"user" create:"optional"` + // Enabled tristate.TriState `nullable:"false" default:"true" list:"user" create:"optional"` // 状态 - Status string `width:"36" charset:"ascii" nullable:"false" default:"offline" update:"admin" list:"user" create:"optional"` + // Status string `width:"36" charset:"ascii" nullable:"false" default:"offline" update:"admin" list:"user" create:"optional"` // indicating whether system disk can be allocated in this storage // 是否可以用作系统盘存储 @@ -128,7 +130,7 @@ func (self *SStorage) ValidateUpdateData(ctx context.Context, userCred mcclient. } func (self *SStorage) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) { - self.SStandaloneResourceBase.PostUpdate(ctx, userCred, query, data) + self.SEnabledStatusStandaloneResourceBase.PostUpdate(ctx, userCred, query, data) if data.Contains("cmtbound") || data.Contains("capacity") { hosts := self.GetAttachedHosts() @@ -159,7 +161,7 @@ func (self *SStorage) AllowDeleteItem(ctx context.Context, userCred mcclient.Tok func (self *SStorage) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { DeleteResourceJointSchedtags(self, ctx, userCred) - return self.SStandaloneResourceBase.Delete(ctx, userCred) + return self.SEnabledStatusStandaloneResourceBase.Delete(ctx, userCred) } func (manager *SStorageManager) GetStorageTypesByHostType(hostType string) ([]string, error) { @@ -215,7 +217,7 @@ func (manager *SStorageManager) ValidateCreateData(ctx context.Context, userCred return nil, err } - input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput) + input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput) if err != nil { return nil, err } @@ -244,11 +246,11 @@ func (self *SStorage) ValidateDeleteCondition(ctx context.Context) error { if cnt > 0 { return httperrors.NewNotEmptyError("storage has snapshots") } - return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx) + return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx) } func (self *SStorage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { - self.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) + self.SEnabledStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) storageDriver := GetStorageDriver(self.StorageType) if storageDriver != nil { @@ -409,20 +411,36 @@ func (self *SStorage) getMoreDetails(ctx context.Context, out api.StorageDetails out.FreeCapacity = capa.GetFree() out.CommitBound = self.GetOvercommitBound() - out.CloudproviderInfo = self.getCloudProviderInfo() out.Schedtags = GetSchedtagsDetailsToResourceV2(self, ctx) return out } func (self *SStorage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.StorageDetails, error) { - var err error - out := api.StorageDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.StorageDetails{}, nil +} + +func (manager *SStorageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.StorageDetails { + rows := make([]api.StorageDetails, len(objs)) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + manageRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.StorageDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + ZoneResourceInfo: zoneRows[i], + ManagedResourceInfo: manageRows[i], + } + rows[i] = objs[i].(*SStorage).getMoreDetails(ctx, rows[i]) } - return self.getMoreDetails(ctx, out), nil + return rows } func (self *SStorage) GetUsedCapacity(isReady tristate.TriState) int64 { @@ -948,7 +966,7 @@ func (self *SStorage) createDisk(name string, diskConfig *api.DiskConfig, userCr disk.StorageId = self.Id disk.AutoDelete = autoDelete disk.ProjectId = ownerId.GetProjectId() - disk.ProjectSrc = string(db.PROJECT_SOURCE_LOCAL) + disk.ProjectSrc = string(apis.OWNER_SOURCE_LOCAL) disk.DomainId = ownerId.GetProjectDomainId() disk.IsSystem = isSystem @@ -1127,33 +1145,27 @@ func (manager *SStorageManager) IsStorageTypeExist(storageType string) (string, } // 块存储列表 -func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.StorageListInput) (*sqlchemy.SQuery, error) { +func (manager *SStorageManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StorageListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } - q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) if err != nil { - return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") - } - - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "zone_id", func() *sqlchemy.SQuery { - return ZoneManager.Query("id") - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter") } if query.Share != nil && *query.Share { @@ -1193,6 +1205,46 @@ func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy. return q, err } +func (manager *SStorageManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.StorageListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SStorageManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SStorage) ClearSchedDescCache() error { hosts := self.GetAllAttachingHosts() if hosts == nil { @@ -1210,7 +1262,7 @@ func (self *SStorage) ClearSchedDescCache() error { return nil } -func (self *SStorage) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SStorage) getCloudProviderInfo() SCloudProviderInfo { var region *SCloudregion zone := self.getZone() if zone != nil { diff --git a/pkg/compute/models/storageschedtags.go b/pkg/compute/models/storageschedtags.go index e06a6708a4..5c3f2b9ca8 100644 --- a/pkg/compute/models/storageschedtags.go +++ b/pkg/compute/models/storageschedtags.go @@ -18,10 +18,12 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SStorageschedtagManager struct { @@ -70,12 +72,47 @@ func (joint *SStorageschedtag) Master() db.IStandaloneModel { return joint.SSchedtagJointsBase.master(joint) } -func (joint *SStorageschedtag) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.StorageschedtagDetails, error) { - var err error - out := api.StorageschedtagDetails{} - out.JoinModelBaseDetails, err = joint.SSchedtagJointsBase.getExtraDetails(joint, ctx, userCred, query, isList) - out.Storage, out.Schedtag = db.JointModelExtra(joint) - return out, err +func (joint *SStorageschedtag) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.StorageschedtagDetails, error) { + return api.StorageschedtagDetails{}, nil +} + +func (manager *SStorageschedtagManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.StorageschedtagDetails { + rows := make([]api.StorageschedtagDetails, len(objs)) + + schedRows := manager.SSchedtagJointsManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + storageIds := make([]string, len(rows)) + for i := range rows { + rows[i] = api.StorageschedtagDetails{ + SchedtagJointResourceDetails: schedRows[i], + } + storageIds[i] = objs[i].(*SStorageschedtag).StorageId + } + + storageIdMaps, err := db.FetchIdNameMap2(StorageManager, storageIds) + if err != nil { + log.Errorf("FetchIdNameMap2 hostIds fail %s", err) + return rows + } + + for i := range rows { + if name, ok := storageIdMaps[storageIds[i]]; ok { + rows[i].Storage = name + } + } + + return rows } func (joint *SStorageschedtag) Delete(ctx context.Context, userCred mcclient.TokenCredential) error { diff --git a/pkg/compute/models/vpcresource.go b/pkg/compute/models/vpcresource.go new file mode 100644 index 0000000000..c31d268d43 --- /dev/null +++ b/pkg/compute/models/vpcresource.go @@ -0,0 +1,268 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SVpcResourceBase struct { + VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"vpc_id"` +} + +type SVpcResourceBaseManager struct { + SCloudregionResourceBaseManager + SManagedResourceBaseManager +} + +func (self *SVpcResourceBase) GetVpc() *SVpc { + obj, _ := VpcManager.FetchById(self.VpcId) + if obj == nil { + return nil + } + return obj.(*SVpc) +} + +func (self *SVpcResourceBase) GetRegion() *SCloudregion { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + region, _ := vpc.GetRegion() + return region +} + +func (self *SVpcResourceBase) GetRegionId() string { + region := self.GetRegion() + if region != nil { + return region.Id + } + return "" +} + +func (self *SVpcResourceBase) GetIRegion() (cloudprovider.ICloudRegion, error) { + vpc := self.GetVpc() + if vpc != nil { + return vpc.GetIRegion() + } + return nil, errors.Wrap(httperrors.ErrBadRequest, "not a valid vpc") +} + +func (self *SVpcResourceBase) GetCloudprovider() *SCloudprovider { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + return vpc.GetCloudprovider() +} + +func (self *SVpcResourceBase) GetCloudproviderId() string { + cloudprovider := self.GetCloudprovider() + if cloudprovider != nil { + return cloudprovider.Id + } + return "" +} + +func (self *SVpcResourceBase) GetProviderName() string { + vpc := self.GetVpc() + if vpc == nil { + return "" + } + return vpc.GetProviderName() +} + +func (self *SVpcResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.VpcResourceInfo { + return api.VpcResourceInfo{} +} + +func (manager *SVpcResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.VpcResourceInfo { + rows := make([]api.VpcResourceInfo, len(objs)) + vpcIds := make([]string, len(objs)) + for i := range objs { + var base *SVpcResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + vpcIds[i] = base.VpcId + } + + vpcs := make(map[string]SVpc) + err := db.FetchStandaloneObjectsByIds(VpcManager, vpcIds, vpcs) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + + regionList := make([]interface{}, len(rows)) + managerList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.VpcResourceInfo{} + if _, ok := vpcs[vpcIds[i]]; ok { + vpc := vpcs[vpcIds[i]] + rows[i].Vpc = vpc.Name + rows[i].VpcExtId = vpc.ExternalId + rows[i].CloudregionId = vpc.CloudregionId + rows[i].ManagerId = vpc.ManagerId + } + regionList[i] = &SCloudregionResourceBase{rows[i].CloudregionId} + managerList[i] = &SManagedResourceBase{rows[i].ManagerId} + } + + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, regionList, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, managerList, fields, isList) + for i := range rows { + rows[i].CloudregionResourceInfo = regionRows[i] + rows[i].ManagedResourceInfo = managerRows[i] + } + + return rows +} + +func (manager *SVpcResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.VpcFilterListInput, +) (*sqlchemy.SQuery, error) { + var err error + if len(query.Vpc) > 0 { + vpcObj, err := VpcManager.FetchByIdOrName(userCred, query.Vpc) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(VpcManager.Keyword(), query.Vpc) + } else { + return nil, errors.Wrap(err, "VpcManager.FetchByIdOrName") + } + } + q = q.Equals("vpc_id", vpcObj.GetId()) + } + subq := VpcManager.Query("id").Snapshot() + subq, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + subq, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("vpc_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SVpcResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "vpc": + vpcQuery := VpcManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(vpcQuery.Field("name", field)) + q = q.Join(vpcQuery, sqlchemy.Equals(q.Field("vpc_id"), vpcQuery.Field("id"))) + q.GroupBy(vpcQuery.Field("name")) + return q, nil + case "region": + vpcs := VpcManager.Query("id", "cloudregion_id").SubQuery() + q = q.LeftJoin(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id"))) + return manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + case "manager", "account", "provider", "brand": + vpcs := VpcManager.Query("id", "manager_id").SubQuery() + q = q.LeftJoin(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id"))) + return manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + } + return q, httperrors.ErrNotFound +} + +func (manager *SVpcResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.VpcFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SVpcResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.VpcFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + vpcQ := VpcManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + if db.NeedOrderQuery(manager.SCloudregionResourceBaseManager.GetOrderByFields(query.RegionalFilterListInput)) { + var regionOrders []string + var regionFields []sqlchemy.IQueryField + vpcQ, regionOrders, regionFields = manager.SCloudregionResourceBaseManager.GetOrderBySubQuery(vpcQ, userCred, query.RegionalFilterListInput) + if len(regionOrders) > 0 { + orders = append(orders, regionOrders...) + fields = append(fields, regionFields...) + } + } + if db.NeedOrderQuery(manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput)) { + var managerOrders []string + var managerFields []sqlchemy.IQueryField + vpcQ, managerOrders, managerFields = manager.SManagedResourceBaseManager.GetOrderBySubQuery(vpcQ, userCred, query.ManagedResourceListInput) + if len(managerOrders) > 0 { + orders = append(orders, managerOrders...) + fields = append(fields, managerFields...) + } + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := vpcQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("vpc_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByVpc}) { + orders = append(orders, query.OrderByVpc) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SVpcResourceBaseManager) GetOrderByFields(query api.VpcFilterListInput) []string { + fields := make([]string, 0) + regionFields := manager.SCloudregionResourceBaseManager.GetOrderByFields(query.RegionalFilterListInput) + fields = append(fields, regionFields...) + managerFields := manager.SManagedResourceBaseManager.GetOrderByFields(query.ManagedResourceListInput) + fields = append(fields, managerFields...) + fields = append(fields, query.OrderByVpc) + return fields +} diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index 408b6b2537..a9addf4452 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -35,10 +35,14 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SVpcManager struct { db.SEnabledStatusStandaloneResourceBaseManager + SManagedResourceBaseManager + SCloudregionResourceBaseManager + SGlobalVpcResourceBaseManager } var VpcManager *SVpcManager @@ -61,6 +65,10 @@ type SVpc struct { SManagedResourceBase + SCloudregionResourceBase + + SGlobalVpcResourceBase + // 是否是默认VPC // example: true IsDefault bool `default:"false" list:"admin" create:"admin_optional"` @@ -70,37 +78,19 @@ type SVpc struct { CidrBlock string `charset:"ascii" nullable:"true" list:"admin" create:"admin_required"` // 区域Id - CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"` + // CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"admin_required" default:"default"` + // 全局VPC Id - GlobalvpcId string `width:"36" charset:"ascii" list:"user"` + // GlobalvpcId string `width:"36" charset:"ascii" list:"user" json:"globalvpc_id"` } func (manager *SVpcManager) GetContextManagers() [][]db.IModelManager { return [][]db.IModelManager{ {CloudregionManager}, + {GlobalVpcManager}, } } -func (self *SVpcManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SVpcManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SVpc) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SVpc) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SVpc) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (self *SVpc) GetCloudRegionId() string { if len(self.CloudregionId) == 0 { return api.DEFAULT_REGION_ID @@ -152,7 +142,7 @@ func (self *SVpc) ValidateDeleteCondition(ctx context.Context) error { if self.Id == api.DEFAULT_VPC_ID { return httperrors.NewProtectedResourceError("not allow to delete default vpc") } - return self.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx) + return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx) } func (self *SVpc) getWireQuery() *sqlchemy.SQuery { @@ -197,14 +187,13 @@ func (manager *SVpcManager) NewVpcForClassicNetwork(host *SHost) (*SVpc, error) if errors.Cause(err) != sql.ErrNoRows { return nil, errors.Wrap(err, "db.FetchByExternalId") } - vpc := &SVpc{ - IsDefault: false, - CloudregionId: region.Id, - } + vpc := &SVpc{} + vpc.IsDefault = false + vpc.CloudregionId = region.Id vpc.SetModelManager(manager, vpc) vpc.Name = fmt.Sprintf("emulated vpc for %s %s classic network", region.Name, cloudprovider.Name) vpc.IsEmulated = true - vpc.Enabled = false + vpc.SetEnabled(false) vpc.Status = api.VPC_STATUS_UNAVAILABLE vpc.ExternalId = externalId vpc.ManagerId = host.ManagerId @@ -247,11 +236,10 @@ func (self *SVpc) getMoreDetails(out api.VpcDetails) api.VpcDetails { out.NetworkCount, _ = self.GetNetworkCount() out.RoutetableCount, _ = self.GetRouteTableCount() out.NatgatewayCount, _ = self.GetNatgatewayCount() - out.CloudproviderInfo = self.getCloudProviderInfo() return out } -func (self *SVpc) getCloudProviderInfo() api.CloudproviderInfo { +func (self *SVpc) getCloudProviderInfo() SCloudProviderInfo { region, _ := self.GetRegion() provider := self.GetCloudprovider() return MakeCloudProviderInfo(region, nil, provider) @@ -260,7 +248,7 @@ func (self *SVpc) getCloudProviderInfo() api.CloudproviderInfo { func (self *SVpc) GetRegion() (*SCloudregion, error) { region, err := CloudregionManager.FetchById(self.CloudregionId) if err != nil { - return nil, err + return nil, errors.Wrap(err, "CloudregionManager.FetchById") } return region.(*SCloudregion), nil } @@ -285,14 +273,38 @@ func (self *SVpc) getZoneByExternalId(externalId string) (*SZone, error) { return nil, fmt.Errorf("found %d duplicate zones by externalId %s in cloudregion %s(%s)", len(zones), externalId, region.Name, region.Id) } -func (self *SVpc) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.VpcDetails, error) { - var err error - out := api.VpcDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SVpc) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.VpcDetails, error) { + return api.VpcDetails{}, nil +} + +func (manager *SVpcManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.VpcDetails { + rows := make([]api.VpcDetails, len(objs)) + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + globalVpcRows := manager.SGlobalVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.VpcDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + ManagedResourceInfo: managerRows[i], + CloudregionResourceInfo: regionRows[i], + GlobalVpcResourceInfo: globalVpcRows[i], + } + rows[i] = objs[i].(*SVpc).getMoreDetails(rows[i]) } - return self.getMoreDetails(out), nil + return rows } func (manager *SVpcManager) getVpcsByRegion(region *SCloudregion, provider *SCloudprovider) ([]SVpc, error) { @@ -404,7 +416,7 @@ func (self *SVpc) syncRemoveCloudVpc(ctx context.Context, userCred mcclient.Toke err := self.ValidateDeleteCondition(ctx) if err != nil { // cannot delete self.markAllNetworksUnknown(userCred) - _, err = self.PerformDisable(ctx, userCred, nil, nil) + _, err = self.PerformDisable(ctx, userCred, nil, apis.PerformDisableInput{}) if err == nil { err = self.SetStatus(userCred, api.VPC_STATUS_UNKNOWN, "sync to delete") } @@ -451,7 +463,7 @@ func (self *SVpc) SyncGlobalVpc(ctx context.Context, userCred mcclient.TokenCred if err != nil { return errors.Wrap(err, "db.GenerateName") } - gv.Enabled = true + gv.SetEnabled(true) gv.Status = api.GLOBAL_VPC_STATUS_AVAILABLE gv.SetModelManager(GlobalVpcManager, gv) err = GlobalVpcManager.TableSpec().Insert(gv) @@ -768,7 +780,7 @@ func (self *SVpc) PerformPurge(ctx context.Context, userCred mcclient.TokenCrede } provider := self.GetCloudprovider() if provider != nil { - if provider.Enabled { + if provider.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge vpc on enabled cloud provider") } } @@ -777,21 +789,32 @@ func (self *SVpc) PerformPurge(ctx context.Context, userCred mcclient.TokenCrede } // 列出VPC -func (manager *SVpcManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.VpcListInput) (*sqlchemy.SQuery, error) { +func (manager *SVpcManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.VpcListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "", nil) + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "", nil) + q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter") } - q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput) + q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + + q, err = manager.SGlobalVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.GlobalVpcResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SGlobalVpcResourceBaseManager.ListItemFilter") } usable := (query.Usable != nil && *query.Usable) @@ -806,16 +829,15 @@ func (manager *SVpcManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQue sqlchemy.In(cloudproviders.Field("health_status"), api.CLOUD_PROVIDER_VALID_HEALTH_STATUS), ), ) - q = q.Join(regions, sqlchemy.Equals(q.Field("cloudregion_id"), regions.Field("id"))). - Filter( - sqlchemy.AND( - sqlchemy.Equals(regions.Field("status"), api.CLOUD_REGION_STATUS_INSERVER), - sqlchemy.OR( - sqlchemy.In(q.Field("manager_id"), providerSQ.SubQuery()), - sqlchemy.IsNullOrEmpty(q.Field("manager_id")), - ), + q = q.Join(regions, sqlchemy.Equals(q.Field("cloudregion_id"), regions.Field("id"))).Filter( + sqlchemy.AND( + sqlchemy.Equals(regions.Field("status"), api.CLOUD_REGION_STATUS_INSERVER), + sqlchemy.OR( + sqlchemy.In(q.Field("manager_id"), providerSQ.SubQuery()), + sqlchemy.IsNullOrEmpty(q.Field("manager_id")), ), - ) + ), + ) if usable { wires := WireManager.Query().SubQuery() @@ -829,22 +851,65 @@ func (manager *SVpcManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQue } } - globalVpcStr := query.Globalvpc - if len(globalVpcStr) > 0 { - globalVpc, err := GlobalVpcManager.FetchByIdOrName(userCred, globalVpcStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewResourceNotFoundError("globaalvpc %s not found", globalVpcStr) - } - return nil, httperrors.NewGeneralError(err) - } - q = q.Equals("globalvpc_id", globalVpc.GetId()) - } - return q, nil } func (manager *SVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "vpc": + q = q.AppendField(q.Field("name").Label("vpc")).Distinct() + return q, nil + default: + var err error + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + q, err = manager.SGlobalVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + } + return q, httperrors.ErrNotFound +} + +func (manager *SVpcManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.VpcListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SGlobalVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.GlobalVpcResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SGlobalVpcResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +/*func (manager *SVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { var err error q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) if err == nil { @@ -867,7 +932,7 @@ func (manager *SVpcManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field st return q, httperrors.NewBadRequestError("unsupport field %s", field) } return q, nil -} +}*/ func (self *SVpc) SyncRemoteWires(ctx context.Context, userCred mcclient.TokenCredential) error { ivpc, err := self.GetIVpc() @@ -913,24 +978,13 @@ func (vpc *SVpc) StartVpcSyncstatusTask(ctx context.Context, userCred mcclient.T return nil } -func (vpc *SVpc) GetGlobalVpc() (*SGlobalVpc, error) { - if len(vpc.GlobalvpcId) == 0 { - return nil, fmt.Errorf("vpc does not belong to any globalvpc") - } - gv, err := GlobalVpcManager.FetchById(vpc.GlobalvpcId) - if err != nil { - return nil, err - } - return gv.(*SGlobalVpc), nil -} - func (self *SVpc) initWire(ctx context.Context, zone *SZone) (*SWire, error) { wire := &SWire{ - VpcId: self.Id, - ZoneId: zone.Id, Bandwidth: 10000, Mtu: 1500, } + wire.VpcId = self.Id + wire.ZoneId = zone.Id wire.IsEmulated = true wire.Name = fmt.Sprintf("vpc-%s", self.Name) wire.SetModelManager(WireManager, wire) diff --git a/pkg/compute/models/wireresource.go b/pkg/compute/models/wireresource.go new file mode 100644 index 0000000000..d60b5af3ec --- /dev/null +++ b/pkg/compute/models/wireresource.go @@ -0,0 +1,263 @@ +// 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 models + +import ( + "context" + "database/sql" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" +) + +type SWireResourceBase struct { + // 二层网络ID + WireId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"wire_id"` +} + +type SWireResourceBaseManager struct { + SVpcResourceBaseManager + SZoneResourceBaseManager +} + +func (self *SWireResourceBase) GetWire() *SWire { + w, _ := WireManager.FetchById(self.WireId) + if w != nil { + return w.(*SWire) + } + return nil +} + +func (self *SWireResourceBase) GetVpc() *SVpc { + wire := self.GetWire() + if wire != nil { + return wire.GetVpc() + } + return nil +} + +func (self *SWireResourceBase) GetRegion() *SCloudregion { + vpc := self.GetVpc() + if vpc == nil { + return nil + } + region, _ := vpc.GetRegion() + return region +} + +func (self *SWireResourceBase) GetZone() *SZone { + wire := self.GetWire() + if wire != nil { + return wire.GetZone() + } + return nil +} + +func (self *SWireResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.WireResourceInfo { + return api.WireResourceInfo{} +} + +func (manager *SWireResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.WireResourceInfo { + rows := make([]api.WireResourceInfo, len(objs)) + + wireIds := make([]string, len(objs)) + for i := range objs { + var base *SWireResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + wireIds[i] = base.WireId + } + + wires := make(map[string]SWire) + err := db.FetchStandaloneObjectsByIds(WireManager, wireIds, &wires) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return nil + } + + vpcList := make([]interface{}, len(rows)) + zoneList := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.WireResourceInfo{} + if _, ok := wires[wireIds[i]]; ok { + wire := wires[wireIds[i]] + rows[i].Wire = wire.Name + rows[i].VpcId = wire.VpcId + rows[i].ZoneId = wire.ZoneId + } + vpcList[i] = &SVpcResourceBase{rows[i].VpcId} + zoneList[i] = &SZoneResourceBase{rows[i].ZoneId} + } + + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcList, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, zoneList, fields, isList) + + for i := range rows { + rows[i].VpcResourceInfo = vpcRows[i] + rows[i].Zone = zoneRows[i].Zone + } + return rows +} + +func (manager *SWireResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.WireFilterListInput, +) (*sqlchemy.SQuery, error) { + var err error + if len(query.Wire) > 0 { + wireObj, err := WireManager.FetchByIdOrName(userCred, query.Wire) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), query.Wire) + } else { + return nil, errors.Wrap(err, "WireManager.FetchByIdOrName") + } + } + q = q.Equals("wire_id", wireObj.GetId()) + } + + wireQ := WireManager.Query("id").Snapshot() + + wireQ, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, wireQ, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") + } + + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + wireQ, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, wireQ, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") + } + + if wireQ.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("wire_id"), wireQ.SubQuery())) + } + return q, nil +} + +func (manager *SWireResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + if field == "wire" { + wireQuery := WireManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(wireQuery.Field("name", field)) + q = q.Join(wireQuery, sqlchemy.Equals(q.Field("wire_id"), wireQuery.Field("id"))) + q.GroupBy(wireQuery.Field("name")) + return q, nil + } else { + wires := WireManager.Query("id", "zone_id", "vpc_id").SubQuery() + q = q.LeftJoin(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id"))) + if field == "zone" { + return manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + } else { + q, err := manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } else { + return q, httperrors.ErrNotFound + } + } + } +} + +func (manager *SWireResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.WireFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SWireResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.WireFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + wireQ := WireManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + if db.NeedOrderQuery(manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery)) { + var zoneOrders []string + var zoneFields []sqlchemy.IQueryField + wireQ, zoneOrders, zoneFields = manager.SZoneResourceBaseManager.GetOrderBySubQuery(wireQ, userCred, zoneQuery) + if len(zoneOrders) > 0 { + orders = append(orders, zoneOrders...) + fields = append(fields, zoneFields...) + } + } + + if db.NeedOrderQuery(manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput)) { + var vpcOrders []string + var vpcFields []sqlchemy.IQueryField + wireQ, vpcOrders, vpcFields = manager.SVpcResourceBaseManager.GetOrderBySubQuery(wireQ, userCred, query.VpcFilterListInput) + if len(vpcOrders) > 0 { + orders = append(orders, vpcOrders...) + fields = append(fields, vpcFields...) + } + } + + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := wireQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("wire_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByWire}) { + orders = append(orders, query.OrderByWire) + fields = append(fields, subq.Field("name")) + } + } + + return q, orders, fields +} + +func (manager *SWireResourceBaseManager) GetOrderByFields(query api.WireFilterListInput) []string { + fields := make([]string, 0) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + zoneFields := manager.SZoneResourceBaseManager.GetOrderByFields(zoneQuery) + fields = append(fields, zoneFields...) + vpcFields := manager.SVpcResourceBaseManager.GetOrderByFields(query.VpcFilterListInput) + fields = append(fields, vpcFields...) + fields = append(fields, query.OrderByWire) + return fields +} diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 409b9f2cf3..8dc6d6eb28 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -37,10 +37,13 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SWireManager struct { db.SStandaloneResourceBaseManager + SVpcResourceBaseManager + SZoneResourceBaseManager } var WireManager *SWireManager @@ -61,18 +64,22 @@ type SWire struct { db.SStandaloneResourceBase db.SExternalizedResourceBase + SVpcResourceBase + SZoneResourceBase + // 带宽大小, 单位Mbps // example: 1000 - Bandwidth int `list:"admin" update:"admin" nullable:"false" create:"admin_required"` + Bandwidth int `list:"admin" update:"admin" nullable:"false" create:"admin_required" json:"bandwidth"` // MTU // example: 1500 - Mtu int `list:"admin" update:"admin" nullable:"false" create:"admin_optional" default:"1500"` + Mtu int `list:"admin" update:"admin" nullable:"false" create:"admin_optional" default:"1500" json:"mtu"` // swagger:ignore - ScheduleRank int `list:"admin" update:"admin"` + ScheduleRank int `list:"admin" update:"admin" json:"schedule_rank"` + // 可用区Id - ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"admin_required"` + // ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"admin_required"` // VPC Id - VpcId string `wdith:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"` + // VpcId string `wdith:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"` } func (manager *SWireManager) GetContextManagers() [][]db.IModelManager { @@ -82,26 +89,6 @@ func (manager *SWireManager) GetContextManagers() [][]db.IModelManager { } } -func (self *SWireManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowList(userCred, self) -} - -func (self *SWireManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SWire) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SWire) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SWire) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (manager *SWireManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.WireCreateInput) (*jsonutils.JSONDict, error) { if input.Bandwidth < 0 { return nil, httperrors.NewOutOfRangeError("bandwidth must be greater than 0") @@ -223,10 +210,9 @@ func (manager *SWireManager) NewWireForClassicNetwork(vpc *SVpc, zone *SZone) (* if errors.Cause(err) != sql.ErrNoRows { return nil, errors.Wrap(err, "db.FetchByExternalId") } - wire := &SWire{ - VpcId: vpc.Id, - ZoneId: zoneId, - } + wire := &SWire{} + wire.VpcId = vpc.Id + wire.ZoneId = zoneId wire.SetModelManager(manager, wire) wire.ExternalId = externalId wire.IsEmulated = true @@ -356,7 +342,7 @@ func (self *SWire) syncRemoveCloudWire(ctx context.Context, userCred mcclient.To lockman.LockObject(ctx, self) defer lockman.ReleaseObject(ctx, self) - vpc := self.getVpc() + vpc := self.GetVpc() cloudprovider := vpc.GetCloudprovider() if self.ExternalId == WireManager.getWireExternalIdForClassicNetwork(cloudprovider.Provider, self.VpcId, self.ZoneId) { return nil @@ -728,14 +714,6 @@ func chooseCandidateNetworksByNetworkType(nets []SNetwork, isExit bool, serverTy } } -func (self *SWire) GetZone() *SZone { - if self.ZoneId == "" { - return nil - } - - return ZoneManager.FetchZoneById(self.ZoneId) -} - func (manager *SWireManager) InitializeData() error { wires := make([]SWire, 0) q := manager.Query() @@ -790,17 +768,8 @@ func (wire *SWire) clearHostSchedDescCache() error { return nil } -func (wire *SWire) getVpc() *SVpc { - vpcObj, err := VpcManager.FetchById(wire.VpcId) - if err != nil { - log.Errorf("getVpc fail %s", err) - return nil - } - return vpcObj.(*SVpc) -} - func (self *SWire) GetIWire() (cloudprovider.ICloudWire, error) { - vpc := self.getVpc() + vpc := self.GetVpc() if vpc == nil { log.Errorf("Cannot find VPC for wire???") return nil, fmt.Errorf("No VPC?????") @@ -835,24 +804,25 @@ func (manager *SWireManager) GetOnPremiseWireOfIp(ipAddr string) (*SWire, error) } // 二层网络列表 -func (manager *SWireManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.WireListInput) (*sqlchemy.SQuery, error) { +func (manager *SWireManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.WireListInput, +) (*sqlchemy.SQuery, error) { var err error - q, err = managedResourceFilterByAccount(q, query.ManagedResourceListInput, "vpc_id", func() *sqlchemy.SQuery { - vpcs := VpcManager.Query().SubQuery() - subq := vpcs.Query(vpcs.Field("id")) - return subq - }) + + q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByAccount") + return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter") } - q, err = managedResourceFilterByDomain(q, query.DomainizedResourceListInput, "vpc_id", func() *sqlchemy.SQuery { - vpcs := VpcManager.Query().SubQuery() - subq := vpcs.Query(vpcs.Field("id")) - return subq - }) + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery) if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByDomain") + return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter") } q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) @@ -860,31 +830,6 @@ func (manager *SWireManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } - vpcStr := query.Vpc - if len(vpcStr) > 0 { - vpc, err := VpcManager.FetchByIdOrName(userCred, vpcStr) - if err != nil { - if err == sql.ErrNoRows { - return nil, httperrors.NewNotFoundError("vpc %s not found", vpcStr) - } else { - return nil, httperrors.NewInternalServerError("vpc %s query fail %s", vpcStr, err) - } - } - q = q.Equals("vpc_id", vpc.GetId()) - } - - q, err = managedResourceFilterByRegion(q, query.RegionalFilterListInput, "vpc_id", func() *sqlchemy.SQuery { - return VpcManager.Query("id") - }) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByRegion") - } - - q, err = managedResourceFilterByZone(q, query.ZonalFilterListInput, "", nil) - if err != nil { - return nil, errors.Wrap(err, "managedResourceFilterByZone") - } - hostStr := query.Host if len(hostStr) > 0 { hostObj, err := HostManager.FetchByIdOrName(userCred, hostStr) @@ -898,7 +843,53 @@ func (manager *SWireManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } -func (self *SWire) getRegion() *SCloudregion { +func (manager *SWireManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.WireListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields") + } + zoneQuery := api.ZonalFilterListInput{ + ZonalFilterListBase: query.ZonalFilterListBase, + } + q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery) + if err != nil { + return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SWireManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +/*func (self *SWire) getRegion() *SCloudregion { zone := self.GetZone() if zone != nil { return zone.GetRegion() @@ -911,31 +902,37 @@ func (self *SWire) getRegion() *SCloudregion { } return nil -} +}*/ func (self *SWire) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.WireDetails, error) { - var err error - out := api.WireDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return self.getMoreDetails(out), nil + return api.WireDetails{}, nil } -func (self *SWire) getMoreDetails(out api.WireDetails) api.WireDetails { - out.Networks, _ = self.NetworkCount() - zone := self.GetZone() - if zone != nil { - out.Zone = zone.Name +func (manager *SWireManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.WireDetails { + rows := make([]api.WireDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.WireDetails{ + StandaloneResourceDetails: stdRows[i], + VpcResourceInfo: vpcRows[i], + ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase, + } + wire := objs[i].(*SWire) + rows[i].Networks, _ = wire.NetworkCount() } - vpc := self.getVpc() - if vpc != nil { - out.Vpc = vpc.Name - out.VpcExtId = vpc.GetExternalId() - out.CloudproviderInfo = vpc.getCloudProviderInfo() - } - return out + + return rows } func (man *SWireManager) removeWiresByVpc(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc) error { diff --git a/pkg/compute/models/zoneresource.go b/pkg/compute/models/zoneresource.go index 0178965bc8..d5863aa789 100644 --- a/pkg/compute/models/zoneresource.go +++ b/pkg/compute/models/zoneresource.go @@ -18,24 +18,158 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SZoneResourceBase struct { - ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` + ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"zone_id"` +} + +type SZoneResourceBaseManager struct { + SCloudregionResourceBaseManager } func (self *SZoneResourceBase) GetZone() *SZone { return ZoneManager.FetchZoneById(self.ZoneId) } -func (self *SZoneResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.ZoneInfo { - out := api.ZoneInfo{} - zone := self.GetZone() - if zone == nil { - return out +func (self *SZoneResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) api.ZoneResourceInfo { + return api.ZoneResourceInfo{} +} + +func (manager *SZoneResourceBaseManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ZoneResourceInfo { + rows := make([]api.ZoneResourceInfo, len(objs)) + zoneIds := make([]string, len(objs)) + for i := range objs { + var base *SZoneResourceBase + err := reflectutils.FindAnonymouStructPointer(objs[i], &base) + if err != nil { + log.Errorf("Cannot find SCloudregionResourceBase in object %s", objs[i]) + continue + } + zoneIds[i] = base.ZoneId } - return zone.GetZoneInfo() + + zones := make(map[string]SZone) + err := db.FetchStandaloneObjectsByIds(ZoneManager, zoneIds, &zones) + if err != nil { + log.Errorf("FetchStandaloneObjectsByIds fail %s", err) + return rows + } + + regions := make([]interface{}, len(rows)) + for i := range rows { + rows[i] = api.ZoneResourceInfo{} + if _, ok := zones[zoneIds[i]]; ok { + rows[i].Zone = zones[zoneIds[i]].Name + rows[i].ZoneExtId = fetchExternalId(zones[zoneIds[i]].ExternalId) + rows[i].CloudregionId = zones[zoneIds[i]].CloudregionId + } + regions[i] = &SCloudregionResourceBase{rows[i].CloudregionId} + } + + regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, regions, fields, isList) + for i := range rows { + rows[i].CloudregionResourceInfo = regionRows[i] + } + + return rows +} + +func (manager *SZoneResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ZonalFilterListInput, +) (*sqlchemy.SQuery, error) { + q, err := managedResourceFilterByZone(q, query, "", nil) + if err != nil { + return nil, errors.Wrap(err, "managedResourceFilterByZone") + } + subq := ZoneManager.Query("id").Snapshot() + subq, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, subq, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter") + } + if subq.IsAltered() { + q = q.Filter(sqlchemy.In(q.Field("zone_id"), subq.SubQuery())) + } + return q, nil +} + +func (manager *SZoneResourceBaseManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + switch field { + case "zone": + zoneQuery := ZoneManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(zoneQuery.Field("name", field)) + q = q.Join(zoneQuery, sqlchemy.Equals(q.Field("zone_id"), zoneQuery.Field("id"))) + q = q.GroupBy(zoneQuery.Field("name")) + return q, nil + } + zones := ZoneManager.Query("id", "cloudregion_id").SubQuery() + q = q.LeftJoin(zones, sqlchemy.Equals(q.Field("zone_id"), zones.Field("id"))) + q, err := manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SZoneResourceBaseManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ZonalFilterListInput, +) (*sqlchemy.SQuery, error) { + q, orders, fields := manager.GetOrderBySubQuery(q, userCred, query) + if len(orders) > 0 { + q = db.OrderByFields(q, orders, fields) + } + return q, nil +} + +func (manager *SZoneResourceBaseManager) GetOrderBySubQuery( + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ZonalFilterListInput, +) (*sqlchemy.SQuery, []string, []sqlchemy.IQueryField) { + zoneQ := ZoneManager.Query("id", "name") + var orders []string + var fields []sqlchemy.IQueryField + if db.NeedOrderQuery(manager.SCloudregionResourceBaseManager.GetOrderByFields(query.RegionalFilterListInput)) { + zoneQ, orders, fields = manager.SCloudregionResourceBaseManager.GetOrderBySubQuery(zoneQ, userCred, query.RegionalFilterListInput) + } + if db.NeedOrderQuery(manager.GetOrderByFields(query)) { + subq := zoneQ.SubQuery() + q = q.LeftJoin(subq, sqlchemy.Equals(q.Field("zone_id"), subq.Field("id"))) + if db.NeedOrderQuery([]string{query.OrderByZone}) { + orders = append(orders, query.OrderByZone) + fields = append(fields, subq.Field("name")) + } + } + return q, orders, fields +} + +func (manager *SZoneResourceBaseManager) GetOrderByFields(query api.ZonalFilterListInput) []string { + orders := make([]string, 0) + zoneOrders := manager.SCloudregionResourceBaseManager.GetOrderByFields(query.RegionalFilterListInput) + orders = append(orders, zoneOrders...) + orders = append(orders, query.OrderByZone) + return orders } diff --git a/pkg/compute/models/zones.go b/pkg/compute/models/zones.go index 580cc50573..041f328324 100644 --- a/pkg/compute/models/zones.go +++ b/pkg/compute/models/zones.go @@ -32,10 +32,12 @@ import ( "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SZoneManager struct { db.SStatusStandaloneResourceBaseManager + SCloudregionResourceBaseManager } var ZoneManager *SZoneManager @@ -56,13 +58,15 @@ func init() { type SZone struct { db.SStatusStandaloneResourceBase db.SExternalizedResourceBase + SCloudregionResourceBase Location string `width:"256" charset:"utf8" get:"user" list:"user" update:"admin"` Contacts string `width:"256" charset:"utf8" get:"user" update:"admin"` NameCn string `width:"256" charset:"utf8"` ManagerUri string `width:"256" charset:"ascii" list:"admin" update:"admin"` + // 区域Id - CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"admin_required"` + // CloudregionId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"admin_required"` } func (manager *SZoneManager) GetContextManagers() [][]db.IModelManager { @@ -71,29 +75,13 @@ func (manager *SZoneManager) GetContextManagers() [][]db.IModelManager { } } -func (self *SZoneManager) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowCreate(userCred, self) -} - -func (self *SZone) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { - return db.IsAdminAllowGet(userCred, self) -} - -func (self *SZone) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { - return db.IsAdminAllowUpdate(userCred, self) -} - -func (self *SZone) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.IsAdminAllowDelete(userCred, self) -} - func (manager *SZoneManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } func (zone *SZone) ValidateDeleteCondition(ctx context.Context) error { usage := zone.GeneralUsage() - if !usage.isEmpty() { + if !usage.IsEmpty() { return httperrors.NewNotEmptyError("not empty zone") } return zone.SStandaloneResourceBase.ValidateDeleteCondition(ctx) @@ -103,34 +91,8 @@ func (manager *SZoneManager) Count() (int, error) { return manager.Query().CountWithError() } -type ZoneGeneralUsage struct { - Hosts int - HostsEnabled int - Baremetals int - BaremetalsEnabled int - Wires int - Networks int - Storages int -} - -func (usage *ZoneGeneralUsage) isEmpty() bool { - if usage.Hosts > 0 { - return false - } - if usage.Wires > 0 { - return false - } - if usage.Networks > 0 { - return false - } - if usage.Storages > 0 { - return false - } - return true -} - -func (zone *SZone) GeneralUsage() ZoneGeneralUsage { - usage := ZoneGeneralUsage{} +func (zone *SZone) GeneralUsage() api.ZoneGeneralUsage { + usage := api.ZoneGeneralUsage{} usage.Hosts, _ = zone.HostCount("", "", tristate.None, "", tristate.None) usage.HostsEnabled, _ = zone.HostCount("", "", tristate.True, "", tristate.None) usage.Baremetals, _ = zone.HostCount("", "", tristate.None, "", tristate.True) @@ -179,37 +141,33 @@ func (zone *SZone) getNetworkCount() (int, error) { return getNetworkCount(nil, zone, "") } -func (zone *SZone) GetZoneInfo() api.ZoneInfo { - out := api.ZoneInfo{ - Zone: zone.Name, - ZoneExtId: fetchExternalId(zone.ExternalId), - } - region := zone.GetRegion() - if region != nil { - out.CloudregionInfo = region.GetRegionInfo() - } - return out -} +func (manager *SZoneManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ZoneDetails { + rows := make([]api.ZoneDetails, len(objs)) -func zoneExtra(zone *SZone, out api.ZoneDetails) api.ZoneDetails { - usage := zone.GeneralUsage() - jsonutils.Update(&out, usage) - region := zone.GetRegion() - if region != nil { - out.Provider = region.Provider - out.Cloudregion = region.Name + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ZoneDetails{ + StatusStandaloneResourceDetails: stdRows[i], + CloudregionResourceInfo: regRows[i], + } + zone := objs[i].(*SZone) + rows[i].ZoneGeneralUsage = zone.GeneralUsage() + rows[i].CloudenvResourceInfo = zone.GetRegion().GetRegionCloudenvInfo() } - return out + return rows } func (zone *SZone) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ZoneDetails, error) { - var err error - out := api.ZoneDetails{} - out.StandaloneResourceDetails, err = zone.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return zoneExtra(zone, out), nil + return api.ZoneDetails{}, nil } func (zone *SZone) GetCloudRegionId() string { @@ -627,6 +585,46 @@ func (manager *SZoneManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } +func (manager *SZoneManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ZoneListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + q, err = manager.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput) + if err != nil { + return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SZoneManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + if field == "zone" { + q = q.AppendField(q.Field("name").Label("zone")) + q = q.GroupBy(q.Field("name")) + return q, nil + } + q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (self *SZone) AllowGetDetailsCapability(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { return true } diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 0efb696752..9134cae410 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -296,8 +296,8 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte data.Set("address", jsonutils.NewString(address)) data.Set("name", jsonutils.NewString(name)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -380,8 +380,8 @@ func (self *SAliyunRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx return nil, httperrors.NewInputParameterError("backend group type must be normal") } - data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId)) - data.Set("manager_id", jsonutils.NewString(listener.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(listener.GetRegionId())) + data.Set("manager_id", jsonutils.NewString(listener.GetCloudproviderId())) return data, nil } @@ -1263,7 +1263,7 @@ func (self *SAliyunRegionDriver) RequestCreateElasticcache(ctx context.Context, return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetIRegion") } - iprovider, err := db.FetchById(models.CloudproviderManager, ec.ManagerId) + iprovider, err := db.FetchById(models.CloudproviderManager, ec.GetCloudproviderId()) if err != nil { return nil, errors.Wrap(err, "aliyunRegionDriver.CreateElasticcache.GetProvider") } diff --git a/pkg/compute/regiondrivers/aws.go b/pkg/compute/regiondrivers/aws.go index a8f4011641..4ffa793b4c 100644 --- a/pkg/compute/regiondrivers/aws.go +++ b/pkg/compute/regiondrivers/aws.go @@ -269,8 +269,8 @@ func (self *SAwsRegionDriver) validateCreateApplicationListenerData(ctx context. } data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) data.Set("scheduler", jsonutils.NewString(api.LB_SCHEDULER_RR)) // aws 不支持指定调度算法 return data, nil } @@ -340,8 +340,8 @@ func (self *SAwsRegionDriver) validateCreateNetworkListenerData(ctx context.Cont data.Set("health_check_fall", jsonutils.NewInt(healthCheckRise)) data.Set("sticky_session", jsonutils.NewString(api.LB_BOOL_OFF)) data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) data.Set("scheduler", jsonutils.NewString(api.LB_SCHEDULER_RR)) // aws 不支持指定调度算法 return data, nil } @@ -443,8 +443,8 @@ func (self *SAwsRegionDriver) validateUpdateApplicationListenerData(ctx context. } data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) data.Set("scheduler", jsonutils.NewString(api.LB_SCHEDULER_RR)) // aws 不支持指定调度算法 return data, nil } @@ -501,8 +501,8 @@ func (self *SAwsRegionDriver) validateUpdateNetworkListenerData(ctx context.Cont data.Set("sticky_session", jsonutils.NewString(api.LB_BOOL_OFF)) data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) data.Set("scheduler", jsonutils.NewString(api.LB_SCHEDULER_RR)) // aws 不支持指定调度算法 return data, nil } @@ -588,8 +588,8 @@ func (self *SAwsRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx con // data.Remove("domain") // data.Remove("path") data.Set("condition", jsonutils.NewString(condition)) - data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId)) - data.Set("manager_id", jsonutils.NewString(listener.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(listener.GetRegionId())) + data.Set("manager_id", jsonutils.NewString(listener.GetCloudproviderId())) return data, nil } @@ -703,8 +703,8 @@ func (self *SAwsRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context. } data.Set("name", jsonutils.NewString(name)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -756,8 +756,8 @@ func (self *SAwsRegionDriver) createLoadbalancerBackendGroup(ctx context.Context // create loadbalancer backendgroup cache cachedLbbg := &models.SAwsCachedLbbg{} - cachedLbbg.ManagerId = lb.ManagerId - cachedLbbg.CloudregionId = lb.CloudregionId + cachedLbbg.ManagerId = lb.GetCloudproviderId() + cachedLbbg.CloudregionId = lb.GetRegionId() cachedLbbg.LoadbalancerId = lb.GetId() cachedLbbg.BackendGroupId = lbbg.GetId() cachedLbbg.ExternalId = iLoadbalancerBackendGroup.GetGlobalId() @@ -881,7 +881,7 @@ func (self *SAwsRegionDriver) RequestCreateLoadbalancerBackend(ctx context.Conte } if ibackend != nil { - if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil); err != nil { + if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil, lb.GetCloudprovider()); err != nil { return nil, errors.Wrap(err, "AwsRegionDriver.RequestCreateLoadbalancerBackend.SyncWithCloudLoadbalancerBackend") } } @@ -957,7 +957,7 @@ func (self *SAwsRegionDriver) RequestCreateLoadbalancerListener(ctx context.Cont { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := models.CloudproviderManager.FetchCloudproviderById(lblis.GetCloudproviderId()) if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1047,7 +1047,7 @@ func (self *SAwsRegionDriver) RequestCreateLoadbalancerListener(ctx context.Cont return nil, errors.Wrap(err, "awsRegionDriver.RequestCreateLoadbalancerListener.SetExternalId") } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, loadbalancer.GetOwnerId()) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, loadbalancer.GetOwnerId(), loadbalancer.GetCloudprovider()) }) return nil } @@ -1094,7 +1094,7 @@ func (self *SAwsRegionDriver) RequestCreateLoadbalancerListenerRule(ctx context. if err := db.SetExternalId(lbr, userCred, iListenerRule.GetGlobalId()); err != nil { return nil, err } - return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil) + return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil, loadbalancer.GetCloudprovider()) }) return nil } @@ -1264,7 +1264,7 @@ func (self *SAwsRegionDriver) RequestSyncLoadbalancerListener(ctx context.Contex { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := models.CloudproviderManager.FetchCloudproviderById(lblis.GetCloudproviderId()) if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1322,7 +1322,7 @@ func (self *SAwsRegionDriver) RequestSyncLoadbalancerListener(ctx context.Contex if err := iListener.Refresh(); err != nil { return nil, errors.Wrap(err, "awsRegionDriver.RequestSyncLoadbalancerListener.Refresh") } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil, loadbalancer.GetCloudprovider()) }) return nil } diff --git a/pkg/compute/regiondrivers/huawei.go b/pkg/compute/regiondrivers/huawei.go index 5d955d362c..4724710071 100644 --- a/pkg/compute/regiondrivers/huawei.go +++ b/pkg/compute/regiondrivers/huawei.go @@ -278,8 +278,8 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte } data.Set("name", jsonutils.NewString(name)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -370,8 +370,8 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerData(ctx cont return nil, err } - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroup) } @@ -428,8 +428,8 @@ func (self *SHuaWeiRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx return data, fmt.Errorf("'domain' or 'path' should not be empty.") } - data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId)) - data.Set("manager_id", jsonutils.NewString(listener.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(listener.GetRegionId())) + data.Set("manager_id", jsonutils.NewString(listener.GetCloudproviderId())) return data, nil } @@ -563,8 +563,8 @@ func (self *SHuaWeiRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont func (self *SHuaWeiRegionDriver) createCachedLbbg(lb *models.SLoadbalancer, lblis *models.SLoadbalancerListener, lbr *models.SLoadbalancerListenerRule, lbbg *models.SLoadbalancerBackendGroup) (*models.SHuaweiCachedLbbg, error) { // create loadbalancer backendgroup cache cachedLbbg := &models.SHuaweiCachedLbbg{} - cachedLbbg.ManagerId = lb.ManagerId - cachedLbbg.CloudregionId = lb.CloudregionId + cachedLbbg.ManagerId = lb.GetCloudproviderId() + cachedLbbg.CloudregionId = lb.GetRegionId() cachedLbbg.LoadbalancerId = lb.GetId() cachedLbbg.BackendGroupId = lbbg.GetId() if lbr != nil { @@ -1147,7 +1147,7 @@ func (self *SHuaWeiRegionDriver) RequestSyncLoadbalancerBackendGroup(ctx context return nil, errors.Wrap(err, "HuaWeiRegionDriver.Sync.LoadbalancerBackendGroup") } - if err := cachedLbbg.SyncWithCloudLoadbalancerBackendgroup(ctx, task.GetUserCred(), lb, ilbbg, lb.GetOwnerId()); err != nil { + if err := cachedLbbg.SyncWithCloudLoadbalancerBackendgroup(ctx, task.GetUserCred(), lb, ilbbg, lb.GetOwnerId(), lb.GetCloudprovider()); err != nil { return nil, errors.Wrap(err, "HuaWeiRegionDriver.Sync.SyncWithCloudLoadbalancerBackendgroup") } @@ -1171,7 +1171,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListener(ctx context.C { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1232,7 +1232,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListener(ctx context.C { aclId, _ := task.GetParams().GetString("acl_id") if len(aclId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1264,7 +1264,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListener(ctx context.C } } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, loadbalancer.GetOwnerId()) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, loadbalancer.GetOwnerId(), loadbalancer.GetCloudprovider()) }) return nil } @@ -1316,7 +1316,7 @@ func (self *SHuaWeiRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1375,7 +1375,7 @@ func (self *SHuaWeiRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con { aclId, _ := task.GetParams().GetString("acl_id") if len(aclId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1421,7 +1421,7 @@ func (self *SHuaWeiRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con if err := iListener.Refresh(); err != nil { return nil, err } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, lblis.GetOwnerId()) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, lblis.GetOwnerId(), lblis.GetCloudprovider()) }) return nil } @@ -1898,7 +1898,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancer(ctx context.Context, } } - if err := lb.SyncWithCloudLoadbalancer(ctx, userCred, iLoadbalancer, nil); err != nil { + if err := lb.SyncWithCloudLoadbalancer(ctx, userCred, iLoadbalancer, nil, lb.GetCloudprovider()); err != nil { return nil, err } lbbgs, err := iLoadbalancer.GetILoadBalancerBackendGroups() @@ -2041,7 +2041,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerBackend(ctx context.Co } if ibackend != nil { - if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil); err != nil { + if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil, lb.GetCloudprovider()); err != nil { return nil, errors.Wrap(err, "huaweiRegionDriver.RequestCreateLoadbalancerBackend.SyncWithCloudLoadbalancerBackend") } } @@ -2104,7 +2104,7 @@ func (self *SHuaWeiRegionDriver) RequestCreateLoadbalancerListenerRule(ctx conte if err := db.SetExternalId(lbr, userCred, iListenerRule.GetGlobalId()); err != nil { return nil, errors.Wrap(err, "huaweiRegionDriver.RequestCreateLoadbalancerListenerRule.SetExternalId") } - return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil) + return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil, loadbalancer.GetCloudprovider()) }) return nil } @@ -2154,9 +2154,8 @@ func (self *SHuaWeiRegionDriver) InitDBInstanceUser(instance *models.SDBInstance user = "rdsuser" } - account := models.SDBInstanceAccount{ - DBInstanceId: instance.Id, - } + account := models.SDBInstanceAccount{} + account.DBInstanceId = instance.Id account.Name = user account.Status = api.DBINSTANCE_USER_AVAILABLE account.ExternalId = user @@ -2426,13 +2425,11 @@ func (self *SHuaWeiRegionDriver) RequestCreateElasticcache(ctx context.Context, return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetIRegion") } - iprovider, err := db.FetchById(models.CloudproviderManager, ec.ManagerId) - if err != nil { - return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetProvider") + provider := ec.GetCloudprovider() + if provider == nil { + return nil, errors.Wrap(httperrors.ErrInvalidStatus, "huaweiRegionDriver.CreateElasticcache.GetProvider") } - provider := iprovider.(*models.SCloudprovider) - params, err := ec.GetCreateHuaweiElasticcacheParams(task.GetParams()) if err != nil { return nil, errors.Wrap(err, "huaweiRegionDriver.CreateElasticcache.GetCreateHuaweiElasticcacheParams") diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index cf85eda299..a62c037870 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -262,8 +262,8 @@ func (self *SKVMRegionDriver) ValidateCreateLoadbalancerBackendData(ctx context. } data.Set("name", jsonutils.NewString(name)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -334,8 +334,8 @@ func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx con return nil, err } - data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId)) - data.Set("manager_id", jsonutils.NewString(listener.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(listener.GetRegionId())) + data.Set("manager_id", jsonutils.NewString(listener.GetCloudproviderId())) return data, nil } @@ -493,8 +493,8 @@ func (self *SKVMRegionDriver) ValidateCreateLoadbalancerListenerData(ctx context return nil, err } - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -689,14 +689,14 @@ func (self *SKVMRegionDriver) RequestCreateLoadbalancerBackendGroup(ctx context. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { for _, backend := range backends { loadbalancerBackend := models.SLoadbalancerBackend{ - BackendGroupId: lbbg.Id, - BackendId: backend.ID, - BackendType: backend.BackendType, - BackendRole: backend.BackendRole, - Weight: backend.Weight, - Address: backend.Address, - Port: backend.Port, + BackendId: backend.ID, + BackendType: backend.BackendType, + BackendRole: backend.BackendRole, + Weight: backend.Weight, + Address: backend.Address, + Port: backend.Port, } + loadbalancerBackend.BackendGroupId = lbbg.Id loadbalancerBackend.Status = api.LB_STATUS_ENABLED loadbalancerBackend.ProjectId = userCred.GetProjectId() loadbalancerBackend.DomainId = userCred.GetProjectDomainId() diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index bb711004c3..736aa6df1b 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -181,7 +181,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancer(ctx co if err := db.SetExternalId(lb, userCred, iLoadbalancer.GetGlobalId()); err != nil { return nil, err } - if err := lb.SyncWithCloudLoadbalancer(ctx, userCred, iLoadbalancer, nil); err != nil { + if err := lb.SyncWithCloudLoadbalancer(ctx, userCred, iLoadbalancer, nil, lb.GetCloudprovider()); err != nil { return nil, err } //公网lb,需要同步public ip @@ -595,7 +595,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancerBackend if err := db.SetExternalId(lbb, userCred, iLoadbalancerBackend.GetGlobalId()); err != nil { return nil, err } - return nil, lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, iLoadbalancerBackend, nil) + return nil, lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, iLoadbalancerBackend, nil, lb.GetCloudprovider()) }) return nil } @@ -680,7 +680,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncLoadbalancerBackend(c return nil, errors.Wrap(err, "regionDriver.RequestSyncLoadbalancerBackend.GetILoadbalancerBackendById") } - return nil, lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, iBackend, nil) + return nil, lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, iBackend, nil, lb.GetCloudprovider()) }) return nil } @@ -690,7 +690,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancerListene { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -725,7 +725,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancerListene { aclId, _ := task.GetParams().GetString("acl_id") if len(aclId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -780,7 +780,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancerListene if err := db.SetExternalId(lblis, userCred, iListener.GetGlobalId()); err != nil { return nil, errors.Wrap(err, "db.SetExternalId") } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil, lblis.GetCloudprovider()) }) return nil } @@ -852,7 +852,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncLoadbalancerListener( { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -887,7 +887,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncLoadbalancerListener( { aclId, _ := task.GetParams().GetString("acl_id") if len(aclId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -951,7 +951,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestSyncLoadbalancerListener( if err := iListener.Refresh(); err != nil { return nil, errors.Wrap(err, "regionDriver.RequestSyncLoadbalancerListener.RefreshListener") } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil, lblis.GetCloudprovider()) }) return nil } @@ -1048,7 +1048,7 @@ func (self *SManagedVirtualizationRegionDriver) RequestCreateLoadbalancerListene if err := db.SetExternalId(lbr, userCred, iListenerRule.GetGlobalId()); err != nil { return nil, err } - return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil) + return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil, loadbalancer.GetCloudprovider()) }) return nil } diff --git a/pkg/compute/regiondrivers/qcloud.go b/pkg/compute/regiondrivers/qcloud.go index fb94f9fd60..595cf054c5 100644 --- a/pkg/compute/regiondrivers/qcloud.go +++ b/pkg/compute/regiondrivers/qcloud.go @@ -204,8 +204,8 @@ func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerListenerData(ctx cont } data.Set("acl_status", jsonutils.NewString(api.LB_BOOL_OFF)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return self.SManagedVirtualizationRegionDriver.ValidateCreateLoadbalancerListenerData(ctx, userCred, ownerId, data, lb, backendGroup) } @@ -301,7 +301,7 @@ func (self *SQcloudRegionDriver) RequestCreateLoadbalancerBackend(ctx context.Co } if ibackend != nil { - if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil); err != nil { + if err := lbb.SyncWithCloudLoadbalancerBackend(ctx, userCred, ibackend, nil, lb.GetCloudprovider()); err != nil { return nil, errors.Wrap(err, "qcloudRegionDriver.RequestCreateLoadbalancerBackend.SyncWithCloudLoadbalancerBackend") } } @@ -368,8 +368,8 @@ func (self *SQcloudRegionDriver) RequestDeleteLoadbalancerBackend(ctx context.Co func (self *SQcloudRegionDriver) createCachedLbbg(lb *models.SLoadbalancer, lblis *models.SLoadbalancerListener, lbr *models.SLoadbalancerListenerRule, lbbg *models.SLoadbalancerBackendGroup) (*models.SQcloudCachedLbbg, error) { // create loadbalancer backendgroup cache cachedLbbg := &models.SQcloudCachedLbbg{} - cachedLbbg.ManagerId = lb.ManagerId - cachedLbbg.CloudregionId = lb.CloudregionId + cachedLbbg.ManagerId = lb.GetCloudproviderId() + cachedLbbg.CloudregionId = lb.GetRegionId() cachedLbbg.LoadbalancerId = lb.GetId() cachedLbbg.BackendGroupId = lbbg.GetId() if lbr != nil { @@ -513,7 +513,7 @@ func (self *SQcloudRegionDriver) RequestCreateLoadbalancerListener(ctx context.C { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -588,7 +588,7 @@ func (self *SQcloudRegionDriver) RequestCreateLoadbalancerListener(ctx context.C } } - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil, loadbalancer.GetCloudprovider()) }) return nil } @@ -682,7 +682,7 @@ func (self *SQcloudRegionDriver) RequestCreateLoadbalancerListenerRule(ctx conte return nil, errors.Wrap(err, "SQcloudRegionDriver.RequestCreateLoadbalancerListener.createLoadbalancerBackendGroup") } - return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil) + return nil, lbr.SyncWithCloudLoadbalancerListenerRule(ctx, userCred, iListenerRule, nil, loadbalancer.GetCloudprovider()) }) return nil } @@ -862,8 +862,8 @@ func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerListenerRuleData(ctx return nil, err } - data.Set("cloudregion_id", jsonutils.NewString(listener.CloudregionId)) - data.Set("manager_id", jsonutils.NewString(listener.ManagerId)) + data.Set("cloudregion_id", jsonutils.NewString(listener.GetRegionId())) + data.Set("manager_id", jsonutils.NewString(listener.GetCloudproviderId())) return data, nil } @@ -1053,8 +1053,8 @@ func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte } data.Set("name", jsonutils.NewString(name)) - data.Set("manager_id", jsonutils.NewString(lb.ManagerId)) - data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) + data.Set("manager_id", jsonutils.NewString(lb.GetCloudproviderId())) + data.Set("cloudregion_id", jsonutils.NewString(lb.GetRegionId())) return data, nil } @@ -1268,7 +1268,7 @@ func (self *SQcloudRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con { certId, _ := task.GetParams().GetString("certificate_id") if len(certId) > 0 { - provider := models.CloudproviderManager.FetchCloudproviderById(lblis.ManagerId) + provider := lblis.GetCloudprovider() if provider == nil { return nil, fmt.Errorf("failed to find provider for lblis %s", lblis.Name) } @@ -1328,7 +1328,7 @@ func (self *SQcloudRegionDriver) RequestSyncLoadbalancerListener(ctx context.Con } if utils.IsInStringArray(lblis.ListenerType, []string{api.LB_LISTENER_TYPE_UDP, api.LB_LISTENER_TYPE_TCP}) { - return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil) + return nil, lblis.SyncWithCloudLoadbalancerListener(ctx, userCred, loadbalancer, iListener, nil, loadbalancer.GetCloudprovider()) } else { // http&https listener 变更不会同步到监听规则 return nil, nil diff --git a/pkg/compute/tasks/baremetal_server_sync_status_task.go b/pkg/compute/tasks/baremetal_server_sync_status_task.go index c1d6eda830..1c00ecc5b3 100644 --- a/pkg/compute/tasks/baremetal_server_sync_status_task.go +++ b/pkg/compute/tasks/baremetal_server_sync_status_task.go @@ -21,6 +21,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -84,14 +85,18 @@ func (self *BaremetalServerSyncStatusTask) OnGuestStatusTaskComplete(ctx context } func (self *BaremetalServerSyncStatusTask) OnGuestStatusTaskCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { - kwargs := jsonutils.NewDict() - kwargs.Set("status", jsonutils.NewString(api.VM_UNKNOWN)) - guest.PerformStatus(ctx, self.UserCred, nil, kwargs) + input := apis.PerformStatusInput{ + Status: api.VM_UNKNOWN, + } + guest.PerformStatus(ctx, self.UserCred, nil, input) } func (self *BaremetalServerSyncStatusTask) OnGetStatusFail(ctx context.Context, guest *models.SGuest) { kwargs := jsonutils.NewDict() kwargs.Set("status", jsonutils.NewString(api.VM_UNKNOWN)) - guest.PerformStatus(ctx, self.UserCred, nil, kwargs) + input := apis.PerformStatusInput{ + Status: api.VM_UNKNOWN, + } + guest.PerformStatus(ctx, self.UserCred, nil, input) self.SetStageComplete(ctx, nil) } diff --git a/pkg/compute/tasks/disk_delete_task.go b/pkg/compute/tasks/disk_delete_task.go index da88f34ecd..64de1be6c8 100644 --- a/pkg/compute/tasks/disk_delete_task.go +++ b/pkg/compute/tasks/disk_delete_task.go @@ -106,7 +106,7 @@ func (self *DiskDeleteTask) startDeleteDisk(ctx context.Context, disk *models.SD } isPurge := false - if (host == nil || !host.Enabled) && jsonutils.QueryBoolean(self.Params, "purge", false) { + if (host == nil || !host.GetEnabled()) && jsonutils.QueryBoolean(self.Params, "purge", false) { isPurge = true } disk.SetStatus(self.UserCred, api.DISK_DEALLOC, "") diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index cafd342c36..961e785463 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -256,7 +256,7 @@ func (self *GuestDeleteTask) DoDeleteGuest(ctx context.Context, guest *models.SG return } self.OnGuestDeleteComplete(ctx, guest, nil) - } else if (host == nil || !host.Enabled) && jsonutils.QueryBoolean(self.Params, "purge", false) { + } else if (host == nil || !host.GetEnabled()) && jsonutils.QueryBoolean(self.Params, "purge", false) { self.OnGuestDeleteComplete(ctx, guest, nil) } else { self.SetStage("OnGuestDeleteComplete", nil) diff --git a/pkg/compute/tasks/guest_detach_all_disks_task.go b/pkg/compute/tasks/guest_detach_all_disks_task.go index 222920e65b..ff10f31d7d 100644 --- a/pkg/compute/tasks/guest_detach_all_disks_task.go +++ b/pkg/compute/tasks/guest_detach_all_disks_task.go @@ -50,7 +50,7 @@ func (self *GuestDetachAllDisksTask) OnDiskDeleteComplete(ctx context.Context, o } host := guest.GetHost() purge := false - if (host == nil || !host.Enabled) && jsonutils.QueryBoolean(self.Params, "purge", false) { + if (host == nil || !host.GetEnabled()) && jsonutils.QueryBoolean(self.Params, "purge", false) { purge = true } for _, guestdisk := range guest.GetDisks() { diff --git a/pkg/compute/tasks/guest_detach_disk_task.go b/pkg/compute/tasks/guest_detach_disk_task.go index c2a156649f..f9e38a6bc7 100644 --- a/pkg/compute/tasks/guest_detach_disk_task.go +++ b/pkg/compute/tasks/guest_detach_disk_task.go @@ -62,12 +62,12 @@ func (self *GuestDetachDiskTask) OnInit(ctx context.Context, obj db.IStandaloneM guest.DetachDisk(ctx, disk, self.UserCred) host := guest.GetHost() - if host != nil && !host.Enabled && jsonutils.QueryBoolean(self.Params, "purge", false) { + if host != nil && !host.GetEnabled() && jsonutils.QueryBoolean(self.Params, "purge", false) { self.OnDetachDiskComplete(ctx, guest, nil) return } - if !host.Enabled { + if !host.GetEnabled() { self.OnDetachDiskCompleteFailed(ctx, guest, jsonutils.Marshal(map[string]string{"error": fmt.Sprintf("host %s(%s) is disabled", host.Name, host.Id)})) return } @@ -103,7 +103,7 @@ func (self *GuestDetachDiskTask) OnDetachDiskComplete(ctx context.Context, guest keepDisk := jsonutils.QueryBoolean(self.Params, "keep_disk", true) host := guest.GetHost() purge := false - if host != nil && !host.Enabled && jsonutils.QueryBoolean(self.Params, "purge", false) { + if host != nil && !host.GetEnabled() && jsonutils.QueryBoolean(self.Params, "purge", false) { purge = true } if !keepDisk && disk.AutoDelete { diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index b7e5dd9fae..33b2663e96 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -20,6 +20,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -67,9 +68,10 @@ func (self *GuestSyncstatusTask) OnGetStatusSucc(ctx context.Context, guest *mod default: statusStr = api.VM_UNKNOWN } - statusData := jsonutils.NewDict() - statusData.Add(jsonutils.NewString(statusStr), "status") - guest.PerformStatus(ctx, self.UserCred, nil, statusData) + input := apis.PerformStatusInput{ + Status: statusStr, + } + guest.PerformStatus(ctx, self.UserCred, nil, input) self.SetStageComplete(ctx, nil) // logclient.AddActionLog(guest, logclient.ACT_VM_SYNC_STATUS, "", self.UserCred, true) } diff --git a/pkg/compute/tasks/host_maintenance_task.go b/pkg/compute/tasks/host_maintenance_task.go index c798e54a40..3c182638f1 100644 --- a/pkg/compute/tasks/host_maintenance_task.go +++ b/pkg/compute/tasks/host_maintenance_task.go @@ -19,6 +19,7 @@ import ( "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" @@ -51,7 +52,7 @@ func (self *HostMaintainTask) OnInit(ctx context.Context, obj db.IStandaloneMode } func (self *HostMaintainTask) OnGuestsMigrate(ctx context.Context, host *models.SHost, data jsonutils.JSONObject) { - host.PerformDisable(ctx, self.UserCred, nil, nil) + host.PerformDisable(ctx, self.UserCred, nil, apis.PerformDisableInput{}) host.SetStatus(self.UserCred, api.BAREMETAL_MAINTAINING, "On host maintain task complete") logclient.AddSimpleActionLog(host, logclient.ACT_HOST_MAINTAINING, "host maintain", self.UserCred, true) self.SetStageComplete(ctx, nil) @@ -62,7 +63,7 @@ func (self *HostMaintainTask) OnGuestsMigrateFailed(ctx context.Context, host *m } func (self *HostMaintainTask) TaskFailed(ctx context.Context, host *models.SHost, reason string) { - host.PerformDisable(ctx, self.UserCred, nil, nil) + host.PerformDisable(ctx, self.UserCred, nil, apis.PerformDisableInput{}) host.SetStatus(self.UserCred, api.BAREMETAL_MAINTAIN_FAIL, "On host maintain task complete failed") logclient.AddSimpleActionLog(host, logclient.ACT_HOST_MAINTAINING, reason, self.UserCred, false) self.SetStageFailed(ctx, reason) diff --git a/pkg/image/models/image_guest.go b/pkg/image/models/image_guest.go index 0cef70e178..794b10c309 100644 --- a/pkg/image/models/image_guest.go +++ b/pkg/image/models/image_guest.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/image" "yunion.io/x/onecloud/pkg/appsrv" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -39,6 +40,7 @@ import ( "yunion.io/x/onecloud/pkg/image/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SGuestImageManager struct { @@ -329,20 +331,36 @@ func (self *SGuestImage) getMoreDetails(ctx context.Context, userCred mcclient.T return out } -func (self *SGuestImage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (api.GuestImageDetails, error) { +func (self *SGuestImage) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GuestImageDetails, error) { + return api.GuestImageDetails{}, nil +} - var err error - out := api.GuestImageDetails{} - out.SharableVirtualResourceDetails, err = self.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - if !isList && query.Contains("image_ids") { - out.ImageIds, _ = query.Get("image_ids") +func (manager *SGuestImageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GuestImageDetails { + rows := make([]api.GuestImageDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.GuestImageDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + guestImage := objs[i].(*SGuestImage) + rows[i] = guestImage.getMoreDetails(ctx, userCred, query, rows[i]) } - return self.getMoreDetails(ctx, userCred, query, out), nil + return rows } func (self *SGuestImage) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, @@ -502,42 +520,72 @@ func (self *SGuestImageManager) CleanPendingDeleteImages(ctx context.Context, us } func (self *SGuestImage) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + query jsonutils.JSONObject, input apis.PerformProjectPublicInput) (jsonutils.JSONObject, error) { images, err := GuestImageJointManager.GetImagesByGuestImageId(self.Id) if err != nil { return nil, errors.Wrap(err, "fail to fetch subimages of guest image") } for i := range images { - _, err := images[i].PerformPublic(ctx, userCred, query, data) + _, err := images[i].PerformPublic(ctx, userCred, query, input) if err != nil { return nil, errors.Wrapf(err, "fail to public subimage %s", images[i].GetId()) } } - return self.SSharableVirtualResourceBase.PerformPublic(ctx, userCred, query, data) + return self.SSharableVirtualResourceBase.PerformPublic(ctx, userCred, query, input) } func (self *SGuestImage) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + query jsonutils.JSONObject, input apis.PerformProjectPrivateInput) (jsonutils.JSONObject, error) { images, err := GuestImageJointManager.GetImagesByGuestImageId(self.Id) if err != nil { return nil, errors.Wrap(err, "fail to fetch subimages of guest image") } for i := range images { - _, err := images[i].PerformPrivate(ctx, userCred, query, data) + _, err := images[i].PerformPrivate(ctx, userCred, query, input) if err != nil { return nil, errors.Wrapf(err, "fail to private subimage %s", images[i].GetId()) } } - return self.SSharableVirtualResourceBase.PerformPrivate(ctx, userCred, query, data) + return self.SSharableVirtualResourceBase.PerformPrivate(ctx, userCred, query, input) } // 主机镜像列表 -func (manager *SGuestImageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.GuestImageListInput) (*sqlchemy.SQuery, error) { +func (manager *SGuestImageManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GuestImageListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput) if err != nil { return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SGuestImageManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GuestImageListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SGuestImageManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index d397fb214d..3c8420c149 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -52,6 +52,7 @@ import ( "yunion.io/x/onecloud/pkg/util/qemuimg" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/streamutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) const ( @@ -252,7 +253,18 @@ func (self *SImage) CustomizedGetDetailsBody(ctx context.Context, userCred mccli return nil, nil } -func (self *SImage) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, out api.ImageDetails) api.ImageDetails { +func (self *SImage) getMoreDetails(out api.ImageDetails) api.ImageDetails { + properties, err := ImagePropertyManager.GetProperties(self.Id) + if err != nil { + log.Errorf("ImagePropertyManager.GetProperties fail %s", err) + } + out.Properties = properties + + if self.PendingDeleted { + pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) + out.AutoDeleteAt = pendingDeletedAt + } + var ossChksum = self.OssChecksum if len(self.OssChecksum) == 0 { ossChksum = self.Checksum @@ -262,42 +274,43 @@ func (self *SImage) getMoreDetails(ctx context.Context, userCred mcclient.TokenC return out } -func (self *SImage) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ImageDetails, error) { - var err error - out := api.ImageDetails{} - out.SharableVirtualResourceDetails, err = self.SSharableVirtualResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SImageManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ImageDetails { + rows := make([]api.ImageDetails, len(objs)) + + virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + image := objs[i].(*SImage) + rows[i] = api.ImageDetails{ + SharableVirtualResourceDetails: virtRows[i], + } + rows[i] = image.getMoreDetails(rows[i]) } - properties, err := ImagePropertyManager.GetProperties(self.Id) - if err != nil { - return out, httperrors.NewGeneralError(err) - } - propJson := jsonutils.NewDict() - for k, v := range properties { - propJson.Add(jsonutils.NewString(v), k) - } - out.Properties = propJson + return rows +} - if self.PendingDeleted { - pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) - out.AutoDeleteAt = pendingDeletedAt - //extra.Add(jsonutils.NewString(timeutils.FullIsoTime(pendingDeletedAt)), "auto_delete_at") - } - - return self.getMoreDetails(ctx, userCred, query, out), nil +func (self *SImage) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ImageDetails, error) { + return api.ImageDetails{}, nil } func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) map[string]string { headers := make(map[string]string) - _extra, _ := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query, false) - extra := _extra.JSON(_extra) - extraRows := self.GetModelManager().FetchCustomizeColumns(ctx, userCred, query, []db.IModel{self}, nil) - if len(extraRows) == 1 { - extra.Update(extraRows[0]) - } + details := ImageManager.FetchCustomizeColumns(ctx, userCred, query, []interface{}{self}, nil, false) + extra := jsonutils.Marshal(details[0]).(*jsonutils.JSONDict) for _, k := range extra.SortedKeys() { val, _ := extra.GetString(k) if len(val) > 0 { @@ -1114,10 +1127,15 @@ func (self *SImage) GetDetailsSubformats(ctx context.Context, userCred mcclient. } // 磁盘镜像列表 -func (manager *SImageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ImageListInput) (*sqlchemy.SQuery, error) { +func (manager *SImageManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ImageListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter") } fmtJsonArray := query.DiskFormats if len(fmtJsonArray) > 0 { @@ -1131,6 +1149,33 @@ func (manager *SImageManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ return q, nil } +func (manager *SImageManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ImageListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SImageManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func isActive(localPath string, size int64, chksum string, fastHash string, useFastHash bool) bool { if len(localPath) == 0 || !fileutils2.Exists(localPath) { log.Errorf("invalid file: %s", localPath) @@ -1263,11 +1308,12 @@ func (self *SImage) PerformMarkStandard( ) (jsonutils.JSONObject, error) { isStandard := jsonutils.QueryBoolean(data, "is_standard", false) if !self.IsStandard.IsTrue() && isStandard { - params := jsonutils.NewDict() - params.Set("scope", jsonutils.NewString("system")) - _, err := self.PerformPublic(ctx, userCred, query, params) + input := apis.PerformProjectPublicInput{ + Scope: "system", + } + _, err := self.PerformPublic(ctx, userCred, query, input) if err != nil { - return nil, err + return nil, errors.Wrap(err, "PerformPublic") } diff, err := db.Update(self, func() error { self.IsStandard = tristate.True diff --git a/pkg/keystone/models/credentials.go b/pkg/keystone/models/credentials.go index a1fd633682..2324e26b0f 100644 --- a/pkg/keystone/models/credentials.go +++ b/pkg/keystone/models/credentials.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/keystone/keys" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SCredentialManager struct { @@ -166,14 +167,35 @@ func (self *SCredential) ValidateUpdateData(ctx context.Context, userCred mcclie return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) } -func (self *SCredential) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.CredentialDetails, error) { - var err error - out := api.CredentialDetails{} - out.StandaloneResourceDetails, err = self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SCredential) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.CredentialDetails, error) { + return api.CredentialDetails{}, nil +} + +func (manager *SCredentialManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.CredentialDetails { + rows := make([]api.CredentialDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.CredentialDetails{ + StandaloneResourceDetails: stdRows[i], + } + rows[i] = credentialExtra(objs[i].(*SCredential), rows[i]) } - return credentialExtra(self, out), nil + + return rows } func credentialExtra(cred *SCredential, out api.CredentialDetails) api.CredentialDetails { @@ -259,6 +281,43 @@ func (manager *SCredentialManager) FetchOwnerId(ctx context.Context, data jsonut } // 用户信用凭证列表 -func (manager *SCredentialManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.CredentialListInput) (*sqlchemy.SQuery, error) { - return manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (manager *SCredentialManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CredentialListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") + } + return q, nil +} + +func (manager *SCredentialManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.CredentialListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SCredentialManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } diff --git a/pkg/keystone/models/domains.go b/pkg/keystone/models/domains.go index 25872f8915..8b5f7a5bb8 100644 --- a/pkg/keystone/models/domains.go +++ b/pkg/keystone/models/domains.go @@ -169,8 +169,14 @@ func (manager *SDomainManager) FetchDomainByIdOrName(domain string) (*SDomain, e } // 域列表 -func (manager *SDomainManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.DomainListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (manager *SDomainManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DomainListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } @@ -178,6 +184,29 @@ func (manager *SDomainManager) ListItemFilter(ctx context.Context, q *sqlchemy.S return q, nil } +func (manager *SDomainManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.DomainListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SDomainManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func (domain *SDomain) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { // domain.ParentId = api.KeystoneDomainRoot domain.DomainId = api.KeystoneDomainRoot @@ -268,29 +297,48 @@ func (domain *SDomain) ValidateUpdateData(ctx context.Context, userCred mcclient return domain.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) } -func (domain *SDomain) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.DomainDetails, error) { - var err error - out := api.DomainDetails{} - out.StandaloneResourceDetails, err = domain.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return domainExtra(domain, out), nil +func (domain *SDomain) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.DomainDetails, error) { + return api.DomainDetails{}, nil } -func domainExtra(domain *SDomain, out api.DomainDetails) api.DomainDetails { - // idp, _ := domain.GetIdentityProvider() - // if idp != nil { - // extra.Add(jsonutils.NewString(idp.Name), "driver") - // } +func (manager *SDomainManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.DomainDetails { + rows := make([]api.DomainDetails, len(objs)) - out.UserCout, _ = domain.GetUserCount() - out.GroupCount, _ = domain.GetGroupCount() - out.ProjectCout, _ = domain.GetProjectCount() - out.RoleCount, _ = domain.GetRoleCount() - out.PolicyCount, _ = domain.GetPolicyCount() - out.IdpCount, _ = domain.GetIdpCount() - return out + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + idList := make([]string, len(rows)) + for i := range rows { + rows[i] = api.DomainDetails{ + StandaloneResourceDetails: stdRows[i], + } + domain := objs[i].(*SDomain) + idList[i] = domain.Id + rows[i].UserCout, _ = domain.GetUserCount() + rows[i].GroupCount, _ = domain.GetGroupCount() + rows[i].ProjectCout, _ = domain.GetProjectCount() + rows[i].RoleCount, _ = domain.GetRoleCount() + rows[i].PolicyCount, _ = domain.GetPolicyCount() + rows[i].IdpCount, _ = domain.GetIdpCount() + } + + idpRows := expandIdpAttributes(api.IdMappingEntityDomain, idList, fields) + + for i := range rows { + rows[i].IdpResourceInfo = idpRows[i] + } + + return rows } func (domain *SDomain) getUsers() ([]SUser, error) { @@ -365,11 +413,6 @@ func (domain *SDomain) IsReadOnly() bool { return false } -func (manager *SDomainManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - return expandIdpAttributes(rows, objs, fields, api.IdMappingEntityDomain) -} - func (domain *SDomain) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { domain.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) logclient.AddActionLogWithContext(ctx, domain, logclient.ACT_CREATE, data, userCred, true) diff --git a/pkg/keystone/models/endpoints.go b/pkg/keystone/models/endpoints.go index e1742977af..656e9a644d 100644 --- a/pkg/keystone/models/endpoints.go +++ b/pkg/keystone/models/endpoints.go @@ -236,10 +236,31 @@ func (cata SServiceCatalog) GetKeystoneCatalogV2() mcclient.KeystoneServiceCatal return results } -func (manager *SEndpointManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) +func (endpoint *SEndpoint) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.EndpointDetails, error) { + return api.EndpointDetails{}, nil +} + +func (manager *SEndpointManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.EndpointDetails { + rows := make([]api.EndpointDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) serviceIds := stringutils2.SSortedStrings{} for i := range objs { + rows[i] = api.EndpointDetails{ + StandaloneResourceDetails: stdRows[i], + } ep := objs[i].(*SEndpoint) serviceIds = stringutils2.Append(serviceIds, ep.ServiceId) } @@ -250,10 +271,10 @@ func (manager *SEndpointManager) FetchCustomizeColumns(ctx context.Context, user ep := objs[i].(*SEndpoint) if srv, ok := svs[ep.ServiceId]; ok { if len(fields) == 0 || fields.Contains("service_name") { - rows[i].Add(jsonutils.NewString(srv.Name), "service_name") + rows[i].ServiceName = srv.Name } if len(fields) == 0 || fields.Contains("service_type") { - rows[i].Add(jsonutils.NewString(srv.Type), "service_type") + rows[i].ServiceType = srv.Type } } } @@ -283,16 +304,6 @@ func (endpoint *SEndpoint) ValidateDeleteCondition(ctx context.Context) error { return endpoint.SStandaloneResourceBase.ValidateDeleteCondition(ctx) } -func (endpoint *SEndpoint) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.EndpointDetails, error) { - var err error - out := api.EndpointDetails{} - out.StandaloneResourceDetails, err = endpoint.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return out, nil -} - func (manager *SEndpointManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { infname, _ := data.GetString("interface") if len(infname) == 0 { @@ -330,7 +341,12 @@ func (manager *SEndpointManager) ValidateCreateData(ctx context.Context, userCre } // 服务地址列表 -func (manager *SEndpointManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.EndpointListInput) (*sqlchemy.SQuery, error) { +func (manager *SEndpointManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.EndpointListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") @@ -351,6 +367,43 @@ func (manager *SEndpointManager) ListItemFilter(ctx context.Context, q *sqlchemy return q, nil } +func (manager *SEndpointManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.EndpointListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + if db.NeedOrderQuery([]string{query.OrderByService}) { + services := ServiceManager.Query("id", "name").SubQuery() + q = q.LeftJoin(services, sqlchemy.Equals(q.Field("service_id"), services.Field("id"))) + if sqlchemy.SQL_ORDER_ASC.Equals(query.OrderByService) { + q = q.Asc(services.Field("name")) + } else { + q = q.Desc(services.Field("name")) + } + } + + return q, nil +} + +func (manager *SEndpointManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (endpoint *SEndpoint) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { endpoint.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data) logclient.AddActionLogWithContext(ctx, endpoint, logclient.ACT_CREATE, data, userCred, true) diff --git a/pkg/keystone/models/expandidps.go b/pkg/keystone/models/expandidps.go index 2ae8f6a38d..f414163959 100644 --- a/pkg/keystone/models/expandidps.go +++ b/pkg/keystone/models/expandidps.go @@ -17,37 +17,36 @@ package models import ( "database/sql" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" - "yunion.io/x/onecloud/pkg/cloudcommon/db" + api "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/util/stringutils2" ) -func expandIdpAttributes(rows []*jsonutils.JSONDict, objs []db.IModel, fields stringutils2.SSortedStrings, entType string) []*jsonutils.JSONDict { +func expandIdpAttributes(entType string, idList []string, fields stringutils2.SSortedStrings) []api.IdpResourceInfo { + rows := make([]api.IdpResourceInfo, len(idList)) + for i := range rows { + rows[i] = api.IdpResourceInfo{} + } if len(fields) == 0 || fields.Contains("idp_id") || fields.Contains("idp") || fields.Contains("idp_entity_id") || fields.Contains("idp_driver") { - log.Debugf("objs %d", len(objs)) - idList := make([]string, len(objs)) - for i := range objs { - idList[i] = objs[i].GetId() - } idps, err := fetchIdmappings(idList, entType) if err == nil && idps != nil { - for i := range rows { - if idp, ok := idps[objs[i].GetId()]; ok { + for i := range idList { + if idp, ok := idps[idList[i]]; ok { if len(fields) == 0 || fields.Contains("idp_id") { - rows[i].Set("idp_id", jsonutils.NewString(idp.IdpId)) + rows[i].IdpId = idp.IdpId } if len(fields) == 0 || fields.Contains("idp") { - rows[i].Set("idp", jsonutils.NewString(idp.IdpName)) + rows[i].Idp = idp.IdpName } if len(fields) == 0 || fields.Contains("idp_entity_id") { - rows[i].Set("idp_entity_id", jsonutils.NewString(idp.EntityId)) + rows[i].IdpEntityId = idp.EntityId } if len(fields) == 0 || fields.Contains("idp_driver") { - rows[i].Set("idp_driver", jsonutils.NewString(idp.Driver)) + rows[i].IdpDriver = idp.Driver + rows[i].IdpDriver = idp.Driver } } } diff --git a/pkg/keystone/models/groups.go b/pkg/keystone/models/groups.go index f22c3d96ca..5ce7ad15a8 100644 --- a/pkg/keystone/models/groups.go +++ b/pkg/keystone/models/groups.go @@ -76,7 +76,12 @@ func (manager *SGroupManager) GetContextManagers() [][]db.IModelManager { } // 用户组列表 -func (manager *SGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.GroupListInput) (*sqlchemy.SQuery, error) { +func (manager *SGroupManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GroupListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) if err != nil { return nil, err @@ -113,6 +118,32 @@ func (manager *SGroupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ return q, nil } +func (manager *SGroupManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.GroupListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.IdentityBaseResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SIdentityBaseResourceManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (group *SGroup) GetUserCount() (int, error) { q := UsergroupManager.Query().Equals("group_id", group.Id) return q.CountWithError() @@ -144,20 +175,40 @@ func (group *SGroup) Delete(ctx context.Context, userCred mcclient.TokenCredenti return group.SIdentityBaseResource.Delete(ctx, userCred) } -func (group *SGroup) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.GroupDetails, error) { - var err error - out := api.GroupDetails{} - out.StandaloneResourceDetails, err = group.SIdentityBaseResource.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return groupExtra(group, out), nil +func (group *SGroup) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.GroupDetails, error) { + return api.GroupDetails{}, nil } -func groupExtra(group *SGroup, out api.GroupDetails) api.GroupDetails { - out.UserCount, _ = group.GetUserCount() - out.ProjectCount, _ = group.GetProjectCount() - return out +func (manager *SGroupManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.GroupDetails { + rows := make([]api.GroupDetails, len(objs)) + identRows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + idList := make([]string, len(rows)) + for i := range rows { + rows[i] = api.GroupDetails{ + IdentityBaseResourceDetails: identRows[i], + } + group := objs[i].(*SGroup) + idList[i] = group.Id + rows[i].UserCount, _ = group.GetUserCount() + rows[i].ProjectCount, _ = group.GetProjectCount() + } + idpRows := expandIdpAttributes(api.IdMappingEntityGroup, idList, fields) + for i := range rows { + rows[i].IdpResourceInfo = idpRows[i] + } + return rows } func (manager *SGroupManager) RegisterExternalGroup(ctx context.Context, idpId string, domainId string, groupId string, groupName string) (*SGroup, error) { @@ -256,11 +307,6 @@ func (group *SGroup) LinkedWithIdp(idpId string) bool { return false } -func (manager *SGroupManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - return expandIdpAttributes(rows, objs, fields, api.IdMappingEntityGroup) -} - func (manager *SGroupManager) FetchGroupsInDomain(domainId string, excludes []string) ([]SGroup, error) { q := manager.Query().Equals("domain_id", domainId).NotIn("id", excludes) grps := make([]SGroup, 0) diff --git a/pkg/keystone/models/identity_provider.go b/pkg/keystone/models/identity_provider.go index e7ba33f808..a8407527ba 100644 --- a/pkg/keystone/models/identity_provider.go +++ b/pkg/keystone/models/identity_provider.go @@ -37,6 +37,7 @@ import ( "yunion.io/x/onecloud/pkg/keystone/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SIdentityProviderManager struct { @@ -105,7 +106,7 @@ func (manager *SIdentityProviderManager) InitializeData() error { sqldrv.SetModelManager(manager, &sqldrv) sqldrv.Id = api.DEFAULT_IDP_ID sqldrv.Name = api.IdentityDriverSQL - sqldrv.Enabled = true + sqldrv.SetEnabled(true) sqldrv.Status = api.IdentityDriverStatusConnected sqldrv.Driver = api.IdentityDriverSQL sqldrv.Description = "Default sql identity provider" @@ -137,7 +138,7 @@ func (manager *SIdentityProviderManager) InitializeData() error { drv.SetModelManager(manager, &drv) drv.Id = domains[i].Id // identical ID with domain, for backward compatibility drv.Name = domains[i].Name - drv.Enabled = domains[i].Enabled.Bool() + drv.SetEnabled(domains[i].Enabled.Bool()) drv.Status = api.IdentityDriverStatusDisconnected drv.Driver = driver drv.Description = domains[i].Description @@ -216,7 +217,7 @@ func (ident *SIdentityProvider) AllowPerformConfig(ctx context.Context, userCred } func (ident *SIdentityProvider) PerformConfig(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (jsonutils.JSONObject, error) { - if ident.Status == api.IdentityDriverStatusConnected && ident.Enabled { + if ident.Status == api.IdentityDriverStatusConnected && ident.GetEnabled() { return nil, httperrors.NewInvalidStatusError("cannot update config when enabled and connected") } if ident.SyncStatus != api.IdentitySyncStatusIdle { @@ -312,7 +313,7 @@ func (manager *SIdentityProviderManager) ValidateCreateData(ctx context.Context, } func (ident *SIdentityProvider) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { - ident.Enabled = true + ident.SetEnabled(true) return ident.SEnabledStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) } @@ -389,7 +390,7 @@ func (self *SIdentityProvider) AllowPerformSync(ctx context.Context, userCred mc } func (self *SIdentityProvider) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - if !self.Enabled { + if !self.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Account disabled") } if self.CanSync() { @@ -398,14 +399,34 @@ func (self *SIdentityProvider) PerformSync(ctx context.Context, userCred mcclien return nil, nil } -func (self *SIdentityProvider) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.IdentityProviderDetails, error) { - var err error - out := api.IdentityProviderDetails{} - out.StandaloneResourceDetails, err = self.SEnabledStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (self *SIdentityProvider) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.IdentityProviderDetails, error) { + return api.IdentityProviderDetails{}, nil +} + +func (manager *SIdentityProviderManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.IdentityProviderDetails { + rows := make([]api.IdentityProviderDetails, len(objs)) + + stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.IdentityProviderDetails{ + EnabledStatusStandaloneResourceDetails: stdRows[i], + } + rows[i] = objs[i].(*SIdentityProvider).getMoreDetails(rows[i]) } - return self.getMoreDetails(out), nil + + return rows } func (self *SIdentityProvider) getMoreDetails(out api.IdentityProviderDetails) api.IdentityProviderDetails { @@ -810,6 +831,44 @@ func (manager *SIdentityProviderManager) FetchPasswordProtectedIdpIdsQuery() *sq return q.SubQuery() } -func (manager *SIdentityProviderManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.IdentityProviderListInput) (*sqlchemy.SQuery, error) { - return manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) +func (manager *SIdentityProviderManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IdentityProviderListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter") + } + + return q, nil +} + +func (manager *SIdentityProviderManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IdentityProviderListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SIdentityProviderManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound } diff --git a/pkg/keystone/models/identitybase.go b/pkg/keystone/models/identitybase.go index 3b4917b815..2457040b5d 100644 --- a/pkg/keystone/models/identitybase.go +++ b/pkg/keystone/models/identitybase.go @@ -22,8 +22,10 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" + "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/identity" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" @@ -117,15 +119,35 @@ func (manager *SIdentityBaseResourceManager) FetchByIdOrName(userCred mcclient.I return db.FetchByIdOrName(manager.GetIIdentityModelManager(), userCred, idStr) } -func (manager *SIdentityBaseResourceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.IdentityBaseResourceListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) +func (manager *SIdentityBaseResourceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IdentityBaseResourceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } + // override manager.SDomainizedResourceBaseManager.ListItemFilter() + if len(query.ProjectDomains) > 0 { + domains := DomainManager.Query().SubQuery() + subq := domains.Query(domains.Field("id")).Filter(sqlchemy.OR( + sqlchemy.In(domains.Field("id"), query.ProjectDomains), + sqlchemy.In(domains.Field("name"), query.ProjectDomains), + )) + q = q.In("domain_id", subq.SubQuery()) + } return q, nil } -func (manager *SEnabledIdentityBaseResourceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.EnabledIdentityBaseResourceListInput) (*sqlchemy.SQuery, error) { +func (manager *SEnabledIdentityBaseResourceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.EnabledIdentityBaseResourceListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) if err != nil { return nil, errors.Wrap(err, "SIdentityBaseResourceManager.ListItemFilter") @@ -140,12 +162,17 @@ func (manager *SEnabledIdentityBaseResourceManager) ListItemFilter(ctx context.C return q, nil } -func (manager *SIdentityBaseResourceManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { - q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query) +func (manager *SIdentityBaseResourceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.IdentityBaseResourceListInput, +) (*sqlchemy.SQuery, error) { + q, err := manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, err } - orderByDomain, _ := query.GetString("order_by_domain") + orderByDomain := query.OrderByDomain if sqlchemy.SQL_ORDER_ASC.Equals(orderByDomain) || sqlchemy.SQL_ORDER_DESC.Equals(orderByDomain) { domains := DomainManager.Query().SubQuery() q = q.LeftJoin(domains, sqlchemy.Equals(q.Field("domain_id"), domains.Field("id"))) @@ -158,6 +185,44 @@ func (manager *SIdentityBaseResourceManager) OrderByExtraFields(ctx context.Cont return q, nil } +func (manager *SEnabledIdentityBaseResourceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.EnabledIdentityBaseResourceListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.IdentityBaseResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SIdentityBaseResourceManager.OrderByExtraFields") + } + return q, nil +} + +func (manager *SIdentityBaseResourceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + if field == "domain" { + domainQuery := DomainManager.Query("name", "id").Distinct().SubQuery() + q.AppendField(domainQuery.Field("name", "domain")) + q = q.Join(domainQuery, sqlchemy.Equals(q.Field("domain_id"), domainQuery.Field("id"))) + q.GroupBy(domainQuery.Field("name")) + return q, nil + } + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + +func (manager *SEnabledIdentityBaseResourceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + q, err := manager.SIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + return q, httperrors.ErrNotFound +} + func fetchDomainInfo(data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) { domainId, key := jsonutils.GetAnyString2(data, []string{"domain_id", "project_domain", "project_domain_id"}) if len(domainId) > 0 { @@ -206,25 +271,49 @@ func (manager *SIdentityBaseResourceManager) NamespaceScope() rbacutils.TRbacSco return rbacutils.ScopeSystem } -func (manager *SIdentityBaseResourceManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - if len(fields) == 0 || fields.Contains("project_domain") { - domainIds := stringutils2.SSortedStrings{} - for i := range objs { - idStr := objs[i].GetOwnerId().GetProjectDomainId() - if idStr != api.KeystoneDomainRoot { - domainIds = stringutils2.Append(domainIds, idStr) - } +func (model *SIdentityBaseResource) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.IdentityBaseResourceDetails, error) { + return api.IdentityBaseResourceDetails{}, nil +} + +func (manager *SIdentityBaseResourceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.IdentityBaseResourceDetails { + rows := make([]api.IdentityBaseResourceDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + domainIds := stringutils2.SSortedStrings{} + for i := range rows { + rows[i] = api.IdentityBaseResourceDetails{ + StandaloneResourceDetails: stdRows[i], + DomainizedResourceInfo: apis.DomainizedResourceInfo{}, } + var base *SIdentityBaseResource + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.DomainId) > 0 && base.DomainId != api.KeystoneDomainRoot { + domainIds = stringutils2.Append(domainIds, base.DomainId) + } + } + + if len(fields) == 0 || fields.Contains("project_domain") { domains := fetchDomain(domainIds) if domains != nil { for i := range rows { - idStr := objs[i].GetOwnerId().GetProjectDomainId() - if idStr != api.KeystoneDomainRoot { - if domain, ok := domains[idStr]; ok { - if len(fields) == 0 || fields.Contains("project_domain") { - rows[i].Add(jsonutils.NewString(domain.Name), "project_domain") - } + var base *SIdentityBaseResource + reflectutils.FindAnonymouStructPointer(objs[i], &base) + if base != nil && len(base.DomainId) > 0 && base.DomainId != api.KeystoneDomainRoot { + if domain, ok := domains[base.DomainId]; ok { + rows[i].ProjectDomain = domain.Name } } } @@ -233,6 +322,36 @@ func (manager *SIdentityBaseResourceManager) FetchCustomizeColumns(ctx context.C return rows } +func (model *SEnabledIdentityBaseResource) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.EnabledIdentityBaseResourceDetails, error) { + return api.EnabledIdentityBaseResourceDetails{}, nil +} + +func (manager *SEnabledIdentityBaseResourceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.EnabledIdentityBaseResourceDetails { + rows := make([]api.EnabledIdentityBaseResourceDetails, len(objs)) + + identRows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.EnabledIdentityBaseResourceDetails{ + IdentityBaseResourceDetails: identRows[i], + } + } + + return rows +} + func fetchDomain(domainIds []string) map[string]SDomain { q := DomainManager.Query().In("id", domainIds) domains := make([]SDomain, 0) diff --git a/pkg/keystone/models/policies.go b/pkg/keystone/models/policies.go index 97070cbf5a..dd9ff47055 100644 --- a/pkg/keystone/models/policies.go +++ b/pkg/keystone/models/policies.go @@ -28,6 +28,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SPolicyManager struct { @@ -207,31 +208,73 @@ func (policy *SPolicy) ValidateDeleteCondition(ctx context.Context) error { } // 权限策略列表 -func (manager *SPolicyManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.PolicyListInput) (*sqlchemy.SQuery, error) { +func (manager *SPolicyManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.PolicyListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SEnabledIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput) if err != nil { return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ListItemFilter") } - if query.IsPublic != nil { - if *query.IsPublic { - q = q.IsTrue("is_public") - } else { - q = q.IsFalse("is_public") - } + q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter") } return q, nil } -func (policy *SPolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.PolicyDetails, error) { +func (manager *SPolicyManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.PolicyListInput, +) (*sqlchemy.SQuery, error) { var err error - out := api.PolicyDetails{} - out.StandaloneResourceDetails, err = policy.SEnabledIdentityBaseResource.GetExtraDetails(ctx, userCred, query, isList) + + q, err = manager.SEnabledIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput) if err != nil { - return out, err + return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.OrderByExtraFields") } - return policyExtra(policy, out), nil + + return q, nil } -func policyExtra(policy *SPolicy, out api.PolicyDetails) api.PolicyDetails { - return out +func (manager *SPolicyManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + +func (policy *SPolicy) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.PolicyDetails, error) { + return api.PolicyDetails{}, nil +} + +func (manager *SPolicyManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.PolicyDetails { + rows := make([]api.PolicyDetails, len(objs)) + identRows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.PolicyDetails{ + EnabledIdentityBaseResourceDetails: identRows[i], + } + } + return rows } diff --git a/pkg/keystone/models/projects.go b/pkg/keystone/models/projects.go index 650992dfe6..b200713a79 100644 --- a/pkg/keystone/models/projects.go +++ b/pkg/keystone/models/projects.go @@ -33,6 +33,7 @@ import ( "yunion.io/x/onecloud/pkg/keystone/options" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/pinyinutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SProjectManager struct { @@ -204,10 +205,17 @@ func (proj *SProject) FetchExtend() (*SProjectExtended, error) { } // 项目列表 -func (manager *SProjectManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ProjectListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) +func (manager *SProjectManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ProjectListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SIdentityBaseResourceManager.ListItemFilter") } userStr := query.User @@ -241,6 +249,33 @@ func (manager *SProjectManager) ListItemFilter(ctx context.Context, q *sqlchemy. return q, nil } +func (manager *SProjectManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ProjectListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.IdentityBaseResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SIdentityBaseResourceManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SProjectManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (model *SProject) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error { model.ParentId = ownerId.GetProjectDomainId() model.IsDomain = tristate.False @@ -289,14 +324,35 @@ func (proj *SProject) ValidateUpdateData(ctx context.Context, userCred mcclient. return proj.SIdentityBaseResource.ValidateUpdateData(ctx, userCred, query, data) } -func (proj *SProject) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ProjectDetails, error) { - var err error - out := api.ProjectDetails{} - out.StandaloneResourceDetails, err = proj.SIdentityBaseResource.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SProjectManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ProjectDetails { + rows := make([]api.ProjectDetails, len(objs)) + + identRows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ProjectDetails{ + IdentityBaseResourceDetails: identRows[i], + } + rows[i] = projectExtra(objs[i].(*SProject), rows[i]) } - return projectExtra(proj, out), nil + + return rows +} + +func (proj *SProject) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ProjectDetails, error) { + return api.ProjectDetails{}, nil } func projectExtra(proj *SProject, out api.ProjectDetails) api.ProjectDetails { diff --git a/pkg/keystone/models/regions.go b/pkg/keystone/models/regions.go index c54c04f278..4408c35a94 100644 --- a/pkg/keystone/models/regions.go +++ b/pkg/keystone/models/regions.go @@ -26,6 +26,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SRegionManager struct { @@ -100,13 +101,26 @@ func (region *SRegion) ValidateDeleteCondition(ctx context.Context) error { } func (region *SRegion) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.RegionDetails, error) { - var err error - out := api.RegionDetails{} - out.StandaloneResourceDetails, err = region.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err + return api.RegionDetails{}, nil +} + +func (manager *SRegionManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.RegionDetails { + rows := make([]api.RegionDetails, len(objs)) + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + for i := range rows { + rows[i] = api.RegionDetails{ + StandaloneResourceDetails: stdRows[i], + } + rows[i] = regionExtra(objs[i].(*SRegion), rows[i]) } - return regionExtra(region, out), nil + return rows } func regionExtra(region *SRegion, out api.RegionDetails) api.RegionDetails { @@ -147,10 +161,42 @@ func (region *SRegion) CustomizeCreate(ctx context.Context, userCred mcclient.To } // 区域列表 -func (manager *SRegionManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.RegionListInput) (*sqlchemy.SQuery, error) { +func (manager *SRegionManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SRegionManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SRegionManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/keystone/models/roles.go b/pkg/keystone/models/roles.go index c079d538f8..b8f1bd1e41 100644 --- a/pkg/keystone/models/roles.go +++ b/pkg/keystone/models/roles.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SRoleManager struct { @@ -195,31 +196,59 @@ func (role *SRole) ValidateDeleteCondition(ctx context.Context) error { return role.SIdentityBaseResource.ValidateDeleteCondition(ctx) } -func (role *SRole) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.RoleDetails, error) { - var err error - out := api.RoleDetails{} - out.StandaloneResourceDetails, err = role.SIdentityBaseResource.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } - return roleExtra(role, out), nil +func (role *SRole) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.RoleDetails, error) { + return api.RoleDetails{}, nil } -func roleExtra(role *SRole, out api.RoleDetails) api.RoleDetails { - out.UserCount, _ = role.GetUserCount() - out.GroupCount, _ = role.GetGroupCount() - out.ProjectCount, _ = role.GetProjectCount() - out.MatchPolicies = policy.PolicyManager.RoleMatchPolicies(role.Name) - return out +func (manager *SRoleManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.RoleDetails { + rows := make([]api.RoleDetails, len(objs)) + + identRows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.RoleDetails{ + IdentityBaseResourceDetails: identRows[i], + } + role := objs[i].(*SRole) + rows[i].UserCount, _ = role.GetUserCount() + rows[i].GroupCount, _ = role.GetGroupCount() + rows[i].ProjectCount, _ = role.GetProjectCount() + rows[i].MatchPolicies = policy.PolicyManager.RoleMatchPolicies(role.Name) + } + + return rows } // 角色列表 -func (manager *SRoleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.RoleListInput) (*sqlchemy.SQuery, error) { - q, err := manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) +func (manager *SRoleManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RoleListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.IdentityBaseResourceListInput) if err != nil { return nil, errors.Wrap(err, "SIdentityBaseResourceManager.ListItemFilter") } + q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter") + } + var projectId string projectStr := query.Project if len(projectStr) > 0 { @@ -265,6 +294,33 @@ func (manager *SRoleManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } +func (manager *SRoleManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RoleListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.IdentityBaseResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SIdentityBaseResourceManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SRoleManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (role *SRole) UpdateInContext(ctx context.Context, userCred mcclient.TokenCredential, ctxObjs []db.IModel, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { if len(ctxObjs) != 2 { return nil, httperrors.NewInputParameterError("not supported update context") diff --git a/pkg/keystone/models/services.go b/pkg/keystone/models/services.go index 46a8dba71b..884d8276dd 100644 --- a/pkg/keystone/models/services.go +++ b/pkg/keystone/models/services.go @@ -29,6 +29,7 @@ import ( "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SServiceManager struct { @@ -108,19 +109,35 @@ func (service *SService) ValidateDeleteCondition(ctx context.Context) error { return service.SStandaloneResourceBase.ValidateDeleteCondition(ctx) } -func (service *SService) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.ServiceDetails, error) { - var err error - out := api.ServiceDetails{} - out.StandaloneResourceDetails, err = service.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SServiceManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ServiceDetails { + rows := make([]api.ServiceDetails, len(objs)) + + stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ServiceDetails{ + StandaloneResourceDetails: stdRows[i], + } + rows[i].EndpointCount, _ = objs[i].(*SService).GetEndpointCount() } - return serviceExtra(service, out), nil + + return rows } -func serviceExtra(service *SService, out api.ServiceDetails) api.ServiceDetails { - out.EndpointCount, _ = service.GetEndpointCount() - return out +func (service *SService) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ServiceDetails, error) { + return api.ServiceDetails{}, nil } func (service *SService) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) { @@ -205,10 +222,42 @@ func (manager *SServiceManager) fetchServiceByType(typeStr string) (*SService, e } // 服务列表 -func (manager *SServiceManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.RegionListInput) (*sqlchemy.SQuery, error) { +func (manager *SServiceManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput) if err != nil { return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter") } return q, nil } + +func (manager *SServiceManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.RegionListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SServiceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} diff --git a/pkg/keystone/models/users.go b/pkg/keystone/models/users.go index 0641486b70..f06cca475d 100644 --- a/pkg/keystone/models/users.go +++ b/pkg/keystone/models/users.go @@ -313,10 +313,15 @@ func localUserVerifyPassword(user *api.SUserExtended, passwd string) error { } // 用户列表 -func (manager *SUserManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.UserListInput) (*sqlchemy.SQuery, error) { +func (manager *SUserManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.UserListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SEnabledIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ListItemFilter") } groupStr := query.Group @@ -364,6 +369,33 @@ func (manager *SUserManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu return q, nil } +func (manager *SUserManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.UserListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput) + if err != nil { + return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.OrderByExtraFields") + } + + return q, nil +} + +func (manager *SUserManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SEnabledIdentityBaseResourceManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (manager *SUserManager) FilterByHiddenSystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacutils.TRbacScope) *sqlchemy.SQuery { q = manager.SEnabledIdentityBaseResourceManager.FilterByHiddenSystemAttributes(q, userCred, query, scope) isSystem := jsonutils.QueryBoolean(query, "system", false) @@ -478,14 +510,43 @@ func (user *SUser) GetCredentialCount() (int, error) { return q.CountWithError() } -func (user *SUser) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.UserDetails, error) { - var err error - out := api.UserDetails{} - out.StandaloneResourceDetails, err = user.SEnabledIdentityBaseResource.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SUserManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.UserDetails { + rows := make([]api.UserDetails, len(objs)) + + identRows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + userIds := make([]string, len(rows)) + + for i := range rows { + rows[i] = api.UserDetails{ + EnabledIdentityBaseResourceDetails: identRows[i], + } + userIds[i] = objs[i].(*SUser).Id + rows[i] = userExtra(objs[i].(*SUser), rows[i]) } - return userExtra(user, out), nil + + idpRows := expandIdpAttributes(api.IdMappingEntityUser, userIds, fields) + + for i := range rows { + rows[i].IdpResourceInfo = idpRows[i] + } + + return rows +} + +func (user *SUser) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.UserDetails, error) { + return api.UserDetails{}, nil } func userExtra(user *SUser, out api.UserDetails) api.UserDetails { @@ -711,11 +772,6 @@ func (user *SUser) LinkedWithIdp(idpId string) bool { return false } -func (manager *SUserManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict { - rows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields) - return expandIdpAttributes(rows, objs, fields, api.IdMappingEntityUser) -} - func (manager *SUserManager) FetchUsersInDomain(domainId string, excludes []string) ([]SUser, error) { q := manager.Query().Equals("domain_id", domainId).NotIn("id", excludes) usrs := make([]SUser, 0) diff --git a/pkg/logger/models/baremetalevents.go b/pkg/logger/models/baremetalevents.go index caf695a5a6..d26b28aa80 100644 --- a/pkg/logger/models/baremetalevents.go +++ b/pkg/logger/models/baremetalevents.go @@ -86,7 +86,12 @@ func (manager *SBaremetalEventManager) GetPagingConfig() *db.SPagingConfig { } // 物理机日志列表 -func (manager *SBaremetalEventManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.BaremetalEventListInput) (*sqlchemy.SQuery, error) { +func (manager *SBaremetalEventManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.BaremetalEventListInput, +) (*sqlchemy.SQuery, error) { q, err := manager.SModelBaseManager.ListItemFilter(ctx, q, userCred, query.ModelBaseListInput) if err != nil { return nil, errors.Wrap(err, "SModelBaseManager.ListItemFilter") diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index 70510833ca..1e4783fd1a 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -44,14 +44,16 @@ type ServerListOptions struct { 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"` WithoutUserMeta *bool `help:"Show Servers without user metadata"` Group string `help:"Instance Group ID or Name"` HostSn string `help:"Host SN"` + OrderByDisk string `help:"Order by disk size" choices:"asc|desc"` + OrderByHost string `help:"Order by host name" choices:"asc|desc"` + OrderByNetwork string `help:"Order by network name" choices:"asc|desc"` + ResourceType string `help:"Resource type" choices:"shared|prepaid|dedicated"` BillingType string `help:"billing type" choices:"postpaid|prepaid"` diff --git a/pkg/monitor/models/alert.go b/pkg/monitor/models/alert.go index 7f452962c8..7ed8d402f9 100644 --- a/pkg/monitor/models/alert.go +++ b/pkg/monitor/models/alert.go @@ -24,12 +24,12 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/monitor" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/monitor/validators" - "yunion.io/x/onecloud/pkg/util/rbacutils" ) const ( @@ -46,6 +46,7 @@ func init() { type SAlertManager struct { db.SVirtualResourceBaseManager + db.SEnabledResourceBaseManager } func NewAlertManager(dt interface{}, keyword, keywordPlural string) *SAlertManager { @@ -72,10 +73,11 @@ func (man *SAlertManager) FetchAllAlerts() ([]SAlert, error) { type SAlert struct { db.SVirtualResourceBase + db.SEnabledResourceBase Frequency int64 `nullable:"false" list:"user" create:"required" update:"user"` Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"` - Enabled bool `nullable:"false" default:"false" list:"user" create:"optional"` + // Enabled bool `nullable:"false" default:"false" list:"user" create:"optional"` Message string `charset:"utf8" list:"user" update:"user"` State string `width:"36" charset:"ascii" list:"user"` @@ -91,20 +93,6 @@ type SAlert struct { ExecutionErrorState string `charset:"utf8" list:"user"` } -func (alert *SAlert) IsEnable() bool { - return alert.Enabled -} - -func (alert *SAlert) SetEnable() error { - alert.Enabled = true - return nil -} - -func (alert *SAlert) SetDisable() error { - alert.Enabled = false - return nil -} - func (alert *SAlert) SetTitle(ctx context.Context, t string) error { return alert.SetMetadata(ctx, AlertMetadataTitle, t, nil) } @@ -184,12 +172,13 @@ func (man *SAlertManager) ValidateCreateData(ctx context.Context, userCred mccli func (man *SAlertManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input monitor.AlertListInput) (*sqlchemy.SQuery, error) { q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter") } - q, err = db.ListEnableItemFilter(q, input.Enabled) + q, err = man.SEnabledResourceBaseManager.ListItemFilter(ctx, q, userCred, input.EnabledResourceBaseListInput) if err != nil { - return nil, err + return nil, errors.Wrap(err, "SEnabledResourceBaseManager.ListItemFilter") } + return q, nil } @@ -238,20 +227,28 @@ func (alert *SAlert) CustomizeCreate(ctx context.Context, userCred mcclient.Toke return alert.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data) } -func (alert *SAlert) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.AllowPerformEnable(alert, rbacutils.ScopeProject, userCred) +func (alert *SAlert) AllowPerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) bool { + return db.IsProjectAllowPerform(userCred, alert, "enable") } -func (alert *SAlert) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return db.PerformEnable(alert, userCred) +func (alert *SAlert) PerformEnable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformEnableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(alert, ctx, userCred, true) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") + } + return nil, nil } -func (alert *SAlert) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { - return db.AllowPerformDisable(alert, rbacutils.ScopeProject, userCred) +func (alert *SAlert) AllowPerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) bool { + return db.IsProjectAllowPerform(userCred, alert, "disable") } -func (alert *SAlert) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return db.PerformDisable(alert, userCred) +func (alert *SAlert) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) { + err := db.EnabledPerformEnable(alert, ctx, userCred, false) + if err != nil { + return nil, errors.Wrap(err, "EnabledPerformEnable") + } + return nil, nil } func (alert *SAlert) GetNotifications() ([]SAlertNotification, error) { diff --git a/pkg/notify/models/mod_contact.go b/pkg/notify/models/mod_contact.go index 9fbab37a8f..e95c36608a 100644 --- a/pkg/notify/models/mod_contact.go +++ b/pkg/notify/models/mod_contact.go @@ -32,6 +32,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/notify/utils" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SContactManager struct { @@ -209,15 +210,35 @@ func (self *SContact) getMoreDetail(ctx context.Context, userCred mcclient.Token return out, nil } -func (self *SContact) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, isList bool) (api.ContactDetails, error) { - var err error - out := api.ContactDetails{} - out.ModelBaseDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err +func (manager *SContactManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.ContactDetails { + rows := make([]api.ContactDetails, len(objs)) + + stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.ContactDetails{ + ResourceBaseDetails: stdRows[i], + } + rows[i], _ = objs[i].(*SContact).getMoreDetail(ctx, userCred, rows[i]) } - return self.getMoreDetail(ctx, userCred, out) + + return rows +} + +func (self *SContact) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.ContactDetails, error) { + return api.ContactDetails{}, nil } // 联系方式列表 diff --git a/pkg/notify/models/mod_notification.go b/pkg/notify/models/mod_notification.go index 6e49c363a4..c5060d084a 100644 --- a/pkg/notify/models/mod_notification.go +++ b/pkg/notify/models/mod_notification.go @@ -36,6 +36,7 @@ import ( "yunion.io/x/onecloud/pkg/notify/options" "yunion.io/x/onecloud/pkg/notify/utils" "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/onecloud/pkg/util/stringutils2" ) type SNotificationManager struct { @@ -104,13 +105,35 @@ type UserDetail struct { ReceivedAt time.Time } -func (self *SNotification) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.NotificationDetails, error) { +func (manager *SNotificationManager) FetchCustomizeColumns( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + objs []interface{}, + fields stringutils2.SSortedStrings, + isList bool, +) []api.NotificationDetails { + rows := make([]api.NotificationDetails, len(objs)) + + resRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList) + + for i := range rows { + rows[i] = api.NotificationDetails{ + ResourceBaseDetails: resRows[i], + } + } + + return rows +} + +func (self *SNotification) GetExtraDetails( + ctx context.Context, + userCred mcclient.TokenCredential, + query jsonutils.JSONObject, + isList bool, +) (api.NotificationDetails, error) { var err error out := api.NotificationDetails{} - out.ModelBaseDetails, err = self.SStatusStandaloneResourceBase.GetExtraDetails(ctx, userCred, query, isList) - if err != nil { - return out, err - } var scopeStr string scopeStr, err = query.GetString("scope") diff --git a/pkg/scheduler/algorithm/predicates/k8s/host_status_predicate.go b/pkg/scheduler/algorithm/predicates/k8s/host_status_predicate.go index f4333833c2..8dea392aa1 100644 --- a/pkg/scheduler/algorithm/predicates/k8s/host_status_predicate.go +++ b/pkg/scheduler/algorithm/predicates/k8s/host_status_predicate.go @@ -43,7 +43,7 @@ func (p *HostStatusPredicate) Execute(cli *kubernetes.Clientset, pod *v1.Pod, no return false, fmt.Errorf("Host status is %s", host.Status) } - if !host.Enabled { + if !host.GetEnabled() { return false, fmt.Errorf("Host is disabled") } return true, nil diff --git a/pkg/scheduler/cache/candidate/base.go b/pkg/scheduler/cache/candidate/base.go index 16ca3c9a83..b4332f8904 100644 --- a/pkg/scheduler/cache/candidate/base.go +++ b/pkg/scheduler/cache/candidate/base.go @@ -158,7 +158,7 @@ func (b baseHostGetter) HostStatus() string { } func (b baseHostGetter) Enabled() bool { - return b.h.Enabled + return b.h.GetEnabled() } func (b baseHostGetter) ProjectGuests() map[string]int64 { @@ -459,7 +459,7 @@ func (b *BaseHostDesc) fillIpmiInfo(host *computemodels.SHost) error { } func (h *BaseHostDesc) GetEnableStatus() string { - if h.Enabled { + if h.GetEnabled() { return "enable" } return "disable" diff --git a/pkg/util/stringutils2/sortedstrings.go b/pkg/util/stringutils2/sortedstrings.go index aba792ad8c..3c9611f8cc 100644 --- a/pkg/util/stringutils2/sortedstrings.go +++ b/pkg/util/stringutils2/sortedstrings.go @@ -29,6 +29,9 @@ func NewSortedStrings(strs []string) SSortedStrings { } func Append(ss SSortedStrings, ele ...string) SSortedStrings { + if ss == nil { + ss = NewSortedStrings([]string{}) + } for _, e := range ele { pos, find := ss.Index(e) if find { diff --git a/pkg/yunionconf/models/parameters.go b/pkg/yunionconf/models/parameters.go index 69badee259..d0b07014cb 100644 --- a/pkg/yunionconf/models/parameters.go +++ b/pkg/yunionconf/models/parameters.go @@ -19,9 +19,11 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/sqlchemy" // "yunion.io/x/pkg/utils" + "yunion.io/x/sqlchemy" + api "yunion.io/x/onecloud/pkg/apis/yunionconf" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/policy" @@ -243,17 +245,27 @@ func (manager *SParameterManager) FilterByName(q *sqlchemy.SQuery, name string) } // 配置参数列表 -func (manager *SParameterManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { +func (manager *SParameterManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ParameterListInput, +) (*sqlchemy.SQuery, error) { + var err error + q, err = manager.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SResourceBaseManager.ListItemFilter") + } if db.IsAdminAllowList(userCred, manager) { - if id, _ := query.GetString("namespace_id"); len(id) > 0 { + if id := query.NamespaceId; len(id) > 0 { q = q.Equals("namespace_id", id) - } else if id := jsonutils.GetAnyString(query, []string{"service", "service_id"}); len(id) > 0 { + } else if id := query.Service; len(id) > 0 { if sid, err := getServiceId(id); err != nil { return q, err } else { q = q.Equals("namespace_id", sid).Equals("namespace", NAMESPACE_SERVICE) } - } else if id := jsonutils.GetAnyString(query, []string{"user", "user_id"}); len(id) > 0 { + } else if id := query.User; len(id) > 0 { if uid, err := getUserId(id); err != nil { return q, err } else { @@ -267,11 +279,37 @@ func (manager *SParameterManager) ListItemFilter(ctx context.Context, q *sqlchem q = q.Equals("namespace_id", userCred.GetUserId()).Equals("namespace", NAMESPACE_USER) } } */ - } return q, nil } +func (manager *SParameterManager) OrderByExtraFields( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query api.ParameterListInput, +) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ResourceBaseListInput) + if err != nil { + return nil, errors.Wrap(err, "SResourceBaseManager.OrderByExtraFielda") + } + + return q, nil +} + +func (manager *SParameterManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) { + var err error + + q, err = manager.SResourceBaseManager.QueryDistinctExtraField(q, field) + if err == nil { + return q, nil + } + + return q, httperrors.ErrNotFound +} + func (model *SParameter) IsOwner(userCred mcclient.TokenCredential) bool { return model.CreatedBy == userCred.GetUserId() || (model.NamespaceId == userCred.GetUserId() && model.Namespace == NAMESPACE_USER) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 88642f858c..eb06f8343e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -884,7 +884,7 @@ sigs.k8s.io/yaml yunion.io/x/executor/apis yunion.io/x/executor/client yunion.io/x/executor/server -# yunion.io/x/jsonutils v0.0.0-20200113074440-9297fd00ba07 +# yunion.io/x/jsonutils v0.0.0-20200303051356-aa609aba0cda yunion.io/x/jsonutils # yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d yunion.io/x/log @@ -921,7 +921,7 @@ yunion.io/x/pkg/util/workqueue yunion.io/x/pkg/utils # yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e yunion.io/x/s3cli -# yunion.io/x/sqlchemy v0.0.0-20200221103553-6a98f7f8ab92 +# yunion.io/x/sqlchemy v0.0.0-20200303101347-d1e82c81b4e1 yunion.io/x/sqlchemy # yunion.io/x/structarg v0.0.0-20190809075558-115bed041de3 yunion.io/x/structarg diff --git a/vendor/yunion.io/x/jsonutils/go.mod b/vendor/yunion.io/x/jsonutils/go.mod index 3696e8e3f0..a521db2cb8 100644 --- a/vendor/yunion.io/x/jsonutils/go.mod +++ b/vendor/yunion.io/x/jsonutils/go.mod @@ -6,10 +6,10 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/mattn/go-colorable v0.1.2 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect - github.com/pkg/errors v0.8.1 + github.com/pkg/errors v0.8.1 // indirect github.com/sirupsen/logrus v1.4.2 // indirect golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 // indirect gopkg.in/yaml.v2 v2.2.2 // indirect yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b - yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa + yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070 ) diff --git a/vendor/yunion.io/x/jsonutils/go.sum b/vendor/yunion.io/x/jsonutils/go.sum index 1fecee9c1e..f965efca1e 100644 --- a/vendor/yunion.io/x/jsonutils/go.sum +++ b/vendor/yunion.io/x/jsonutils/go.sum @@ -35,7 +35,5 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b h1:Z9z+7iegu0HXuL+S8taVWRd1P4b9JJOgPXIeoqYrj7c= yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE= -yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf h1:OsKC+2ghZHwp+Ztm/MwKlLKKRiE7QcPG8eTp0GmsHbg= -yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= -yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa h1:+7zYi8MhaOW/53/7FOERnhQqAU4UhgaOVIS+AMzTKNU= -yunion.io/x/pkg v0.0.0-20200103043034-27c6f82160fa/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= +yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070 h1:rKnYgtvMHKmzPEUTkyNjyKOG7wzjpUvI7fcZwLNGQXw= +yunion.io/x/pkg v0.0.0-20200302034534-fdf44d54b070/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E= diff --git a/vendor/yunion.io/x/jsonutils/unmarshal.go b/vendor/yunion.io/x/jsonutils/unmarshal.go index ef80b8730f..7739088a02 100644 --- a/vendor/yunion.io/x/jsonutils/unmarshal.go +++ b/vendor/yunion.io/x/jsonutils/unmarshal.go @@ -529,18 +529,23 @@ func setStructFieldAt(key string, v JSONObject, fieldValues reflectutils.SStruct return nil } visited[key] = true - index := fieldValues.GetStructFieldIndex(key) - if index < 0 { + indexes := fieldValues.GetStructFieldIndexes(key) + if len(indexes) == 0 { // no field match k, ignore return nil } - err := v.unmarshalValue(fieldValues[index].Value) - if err != nil { - return errors.Wrap(err, "JSONDict.unmarshalStruct") - } - depInfo, ok := fieldValues[index].Info.Tags["deprecated-by"] - if ok { - return setStructFieldAt(depInfo, v, fieldValues, visited) + for _, index := range indexes { + err := v.unmarshalValue(fieldValues[index].Value) + if err != nil { + return errors.Wrap(err, "JSONDict.unmarshalStruct") + } + depInfo, ok := fieldValues[index].Info.Tags["deprecated-by"] + if ok { + err := setStructFieldAt(depInfo, v, fieldValues, visited) + if err != nil { + return errors.Wrap(err, "setStructFieldAt") + } + } } return nil } diff --git a/vendor/yunion.io/x/sqlchemy/query.go b/vendor/yunion.io/x/sqlchemy/query.go index 7b0f257c57..ee62f7cf67 100644 --- a/vendor/yunion.io/x/sqlchemy/query.go +++ b/vendor/yunion.io/x/sqlchemy/query.go @@ -22,8 +22,8 @@ import ( "strings" "yunion.io/x/log" - "yunion.io/x/pkg/util/reflectutils" "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/reflectutils" ) type IQuery interface { @@ -104,6 +104,8 @@ type SQuery struct { offset int fieldCache map[string]IQueryField + + snapshot string } type SSubQuery struct { @@ -173,7 +175,7 @@ func (sq *SSubQuery) findField(id string) IQueryField { for i := range queryFields { if queryFields[i].Name() == id { sq.referedFields[id] = sq.query.Field(queryFields[i].Name()) - return queryFields[i] + return sq.referedFields[id] } } return nil @@ -694,3 +696,15 @@ func (q *SQuery) Row2Struct(row IRowScanner, dest interface{}) error { } return q.RowMap2Struct(result, dest) } + +func (q *SQuery) Snapshot() *SQuery { + q.snapshot = q.String() + return q +} + +func (q *SQuery) IsAltered() bool { + if len(q.snapshot) == 0 { + panic(fmt.Sprintf("Query %s has never been snapshot when IsAltered called", q.String())) + } + return q.String() != q.snapshot +} diff --git a/vendor/yunion.io/x/sqlchemy/table.go b/vendor/yunion.io/x/sqlchemy/table.go index 6c95deb338..4b7fa6ad5b 100644 --- a/vendor/yunion.io/x/sqlchemy/table.go +++ b/vendor/yunion.io/x/sqlchemy/table.go @@ -19,6 +19,7 @@ import ( "reflect" "strings" + "yunion.io/x/log" "yunion.io/x/pkg/utils" ) @@ -119,7 +120,8 @@ func (tbl *STable) Field(name string, alias ...string) IQueryField { name = utils.CamelSplit(name, "_") spec := tbl.spec.ColumnSpec(name) if spec == nil { - panic("column not found: " + name) + log.Warningf("column %s not found in table %s", name, tbl.spec.Name()) + return nil } col := STableField{table: tbl, spec: spec} if len(alias) > 0 {