diff --git a/pkg/apis/image/image.go b/pkg/apis/image/image.go index f0e88fbc08..f6ed93d373 100644 --- a/pkg/apis/image/image.go +++ b/pkg/apis/image/image.go @@ -88,3 +88,12 @@ type ImageCreateInput struct { // 镜像属性 Properties map[string]string `json:"properties"` } + +type ImageUpdateStatusInput struct { + apis.Meta + + // 镜像状态 + Status string `json:"status"` + // 更新镜像状态原因 + Reason string `json:"reason"` +} diff --git a/pkg/hostman/storageman/storage_local.go b/pkg/hostman/storageman/storage_local.go index ec7c5d0592..4c8a6a863b 100644 --- a/pkg/hostman/storageman/storage_local.go +++ b/pkg/hostman/storageman/storage_local.go @@ -219,7 +219,7 @@ func (s *SLocalStorage) SaveToGlance(ctx context.Context, params interface{}) (j if err := s.saveToGlance(ctx, imageId, imagePath, compress, format); err != nil { log.Errorf("Save to glance failed: %s", err) - s.onSaveToGlanceFailed(ctx, imageId) + s.onSaveToGlanceFailed(ctx, imageId, err.Error()) } imagecacheManager := s.Manager.LocalStorageImagecacheManager @@ -305,11 +305,14 @@ func (s *SLocalStorage) saveToGlance(ctx context.Context, imageId, imagePath str return err } -func (s *SLocalStorage) onSaveToGlanceFailed(ctx context.Context, imageId string) { +func (s *SLocalStorage) onSaveToGlanceFailed(ctx context.Context, imageId string, reason string) { params := jsonutils.NewDict() params.Set("status", jsonutils.NewString("killed")) - _, err := modules.Images.Update(hostutils.GetImageSession(ctx, s.GetZoneName()), - imageId, params) + params.Set("reason", jsonutils.NewString(reason)) + _, err := modules.Images.PerformAction( + hostutils.GetImageSession(ctx, s.GetZoneName()), + imageId, "update-status", params, + ) if err != nil { log.Errorln(err) } diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index 14a1a50b89..5f4c0ba666 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -1452,6 +1452,26 @@ func (img *SImage) GetUsages() []db.IUsage { } } +func (self *SImage) AllowPerformUpdateStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return db.IsAdminAllowPerform(userCred, self, "update-status") +} + +func (img *SImage) PerformUpdateStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ImageUpdateStatusInput) (jsonutils.JSONObject, error) { + if !utils.IsInStringArray(input.Status, api.ImageDeadStatus) { + return nil, httperrors.NewBadRequestError("can't udpate image to status %s, must in %v", input.Status, api.ImageDeadStatus) + } + _, err := db.Update(img, func() error { + img.Status = input.Status + return nil + }) + if err != nil { + return nil, errors.Wrap(err, "udpate image status") + } + db.OpsLog.LogEvent(img, db.ACT_UPDATE_STATUS, input.Reason, userCred) + logclient.AddSimpleActionLog(img, logclient.ACT_UPDATE_STATUS, input.Reason, userCred, true) + return nil, nil +} + func (img *SImage) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicProjectInput) (jsonutils.JSONObject, error) { if img.IsStandard.IsTrue() { return nil, errors.Wrap(httperrors.ErrForbidden, "cannot perform public for standard image")