]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py
check in ceph 17.2.3 sources
[ceph.git] / ceph / src / pybind / mgr / volumes / fs / operations / versions / metadata_manager.py
CommitLineData
92f5a8d4
TL
1import os
2import errno
3import logging
9f95a23c 4import sys
92f5a8d4 5
9f95a23c 6if sys.version_info >= (3, 2):
92f5a8d4 7 import configparser
9f95a23c 8else:
92f5a8d4
TL
9 import ConfigParser as configparser
10
11try:
12 from StringIO import StringIO
13except ImportError:
14 from io import StringIO
15
16import cephfs
17
18from ...exception import MetadataMgrException
19
20log = logging.getLogger(__name__)
21
22class MetadataManager(object):
23 GLOBAL_SECTION = "GLOBAL"
33c7a0ef 24 USER_METADATA_SECTION = "USER_METADATA"
92f5a8d4
TL
25 GLOBAL_META_KEY_VERSION = "version"
26 GLOBAL_META_KEY_TYPE = "type"
27 GLOBAL_META_KEY_PATH = "path"
28 GLOBAL_META_KEY_STATE = "state"
29
33c7a0ef
TL
30 CLONE_FAILURE_SECTION = "CLONE_FAILURE"
31 CLONE_FAILURE_META_KEY_ERRNO = "errno"
32 CLONE_FAILURE_META_KEY_ERROR_MSG = "error_msg"
33
92f5a8d4
TL
34 MAX_IO_BYTES = 8 * 1024
35
36 def __init__(self, fs, config_path, mode):
37 self.fs = fs
38 self.mode = mode
39 self.config_path = config_path
9f95a23c
TL
40 if sys.version_info >= (3, 2):
41 self.config = configparser.ConfigParser()
42 else:
43 self.config = configparser.SafeConfigParser()
92f5a8d4
TL
44
45 def refresh(self):
46 fd = None
47 conf_data = StringIO()
0948533f 48 log.debug("opening config {0}".format(self.config_path))
92f5a8d4 49 try:
92f5a8d4
TL
50 fd = self.fs.open(self.config_path, os.O_RDONLY)
51 while True:
52 data = self.fs.read(fd, -1, MetadataManager.MAX_IO_BYTES)
53 if not len(data):
54 break
55 conf_data.write(data.decode('utf-8'))
0948533f
TL
56 except UnicodeDecodeError:
57 raise MetadataMgrException(-errno.EINVAL,
58 "failed to decode, erroneous metadata config '{0}'".format(self.config_path))
92f5a8d4
TL
59 except cephfs.ObjectNotFound:
60 raise MetadataMgrException(-errno.ENOENT, "metadata config '{0}' not found".format(self.config_path))
61 except cephfs.Error as e:
62 raise MetadataMgrException(-e.args[0], e.args[1])
63 finally:
64 if fd is not None:
65 self.fs.close(fd)
0948533f
TL
66
67 conf_data.seek(0)
68 try:
69 if sys.version_info >= (3, 2):
70 self.config.read_file(conf_data)
71 else:
72 self.config.readfp(conf_data)
73 except configparser.Error:
74 raise MetadataMgrException(-errno.EINVAL, "failed to parse, erroneous metadata config "
75 "'{0}'".format(self.config_path))
92f5a8d4
TL
76
77 def flush(self):
78 # cull empty sections
79 for section in list(self.config.sections()):
80 if len(self.config.items(section)) == 0:
81 self.config.remove_section(section)
82
83 conf_data = StringIO()
84 self.config.write(conf_data)
85 conf_data.seek(0)
86
87 fd = None
88 try:
89 fd = self.fs.open(self.config_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, self.mode)
90 wrote = 0
91 while True:
92 data = conf_data.read()
93 if not len(data):
94 break
95 wrote += self.fs.write(fd, data.encode('utf-8'), -1)
96 self.fs.fsync(fd, 0)
97 log.info("wrote {0} bytes to config {1}".format(wrote, self.config_path))
98 except cephfs.Error as e:
99 raise MetadataMgrException(-e.args[0], e.args[1])
100 finally:
101 if fd is not None:
102 self.fs.close(fd)
103
104 def init(self, version, typ, path, state):
105 # you may init just once before refresh (helps to overwrite conf)
106 if self.config.has_section(MetadataManager.GLOBAL_SECTION):
107 raise MetadataMgrException(-errno.EINVAL, "init called on an existing config")
108
109 self.add_section(MetadataManager.GLOBAL_SECTION)
110 self.update_section_multi(
111 MetadataManager.GLOBAL_SECTION, {MetadataManager.GLOBAL_META_KEY_VERSION : str(version),
112 MetadataManager.GLOBAL_META_KEY_TYPE : str(typ),
113 MetadataManager.GLOBAL_META_KEY_PATH : str(path),
114 MetadataManager.GLOBAL_META_KEY_STATE : str(state)
115 })
116
117 def add_section(self, section):
118 try:
119 self.config.add_section(section)
120 except configparser.DuplicateSectionError:
121 return
122 except:
123 raise MetadataMgrException(-errno.EINVAL, "error adding section to config")
124
125 def remove_option(self, section, key):
126 if not self.config.has_section(section):
127 raise MetadataMgrException(-errno.ENOENT, "section '{0}' does not exist".format(section))
33c7a0ef 128 return self.config.remove_option(section, key)
92f5a8d4
TL
129
130 def remove_section(self, section):
131 self.config.remove_section(section)
132
133 def update_section(self, section, key, value):
134 if not self.config.has_section(section):
135 raise MetadataMgrException(-errno.ENOENT, "section '{0}' does not exist".format(section))
136 self.config.set(section, key, str(value))
137
138 def update_section_multi(self, section, dct):
139 if not self.config.has_section(section):
140 raise MetadataMgrException(-errno.ENOENT, "section '{0}' does not exist".format(section))
141 for key,value in dct.items():
142 self.config.set(section, key, str(value))
143
144 def update_global_section(self, key, value):
145 self.update_section(MetadataManager.GLOBAL_SECTION, key, str(value))
146
147 def get_option(self, section, key):
148 if not self.config.has_section(section):
149 raise MetadataMgrException(-errno.ENOENT, "section '{0}' does not exist".format(section))
150 if not self.config.has_option(section, key):
151 raise MetadataMgrException(-errno.ENOENT, "no config '{0}' in section '{1}'".format(key, section))
152 return self.config.get(section, key)
153
154 def get_global_option(self, key):
155 return self.get_option(MetadataManager.GLOBAL_SECTION, key)
156
33c7a0ef
TL
157 def list_all_options_from_section(self, section):
158 metadata_dict = {}
159 if self.config.has_section(section):
160 options = self.config.options(section)
161 for option in options:
162 metadata_dict[option] = self.config.get(section,option)
163 return metadata_dict
164
92f5a8d4
TL
165 def section_has_item(self, section, item):
166 if not self.config.has_section(section):
167 raise MetadataMgrException(-errno.ENOENT, "section '{0}' does not exist".format(section))
168 return item in [v[1] for v in self.config.items(section)]