From 04dcae9cac27ea794814f22b8fffc3e33ca17f80 Mon Sep 17 00:00:00 2001 From: Jian Qiu Date: Wed, 30 Jul 2025 01:43:59 +0800 Subject: [PATCH] fix: inconsist checksum between image and its same format subimage (#22986) Co-authored-by: Qiu Jian --- pkg/image/models/images.go | 65 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index 603625f94f..a208750e40 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -326,10 +326,10 @@ func (manager *SImageManager) FetchCustomizeColumns( return rows } -func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) map[string]string { +func (img *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) map[string]string { headers := make(map[string]string) - details := ImageManager.FetchCustomizeColumns(ctx, userCred, query, []interface{}{self}, nil, false) + details := ImageManager.FetchCustomizeColumns(ctx, userCred, query, []interface{}{img}, nil, false) extra := jsonutils.Marshal(details[0]).(*jsonutils.JSONDict) for _, k := range extra.SortedKeys() { if k == "properties" { @@ -341,8 +341,8 @@ func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclien } } - jsonDict := jsonutils.Marshal(self).(*jsonutils.JSONDict) - fields, _ := db.GetDetailFields(self.GetModelManager(), userCred) + jsonDict := jsonutils.Marshal(img).(*jsonutils.JSONDict) + fields, _ := db.GetDetailFields(img.GetModelManager(), userCred) for _, k := range jsonDict.SortedKeys() { if utils.IsInStringArray(k, fields) { val, _ := jsonDict.GetString(k) @@ -352,9 +352,16 @@ func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclien } } + // none of subimage business + var ossChksum = img.OssChecksum + if len(img.OssChecksum) == 0 { + ossChksum = img.Checksum + } + headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "oss_checksum")] = ossChksum + formatStr := jsonutils.GetAnyString(query, []string{"format", "disk_format"}) if len(formatStr) > 0 { - subimg := ImageSubformatManager.FetchSubImage(self.Id, formatStr) + subimg := ImageSubformatManager.FetchSubImage(img.Id, formatStr) if subimg != nil { headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "disk_format")] = formatStr isTorrent := jsonutils.QueryBoolean(query, "torrent", false) @@ -362,6 +369,7 @@ func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclien headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "status")] = subimg.Status headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "size")] = fmt.Sprintf("%d", subimg.Size) headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "checksum")] = subimg.Checksum + headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "oss_checksum")] = subimg.Checksum } else { headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "status")] = subimg.TorrentStatus headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "size")] = fmt.Sprintf("%d", subimg.TorrentSize) @@ -370,31 +378,24 @@ func (self *SImage) GetExtraDetailsHeaders(ctx context.Context, userCred mcclien } } - // none of subimage business - var ossChksum = self.OssChecksum - if len(self.OssChecksum) == 0 { - ossChksum = self.Checksum - } - headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "oss_checksum")] = ossChksum - - properties, _ := ImagePropertyManager.GetProperties(self.Id) + properties, _ := ImagePropertyManager.GetProperties(img.Id) if len(properties) > 0 { for k, v := range properties { headers[fmt.Sprintf("%s%s", modules.IMAGE_META_PROPERTY, k)] = v } } - if self.PendingDeleted { - pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) + if img.PendingDeleted { + pendingDeletedAt := img.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds)) headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "auto_delete_at")] = timeutils.FullIsoTime(pendingDeletedAt) } - if strings.HasPrefix(self.Location, api.S3Prefix) { + if strings.HasPrefix(img.Location, api.S3Prefix) { headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_url")] = s3.GetEndpoint(options.Options.S3Endpoint, options.Options.S3UseSSL) headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_access_key")] = options.Options.S3AccessKey headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_secret")] = options.Options.S3SecretKey headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_bucket")] = options.Options.S3BucketName - headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_key")] = imagePathToName(self.Location) + headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_key")] = imagePathToName(img.Location) headers[fmt.Sprintf("%s%s", modules.IMAGE_META, "s3_info_sign_ver")] = options.Options.S3SignVersion } @@ -1084,44 +1085,44 @@ func (self *SImage) newSubformat(ctx context.Context, format qemuimgfmt.TImageFo return nil } -func (self *SImage) migrateSubImage(ctx context.Context) error { +func (img *SImage) migrateSubImage(ctx context.Context) error { log.Debugf("migrateSubImage") - if !qemuimgfmt.IsSupportedImageFormat(self.DiskFormat) { - log.Warningf("Unsupported image format %s, no need to migrate", self.DiskFormat) + if !qemuimgfmt.IsSupportedImageFormat(img.DiskFormat) { + log.Warningf("Unsupported image format %s, no need to migrate", img.DiskFormat) return nil } - subimg := ImageSubformatManager.FetchSubImage(self.Id, self.DiskFormat) + subimg := ImageSubformatManager.FetchSubImage(img.Id, img.DiskFormat) if subimg != nil { return nil } - imgInst, err := self.getQemuImage() + imgInst, err := img.getQemuImage() if err != nil { return errors.Wrap(err, "getQemuImage") } - if self.GetImageType() != api.ImageTypeISO && imgInst.IsSparse() && utils.IsInStringArray(self.DiskFormat, options.Options.TargetImageFormats) { + if img.GetImageType() != api.ImageTypeISO && imgInst.IsSparse() && utils.IsInStringArray(img.DiskFormat, options.Options.TargetImageFormats) { // need to convert again log.Debugf("migrateImage: image is not iso but sparse, need to convert the image") - return self.newSubformat(ctx, qemuimgfmt.String2ImageFormat(self.DiskFormat), false) + return img.newSubformat(ctx, qemuimgfmt.String2ImageFormat(img.DiskFormat), false) } else { log.Debugf("migrateImage: no need to convert the image") - localPath := self.GetLocalLocation() - if !strings.HasSuffix(localPath, fmt.Sprintf(".%s", self.DiskFormat)) { - newLocalpath := fmt.Sprintf("%s.%s", localPath, self.DiskFormat) + localPath := img.GetLocalLocation() + if !strings.HasSuffix(localPath, fmt.Sprintf(".%s", img.DiskFormat)) { + newLocalpath := fmt.Sprintf("%s.%s", localPath, img.DiskFormat) out, err := procutils.NewCommand("mv", "-f", localPath, newLocalpath).Output() if err != nil { return errors.Wrapf(err, "rename file failed %s", out) } - _, err = db.Update(self, func() error { - self.Location = self.GetNewLocation(newLocalpath) + _, err = db.Update(img, func() error { + img.Location = img.GetNewLocation(newLocalpath) return nil }) if err != nil { return err } } - return self.newSubformat(ctx, qemuimgfmt.String2ImageFormat(self.DiskFormat), true) + return img.newSubformat(ctx, qemuimgfmt.String2ImageFormat(img.DiskFormat), true) } } @@ -1914,7 +1915,7 @@ func (image *SImage) doUploadPermanentStorage(ctx context.Context, userCred mccl if !subimgs[i].isLocal() { continue } - if subimgs[i].Format == image.DiskFormat { + if subimgs[i].Format == image.DiskFormat && subimgs[i].Checksum == image.Checksum { _, err := db.Update(&subimgs[i], func() error { subimgs[i].Location = image.Location subimgs[i].Status = api.IMAGE_STATUS_ACTIVE @@ -1926,7 +1927,7 @@ func (image *SImage) doUploadPermanentStorage(ctx context.Context, userCred mccl } else { imagePath := subimgs[i].GetLocalLocation() storage := GetStorage() - location, err := GetStorage().SaveImage(ctx, imagePath, nil) + location, err := storage.SaveImage(ctx, imagePath, nil) if err != nil { log.Errorf("Failed save image to sepcific storage %s", err) subimgs[i].SetStatus(api.IMAGE_STATUS_SAVE_FAIL)