]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/volumes/fs/operations/versions/__init__.py
import ceph 15.2.10
[ceph.git] / ceph / src / pybind / mgr / volumes / fs / operations / versions / __init__.py
CommitLineData
92f5a8d4
TL
1import errno
2import logging
3import importlib
4
5import cephfs
6
7from .subvolume_base import SubvolumeBase
adb31ebb
TL
8from .subvolume_attrs import SubvolumeTypes
9from .subvolume_v1 import SubvolumeV1
10from .subvolume_v2 import SubvolumeV2
11from .metadata_manager import MetadataManager
12from .op_sm import SubvolumeOpSm
13from ..template import SubvolumeOpType
9f95a23c 14from ...exception import MetadataMgrException, OpSmException, VolumeException
92f5a8d4
TL
15
16log = logging.getLogger(__name__)
17
18class SubvolumeLoader(object):
19 INVALID_VERSION = -1
20
adb31ebb 21 SUPPORTED_MODULES = ['subvolume_v1.SubvolumeV1', 'subvolume_v2.SubvolumeV2']
92f5a8d4
TL
22
23 def __init__(self):
24 self.max_version = SubvolumeLoader.INVALID_VERSION
25 self.versions = {}
26
27 def _load_module(self, mod_cls):
28 mod_name, cls_name = mod_cls.split('.')
29 mod = importlib.import_module('.versions.{0}'.format(mod_name), package='volumes.fs.operations')
30 return getattr(mod, cls_name)
31
32 def _load_supported_versions(self):
33 for mod_cls in SubvolumeLoader.SUPPORTED_MODULES:
34 cls = self._load_module(mod_cls)
35 log.info("loaded v{0} subvolume".format(cls.version()))
36 if self.max_version is not None or cls.version() > self.max_version:
37 self.max_version = cls.version()
38 self.versions[cls.version()] = cls
39 if self.max_version == SubvolumeLoader.INVALID_VERSION:
9f95a23c 40 raise VolumeException(-errno.EINVAL, "no subvolume version available")
92f5a8d4
TL
41 log.info("max subvolume version is v{0}".format(self.max_version))
42
43 def _get_subvolume_version(self, version):
44 try:
45 return self.versions[version]
46 except KeyError:
47 raise VolumeException(-errno.EINVAL, "subvolume class v{0} does not exist".format(version))
48
cd265ab1
TL
49 def get_subvolume_object_max(self, mgr, fs, vol_spec, group, subvolname):
50 return self._get_subvolume_version(self.max_version)(mgr, fs, vol_spec, group, subvolname)
92f5a8d4 51
adb31ebb
TL
52 def upgrade_to_v2_subvolume(self, subvolume):
53 # legacy mode subvolumes cannot be upgraded to v2
54 if subvolume.legacy_mode:
55 return
56
57 version = int(subvolume.metadata_mgr.get_global_option('version'))
58 if version >= SubvolumeV2.version():
59 return
60
cd265ab1 61 v1_subvolume = self._get_subvolume_version(version)(subvolume.mgr, subvolume.fs, subvolume.vol_spec, subvolume.group, subvolume.subvolname)
adb31ebb
TL
62 try:
63 v1_subvolume.open(SubvolumeOpType.SNAP_LIST)
64 except VolumeException as ve:
65 # if volume is not ready for snapshot listing, do not upgrade at present
66 if ve.errno == -errno.EAGAIN:
67 return
68 raise
69
70 # v1 subvolumes with snapshots cannot be upgraded to v2
71 if v1_subvolume.list_snapshots():
72 return
73
74 subvolume.metadata_mgr.update_global_section(MetadataManager.GLOBAL_META_KEY_VERSION, SubvolumeV2.version())
75 subvolume.metadata_mgr.flush()
76
92f5a8d4
TL
77 def upgrade_legacy_subvolume(self, fs, subvolume):
78 assert subvolume.legacy_mode
79 try:
80 fs.mkdirs(subvolume.legacy_dir, 0o700)
81 except cephfs.Error as e:
82 raise VolumeException(-e.args[0], "error accessing subvolume")
adb31ebb 83 subvolume_type = SubvolumeTypes.TYPE_NORMAL
92f5a8d4 84 try:
adb31ebb 85 initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
92f5a8d4
TL
86 except OpSmException as oe:
87 raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
88 qpath = subvolume.base_path.decode('utf-8')
adb31ebb
TL
89 # legacy is only upgradable to v1
90 subvolume.init_config(SubvolumeV1.version(), subvolume_type, qpath, initial_state)
92f5a8d4 91
cd265ab1
TL
92 def get_subvolume_object(self, mgr, fs, vol_spec, group, subvolname, upgrade=True):
93 subvolume = SubvolumeBase(mgr, fs, vol_spec, group, subvolname)
92f5a8d4
TL
94 try:
95 subvolume.discover()
adb31ebb 96 self.upgrade_to_v2_subvolume(subvolume)
92f5a8d4 97 version = int(subvolume.metadata_mgr.get_global_option('version'))
cd265ab1 98 return self._get_subvolume_version(version)(mgr, fs, vol_spec, group, subvolname, legacy=subvolume.legacy_mode)
92f5a8d4
TL
99 except MetadataMgrException as me:
100 if me.errno == -errno.ENOENT and upgrade:
101 self.upgrade_legacy_subvolume(fs, subvolume)
cd265ab1 102 return self.get_subvolume_object(mgr, fs, vol_spec, group, subvolname, upgrade=False)
92f5a8d4
TL
103 else:
104 # log the actual error and generalize error string returned to user
105 log.error("error accessing subvolume metadata for '{0}' ({1})".format(subvolname, me))
106 raise VolumeException(-errno.EINVAL, "error accessing subvolume metadata")
107
108loaded_subvolumes = SubvolumeLoader()
109loaded_subvolumes._load_supported_versions()