mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #13371 from rainzm/secret/resource
Classification of resources
This commit is contained in:
@@ -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("class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{})
|
||||
|
||||
cmd.BatchPerform("enable", &options.BaseIdsOptions{})
|
||||
cmd.BatchPerform("disable", &options.BaseIdsOptions{})
|
||||
|
||||
@@ -31,6 +31,8 @@ func init() {
|
||||
cmd.List(&identity_options.ProjectListOptions{})
|
||||
cmd.Perform("user-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("set-user-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.GetProperty(&identity_options.ProjectGetPropertyTagValuePairOptions{})
|
||||
cmd.GetProperty(&identity_options.ProjectGetPropertyTagValueTreeOptions{})
|
||||
cmd.GetProperty(&identity_options.ProjectGetPropertyDomainTagValuePairOptions{})
|
||||
|
||||
@@ -20,4 +20,5 @@ const (
|
||||
CLOUD_TAG_PREFIX = apis.CLOUD_TAG_PREFIX
|
||||
USER_TAG_PREFIX = apis.USER_TAG_PREFIX
|
||||
SYS_CLOUD_TAG_PREFIX = apis.SYS_CLOUD_TAG_PREFIX
|
||||
CLASS_TAT_PREFIX = apis.CLASS_TAT_PREFIX
|
||||
)
|
||||
|
||||
@@ -26,6 +26,10 @@ type CachedImageUncacheImageInput struct {
|
||||
IsForce bool `json:"is_force"`
|
||||
}
|
||||
|
||||
type CachedImageManagerCacheImageInput struct {
|
||||
ImageId string `json:"image_id"`
|
||||
}
|
||||
|
||||
type CachedimageDetails struct {
|
||||
apis.SharableVirtualResourceDetails
|
||||
|
||||
@@ -54,3 +58,7 @@ type CachedimageDetails struct {
|
||||
// example: 0
|
||||
CachedCount int `json:"cached_count"`
|
||||
}
|
||||
|
||||
type CachedImageSetClassMetadataInput struct {
|
||||
ClassMetadata map[string]string `json:"class_metadata"`
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ const (
|
||||
CLOUD_TAG_PREFIX = "ext:"
|
||||
USER_TAG_PREFIX = "user:"
|
||||
SYS_CLOUD_TAG_PREFIX = "sys:"
|
||||
// Such tags have inherited and isolated properties
|
||||
CLASS_TAT_PREFIX = "cls:"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -35,6 +35,8 @@ const (
|
||||
IMAGE_STATUS_DELETED = "deleted"
|
||||
IMAGE_STATUS_PENDING_DELETE = "pending_delete"
|
||||
|
||||
IMAGE_STATUS_SYNC_CLASS_METADATA_FAILEd = "sync_class_metadata_failed"
|
||||
|
||||
ImageTypeTemplate = TImageType("image")
|
||||
ImageTypeISO = TImageType("iso")
|
||||
|
||||
|
||||
@@ -344,6 +344,12 @@ type PerformUserMetadataInput map[string]string
|
||||
// 全量替换资源的用户标签(元数据)输入
|
||||
type PerformSetUserMetadataInput map[string]string
|
||||
|
||||
type PerformClassMetadataInput map[string]string
|
||||
|
||||
type PerformSetClassMetadataInput map[string]string
|
||||
|
||||
type GetClassMetadataOutput map[string]string
|
||||
|
||||
// 获取资源的元数据输入
|
||||
type GetMetadataInput struct {
|
||||
// 指定需要获取的所有标签的KEY列表,如果列表为空,则获取全部标签
|
||||
|
||||
@@ -64,6 +64,9 @@ type ServerConfig struct {
|
||||
GroupRelations []*GroupRelation `json:"group_releations"`
|
||||
Groups interface{} `json:"groups"`
|
||||
Id string `json:"id"`
|
||||
|
||||
InstanceSnapshotId string `json:"instance_snapshot_id"`
|
||||
InstanceBackupId string `json:"instance_backup_id"`
|
||||
}
|
||||
|
||||
// ScheduleInput used by scheduler sync-schedule/test/forecast api
|
||||
|
||||
@@ -45,6 +45,7 @@ const (
|
||||
CLOUD_TAG_PREFIX = dbapi.CLOUD_TAG_PREFIX
|
||||
USER_TAG_PREFIX = dbapi.USER_TAG_PREFIX
|
||||
SYS_CLOUD_TAG_PREFIX = dbapi.SYS_CLOUD_TAG_PREFIX
|
||||
CLASS_TAG_PREFIX = dbapi.CLASS_TAT_PREFIX
|
||||
|
||||
// TAG_DELETE_RANGE_USER = "user"
|
||||
// TAG_DELETE_RANGE_CLOUD = CLOUD_TAG_PREFIX // "cloud"
|
||||
@@ -602,14 +603,15 @@ func (manager *SMetadataManager) rawSetValues(ctx context.Context, objType strin
|
||||
if replace {
|
||||
records := []SMetadata{}
|
||||
q := manager.Query().Equals("id", idStr).NotLike("key", `\_\_%`) //避免删除系统内置的metadata, _ 在mysql里面有特殊含义,需要转义
|
||||
switch replaceRange {
|
||||
case USER_TAG_PREFIX:
|
||||
q = q.Startswith("key", USER_TAG_PREFIX)
|
||||
case CLOUD_TAG_PREFIX:
|
||||
q = q.Startswith("key", CLOUD_TAG_PREFIX)
|
||||
case SYS_CLOUD_TAG_PREFIX:
|
||||
q = q.Startswith("key", SYS_CLOUD_TAG_PREFIX)
|
||||
}
|
||||
// switch replaceRange {
|
||||
// case USER_TAG_PREFIX:
|
||||
// q = q.Startswith("key", USER_TAG_PREFIX)
|
||||
// case CLOUD_TAG_PREFIX:
|
||||
// q = q.Startswith("key", CLOUD_TAG_PREFIX)
|
||||
// case SYS_CLOUD_TAG_PREFIX:
|
||||
// q = q.Startswith("key", SYS_CLOUD_TAG_PREFIX)
|
||||
// }
|
||||
q = q.Startswith("key", replaceRange)
|
||||
q = q.Filter(sqlchemy.NOT(sqlchemy.In(q.Field("key"), keys)))
|
||||
if err := FetchModelObjects(manager, q, &records); err != nil {
|
||||
log.Errorf("failed to fetch metadata error: %v", err)
|
||||
|
||||
@@ -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/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/tagutils"
|
||||
@@ -274,6 +275,70 @@ func (model *SStandaloneAnonResourceBase) SetCloudMetadataAll(ctx context.Contex
|
||||
return Metadata.SetAll(ctx, model, userTags, userCred, USER_TAG_PREFIX)
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) SetClassMetadataValues(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
err := Metadata.SetValuesWithLog(ctx, model, dictstore, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetValuesWithLog")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) SetClassMetadataAll(ctx context.Context, dictstore map[string]string, userCred mcclient.TokenCredential) error {
|
||||
afterCheck := make(map[string]interface{}, len(dictstore))
|
||||
for k, v := range dictstore {
|
||||
if !strings.HasPrefix(k, CLASS_TAG_PREFIX) {
|
||||
afterCheck[CLASS_TAG_PREFIX+k] = v
|
||||
} else {
|
||||
afterCheck[k] = v
|
||||
}
|
||||
}
|
||||
err := Metadata.SetAll(ctx, model, afterCheck, userCred, CLASS_TAG_PREFIX)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetAll")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) Inherit(ctx context.Context, sonModel *SStandaloneAnonResourceBase) error {
|
||||
metadata, err := model.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetAllPureMetadata")
|
||||
}
|
||||
if len(metadata) == 0 {
|
||||
return nil
|
||||
}
|
||||
userCred := auth.AdminCredential()
|
||||
return sonModel.SetClassMetadataAll(ctx, metadata, userCred)
|
||||
}
|
||||
|
||||
type IClassMetadataOwner interface {
|
||||
GetAllClassMetadata() (map[string]string, error)
|
||||
}
|
||||
|
||||
func IsInSameClass(ctx context.Context, cmo1, cmo2 IClassMetadataOwner) (bool, error) {
|
||||
pureTags, err := cmo1.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "GetAllPureMetadata")
|
||||
}
|
||||
pureTagsP, err := cmo2.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "GetAllPureMetadata")
|
||||
}
|
||||
if len(pureTags) != len(pureTagsP) {
|
||||
return false, nil
|
||||
}
|
||||
for k, v := range pureTags {
|
||||
if vp, ok := pureTagsP[k]; !ok || vp != v {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) IsInSameClass(ctx context.Context, pModel *SStandaloneAnonResourceBase) (bool, error) {
|
||||
return IsInSameClass(ctx, model, pModel)
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) SetSysCloudMetadataAll(ctx context.Context, dictstore map[string]interface{}, userCred mcclient.TokenCredential) error {
|
||||
err := Metadata.SetAll(ctx, model, dictstore, userCred, SYS_CLOUD_TAG_PREFIX)
|
||||
if err != nil {
|
||||
@@ -326,6 +391,18 @@ func (model *SStandaloneAnonResourceBase) GetAllCloudMetadata() (map[string]stri
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) GetAllClassMetadata() (map[string]string, error) {
|
||||
meta, err := Metadata.GetAll(nil, model, nil, CLASS_TAG_PREFIX, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Metadata.GetAll")
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
for k, v := range meta {
|
||||
ret[k[len(CLASS_TAG_PREFIX):]] = v
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// 获取资源标签(元数据)
|
||||
func (model *SStandaloneAnonResourceBase) GetDetailsMetadata(ctx context.Context, userCred mcclient.TokenCredential, input apis.GetMetadataInput) (apis.GetMetadataOutput, error) {
|
||||
val, err := Metadata.GetAll(ctx, model, input.Field, input.Prefix, userCred)
|
||||
@@ -393,6 +470,42 @@ func (model *SStandaloneAnonResourceBase) PerformSetUserMetadata(ctx context.Con
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 更新资源的 class 标签
|
||||
func (model *SStandaloneAnonResourceBase) PerformClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
dictStore := make(map[string]interface{})
|
||||
for k, v := range input {
|
||||
dictStore[CLASS_TAG_PREFIX+k] = v
|
||||
}
|
||||
err := model.SetUserMetadataValues(ctx, dictStore, userCred)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SetUserMetadataValues")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 全量替换资源的所有 class 标签
|
||||
func (model *SStandaloneAnonResourceBase) PerformSetClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformSetClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
dictStore := make(map[string]string)
|
||||
for k, v := range input {
|
||||
if len(k) > 64-len(CLASS_TAG_PREFIX) {
|
||||
return nil, httperrors.NewInputParameterError("input key too long > %d", 64-len(CLASS_TAG_PREFIX))
|
||||
}
|
||||
if len(v) > 65535 {
|
||||
return nil, httperrors.NewInputParameterError("input value too long > %d", 65535)
|
||||
}
|
||||
dictStore[k] = v
|
||||
}
|
||||
err := model.SetClassMetadataAll(ctx, dictStore, userCred)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SetUserMetadataAll")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (model *SStandaloneAnonResourceBase) GetDetailsClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, input apis.GetClassMetadataOutput) (apis.GetClassMetadataOutput, error) {
|
||||
return model.GetAllClassMetadata()
|
||||
}
|
||||
|
||||
type sPolicyTags struct {
|
||||
PolicyObjectTags tagutils.TTagSetList `json:"policy_object_tags"`
|
||||
PolicyProjectTags tagutils.TTagSetList `json:"policy_project_tags"`
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -520,3 +521,26 @@ func (tenant *STenant) IsDomain() bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (tenant *STenant) objType() string {
|
||||
if tenant.IsDomain() {
|
||||
return "domain"
|
||||
} else {
|
||||
return "project"
|
||||
}
|
||||
}
|
||||
|
||||
func (tenant *STenant) GetAllClassMetadata() (map[string]string, error) {
|
||||
meta, err := Metadata.rawGetAll(tenant.objType(), tenant.GetId(), nil, CLASS_TAG_PREFIX)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "rawGetAll")
|
||||
}
|
||||
ret := make(map[string]string)
|
||||
for k, v := range meta {
|
||||
if strings.HasPrefix(k, SYSTEM_ADMIN_PREFIX) {
|
||||
continue
|
||||
}
|
||||
ret[k[len(CLASS_TAG_PREFIX):]] = v
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -282,6 +282,18 @@ func (model *SVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred
|
||||
return model.SStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
|
||||
}
|
||||
|
||||
func (model *SVirtualResourceBase) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
project, err := model.GetTenantCache(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("unable to GetTenantCache: %s", err.Error())
|
||||
return
|
||||
}
|
||||
err = project.Inherit(ctx, &model.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
log.Errorf("unable to inherit class metadata from poject %s: %s", project.GetId(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SVirtualResourceBaseManager) FetchCustomizeColumns(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
@@ -416,6 +428,27 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
|
||||
log.Warningf("tenant_id %s not found", model.ProjectId)
|
||||
formerObj := NewTenant(model.ProjectId, "unknown", model.DomainId, "unknown")
|
||||
former = &formerObj
|
||||
} else {
|
||||
// check fromer's class metadata
|
||||
cm, err := former.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to GetAllClassMetadata")
|
||||
}
|
||||
if len(cm) > 0 {
|
||||
return nil, httperrors.NewForbiddenError("can't change owner for resource in project with class metadata")
|
||||
}
|
||||
}
|
||||
|
||||
toer, err := TenantCacheManager.FetchTenantById(ctx, ownerId.GetProjectId())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to get project %s", ownerId.GetProjectId())
|
||||
}
|
||||
toCm, err := toer.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to GetAllClassMetadata")
|
||||
}
|
||||
if model.Keyword() != "image" && len(toCm) > 0 {
|
||||
return nil, httperrors.NewForbiddenError("can't change resource's owner as that in project with class metadata")
|
||||
}
|
||||
|
||||
// clean shared projects before update project id
|
||||
@@ -461,6 +494,13 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC
|
||||
NewDomainId: ownerId.GetProjectDomainId(),
|
||||
NewDomain: ownerId.GetProjectDomain(),
|
||||
}
|
||||
|
||||
// set class metadata
|
||||
|
||||
err = model.SetClassMetadataAll(ctx, toCm, userCred)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to SetClassMetadataAll")
|
||||
}
|
||||
logclient.AddActionLogWithContext(ctx, model, logclient.ACT_CHANGE_OWNER, notes, userCred, true)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -262,6 +262,14 @@ func (db *SDiskBackup) CustomizeCreate(ctx context.Context, userCred mcclient.To
|
||||
|
||||
func (db *SDiskBackup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
db.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
|
||||
disk, err := db.GetDisk()
|
||||
if err != nil {
|
||||
log.Errorf("unable to GetDisk: %s", err.Error())
|
||||
}
|
||||
err = disk.Inherit(ctx, &db.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
log.Errorf("unable to inherit from disk %s to backup %s: %s", disk.GetId(), db.GetId(), err.Error())
|
||||
}
|
||||
db.StartBackupCreateTask(ctx, userCred, nil, "")
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,21 @@ func (self *SCachedimage) GetImage() (*cloudprovider.SImage, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SCachedimage) syncClassMetadata(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
session := auth.GetSessionWithInternal(ctx, userCred, "", "")
|
||||
ret, err := image.Images.GetSpecific(session, self.Id, "class-metadata", nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to get class_metadata")
|
||||
}
|
||||
classMetadata := make(map[string]string, 0)
|
||||
err = ret.Unmarshal(&classMetadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return self.SetClassMetadataAll(ctx, classMetadata, userCred)
|
||||
}
|
||||
|
||||
func (manager *SCachedimageManager) cacheGlanceImageInfo(ctx context.Context, userCred mcclient.TokenCredential, info jsonutils.JSONObject) (*SCachedimage, error) {
|
||||
lockman.LockRawObject(ctx, manager.Keyword(), "name")
|
||||
defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
|
||||
@@ -254,6 +269,7 @@ func (manager *SCachedimageManager) cacheGlanceImageInfo(ctx context.Context, us
|
||||
}
|
||||
db.OpsLog.LogEvent(&imageCache, db.ACT_CREATE, info, userCred)
|
||||
|
||||
imageCache.syncClassMetadata(ctx, userCred)
|
||||
return &imageCache, nil
|
||||
} else {
|
||||
log.Errorf("fetching image cache (%s) failed: %s", img.Id, err)
|
||||
@@ -297,6 +313,28 @@ func (image *SCachedimage) GetStorages() ([]SStorage, error) {
|
||||
return storages, nil
|
||||
}
|
||||
|
||||
func (manager *SCachedimageManager) GetCachedimageById(ctx context.Context, imageId string) (*SCachedimage, error) {
|
||||
img, err := manager.FetchById(imageId)
|
||||
if err == nil {
|
||||
return img.(*SCachedimage), nil
|
||||
}
|
||||
if errors.Cause(err) != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
s := auth.GetAdminSession(ctx, options.Options.Region, "")
|
||||
obj, err := image.Images.Get(s, imageId, nil)
|
||||
if err != nil {
|
||||
log.Errorf("GetImageById %s error %s", imageId, err)
|
||||
return nil, errors.Wrap(err, "modules.Images.Get")
|
||||
}
|
||||
userCred := s.GetToken()
|
||||
cachedImage, err := manager.cacheGlanceImageInfo(ctx, userCred, obj)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "manager.cacheGlanceImageInfo")
|
||||
}
|
||||
return cachedImage, nil
|
||||
}
|
||||
|
||||
func (manager *SCachedimageManager) GetImageById(ctx context.Context, userCred mcclient.TokenCredential, imageId string, refresh bool) (*cloudprovider.SImage, error) {
|
||||
imgObj, _ := manager.FetchById(imageId)
|
||||
if imgObj != nil {
|
||||
@@ -408,6 +446,22 @@ func (self *SCachedimage) PerformUncacheImage(ctx context.Context, userCred mccl
|
||||
return storagecache.PerformUncacheImage(ctx, userCred, query, jsonutils.Marshal(map[string]interface{}{"image": self.Id, "is_force": input.IsForce}))
|
||||
}
|
||||
|
||||
func (self *SCachedimageManager) PerformCacheImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CachedImageManagerCacheImageInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.ImageId) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("image_id")
|
||||
}
|
||||
s := auth.GetAdminSession(ctx, options.Options.Region, "")
|
||||
obj, err := image.Images.Get(s, input.ImageId, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "modules.Images.Get")
|
||||
}
|
||||
_, err = self.cacheGlanceImageInfo(ctx, userCred, obj)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "manager.cacheGlanceImageInfo")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SCachedimage) addRefCount() {
|
||||
if self.GetStatus() != api.CACHED_IMAGE_STATUS_ACTIVE {
|
||||
return
|
||||
|
||||
@@ -1044,6 +1044,17 @@ func (self *SDisk) PrepareSaveImage(ctx context.Context, userCred mcclient.Token
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// check class metadata
|
||||
cm, err := self.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to GetAllClassMetadata")
|
||||
}
|
||||
if len(cm) > 0 {
|
||||
_, err = image.Images.PerformAction(us, imageId, "set-class-metadata", jsonutils.Marshal(cm))
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to SetClassMetadata for image %s", imageId)
|
||||
}
|
||||
}
|
||||
return imageId, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,18 @@ func (self *SGuest) PerformSaveGuestImage(ctx context.Context, userCred mcclient
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
guestImageId, _ := ret.GetString("id")
|
||||
// set class metadata
|
||||
cm, err := self.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to GetAllClassMetadata")
|
||||
}
|
||||
if len(cm) > 0 {
|
||||
_, err = image.Images.PerformAction(s, guestImageId, "set-class-metadata", jsonutils.Marshal(cm))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to SetClassMetadata for guest image %s", guestImageId)
|
||||
}
|
||||
}
|
||||
guestImageInfo := struct {
|
||||
RootImage imageapi.SubImageInfo
|
||||
DataImages []imageapi.SubImageInfo
|
||||
@@ -719,6 +731,13 @@ func (self *SGuest) ValidateAttachDisk(ctx context.Context, disk *SDisk) error {
|
||||
if !utils.IsInStringArray(self.Status, guestStatus) {
|
||||
return httperrors.NewInputParameterError("Guest %s not support attach disk in status %s", self.Name, self.Status)
|
||||
}
|
||||
ok, err := self.IsInSameClass(ctx, &disk.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return httperrors.NewForbiddenError("the class metadata of guest and disk is different")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4694,6 +4713,10 @@ func (self *SGuest) PerformInstanceSnapshot(
|
||||
ctx, userCred, pendingUsage, pendingUsage, false)
|
||||
return nil, httperrors.NewInternalServerError("create instance snapshot failed: %s", err)
|
||||
}
|
||||
err = self.Inherit(ctx, &instanceSnapshot.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to inherit from guest %s to instance snapshot %s", self.GetId(), instanceSnapshot.GetId())
|
||||
}
|
||||
err = self.InstaceCreateSnapshot(ctx, userCred, instanceSnapshot, pendingUsage)
|
||||
if err != nil {
|
||||
quotas.CancelPendingUsage(
|
||||
@@ -4723,6 +4746,10 @@ func (self *SGuest) PerformInstanceBackup(ctx context.Context, userCred mcclient
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("create instance backup failed: %s", err)
|
||||
}
|
||||
err = self.Inherit(ctx, &instanceBackup.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to inherit from guest %s to instance backup %s", self.GetId(), instanceBackup.GetId())
|
||||
}
|
||||
err = self.InstanceCreateBackup(ctx, userCred, instanceBackup)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("start create backup task failed: %s", err)
|
||||
|
||||
@@ -3806,6 +3806,10 @@ func (self *SGuest) createDiskOnHost(
|
||||
if autoAttach {
|
||||
err = self.attach2Disk(ctx, disk, userCred, diskConfig.Driver, diskConfig.Cache, diskConfig.Mountpoint)
|
||||
}
|
||||
err = self.Inherit(ctx, &disk.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to inherit from guest %s to disk %s", self.GetId(), disk.GetId())
|
||||
}
|
||||
return disk, err
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,14 @@ func (snapshot *SSnapshot) PostCreate(ctx context.Context, userCred mcclient.Tok
|
||||
if err != nil {
|
||||
log.Errorf("quotas.CancelPendingUsage fail %s", err)
|
||||
}
|
||||
disk, err := snapshot.GetDisk()
|
||||
if err != nil {
|
||||
log.Errorf("unable to GetDisk: %s", err.Error())
|
||||
}
|
||||
err = disk.Inherit(ctx, &snapshot.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
log.Errorf("unable to inherit from disk %s to snapshot %s: %s", disk.GetId(), snapshot.GetId(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SSnapshotManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
|
||||
@@ -1127,6 +1127,11 @@ func (self *SKVMRegionDriver) RequestCreateInstanceSnapshot(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
|
||||
err = isp.Inherit(ctx, &snapshot.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to inherit from instance snapshot %s to snapshot %s", isp.GetId(), snapshot.GetId())
|
||||
}
|
||||
|
||||
err = models.InstanceSnapshotJointManager.CreateJoint(ctx, isp.Id, snapshot.Id, int8(diskIndex))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1274,6 +1279,10 @@ func (self *SKVMRegionDriver) RequestCreateInstanceBackup(ctx context.Context, g
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ib.Inherit(ctx, &backup.SStandaloneAnonResourceBase)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to inherit from instance backup %s to backup %s", ib.GetId(), backup.GetId())
|
||||
}
|
||||
err = models.InstanceBackupJointManager.CreateJoint(ctx, ib.Id, backup.Id, int8(i))
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -652,3 +652,21 @@ func (gi *SGuestImage) GetUsages() []db.IUsage {
|
||||
}
|
||||
return usages
|
||||
}
|
||||
|
||||
func (img *SGuestImage) PerformSetClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformSetClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
ret, err := img.SStandaloneAnonResourceBase.PerformSetClassMetadata(ctx, userCred, query, input)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
images, err := GuestImageJointManager.GetImagesByGuestImageId(img.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range images {
|
||||
_, err := images[i].PerformSetClassMetadata(ctx, userCred, query, input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to PerformSetClassMetadata for image %s", images[i].GetId())
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -1536,6 +1536,20 @@ func (img *SImage) PerformUpdateStatus(ctx context.Context, userCred mcclient.To
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (img *SImage) PerformSetClassMetadata(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformSetClassMetadataInput) (jsonutils.JSONObject, error) {
|
||||
ret, err := img.SStandaloneAnonResourceBase.PerformSetClassMetadata(ctx, userCred, query, input)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "ImageSyncClassMetadataTask", img, userCred, nil, "", "", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
task.ScheduleRun(nil)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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 tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/image"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/image/models"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type ImageSyncClassMetadataTask struct {
|
||||
taskman.STask
|
||||
}
|
||||
|
||||
func init() {
|
||||
taskman.RegisterTask(ImageSyncClassMetadataTask{})
|
||||
}
|
||||
|
||||
func (self *ImageSyncClassMetadataTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
img := obj.(*models.SImage)
|
||||
cm, err := img.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, img, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
}
|
||||
session := auth.GetAdminSession(ctx, "", "")
|
||||
_, err = compute.Cachedimages.PerformAction(session, img.Id, "set-class-metadata", jsonutils.Marshal(cm))
|
||||
if err == nil {
|
||||
self.taskSuccess(ctx, img)
|
||||
return
|
||||
}
|
||||
if errors.Cause(err) != httperrors.ErrResourceNotFound {
|
||||
self.taskFailed(ctx, img, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
params.Set("image_id", jsonutils.NewString(img.Id))
|
||||
_, err = compute.Cachedimages.PerformClassAction(session, "cache-image", params)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, img, jsonutils.NewString(err.Error()))
|
||||
return
|
||||
}
|
||||
self.taskSuccess(ctx, img)
|
||||
}
|
||||
|
||||
func (self *ImageSyncClassMetadataTask) taskFailed(ctx context.Context, image *models.SImage, reason jsonutils.JSONObject) {
|
||||
reasonStr, _ := reason.GetString()
|
||||
image.SetStatus(self.UserCred, api.IMAGE_STATUS_SYNC_CLASS_METADATA_FAILEd, reasonStr)
|
||||
logclient.AddActionLogWithStartable(self, image, logclient.ACT_SYNC_CLASS_METADATA, reason, self.UserCred, false)
|
||||
self.SetStageFailed(ctx, reason)
|
||||
}
|
||||
|
||||
func (self *ImageSyncClassMetadataTask) taskSuccess(ctx context.Context, image *models.SImage) {
|
||||
logclient.AddActionLogWithStartable(self, image, logclient.ACT_SYNC_CLASS_METADATA, nil, self.UserCred, true)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// 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 predicates
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/scheduler/core"
|
||||
)
|
||||
|
||||
type ClassMetadataPredicate struct {
|
||||
BasePredicate
|
||||
|
||||
guestSource *ResourceWithClassMetadata
|
||||
tenant *ResourceWithClassMetadata
|
||||
}
|
||||
|
||||
type ResourceWithClassMetadata struct {
|
||||
keyword string
|
||||
name string
|
||||
classMedata map[string]string
|
||||
}
|
||||
|
||||
func (rcm *ResourceWithClassMetadata) GetAllClassMetadata() (map[string]string, error) {
|
||||
return rcm.classMedata, nil
|
||||
}
|
||||
|
||||
func (rcm *ResourceWithClassMetadata) GetDescription() string {
|
||||
return fmt.Sprintf("%s %s", rcm.keyword, rcm.name)
|
||||
}
|
||||
|
||||
func (p *ClassMetadataPredicate) Name() string {
|
||||
return "class_metadata"
|
||||
}
|
||||
|
||||
func (p *ClassMetadataPredicate) Clone() core.FitPredicate {
|
||||
return &ClassMetadataPredicate{
|
||||
guestSource: p.guestSource,
|
||||
tenant: p.tenant,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ClassMetadataPredicate) PreExecute(u *core.Unit, cs []core.Candidater) (bool, error) {
|
||||
info := u.SchedData()
|
||||
tenant, err := db.TenantCacheManager.FetchTenantById(context.Background(), info.Project)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch tenant %s", info.Project)
|
||||
}
|
||||
tcm, err := tenant.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to GetAllClassMetadata of project %s", info.Project)
|
||||
}
|
||||
p.tenant = &ResourceWithClassMetadata{
|
||||
classMedata: tcm,
|
||||
keyword: tenant.Keyword(),
|
||||
name: tenant.GetName(),
|
||||
}
|
||||
|
||||
// guest source
|
||||
guestSource := &ResourceWithClassMetadata{}
|
||||
disks := info.Disks
|
||||
var stand *db.SStandaloneAnonResourceBase
|
||||
// TODO GuestImage
|
||||
switch {
|
||||
case len(info.InstanceBackupId) > 0:
|
||||
obj, err := models.InstanceBackupManager.FetchById(info.InstanceBackupId)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch instanceBackup %s", info.InstanceSnapshotId)
|
||||
}
|
||||
stand = &obj.(*models.SInstanceBackup).SStandaloneAnonResourceBase
|
||||
case len(info.InstanceSnapshotId) > 0:
|
||||
obj, err := models.InstanceSnapshotManager.FetchById(info.InstanceSnapshotId)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch instanceSnapshot %s", info.InstanceSnapshotId)
|
||||
}
|
||||
stand = &obj.(*models.SInstanceSnapshot).SStandaloneAnonResourceBase
|
||||
case len(disks) == 0:
|
||||
case disks[0].ImageId != "":
|
||||
obj, err := models.CachedimageManager.GetCachedimageById(context.Background(), disks[0].ImageId)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch cachedimage %s", disks[0].ImageId)
|
||||
}
|
||||
stand = &obj.SStandaloneAnonResourceBase
|
||||
guestSource.keyword = "image"
|
||||
case disks[0].SnapshotId != "":
|
||||
obj, err := models.SnapshotManager.FetchById(disks[0].SnapshotId)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch snapshot %s", disks[0].SnapshotId)
|
||||
}
|
||||
stand = &obj.(*models.SSnapshot).SStandaloneAnonResourceBase
|
||||
case disks[0].BackupId != "":
|
||||
obj, err := models.DiskBackupManager.FetchById(disks[0].BackupId)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to fetch diskbackup %s", disks[0].BackupId)
|
||||
}
|
||||
stand = &obj.(*models.SDiskBackup).SStandaloneAnonResourceBase
|
||||
}
|
||||
if stand == nil {
|
||||
return true, nil
|
||||
}
|
||||
cm, err := stand.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "unable to GetAllClassMetadata %s", stand.GetId())
|
||||
}
|
||||
guestSource.classMedata = cm
|
||||
if guestSource.keyword == "" {
|
||||
guestSource.keyword = stand.Keyword()
|
||||
}
|
||||
guestSource.name = stand.GetName()
|
||||
p.guestSource = guestSource
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *ClassMetadataPredicate) Execute(u *core.Unit, c core.Candidater) (bool, []core.PredicateFailureReason, error) {
|
||||
h := NewPredicateHelper(p, u, c)
|
||||
ctx := context.Background()
|
||||
for _, resource := range []*ResourceWithClassMetadata{p.tenant, p.guestSource} {
|
||||
ic, err := db.IsInSameClass(ctx, c.Getter(), resource)
|
||||
if err != nil {
|
||||
return false, nil, errors.Wrap(err, "unable to determine whether they are in a class")
|
||||
}
|
||||
if !ic {
|
||||
h.Exclude(fmt.Sprintf("The host doesn't have the same class metadata as the choosen %s.", resource.GetDescription()))
|
||||
break
|
||||
}
|
||||
}
|
||||
return h.GetResult()
|
||||
}
|
||||
@@ -35,6 +35,7 @@ func defaultPredicates() sets.String {
|
||||
factory.RegisterFitPredicate("d-GuestMigrateFilter", &predicateguest.MigratePredicate{}),
|
||||
factory.RegisterFitPredicate("e-GuestDomainFilter", &predicates.DomainPredicate{}),
|
||||
factory.RegisterFitPredicate("e-GuestImageFilter", &predicateguest.ImagePredicate{}),
|
||||
factory.RegisterFitPredicate("f-ClassMetadataFilter", &predicates.ClassMetadataPredicate{}),
|
||||
//factory.RegisterFitPredicate("f-GuestGroupFilter", &predicateguest.GroupPredicate{}),
|
||||
factory.RegisterFitPredicate("g-GuestCPUFilter", &predicateguest.CPUPredicate{}),
|
||||
factory.RegisterFitPredicate("h-GuestMemoryFilter", &predicateguest.MemoryPredicate{}),
|
||||
|
||||
+19
@@ -56,6 +56,8 @@ type BaseHostDesc struct {
|
||||
|
||||
SharedDomains []string `json:"shared_domains"`
|
||||
PendingUsage map[string]interface{} `json:"pending_usage"`
|
||||
|
||||
ClassMetadata map[string]string `json:"class_metadata"`
|
||||
}
|
||||
|
||||
type baseHostGetter struct {
|
||||
@@ -148,6 +150,10 @@ func (b baseHostGetter) InstanceGroups() map[string]*api.CandidateGroup {
|
||||
return b.h.InstanceGroups
|
||||
}
|
||||
|
||||
func (b baseHostGetter) GetAllClassMetadata() (map[string]string, error) {
|
||||
return b.h.ClassMetadata, nil
|
||||
}
|
||||
|
||||
func (b baseHostGetter) GetFreeGroupCount(groupId string) (int, error) {
|
||||
// Must Be
|
||||
scg, ok := b.h.InstanceGroups[groupId]
|
||||
@@ -333,6 +339,10 @@ func newBaseHostDesc(b *baseBuilder, host *computemodels.SHost) (*BaseHostDesc,
|
||||
return nil, fmt.Errorf("Fill instance group error: %v", err)
|
||||
}
|
||||
|
||||
if err := desc.fillClassMetadata(host); err != nil {
|
||||
return nil, fmt.Errorf("Fill class metadata error: %v", err)
|
||||
}
|
||||
|
||||
if err := desc.fillIpmiInfo(host); err != nil {
|
||||
return nil, fmt.Errorf("Fill ipmi info error: %v", err)
|
||||
}
|
||||
@@ -674,6 +684,15 @@ func (b *BaseHostDesc) fillInstanceGroups(host *computemodels.SHost) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseHostDesc) fillClassMetadata(host *computemodels.SHost) error {
|
||||
cm, err := host.GetAllClassMetadata()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.ClassMetadata = cm
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseHostDesc) fillIpmiInfo(host *computemodels.SHost) error {
|
||||
info, err := host.GetIpmiInfo()
|
||||
if err != nil {
|
||||
|
||||
@@ -106,6 +106,8 @@ type CandidatePropertyGetter interface {
|
||||
InstanceGroups() map[string]*api.CandidateGroup
|
||||
GetFreeGroupCount(groupId string) (int, error)
|
||||
|
||||
GetAllClassMetadata() (map[string]string, error)
|
||||
|
||||
GetIpmiInfo() types.SIPMIInfo
|
||||
|
||||
GetNics() []*types.SNic
|
||||
|
||||
@@ -369,6 +369,21 @@ func (mr *MockCandidatePropertyGetterMockRecorder) InstanceGroups() *gomock.Call
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceGroups", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).InstanceGroups))
|
||||
}
|
||||
|
||||
// GetAllClassMetadata mocks base method
|
||||
func (m *MockCandidatePropertyGetter) GetAllClassMetadata() (map[string]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InstanceGroups")
|
||||
ret0, _ := ret[0].(map[string]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetAllClassMetadata indicates an expected call of InstanceGroups
|
||||
func (mr *MockCandidatePropertyGetterMockRecorder) GetAllClassMetadata() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceGroups", reflect.TypeOf((*MockCandidatePropertyGetter)(nil).GetAllClassMetadata))
|
||||
}
|
||||
|
||||
// IsEmpty mocks base method
|
||||
func (m *MockCandidatePropertyGetter) IsEmpty() bool {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -216,4 +216,6 @@ const (
|
||||
ACT_RESTART_NETWORK = "restart_network"
|
||||
|
||||
ACT_RECOVERY = "recovery"
|
||||
|
||||
ACT_SYNC_CLASS_METADATA = "sync_class_metadata"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user