]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/volumes/fs/operations/versions/__init__.py
import ceph quincy 17.2.4
[ceph.git] / ceph / src / pybind / mgr / volumes / fs / operations / versions / __init__.py
1 import errno
2 import logging
3 import importlib
4
5 import cephfs
6
7 from .subvolume_base import SubvolumeBase
8 from .subvolume_attrs import SubvolumeTypes
9 from .subvolume_v1 import SubvolumeV1
10 from .subvolume_v2 import SubvolumeV2
11 from .metadata_manager import MetadataManager
12 from .op_sm import SubvolumeOpSm
13 from ..template import SubvolumeOpType
14 from ...exception import MetadataMgrException, OpSmException, VolumeException
15
16 log = logging.getLogger(__name__)
17
18 class SubvolumeLoader(object):
19 INVALID_VERSION = -1
20
21 SUPPORTED_MODULES = ['subvolume_v1.SubvolumeV1', 'subvolume_v2.SubvolumeV2']
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:
40 raise VolumeException(-errno.EINVAL, "no subvolume version available")
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
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)
51
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
61 v1_subvolume = self._get_subvolume_version(version)(subvolume.mgr, subvolume.fs, subvolume.vol_spec, subvolume.group, subvolume.subvolname)
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
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")
83 subvolume_type = SubvolumeTypes.TYPE_NORMAL
84 try:
85 initial_state = SubvolumeOpSm.get_init_state(subvolume_type)
86 except OpSmException as oe:
87 raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error")
88 qpath = subvolume.base_path.decode('utf-8')
89 # legacy is only upgradable to v1
90 subvolume.init_config(SubvolumeV1.version(), subvolume_type, qpath, initial_state)
91
92 def get_subvolume_object(self, mgr, fs, vol_spec, group, subvolname, upgrade=True):
93 subvolume = SubvolumeBase(mgr, fs, vol_spec, group, subvolname)
94 try:
95 subvolume.discover()
96 self.upgrade_to_v2_subvolume(subvolume)
97 version = int(subvolume.metadata_mgr.get_global_option('version'))
98 subvolume_version_object = self._get_subvolume_version(version)(mgr, fs, vol_spec, group, subvolname, legacy=subvolume.legacy_mode)
99 subvolume_version_object.metadata_mgr.refresh()
100 subvolume_version_object.clean_stale_snapshot_metadata()
101 return subvolume_version_object
102 except MetadataMgrException as me:
103 if me.errno == -errno.ENOENT and upgrade:
104 self.upgrade_legacy_subvolume(fs, subvolume)
105 return self.get_subvolume_object(mgr, fs, vol_spec, group, subvolname, upgrade=False)
106 else:
107 # log the actual error and generalize error string returned to user
108 log.error("error accessing subvolume metadata for '{0}' ({1})".format(subvolname, me))
109 raise VolumeException(-errno.EINVAL, "error accessing subvolume metadata")
110
111 loaded_subvolumes = SubvolumeLoader()
112 loaded_subvolumes._load_supported_versions()