root / lib / storage / container.py @ ba174485
History | View | Annotate | Download (13.2 kB)
1 | ac2d0fe4 | Michael Hanselmann | #
|
---|---|---|---|
2 | ac2d0fe4 | Michael Hanselmann | #
|
3 | ac2d0fe4 | Michael Hanselmann | |
4 | 048eeb2b | Iustin Pop | # Copyright (C) 2009, 2011, 2012 Google Inc.
|
5 | ac2d0fe4 | Michael Hanselmann | #
|
6 | ac2d0fe4 | Michael Hanselmann | # This program is free software; you can redistribute it and/or modify
|
7 | ac2d0fe4 | Michael Hanselmann | # it under the terms of the GNU General Public License as published by
|
8 | ac2d0fe4 | Michael Hanselmann | # the Free Software Foundation; either version 2 of the License, or
|
9 | ac2d0fe4 | Michael Hanselmann | # (at your option) any later version.
|
10 | ac2d0fe4 | Michael Hanselmann | #
|
11 | ac2d0fe4 | Michael Hanselmann | # This program is distributed in the hope that it will be useful, but
|
12 | ac2d0fe4 | Michael Hanselmann | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | ac2d0fe4 | Michael Hanselmann | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | ac2d0fe4 | Michael Hanselmann | # General Public License for more details.
|
15 | ac2d0fe4 | Michael Hanselmann | #
|
16 | ac2d0fe4 | Michael Hanselmann | # You should have received a copy of the GNU General Public License
|
17 | ac2d0fe4 | Michael Hanselmann | # along with this program; if not, write to the Free Software
|
18 | ac2d0fe4 | Michael Hanselmann | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | ac2d0fe4 | Michael Hanselmann | # 02110-1301, USA.
|
20 | ac2d0fe4 | Michael Hanselmann | |
21 | ac2d0fe4 | Michael Hanselmann | |
22 | ac2d0fe4 | Michael Hanselmann | """Storage container abstraction.
|
23 | ac2d0fe4 | Michael Hanselmann |
|
24 | ac2d0fe4 | Michael Hanselmann | """
|
25 | ac2d0fe4 | Michael Hanselmann | |
26 | b459a848 | Andrea Spadaccini | # pylint: disable=W0232,R0201
|
27 | 7260cfbe | Iustin Pop | |
28 | 7260cfbe | Iustin Pop | # W0232, since we use these as singletons rather than object holding
|
29 | 7260cfbe | Iustin Pop | # data
|
30 | 7260cfbe | Iustin Pop | |
31 | 7260cfbe | Iustin Pop | # R0201, for the same reason
|
32 | 7260cfbe | Iustin Pop | |
33 | 7260cfbe | Iustin Pop | # TODO: FileStorage initialised with paths whereas the others not
|
34 | ac2d0fe4 | Michael Hanselmann | |
35 | ac2d0fe4 | Michael Hanselmann | import logging |
36 | ac2d0fe4 | Michael Hanselmann | |
37 | ac2d0fe4 | Michael Hanselmann | from ganeti import errors |
38 | ac2d0fe4 | Michael Hanselmann | from ganeti import constants |
39 | ac2d0fe4 | Michael Hanselmann | from ganeti import utils |
40 | ac2d0fe4 | Michael Hanselmann | |
41 | ac2d0fe4 | Michael Hanselmann | |
42 | ac2d0fe4 | Michael Hanselmann | def _ParseSize(value): |
43 | ac2d0fe4 | Michael Hanselmann | return int(round(float(value), 0)) |
44 | ac2d0fe4 | Michael Hanselmann | |
45 | ac2d0fe4 | Michael Hanselmann | |
46 | ac2d0fe4 | Michael Hanselmann | class _Base: |
47 | ac2d0fe4 | Michael Hanselmann | """Base class for storage abstraction.
|
48 | ac2d0fe4 | Michael Hanselmann |
|
49 | ac2d0fe4 | Michael Hanselmann | """
|
50 | ac2d0fe4 | Michael Hanselmann | def List(self, name, fields): |
51 | ac2d0fe4 | Michael Hanselmann | """Returns a list of all entities within the storage unit.
|
52 | ac2d0fe4 | Michael Hanselmann |
|
53 | ac2d0fe4 | Michael Hanselmann | @type name: string or None
|
54 | ac2d0fe4 | Michael Hanselmann | @param name: Entity name or None for all
|
55 | ac2d0fe4 | Michael Hanselmann | @type fields: list
|
56 | ac2d0fe4 | Michael Hanselmann | @param fields: List with all requested result fields (order is preserved)
|
57 | ac2d0fe4 | Michael Hanselmann |
|
58 | ac2d0fe4 | Michael Hanselmann | """
|
59 | ac2d0fe4 | Michael Hanselmann | raise NotImplementedError() |
60 | ac2d0fe4 | Michael Hanselmann | |
61 | b459a848 | Andrea Spadaccini | def Modify(self, name, changes): # pylint: disable=W0613 |
62 | 9b648ee7 | Michael Hanselmann | """Modifies an entity within the storage unit.
|
63 | 9b648ee7 | Michael Hanselmann |
|
64 | 9b648ee7 | Michael Hanselmann | @type name: string
|
65 | 9b648ee7 | Michael Hanselmann | @param name: Entity name
|
66 | 9b648ee7 | Michael Hanselmann | @type changes: dict
|
67 | 9b648ee7 | Michael Hanselmann | @param changes: New field values
|
68 | 9b648ee7 | Michael Hanselmann |
|
69 | 9b648ee7 | Michael Hanselmann | """
|
70 | 9b648ee7 | Michael Hanselmann | # Don't raise an error if no changes are requested
|
71 | 9b648ee7 | Michael Hanselmann | if changes:
|
72 | 9b648ee7 | Michael Hanselmann | raise errors.ProgrammerError("Unable to modify the following" |
73 | 9b648ee7 | Michael Hanselmann | "fields: %r" % (changes.keys(), ))
|
74 | 9b648ee7 | Michael Hanselmann | |
75 | 4b37cac5 | Michael Hanselmann | def Execute(self, name, op): |
76 | 4b37cac5 | Michael Hanselmann | """Executes an operation on an entity within the storage unit.
|
77 | 4b37cac5 | Michael Hanselmann |
|
78 | 4b37cac5 | Michael Hanselmann | @type name: string
|
79 | 4b37cac5 | Michael Hanselmann | @param name: Entity name
|
80 | 4b37cac5 | Michael Hanselmann | @type op: string
|
81 | 4b37cac5 | Michael Hanselmann | @param op: Operation name
|
82 | 4b37cac5 | Michael Hanselmann |
|
83 | 4b37cac5 | Michael Hanselmann | """
|
84 | 4b37cac5 | Michael Hanselmann | raise NotImplementedError() |
85 | 4b37cac5 | Michael Hanselmann | |
86 | ac2d0fe4 | Michael Hanselmann | |
87 | b459a848 | Andrea Spadaccini | class FileStorage(_Base): # pylint: disable=W0223 |
88 | ac2d0fe4 | Michael Hanselmann | """File storage unit.
|
89 | ac2d0fe4 | Michael Hanselmann |
|
90 | ac2d0fe4 | Michael Hanselmann | """
|
91 | ac2d0fe4 | Michael Hanselmann | def __init__(self, paths): |
92 | ac2d0fe4 | Michael Hanselmann | """Initializes this class.
|
93 | ac2d0fe4 | Michael Hanselmann |
|
94 | ac2d0fe4 | Michael Hanselmann | @type paths: list
|
95 | ac2d0fe4 | Michael Hanselmann | @param paths: List of file storage paths
|
96 | ac2d0fe4 | Michael Hanselmann |
|
97 | ac2d0fe4 | Michael Hanselmann | """
|
98 | ac2d0fe4 | Michael Hanselmann | self._paths = paths
|
99 | ac2d0fe4 | Michael Hanselmann | |
100 | ac2d0fe4 | Michael Hanselmann | def List(self, name, fields): |
101 | ac2d0fe4 | Michael Hanselmann | """Returns a list of all entities within the storage unit.
|
102 | ac2d0fe4 | Michael Hanselmann |
|
103 | ac2d0fe4 | Michael Hanselmann | See L{_Base.List}.
|
104 | ac2d0fe4 | Michael Hanselmann |
|
105 | ac2d0fe4 | Michael Hanselmann | """
|
106 | ac2d0fe4 | Michael Hanselmann | rows = [] |
107 | ac2d0fe4 | Michael Hanselmann | |
108 | ac2d0fe4 | Michael Hanselmann | if name is None: |
109 | ac2d0fe4 | Michael Hanselmann | paths = self._paths
|
110 | ac2d0fe4 | Michael Hanselmann | else:
|
111 | ac2d0fe4 | Michael Hanselmann | paths = [name] |
112 | ac2d0fe4 | Michael Hanselmann | |
113 | ac2d0fe4 | Michael Hanselmann | for path in paths: |
114 | ac2d0fe4 | Michael Hanselmann | rows.append(self._ListInner(path, fields))
|
115 | ac2d0fe4 | Michael Hanselmann | |
116 | ac2d0fe4 | Michael Hanselmann | return rows
|
117 | ac2d0fe4 | Michael Hanselmann | |
118 | ac2d0fe4 | Michael Hanselmann | @staticmethod
|
119 | ac2d0fe4 | Michael Hanselmann | def _ListInner(path, fields): |
120 | ac2d0fe4 | Michael Hanselmann | """Gathers requested information from directory.
|
121 | ac2d0fe4 | Michael Hanselmann |
|
122 | ac2d0fe4 | Michael Hanselmann | @type path: string
|
123 | ac2d0fe4 | Michael Hanselmann | @param path: Path to directory
|
124 | ac2d0fe4 | Michael Hanselmann | @type fields: list
|
125 | ac2d0fe4 | Michael Hanselmann | @param fields: Requested fields
|
126 | ac2d0fe4 | Michael Hanselmann |
|
127 | ac2d0fe4 | Michael Hanselmann | """
|
128 | ac2d0fe4 | Michael Hanselmann | values = [] |
129 | ac2d0fe4 | Michael Hanselmann | |
130 | ac2d0fe4 | Michael Hanselmann | # Pre-calculate information in case it's requested more than once
|
131 | 6032697c | Michael Hanselmann | if constants.SF_USED in fields: |
132 | ac2d0fe4 | Michael Hanselmann | dirsize = utils.CalculateDirectorySize(path) |
133 | ac2d0fe4 | Michael Hanselmann | else:
|
134 | ac2d0fe4 | Michael Hanselmann | dirsize = None
|
135 | ac2d0fe4 | Michael Hanselmann | |
136 | 620a85fd | Iustin Pop | if constants.SF_FREE in fields or constants.SF_SIZE in fields: |
137 | 620a85fd | Iustin Pop | fsstats = utils.GetFilesystemStats(path) |
138 | ac2d0fe4 | Michael Hanselmann | else:
|
139 | 620a85fd | Iustin Pop | fsstats = None
|
140 | ac2d0fe4 | Michael Hanselmann | |
141 | 6032697c | Michael Hanselmann | # Make sure to update constants.VALID_STORAGE_FIELDS when changing fields.
|
142 | ac2d0fe4 | Michael Hanselmann | for field_name in fields: |
143 | 6032697c | Michael Hanselmann | if field_name == constants.SF_NAME:
|
144 | ac2d0fe4 | Michael Hanselmann | values.append(path) |
145 | ac2d0fe4 | Michael Hanselmann | |
146 | 6032697c | Michael Hanselmann | elif field_name == constants.SF_USED:
|
147 | ac2d0fe4 | Michael Hanselmann | values.append(dirsize) |
148 | ac2d0fe4 | Michael Hanselmann | |
149 | 6032697c | Michael Hanselmann | elif field_name == constants.SF_FREE:
|
150 | 620a85fd | Iustin Pop | values.append(fsstats[1])
|
151 | 620a85fd | Iustin Pop | |
152 | 620a85fd | Iustin Pop | elif field_name == constants.SF_SIZE:
|
153 | 620a85fd | Iustin Pop | values.append(fsstats[0])
|
154 | 620a85fd | Iustin Pop | |
155 | 620a85fd | Iustin Pop | elif field_name == constants.SF_ALLOCATABLE:
|
156 | 620a85fd | Iustin Pop | values.append(True)
|
157 | ac2d0fe4 | Michael Hanselmann | |
158 | ac2d0fe4 | Michael Hanselmann | else:
|
159 | ac2d0fe4 | Michael Hanselmann | raise errors.StorageError("Unknown field: %r" % field_name) |
160 | ac2d0fe4 | Michael Hanselmann | |
161 | ac2d0fe4 | Michael Hanselmann | return values
|
162 | ac2d0fe4 | Michael Hanselmann | |
163 | ac2d0fe4 | Michael Hanselmann | |
164 | b459a848 | Andrea Spadaccini | class _LvmBase(_Base): # pylint: disable=W0223 |
165 | ac2d0fe4 | Michael Hanselmann | """Base class for LVM storage containers.
|
166 | ac2d0fe4 | Michael Hanselmann |
|
167 | 620a85fd | Iustin Pop | @cvar LIST_FIELDS: list of tuples consisting of three elements: SF_*
|
168 | 620a85fd | Iustin Pop | constants, lvm command output fields (list), and conversion
|
169 | 620a85fd | Iustin Pop | function or static value (for static value, the lvm output field
|
170 | 620a85fd | Iustin Pop | can be an empty list)
|
171 | 620a85fd | Iustin Pop |
|
172 | ac2d0fe4 | Michael Hanselmann | """
|
173 | ac2d0fe4 | Michael Hanselmann | LIST_SEP = "|"
|
174 | ac2d0fe4 | Michael Hanselmann | LIST_COMMAND = None
|
175 | ac2d0fe4 | Michael Hanselmann | LIST_FIELDS = None
|
176 | ac2d0fe4 | Michael Hanselmann | |
177 | ac2d0fe4 | Michael Hanselmann | def List(self, name, wanted_field_names): |
178 | ac2d0fe4 | Michael Hanselmann | """Returns a list of all entities within the storage unit.
|
179 | ac2d0fe4 | Michael Hanselmann |
|
180 | ac2d0fe4 | Michael Hanselmann | See L{_Base.List}.
|
181 | ac2d0fe4 | Michael Hanselmann |
|
182 | ac2d0fe4 | Michael Hanselmann | """
|
183 | ac2d0fe4 | Michael Hanselmann | # Get needed LVM fields
|
184 | ac2d0fe4 | Michael Hanselmann | lvm_fields = self._GetLvmFields(self.LIST_FIELDS, wanted_field_names) |
185 | ac2d0fe4 | Michael Hanselmann | |
186 | ac2d0fe4 | Michael Hanselmann | # Build LVM command
|
187 | ac2d0fe4 | Michael Hanselmann | cmd_args = self._BuildListCommand(self.LIST_COMMAND, self.LIST_SEP, |
188 | ac2d0fe4 | Michael Hanselmann | lvm_fields, name) |
189 | ac2d0fe4 | Michael Hanselmann | |
190 | ac2d0fe4 | Michael Hanselmann | # Run LVM command
|
191 | ac2d0fe4 | Michael Hanselmann | cmd_result = self._RunListCommand(cmd_args)
|
192 | ac2d0fe4 | Michael Hanselmann | |
193 | ac2d0fe4 | Michael Hanselmann | # Split and rearrange LVM command output
|
194 | ac2d0fe4 | Michael Hanselmann | return self._BuildList(self._SplitList(cmd_result, self.LIST_SEP, |
195 | ac2d0fe4 | Michael Hanselmann | len(lvm_fields)),
|
196 | ac2d0fe4 | Michael Hanselmann | self.LIST_FIELDS,
|
197 | ac2d0fe4 | Michael Hanselmann | wanted_field_names, |
198 | ac2d0fe4 | Michael Hanselmann | lvm_fields) |
199 | ac2d0fe4 | Michael Hanselmann | |
200 | ac2d0fe4 | Michael Hanselmann | @staticmethod
|
201 | ac2d0fe4 | Michael Hanselmann | def _GetLvmFields(fields_def, wanted_field_names): |
202 | ac2d0fe4 | Michael Hanselmann | """Returns unique list of fields wanted from LVM command.
|
203 | ac2d0fe4 | Michael Hanselmann |
|
204 | ac2d0fe4 | Michael Hanselmann | @type fields_def: list
|
205 | ac2d0fe4 | Michael Hanselmann | @param fields_def: Field definitions
|
206 | ac2d0fe4 | Michael Hanselmann | @type wanted_field_names: list
|
207 | ac2d0fe4 | Michael Hanselmann | @param wanted_field_names: List of requested fields
|
208 | ac2d0fe4 | Michael Hanselmann |
|
209 | ac2d0fe4 | Michael Hanselmann | """
|
210 | ac2d0fe4 | Michael Hanselmann | field_to_idx = dict([(field_name, idx)
|
211 | 4d4a651d | Michael Hanselmann | for (idx, (field_name, _, _)) in |
212 | 4d4a651d | Michael Hanselmann | enumerate(fields_def)])
|
213 | ac2d0fe4 | Michael Hanselmann | |
214 | ac2d0fe4 | Michael Hanselmann | lvm_fields = [] |
215 | ac2d0fe4 | Michael Hanselmann | |
216 | ac2d0fe4 | Michael Hanselmann | for field_name in wanted_field_names: |
217 | ac2d0fe4 | Michael Hanselmann | try:
|
218 | ac2d0fe4 | Michael Hanselmann | idx = field_to_idx[field_name] |
219 | ac2d0fe4 | Michael Hanselmann | except IndexError: |
220 | ac2d0fe4 | Michael Hanselmann | raise errors.StorageError("Unknown field: %r" % field_name) |
221 | ac2d0fe4 | Michael Hanselmann | |
222 | 620a85fd | Iustin Pop | (_, lvm_names, _) = fields_def[idx] |
223 | ac2d0fe4 | Michael Hanselmann | |
224 | 620a85fd | Iustin Pop | lvm_fields.extend(lvm_names) |
225 | ac2d0fe4 | Michael Hanselmann | |
226 | ac2d0fe4 | Michael Hanselmann | return utils.UniqueSequence(lvm_fields)
|
227 | ac2d0fe4 | Michael Hanselmann | |
228 | ac2d0fe4 | Michael Hanselmann | @classmethod
|
229 | ac2d0fe4 | Michael Hanselmann | def _BuildList(cls, cmd_result, fields_def, wanted_field_names, lvm_fields): |
230 | ac2d0fe4 | Michael Hanselmann | """Builds the final result list.
|
231 | ac2d0fe4 | Michael Hanselmann |
|
232 | ac2d0fe4 | Michael Hanselmann | @type cmd_result: iterable
|
233 | ac2d0fe4 | Michael Hanselmann | @param cmd_result: Iterable of LVM command output (iterable of lists)
|
234 | ac2d0fe4 | Michael Hanselmann | @type fields_def: list
|
235 | ac2d0fe4 | Michael Hanselmann | @param fields_def: Field definitions
|
236 | ac2d0fe4 | Michael Hanselmann | @type wanted_field_names: list
|
237 | ac2d0fe4 | Michael Hanselmann | @param wanted_field_names: List of requested fields
|
238 | ac2d0fe4 | Michael Hanselmann | @type lvm_fields: list
|
239 | ac2d0fe4 | Michael Hanselmann | @param lvm_fields: LVM fields
|
240 | ac2d0fe4 | Michael Hanselmann |
|
241 | ac2d0fe4 | Michael Hanselmann | """
|
242 | ac2d0fe4 | Michael Hanselmann | lvm_name_to_idx = dict([(lvm_name, idx)
|
243 | ac2d0fe4 | Michael Hanselmann | for (idx, lvm_name) in enumerate(lvm_fields)]) |
244 | ac2d0fe4 | Michael Hanselmann | field_to_idx = dict([(field_name, idx)
|
245 | 4d4a651d | Michael Hanselmann | for (idx, (field_name, _, _)) in |
246 | 4d4a651d | Michael Hanselmann | enumerate(fields_def)])
|
247 | ac2d0fe4 | Michael Hanselmann | |
248 | ac2d0fe4 | Michael Hanselmann | data = [] |
249 | ac2d0fe4 | Michael Hanselmann | for raw_data in cmd_result: |
250 | ac2d0fe4 | Michael Hanselmann | row = [] |
251 | ac2d0fe4 | Michael Hanselmann | |
252 | ac2d0fe4 | Michael Hanselmann | for field_name in wanted_field_names: |
253 | 620a85fd | Iustin Pop | (_, lvm_names, mapper) = fields_def[field_to_idx[field_name]] |
254 | ac2d0fe4 | Michael Hanselmann | |
255 | 620a85fd | Iustin Pop | values = [raw_data[lvm_name_to_idx[i]] for i in lvm_names] |
256 | ac2d0fe4 | Michael Hanselmann | |
257 | 620a85fd | Iustin Pop | if callable(mapper): |
258 | 620a85fd | Iustin Pop | # we got a function, call it with all the declared fields
|
259 | b459a848 | Andrea Spadaccini | val = mapper(*values) # pylint: disable=W0142
|
260 | 620a85fd | Iustin Pop | elif len(values) == 1: |
261 | 985e3f77 | Iustin Pop | assert mapper is None, ("Invalid mapper value (neither callable" |
262 | 985e3f77 | Iustin Pop | " nor None) for one-element fields")
|
263 | 620a85fd | Iustin Pop | # we don't have a function, but we had a single field
|
264 | 620a85fd | Iustin Pop | # declared, pass it unchanged
|
265 | 620a85fd | Iustin Pop | val = values[0]
|
266 | 620a85fd | Iustin Pop | else:
|
267 | 620a85fd | Iustin Pop | # let's make sure there are no fields declared (cannot map >
|
268 | 620a85fd | Iustin Pop | # 1 field without a function)
|
269 | 620a85fd | Iustin Pop | assert not values, "LVM storage has multi-fields without a function" |
270 | 620a85fd | Iustin Pop | val = mapper |
271 | ac2d0fe4 | Michael Hanselmann | |
272 | 620a85fd | Iustin Pop | row.append(val) |
273 | ac2d0fe4 | Michael Hanselmann | |
274 | ac2d0fe4 | Michael Hanselmann | data.append(row) |
275 | ac2d0fe4 | Michael Hanselmann | |
276 | ac2d0fe4 | Michael Hanselmann | return data
|
277 | ac2d0fe4 | Michael Hanselmann | |
278 | ac2d0fe4 | Michael Hanselmann | @staticmethod
|
279 | ac2d0fe4 | Michael Hanselmann | def _BuildListCommand(cmd, sep, options, name): |
280 | ac2d0fe4 | Michael Hanselmann | """Builds LVM command line.
|
281 | ac2d0fe4 | Michael Hanselmann |
|
282 | ac2d0fe4 | Michael Hanselmann | @type cmd: string
|
283 | ac2d0fe4 | Michael Hanselmann | @param cmd: Command name
|
284 | ac2d0fe4 | Michael Hanselmann | @type sep: string
|
285 | ac2d0fe4 | Michael Hanselmann | @param sep: Field separator character
|
286 | ac2d0fe4 | Michael Hanselmann | @type options: list of strings
|
287 | ac2d0fe4 | Michael Hanselmann | @param options: Wanted LVM fields
|
288 | ac2d0fe4 | Michael Hanselmann | @type name: name or None
|
289 | ac2d0fe4 | Michael Hanselmann | @param name: Name of requested entity
|
290 | ac2d0fe4 | Michael Hanselmann |
|
291 | ac2d0fe4 | Michael Hanselmann | """
|
292 | ac2d0fe4 | Michael Hanselmann | args = [cmd, |
293 | ac2d0fe4 | Michael Hanselmann | "--noheadings", "--units=m", "--nosuffix", |
294 | ac2d0fe4 | Michael Hanselmann | "--separator", sep,
|
295 | ac2d0fe4 | Michael Hanselmann | "--options", ",".join(options)] |
296 | ac2d0fe4 | Michael Hanselmann | |
297 | ac2d0fe4 | Michael Hanselmann | if name is not None: |
298 | ac2d0fe4 | Michael Hanselmann | args.append(name) |
299 | ac2d0fe4 | Michael Hanselmann | |
300 | ac2d0fe4 | Michael Hanselmann | return args
|
301 | ac2d0fe4 | Michael Hanselmann | |
302 | ac2d0fe4 | Michael Hanselmann | @staticmethod
|
303 | ac2d0fe4 | Michael Hanselmann | def _RunListCommand(args): |
304 | ac2d0fe4 | Michael Hanselmann | """Run LVM command.
|
305 | ac2d0fe4 | Michael Hanselmann |
|
306 | ac2d0fe4 | Michael Hanselmann | """
|
307 | ac2d0fe4 | Michael Hanselmann | result = utils.RunCmd(args) |
308 | ac2d0fe4 | Michael Hanselmann | |
309 | ac2d0fe4 | Michael Hanselmann | if result.failed:
|
310 | ac2d0fe4 | Michael Hanselmann | raise errors.StorageError("Failed to run %r, command output: %s" % |
311 | ac2d0fe4 | Michael Hanselmann | (args[0], result.output))
|
312 | ac2d0fe4 | Michael Hanselmann | |
313 | ac2d0fe4 | Michael Hanselmann | return result.stdout
|
314 | ac2d0fe4 | Michael Hanselmann | |
315 | ac2d0fe4 | Michael Hanselmann | @staticmethod
|
316 | ac2d0fe4 | Michael Hanselmann | def _SplitList(data, sep, fieldcount): |
317 | ac2d0fe4 | Michael Hanselmann | """Splits LVM command output into rows and fields.
|
318 | ac2d0fe4 | Michael Hanselmann |
|
319 | ac2d0fe4 | Michael Hanselmann | @type data: string
|
320 | ac2d0fe4 | Michael Hanselmann | @param data: LVM command output
|
321 | ac2d0fe4 | Michael Hanselmann | @type sep: string
|
322 | ac2d0fe4 | Michael Hanselmann | @param sep: Field separator character
|
323 | ac2d0fe4 | Michael Hanselmann | @type fieldcount: int
|
324 | ac2d0fe4 | Michael Hanselmann | @param fieldcount: Expected number of fields
|
325 | ac2d0fe4 | Michael Hanselmann |
|
326 | ac2d0fe4 | Michael Hanselmann | """
|
327 | ac2d0fe4 | Michael Hanselmann | for line in data.splitlines(): |
328 | ac2d0fe4 | Michael Hanselmann | fields = line.strip().split(sep) |
329 | ac2d0fe4 | Michael Hanselmann | |
330 | ac2d0fe4 | Michael Hanselmann | if len(fields) != fieldcount: |
331 | 620a85fd | Iustin Pop | logging.warning("Invalid line returned from lvm command: %s", line)
|
332 | ac2d0fe4 | Michael Hanselmann | continue
|
333 | ac2d0fe4 | Michael Hanselmann | |
334 | ac2d0fe4 | Michael Hanselmann | yield fields
|
335 | ac2d0fe4 | Michael Hanselmann | |
336 | ac2d0fe4 | Michael Hanselmann | |
337 | 5ae7cd11 | Michael Hanselmann | def _LvmPvGetAllocatable(attr): |
338 | 5ae7cd11 | Michael Hanselmann | """Determines whether LVM PV is allocatable.
|
339 | 5ae7cd11 | Michael Hanselmann |
|
340 | 5ae7cd11 | Michael Hanselmann | @rtype: bool
|
341 | 5ae7cd11 | Michael Hanselmann |
|
342 | 5ae7cd11 | Michael Hanselmann | """
|
343 | 5ae7cd11 | Michael Hanselmann | if attr:
|
344 | 5ae7cd11 | Michael Hanselmann | return (attr[0] == "a") |
345 | 5ae7cd11 | Michael Hanselmann | else:
|
346 | 5ae7cd11 | Michael Hanselmann | logging.warning("Invalid PV attribute: %r", attr)
|
347 | 5ae7cd11 | Michael Hanselmann | return False |
348 | 5ae7cd11 | Michael Hanselmann | |
349 | 5ae7cd11 | Michael Hanselmann | |
350 | b459a848 | Andrea Spadaccini | class LvmPvStorage(_LvmBase): # pylint: disable=W0223 |
351 | ac2d0fe4 | Michael Hanselmann | """LVM Physical Volume storage unit.
|
352 | ac2d0fe4 | Michael Hanselmann |
|
353 | ac2d0fe4 | Michael Hanselmann | """
|
354 | ac2d0fe4 | Michael Hanselmann | LIST_COMMAND = "pvs"
|
355 | 6032697c | Michael Hanselmann | |
356 | 6032697c | Michael Hanselmann | # Make sure to update constants.VALID_STORAGE_FIELDS when changing field
|
357 | 6032697c | Michael Hanselmann | # definitions.
|
358 | ac2d0fe4 | Michael Hanselmann | LIST_FIELDS = [ |
359 | 620a85fd | Iustin Pop | (constants.SF_NAME, ["pv_name"], None), |
360 | 620a85fd | Iustin Pop | (constants.SF_SIZE, ["pv_size"], _ParseSize),
|
361 | 620a85fd | Iustin Pop | (constants.SF_USED, ["pv_used"], _ParseSize),
|
362 | 620a85fd | Iustin Pop | (constants.SF_FREE, ["pv_free"], _ParseSize),
|
363 | 5ae7cd11 | Michael Hanselmann | (constants.SF_ALLOCATABLE, ["pv_attr"], _LvmPvGetAllocatable),
|
364 | ac2d0fe4 | Michael Hanselmann | ] |
365 | ac2d0fe4 | Michael Hanselmann | |
366 | 9b648ee7 | Michael Hanselmann | def _SetAllocatable(self, name, allocatable): |
367 | 9b648ee7 | Michael Hanselmann | """Sets the "allocatable" flag on a physical volume.
|
368 | 9b648ee7 | Michael Hanselmann |
|
369 | 9b648ee7 | Michael Hanselmann | @type name: string
|
370 | 9b648ee7 | Michael Hanselmann | @param name: Physical volume name
|
371 | 9b648ee7 | Michael Hanselmann | @type allocatable: bool
|
372 | 9b648ee7 | Michael Hanselmann | @param allocatable: Whether to set the "allocatable" flag
|
373 | 9b648ee7 | Michael Hanselmann |
|
374 | 9b648ee7 | Michael Hanselmann | """
|
375 | 9b648ee7 | Michael Hanselmann | args = ["pvchange", "--allocatable"] |
376 | 9b648ee7 | Michael Hanselmann | |
377 | 9b648ee7 | Michael Hanselmann | if allocatable:
|
378 | 9b648ee7 | Michael Hanselmann | args.append("y")
|
379 | 9b648ee7 | Michael Hanselmann | else:
|
380 | 9b648ee7 | Michael Hanselmann | args.append("n")
|
381 | 9b648ee7 | Michael Hanselmann | |
382 | 9b648ee7 | Michael Hanselmann | args.append(name) |
383 | 9b648ee7 | Michael Hanselmann | |
384 | 9b648ee7 | Michael Hanselmann | result = utils.RunCmd(args) |
385 | 9b648ee7 | Michael Hanselmann | if result.failed:
|
386 | 9b648ee7 | Michael Hanselmann | raise errors.StorageError("Failed to modify physical volume," |
387 | 9b648ee7 | Michael Hanselmann | " pvchange output: %s" %
|
388 | 9b648ee7 | Michael Hanselmann | result.output) |
389 | 9b648ee7 | Michael Hanselmann | |
390 | 9b648ee7 | Michael Hanselmann | def Modify(self, name, changes): |
391 | 9b648ee7 | Michael Hanselmann | """Modifies flags on a physical volume.
|
392 | 9b648ee7 | Michael Hanselmann |
|
393 | 9b648ee7 | Michael Hanselmann | See L{_Base.Modify}.
|
394 | 9b648ee7 | Michael Hanselmann |
|
395 | 9b648ee7 | Michael Hanselmann | """
|
396 | 9b648ee7 | Michael Hanselmann | if constants.SF_ALLOCATABLE in changes: |
397 | 9b648ee7 | Michael Hanselmann | self._SetAllocatable(name, changes[constants.SF_ALLOCATABLE])
|
398 | 9b648ee7 | Michael Hanselmann | del changes[constants.SF_ALLOCATABLE]
|
399 | 9b648ee7 | Michael Hanselmann | |
400 | 9b648ee7 | Michael Hanselmann | # Other changes will be handled (and maybe refused) by the base class.
|
401 | 9b648ee7 | Michael Hanselmann | return _LvmBase.Modify(self, name, changes) |
402 | 9b648ee7 | Michael Hanselmann | |
403 | ac2d0fe4 | Michael Hanselmann | |
404 | ac2d0fe4 | Michael Hanselmann | class LvmVgStorage(_LvmBase): |
405 | ac2d0fe4 | Michael Hanselmann | """LVM Volume Group storage unit.
|
406 | ac2d0fe4 | Michael Hanselmann |
|
407 | ac2d0fe4 | Michael Hanselmann | """
|
408 | ac2d0fe4 | Michael Hanselmann | LIST_COMMAND = "vgs"
|
409 | 048eeb2b | Iustin Pop | VGREDUCE_COMMAND = "vgreduce"
|
410 | 6032697c | Michael Hanselmann | |
411 | 6032697c | Michael Hanselmann | # Make sure to update constants.VALID_STORAGE_FIELDS when changing field
|
412 | 6032697c | Michael Hanselmann | # definitions.
|
413 | ac2d0fe4 | Michael Hanselmann | LIST_FIELDS = [ |
414 | 620a85fd | Iustin Pop | (constants.SF_NAME, ["vg_name"], None), |
415 | 620a85fd | Iustin Pop | (constants.SF_SIZE, ["vg_size"], _ParseSize),
|
416 | 620a85fd | Iustin Pop | (constants.SF_FREE, ["vg_free"], _ParseSize),
|
417 | 620a85fd | Iustin Pop | (constants.SF_USED, ["vg_size", "vg_free"], |
418 | 620a85fd | Iustin Pop | lambda x, y: _ParseSize(x) - _ParseSize(y)),
|
419 | 620a85fd | Iustin Pop | (constants.SF_ALLOCATABLE, [], True),
|
420 | ac2d0fe4 | Michael Hanselmann | ] |
421 | ac2d0fe4 | Michael Hanselmann | |
422 | 048eeb2b | Iustin Pop | def _RemoveMissing(self, name, _runcmd_fn=utils.RunCmd): |
423 | 6c3c6db9 | Michael Hanselmann | """Runs "vgreduce --removemissing" on a volume group.
|
424 | 6c3c6db9 | Michael Hanselmann |
|
425 | 6c3c6db9 | Michael Hanselmann | @type name: string
|
426 | 6c3c6db9 | Michael Hanselmann | @param name: Volume group name
|
427 | 6c3c6db9 | Michael Hanselmann |
|
428 | 6c3c6db9 | Michael Hanselmann | """
|
429 | 6c3c6db9 | Michael Hanselmann | # Ignoring vgreduce exit code. Older versions exit with an error even tough
|
430 | 6c3c6db9 | Michael Hanselmann | # the VG is already consistent. This was fixed in later versions, but we
|
431 | 6c3c6db9 | Michael Hanselmann | # cannot depend on it.
|
432 | 048eeb2b | Iustin Pop | result = _runcmd_fn([self.VGREDUCE_COMMAND, "--removemissing", name]) |
433 | 6c3c6db9 | Michael Hanselmann | |
434 | 6c3c6db9 | Michael Hanselmann | # Keep output in case something went wrong
|
435 | 6c3c6db9 | Michael Hanselmann | vgreduce_output = result.output |
436 | 6c3c6db9 | Michael Hanselmann | |
437 | 048eeb2b | Iustin Pop | # work around newer LVM version
|
438 | 048eeb2b | Iustin Pop | if ("Wrote out consistent volume group" not in vgreduce_output or |
439 | 048eeb2b | Iustin Pop | "vgreduce --removemissing --force" in vgreduce_output): |
440 | 048eeb2b | Iustin Pop | # we need to re-run with --force
|
441 | 048eeb2b | Iustin Pop | result = _runcmd_fn([self.VGREDUCE_COMMAND, "--removemissing", |
442 | 048eeb2b | Iustin Pop | "--force", name])
|
443 | 048eeb2b | Iustin Pop | vgreduce_output += "\n" + result.output
|
444 | 048eeb2b | Iustin Pop | |
445 | 048eeb2b | Iustin Pop | result = _runcmd_fn([self.LIST_COMMAND, "--noheadings", |
446 | 048eeb2b | Iustin Pop | "--nosuffix", name])
|
447 | 048eeb2b | Iustin Pop | # we also need to check the output
|
448 | 048eeb2b | Iustin Pop | if result.failed or "Couldn't find device with uuid" in result.output: |
449 | 6c3c6db9 | Michael Hanselmann | raise errors.StorageError(("Volume group '%s' still not consistent," |
450 | 6c3c6db9 | Michael Hanselmann | " 'vgreduce' output: %r,"
|
451 | 6c3c6db9 | Michael Hanselmann | " 'vgs' output: %r") %
|
452 | 6c3c6db9 | Michael Hanselmann | (name, vgreduce_output, result.output)) |
453 | 6c3c6db9 | Michael Hanselmann | |
454 | 6c3c6db9 | Michael Hanselmann | def Execute(self, name, op): |
455 | 6c3c6db9 | Michael Hanselmann | """Executes an operation on a virtual volume.
|
456 | 6c3c6db9 | Michael Hanselmann |
|
457 | 6c3c6db9 | Michael Hanselmann | See L{_Base.Execute}.
|
458 | 6c3c6db9 | Michael Hanselmann |
|
459 | 6c3c6db9 | Michael Hanselmann | """
|
460 | 6c3c6db9 | Michael Hanselmann | if op == constants.SO_FIX_CONSISTENCY:
|
461 | 6c3c6db9 | Michael Hanselmann | return self._RemoveMissing(name) |
462 | 6c3c6db9 | Michael Hanselmann | |
463 | 6c3c6db9 | Michael Hanselmann | return _LvmBase.Execute(self, name, op) |
464 | 6c3c6db9 | Michael Hanselmann | |
465 | ac2d0fe4 | Michael Hanselmann | |
466 | ac2d0fe4 | Michael Hanselmann | # Lookup table for storage types
|
467 | ac2d0fe4 | Michael Hanselmann | _STORAGE_TYPES = { |
468 | ac2d0fe4 | Michael Hanselmann | constants.ST_FILE: FileStorage, |
469 | ac2d0fe4 | Michael Hanselmann | constants.ST_LVM_PV: LvmPvStorage, |
470 | ac2d0fe4 | Michael Hanselmann | constants.ST_LVM_VG: LvmVgStorage, |
471 | ac2d0fe4 | Michael Hanselmann | } |
472 | ac2d0fe4 | Michael Hanselmann | |
473 | ac2d0fe4 | Michael Hanselmann | |
474 | ac2d0fe4 | Michael Hanselmann | def GetStorageClass(name): |
475 | ac2d0fe4 | Michael Hanselmann | """Returns the class for a storage type.
|
476 | ac2d0fe4 | Michael Hanselmann |
|
477 | ac2d0fe4 | Michael Hanselmann | @type name: string
|
478 | ac2d0fe4 | Michael Hanselmann | @param name: Storage type
|
479 | ac2d0fe4 | Michael Hanselmann |
|
480 | ac2d0fe4 | Michael Hanselmann | """
|
481 | ac2d0fe4 | Michael Hanselmann | try:
|
482 | ac2d0fe4 | Michael Hanselmann | return _STORAGE_TYPES[name]
|
483 | ac2d0fe4 | Michael Hanselmann | except KeyError: |
484 | ac2d0fe4 | Michael Hanselmann | raise errors.StorageError("Unknown storage type: %r" % name) |
485 | ac2d0fe4 | Michael Hanselmann | |
486 | ac2d0fe4 | Michael Hanselmann | |
487 | ac2d0fe4 | Michael Hanselmann | def GetStorage(name, *args): |
488 | ac2d0fe4 | Michael Hanselmann | """Factory function for storage methods.
|
489 | ac2d0fe4 | Michael Hanselmann |
|
490 | ac2d0fe4 | Michael Hanselmann | @type name: string
|
491 | ac2d0fe4 | Michael Hanselmann | @param name: Storage type
|
492 | ac2d0fe4 | Michael Hanselmann |
|
493 | ac2d0fe4 | Michael Hanselmann | """
|
494 | ac2d0fe4 | Michael Hanselmann | return GetStorageClass(name)(*args) |