Statistics
| Branch: | Tag: | Revision:

root / lib / storage / base.py @ 355d1f32

History | View | Annotate | Download (12.4 kB)

1 89ff748d Thomas Thrainer
#
2 89ff748d Thomas Thrainer
#
3 89ff748d Thomas Thrainer
4 89ff748d Thomas Thrainer
# Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Google Inc.
5 89ff748d Thomas Thrainer
#
6 89ff748d Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 89ff748d Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 89ff748d Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 89ff748d Thomas Thrainer
# (at your option) any later version.
10 89ff748d Thomas Thrainer
#
11 89ff748d Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 89ff748d Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 89ff748d Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 89ff748d Thomas Thrainer
# General Public License for more details.
15 89ff748d Thomas Thrainer
#
16 89ff748d Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 89ff748d Thomas Thrainer
# along with this program; if not, write to the Free Software
18 89ff748d Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 89ff748d Thomas Thrainer
# 02110-1301, USA.
20 89ff748d Thomas Thrainer
21 89ff748d Thomas Thrainer
22 89ff748d Thomas Thrainer
"""Block device abstraction - base class and utility functions"""
23 89ff748d Thomas Thrainer
24 89ff748d Thomas Thrainer
import logging
25 89ff748d Thomas Thrainer
26 89ff748d Thomas Thrainer
from ganeti import objects
27 89ff748d Thomas Thrainer
from ganeti import constants
28 89ff748d Thomas Thrainer
from ganeti import utils
29 89ff748d Thomas Thrainer
from ganeti import errors
30 89ff748d Thomas Thrainer
31 89ff748d Thomas Thrainer
32 89ff748d Thomas Thrainer
class BlockDev(object):
33 89ff748d Thomas Thrainer
  """Block device abstract class.
34 89ff748d Thomas Thrainer

35 89ff748d Thomas Thrainer
  A block device can be in the following states:
36 89ff748d Thomas Thrainer
    - not existing on the system, and by `Create()` it goes into:
37 89ff748d Thomas Thrainer
    - existing but not setup/not active, and by `Assemble()` goes into:
38 89ff748d Thomas Thrainer
    - active read-write and by `Open()` it goes into
39 89ff748d Thomas Thrainer
    - online (=used, or ready for use)
40 89ff748d Thomas Thrainer

41 89ff748d Thomas Thrainer
  A device can also be online but read-only, however we are not using
42 89ff748d Thomas Thrainer
  the readonly state (LV has it, if needed in the future) and we are
43 89ff748d Thomas Thrainer
  usually looking at this like at a stack, so it's easier to
44 89ff748d Thomas Thrainer
  conceptualise the transition from not-existing to online and back
45 89ff748d Thomas Thrainer
  like a linear one.
46 89ff748d Thomas Thrainer

47 89ff748d Thomas Thrainer
  The many different states of the device are due to the fact that we
48 89ff748d Thomas Thrainer
  need to cover many device types:
49 89ff748d Thomas Thrainer
    - logical volumes are created, lvchange -a y $lv, and used
50 89ff748d Thomas Thrainer
    - drbd devices are attached to a local disk/remote peer and made primary
51 89ff748d Thomas Thrainer

52 89ff748d Thomas Thrainer
  A block device is identified by three items:
53 89ff748d Thomas Thrainer
    - the /dev path of the device (dynamic)
54 89ff748d Thomas Thrainer
    - a unique ID of the device (static)
55 89ff748d Thomas Thrainer
    - it's major/minor pair (dynamic)
56 89ff748d Thomas Thrainer

57 89ff748d Thomas Thrainer
  Not all devices implement both the first two as distinct items. LVM
58 89ff748d Thomas Thrainer
  logical volumes have their unique ID (the pair volume group, logical
59 89ff748d Thomas Thrainer
  volume name) in a 1-to-1 relation to the dev path. For DRBD devices,
60 89ff748d Thomas Thrainer
  the /dev path is again dynamic and the unique id is the pair (host1,
61 89ff748d Thomas Thrainer
  dev1), (host2, dev2).
62 89ff748d Thomas Thrainer

63 89ff748d Thomas Thrainer
  You can get to a device in two ways:
64 89ff748d Thomas Thrainer
    - creating the (real) device, which returns you
65 89ff748d Thomas Thrainer
      an attached instance (lvcreate)
66 89ff748d Thomas Thrainer
    - attaching of a python instance to an existing (real) device
67 89ff748d Thomas Thrainer

68 89ff748d Thomas Thrainer
  The second point, the attachment to a device, is different
69 89ff748d Thomas Thrainer
  depending on whether the device is assembled or not. At init() time,
70 89ff748d Thomas Thrainer
  we search for a device with the same unique_id as us. If found,
71 89ff748d Thomas Thrainer
  good. It also means that the device is already assembled. If not,
72 89ff748d Thomas Thrainer
  after assembly we'll have our correct major/minor.
73 89ff748d Thomas Thrainer

74 89ff748d Thomas Thrainer
  """
75 89ff748d Thomas Thrainer
  def __init__(self, unique_id, children, size, params):
76 89ff748d Thomas Thrainer
    self._children = children
77 89ff748d Thomas Thrainer
    self.dev_path = None
78 89ff748d Thomas Thrainer
    self.unique_id = unique_id
79 89ff748d Thomas Thrainer
    self.major = None
80 89ff748d Thomas Thrainer
    self.minor = None
81 89ff748d Thomas Thrainer
    self.attached = False
82 89ff748d Thomas Thrainer
    self.size = size
83 89ff748d Thomas Thrainer
    self.params = params
84 89ff748d Thomas Thrainer
85 89ff748d Thomas Thrainer
  def Assemble(self):
86 89ff748d Thomas Thrainer
    """Assemble the device from its components.
87 89ff748d Thomas Thrainer

88 89ff748d Thomas Thrainer
    Implementations of this method by child classes must ensure that:
89 89ff748d Thomas Thrainer
      - after the device has been assembled, it knows its major/minor
90 89ff748d Thomas Thrainer
        numbers; this allows other devices (usually parents) to probe
91 89ff748d Thomas Thrainer
        correctly for their children
92 89ff748d Thomas Thrainer
      - calling this method on an existing, in-use device is safe
93 89ff748d Thomas Thrainer
      - if the device is already configured (and in an OK state),
94 89ff748d Thomas Thrainer
        this method is idempotent
95 89ff748d Thomas Thrainer

96 89ff748d Thomas Thrainer
    """
97 89ff748d Thomas Thrainer
    pass
98 89ff748d Thomas Thrainer
99 89ff748d Thomas Thrainer
  def Attach(self):
100 89ff748d Thomas Thrainer
    """Find a device which matches our config and attach to it.
101 89ff748d Thomas Thrainer

102 89ff748d Thomas Thrainer
    """
103 89ff748d Thomas Thrainer
    raise NotImplementedError
104 89ff748d Thomas Thrainer
105 89ff748d Thomas Thrainer
  def Close(self):
106 89ff748d Thomas Thrainer
    """Notifies that the device will no longer be used for I/O.
107 89ff748d Thomas Thrainer

108 89ff748d Thomas Thrainer
    """
109 89ff748d Thomas Thrainer
    raise NotImplementedError
110 89ff748d Thomas Thrainer
111 89ff748d Thomas Thrainer
  @classmethod
112 24c06acb Bernardo Dal Seno
  def Create(cls, unique_id, children, size, spindles, params, excl_stor):
113 89ff748d Thomas Thrainer
    """Create the device.
114 89ff748d Thomas Thrainer

115 89ff748d Thomas Thrainer
    If the device cannot be created, it will return None
116 89ff748d Thomas Thrainer
    instead. Error messages go to the logging system.
117 89ff748d Thomas Thrainer

118 89ff748d Thomas Thrainer
    Note that for some devices, the unique_id is used, and for other,
119 89ff748d Thomas Thrainer
    the children. The idea is that these two, taken together, are
120 89ff748d Thomas Thrainer
    enough for both creation and assembly (later).
121 89ff748d Thomas Thrainer

122 5073fa0c Bernardo Dal Seno
    @type unique_id: 2-element tuple or list
123 5073fa0c Bernardo Dal Seno
    @param unique_id: unique identifier; the details depend on the actual device
124 5073fa0c Bernardo Dal Seno
        type
125 5073fa0c Bernardo Dal Seno
    @type children: list of L{BlockDev}
126 5073fa0c Bernardo Dal Seno
    @param children: for hierarchical devices, the child devices
127 5073fa0c Bernardo Dal Seno
    @type size: float
128 5073fa0c Bernardo Dal Seno
    @param size: size in MiB
129 24c06acb Bernardo Dal Seno
    @type spindles: int
130 24c06acb Bernardo Dal Seno
    @param spindles: number of physical disk to dedicate to the device
131 5073fa0c Bernardo Dal Seno
    @type params: dict
132 5073fa0c Bernardo Dal Seno
    @param params: device-specific options/parameters
133 5073fa0c Bernardo Dal Seno
    @type excl_stor: bool
134 5073fa0c Bernardo Dal Seno
    @param excl_stor: whether exclusive_storage is active
135 5073fa0c Bernardo Dal Seno
    @rtype: L{BlockDev}
136 5073fa0c Bernardo Dal Seno
    @return: the created device, or C{None} in case of an error
137 5073fa0c Bernardo Dal Seno

138 89ff748d Thomas Thrainer
    """
139 89ff748d Thomas Thrainer
    raise NotImplementedError
140 89ff748d Thomas Thrainer
141 89ff748d Thomas Thrainer
  def Remove(self):
142 89ff748d Thomas Thrainer
    """Remove this device.
143 89ff748d Thomas Thrainer

144 89ff748d Thomas Thrainer
    This makes sense only for some of the device types: LV and file
145 89ff748d Thomas Thrainer
    storage. Also note that if the device can't attach, the removal
146 89ff748d Thomas Thrainer
    can't be completed.
147 89ff748d Thomas Thrainer

148 89ff748d Thomas Thrainer
    """
149 89ff748d Thomas Thrainer
    raise NotImplementedError
150 89ff748d Thomas Thrainer
151 89ff748d Thomas Thrainer
  def Rename(self, new_id):
152 89ff748d Thomas Thrainer
    """Rename this device.
153 89ff748d Thomas Thrainer

154 89ff748d Thomas Thrainer
    This may or may not make sense for a given device type.
155 89ff748d Thomas Thrainer

156 89ff748d Thomas Thrainer
    """
157 89ff748d Thomas Thrainer
    raise NotImplementedError
158 89ff748d Thomas Thrainer
159 89ff748d Thomas Thrainer
  def Open(self, force=False):
160 89ff748d Thomas Thrainer
    """Make the device ready for use.
161 89ff748d Thomas Thrainer

162 89ff748d Thomas Thrainer
    This makes the device ready for I/O. For now, just the DRBD
163 89ff748d Thomas Thrainer
    devices need this.
164 89ff748d Thomas Thrainer

165 89ff748d Thomas Thrainer
    The force parameter signifies that if the device has any kind of
166 89ff748d Thomas Thrainer
    --force thing, it should be used, we know what we are doing.
167 89ff748d Thomas Thrainer

168 47e0abee Thomas Thrainer
    @type force: boolean
169 47e0abee Thomas Thrainer

170 89ff748d Thomas Thrainer
    """
171 89ff748d Thomas Thrainer
    raise NotImplementedError
172 89ff748d Thomas Thrainer
173 89ff748d Thomas Thrainer
  def Shutdown(self):
174 89ff748d Thomas Thrainer
    """Shut down the device, freeing its children.
175 89ff748d Thomas Thrainer

176 89ff748d Thomas Thrainer
    This undoes the `Assemble()` work, except for the child
177 89ff748d Thomas Thrainer
    assembling; as such, the children on the device are still
178 89ff748d Thomas Thrainer
    assembled after this call.
179 89ff748d Thomas Thrainer

180 89ff748d Thomas Thrainer
    """
181 89ff748d Thomas Thrainer
    raise NotImplementedError
182 89ff748d Thomas Thrainer
183 89ff748d Thomas Thrainer
  def SetSyncParams(self, params):
184 89ff748d Thomas Thrainer
    """Adjust the synchronization parameters of the mirror.
185 89ff748d Thomas Thrainer

186 89ff748d Thomas Thrainer
    In case this is not a mirroring device, this is no-op.
187 89ff748d Thomas Thrainer

188 89ff748d Thomas Thrainer
    @param params: dictionary of LD level disk parameters related to the
189 89ff748d Thomas Thrainer
    synchronization.
190 89ff748d Thomas Thrainer
    @rtype: list
191 89ff748d Thomas Thrainer
    @return: a list of error messages, emitted both by the current node and by
192 89ff748d Thomas Thrainer
    children. An empty list means no errors.
193 89ff748d Thomas Thrainer

194 89ff748d Thomas Thrainer
    """
195 89ff748d Thomas Thrainer
    result = []
196 89ff748d Thomas Thrainer
    if self._children:
197 89ff748d Thomas Thrainer
      for child in self._children:
198 89ff748d Thomas Thrainer
        result.extend(child.SetSyncParams(params))
199 89ff748d Thomas Thrainer
    return result
200 89ff748d Thomas Thrainer
201 89ff748d Thomas Thrainer
  def PauseResumeSync(self, pause):
202 89ff748d Thomas Thrainer
    """Pause/Resume the sync of the mirror.
203 89ff748d Thomas Thrainer

204 89ff748d Thomas Thrainer
    In case this is not a mirroring device, this is no-op.
205 89ff748d Thomas Thrainer

206 47e0abee Thomas Thrainer
    @type pause: boolean
207 89ff748d Thomas Thrainer
    @param pause: Whether to pause or resume
208 89ff748d Thomas Thrainer

209 89ff748d Thomas Thrainer
    """
210 89ff748d Thomas Thrainer
    result = True
211 89ff748d Thomas Thrainer
    if self._children:
212 89ff748d Thomas Thrainer
      for child in self._children:
213 89ff748d Thomas Thrainer
        result = result and child.PauseResumeSync(pause)
214 89ff748d Thomas Thrainer
    return result
215 89ff748d Thomas Thrainer
216 89ff748d Thomas Thrainer
  def GetSyncStatus(self):
217 89ff748d Thomas Thrainer
    """Returns the sync status of the device.
218 89ff748d Thomas Thrainer

219 89ff748d Thomas Thrainer
    If this device is a mirroring device, this function returns the
220 89ff748d Thomas Thrainer
    status of the mirror.
221 89ff748d Thomas Thrainer

222 89ff748d Thomas Thrainer
    If sync_percent is None, it means the device is not syncing.
223 89ff748d Thomas Thrainer

224 89ff748d Thomas Thrainer
    If estimated_time is None, it means we can't estimate
225 89ff748d Thomas Thrainer
    the time needed, otherwise it's the time left in seconds.
226 89ff748d Thomas Thrainer

227 89ff748d Thomas Thrainer
    If is_degraded is True, it means the device is missing
228 89ff748d Thomas Thrainer
    redundancy. This is usually a sign that something went wrong in
229 89ff748d Thomas Thrainer
    the device setup, if sync_percent is None.
230 89ff748d Thomas Thrainer

231 89ff748d Thomas Thrainer
    The ldisk parameter represents the degradation of the local
232 89ff748d Thomas Thrainer
    data. This is only valid for some devices, the rest will always
233 89ff748d Thomas Thrainer
    return False (not degraded).
234 89ff748d Thomas Thrainer

235 89ff748d Thomas Thrainer
    @rtype: objects.BlockDevStatus
236 89ff748d Thomas Thrainer

237 89ff748d Thomas Thrainer
    """
238 89ff748d Thomas Thrainer
    return objects.BlockDevStatus(dev_path=self.dev_path,
239 89ff748d Thomas Thrainer
                                  major=self.major,
240 89ff748d Thomas Thrainer
                                  minor=self.minor,
241 89ff748d Thomas Thrainer
                                  sync_percent=None,
242 89ff748d Thomas Thrainer
                                  estimated_time=None,
243 89ff748d Thomas Thrainer
                                  is_degraded=False,
244 89ff748d Thomas Thrainer
                                  ldisk_status=constants.LDS_OKAY)
245 89ff748d Thomas Thrainer
246 89ff748d Thomas Thrainer
  def CombinedSyncStatus(self):
247 89ff748d Thomas Thrainer
    """Calculate the mirror status recursively for our children.
248 89ff748d Thomas Thrainer

249 89ff748d Thomas Thrainer
    The return value is the same as for `GetSyncStatus()` except the
250 89ff748d Thomas Thrainer
    minimum percent and maximum time are calculated across our
251 89ff748d Thomas Thrainer
    children.
252 89ff748d Thomas Thrainer

253 89ff748d Thomas Thrainer
    @rtype: objects.BlockDevStatus
254 89ff748d Thomas Thrainer

255 89ff748d Thomas Thrainer
    """
256 89ff748d Thomas Thrainer
    status = self.GetSyncStatus()
257 89ff748d Thomas Thrainer
258 89ff748d Thomas Thrainer
    min_percent = status.sync_percent
259 89ff748d Thomas Thrainer
    max_time = status.estimated_time
260 89ff748d Thomas Thrainer
    is_degraded = status.is_degraded
261 89ff748d Thomas Thrainer
    ldisk_status = status.ldisk_status
262 89ff748d Thomas Thrainer
263 89ff748d Thomas Thrainer
    if self._children:
264 89ff748d Thomas Thrainer
      for child in self._children:
265 89ff748d Thomas Thrainer
        child_status = child.GetSyncStatus()
266 89ff748d Thomas Thrainer
267 89ff748d Thomas Thrainer
        if min_percent is None:
268 89ff748d Thomas Thrainer
          min_percent = child_status.sync_percent
269 89ff748d Thomas Thrainer
        elif child_status.sync_percent is not None:
270 89ff748d Thomas Thrainer
          min_percent = min(min_percent, child_status.sync_percent)
271 89ff748d Thomas Thrainer
272 89ff748d Thomas Thrainer
        if max_time is None:
273 89ff748d Thomas Thrainer
          max_time = child_status.estimated_time
274 89ff748d Thomas Thrainer
        elif child_status.estimated_time is not None:
275 89ff748d Thomas Thrainer
          max_time = max(max_time, child_status.estimated_time)
276 89ff748d Thomas Thrainer
277 89ff748d Thomas Thrainer
        is_degraded = is_degraded or child_status.is_degraded
278 89ff748d Thomas Thrainer
279 89ff748d Thomas Thrainer
        if ldisk_status is None:
280 89ff748d Thomas Thrainer
          ldisk_status = child_status.ldisk_status
281 89ff748d Thomas Thrainer
        elif child_status.ldisk_status is not None:
282 89ff748d Thomas Thrainer
          ldisk_status = max(ldisk_status, child_status.ldisk_status)
283 89ff748d Thomas Thrainer
284 89ff748d Thomas Thrainer
    return objects.BlockDevStatus(dev_path=self.dev_path,
285 89ff748d Thomas Thrainer
                                  major=self.major,
286 89ff748d Thomas Thrainer
                                  minor=self.minor,
287 89ff748d Thomas Thrainer
                                  sync_percent=min_percent,
288 89ff748d Thomas Thrainer
                                  estimated_time=max_time,
289 89ff748d Thomas Thrainer
                                  is_degraded=is_degraded,
290 89ff748d Thomas Thrainer
                                  ldisk_status=ldisk_status)
291 89ff748d Thomas Thrainer
292 89ff748d Thomas Thrainer
  def SetInfo(self, text):
293 89ff748d Thomas Thrainer
    """Update metadata with info text.
294 89ff748d Thomas Thrainer

295 89ff748d Thomas Thrainer
    Only supported for some device types.
296 89ff748d Thomas Thrainer

297 89ff748d Thomas Thrainer
    """
298 89ff748d Thomas Thrainer
    for child in self._children:
299 89ff748d Thomas Thrainer
      child.SetInfo(text)
300 89ff748d Thomas Thrainer
301 be9150ea Bernardo Dal Seno
  def Grow(self, amount, dryrun, backingstore, excl_stor):
302 89ff748d Thomas Thrainer
    """Grow the block device.
303 89ff748d Thomas Thrainer

304 89ff748d Thomas Thrainer
    @type amount: integer
305 89ff748d Thomas Thrainer
    @param amount: the amount (in mebibytes) to grow with
306 89ff748d Thomas Thrainer
    @type dryrun: boolean
307 89ff748d Thomas Thrainer
    @param dryrun: whether to execute the operation in simulation mode
308 89ff748d Thomas Thrainer
        only, without actually increasing the size
309 89ff748d Thomas Thrainer
    @param backingstore: whether to execute the operation on backing storage
310 89ff748d Thomas Thrainer
        only, or on "logical" storage only; e.g. DRBD is logical storage,
311 89ff748d Thomas Thrainer
        whereas LVM, file, RBD are backing storage
312 be9150ea Bernardo Dal Seno
    @type excl_stor: boolean
313 be9150ea Bernardo Dal Seno
    @param excl_stor: Whether exclusive_storage is active
314 89ff748d Thomas Thrainer

315 89ff748d Thomas Thrainer
    """
316 89ff748d Thomas Thrainer
    raise NotImplementedError
317 89ff748d Thomas Thrainer
318 89ff748d Thomas Thrainer
  def GetActualSize(self):
319 89ff748d Thomas Thrainer
    """Return the actual disk size.
320 89ff748d Thomas Thrainer

321 89ff748d Thomas Thrainer
    @note: the device needs to be active when this is called
322 89ff748d Thomas Thrainer

323 89ff748d Thomas Thrainer
    """
324 89ff748d Thomas Thrainer
    assert self.attached, "BlockDevice not attached in GetActualSize()"
325 89ff748d Thomas Thrainer
    result = utils.RunCmd(["blockdev", "--getsize64", self.dev_path])
326 89ff748d Thomas Thrainer
    if result.failed:
327 89ff748d Thomas Thrainer
      ThrowError("blockdev failed (%s): %s",
328 89ff748d Thomas Thrainer
                  result.fail_reason, result.output)
329 89ff748d Thomas Thrainer
    try:
330 89ff748d Thomas Thrainer
      sz = int(result.output.strip())
331 89ff748d Thomas Thrainer
    except (ValueError, TypeError), err:
332 89ff748d Thomas Thrainer
      ThrowError("Failed to parse blockdev output: %s", str(err))
333 89ff748d Thomas Thrainer
    return sz
334 89ff748d Thomas Thrainer
335 baa7f1d6 Bernardo Dal Seno
  def GetActualSpindles(self):
336 baa7f1d6 Bernardo Dal Seno
    """Return the actual number of spindles used.
337 baa7f1d6 Bernardo Dal Seno

338 baa7f1d6 Bernardo Dal Seno
    This is not supported by all devices; if not supported, C{None} is returned.
339 baa7f1d6 Bernardo Dal Seno

340 baa7f1d6 Bernardo Dal Seno
    @note: the device needs to be active when this is called
341 baa7f1d6 Bernardo Dal Seno

342 baa7f1d6 Bernardo Dal Seno
    """
343 baa7f1d6 Bernardo Dal Seno
    assert self.attached, "BlockDevice not attached in GetActualSpindles()"
344 baa7f1d6 Bernardo Dal Seno
    return None
345 baa7f1d6 Bernardo Dal Seno
346 baa7f1d6 Bernardo Dal Seno
  def GetActualDimensions(self):
347 baa7f1d6 Bernardo Dal Seno
    """Return the actual disk size and number of spindles used.
348 baa7f1d6 Bernardo Dal Seno

349 baa7f1d6 Bernardo Dal Seno
    @rtype: tuple
350 baa7f1d6 Bernardo Dal Seno
    @return: (size, spindles); spindles is C{None} when they are not supported
351 baa7f1d6 Bernardo Dal Seno

352 baa7f1d6 Bernardo Dal Seno
    @note: the device needs to be active when this is called
353 baa7f1d6 Bernardo Dal Seno

354 baa7f1d6 Bernardo Dal Seno
    """
355 baa7f1d6 Bernardo Dal Seno
    return (self.GetActualSize(), self.GetActualSpindles())
356 baa7f1d6 Bernardo Dal Seno
357 89ff748d Thomas Thrainer
  def __repr__(self):
358 89ff748d Thomas Thrainer
    return ("<%s: unique_id: %s, children: %s, %s:%s, %s>" %
359 89ff748d Thomas Thrainer
            (self.__class__, self.unique_id, self._children,
360 89ff748d Thomas Thrainer
             self.major, self.minor, self.dev_path))
361 89ff748d Thomas Thrainer
362 89ff748d Thomas Thrainer
363 89ff748d Thomas Thrainer
def ThrowError(msg, *args):
364 89ff748d Thomas Thrainer
  """Log an error to the node daemon and the raise an exception.
365 89ff748d Thomas Thrainer

366 89ff748d Thomas Thrainer
  @type msg: string
367 89ff748d Thomas Thrainer
  @param msg: the text of the exception
368 89ff748d Thomas Thrainer
  @raise errors.BlockDeviceError
369 89ff748d Thomas Thrainer

370 89ff748d Thomas Thrainer
  """
371 89ff748d Thomas Thrainer
  if args:
372 89ff748d Thomas Thrainer
    msg = msg % args
373 89ff748d Thomas Thrainer
  logging.error(msg)
374 89ff748d Thomas Thrainer
  raise errors.BlockDeviceError(msg)
375 89ff748d Thomas Thrainer
376 89ff748d Thomas Thrainer
377 89ff748d Thomas Thrainer
def IgnoreError(fn, *args, **kwargs):
378 89ff748d Thomas Thrainer
  """Executes the given function, ignoring BlockDeviceErrors.
379 89ff748d Thomas Thrainer

380 89ff748d Thomas Thrainer
  This is used in order to simplify the execution of cleanup or
381 89ff748d Thomas Thrainer
  rollback functions.
382 89ff748d Thomas Thrainer

383 89ff748d Thomas Thrainer
  @rtype: boolean
384 89ff748d Thomas Thrainer
  @return: True when fn didn't raise an exception, False otherwise
385 89ff748d Thomas Thrainer

386 89ff748d Thomas Thrainer
  """
387 89ff748d Thomas Thrainer
  try:
388 89ff748d Thomas Thrainer
    fn(*args, **kwargs)
389 89ff748d Thomas Thrainer
    return True
390 89ff748d Thomas Thrainer
  except errors.BlockDeviceError, err:
391 89ff748d Thomas Thrainer
    logging.warning("Caught BlockDeviceError but ignoring: %s", str(err))
392 89ff748d Thomas Thrainer
    return False