The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3761
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Closes #3760. Signed-off-by: Christian Brauner <[email protected]>
From c544742bb8c4f86c74a6555fc02a5f248dc58c8a Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sun, 3 Sep 2017 21:50:04 +0200 Subject: [PATCH] ceph: implement resizing Closes #3760. Signed-off-by: Christian Brauner <[email protected]> --- lxd/storage_ceph.go | 125 +++++++++++++++++++++++++++++++++++++++++++++- lxd/storage_ceph_utils.go | 122 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 2 deletions(-) diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go index c0410a385..975452c15 100644 --- a/lxd/storage_ceph.go +++ b/lxd/storage_ceph.go @@ -454,6 +454,19 @@ func (s *storageCeph) StoragePoolVolumeCreate() error { } }() + // apply quota + if s.volume.Config["size"] != "" { + size, err := shared.ParseByteSizeString(s.volume.Config["size"]) + if err != nil { + return err + } + + err = s.StorageEntitySetQuota(storagePoolVolumeTypeCustom, size, nil) + if err != nil { + return err + } + } + logger.Debugf(`Created RBD storage volume "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name) @@ -647,7 +660,38 @@ func (s *storageCeph) StoragePoolVolumeUmount() (bool, error) { } func (s *storageCeph) StoragePoolVolumeUpdate(writable *api.StorageVolumePut, changedConfig []string) error { - return fmt.Errorf("RBD storage volume properties cannot be changed") + logger.Infof(`Updating RBD storage volume "%s" on storage pool "%s"`, + s.volume.Name, s.pool.Name) + + if !(shared.StringInSlice("block.mount_options", changedConfig) && + len(changedConfig) == 1) && + !(shared.StringInSlice("block.mount_options", changedConfig) && + len(changedConfig) == 2 && + shared.StringInSlice("size", changedConfig)) && + !(shared.StringInSlice("size", changedConfig) && + len(changedConfig) == 1) { + return fmt.Errorf("The properties \"%v\" cannot be changed", + changedConfig) + } + + if shared.StringInSlice("size", changedConfig) { + // apply quota + if s.volume.Config["size"] != writable.Config["size"] { + size, err := shared.ParseByteSizeString(writable.Config["size"]) + if err != nil { + return err + } + + err = s.StorageEntitySetQuota(storagePoolVolumeTypeCustom, size, nil) + if err != nil { + return err + } + } + } + + logger.Infof(`Updated RBD storage volume "%s" on storage pool "%s"`, + s.volume.Name, s.pool.Name) + return nil } func (s *storageCeph) StoragePoolUpdate(writable *api.StoragePoolPut, changedConfig []string) error { @@ -2500,5 +2544,82 @@ func (s *storageCeph) ImageUmount(fingerprint string) (bool, error) { } func (s *storageCeph) StorageEntitySetQuota(volumeType int, size int64, data interface{}) error { - return fmt.Errorf("RBD storage volume quota are not supported") + logger.Debugf(`Setting RBD quota for "%s"`, s.volume.Name) + + if !shared.IntInSlice(volumeType, supportedVolumeTypes) { + return fmt.Errorf("Invalid storage type") + } + + var ret int + var c container + fsType := s.getRBDFilesystem() + mountpoint := "" + RBDDevPath := "" + volumeName := "" + switch volumeType { + case storagePoolVolumeTypeContainer: + c = data.(container) + ctName := c.Name() + if c.IsRunning() { + msg := fmt.Sprintf(`Cannot resize RBD storage volume `+ + `for container \"%s\" when it is running`, + ctName) + logger.Errorf(msg) + return fmt.Errorf(msg) + } + + RBDDevPath, ret = getRBDMappedDevPath(s.ClusterName, + s.OSDPoolName, storagePoolVolumeTypeNameContainer, + s.volume.Name, true, s.UserName) + mountpoint = getContainerMountPoint(s.pool.Name, ctName) + volumeName = ctName + default: + RBDDevPath, ret = getRBDMappedDevPath(s.ClusterName, + s.OSDPoolName, storagePoolVolumeTypeNameCustom, + s.volume.Name, true, s.UserName) + mountpoint = getStoragePoolVolumeMountPoint(s.pool.Name, + s.volume.Name) + volumeName = s.volume.Name + } + if ret < 0 { + return fmt.Errorf("Failed to get mapped RBD path") + } + + oldSize, err := shared.ParseByteSizeString(s.volume.Config["size"]) + if err != nil { + return err + } + + // The right disjunct just means that someone unset the size property in + // the container's config. We obviously cannot resize to 0. + if oldSize == size || size == 0 { + return nil + } + + if size < oldSize { + err = s.rbdShrink(RBDDevPath, size, fsType, mountpoint, + volumeType, volumeName, data) + } else if size > oldSize { + err = s.rbdGrow(RBDDevPath, size, fsType, mountpoint, + volumeType, volumeName, data) + } + if err != nil { + return err + } + + // Update the database + s.volume.Config["size"] = shared.GetByteSizeString(size, 0) + err = db.StoragePoolVolumeUpdate( + s.s.DB, + s.volume.Name, + volumeType, + s.poolID, + s.volume.Description, + s.volume.Config) + if err != nil { + return err + } + + logger.Debugf(`Set RBD quota for "%s"`, s.volume.Name) + return nil } diff --git a/lxd/storage_ceph_utils.go b/lxd/storage_ceph_utils.go index 1f4ec0e2e..e27969366 100644 --- a/lxd/storage_ceph_utils.go +++ b/lxd/storage_ceph_utils.go @@ -1492,3 +1492,125 @@ mapImage: return strings.TrimSpace(devPath), 2 } + +func (s *storageCeph) rbdShrink(path string, size int64, fsType string, + fsMntPoint string, volumeType int, volumeName string, + data interface{}) error { + var err error + var msg string + + sizeString := strconv.FormatInt(size, 10) + switch fsType { + case "xfs": + logger.Errorf("xfs filesystems cannot be shrunk: dump, mkfs, and restore are required") + return fmt.Errorf("xfs filesystems cannot be shrunk: dump, mkfs, and restore are required") + default: + // default = ext4 + switch volumeType { + case storagePoolVolumeTypeContainer: + c := data.(container) + ourMount, err := c.StorageStop() + if err != nil { + return err + } + if !ourMount { + defer c.StorageStart() + } + case storagePoolVolumeTypeCustom: + ourMount, err := s.StoragePoolVolumeUmount() + if err != nil { + return err + } + if !ourMount { + defer s.StoragePoolVolumeMount() + } + } + + msg, err = shared.TryRunCommand("e2fsck", "-f", "-y", path) + if err != nil { + return err + } + + // don't assume resize2fs semantics are sane (because they + // aren't) + kbSize := size / 1024 + ext4SizeString := strconv.FormatInt(kbSize, 10) + ext4SizeString += "K" + msg, err = shared.TryRunCommand("resize2fs", path, ext4SizeString) + if err != nil { + logger.Errorf("could not reduce underlying %s filesystem for LV \"%s\": %s", fsType, path, msg) + return fmt.Errorf("could not reduce underlying %s filesystem for LV \"%s\": %s", fsType, path, msg) + } + } + + sizeString = shared.GetByteSizeString(size, 0) + msg, err = shared.TryRunCommand( + "rbd", + "resize", + "--allow-shrink", + "--id", s.UserName, + "--cluster", s.ClusterName, + "--pool", s.OSDPoolName, + "--size", sizeString, + fmt.Sprintf("%s_%s", volumeType, volumeName)) + if err != nil { + logger.Errorf("could not extend LV \"%s\": %s", path, msg) + return fmt.Errorf("could not extend LV \"%s\": %s", path, msg) + } + + logger.Debugf("reduce underlying %s filesystem for LV \"%s\"", fsType, path) + return nil +} + +func (s *storageCeph) rbdGrow(path string, size int64, fsType string, + fsMntPoint string, volumeType int, volumeName string, + data interface{}) error { + sizeString := shared.GetByteSizeString(size, 0) + msg, err := shared.TryRunCommand( + "rbd", + "resize", + "--id", s.UserName, + "--cluster", s.ClusterName, + "--pool", s.OSDPoolName, + "--size", sizeString, + fmt.Sprintf("%s_%s", volumeType, volumeName)) + if err != nil { + logger.Errorf("could not extend LV \"%s\": %s", path, msg) + return fmt.Errorf("could not extend LV \"%s\": %s", path, msg) + } + + switch volumeType { + case storagePoolVolumeTypeContainer: + c := data.(container) + ourMount, err := c.StorageStart() + if err != nil { + return err + } + if ourMount { + defer c.StorageStop() + } + case storagePoolVolumeTypeCustom: + ourMount, err := s.StoragePoolVolumeMount() + if err != nil { + return err + } + if ourMount { + defer s.StoragePoolVolumeUmount() + } + } + + switch fsType { + case "xfs": + msg, err = shared.TryRunCommand("xfs_growfs", fsMntPoint) + default: + // default = ext4 + msg, err = shared.TryRunCommand("resize2fs", path) + } + if err != nil { + logger.Errorf("could not extend underlying %s filesystem for LV \"%s\": %s", fsType, path, msg) + return fmt.Errorf("could not extend underlying %s filesystem for LV \"%s\": %s", fsType, path, msg) + } + + logger.Debugf("extended underlying %s filesystem for LV \"%s\"", fsType, path) + return nil +}
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
