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

Reply via email to