fix(region): container overlay volume_mount over disk image

This commit is contained in:
Zexi Li
2024-04-11 15:44:49 +08:00
parent 0ad64ba062
commit 3d95b9087d
8 changed files with 136 additions and 64 deletions
+8 -3
View File
@@ -131,18 +131,23 @@ type ContainerOverlayDiskImage struct {
type ContainerDiskOverlayType string
const (
CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY ContainerDiskOverlayType = "directory"
CONTAINER_DISK_OVERLAY_TYPE_UNKNOWN ContainerDiskOverlayType = "unknown"
CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY ContainerDiskOverlayType = "directory"
CONTAINER_DISK_OVERLAY_TYPE_DISK_IMAGE ContainerDiskOverlayType = "disk_image"
CONTAINER_DISK_OVERLAY_TYPE_UNKNOWN ContainerDiskOverlayType = "unknown"
)
type ContainerVolumeMountDiskOverlay struct {
LowerDir []string `json:"lower_dir"`
LowerDir []string `json:"lower_dir"`
UseDiskImage bool `json:"use_disk_image"`
}
func (o ContainerVolumeMountDiskOverlay) GetType() ContainerDiskOverlayType {
if len(o.LowerDir) != 0 {
return CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY
}
if o.UseDiskImage {
return CONTAINER_DISK_OVERLAY_TYPE_DISK_IMAGE
}
return CONTAINER_DISK_OVERLAY_TYPE_UNKNOWN
}
@@ -17,7 +17,8 @@ func init() {
}
type iDiskOverlay interface {
validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay) error
validatePodCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, disk *api.DiskConfig) error
validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, obj *models.SDisk) error
}
type disk struct {
@@ -27,7 +28,8 @@ type disk struct {
func newDisk() models.IContainerVolumeMountDriver {
return &disk{
overlayDrivers: map[apis.ContainerDiskOverlayType]iDiskOverlay{
apis.CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY: newDiskOverlayDir(),
apis.CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY: newDiskOverlayDir(),
apis.CONTAINER_DISK_OVERLAY_TYPE_DISK_IMAGE: newDiskOverlayImage(),
},
}
}
@@ -61,20 +63,16 @@ func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCre
return nil, errors.Wrap(err, "get pod disks")
}
disk := vm.Disk
var diskObj models.SDisk
if disk.Index != nil {
diskIndex := *disk.Index
if diskIndex >= len(disks) {
return nil, httperrors.NewInputParameterError("disk.index %d is large than disk size %d", diskIndex, len(disks))
}
diskObj := disks[diskIndex]
diskObj = disks[diskIndex]
vm.Disk.Id = diskObj.GetId()
// remove index
vm.Disk.Index = nil
if diskObj.TemplateId != "" {
if vm.Disk.SubDirectory == "" {
return nil, httperrors.NewInputParameterError("sub_directory is required when disk has template_id %s", diskObj.TemplateId)
}
}
} else {
if disk.Id == "" {
return nil, httperrors.NewNotEmptyError("disk.id is empty")
@@ -83,11 +81,7 @@ func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCre
for _, d := range disks {
if d.GetId() == disk.Id || d.GetName() == disk.Id {
disk.Id = d.GetId()
if d.TemplateId != "" {
if vm.Disk.SubDirectory == "" {
return nil, httperrors.NewInputParameterError("sub_directory is required when disk has template_id %s", d.TemplateId)
}
}
diskObj = d
foundDisk = true
break
}
@@ -96,7 +90,7 @@ func (d disk) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCre
return nil, httperrors.NewNotFoundError("not found pod disk by %s", disk.Id)
}
}
if err := d.validateOverlay(ctx, userCred, vm); err != nil {
if err := d.validateOverlay(ctx, userCred, vm, &diskObj); err != nil {
return nil, errors.Wrapf(err, "validate overlay")
}
return vm, nil
@@ -122,9 +116,9 @@ func (d disk) ValidatePodCreateData(ctx context.Context, userCred mcclient.Token
return httperrors.NewInputParameterError("disk.index %d is large than disk size %d", diskIndex, len(disks))
}
inputDisk := disks[diskIndex]
if inputDisk.ImageId != "" {
if disk.SubDirectory == "" {
return httperrors.NewInputParameterError("sub_directory is required when disk has image_id %s", inputDisk.ImageId)
if vm.Disk.Overlay != nil {
if err := d.getOverlayDriver(vm.Disk.Overlay).validatePodCreateData(ctx, userCred, vm.Disk.Overlay, inputDisk); err != nil {
return httperrors.NewInputParameterError("valid overlay %v", err)
}
}
return nil
@@ -134,7 +128,7 @@ func (d disk) getOverlayDriver(ov *apis.ContainerVolumeMountDiskOverlay) iDiskOv
return d.overlayDrivers[ov.GetType()]
}
func (d disk) validateOverlay(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount) error {
func (d disk) validateOverlay(ctx context.Context, userCred mcclient.TokenCredential, vm *apis.ContainerVolumeMount, diskObj *models.SDisk) error {
if vm.Disk.Overlay == nil {
return nil
}
@@ -142,7 +136,7 @@ func (d disk) validateOverlay(ctx context.Context, userCred mcclient.TokenCreden
if err := ov.IsValid(); err != nil {
return httperrors.NewInputParameterError("invalid overlay input: %v", err)
}
if err := d.getOverlayDriver(ov).validateCreateData(ctx, userCred, ov); err != nil {
if err := d.getOverlayDriver(ov).validateCreateData(ctx, userCred, ov, diskObj); err != nil {
return errors.Wrapf(err, "validate overlay %s", ov.GetType())
}
return nil
@@ -154,7 +148,7 @@ func newDiskOverlayDir() iDiskOverlay {
return &diskOverlayDir{}
}
func (d diskOverlayDir) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay) error {
func (d diskOverlayDir) validateCommonCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay) error {
if len(input.LowerDir) == 0 {
return httperrors.NewNotEmptyError("lower_dir is required")
}
@@ -168,3 +162,37 @@ func (d diskOverlayDir) validateCreateData(ctx context.Context, userCred mcclien
}
return nil
}
func (d diskOverlayDir) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, _ *models.SDisk) error {
return d.validateCommonCreateData(ctx, userCred, input)
}
func (d diskOverlayDir) validatePodCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, disk *api.DiskConfig) error {
return d.validateCommonCreateData(ctx, userCred, input)
}
type diskOverlayImage struct{}
func newDiskOverlayImage() iDiskOverlay {
return &diskOverlayImage{}
}
func (d diskOverlayImage) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, diskObj *models.SDisk) error {
if !input.UseDiskImage {
return nil
}
if diskObj.TemplateId == "" {
return httperrors.NewInputParameterError("disk %s must have template_id", diskObj.GetId())
}
return nil
}
func (d diskOverlayImage) validatePodCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *apis.ContainerVolumeMountDiskOverlay, disk *api.DiskConfig) error {
if !input.UseDiskImage {
return nil
}
if disk.ImageId == "" {
return httperrors.NewInputParameterError("disk %#v must have image_id", disk)
}
return nil
}
+11 -7
View File
@@ -305,19 +305,23 @@ func (vm *ContainerVolumeMountRelation) toHostDiskMount(disk *apis.ContainerVolu
}
func (vm *ContainerVolumeMountRelation) ToHostMount() (*hostapi.ContainerVolumeMount, error) {
disk, err := vm.toHostDiskMount(vm.VolumeMount.Disk)
if err != nil {
return nil, errors.Wrap(err, "toHostDiskMount")
}
return &hostapi.ContainerVolumeMount{
ret := &hostapi.ContainerVolumeMount{
Type: vm.VolumeMount.Type,
Disk: disk,
Disk: nil,
HostPath: vm.VolumeMount.HostPath,
ReadOnly: vm.VolumeMount.ReadOnly,
MountPath: vm.VolumeMount.MountPath,
SelinuxRelabel: vm.VolumeMount.SelinuxRelabel,
Propagation: vm.VolumeMount.Propagation,
}, nil
}
if vm.VolumeMount.Disk != nil {
disk, err := vm.toHostDiskMount(vm.VolumeMount.Disk)
if err != nil {
return nil, errors.Wrap(err, "toHostDiskMount")
}
ret.Disk = disk
}
return ret, nil
}
func (m *SContainerManager) GetVolumeMountRelations(pod *SGuest, spec *api.ContainerSpec) ([]*ContainerVolumeMountRelation, error) {
+17 -4
View File
@@ -1377,11 +1377,24 @@ func (self *SDisk) GetFsFormat() string {
return self.FsFormat
}
func (self *SDisk) GetCacheImageFormat() string {
if self.DiskFormat == "raw" {
return "qcow2"
func (self *SDisk) GetCacheImageFormat(ctx context.Context) (string, error) {
if self.TemplateId != "" {
s := auth.GetAdminSession(ctx, options.Options.Region)
img, err := image.Images.Get(s, self.TemplateId, nil)
if err == nil {
diskFmt, err := img.GetString("disk_format")
if err != nil {
return "", errors.Wrapf(err, "not found disk_format of image %s", self.TemplateId)
}
if diskFmt == imageapi.IMAGE_DISK_FORMAT_TGZ {
return imageapi.IMAGE_DISK_FORMAT_TGZ, nil
}
}
}
return self.DiskFormat
if self.DiskFormat == "raw" {
return "qcow2", nil
}
return self.DiskFormat, nil
}
func (manager *SDiskManager) getDisksByStorage(storage *SStorage) ([]SDisk, error) {
+6 -1
View File
@@ -44,9 +44,14 @@ func (self *DiskCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel,
// use image only if disk not created from snapshot or backup
if len(imageId) > 0 && len(disk.SnapshotId) == 0 && len(disk.BackupId) == 0 {
self.SetStage("OnStorageCacheImageComplete", nil)
cacheImageFmt, err := disk.GetCacheImageFormat(ctx)
if err != nil {
self.OnStartAllocateFailed(ctx, disk, jsonutils.NewString(err.Error()))
return
}
input := api.CacheImageInput{
ImageId: imageId,
Format: disk.GetCacheImageFormat(),
Format: cacheImageFmt,
ParentTaskId: self.GetTaskId(),
}
guest := disk.GetGuest()
+22 -29
View File
@@ -35,7 +35,8 @@ type disk struct {
func newDisk() IVolumeMount {
return &disk{
overlayDrivers: map[apis.ContainerDiskOverlayType]iDiskOverlay{
apis.CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY: newDiskOverlayDir(),
apis.CONTAINER_DISK_OVERLAY_TYPE_DIRECTORY: newDiskOverlayDir(),
apis.CONTAINER_DISK_OVERLAY_TYPE_DISK_IMAGE: newDiskOverlayImage(),
},
}
}
@@ -160,11 +161,6 @@ func (d disk) Mount(pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount
return errors.Wrapf(err, "mount container %s overlay dir: %#v", ctrId, vmDisk.Overlay)
}
}
if vmDisk.TemplateId != "" {
if err := d.mountTemplateOverlay(context.Background(), pod, ctrId, vm); err != nil {
return errors.Wrapf(err, "mount container %s template overlay: %#v", ctrId, vmDisk.TemplateId)
}
}
return nil
}
@@ -197,11 +193,6 @@ func (d disk) Unmount(pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMou
return errors.Wrapf(err, "umount overlay")
}
}
if vm.Disk.TemplateId != "" {
if err := d.unmountTemplateOverlay(context.Background(), pod, ctrId, vm); err != nil {
return errors.Wrapf(err, "unmount container %s template overlay: %#v", ctrId, vm.Disk.TemplateId)
}
}
mntPoint := pod.GetDiskMountPoint(iDisk)
if err := container_storage.Unmount(mntPoint); err != nil {
return errors.Wrapf(err, "unmount %s", mntPoint)
@@ -258,24 +249,6 @@ func (d disk) doTemplateOverlayAction(
return nil
}
func (d disk) mountTemplateOverlay(
ctx context.Context,
pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount) error {
if err := d.doTemplateOverlayAction(ctx, pod, ctrId, vm, newDiskOverlayDir().mount); err != nil {
return errors.Wrapf(err, "mount template overlay")
}
return nil
}
func (d disk) unmountTemplateOverlay(
ctx context.Context,
pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount) error {
if err := d.doTemplateOverlayAction(ctx, pod, ctrId, vm, newDiskOverlayDir().unmount); err != nil {
return errors.Wrapf(err, "unmount template overlay")
}
return nil
}
type diskOverlayDir struct{}
func newDiskOverlayDir() iDiskOverlay {
@@ -314,3 +287,23 @@ func (dod diskOverlayDir) unmount(d disk, pod IPodInfo, ctrId string, vm *hostap
overlayDir := d.getOverlayMergedDir(pod, ctrId, vm, upperDir)
return container_storage.Unmount(overlayDir)
}
type diskOverlayImage struct{}
func newDiskOverlayImage() iDiskOverlay {
return &diskOverlayImage{}
}
func (di diskOverlayImage) mount(d disk, pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount) error {
if err := d.doTemplateOverlayAction(context.Background(), pod, ctrId, vm, newDiskOverlayDir().mount); err != nil {
return errors.Wrapf(err, "mount template overlay")
}
return nil
}
func (di diskOverlayImage) unmount(d disk, pod IPodInfo, ctrId string, vm *hostapi.ContainerVolumeMount) error {
if err := d.doTemplateOverlayAction(context.Background(), pod, ctrId, vm, newDiskOverlayDir().unmount); err != nil {
return errors.Wrapf(err, "unmount template overlay")
}
return nil
}
@@ -208,6 +208,15 @@ func parseContainerVolumeMount(vmStr string) (*apis.ContainerVolumeMount, error)
vm.Disk.Overlay = &apis.ContainerVolumeMountDiskOverlay{
LowerDir: strings.Split(val, ":"),
}
case "overlay_disk_image":
if strings.ToLower(val) == "true" {
if vm.Disk == nil {
vm.Disk = &apis.ContainerVolumeMountDisk{}
}
vm.Disk.Overlay = &apis.ContainerVolumeMountDiskOverlay{
UseDiskImage: true,
}
}
}
}
return vm, nil
@@ -51,6 +51,21 @@ func Test_parseContainerVolumeMount(t *testing.T) {
Type: apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
},
},
{
args: "readonly=true,mount_path=/data,disk_index=0,disk_subdir=data,overlay_disk_image=true",
want: &apis.ContainerVolumeMount{
ReadOnly: true,
MountPath: "/data",
Disk: &apis.ContainerVolumeMountDisk{
Index: &index0,
SubDirectory: "data",
Overlay: &apis.ContainerVolumeMountDiskOverlay{
UseDiskImage: true,
},
},
Type: apis.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
},
},
{
args: "readonly=true,mount_path=/storage_size,disk_index=0,disk_ssf=storage_size",
want: &apis.ContainerVolumeMount{