summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/volumes/fs/operations/versions
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/volumes/fs/operations/versions')
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/__init__.py17
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py2
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/op_sm.py2
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py4
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py41
-rw-r--r--src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py25
6 files changed, 54 insertions, 37 deletions
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/__init__.py b/src/pybind/mgr/volumes/fs/operations/versions/__init__.py
index 544afa165..097620d73 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/__init__.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/__init__.py
@@ -49,6 +49,18 @@ class SubvolumeLoader(object):
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 allow_subvolume_upgrade(self, subvolume):
+ asu = True
+ try:
+ opt = subvolume.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_ALLOW_SUBVOLUME_UPGRADE)
+ asu = False if opt == "0" else True
+ except MetadataMgrException:
+ # this key is injected for QA testing and will not be available in
+ # production
+ pass
+
+ return asu
+
def upgrade_to_v2_subvolume(self, subvolume):
# legacy mode subvolumes cannot be upgraded to v2
if subvolume.legacy_mode:
@@ -58,6 +70,9 @@ class SubvolumeLoader(object):
if version >= SubvolumeV2.version():
return
+ if not self.allow_subvolume_upgrade(subvolume):
+ 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)
@@ -83,7 +98,7 @@ class SubvolumeLoader(object):
subvolume_type = SubvolumeTypes.TYPE_NORMAL
try:
initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
- except OpSmException as oe:
+ except OpSmException:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
qpath = subvolume.base_path.decode('utf-8')
# legacy is only upgradable to v1
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py b/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py
index 718735d91..610a61e6a 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py
@@ -1,7 +1,6 @@
import os
import errno
import logging
-import sys
import threading
import configparser
import re
@@ -59,6 +58,7 @@ class MetadataManager(object):
GLOBAL_META_KEY_TYPE = "type"
GLOBAL_META_KEY_PATH = "path"
GLOBAL_META_KEY_STATE = "state"
+ GLOBAL_META_KEY_ALLOW_SUBVOLUME_UPGRADE = "allow_subvolume_upgrade"
CLONE_FAILURE_SECTION = "CLONE_FAILURE"
CLONE_FAILURE_META_KEY_ERRNO = "errno"
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/op_sm.py b/src/pybind/mgr/volumes/fs/operations/versions/op_sm.py
index 1142600cb..93eafb2bd 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/op_sm.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/op_sm.py
@@ -19,7 +19,7 @@ class TransitionKey(object):
return not(self == other)
class SubvolumeOpSm(object):
- transition_table = {} # type: Dict
+ transition_table: Dict = {}
@staticmethod
def is_complete_state(state):
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py
index 3bae0707a..8fbe177e5 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py
@@ -144,7 +144,7 @@ class SubvolumeBase(object):
try:
self.fs.stat(self.legacy_config_path)
self.legacy_mode = True
- except cephfs.Error as e:
+ except cephfs.Error:
pass
log.debug("loading config "
@@ -160,7 +160,7 @@ class SubvolumeBase(object):
def get_attrs(self, pathname):
# get subvolume attributes
- attrs = {} # type: Dict[str, Union[int, str, None]]
+ attrs: Dict[str, Union[int, str, None]] = {}
stx = self.fs.statx(pathname,
cephfs.CEPH_STATX_UID | cephfs.CEPH_STATX_GID
| cephfs.CEPH_STATX_MODE,
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py
index b5a10dd6c..90f35a4c9 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py
@@ -55,7 +55,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
try:
# no need to stat the path -- open() does that
return self.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_PATH).encode('utf-8')
- except MetadataMgrException as me:
+ except MetadataMgrException:
raise VolumeException(-errno.EINVAL, "error fetching subvolume metadata")
@property
@@ -68,7 +68,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
try:
# MDS treats this as a noop for already marked subvolume
self.fs.setxattr(self.path, 'ceph.dir.subvolume', b'1', 0)
- except cephfs.InvalidValue as e:
+ except cephfs.InvalidValue:
raise VolumeException(-errno.EINVAL, "invalid value specified for ceph.dir.subvolume")
except cephfs.Error as e:
raise VolumeException(-e.args[0], e.args[1])
@@ -89,7 +89,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
subvolume_type = SubvolumeTypes.TYPE_NORMAL
try:
initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
- except OpSmException as oe:
+ except OpSmException:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
subvol_path = os.path.join(self.base_path, str(uuid.uuid4()).encode('utf-8'))
@@ -98,7 +98,6 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
create_base_dir(self.fs, self.group.path, self.vol_spec.DEFAULT_MODE)
# create directory and set attributes
self.fs.mkdirs(subvol_path, mode)
- self.mark_subvolume()
attrs = {
'uid': uid,
'gid': gid,
@@ -111,6 +110,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
# persist subvolume metadata
qpath = subvol_path.decode('utf-8')
self.init_config(SubvolumeV1.VERSION, subvolume_type, qpath, initial_state)
+ self.mark_subvolume()
except (VolumeException, MetadataMgrException, cephfs.Error) as e:
try:
log.info("cleaning up subvolume with path: {0}".format(self.subvolname))
@@ -156,7 +156,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
subvolume_type = SubvolumeTypes.TYPE_CLONE
try:
initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
- except OpSmException as oe:
+ except OpSmException:
raise VolumeException(-errno.EINVAL, "clone failed: internal error")
subvol_path = os.path.join(self.base_path, str(uuid.uuid4()).encode('utf-8'))
@@ -596,7 +596,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
"""
with self.auth_mdata_mgr.subvol_metadata_lock(self.group.groupname, self.subvolname):
meta = self.auth_mdata_mgr.subvol_metadata_get(self.group.groupname, self.subvolname)
- auths = [] # type: List[Dict[str,str]]
+ auths: List[Dict[str,str]] = []
if not meta or not meta['auths']:
return auths
@@ -669,7 +669,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
pass
else:
raise
- except MetadataMgrException as me:
+ except MetadataMgrException:
raise VolumeException(-errno.EINVAL, "error fetching subvolume metadata")
return clone_source
@@ -684,16 +684,16 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
def status(self):
state = SubvolumeStates.from_value(self.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_STATE))
subvolume_type = self.subvol_type
- subvolume_status = {
- 'state' : state.value
- }
- if not SubvolumeOpSm.is_complete_state(state) and subvolume_type == SubvolumeTypes.TYPE_CLONE:
- subvolume_status["source"] = self._get_clone_source()
- if SubvolumeOpSm.is_failed_state(state) and subvolume_type == SubvolumeTypes.TYPE_CLONE:
- try:
- subvolume_status["failure"] = self._get_clone_failure()
- except MetadataMgrException:
- pass
+ subvolume_status = {'state' : state.value}
+
+ if subvolume_type == SubvolumeTypes.TYPE_CLONE:
+ if not SubvolumeOpSm.is_complete_state(state):
+ subvolume_status["source"] = self._get_clone_source()
+ if SubvolumeOpSm.is_failed_state(state):
+ try:
+ subvolume_status["failure"] = self._get_clone_failure()
+ except MetadataMgrException:
+ pass
return subvolume_status
@@ -744,7 +744,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
raise
def get_pending_clones(self, snapname):
- pending_clones_info = {"has_pending_clones": "no"} # type: Dict[str, Any]
+ pending_clones_info: Dict[str, Any] = {"has_pending_clones": "no"}
pending_track_id_list = []
pending_clone_list = []
index_path = ""
@@ -777,7 +777,6 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
# If clone is completed between 'list_all_keys_with_specified_values_from_section'
# and readlink(track_id_path) call then readlink will fail with error ENOENT (2)
# Hence we double check whether track_id is exist in .meta file or not.
- value = self.metadata_mgr.get_option('clone snaps', track_id)
# Edge case scenario.
# If track_id for clone exist but path /volumes/_index/clone/{track_id} not found
# then clone is orphan.
@@ -790,7 +789,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
path = Path(link_path.decode('utf-8'))
clone_name = os.path.basename(link_path).decode('utf-8')
group_name = os.path.basename(path.parent.absolute())
- details = {"name": clone_name} # type: Dict[str, str]
+ details = {"name": clone_name}
if group_name != Group.NO_GROUP_NAME:
details["target_group"] = group_name
pending_clone_list.append(details)
@@ -839,7 +838,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate):
snap_info[key] = self.fs.getxattr(snappath, val)
pending_clones_info = self.get_pending_clones(snapname)
info_dict = {'created_at': str(datetime.fromtimestamp(float(snap_info['created_at']))),
- 'data_pool': snap_info['data_pool'].decode('utf-8')} # type: Dict[str, Any]
+ 'data_pool': snap_info['data_pool'].decode('utf-8')}
info_dict.update(pending_clones_info);
return info_dict
except cephfs.Error as e:
diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py
index 03085d049..55d7f945b 100644
--- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py
+++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v2.py
@@ -10,7 +10,6 @@ from .metadata_manager import MetadataManager
from .subvolume_attrs import SubvolumeTypes, SubvolumeStates, SubvolumeFeatures
from .op_sm import SubvolumeOpSm
from .subvolume_v1 import SubvolumeV1
-from ..template import SubvolumeTemplate
from ...exception import OpSmException, VolumeException, MetadataMgrException
from ...fs_util import listdir, create_base_dir
from ..template import SubvolumeOpType
@@ -99,7 +98,7 @@ class SubvolumeV2(SubvolumeV1):
try:
# MDS treats this as a noop for already marked subvolume
self.fs.setxattr(self.base_path, 'ceph.dir.subvolume', b'1', 0)
- except cephfs.InvalidValue as e:
+ except cephfs.InvalidValue:
raise VolumeException(-errno.EINVAL, "invalid value specified for ceph.dir.subvolume")
except cephfs.Error as e:
raise VolumeException(-e.args[0], e.args[1])
@@ -159,7 +158,7 @@ class SubvolumeV2(SubvolumeV1):
subvolume_type = SubvolumeTypes.TYPE_NORMAL
try:
initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
- except OpSmException as oe:
+ except OpSmException:
raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
retained = self.retained
@@ -207,7 +206,7 @@ class SubvolumeV2(SubvolumeV1):
subvolume_type = SubvolumeTypes.TYPE_CLONE
try:
initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
- except OpSmException as oe:
+ except OpSmException:
raise VolumeException(-errno.EINVAL, "clone failed: internal error")
retained = self.retained
@@ -308,13 +307,17 @@ class SubvolumeV2(SubvolumeV1):
op_type.value, self.subvolname, etype.value))
estate = self.state
- if op_type not in self.allowed_ops_by_state(estate) and estate == SubvolumeStates.STATE_RETAINED:
- raise VolumeException(-errno.ENOENT, "subvolume '{0}' is removed and has only snapshots retained".format(
- self.subvolname))
-
- if op_type not in self.allowed_ops_by_state(estate) and estate != SubvolumeStates.STATE_RETAINED:
- raise VolumeException(-errno.EAGAIN, "subvolume '{0}' is not ready for operation {1}".format(
- self.subvolname, op_type.value))
+ if op_type not in self.allowed_ops_by_state(estate):
+ if estate == SubvolumeStates.STATE_RETAINED:
+ raise VolumeException(
+ -errno.ENOENT,
+ f'subvolume "{self.subvolname}" is removed and has '
+ 'only snapshots retained')
+ else:
+ raise VolumeException(
+ -errno.EAGAIN,
+ f'subvolume "{self.subvolname}" is not ready for '
+ f'operation "{op_type.value}"')
if estate != SubvolumeStates.STATE_RETAINED:
subvol_path = self.path