[lxc-devel] [lxd/master] lxd/storage: Remove legacy cephfs implementation

stgraber on Github lxc-bot at linuxcontainers.org
Thu Dec 5 20:14:02 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 354 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191205/b0fa47d1/attachment-0001.bin>
-------------- next part --------------
From 37a690ca88ab52a6653f4e7fb2083b9b56b83cab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at 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 <stgraber at 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
-}


More information about the lxc-devel mailing list