Statistics
| Branch: | Tag: | Revision:

root / lib / storage.py @ 8062638d

History | View | Annotate | Download (12.5 kB)

1 ac2d0fe4 Michael Hanselmann
#
2 ac2d0fe4 Michael Hanselmann
#
3 ac2d0fe4 Michael Hanselmann
4 ac2d0fe4 Michael Hanselmann
# Copyright (C) 2009 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 7260cfbe Iustin Pop
# pylint: disable-msg=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 7260cfbe Iustin Pop
  def Modify(self, name, changes): # pylint: disable-msg=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 7260cfbe Iustin Pop
class FileStorage(_Base): # pylint: disable-msg=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 7260cfbe Iustin Pop
class _LvmBase(_Base): # pylint: disable-msg=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 7260cfbe Iustin Pop
          val = mapper(*values) # pylint: disable-msg=W0142
260 620a85fd Iustin Pop
        elif len(values) == 1:
261 620a85fd Iustin Pop
          # we don't have a function, but we had a single field
262 620a85fd Iustin Pop
          # declared, pass it unchanged
263 620a85fd Iustin Pop
          val = values[0]
264 620a85fd Iustin Pop
        else:
265 620a85fd Iustin Pop
          # let's make sure there are no fields declared (cannot map >
266 620a85fd Iustin Pop
          # 1 field without a function)
267 620a85fd Iustin Pop
          assert not values, "LVM storage has multi-fields without a function"
268 620a85fd Iustin Pop
          val = mapper
269 ac2d0fe4 Michael Hanselmann
270 620a85fd Iustin Pop
        row.append(val)
271 ac2d0fe4 Michael Hanselmann
272 ac2d0fe4 Michael Hanselmann
      data.append(row)
273 ac2d0fe4 Michael Hanselmann
274 ac2d0fe4 Michael Hanselmann
    return data
275 ac2d0fe4 Michael Hanselmann
276 ac2d0fe4 Michael Hanselmann
  @staticmethod
277 ac2d0fe4 Michael Hanselmann
  def _BuildListCommand(cmd, sep, options, name):
278 ac2d0fe4 Michael Hanselmann
    """Builds LVM command line.
279 ac2d0fe4 Michael Hanselmann

280 ac2d0fe4 Michael Hanselmann
    @type cmd: string
281 ac2d0fe4 Michael Hanselmann
    @param cmd: Command name
282 ac2d0fe4 Michael Hanselmann
    @type sep: string
283 ac2d0fe4 Michael Hanselmann
    @param sep: Field separator character
284 ac2d0fe4 Michael Hanselmann
    @type options: list of strings
285 ac2d0fe4 Michael Hanselmann
    @param options: Wanted LVM fields
286 ac2d0fe4 Michael Hanselmann
    @type name: name or None
287 ac2d0fe4 Michael Hanselmann
    @param name: Name of requested entity
288 ac2d0fe4 Michael Hanselmann

289 ac2d0fe4 Michael Hanselmann
    """
290 ac2d0fe4 Michael Hanselmann
    args = [cmd,
291 ac2d0fe4 Michael Hanselmann
            "--noheadings", "--units=m", "--nosuffix",
292 ac2d0fe4 Michael Hanselmann
            "--separator", sep,
293 ac2d0fe4 Michael Hanselmann
            "--options", ",".join(options)]
294 ac2d0fe4 Michael Hanselmann
295 ac2d0fe4 Michael Hanselmann
    if name is not None:
296 ac2d0fe4 Michael Hanselmann
      args.append(name)
297 ac2d0fe4 Michael Hanselmann
298 ac2d0fe4 Michael Hanselmann
    return args
299 ac2d0fe4 Michael Hanselmann
300 ac2d0fe4 Michael Hanselmann
  @staticmethod
301 ac2d0fe4 Michael Hanselmann
  def _RunListCommand(args):
302 ac2d0fe4 Michael Hanselmann
    """Run LVM command.
303 ac2d0fe4 Michael Hanselmann

304 ac2d0fe4 Michael Hanselmann
    """
305 ac2d0fe4 Michael Hanselmann
    result = utils.RunCmd(args)
306 ac2d0fe4 Michael Hanselmann
307 ac2d0fe4 Michael Hanselmann
    if result.failed:
308 ac2d0fe4 Michael Hanselmann
      raise errors.StorageError("Failed to run %r, command output: %s" %
309 ac2d0fe4 Michael Hanselmann
                                (args[0], result.output))
310 ac2d0fe4 Michael Hanselmann
311 ac2d0fe4 Michael Hanselmann
    return result.stdout
312 ac2d0fe4 Michael Hanselmann
313 ac2d0fe4 Michael Hanselmann
  @staticmethod
314 ac2d0fe4 Michael Hanselmann
  def _SplitList(data, sep, fieldcount):
315 ac2d0fe4 Michael Hanselmann
    """Splits LVM command output into rows and fields.
316 ac2d0fe4 Michael Hanselmann

317 ac2d0fe4 Michael Hanselmann
    @type data: string
318 ac2d0fe4 Michael Hanselmann
    @param data: LVM command output
319 ac2d0fe4 Michael Hanselmann
    @type sep: string
320 ac2d0fe4 Michael Hanselmann
    @param sep: Field separator character
321 ac2d0fe4 Michael Hanselmann
    @type fieldcount: int
322 ac2d0fe4 Michael Hanselmann
    @param fieldcount: Expected number of fields
323 ac2d0fe4 Michael Hanselmann

324 ac2d0fe4 Michael Hanselmann
    """
325 ac2d0fe4 Michael Hanselmann
    for line in data.splitlines():
326 ac2d0fe4 Michael Hanselmann
      fields = line.strip().split(sep)
327 ac2d0fe4 Michael Hanselmann
328 ac2d0fe4 Michael Hanselmann
      if len(fields) != fieldcount:
329 620a85fd Iustin Pop
        logging.warning("Invalid line returned from lvm command: %s", line)
330 ac2d0fe4 Michael Hanselmann
        continue
331 ac2d0fe4 Michael Hanselmann
332 ac2d0fe4 Michael Hanselmann
      yield fields
333 ac2d0fe4 Michael Hanselmann
334 ac2d0fe4 Michael Hanselmann
335 7260cfbe Iustin Pop
class LvmPvStorage(_LvmBase): # pylint: disable-msg=W0223
336 ac2d0fe4 Michael Hanselmann
  """LVM Physical Volume storage unit.
337 ac2d0fe4 Michael Hanselmann

338 ac2d0fe4 Michael Hanselmann
  """
339 6c881c52 Iustin Pop
  @staticmethod
340 ac2d0fe4 Michael Hanselmann
  def _GetAllocatable(attr):
341 ac2d0fe4 Michael Hanselmann
    if attr:
342 ac2d0fe4 Michael Hanselmann
      return (attr[0] == "a")
343 ac2d0fe4 Michael Hanselmann
    else:
344 ac2d0fe4 Michael Hanselmann
      logging.warning("Invalid PV attribute: %r", attr)
345 ac2d0fe4 Michael Hanselmann
      return False
346 ac2d0fe4 Michael Hanselmann
347 ac2d0fe4 Michael Hanselmann
  LIST_COMMAND = "pvs"
348 6032697c Michael Hanselmann
349 6032697c Michael Hanselmann
  # Make sure to update constants.VALID_STORAGE_FIELDS when changing field
350 6032697c Michael Hanselmann
  # definitions.
351 ac2d0fe4 Michael Hanselmann
  LIST_FIELDS = [
352 620a85fd Iustin Pop
    (constants.SF_NAME, ["pv_name"], None),
353 620a85fd Iustin Pop
    (constants.SF_SIZE, ["pv_size"], _ParseSize),
354 620a85fd Iustin Pop
    (constants.SF_USED, ["pv_used"], _ParseSize),
355 620a85fd Iustin Pop
    (constants.SF_FREE, ["pv_free"], _ParseSize),
356 620a85fd Iustin Pop
    (constants.SF_ALLOCATABLE, ["pv_attr"], _GetAllocatable),
357 ac2d0fe4 Michael Hanselmann
    ]
358 ac2d0fe4 Michael Hanselmann
359 9b648ee7 Michael Hanselmann
  def _SetAllocatable(self, name, allocatable):
360 9b648ee7 Michael Hanselmann
    """Sets the "allocatable" flag on a physical volume.
361 9b648ee7 Michael Hanselmann

362 9b648ee7 Michael Hanselmann
    @type name: string
363 9b648ee7 Michael Hanselmann
    @param name: Physical volume name
364 9b648ee7 Michael Hanselmann
    @type allocatable: bool
365 9b648ee7 Michael Hanselmann
    @param allocatable: Whether to set the "allocatable" flag
366 9b648ee7 Michael Hanselmann

367 9b648ee7 Michael Hanselmann
    """
368 9b648ee7 Michael Hanselmann
    args = ["pvchange", "--allocatable"]
369 9b648ee7 Michael Hanselmann
370 9b648ee7 Michael Hanselmann
    if allocatable:
371 9b648ee7 Michael Hanselmann
      args.append("y")
372 9b648ee7 Michael Hanselmann
    else:
373 9b648ee7 Michael Hanselmann
      args.append("n")
374 9b648ee7 Michael Hanselmann
375 9b648ee7 Michael Hanselmann
    args.append(name)
376 9b648ee7 Michael Hanselmann
377 9b648ee7 Michael Hanselmann
    result = utils.RunCmd(args)
378 9b648ee7 Michael Hanselmann
    if result.failed:
379 9b648ee7 Michael Hanselmann
      raise errors.StorageError("Failed to modify physical volume,"
380 9b648ee7 Michael Hanselmann
                                " pvchange output: %s" %
381 9b648ee7 Michael Hanselmann
                                result.output)
382 9b648ee7 Michael Hanselmann
383 9b648ee7 Michael Hanselmann
  def Modify(self, name, changes):
384 9b648ee7 Michael Hanselmann
    """Modifies flags on a physical volume.
385 9b648ee7 Michael Hanselmann

386 9b648ee7 Michael Hanselmann
    See L{_Base.Modify}.
387 9b648ee7 Michael Hanselmann

388 9b648ee7 Michael Hanselmann
    """
389 9b648ee7 Michael Hanselmann
    if constants.SF_ALLOCATABLE in changes:
390 9b648ee7 Michael Hanselmann
      self._SetAllocatable(name, changes[constants.SF_ALLOCATABLE])
391 9b648ee7 Michael Hanselmann
      del changes[constants.SF_ALLOCATABLE]
392 9b648ee7 Michael Hanselmann
393 9b648ee7 Michael Hanselmann
    # Other changes will be handled (and maybe refused) by the base class.
394 9b648ee7 Michael Hanselmann
    return _LvmBase.Modify(self, name, changes)
395 9b648ee7 Michael Hanselmann
396 ac2d0fe4 Michael Hanselmann
397 ac2d0fe4 Michael Hanselmann
class LvmVgStorage(_LvmBase):
398 ac2d0fe4 Michael Hanselmann
  """LVM Volume Group storage unit.
399 ac2d0fe4 Michael Hanselmann

400 ac2d0fe4 Michael Hanselmann
  """
401 ac2d0fe4 Michael Hanselmann
  LIST_COMMAND = "vgs"
402 6032697c Michael Hanselmann
403 6032697c Michael Hanselmann
  # Make sure to update constants.VALID_STORAGE_FIELDS when changing field
404 6032697c Michael Hanselmann
  # definitions.
405 ac2d0fe4 Michael Hanselmann
  LIST_FIELDS = [
406 620a85fd Iustin Pop
    (constants.SF_NAME, ["vg_name"], None),
407 620a85fd Iustin Pop
    (constants.SF_SIZE, ["vg_size"], _ParseSize),
408 620a85fd Iustin Pop
    (constants.SF_FREE, ["vg_free"], _ParseSize),
409 620a85fd Iustin Pop
    (constants.SF_USED, ["vg_size", "vg_free"],
410 620a85fd Iustin Pop
     lambda x, y: _ParseSize(x) - _ParseSize(y)),
411 620a85fd Iustin Pop
    (constants.SF_ALLOCATABLE, [], True),
412 ac2d0fe4 Michael Hanselmann
    ]
413 ac2d0fe4 Michael Hanselmann
414 6c3c6db9 Michael Hanselmann
  def _RemoveMissing(self, name):
415 6c3c6db9 Michael Hanselmann
    """Runs "vgreduce --removemissing" on a volume group.
416 6c3c6db9 Michael Hanselmann

417 6c3c6db9 Michael Hanselmann
    @type name: string
418 6c3c6db9 Michael Hanselmann
    @param name: Volume group name
419 6c3c6db9 Michael Hanselmann

420 6c3c6db9 Michael Hanselmann
    """
421 6c3c6db9 Michael Hanselmann
    # Ignoring vgreduce exit code. Older versions exit with an error even tough
422 6c3c6db9 Michael Hanselmann
    # the VG is already consistent. This was fixed in later versions, but we
423 6c3c6db9 Michael Hanselmann
    # cannot depend on it.
424 6c3c6db9 Michael Hanselmann
    result = utils.RunCmd(["vgreduce", "--removemissing", name])
425 6c3c6db9 Michael Hanselmann
426 6c3c6db9 Michael Hanselmann
    # Keep output in case something went wrong
427 6c3c6db9 Michael Hanselmann
    vgreduce_output = result.output
428 6c3c6db9 Michael Hanselmann
429 6c3c6db9 Michael Hanselmann
    result = utils.RunCmd(["vgs", "--noheadings", "--nosuffix", name])
430 6c3c6db9 Michael Hanselmann
    if result.failed:
431 6c3c6db9 Michael Hanselmann
      raise errors.StorageError(("Volume group '%s' still not consistent,"
432 6c3c6db9 Michael Hanselmann
                                 " 'vgreduce' output: %r,"
433 6c3c6db9 Michael Hanselmann
                                 " 'vgs' output: %r") %
434 6c3c6db9 Michael Hanselmann
                                (name, vgreduce_output, result.output))
435 6c3c6db9 Michael Hanselmann
436 6c3c6db9 Michael Hanselmann
  def Execute(self, name, op):
437 6c3c6db9 Michael Hanselmann
    """Executes an operation on a virtual volume.
438 6c3c6db9 Michael Hanselmann

439 6c3c6db9 Michael Hanselmann
    See L{_Base.Execute}.
440 6c3c6db9 Michael Hanselmann

441 6c3c6db9 Michael Hanselmann
    """
442 6c3c6db9 Michael Hanselmann
    if op == constants.SO_FIX_CONSISTENCY:
443 6c3c6db9 Michael Hanselmann
      return self._RemoveMissing(name)
444 6c3c6db9 Michael Hanselmann
445 6c3c6db9 Michael Hanselmann
    return _LvmBase.Execute(self, name, op)
446 6c3c6db9 Michael Hanselmann
447 ac2d0fe4 Michael Hanselmann
448 ac2d0fe4 Michael Hanselmann
# Lookup table for storage types
449 ac2d0fe4 Michael Hanselmann
_STORAGE_TYPES = {
450 ac2d0fe4 Michael Hanselmann
  constants.ST_FILE: FileStorage,
451 ac2d0fe4 Michael Hanselmann
  constants.ST_LVM_PV: LvmPvStorage,
452 ac2d0fe4 Michael Hanselmann
  constants.ST_LVM_VG: LvmVgStorage,
453 ac2d0fe4 Michael Hanselmann
  }
454 ac2d0fe4 Michael Hanselmann
455 ac2d0fe4 Michael Hanselmann
456 ac2d0fe4 Michael Hanselmann
def GetStorageClass(name):
457 ac2d0fe4 Michael Hanselmann
  """Returns the class for a storage type.
458 ac2d0fe4 Michael Hanselmann

459 ac2d0fe4 Michael Hanselmann
  @type name: string
460 ac2d0fe4 Michael Hanselmann
  @param name: Storage type
461 ac2d0fe4 Michael Hanselmann

462 ac2d0fe4 Michael Hanselmann
  """
463 ac2d0fe4 Michael Hanselmann
  try:
464 ac2d0fe4 Michael Hanselmann
    return _STORAGE_TYPES[name]
465 ac2d0fe4 Michael Hanselmann
  except KeyError:
466 ac2d0fe4 Michael Hanselmann
    raise errors.StorageError("Unknown storage type: %r" % name)
467 ac2d0fe4 Michael Hanselmann
468 ac2d0fe4 Michael Hanselmann
469 ac2d0fe4 Michael Hanselmann
def GetStorage(name, *args):
470 ac2d0fe4 Michael Hanselmann
  """Factory function for storage methods.
471 ac2d0fe4 Michael Hanselmann

472 ac2d0fe4 Michael Hanselmann
  @type name: string
473 ac2d0fe4 Michael Hanselmann
  @param name: Storage type
474 ac2d0fe4 Michael Hanselmann

475 ac2d0fe4 Michael Hanselmann
  """
476 ac2d0fe4 Michael Hanselmann
  return GetStorageClass(name)(*args)