]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | import errno |
2 | import logging | |
3 | import importlib | |
4 | ||
5 | import cephfs | |
6 | ||
7 | from .subvolume_base import SubvolumeBase | |
adb31ebb TL |
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 | |
9f95a23c | 14 | from ...exception import MetadataMgrException, OpSmException, VolumeException |
92f5a8d4 TL |
15 | |
16 | log = logging.getLogger(__name__) | |
17 | ||
18 | class 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 | ||
108 | loaded_subvolumes = SubvolumeLoader() | |
109 | loaded_subvolumes._load_supported_versions() |