The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6563
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) === Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
From 37a690ca88ab52a6653f4e7fb2083b9b56b83cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Thu, 5 Dec 2019 15:13:42 -0500 Subject: [PATCH] lxd/storage: Remove legacy cephfs implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/storage.go | 27 +- lxd/storage_cephfs.go | 1098 ----------------------------------------- 2 files changed, 2 insertions(+), 1123 deletions(-) delete mode 100644 lxd/storage_cephfs.go diff --git a/lxd/storage.go b/lxd/storage.go index 64172414df..2ac2fa3230 100644 --- a/lxd/storage.go +++ b/lxd/storage.go @@ -101,7 +101,6 @@ type storageType int const ( storageTypeBtrfs storageType = iota storageTypeCeph - storageTypeCephFs storageTypeDir storageTypeLvm storageTypeMock @@ -116,8 +115,6 @@ func storageTypeToString(sType storageType) (string, error) { return "btrfs", nil case storageTypeCeph: return "ceph", nil - case storageTypeCephFs: - return "cephfs", nil case storageTypeDir: return "dir", nil case storageTypeLvm: @@ -128,7 +125,7 @@ func storageTypeToString(sType storageType) (string, error) { return "zfs", nil } - return "", fmt.Errorf("invalid storage type") + return "", fmt.Errorf("Invalid storage type") } func storageStringToType(sName string) (storageType, error) { @@ -137,8 +134,6 @@ func storageStringToType(sName string) (storageType, error) { return storageTypeBtrfs, nil case "ceph": return storageTypeCeph, nil - case "cephfs": - return storageTypeCephFs, nil case "dir": return storageTypeDir, nil case "lvm": @@ -149,7 +144,7 @@ func storageStringToType(sName string) (storageType, error) { return storageTypeZfs, nil } - return -1, fmt.Errorf("invalid storage type name") + return -1, fmt.Errorf("Invalid storage type name") } // The storage interface defines the functions needed to implement a storage @@ -286,13 +281,6 @@ func storageCoreInit(driver string) (storage, error) { return nil, err } return &ceph, nil - case storageTypeCephFs: - cephfs := storageCephFs{} - err = cephfs.StorageCoreInit() - if err != nil { - return nil, err - } - return &cephfs, nil case storageTypeLvm: lvm := storageLvm{} err = lvm.StorageCoreInit() @@ -383,17 +371,6 @@ func storageInit(s *state.State, project, poolName, volumeName string, volumeTyp return nil, err } return &ceph, nil - case storageTypeCephFs: - cephfs := storageCephFs{} - cephfs.poolID = poolID - cephfs.pool = pool - cephfs.volume = volume - cephfs.s = s - err = cephfs.StoragePoolInit() - if err != nil { - return nil, err - } - return &cephfs, nil case storageTypeLvm: lvm := storageLvm{} lvm.poolID = poolID diff --git a/lxd/storage_cephfs.go b/lxd/storage_cephfs.go deleted file mode 100644 index 51e694e098..0000000000 --- a/lxd/storage_cephfs.go +++ /dev/null @@ -1,1098 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "syscall" - - "github.com/gorilla/websocket" - "github.com/pkg/errors" - - "github.com/lxc/lxd/lxd/backup" - "github.com/lxc/lxd/lxd/instance" - "github.com/lxc/lxd/lxd/migration" - "github.com/lxc/lxd/lxd/operations" - "github.com/lxc/lxd/lxd/rsync" - "github.com/lxc/lxd/lxd/state" - driver "github.com/lxc/lxd/lxd/storage" - "github.com/lxc/lxd/shared" - "github.com/lxc/lxd/shared/api" - "github.com/lxc/lxd/shared/ioprogress" - "github.com/lxc/lxd/shared/logger" - "github.com/lxc/lxd/shared/units" -) - -type storageCephFs struct { - ClusterName string - FsName string - UserName string - storageShared -} - -func (s *storageCephFs) StorageCoreInit() error { - s.sType = storageTypeCeph - typeName, err := storageTypeToString(s.sType) - if err != nil { - return err - } - s.sTypeName = typeName - - if cephVersion != "" { - s.sTypeVersion = cephVersion - return nil - } - - msg, err := shared.RunCommand("rbd", "--version") - if err != nil { - return fmt.Errorf("Error getting CEPH version: %s", err) - } - s.sTypeVersion = strings.TrimSpace(msg) - cephVersion = s.sTypeVersion - - return nil -} - -func (s *storageCephFs) StoragePoolInit() error { - var err error - - err = s.StorageCoreInit() - if err != nil { - return errors.Wrap(err, "Storage pool init") - } - - // set cluster name - if s.pool.Config["cephfs.cluster_name"] != "" { - s.ClusterName = s.pool.Config["cephfs.cluster_name"] - } else { - s.ClusterName = "ceph" - } - - // set ceph user name - if s.pool.Config["cephfs.user.name"] != "" { - s.UserName = s.pool.Config["cephfs.user.name"] - } else { - s.UserName = "admin" - } - - // set osd pool name - if s.pool.Config["cephfs.path"] != "" { - s.FsName = s.pool.Config["cephfs.path"] - } - - return nil -} - -func (s *storageCephFs) StoragePoolCheck() error { - return nil -} - -func (s *storageCephFs) StoragePoolCreate() error { - logger.Infof(`Creating CEPHFS storage pool "%s" in cluster "%s"`, s.pool.Name, s.ClusterName) - - // Setup config - s.pool.Config["volatile.initial_source"] = s.pool.Config["source"] - - if s.pool.Config["source"] == "" { - return fmt.Errorf("A CEPHFS name or name/path source is required") - } - - if s.pool.Config["cephfs.path"] != "" && s.pool.Config["cephfs.path"] != s.pool.Config["source"] { - return fmt.Errorf("cephfs.path must match the source") - } - - if s.pool.Config["cephfs.cluster_name"] == "" { - s.pool.Config["cephfs.cluster_name"] = "ceph" - } - - if s.pool.Config["cephfs.user.name"] != "" { - s.pool.Config["cephfs.user.name"] = "admin" - } - - s.pool.Config["cephfs.path"] = s.pool.Config["source"] - s.FsName = s.pool.Config["source"] - - // Parse the namespace / path - fields := strings.SplitN(s.FsName, "/", 2) - fsName := fields[0] - fsPath := "/" - if len(fields) > 1 { - fsPath = fields[1] - } - - // Check that the filesystem exists - if !cephFsExists(s.ClusterName, s.UserName, fsName) { - return fmt.Errorf("The requested '%v' CEPHFS doesn't exist", fsName) - } - - // Create a temporary mountpoint - mountPath, err := ioutil.TempDir("", "lxd_cephfs_") - if err != nil { - return err - } - defer os.RemoveAll(mountPath) - - err = os.Chmod(mountPath, 0700) - if err != nil { - return err - } - - mountPoint := filepath.Join(mountPath, "mount") - err = os.Mkdir(mountPoint, 0700) - if err != nil { - return err - } - - // Get the credentials and host - monAddresses, userSecret, err := cephFsConfig(s.ClusterName, s.UserName) - if err != nil { - return err - } - - connected := false - for _, monAddress := range monAddresses { - uri := fmt.Sprintf("%s:6789:/", monAddress) - err = driver.TryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName)) - if err != nil { - continue - } - - connected = true - defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH) - break - } - - if !connected { - return err - } - - // Create the path if missing - err = os.MkdirAll(filepath.Join(mountPoint, fsPath), 0755) - if err != nil { - return err - } - - // Check that the existing path is empty - ok, _ := shared.PathIsEmpty(filepath.Join(mountPoint, fsPath)) - if !ok { - return fmt.Errorf("Only empty CEPHFS paths can be used as a LXD storage pool") - } - - // Create the mountpoint for the storage pool. - poolMntPoint := driver.GetStoragePoolMountPoint(s.pool.Name) - err = os.MkdirAll(poolMntPoint, 0711) - if err != nil { - return err - } - - logger.Infof(`Created CEPHFS storage pool "%s" in cluster "%s"`, s.pool.Name, s.ClusterName) - - return nil -} - -func (s *storageCephFs) StoragePoolDelete() error { - logger.Infof(`Deleting CEPHFS storage pool "%s" in cluster "%s"`, s.pool.Name, s.ClusterName) - - // Parse the namespace / path - fields := strings.SplitN(s.FsName, "/", 2) - fsName := fields[0] - fsPath := "/" - if len(fields) > 1 { - fsPath = fields[1] - } - - // Create a temporary mountpoint - mountPath, err := ioutil.TempDir("", "lxd_cephfs_") - if err != nil { - return err - } - defer os.RemoveAll(mountPath) - - err = os.Chmod(mountPath, 0700) - if err != nil { - return err - } - - mountPoint := filepath.Join(mountPath, "mount") - err = os.Mkdir(mountPoint, 0700) - if err != nil { - return err - } - - // Get the credentials and host - monAddresses, userSecret, err := cephFsConfig(s.ClusterName, s.UserName) - if err != nil { - return err - } - - connected := false - for _, monAddress := range monAddresses { - uri := fmt.Sprintf("%s:6789:/", monAddress) - err = driver.TryMount(uri, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, fsName)) - if err != nil { - continue - } - - connected = true - defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH) - break - } - - if !connected { - return err - } - - if shared.PathExists(filepath.Join(mountPoint, fsPath)) { - // Delete the usual directories - for _, dir := range []string{"custom", "custom-snapshots"} { - if shared.PathExists(filepath.Join(mountPoint, fsPath, dir)) { - err = os.Remove(filepath.Join(mountPoint, fsPath, dir)) - if err != nil { - return err - } - } - } - - // Confirm that the path is now empty - ok, _ := shared.PathIsEmpty(filepath.Join(mountPoint, fsPath)) - if !ok { - return fmt.Errorf("Only empty CEPHFS paths can be used as a LXD storage pool") - } - - // Delete the path itself - if fsPath != "" && fsPath != "/" { - err = os.Remove(filepath.Join(mountPoint, fsPath)) - if err != nil { - return err - } - } - } - - // Make sure the existing pool is unmounted - _, err = s.StoragePoolUmount() - if err != nil { - return err - } - - // Delete the mountpoint for the storage pool - poolMntPoint := driver.GetStoragePoolMountPoint(s.pool.Name) - if shared.PathExists(poolMntPoint) { - err := os.RemoveAll(poolMntPoint) - if err != nil { - return err - } - logger.Debugf(`Deleted mountpoint "%s" for CEPHFS storage pool "%s" in cluster "%s"`, poolMntPoint, s.FsName, s.ClusterName) - } - - logger.Infof(`Deleted CEPHFS storage pool "%s" in cluster "%s"`, s.pool.Name, s.ClusterName) - return nil -} - -func (s *storageCephFs) StoragePoolMount() (bool, error) { - logger.Debugf("Mounting CEPHFS storage pool \"%s\"", s.pool.Name) - - // Locking - poolMountLockID := getPoolMountLockID(s.pool.Name) - lxdStorageMapLock.Lock() - if waitChannel, ok := lxdStorageOngoingOperationMap[poolMountLockID]; ok { - lxdStorageMapLock.Unlock() - if _, ok := <-waitChannel; ok { - logger.Warnf("Received value over semaphore, this should not have happened") - } - // Give the benefit of the doubt and assume that the other - // thread actually succeeded in mounting the storage pool. - return false, nil - } - - lxdStorageOngoingOperationMap[poolMountLockID] = make(chan bool) - lxdStorageMapLock.Unlock() - - removeLockFromMap := func() { - lxdStorageMapLock.Lock() - if waitChannel, ok := lxdStorageOngoingOperationMap[poolMountLockID]; ok { - close(waitChannel) - delete(lxdStorageOngoingOperationMap, poolMountLockID) - } - lxdStorageMapLock.Unlock() - } - defer removeLockFromMap() - - // Check if already mounted - poolMntPoint := driver.GetStoragePoolMountPoint(s.pool.Name) - if shared.IsMountPoint(poolMntPoint) { - return false, nil - } - - // Parse the namespace / path - fields := strings.SplitN(s.FsName, "/", 2) - fsName := fields[0] - fsPath := "/" - if len(fields) > 1 { - fsPath = fields[1] - } - - // Get the credentials and host - monAddresses, secret, err := cephFsConfig(s.ClusterName, s.UserName) - if err != nil { - return false, err - } - - // Do the actual mount - connected := false - for _, monAddress := range monAddresses { - uri := fmt.Sprintf("%s:6789:/%s", monAddress, fsPath) - err = driver.TryMount(uri, poolMntPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, secret, fsName)) - if err != nil { - continue - } - - connected = true - break - } - - if !connected { - return false, err - } - - logger.Debugf("Mounted CEPHFS storage pool \"%s\"", s.pool.Name) - - return true, nil -} - -func (s *storageCephFs) StoragePoolUmount() (bool, error) { - logger.Debugf("Unmounting CEPHFS storage pool \"%s\"", s.pool.Name) - - // Locking - poolUmountLockID := getPoolUmountLockID(s.pool.Name) - lxdStorageMapLock.Lock() - if waitChannel, ok := lxdStorageOngoingOperationMap[poolUmountLockID]; ok { - lxdStorageMapLock.Unlock() - if _, ok := <-waitChannel; ok { - logger.Warnf("Received value over semaphore, this should not have happened") - } - // Give the benefit of the doubt and assume that the other - // thread actually succeeded in unmounting the storage pool. - return false, nil - } - - lxdStorageOngoingOperationMap[poolUmountLockID] = make(chan bool) - lxdStorageMapLock.Unlock() - - removeLockFromMap := func() { - lxdStorageMapLock.Lock() - if waitChannel, ok := lxdStorageOngoingOperationMap[poolUmountLockID]; ok { - close(waitChannel) - delete(lxdStorageOngoingOperationMap, poolUmountLockID) - } - lxdStorageMapLock.Unlock() - } - - defer removeLockFromMap() - - // Check if already unmounted - poolMntPoint := driver.GetStoragePoolMountPoint(s.pool.Name) - if !shared.IsMountPoint(poolMntPoint) { - return false, nil - } - - // Unmount - err := driver.TryUnmount(poolMntPoint, syscall.MNT_DETACH) - if err != nil { - return false, err - } - - logger.Debugf("Unmounted CEPHFS pool \"%s\"", s.pool.Name) - return true, nil -} - -func (s *storageCephFs) GetStoragePoolWritable() api.StoragePoolPut { - return s.pool.Writable() -} - -func (s *storageCephFs) GetStoragePoolVolumeWritable() api.StorageVolumePut { - return s.volume.Writable() -} - -func (s *storageCephFs) SetStoragePoolWritable(writable *api.StoragePoolPut) { - s.pool.StoragePoolPut = *writable -} - -func (s *storageCephFs) SetStoragePoolVolumeWritable(writable *api.StorageVolumePut) { - s.volume.StorageVolumePut = *writable -} - -func (s *storageCephFs) GetContainerPoolInfo() (int64, string, string) { - return s.poolID, s.pool.Name, s.pool.Name -} - -func (s *storageCephFs) StoragePoolUpdate(writable *api.StoragePoolPut, changedConfig []string) error { - logger.Infof(`Updating CEPHFS storage pool "%s"`, s.pool.Name) - - // Validate the properties - changeable := changeableStoragePoolProperties["cephfs"] - unchangeable := []string{} - for _, change := range changedConfig { - if !shared.StringInSlice(change, changeable) { - unchangeable = append(unchangeable, change) - } - } - - if len(unchangeable) > 0 { - return updateStoragePoolError(unchangeable, "cephfs") - } - - logger.Infof(`Updated CEPHFS storage pool "%s"`, s.pool.Name) - return nil -} - -// Functions dealing with storage pools. -func (s *storageCephFs) StoragePoolVolumeCreate() error { - logger.Infof("Creating CEPHFS storage volume \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Create the volume - storageVolumePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - err = os.MkdirAll(storageVolumePath, 0711) - if err != nil { - return err - } - - logger.Infof("Created CEPHFS storage volume \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - return nil -} - -func (s *storageCephFs) StoragePoolVolumeDelete() error { - logger.Infof("Deleting CEPHFS storage volume \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Check if not gone already - storageVolumePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - if !shared.PathExists(storageVolumePath) { - return nil - } - - // Delete the volume - err = os.RemoveAll(storageVolumePath) - if err != nil { - return err - } - - // Delete the snapshot directory - err = os.Remove(driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name)) - if err != nil && !os.IsNotExist(err) { - return err - } - - // Delete the database entry - err = s.s.Cluster.StoragePoolVolumeDelete("default", s.volume.Name, storagePoolVolumeTypeCustom, s.poolID) - if err != nil { - return err - } - - logger.Infof("Deleted CEPHFS storage volume \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - return nil -} - -func (s *storageCephFs) StoragePoolVolumeMount() (bool, error) { - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return true, err - } - - return true, nil -} - -func (s *storageCephFs) StoragePoolVolumeUmount() (bool, error) { - return true, nil -} - -func (s *storageCephFs) StoragePoolVolumeUpdate(writable *api.StorageVolumePut, changedConfig []string) error { - // Snapshot restores - if writable.Restore != "" { - logger.Infof(`Restoring CEPHFS storage volume "%s" from snapshot "%s"`, s.volume.Name, writable.Restore) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - targetPath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - sourcePath := filepath.Join(targetPath, ".snap", writable.Restore) - - // Restore using rsync - bwlimit := s.pool.Config["rsync.bwlimit"] - output, err := rsync.LocalCopy(sourcePath, targetPath, bwlimit, false) - if err != nil { - return fmt.Errorf("Failed to rsync container: %s: %s", string(output), err) - } - - logger.Infof(`Restored CEPHFS storage volume "%s" from snapshot "%s"`, s.volume.Name, writable.Restore) - return nil - } - - // Config updates - logger.Infof(`Updating CEPHFS storage volume "%s"`, s.volume.Name) - - // Validate the properties - changeable := changeableStoragePoolVolumeProperties["cephfs"] - unchangeable := []string{} - for _, change := range changedConfig { - if !shared.StringInSlice(change, changeable) { - unchangeable = append(unchangeable, change) - } - } - - if len(unchangeable) > 0 { - return updateStoragePoolVolumeError(unchangeable, "cephfs") - } - - // Handle setting quotas - if shared.StringInSlice("size", changedConfig) { - if s.volume.Type != storagePoolVolumeTypeNameCustom { - return updateStoragePoolVolumeError([]string{"size"}, "cephfs") - } - - if s.volume.Config["size"] != writable.Config["size"] { - size, err := units.ParseByteSizeString(writable.Config["size"]) - if err != nil { - return err - } - - err = s.StorageEntitySetQuota(storagePoolVolumeTypeCustom, size, nil) - if err != nil { - return err - } - } - } - - logger.Infof(`Updated CEPHFS storage volume "%s"`, s.volume.Name) - return nil -} - -func (s *storageCephFs) StoragePoolVolumeRename(newName string) error { - logger.Infof(`Renaming CEPHFS storage volume on storage pool "%s" from "%s" to "%s`, s.pool.Name, s.volume.Name, newName) - - // Sanity check - usedBy, err := storagePoolVolumeUsedByInstancesGet(s.s, "default", s.pool.Name, s.volume.Name) - if err != nil { - return err - } - if len(usedBy) > 0 { - return fmt.Errorf(`CEPHFS storage volume "%s" on storage pool "%s" is attached to containers`, - s.volume.Name, s.pool.Name) - } - - // Make sure the pool is currently mounted - _, err = s.StoragePoolMount() - if err != nil { - return err - } - - // Rename the directory - oldPath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - newPath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, newName) - err = os.Rename(oldPath, newPath) - if err != nil { - return err - } - - // Update the database entry - err = s.s.Cluster.StoragePoolVolumeRename("default", s.volume.Name, newName, storagePoolVolumeTypeCustom, s.poolID) - if err != nil { - return err - } - - logger.Infof(`Renamed CEPHFS storage volume on storage pool "%s" from "%s" to "%s`, s.pool.Name, s.volume.Name, newName) - return nil -} - -func (s *storageCephFs) ContainerStorageReady(container instance.Instance) bool { - containerMntPoint := driver.GetContainerMountPoint(container.Project(), s.pool.Name, container.Name()) - ok, _ := shared.PathIsEmpty(containerMntPoint) - return !ok -} - -func (s *storageCephFs) ContainerCreate(container instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerCreateFromImage(container instance.Instance, imageFingerprint string, tracker *ioprogress.ProgressTracker) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerCanRestore(container instance.Instance, sourceContainer instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerDelete(container instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerCopy(target instance.Instance, source instance.Instance, containerOnly bool) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerRefresh(target instance.Instance, source instance.Instance, snapshots []instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerMount(c instance.Instance) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerUmount(c instance.Instance, path string) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerRename(container instance.Instance, newName string) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerRestore(container instance.Instance, sourceContainer instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerGetUsage(c instance.Instance) (int64, error) { - return -1, fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotCreate(snapshotContainer instance.Instance, sourceContainer instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotCreateEmpty(snapshotContainer instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotDelete(snapshotContainer instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotRename(snapshotContainer instance.Instance, newName string) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotStart(container instance.Instance) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerSnapshotStop(container instance.Instance) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerBackupCreate(path string, backup backup.Backup, source instance.Instance) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ContainerBackupLoad(info backup.Info, data io.ReadSeeker, tarArgs []string) error { - return fmt.Errorf("CEPHFS cannot be used for containers") -} - -func (s *storageCephFs) ImageCreate(fingerprint string, tracker *ioprogress.ProgressTracker) error { - return fmt.Errorf("CEPHFS cannot be used for images") -} - -func (s *storageCephFs) ImageDelete(fingerprint string) error { - return fmt.Errorf("CEPHFS cannot be used for images") -} - -func (s *storageCephFs) ImageMount(fingerprint string) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for images") -} - -func (s *storageCephFs) ImageUmount(fingerprint string) (bool, error) { - return false, fmt.Errorf("CEPHFS cannot be used for images") -} - -func (s *storageCephFs) MigrationType() migration.MigrationFSType { - return migration.MigrationFSType_RSYNC -} - -func (s *storageCephFs) PreservesInodes() bool { - return false -} - -func (s *storageCephFs) MigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDriver, error) { - return rsyncMigrationSource(args) -} - -func (s *storageCephFs) MigrationSink(conn *websocket.Conn, op *operations.Operation, args MigrationSinkArgs) error { - return rsyncMigrationSink(conn, op, args) -} - -func (s *storageCephFs) StorageEntitySetQuota(volumeType int, size int64, data interface{}) error { - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return nil - } - - // Apply the limit - storageVolumePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - _, err = shared.RunCommand("setfattr", "-n", "ceph.quota.max_bytes", "-v", fmt.Sprintf("%d", size), storageVolumePath) - if err != nil { - return err - } - - return nil -} - -func (s *storageCephFs) StoragePoolResources() (*api.ResourcesStoragePool, error) { - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return nil, err - } - - poolMntPoint := driver.GetStoragePoolMountPoint(s.pool.Name) - return driver.GetStorageResource(poolMntPoint) -} - -func (s *storageCephFs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) error { - logger.Infof("Copying CEPHFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Setup storage for the source volume - if s.pool.Name != source.Pool { - srcStorage, err := storagePoolVolumeInit(s.s, "default", source.Pool, source.Name, storagePoolVolumeTypeCustom) - if err != nil { - logger.Errorf("Failed to initialize CEPHFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err) - return err - } - - ourMount, err := srcStorage.StoragePoolMount() - if err != nil { - logger.Errorf("Failed to mount CEPHFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err) - return err - } - if ourMount { - defer srcStorage.StoragePoolUmount() - } - } - - // Create empty volume - storageVolumePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, s.volume.Name) - err = os.MkdirAll(storageVolumePath, 0711) - if err != nil { - return err - } - - // Copy the snapshots - if !source.VolumeOnly { - snapshots, err := driver.VolumeSnapshotsGet(s.s, source.Pool, source.Name, storagePoolVolumeTypeCustom) - if err != nil { - return err - } - - for _, snap := range snapshots { - _, snapOnlyName, _ := shared.InstanceGetParentAndSnapshotName(snap.Name) - err = s.copyVolume(source.Pool, snap.Name, fmt.Sprintf("%s/%s", s.volume.Name, snapOnlyName)) - if err != nil { - return err - } - } - } - - // Copy the main volume - err = s.copyVolume(source.Pool, source.Name, s.volume.Name) - if err != nil { - return err - } - - logger.Infof("Copied CEPHFS storage volume \"%s\" on storage pool \"%s\" as \"%s\" to storage pool \"%s\"", source.Name, source.Pool, s.volume.Name, s.pool.Name) - return nil -} - -func (s *storageCephFs) StorageMigrationSource(args MigrationSourceArgs) (MigrationStorageSourceDriver, error) { - return rsyncStorageMigrationSource(args) -} - -func (s *storageCephFs) StorageMigrationSink(conn *websocket.Conn, op *operations.Operation, args MigrationSinkArgs) error { - return rsyncStorageMigrationSink(conn, op, args) -} - -func (s *storageCephFs) GetStoragePool() *api.StoragePool { - return s.pool -} - -func (s *storageCephFs) GetStoragePoolVolume() *api.StorageVolume { - return s.volume -} - -func (s *storageCephFs) GetState() *state.State { - return s.s -} - -func (s *storageCephFs) StoragePoolVolumeSnapshotCreate(target *api.StorageVolumeSnapshotsPost) error { - logger.Infof("Creating CEPHFS storage volume snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Parse the name - sourceName, snapName, ok := shared.InstanceGetParentAndSnapshotName(target.Name) - if !ok { - return fmt.Errorf("Not a snapshot name") - } - - // Create the snapshot - sourcePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, sourceName) - cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - - err = os.Mkdir(cephSnapPath, 0711) - if err != nil { - return err - } - - // Make the snapshot path a symlink - targetPath := driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, target.Name) - err = os.MkdirAll(filepath.Dir(targetPath), 0711) - if err != nil { - return err - } - - err = os.Symlink(cephSnapPath, targetPath) - if err != nil { - return err - } - - logger.Infof("Created CEPHFS storage volume snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - return nil -} - -func (s *storageCephFs) StoragePoolVolumeSnapshotDelete() error { - logger.Infof("Deleting CEPHFS storage volume snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Parse the name - sourceName, snapName, ok := shared.InstanceGetParentAndSnapshotName(s.volume.Name) - if !ok { - return fmt.Errorf("Not a snapshot name") - } - - // Create the snapshot - sourcePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, sourceName) - cephSnapPath := filepath.Join(sourcePath, ".snap", snapName) - - err = os.Remove(cephSnapPath) - if err != nil && !os.IsNotExist(err) { - return err - } - - // Make the snapshot path a symlink - targetPath := driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name) - err = os.Remove(targetPath) - if err != nil && !os.IsNotExist(err) { - return err - } - - // Delete the database entry - err = s.s.Cluster.StoragePoolVolumeDelete("default", s.volume.Name, storagePoolVolumeTypeCustom, s.poolID) - if err != nil { - logger.Errorf(`Failed to delete database entry for CEPHFS storage volume snapshot "%s" on storage pool "%s"`, s.volume.Name, s.pool.Name) - return err - } - - logger.Infof("Deleted CEPHFS storage volume snapshot \"%s\" on storage pool \"%s\"", s.volume.Name, s.pool.Name) - return nil -} - -func (s *storageCephFs) StoragePoolVolumeSnapshotRename(newName string) error { - logger.Infof("Renaming CEPHFS storage volume on storage pool \"%s\" from \"%s\" to \"%s\"", s.pool.Name, s.volume.Name, newName) - - // Make sure the pool is currently mounted - _, err := s.StoragePoolMount() - if err != nil { - return err - } - - // Rename the snapshot entry - sourceName, oldSnapName, _ := shared.InstanceGetParentAndSnapshotName(s.volume.Name) - sourcePath := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, sourceName) - oldCephSnapPath := filepath.Join(sourcePath, ".snap", oldSnapName) - newCephSnapPath := filepath.Join(sourcePath, ".snap", newName) - - err = os.Rename(oldCephSnapPath, newCephSnapPath) - if err != nil { - return err - } - - // Re-generate the snapshot symlink - oldPath := driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name) - err = os.Remove(oldPath) - if err != nil { - return err - } - - newPath := driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, filepath.Join(sourceName, newName)) - err = os.Symlink(newCephSnapPath, newPath) - if err != nil { - return err - } - - // Update the database record - fullSnapshotName := fmt.Sprintf("%s%s%s", sourceName, shared.SnapshotDelimiter, newName) - err = s.s.Cluster.StoragePoolVolumeRename("default", s.volume.Name, fullSnapshotName, storagePoolVolumeTypeCustom, s.poolID) - if err != nil { - return err - } - - logger.Infof("Renamed CEPHFS storage volume on storage pool \"%s\" from \"%s\" to \"%s\"", s.pool.Name, s.volume.Name, newName) - return nil -} - -func (s *storageCephFs) copyVolume(sourcePool string, source string, target string) error { - // Figure out the mountpoints - var srcMountPoint string - if shared.IsSnapshot(source) { - srcMountPoint = driver.GetStoragePoolVolumeSnapshotMountPoint(sourcePool, source) - } else { - srcMountPoint = driver.GetStoragePoolVolumeMountPoint(sourcePool, source) - } - - // Split target name - targetVolName, targetSnapName, ok := shared.InstanceGetParentAndSnapshotName(target) - - // Figure out target path - dstMountPoint := driver.GetStoragePoolVolumeMountPoint(s.pool.Name, targetVolName) - - // Sync data on target - bwlimit := s.pool.Config["rsync.bwlimit"] - _, err := rsync.LocalCopy(srcMountPoint, dstMountPoint, bwlimit, false) - if err != nil { - logger.Errorf("Failed to rsync into CEPHFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err) - return err - } - - // Snapshot target - if ok { - cephSnapPath := filepath.Join(dstMountPoint, ".snap", targetSnapName) - err := os.Mkdir(cephSnapPath, 0711) - if err != nil { - return err - } - - // Make the snapshot path a symlink - targetPath := driver.GetStoragePoolVolumeSnapshotMountPoint(s.pool.Name, target) - err = os.MkdirAll(filepath.Dir(targetPath), 0711) - if err != nil { - return err - } - - err = os.Symlink(cephSnapPath, targetPath) - if err != nil { - return err - } - } - - return nil -} - -func cephFsExists(clusterName string, userName string, fsName string) bool { - _, err := shared.RunCommand("ceph", "--name", fmt.Sprintf("client.%s", userName), "--cluster", clusterName, "fs", "get", fsName) - if err != nil { - return false - } - - return true -} - -func cephFsConfig(clusterName string, userName string) ([]string, string, error) { - // Parse the CEPH configuration - cephConf, err := os.Open(fmt.Sprintf("/etc/ceph/%s.conf", clusterName)) - if err != nil { - return nil, "", err - } - - cephMon := []string{} - - scan := bufio.NewScanner(cephConf) - for scan.Scan() { - line := scan.Text() - line = strings.TrimSpace(line) - - if line == "" { - continue - } - - if strings.HasPrefix(line, "mon_host") { - fields := strings.SplitN(line, "=", 2) - if len(fields) < 2 { - continue - } - - servers := strings.Split(fields[1], ",") - for _, server := range servers { - cephMon = append(cephMon, strings.TrimSpace(server)) - } - break - } - } - - if len(cephMon) == 0 { - return nil, "", fmt.Errorf("Couldn't find a CPEH mon") - } - - // Parse the CEPH keyring - cephKeyring, err := os.Open(fmt.Sprintf("/etc/ceph/%v.client.%v.keyring", clusterName, userName)) - if err != nil { - return nil, "", err - } - - var cephSecret string - - scan = bufio.NewScanner(cephKeyring) - for scan.Scan() { - line := scan.Text() - line = strings.TrimSpace(line) - - if line == "" { - continue - } - - if strings.HasPrefix(line, "key") { - fields := strings.SplitN(line, "=", 2) - if len(fields) < 2 { - continue - } - - cephSecret = strings.TrimSpace(fields[1]) - break - } - } - - if cephSecret == "" { - return nil, "", fmt.Errorf("Couldn't find a keyring entry") - } - - return cephMon, cephSecret, nil -}
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel