mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(region): container overlay volume_mount over disk image
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user