| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- // 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"
- "fmt"
- "sort"
- "strings"
- "time"
- "golang.org/x/sync/errgroup"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/qemuimgfmt"
- "yunion.io/x/pkg/util/rbacscope"
- "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"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/httperrors"
- "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/rbacutils"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- type SGuestImageManager struct {
- db.SSharableVirtualResourceBaseManager
- db.SMultiArchResourceBaseManager
- db.SEncryptedResourceManager
- }
- var GuestImageManager *SGuestImageManager
- func init() {
- GuestImageManager = &SGuestImageManager{
- SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
- SGuestImage{},
- "guestimages_tbl",
- "guestimage",
- "guestimages",
- ),
- }
- GuestImageManager.SetVirtualObject(GuestImageManager)
- }
- type SGuestImage struct {
- db.SSharableVirtualResourceBase
- db.SMultiArchResourceBase
- db.SEncryptedResource
- Protected tristate.TriState `default:"true" list:"user" get:"user" create:"optional" update:"user"`
- }
- func (manager *SGuestImageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.GuestImageCreateInput) (api.GuestImageCreateInput, error) {
- var err error
- input.SharableVirtualResourceCreateInput, err = manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
- if err != nil {
- return input, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ValidateCreateData")
- }
- input.EncryptedResourceCreateInput, err = manager.SEncryptedResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EncryptedResourceCreateInput)
- if err != nil {
- return input, errors.Wrap(err, "SEncryptedResourceManager.ValidateCreateData")
- }
- imageNum := len(input.Images)
- if imageNum == 0 {
- return input, httperrors.NewMissingParameterError("images")
- }
- errs := make([]error, 0)
- for i := range input.Images {
- if len(input.Images[i].Id) > 0 {
- imgObj, err := ImageManager.FetchByIdOrName(ctx, userCred, input.Images[i].Id)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- errs = append(errs, httperrors.NewResourceNotFoundError2(ImageManager.Keyword(), input.Images[i].Id))
- } else {
- errs = append(errs, errors.Wrap(err, "FetchByIdOrName"))
- }
- continue
- }
- image := imgObj.(*SImage)
- if image.Status != api.IMAGE_STATUS_ACTIVE {
- errs = append(errs, httperrors.NewInvalidStatusError("image %s status %s expect active", image.Name, image.Status))
- continue
- }
- if !db.IsAllowGet(ctx, rbacscope.ScopeProject, userCred, image) {
- errs = append(errs, httperrors.NewForbiddenError("not allow to access %s", image.Name))
- continue
- }
- if i == 0 && image.IsData.IsTrue() {
- errs = append(errs, httperrors.NewInvalidStatusError("first image %s should not be a data image", image.Name))
- continue
- }
- input.Images[i].Id = image.Id
- }
- }
- if len(errs) > 0 {
- return input, errors.NewAggregate(errs)
- }
- input.DiskFormat = string(qemuimgfmt.QCOW2)
- pendingUsage := SQuota{Image: int(imageNum)}
- keys := imageCreateInput2QuotaKeys("qcow2", ownerId)
- pendingUsage.SetKeys(keys)
- if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
- return input, httperrors.NewOutOfQuotaError("%s", err)
- }
- return input, nil
- }
- func (gi *SGuestImage) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- err := gi.SSharableVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
- if err != nil {
- return err
- }
- gi.Status = api.IMAGE_STATUS_QUEUED
- return nil
- }
- func (gi *SGuestImage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- kwargs := data.(*jsonutils.JSONDict)
- // get image number
- // imageNumber, _ := kwargs.Int("image_number")
- // deal public params
- kwargs.Remove("size")
- kwargs.Remove("image_number")
- kwargs.Remove("name")
- kwargs.Remove("generate_name")
- if !kwargs.Contains("images") {
- return
- }
- images, _ := kwargs.GetArray("images")
- kwargs.Remove("images")
- // kwargs.Add(jsonutils.NewString(gi.Id), "guest_image_id")
- suc := true
- // HACK
- appParams := appsrv.AppContextGetParams(ctx)
- appParams.Request.ContentLength = 0
- creating := false
- for i := 0; i < len(images); i++ {
- log.Debugf("process subimg %d %s", i, images[i])
- subimg := api.GuestImageCreateInputSubimage{}
- err := images[i].Unmarshal(&subimg)
- if err != nil {
- // unlikely
- suc = false
- log.Errorf("UNLIKELY!!!!unmarshal image %d error %s", i, err)
- break
- }
- var image *SImage
- if len(subimg.Id) > 0 {
- // mark sub image as guest image
- imgObj, err := ImageManager.FetchById(subimg.Id)
- if err != nil {
- log.Errorf("FetchById %s fail: %s", subimg.Id, err)
- suc = false
- break
- }
- image = imgObj.(*SImage)
- if i > 0 {
- // mark none first image as data image
- err := image.markDataImage(userCred)
- if err != nil {
- log.Errorf("markDataImage %s fail: %s", image.Name, err)
- suc = false
- break
- }
- }
- } else {
- // create subimg
- params := jsonutils.DeepCopy(kwargs).(*jsonutils.JSONDict)
- params.Update(jsonutils.Marshal(subimg))
- params.Add(jsonutils.JSONTrue, "is_guest_image")
- if i == len(images)-1 {
- params.Add(jsonutils.NewString(fmt.Sprintf("%s-%s", gi.Name, "root")), "generate_name")
- } else {
- params.Add(jsonutils.NewString(fmt.Sprintf("%s-%s-%d", gi.Name, "data", i)), "generate_name")
- params.Add(jsonutils.JSONTrue, "is_data")
- }
- model, err := db.DoCreate(ImageManager, ctx, userCred, query, params, ownerId)
- if err != nil {
- suc = false
- break
- }
- func() {
- lockman.LockObject(ctx, model)
- defer lockman.ReleaseObject(ctx, model)
- model.PostCreate(ctx, userCred, ownerId, query, data)
- }()
- creating = true
- image = model.(*SImage)
- }
- _, err = GuestImageJointManager.CreateGuestImageJoint(ctx, gi.Id, image.Id)
- if err != nil {
- log.Errorf("join %s fail %s", image.Id, err)
- image.OnJointFailed(ctx, userCred)
- }
- }
- pendingUsage := SQuota{Image: len(images)}
- keys := imageCreateInput2QuotaKeys("qcow2", ownerId)
- pendingUsage.SetKeys(keys)
- quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
- if !suc {
- gi.SetStatus(ctx, userCred, api.IMAGE_STATUS_KILLED, "create subimage failed")
- } else if creating {
- gi.SetStatus(ctx, userCred, api.IMAGE_STATUS_SAVING, "")
- } else {
- gi.SetStatus(ctx, userCred, api.IMAGE_STATUS_ACTIVE, "")
- }
- }
- func (gi *SGuestImage) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
- if gi.Protected.IsTrue() {
- return httperrors.NewForbiddenError("image is protected")
- }
- return nil
- }
- func (gi *SGuestImage) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- log.Infof("image delete to nothing")
- return nil
- }
- func (gi *SGuestImage) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- // delete joint
- guestJoints, err := GuestImageJointManager.GetByGuestImageId(gi.Id)
- if err != nil {
- return errors.Wrap(err, "get guest image joint failed")
- }
- for i := range guestJoints {
- guestJoints[i].Delete(ctx, userCred)
- }
- return gi.SSharableVirtualResourceBase.Delete(ctx, userCred)
- }
- func (gi *SGuestImage) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- images, err := GuestImageJointManager.GetByGuestImageId(gi.Id)
- if err != nil {
- return errors.Wrap(err, "get images of guest images failed")
- }
- if len(images) == 0 {
- return gi.RealDelete(ctx, userCred)
- }
- overridePendingDelete := false
- purge := false
- if query != nil {
- overridePendingDelete = jsonutils.QueryBoolean(query, "override_pending_delete", false)
- purge = jsonutils.QueryBoolean(query, "purge", false)
- }
- if gi.Status == api.IMAGE_STATUS_QUEUED {
- gi.checkStatus(ctx, userCred)
- }
- if utils.IsInStringArray(gi.Status, []string{api.IMAGE_STATUS_QUEUED, api.IMAGE_STATUS_KILLED}) {
- overridePendingDelete = true
- }
- return gi.startDeleteTask(ctx, userCred, "", purge, overridePendingDelete)
- }
- func (gi *SGuestImage) startDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string,
- isPurge bool, overridePendingDelete bool) error {
- params := jsonutils.NewDict()
- if isPurge {
- params.Add(jsonutils.JSONTrue, "purge")
- }
- if overridePendingDelete {
- params.Add(jsonutils.JSONTrue, "override_pending_delete")
- }
- params.Add(jsonutils.NewString(gi.Status), "image_status")
- gi.SetStatus(ctx, userCred, api.IMAGE_STATUS_DEACTIVATED, "")
- if task, err := taskman.TaskManager.NewTask(ctx, "GuestImageDeleteTask", gi, userCred, params, parentTaskId, "",
- nil); err != nil {
- return err
- } else {
- task.ScheduleRun(nil)
- }
- return nil
- }
- func (gi *SGuestImage) PerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if gi.PendingDeleted && !gi.Deleted {
- err := gi.DoCancelPendingDelete(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "DoCancelPendingDelete")
- }
- gi.RecoverUsages(ctx, userCred)
- }
- return nil, nil
- }
- func (gi *SGuestImage) DoCancelPendingDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- subImages, err := GuestImageJointManager.GetByGuestImageId(gi.Id)
- if err != nil {
- return errors.Wrap(err, "GetImagesByGuestImageId")
- }
- for i := range subImages {
- image, err := subImages[i].GetImage()
- if err != nil {
- return errors.Wrapf(err, "subImages[%d].GetImage", i)
- }
- err = image.DoCancelPendingDelete(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "subimage %s cancel delete error", subImages[i].GetId())
- }
- }
- err = gi.SSharableVirtualResourceBase.DoCancelPendingDelete(ctx, userCred)
- if err != nil {
- return err
- }
- _, err = db.Update(gi, func() error {
- gi.Status = api.IMAGE_STATUS_ACTIVE
- return nil
- })
- return errors.Wrap(err, "guest image cancel delete error")
- }
- func (guestImage *SGuestImage) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
- out api.GuestImageDetails) api.GuestImageDetails {
- if guestImage.Status != api.IMAGE_STATUS_ACTIVE {
- guestImage.checkStatus(ctx, userCred)
- out.Status = guestImage.Status
- }
- images, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return out
- }
- var size int64 = 0
- if len(images) == 0 {
- out.Size = size
- return out
- }
- dataImages := make([]api.SubImageInfo, 0, len(images)-1)
- var rootImage *api.SubImageInfo
- for i := range images {
- image, err := images[i].GetImage()
- if err != nil {
- log.Errorf("subimage[%d].GetImage fail %s", i, err)
- continue
- }
- size += image.Size
- if !image.IsData.IsTrue() && rootImage == nil {
- rootImage = &api.SubImageInfo{
- ID: image.Id,
- Name: image.Name,
- MinDiskMB: image.MinDiskMB,
- DiskFormat: image.DiskFormat,
- Size: image.Size,
- Status: image.Status,
- CreatedAt: image.CreatedAt,
- EncryptKeyId: image.EncryptKeyId,
- DisableDelete: image.Protected.Bool(),
- }
- out.MinRamMb = image.MinRamMB
- out.DiskFormat = image.DiskFormat
- continue
- }
- dataImages = append(dataImages, api.SubImageInfo{
- ID: image.Id,
- Name: image.Name,
- MinDiskMB: image.MinDiskMB,
- DiskFormat: image.DiskFormat,
- Size: image.Size,
- Status: image.Status,
- CreatedAt: image.CreatedAt,
- EncryptKeyId: image.EncryptKeyId,
- DisableDelete: image.Protected.Bool(),
- })
- }
- // make sure that the sort of dataimage is fixed
- sort.Slice(dataImages, func(i, j int) bool {
- return dataImages[i].Name < dataImages[j].Name
- })
- out.Size = size
- out.DataImages = dataImages
- if rootImage != nil {
- out.RootImage = *rootImage
- // properties of root image
- properties, err := ImagePropertyManager.GetProperties(rootImage.ID)
- if err != nil {
- return out
- }
- propJson := jsonutils.NewDict()
- for k, v := range properties {
- propJson.Add(jsonutils.NewString(v), k)
- }
- out.Properties = propJson
- }
- out.DisableDelete = guestImage.Protected.Bool()
- return out
- }
- 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)
- encRows := manager.SEncryptedResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- for i := range rows {
- rows[i] = api.GuestImageDetails{
- SharableVirtualResourceDetails: virtRows[i],
- EncryptedResourceDetails: encRows[i],
- }
- guestImage := objs[i].(*SGuestImage)
- rows[i] = guestImage.getMoreDetails(ctx, userCred, query, rows[i])
- }
- return rows
- }
- func (guestImage *SGuestImage) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
- data jsonutils.JSONObject) {
- lockman.LockClass(ctx, ImageManager, db.GetLockClassKey(ImageManager, userCred))
- defer lockman.ReleaseClass(ctx, ImageManager, db.GetLockClassKey(ImageManager, userCred))
- err := guestImage.UpdateSubImage(ctx, userCred, data)
- if err != nil {
- logclient.AddSimpleActionLog(guestImage, logclient.ACT_UPDATE, nil, userCred, false)
- }
- }
- func (guestImage *SGuestImage) UpdateSubImage(ctx context.Context, userCred mcclient.TokenCredential,
- data jsonutils.JSONObject) error {
- subImages, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return errors.Wrap(err, "GetByGuestImageId")
- }
- dict := data.(*jsonutils.JSONDict)
- var g errgroup.Group
- for i := range subImages {
- img, err := subImages[i].GetImage()
- if err != nil {
- g.Go(func() error {
- return err
- })
- continue
- }
- if f, ok := guestImage.genUpdateImage(ctx, userCred, img, i, dict); ok {
- g.Go(f)
- }
- }
- return g.Wait()
- }
- func (guestImage *SGuestImage) genUpdateImage(ctx context.Context, userCred mcclient.TokenCredential, image *SImage,
- index int, dict *jsonutils.JSONDict) (func() error, bool) {
- if image.IsGuestImage.IsFalse() {
- return nil, false
- }
- if !dict.Contains("name") && image.IsData.IsTrue() {
- return nil, false
- }
- if image.IsData.IsTrue() {
- if !dict.Contains("name") {
- return nil, false
- }
- return func() error {
- lockman.LockRawObject(ctx, ImageManager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, ImageManager.Keyword(), "name")
- name, _ := dict.GetString("name")
- name, err := db.GenerateName(ctx, ImageManager, userCred, fmt.Sprintf("%s-%s-%d", name, "data", index))
- if err != nil {
- return errors.Wrap(err, "fail to generate unique name")
- }
- _, err = db.Update(image, func() error {
- image.Name = name
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "modify subimage's name failed")
- }
- return nil
- }, true
- }
- return func() error {
- if dict.Contains("name") {
- lockman.LockRawObject(ctx, ImageManager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, ImageManager.Keyword(), "name")
- name, _ := dict.GetString("name")
- name, err := db.GenerateName(ctx, ImageManager, userCred, fmt.Sprintf("%s-%s", name, "root"))
- if err != nil {
- return errors.Wrap(err, "fail to generate unique name")
- }
- _, err = db.Update(image, func() error {
- image.Name = name
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "modify subimage's name failed")
- }
- }
- if dict.Contains("properties") {
- props, _ := dict.Get("properties")
- err := ImagePropertyManager.SaveProperties(ctx, userCred, image.GetId(), props)
- if err != nil {
- return errors.Wrap(err, "save properties error")
- }
- }
- return nil
- }, true
- }
- var checkStatus = map[string]int{
- api.IMAGE_STATUS_ACTIVE: 1,
- api.IMAGE_STATUS_QUEUED: 2,
- api.IMAGE_STATUS_SAVING: 3,
- api.IMAGE_STATUS_DEACTIVATED: 4,
- api.IMAGE_STATUS_KILLED: 5,
- api.IMAGE_STATUS_UNKNOWN: 6,
- }
- func (guestImage *SGuestImage) checkStatus(ctx context.Context, userCred mcclient.TokenCredential) error {
- images, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return errors.Wrap(err, "GetByGuestImageId")
- }
- if len(images) == 0 {
- return nil
- }
- status := api.IMAGE_STATUS_ACTIVE
- for i := range images {
- imgStatus := ""
- image, err := images[i].GetImage()
- if err != nil {
- log.Errorf("subimage %d GetImage fail %s", i, err)
- imgStatus = api.IMAGE_STATUS_UNKNOWN
- } else {
- imgStatus = image.Status
- }
- if checkStatus[imgStatus] > checkStatus[status] {
- status = imgStatus
- }
- }
- if guestImage.Status != status {
- guestImage.SetStatus(ctx, userCred, status, "")
- guestImage.Status = status
- }
- return nil
- }
- func (guestImage *SGuestImage) getSize(ctx context.Context, userCred mcclient.TokenCredential) (int64, error) {
- images, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return 0, err
- }
- var size int64 = 0
- for i := range images {
- image, _ := images[i].GetImage()
- if image != nil {
- size += image.Size
- }
- }
- return size, nil
- }
- func (guestImage *SGuestImageManager) getExpiredPendingDeleteImages() []SGuestImage {
- deadline := time.Now().Add(time.Duration(-options.Options.PendingDeleteExpireSeconds) * time.Second)
- // there are so many common images of one guest image, so that batch shrink three times
- q := guestImage.Query().IsTrue("pending_deleted").LT("pending_deleted_at",
- deadline).Limit(options.Options.PendingDeleteMaxCleanBatchSize / 3)
- images := make([]SGuestImage, 0)
- err := db.FetchModelObjects(guestImage, q, &images)
- if err != nil {
- log.Errorf("fetch guest images error %s", err)
- return nil
- }
- return images
- }
- func (guestImage *SGuestImageManager) CleanPendingDeleteImages(ctx context.Context, userCred mcclient.TokenCredential,
- isStart bool) {
- images := guestImage.getExpiredPendingDeleteImages()
- if images == nil {
- return
- }
- for i := range images {
- images[i].startDeleteTask(ctx, userCred, "", false, true)
- }
- }
- func (guestImage *SGuestImage) PerformPublic(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input apis.PerformPublicProjectInput,
- ) (jsonutils.JSONObject, error) {
- images, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return nil, errors.Wrap(err, "fail to fetch subimages of guest image")
- }
- for i := range images {
- image, _ := images[i].GetImage()
- if image == nil {
- continue
- }
- _, err := image.performPublic(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrapf(err, "fail to public subimage %s", images[i].GetId())
- }
- }
- return guestImage.SSharableVirtualResourceBase.PerformPublic(ctx, userCred, query, input)
- }
- func (guestImage *SGuestImage) PerformPrivate(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input apis.PerformPrivateInput,
- ) (jsonutils.JSONObject, error) {
- images, err := GuestImageJointManager.GetByGuestImageId(guestImage.Id)
- if err != nil {
- return nil, errors.Wrap(err, "fail to fetch subimages of guest image")
- }
- for i := range images {
- image, _ := images[i].GetImage()
- if image == nil {
- continue
- }
- _, err := image.performPrivate(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrapf(err, "fail to private subimage %s", images[i].GetId())
- }
- }
- return guestImage.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) {
- q, err := manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SMultiArchResourceBaseManager.ListItemFilter(ctx, q, userCred, query.MultiArchResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SMultiArchResourceBaseManager.ListItemFilter")
- }
- if query.Protected != nil {
- if *query.Protected {
- q = q.IsTrue("protected")
- } else {
- q = q.IsFalse("protected")
- }
- }
- if len(query.DiskFormat) > 0 {
- q = q.In("disk_format", query.DiskFormat)
- }
- 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
- }
- func (manager *SGuestImageManager) Usage(ctx context.Context, scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, prefix string, policyResult rbacutils.SPolicyResult) map[string]int64 {
- usages := make(map[string]int64)
- count := ImageManager.count(ctx, scope, ownerId, api.IMAGE_STATUS_ACTIVE, tristate.False, false, tristate.True, policyResult)
- expandUsageCount(usages, prefix, "guest_image", "", count)
- sq := manager.Query()
- switch scope {
- case rbacscope.ScopeSystem:
- // do nothing
- case rbacscope.ScopeDomain:
- sq = sq.Equals("domain_id", ownerId.GetProjectDomainId())
- case rbacscope.ScopeProject:
- sq = sq.Equals("tenant_id", ownerId.GetProjectId())
- }
- cnt, _ := sq.CountWithError()
- key := []string{}
- if len(prefix) > 0 {
- key = append(key, prefix)
- }
- key = append(key, "guest_image", "count")
- usages[strings.Join(key, ".")] = int64(cnt)
- return usages
- }
- func (gi *SGuestImage) GetUsages() []db.IUsage {
- if gi.PendingDeleted || gi.Deleted {
- return nil
- }
- images, err := GuestImageJointManager.GetByGuestImageId(gi.Id)
- if err != nil {
- return nil
- }
- usages := make([]db.IUsage, 0)
- for i := range images {
- image, err := images[i].GetImage()
- if err != nil {
- log.Errorf("subimage %d GetImage fail %s", i, err)
- continue
- }
- ui := image.GetUsages()
- if len(ui) > 0 {
- usages = append(usages, ui...)
- }
- }
- 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.GetByGuestImageId(img.Id)
- if err != nil {
- return nil, err
- }
- for i := range images {
- image, err := images[i].GetImage()
- if err != nil {
- log.Errorf("subimage %d GetImage fail %s", i, err)
- continue
- }
- _, err = image.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
- }
|