import cephfs
from .subvolume_base import SubvolumeBase
-from ..op_sm import OpSm
+from .subvolume_attrs import SubvolumeTypes
+from .subvolume_v1 import SubvolumeV1
+from .subvolume_v2 import SubvolumeV2
+from .metadata_manager import MetadataManager
+from .op_sm import SubvolumeOpSm
+from ..template import SubvolumeOpType
from ...exception import MetadataMgrException, OpSmException, VolumeException
log = logging.getLogger(__name__)
class SubvolumeLoader(object):
INVALID_VERSION = -1
- SUPPORTED_MODULES = ['subvolume_v1.SubvolumeV1']
+ SUPPORTED_MODULES = ['subvolume_v1.SubvolumeV1', 'subvolume_v2.SubvolumeV2']
def __init__(self):
self.max_version = SubvolumeLoader.INVALID_VERSION
except KeyError:
raise VolumeException(-errno.EINVAL, "subvolume class v{0} does not exist".format(version))
- def get_subvolume_object_max(self, fs, vol_spec, group, subvolname):
- return self._get_subvolume_version(self.max_version)(fs, vol_spec, group, subvolname)
+ def get_subvolume_object_max(self, mgr, fs, vol_spec, group, subvolname):
+ return self._get_subvolume_version(self.max_version)(mgr, fs, vol_spec, group, subvolname)
+
+ def upgrade_to_v2_subvolume(self, subvolume):
+ # legacy mode subvolumes cannot be upgraded to v2
+ if subvolume.legacy_mode:
+ return
+
+ version = int(subvolume.metadata_mgr.get_global_option('version'))
+ if version >= SubvolumeV2.version():
+ return
+
+ v1_subvolume = self._get_subvolume_version(version)(subvolume.mgr, subvolume.fs, subvolume.vol_spec, subvolume.group, subvolume.subvolname)
+ try:
+ v1_subvolume.open(SubvolumeOpType.SNAP_LIST)
+ except VolumeException as ve:
+ # if volume is not ready for snapshot listing, do not upgrade at present
+ if ve.errno == -errno.EAGAIN:
+ return
+ raise
+
+ # v1 subvolumes with snapshots cannot be upgraded to v2
+ if v1_subvolume.list_snapshots():
+ return
+
+ subvolume.metadata_mgr.update_global_section(MetadataManager.GLOBAL_META_KEY_VERSION, SubvolumeV2.version())
+ subvolume.metadata_mgr.flush()
def upgrade_legacy_subvolume(self, fs, subvolume):
assert subvolume.legacy_mode
fs.mkdirs(subvolume.legacy_dir, 0o700)
except cephfs.Error as e:
raise VolumeException(-e.args[0], "error accessing subvolume")
- subvolume_type = SubvolumeBase.SUBVOLUME_TYPE_NORMAL
+ subvolume_type = SubvolumeTypes.TYPE_NORMAL
try:
- initial_state = OpSm.get_init_state(subvolume_type)
+ initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
except OpSmException as oe:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
qpath = subvolume.base_path.decode('utf-8')
- subvolume.init_config(self.max_version, subvolume_type, qpath, initial_state)
+ # legacy is only upgradable to v1
+ subvolume.init_config(SubvolumeV1.version(), subvolume_type, qpath, initial_state)
- def get_subvolume_object(self, fs, vol_spec, group, subvolname, upgrade=True):
- subvolume = SubvolumeBase(fs, vol_spec, group, subvolname)
+ def get_subvolume_object(self, mgr, fs, vol_spec, group, subvolname, upgrade=True):
+ subvolume = SubvolumeBase(mgr, fs, vol_spec, group, subvolname)
try:
subvolume.discover()
+ self.upgrade_to_v2_subvolume(subvolume)
version = int(subvolume.metadata_mgr.get_global_option('version'))
- return self._get_subvolume_version(version)(fs, vol_spec, group, subvolname, legacy=subvolume.legacy_mode)
+ return self._get_subvolume_version(version)(mgr, fs, vol_spec, group, subvolname, legacy=subvolume.legacy_mode)
except MetadataMgrException as me:
if me.errno == -errno.ENOENT and upgrade:
self.upgrade_legacy_subvolume(fs, subvolume)
- return self.get_subvolume_object(fs, vol_spec, group, subvolname, upgrade=False)
+ return self.get_subvolume_object(mgr, fs, vol_spec, group, subvolname, upgrade=False)
else:
# log the actual error and generalize error string returned to user
log.error("error accessing subvolume metadata for '{0}' ({1})".format(subvolname, me))