]>
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 | |
8 | from ..op_sm import OpSm | |
9 | from ...exception import VolumeException, MetadataMgrException | |
10 | ||
11 | log = logging.getLogger(__name__) | |
12 | ||
13 | class SubvolumeLoader(object): | |
14 | INVALID_VERSION = -1 | |
15 | ||
16 | SUPPORTED_MODULES = ['subvolume_v1.SubvolumeV1'] | |
17 | ||
18 | def __init__(self): | |
19 | self.max_version = SubvolumeLoader.INVALID_VERSION | |
20 | self.versions = {} | |
21 | ||
22 | def _load_module(self, mod_cls): | |
23 | mod_name, cls_name = mod_cls.split('.') | |
24 | mod = importlib.import_module('.versions.{0}'.format(mod_name), package='volumes.fs.operations') | |
25 | return getattr(mod, cls_name) | |
26 | ||
27 | def _load_supported_versions(self): | |
28 | for mod_cls in SubvolumeLoader.SUPPORTED_MODULES: | |
29 | cls = self._load_module(mod_cls) | |
30 | log.info("loaded v{0} subvolume".format(cls.version())) | |
31 | if self.max_version is not None or cls.version() > self.max_version: | |
32 | self.max_version = cls.version() | |
33 | self.versions[cls.version()] = cls | |
34 | if self.max_version == SubvolumeLoader.INVALID_VERSION: | |
35 | raise VolumeException("no subvolume version available") | |
36 | log.info("max subvolume version is v{0}".format(self.max_version)) | |
37 | ||
38 | def _get_subvolume_version(self, version): | |
39 | try: | |
40 | return self.versions[version] | |
41 | except KeyError: | |
42 | raise VolumeException(-errno.EINVAL, "subvolume class v{0} does not exist".format(version)) | |
43 | ||
44 | def get_subvolume_object_max(self, fs, vol_spec, group, subvolname): | |
45 | return self._get_subvolume_version(self.max_version)(fs, vol_spec, group, subvolname) | |
46 | ||
47 | def upgrade_legacy_subvolume(self, fs, subvolume): | |
48 | assert subvolume.legacy_mode | |
49 | try: | |
50 | fs.mkdirs(subvolume.legacy_dir, 0o700) | |
51 | except cephfs.Error as e: | |
52 | raise VolumeException(-e.args[0], "error accessing subvolume") | |
53 | subvolume_type = SubvolumeBase.SUBVOLUME_TYPE_NORMAL | |
54 | try: | |
55 | initial_state = OpSm.get_init_state(subvolume_type) | |
56 | except OpSmException as oe: | |
57 | raise VolumeException(-errno.EINVAL, "subvolume creation failed: internal error") | |
58 | qpath = subvolume.base_path.decode('utf-8') | |
59 | subvolume.init_config(self.max_version, subvolume_type, qpath, initial_state) | |
60 | ||
61 | def get_subvolume_object(self, fs, vol_spec, group, subvolname, upgrade=True): | |
62 | subvolume = SubvolumeBase(fs, vol_spec, group, subvolname) | |
63 | try: | |
64 | subvolume.discover() | |
65 | version = int(subvolume.metadata_mgr.get_global_option('version')) | |
66 | return self._get_subvolume_version(version)(fs, vol_spec, group, subvolname, legacy=subvolume.legacy_mode) | |
67 | except MetadataMgrException as me: | |
68 | if me.errno == -errno.ENOENT and upgrade: | |
69 | self.upgrade_legacy_subvolume(fs, subvolume) | |
70 | subvolume = None | |
71 | return self.get_subvolume_object(fs, vol_spec, group, subvolname, upgrade=False) | |
72 | else: | |
73 | # log the actual error and generalize error string returned to user | |
74 | log.error("error accessing subvolume metadata for '{0}' ({1})".format(subvolname, me)) | |
75 | raise VolumeException(-errno.EINVAL, "error accessing subvolume metadata") | |
76 | ||
77 | loaded_subvolumes = SubvolumeLoader() | |
78 | loaded_subvolumes._load_supported_versions() |