From 869b2493741e64bbd6e1807b7600d2b365760c68 Mon Sep 17 00:00:00 2001 From: Zexi Date: Sat, 13 Apr 2019 11:31:48 +0800 Subject: [PATCH] hide some server metadata --- pkg/apis/compute/guest_const.go | 11 +- pkg/cloudcommon/db/interface.go | 7 ++ pkg/cloudcommon/db/metadata.go | 28 +++++ pkg/cloudcommon/db/metadata_test.go | 165 ++++++++++++++++++++++++++++ pkg/compute/models/guest_actions.go | 6 +- pkg/compute/models/guests.go | 16 ++- 6 files changed, 224 insertions(+), 9 deletions(-) create mode 100644 pkg/cloudcommon/db/metadata_test.go diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index 89cb1b8165..a96c1889eb 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -188,6 +188,13 @@ var HOSTTYPE_HYPERVISOR = map[string]string{ const ( VM_AWS_DEFAULT_LOGIN_USER = "ec2user" - VM_METADATA_APP_TAGS = "app_tags" - VM_METADATA_CREATE_PARAMS = "create_params" + VM_METADATA_APP_TAGS = "app_tags" + VM_METADATA_CREATE_PARAMS = "create_params" + VM_METADATA_LOGIN_ACCOUNT = "login_account" + VM_METADATA_LOGIN_KEY = "login_key" + VM_METADATA_LOGIN_KEY_TIMESTAMP = "login_key_timestamp" + VM_METADATA_OS_ARCH = "os_arch" + VM_METADATA_OS_DISTRO = "os_distribution" + VM_METADATA_OS_NAME = "os_name" + VM_METADATA_OS_VERSION = "os_version" ) diff --git a/pkg/cloudcommon/db/interface.go b/pkg/cloudcommon/db/interface.go index f57f88cc91..a3c8f20feb 100644 --- a/pkg/cloudcommon/db/interface.go +++ b/pkg/cloudcommon/db/interface.go @@ -191,6 +191,13 @@ type IStandaloneModel interface { // GetExternalId() string } +type IMetadataModel interface { + IStandaloneModel + + GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) + GetMetadataHideKeys() []string +} + type IVirtualModelManager interface { IStandaloneModelManager } diff --git a/pkg/cloudcommon/db/metadata.go b/pkg/cloudcommon/db/metadata.go index 9e714f2347..f42c89c105 100644 --- a/pkg/cloudcommon/db/metadata.go +++ b/pkg/cloudcommon/db/metadata.go @@ -374,13 +374,41 @@ func (manager *SMetadataManager) GetAll(obj IModel, keys []string, userCred mccl } func (manager *SMetadataManager) IsSystemAdminKey(key string) bool { + return IsMetadataKeySystemAdmin(key) +} + +func IsMetadataKeySystemAdmin(key string) bool { return strings.HasPrefix(key, SYSTEM_ADMIN_PREFIX) } +func IsMetadataKeySysTag(key string) bool { + return strings.HasPrefix(key, SYS_TAG_PREFIX) +} + func (manager *SMetadataManager) GetSysadminKey(key string) string { return fmt.Sprintf("%s%s", SYSTEM_ADMIN_PREFIX, key) } +func IsMetadataKeyVisiable(key string) bool { + return !(IsMetadataKeySysTag(key) || IsMetadataKeySystemAdmin(key)) +} + +func GetVisiableMetadata(model IMetadataModel, userCred mcclient.TokenCredential) (map[string]string, error) { + metaData, err := model.GetAllMetadata(userCred) + if err != nil { + return nil, err + } + for _, key := range model.GetMetadataHideKeys() { + delete(metaData, key) + } + for key := range metaData { + if !IsMetadataKeyVisiable(key) { + delete(metaData, key) + } + } + return metaData, nil +} + /* @classmethod diff --git a/pkg/cloudcommon/db/metadata_test.go b/pkg/cloudcommon/db/metadata_test.go new file mode 100644 index 0000000000..6cf61e6894 --- /dev/null +++ b/pkg/cloudcommon/db/metadata_test.go @@ -0,0 +1,165 @@ +// 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 ( + "reflect" + "testing" + + "github.com/stretchr/testify/mock" + + "yunion.io/x/onecloud/pkg/mcclient" +) + +func TestIsMetadataKeySystemAdmin(t *testing.T) { + tests := []struct { + name string + key string + want bool + }{ + { + name: "__sys_key is system admin key", + key: "__sys_key", + want: true, + }, + { + name: "__sys is not system admin key", + key: "__sys", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsMetadataKeySystemAdmin(tt.key); got != tt.want { + t.Errorf("IsMetadataKeySystemAdmin() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsMetadataKeySysTag(t *testing.T) { + tests := []struct { + name string + key string + want bool + }{ + { + name: "__qemu_version is sys tag key", + key: "__qemu_version", + want: true, + }, + { + name: "_sys is not sys tag key", + key: "_sys", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsMetadataKeySysTag(tt.key); got != tt.want { + t.Errorf("IsMetadataKeySysTag() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsMetadataKeyVisiable(t *testing.T) { + tests := []struct { + name string + key string + want bool + }{ + { + name: "__qemu_version should not visiable", + key: "__qemu_version", + want: false, + }, + { + name: "__sys_key should not visiable", + key: "__sys_key", + want: false, + }, + { + name: "key1 should visiable", + key: "key1", + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := IsMetadataKeyVisiable(tt.key); got != tt.want { + t.Errorf("IsMetadataKeyVisiable() = %v, want %v", got, tt.want) + } + }) + } +} + +type MockMetadataModel struct { + mock.Mock + SStandaloneResourceBase +} + +func (m *MockMetadataModel) GetAllMetadata(userCred mcclient.TokenCredential) (map[string]string, error) { + args := m.Called(userCred) + return args.Get(0).(map[string]string), args.Error(1) +} + +func (m *MockMetadataModel) GetMetadataHideKeys() []string { + args := m.Called() + return args.Get(0).([]string) +} + +func TestGetVisiableMetadata(t *testing.T) { + testObj := new(MockMetadataModel) + testObj.On("GetAllMetadata", nil).Return( + map[string]string{ + "__os_profile__": "{\"disk_driver\":\"scsi\",\"fs_format\":\"ext4\",\"hypervisor\":\"kvm\",\"net_driver\":\"virtio\",\"os_type\":\"Linux\"}", + "login_account": "root", + "os_arch": "x86_64", + "os_distribution": "CentOS", + }, + nil, + ) + testObj.On("GetMetadataHideKeys").Return([]string{"login_account"}) + + tests := []struct { + name string + model IMetadataModel + want map[string]string + wantErr bool + }{ + { + name: "exclude sys tag and customize hide keys", + model: testObj, + want: map[string]string{ + "os_arch": "x86_64", + "os_distribution": "CentOS", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetVisiableMetadata(tt.model, nil) + if (err != nil) != tt.wantErr { + t.Errorf("GetVisiableMetadata() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetVisiableMetadata() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 6f099dc9b8..7e6c679dd0 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -643,11 +643,11 @@ func (self *SGuest) NotifyServerEvent(userCred mcclient.TokenCredential, event s kwargs.Add(jsonutils.NewString(self.Hypervisor), "hypervisor") if loginInfo { kwargs.Add(jsonutils.NewString(self.getNotifyIps()), "ips") - osName := meta["os_name"] + osName := meta[api.VM_METADATA_OS_NAME] if osName == "Windows" { kwargs.Add(jsonutils.JSONTrue, "windows") } - loginAccount := meta["login_account"] + loginAccount := meta[api.VM_METADATA_LOGIN_ACCOUNT] if len(loginAccount) > 0 { kwargs.Add(jsonutils.NewString(loginAccount), "account") } @@ -655,7 +655,7 @@ func (self *SGuest) NotifyServerEvent(userCred mcclient.TokenCredential, event s if len(keypair) > 0 { kwargs.Add(jsonutils.NewString(keypair), "keypair") } else { - loginKey := meta["login_key"] + loginKey := meta[api.VM_METADATA_LOGIN_KEY] if len(loginKey) > 0 { passwd, err := utils.DescryptAESBase64(self.Id, loginKey) if err == nil { diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 580d7d35ea..f1d2e12be1 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -175,8 +175,8 @@ const ( const ( VM_AWS_DEFAULT_LOGIN_USER = "ec2user" - VM_METADATA_APP_TAGS = "app_tags" - VM_METADATA_CREATE_PARAMS = "create_params" + VM_METADATA_APP_TAGS = "app_tags" + VM_METADATA_CREATE_PARAMS = "create_params" ) var VM_RUNNING_STATUS = api.VM_RUNNING_STATUS @@ -1376,6 +1376,15 @@ func (self *SGuest) moreExtraInfo(extra *jsonutils.JSONDict, fields stringutils2 return extra } +func (self *SGuest) GetMetadataHideKeys() []string { + return []string{ + api.VM_METADATA_CREATE_PARAMS, + api.VM_METADATA_LOGIN_ACCOUNT, + api.VM_METADATA_LOGIN_KEY, + api.VM_METADATA_LOGIN_KEY_TIMESTAMP, + } +} + func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) { extra, err := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query) if err != nil { @@ -1397,7 +1406,7 @@ func (self *SGuest) GetExtraDetails(ctx context.Context, userCred mcclient.Token } } - if metaData, err := self.GetAllMetadata(userCred); err == nil { + if metaData, err := db.GetVisiableMetadata(self, userCred); err == nil { extra.Add(jsonutils.Marshal(metaData), "metadata") } @@ -3533,7 +3542,6 @@ func (self *SGuest) saveOsType(userCred mcclient.TokenCredential, osType string) } func (self *SGuest) SaveDeployInfo(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) { - // log.Infof("------SaveDeployInfo: %s", data.PrettyString()) info := make(map[string]interface{}) if data.Contains("os") { osName, _ := data.GetString("os")