Statistics
| Branch: | Tag: | Revision:

root / lib / storage.py @ 364c350f

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)