mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
178 lines
5.7 KiB
Go
178 lines
5.7 KiB
Go
// 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 storageman
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
|
|
computeapis "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/hostman/hostutils"
|
|
"yunion.io/x/onecloud/pkg/hostman/options"
|
|
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
|
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
|
baseoptions "yunion.io/x/onecloud/pkg/mcclient/options"
|
|
"yunion.io/x/onecloud/pkg/util/qemuimg"
|
|
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
|
)
|
|
|
|
func cleanImages(ctx context.Context, manager IImageCacheManger, images map[string]IImageCache) (int64, error) {
|
|
if !manager.IsLocal() {
|
|
return 0, nil
|
|
}
|
|
storageCachedImages := make(map[string]computeapis.StoragecachedimageDetails)
|
|
limit := 50
|
|
total := -1
|
|
for total < 0 || len(storageCachedImages) < total {
|
|
params := baseoptions.BaseListOptions{}
|
|
details := true
|
|
params.Details = &details
|
|
params.Limit = &limit
|
|
offset := len(storageCachedImages)
|
|
params.Offset = &offset
|
|
result, err := compute.Storagecachedimages.ListDescendent(hostutils.GetComputeSession(ctx), manager.GetId(), jsonutils.Marshal(params))
|
|
if err != nil {
|
|
return 0, errors.Wrap(err, "List Storage Cached Images")
|
|
}
|
|
total = result.Total
|
|
for i := range result.Data {
|
|
ci := computeapis.StoragecachedimageDetails{}
|
|
err := result.Data[i].Unmarshal(&ci)
|
|
if err != nil {
|
|
return 0, errors.Wrap(err, "Unmarshal")
|
|
}
|
|
storageCachedImages[ci.CachedimageId] = ci
|
|
}
|
|
}
|
|
|
|
inUseCacheImageIds := findCachedImagesInUse(manager)
|
|
|
|
log.Infof("found image caches in use: %v", inUseCacheImageIds)
|
|
|
|
deleteSizeMb := int64(0)
|
|
for imageId, image := range images {
|
|
if _, ok := storageCachedImages[imageId]; !ok {
|
|
atime := image.GetDesc().AccessAt
|
|
if !atime.IsZero() && time.Now().Sub(atime) > time.Duration(options.HostOptions.ImageCacheExpireDays*86400)*time.Second {
|
|
continue
|
|
}
|
|
|
|
if inUseCacheImageIds.Contains(imageId) {
|
|
log.Infof("cached image not found but referenced by disks backing file")
|
|
continue
|
|
}
|
|
|
|
log.Infof("cached image %s not found on region, to delete size %dMB ...", imageId, image.GetDesc().SizeMb)
|
|
// not found on region, clean directly
|
|
if options.HostOptions.ImageCacheCleanupDryRun {
|
|
continue
|
|
}
|
|
err := manager.RemoveImage(ctx, imageId)
|
|
if err != nil {
|
|
return deleteSizeMb, errors.Wrapf(err, "RemoveImage %s", imageId)
|
|
}
|
|
deleteSizeMb += image.GetDesc().SizeMb
|
|
}
|
|
}
|
|
log.Infof("to delete non-exist image caches %dMB", deleteSizeMb)
|
|
|
|
for imgId := range storageCachedImages {
|
|
if _, ok := images[imgId]; !ok {
|
|
log.Infof("cached image %s in database not exists locally, to delete remotely ...", imgId)
|
|
_, err := modules.Storagecachedimages.Detach(hostutils.GetComputeSession(ctx), manager.GetId(), imgId, nil)
|
|
if err != nil {
|
|
log.Errorf("Fail to delete host cached image %s at %s: %s", imgId, manager.GetId(), err)
|
|
}
|
|
continue
|
|
}
|
|
img := storageCachedImages[imgId]
|
|
if img.Reference == 0 && (img.Size == 0 || time.Now().Sub(img.UpdatedAt) > time.Duration(options.HostOptions.ImageCacheExpireDays*86400)*time.Second) {
|
|
if img.Size == 0 {
|
|
img.Size = images[imgId].GetDesc().SizeMb * 1024 * 1024
|
|
}
|
|
|
|
if inUseCacheImageIds.Contains(imgId) {
|
|
log.Infof("cached image database reference zero but referenced by disks locally")
|
|
continue
|
|
}
|
|
|
|
log.Infof("image reference zero, to delete %s(%s) size %dMB", img.Cachedimage, img.CachedimageId, img.Size/1024/1024)
|
|
if options.HostOptions.ImageCacheCleanupDryRun {
|
|
continue
|
|
}
|
|
err := manager.RemoveImage(ctx, imgId)
|
|
if err != nil {
|
|
return deleteSizeMb, errors.Wrapf(err, "RemoveImage %s", imgId)
|
|
}
|
|
deleteSizeMb += img.Size / 1024 / 1024
|
|
}
|
|
}
|
|
|
|
return deleteSizeMb, nil
|
|
}
|
|
|
|
func findCachedImagesInUse(manager IImageCacheManger) stringutils2.SSortedStrings {
|
|
imageIds := stringutils2.NewSortedStrings(nil)
|
|
for _, imageId := range findQumuImagesInUse(manager) {
|
|
imageIds = imageIds.Append(imageId)
|
|
}
|
|
for _, imageId := range storageManager.host.GetIGuestManager().GetImageDeps(manager.GetStorageType()) {
|
|
imageIds = imageIds.Append(imageId)
|
|
}
|
|
return imageIds
|
|
}
|
|
|
|
func findQumuImagesInUse(manager IImageCacheManger) stringutils2.SSortedStrings {
|
|
imageIds := stringutils2.NewSortedStrings(nil)
|
|
for i := range storageManager.Storages {
|
|
storage := storageManager.Storages[i]
|
|
if storage.GetStoragecacheId() != manager.GetId() {
|
|
continue
|
|
}
|
|
// load storage disks used image cache
|
|
disksPath, err := storage.GetDisksPath()
|
|
if err != nil {
|
|
log.Errorf("storage %s failed get disksPath: %s", storage.GetPath(), err)
|
|
continue
|
|
}
|
|
|
|
for j := range disksPath {
|
|
diskPath := disksPath[j]
|
|
img, err := qemuimg.NewQemuImage(diskPath)
|
|
if err != nil {
|
|
log.Errorf("failed NewQemuImage of %s", diskPath)
|
|
continue
|
|
}
|
|
backingChain, err := img.GetBackingChain()
|
|
if err != nil {
|
|
log.Errorf("disk %s failed get backing chain", diskPath)
|
|
continue
|
|
}
|
|
for _, backingPath := range backingChain {
|
|
if strings.HasPrefix(backingPath, manager.GetPath()) {
|
|
imageId := strings.Trim(strings.TrimPrefix(backingPath, manager.GetPath()), "/")
|
|
imageIds = imageIds.Append(imageId)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return imageIds
|
|
}
|