]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | import os |
2 | import errno | |
3 | import logging | |
9f95a23c | 4 | import sys |
92f5a8d4 | 5 | |
9f95a23c | 6 | if sys.version_info >= (3, 2): |
92f5a8d4 | 7 | import configparser |
9f95a23c | 8 | else: |
92f5a8d4 TL |
9 | import ConfigParser as configparser |
10 | ||
11 | try: | |
12 | from StringIO import StringIO | |
13 | except ImportError: | |
14 | from io import StringIO | |
15 | ||
16 | import cephfs | |
17 | ||
18 | from ...exception import MetadataMgrException | |
19 | ||
20 | log = logging.getLogger(__name__) | |
21 | ||
22 | class 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)] |