diff --git a/pkg/apis/compute/container.go b/pkg/apis/compute/container.go index 5041783c136..3d221848adb 100644 --- a/pkg/apis/compute/container.go +++ b/pkg/apis/compute/container.go @@ -19,6 +19,7 @@ import ( "time" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/util/sets" @@ -290,3 +291,42 @@ type ContainerCacheImageInput struct { type ContainerCacheImagesInput struct { Images []*ContainerCacheImageInput `json:"images"` } + +func (i *ContainerCacheImagesInput) isImageExists(diskId string, imgId string) bool { + for idx := range i.Images { + img := i.Images[idx] + if img.DiskId != diskId { + return false + } + if img.Image == nil { + return false + } + if img.Image.ImageId == imgId { + return true + } + } + return false +} + +func (i *ContainerCacheImagesInput) Add(diskId string, imgId string, format string) error { + if diskId == "" { + return errors.Errorf("diskId is empty") + } + if imgId == "" { + return errors.Errorf("imageId is empty") + } + if !i.isImageExists(diskId, imgId) { + if i.Images == nil { + i.Images = []*ContainerCacheImageInput{} + } + i.Images = append(i.Images, &ContainerCacheImageInput{ + DiskId: diskId, + Image: &CacheImageInput{ + ImageId: imgId, + Format: format, + SkipChecksumIfExists: true, + }, + }) + } + return nil +} diff --git a/pkg/compute/container_drivers/volume_mount/disk.go b/pkg/compute/container_drivers/volume_mount/disk.go index c4ca772b364..86dece4069a 100644 --- a/pkg/compute/container_drivers/volume_mount/disk.go +++ b/pkg/compute/container_drivers/volume_mount/disk.go @@ -230,7 +230,8 @@ func (d disk) ValidatePostOverlay(ctx context.Context, userCred mcclient.TokenCr return nil } ovs := vm.Disk.PostOverlay - for i, ov := range ovs { + for i := range ovs { + ov := ovs[i] if err := d.ValidatePostSingleOverlay(ctx, userCred, ov); err != nil { return err } diff --git a/pkg/compute/tasks/container_create_task.go b/pkg/compute/tasks/container_create_task.go index 0508eebd43b..af502a87c39 100644 --- a/pkg/compute/tasks/container_create_task.go +++ b/pkg/compute/tasks/container_create_task.go @@ -20,7 +20,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" + "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" + imageapi "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/compute/models" @@ -46,6 +48,27 @@ func (t *ContainerBaseTask) GetPodDriver() models.IPodDriver { return drv.(models.IPodDriver) } +func (t *ContainerBaseTask) GetContainerCacheImagesInput(ctr *models.SContainer) (*api.ContainerCacheImagesInput, error) { + input := &api.ContainerCacheImagesInput{} + for i := range ctr.Spec.VolumeMounts { + vol := ctr.Spec.VolumeMounts[i] + if vol.Type != apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK { + continue + } + disk := vol.Disk + for j := range disk.PostOverlay { + pov := vol.Disk.PostOverlay[j] + if pov.GetType() != apis.CONTAINER_VOLUME_MOUNT_DISK_POST_OVERLAY_IMAGE { + continue + } + if err := input.Add(disk.Id, pov.Image.Id, imageapi.IMAGE_DISK_FORMAT_TGZ); err != nil { + return nil, errors.Wrapf(err, "add disk %q, image %q", disk.Id, pov.Image.Id) + } + } + } + return input, nil +} + type ContainerCreateTask struct { ContainerBaseTask } diff --git a/pkg/compute/tasks/container_start_task.go b/pkg/compute/tasks/container_start_task.go index 3ee47f6d21f..39720f5311a 100644 --- a/pkg/compute/tasks/container_start_task.go +++ b/pkg/compute/tasks/container_start_task.go @@ -18,6 +18,7 @@ import ( "context" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -34,7 +35,31 @@ func init() { } func (t *ContainerStartTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) { - t.requestStart(ctx, obj.(*models.SContainer)) + ctr := obj.(*models.SContainer) + if err := t.startCacheImages(ctx, ctr); err != nil { + t.OnStartedFailed(ctx, ctr, jsonutils.NewString(err.Error())) + } +} + +func (t *ContainerStartTask) startCacheImages(ctx context.Context, ctr *models.SContainer) error { + t.SetStage("OnCacheImagesComplete", nil) + input, err := t.GetContainerCacheImagesInput(ctr) + if err != nil { + return errors.Wrap(err, "GetContainerCacheImagesInput") + } + if len(input.Images) == 0 { + t.OnCacheImagesComplete(ctx, ctr, nil) + return nil + } + return ctr.StartCacheImagesTask(ctx, t.GetUserCred(), input, t.GetTaskId()) +} + +func (t *ContainerStartTask) OnCacheImagesComplete(ctx context.Context, ctr *models.SContainer, data jsonutils.JSONObject) { + t.requestStart(ctx, ctr) +} + +func (t *ContainerStartTask) OnCacheImagesCompleteFailed(ctx context.Context, ctr *models.SContainer, data jsonutils.JSONObject) { + t.OnStartedFailed(ctx, ctr, jsonutils.NewString(data.String())) } func (t *ContainerStartTask) requestStart(ctx context.Context, container *models.SContainer) { diff --git a/pkg/compute/tasks/container_volume_mount_task.go b/pkg/compute/tasks/container_volume_mount_task.go index 085704ce287..7135e0c2241 100644 --- a/pkg/compute/tasks/container_volume_mount_task.go +++ b/pkg/compute/tasks/container_volume_mount_task.go @@ -75,14 +75,9 @@ func (t *ContainerAddVolumeMountPostOverlayTask) startCacheImage(ctx context.Con for i := range input.PostOverlay { po := input.PostOverlay[i] if po.GetType() == apis.CONTAINER_VOLUME_MOUNT_DISK_POST_OVERLAY_IMAGE { - taskInput.Images = append(taskInput.Images, &api.ContainerCacheImageInput{ - DiskId: diskId, - Image: &api.CacheImageInput{ - ImageId: po.Image.Id, - Format: imageapi.IMAGE_DISK_FORMAT_TGZ, - SkipChecksumIfExists: true, - }, - }) + if err := taskInput.Add(diskId, po.Image.Id, imageapi.IMAGE_DISK_FORMAT_TGZ); err != nil { + return errors.Wrap(err, "add cached image to input") + } } } if len(taskInput.Images) != 0 {