From 27d70e9a30a77346bcb8c5bc62eeba3d50c9deeb Mon Sep 17 00:00:00 2001 From: rainzm Date: Wed, 26 Jan 2022 12:11:47 +0800 Subject: [PATCH] feat(region,image): add SecretResourceBase --- cmd/climc/shell/compute/hosts.go | 2 + cmd/climc/shell/image/images.go | 24 +++++++++++ pkg/apis/cloudcommon/db/secret.go | 19 +++++++++ pkg/apis/compute/api.go | 3 ++ pkg/apis/compute/host.go | 10 +++++ pkg/apis/image/image.go | 5 +++ pkg/apis/list.go | 6 +++ pkg/apis/output.go | 5 +++ pkg/cloudcommon/db/secretresource.go | 63 ++++++++++++++++++++++++++++ pkg/compute/models/hosts.go | 25 +++++++++++ pkg/image/models/images.go | 7 ++++ pkg/mcclient/options/compute/host.go | 19 +++++++++ 12 files changed, 188 insertions(+) create mode 100644 pkg/apis/cloudcommon/db/secret.go create mode 100644 pkg/cloudcommon/db/secretresource.go diff --git a/cmd/climc/shell/compute/hosts.go b/cmd/climc/shell/compute/hosts.go index 419ca00e57..f99827a06c 100644 --- a/cmd/climc/shell/compute/hosts.go +++ b/cmd/climc/shell/compute/hosts.go @@ -49,6 +49,8 @@ func init() { cmd.BatchDelete(&options.BaseIdsOptions{}) cmd.Perform("remove-all-netifs", &options.BaseIdOptions{}) cmd.Perform("probe-isolated-devices", &options.BaseIdOptions{}) + cmd.Perform("set-secret-level", &compute.HostSetSecretLevelOptions{}) + cmd.Perform("remove-secret-level", &compute.HostSetSecretLevelOptions{}) cmd.BatchPerform("enable", &options.BaseIdsOptions{}) cmd.BatchPerform("disable", &options.BaseIdsOptions{}) diff --git a/cmd/climc/shell/image/images.go b/cmd/climc/shell/image/images.go index 2941adf77c..9a34d31319 100644 --- a/cmd/climc/shell/image/images.go +++ b/cmd/climc/shell/image/images.go @@ -419,6 +419,30 @@ func init() { return nil }) + type ImageSetSecretLevelOptions struct { + ID string `json:"-"` + SecretLevel string `json:"secret_level"` + } + R(&ImageSetSecretLevelOptions{}, "image-set-secret-level", "Set secret level", func(s *mcclient.ClientSession, args *ImageSetSecretLevelOptions) error { + result, err := modules.Images.PerformAction(s, args.ID, "set-secret-level", jsonutils.Marshal(args)) + if err != nil { + return err + } + printObject(result) + return nil + }) + type ImageRemoveSecretLevelOptions struct { + ID string `json:"-"` + } + R(&ImageRemoveSecretLevelOptions{}, "image-remove-secret-level", "remove secret level", func(s *mcclient.ClientSession, args *ImageRemoveSecretLevelOptions) error { + result, err := modules.Images.PerformAction(s, args.ID, "remove-secret-level", nil) + if err != nil { + return err + } + printObject(result) + return nil + }) + type ImagePublicOptions struct { ID []string `help:"ID or name of image" json:"-"` Scope string `help:"sharing scope" choices:"system|domain|project"` diff --git a/pkg/apis/cloudcommon/db/secret.go b/pkg/apis/cloudcommon/db/secret.go new file mode 100644 index 0000000000..75c3036ebe --- /dev/null +++ b/pkg/apis/cloudcommon/db/secret.go @@ -0,0 +1,19 @@ +// 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 + +const ( + SECRET_KEY = "secret_level" +) diff --git a/pkg/apis/compute/api.go b/pkg/apis/compute/api.go index 6d15e6ac24..f58f40a748 100644 --- a/pkg/apis/compute/api.go +++ b/pkg/apis/compute/api.go @@ -208,6 +208,9 @@ type DiskConfig struct { //swagger:ignore DiskId string `json:"disk_id"` + + //swagger: ignore + SecretLevel string `json:"secret_level"` } type IsolatedDeviceConfig struct { diff --git a/pkg/apis/compute/host.go b/pkg/apis/compute/host.go index c1b7049fd1..d70c14b489 100644 --- a/pkg/apis/compute/host.go +++ b/pkg/apis/compute/host.go @@ -392,6 +392,16 @@ type HostCreateInput struct { BootMode string `json:"boot_mode"` } +type HostSetSecretLevelInput struct { + // description: 秘密级别 + SecretLevel string `json:"secret_level"` + Force bool `json:"force"` +} + +type HostRemoveSecretLevelInput struct { + Force bool `json:"force"` +} + type HostUpdateInput struct { apis.EnabledStatusInfrasResourceBaseUpdateInput diff --git a/pkg/apis/image/image.go b/pkg/apis/image/image.go index 098d05af43..643ed29f70 100644 --- a/pkg/apis/image/image.go +++ b/pkg/apis/image/image.go @@ -106,5 +106,10 @@ type ImageUpdateStatusInput struct { Reason string `json:"reason"` } +type ImageSetSecretLevelInput struct { + // description: 秘密级别 + SecretLevel string `json:"secret_level"` +} + type PerformProbeInput struct { } diff --git a/pkg/apis/list.go b/pkg/apis/list.go index 880d35ee42..4369face7f 100644 --- a/pkg/apis/list.go +++ b/pkg/apis/list.go @@ -246,11 +246,17 @@ type MetadataResourceListInput struct { WithMeta *bool `json:"with_meta"` } +type SecretResourceListInput struct { + SecretLevel string +} + type StandaloneAnonResourceListInput struct { ResourceBaseListInput MetadataResourceListInput + SecretResourceListInput + // 显示所有的资源,包括模拟的资源 ShowEmulated *bool `json:"show_emulated" help:"show emulated resources" negative:"do not show emulated resources"` diff --git a/pkg/apis/output.go b/pkg/apis/output.go index e35c30ad5b..be3c17304f 100644 --- a/pkg/apis/output.go +++ b/pkg/apis/output.go @@ -133,6 +133,10 @@ type MetadataResourceInfo struct { Metadata map[string]string `json:"metadata"` } +type SecretResourceInfo struct { + SecretLevel string `json:"secret_level"` +} + type StatusDomainLevelUserResourceDetails struct { StatusDomainLevelResourceDetails @@ -151,6 +155,7 @@ type StandaloneAnonResourceDetails struct { ResourceBaseDetails MetadataResourceInfo + SecretResourceInfo } type StandaloneResourceDetails struct { diff --git a/pkg/cloudcommon/db/secretresource.go b/pkg/cloudcommon/db/secretresource.go new file mode 100644 index 0000000000..fef93977e3 --- /dev/null +++ b/pkg/cloudcommon/db/secretresource.go @@ -0,0 +1,63 @@ +package db + +import ( + "context" + + "yunion.io/x/log" + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + dbapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/stringutils2" + "yunion.io/x/onecloud/pkg/util/tagutils" +) + +type SSecretResourceBaseModelManager struct{} + +func (secret *SSecretResourceBaseModelManager) ListItemFilter(manager IModelManager, q *sqlchemy.SQuery, input apis.SecretResourceListInput) *sqlchemy.SQuery { + if input.SecretLevel == "" { + return q + } + inputTagFilters := tagutils.STagFilters{} + tag := tagutils.STag{ + Key: CLASS_TAG_PREFIX + dbapi.SECRET_KEY, + Value: input.SecretLevel, + } + var tagSet tagutils.TTagSet = []tagutils.STag{tag} + inputTagFilters.AddFilter(tagSet) + return ObjectIdQueryWithTagFilters(q, "id", manager.Keyword(), inputTagFilters) +} + +func (secret *SSecretResourceBaseModelManager) FetchCustomizeColumns(manager IModelManager, userCred mcclient.TokenCredential, objs []interface{}, fields stringutils2.SSortedStrings) []apis.SecretResourceInfo { + ret := make([]apis.SecretResourceInfo, len(objs)) + resIds := make([]string, len(objs)) + for i := range objs { + resIds[i] = GetModelIdstr(objs[i].(IModel)) + } + if fields == nil || fields.Contains("secret_level") { + q := Metadata.Query("id", "key", "value").Equals("key", CLASS_TAG_PREFIX+dbapi.SECRET_KEY) + 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].SecretLevel = metaList[0].Value + } + } + } + return ret +} + +func (secret *SSecretResourceBaseModelManager) SetSecretLevel(ctx context.Context, userCred mcclient.TokenCredential, model *SStandaloneAnonResourceBase, secretLevel string) error { + return model.SetClassMetadataAll(ctx, map[string]interface{}{ + dbapi.SECRET_KEY: secretLevel, + }, userCred) +} + +func (secret *SSecretResourceBaseModelManager) RemoveSecretLevel(ctx context.Context, userCred mcclient.TokenCredential, model *SStandaloneAnonResourceBase) error { + return model.RemoveMetadata(ctx, CLASS_TAG_PREFIX+dbapi.SECRET_KEY, userCred) +} diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 4fe13c93bf..7d202b41ee 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -5801,6 +5801,31 @@ func (manager *SHostManager) initHostname() error { return nil } +func (host *SHost) PerformSetSecretLevel(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.HostSetSecretLevelInput) (jsonutils.JSONObject, error) { + if input.SecretLevel == "" { + return nil, httperrors.NewMissingParameterError("secret_level") + } + count, err := host.GetGuestCount() + if err != nil { + return nil, errors.Wrap(err, "unable to GetGuestCount") + } + if !input.Force && count > 0 { + return nil, httperrors.NewForbiddenError("It is forbidden to modify the security level of the host with virtual machines") + } + return nil, HostManager.SSecretResourceBaseModelManager.SetSecretLevel(ctx, userCred, &host.SStandaloneAnonResourceBase, input.SecretLevel) +} + +func (host *SHost) PerformRemoveSecretLevel(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.HostRemoveSecretLevelInput) (jsonutils.JSONObject, error) { + count, err := host.GetGuestCount() + if err != nil { + return nil, errors.Wrap(err, "unable to GetGuestCount") + } + if !input.Force && count > 0 { + return nil, httperrors.NewForbiddenError("It is forbidden to modify the security level of the host with virtual machines") + } + return nil, HostManager.SSecretResourceBaseModelManager.RemoveSecretLevel(ctx, userCred, &host.SStandaloneAnonResourceBase) +} + func (manager *SHostManager) InitializeData() error { return manager.initHostname() } diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index 87f5433c54..2a2a1d9dab 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -1536,6 +1536,13 @@ func (img *SImage) PerformUpdateStatus(ctx context.Context, userCred mcclient.To return nil, nil } +func (img *SImage) PerformSetSecretLevel(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ImageSetSecretLevelInput) (jsonutils.JSONObject, error) { + if input.SecretLevel == "" { + return nil, httperrors.NewMissingParameterError("secret_level") + } + return nil, ImageManager.SSecretResourceBaseModelManager.SetSecretLevel(ctx, userCred, &img.SStandaloneAnonResourceBase, input.SecretLevel) +} + func (img *SImage) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicProjectInput) (jsonutils.JSONObject, error) { if img.IsGuestImage.IsTrue() { return nil, errors.Wrap(httperrors.ErrForbidden, "cannot perform public for guest image") diff --git a/pkg/mcclient/options/compute/host.go b/pkg/mcclient/options/compute/host.go index 12a8b67228..06bf6b923f 100644 --- a/pkg/mcclient/options/compute/host.go +++ b/pkg/mcclient/options/compute/host.go @@ -85,3 +85,22 @@ type HostStatusStatisticsOptions struct { HostListOptions options.StatusStatisticsOptions } + +type HostSetSecretLevelOptions struct { + options.BaseIdOptions + SecretLevel string `json:"secret_level"` + Force bool `json:"force"` +} + +func (opt *HostSetSecretLevelOptions) Params() (jsonutils.JSONObject, error) { + return jsonutils.Marshal(opt), nil +} + +type HostRemoveSecretLevelOptions struct { + options.BaseIdOptions + Force bool `json:"force"` +} + +func (opt *HostRemoveSecretLevelOptions) Params() (jsonutils.JSONObject, error) { + return jsonutils.Marshal(opt), nil +}