Statistics
| Branch: | Tag: | Revision:

root / lib / bdev.py @ 0188611b

History | View | Annotate | Download (87 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 0304f0ec Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Block device abstraction"""
23 a8083063 Iustin Pop
24 a8083063 Iustin Pop
import re
25 a8083063 Iustin Pop
import time
26 a8083063 Iustin Pop
import errno
27 ad1dd4c7 Andrea Spadaccini
import shlex
28 b6135bbc Apollon Oikonomopoulos
import stat
29 a2cfdea2 Iustin Pop
import pyparsing as pyp
30 6f695a2e Manuel Franceschini
import os
31 468c5f77 Iustin Pop
import logging
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti import utils
34 a8083063 Iustin Pop
from ganeti import errors
35 fe96220b Iustin Pop
from ganeti import constants
36 96acbc09 Michael Hanselmann
from ganeti import objects
37 cea881e5 Michael Hanselmann
from ganeti import compat
38 a744b676 Manuel Franceschini
from ganeti import netutils
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
41 310fbb64 Iustin Pop
# Size of reads in _CanReadDevice
42 310fbb64 Iustin Pop
_DEVICE_READ_SIZE = 128 * 1024
43 310fbb64 Iustin Pop
44 310fbb64 Iustin Pop
45 82463074 Iustin Pop
def _IgnoreError(fn, *args, **kwargs):
46 82463074 Iustin Pop
  """Executes the given function, ignoring BlockDeviceErrors.
47 82463074 Iustin Pop

48 82463074 Iustin Pop
  This is used in order to simplify the execution of cleanup or
49 82463074 Iustin Pop
  rollback functions.
50 82463074 Iustin Pop

51 82463074 Iustin Pop
  @rtype: boolean
52 82463074 Iustin Pop
  @return: True when fn didn't raise an exception, False otherwise
53 82463074 Iustin Pop

54 82463074 Iustin Pop
  """
55 82463074 Iustin Pop
  try:
56 82463074 Iustin Pop
    fn(*args, **kwargs)
57 82463074 Iustin Pop
    return True
58 82463074 Iustin Pop
  except errors.BlockDeviceError, err:
59 099c52ad Iustin Pop
    logging.warning("Caught BlockDeviceError but ignoring: %s", str(err))
60 82463074 Iustin Pop
    return False
61 82463074 Iustin Pop
62 82463074 Iustin Pop
63 82463074 Iustin Pop
def _ThrowError(msg, *args):
64 82463074 Iustin Pop
  """Log an error to the node daemon and the raise an exception.
65 82463074 Iustin Pop

66 82463074 Iustin Pop
  @type msg: string
67 82463074 Iustin Pop
  @param msg: the text of the exception
68 82463074 Iustin Pop
  @raise errors.BlockDeviceError
69 82463074 Iustin Pop

70 82463074 Iustin Pop
  """
71 82463074 Iustin Pop
  if args:
72 82463074 Iustin Pop
    msg = msg % args
73 82463074 Iustin Pop
  logging.error(msg)
74 82463074 Iustin Pop
  raise errors.BlockDeviceError(msg)
75 82463074 Iustin Pop
76 82463074 Iustin Pop
77 310fbb64 Iustin Pop
def _CanReadDevice(path):
78 310fbb64 Iustin Pop
  """Check if we can read from the given device.
79 310fbb64 Iustin Pop

80 310fbb64 Iustin Pop
  This tries to read the first 128k of the device.
81 310fbb64 Iustin Pop

82 310fbb64 Iustin Pop
  """
83 310fbb64 Iustin Pop
  try:
84 310fbb64 Iustin Pop
    utils.ReadFile(path, size=_DEVICE_READ_SIZE)
85 310fbb64 Iustin Pop
    return True
86 1122eb25 Iustin Pop
  except EnvironmentError:
87 310fbb64 Iustin Pop
    logging.warning("Can't read from device %s", path, exc_info=True)
88 310fbb64 Iustin Pop
    return False
89 310fbb64 Iustin Pop
90 310fbb64 Iustin Pop
91 a8083063 Iustin Pop
class BlockDev(object):
92 a8083063 Iustin Pop
  """Block device abstract class.
93 a8083063 Iustin Pop

94 a8083063 Iustin Pop
  A block device can be in the following states:
95 a8083063 Iustin Pop
    - not existing on the system, and by `Create()` it goes into:
96 a8083063 Iustin Pop
    - existing but not setup/not active, and by `Assemble()` goes into:
97 a8083063 Iustin Pop
    - active read-write and by `Open()` it goes into
98 a8083063 Iustin Pop
    - online (=used, or ready for use)
99 a8083063 Iustin Pop

100 a8083063 Iustin Pop
  A device can also be online but read-only, however we are not using
101 abdf0113 Iustin Pop
  the readonly state (LV has it, if needed in the future) and we are
102 abdf0113 Iustin Pop
  usually looking at this like at a stack, so it's easier to
103 abdf0113 Iustin Pop
  conceptualise the transition from not-existing to online and back
104 a8083063 Iustin Pop
  like a linear one.
105 a8083063 Iustin Pop

106 a8083063 Iustin Pop
  The many different states of the device are due to the fact that we
107 a8083063 Iustin Pop
  need to cover many device types:
108 a8083063 Iustin Pop
    - logical volumes are created, lvchange -a y $lv, and used
109 a8083063 Iustin Pop
    - drbd devices are attached to a local disk/remote peer and made primary
110 a8083063 Iustin Pop

111 a8083063 Iustin Pop
  A block device is identified by three items:
112 a8083063 Iustin Pop
    - the /dev path of the device (dynamic)
113 a8083063 Iustin Pop
    - a unique ID of the device (static)
114 a8083063 Iustin Pop
    - it's major/minor pair (dynamic)
115 a8083063 Iustin Pop

116 a8083063 Iustin Pop
  Not all devices implement both the first two as distinct items. LVM
117 a8083063 Iustin Pop
  logical volumes have their unique ID (the pair volume group, logical
118 abdf0113 Iustin Pop
  volume name) in a 1-to-1 relation to the dev path. For DRBD devices,
119 abdf0113 Iustin Pop
  the /dev path is again dynamic and the unique id is the pair (host1,
120 abdf0113 Iustin Pop
  dev1), (host2, dev2).
121 a8083063 Iustin Pop

122 a8083063 Iustin Pop
  You can get to a device in two ways:
123 a8083063 Iustin Pop
    - creating the (real) device, which returns you
124 abdf0113 Iustin Pop
      an attached instance (lvcreate)
125 a8083063 Iustin Pop
    - attaching of a python instance to an existing (real) device
126 a8083063 Iustin Pop

127 a8083063 Iustin Pop
  The second point, the attachement to a device, is different
128 a8083063 Iustin Pop
  depending on whether the device is assembled or not. At init() time,
129 a8083063 Iustin Pop
  we search for a device with the same unique_id as us. If found,
130 a8083063 Iustin Pop
  good. It also means that the device is already assembled. If not,
131 a8083063 Iustin Pop
  after assembly we'll have our correct major/minor.
132 a8083063 Iustin Pop

133 a8083063 Iustin Pop
  """
134 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
135 a8083063 Iustin Pop
    self._children = children
136 a8083063 Iustin Pop
    self.dev_path = None
137 a8083063 Iustin Pop
    self.unique_id = unique_id
138 a8083063 Iustin Pop
    self.major = None
139 a8083063 Iustin Pop
    self.minor = None
140 cb999543 Iustin Pop
    self.attached = False
141 464f8daf Iustin Pop
    self.size = size
142 94dcbdb0 Andrea Spadaccini
    self.params = params
143 a8083063 Iustin Pop
144 a8083063 Iustin Pop
  def Assemble(self):
145 a8083063 Iustin Pop
    """Assemble the device from its components.
146 a8083063 Iustin Pop

147 f87548b5 Iustin Pop
    Implementations of this method by child classes must ensure that:
148 f87548b5 Iustin Pop
      - after the device has been assembled, it knows its major/minor
149 f87548b5 Iustin Pop
        numbers; this allows other devices (usually parents) to probe
150 f87548b5 Iustin Pop
        correctly for their children
151 f87548b5 Iustin Pop
      - calling this method on an existing, in-use device is safe
152 f87548b5 Iustin Pop
      - if the device is already configured (and in an OK state),
153 f87548b5 Iustin Pop
        this method is idempotent
154 a8083063 Iustin Pop

155 a8083063 Iustin Pop
    """
156 1063abd1 Iustin Pop
    pass
157 a8083063 Iustin Pop
158 a8083063 Iustin Pop
  def Attach(self):
159 a8083063 Iustin Pop
    """Find a device which matches our config and attach to it.
160 a8083063 Iustin Pop

161 a8083063 Iustin Pop
    """
162 a8083063 Iustin Pop
    raise NotImplementedError
163 a8083063 Iustin Pop
164 a8083063 Iustin Pop
  def Close(self):
165 a8083063 Iustin Pop
    """Notifies that the device will no longer be used for I/O.
166 a8083063 Iustin Pop

167 a8083063 Iustin Pop
    """
168 a8083063 Iustin Pop
    raise NotImplementedError
169 a8083063 Iustin Pop
170 a8083063 Iustin Pop
  @classmethod
171 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
172 a8083063 Iustin Pop
    """Create the device.
173 a8083063 Iustin Pop

174 a8083063 Iustin Pop
    If the device cannot be created, it will return None
175 a8083063 Iustin Pop
    instead. Error messages go to the logging system.
176 a8083063 Iustin Pop

177 a8083063 Iustin Pop
    Note that for some devices, the unique_id is used, and for other,
178 a8083063 Iustin Pop
    the children. The idea is that these two, taken together, are
179 a8083063 Iustin Pop
    enough for both creation and assembly (later).
180 a8083063 Iustin Pop

181 a8083063 Iustin Pop
    """
182 a8083063 Iustin Pop
    raise NotImplementedError
183 a8083063 Iustin Pop
184 a8083063 Iustin Pop
  def Remove(self):
185 a8083063 Iustin Pop
    """Remove this device.
186 a8083063 Iustin Pop

187 abdf0113 Iustin Pop
    This makes sense only for some of the device types: LV and file
188 5bbd3f7f Michael Hanselmann
    storage. Also note that if the device can't attach, the removal
189 abdf0113 Iustin Pop
    can't be completed.
190 a8083063 Iustin Pop

191 a8083063 Iustin Pop
    """
192 a8083063 Iustin Pop
    raise NotImplementedError
193 a8083063 Iustin Pop
194 f3e513ad Iustin Pop
  def Rename(self, new_id):
195 f3e513ad Iustin Pop
    """Rename this device.
196 f3e513ad Iustin Pop

197 f3e513ad Iustin Pop
    This may or may not make sense for a given device type.
198 f3e513ad Iustin Pop

199 f3e513ad Iustin Pop
    """
200 f3e513ad Iustin Pop
    raise NotImplementedError
201 f3e513ad Iustin Pop
202 a8083063 Iustin Pop
  def Open(self, force=False):
203 a8083063 Iustin Pop
    """Make the device ready for use.
204 a8083063 Iustin Pop

205 a8083063 Iustin Pop
    This makes the device ready for I/O. For now, just the DRBD
206 a8083063 Iustin Pop
    devices need this.
207 a8083063 Iustin Pop

208 a8083063 Iustin Pop
    The force parameter signifies that if the device has any kind of
209 a8083063 Iustin Pop
    --force thing, it should be used, we know what we are doing.
210 a8083063 Iustin Pop

211 a8083063 Iustin Pop
    """
212 a8083063 Iustin Pop
    raise NotImplementedError
213 a8083063 Iustin Pop
214 a8083063 Iustin Pop
  def Shutdown(self):
215 a8083063 Iustin Pop
    """Shut down the device, freeing its children.
216 a8083063 Iustin Pop

217 a8083063 Iustin Pop
    This undoes the `Assemble()` work, except for the child
218 a8083063 Iustin Pop
    assembling; as such, the children on the device are still
219 a8083063 Iustin Pop
    assembled after this call.
220 a8083063 Iustin Pop

221 a8083063 Iustin Pop
    """
222 a8083063 Iustin Pop
    raise NotImplementedError
223 a8083063 Iustin Pop
224 f2f57b6e Andrea Spadaccini
  def SetSyncParams(self, params):
225 f2f57b6e Andrea Spadaccini
    """Adjust the synchronization parameters of the mirror.
226 a8083063 Iustin Pop

227 a8083063 Iustin Pop
    In case this is not a mirroring device, this is no-op.
228 a8083063 Iustin Pop

229 f2f57b6e Andrea Spadaccini
    @param params: dictionary of LD level disk parameters related to the
230 f2f57b6e Andrea Spadaccini
    synchronization.
231 8584e922 Andrea Spadaccini
    @rtype: list
232 8584e922 Andrea Spadaccini
    @return: a list of error messages, emitted both by the current node and by
233 8584e922 Andrea Spadaccini
    children. An empty list means no errors.
234 f2f57b6e Andrea Spadaccini

235 a8083063 Iustin Pop
    """
236 8584e922 Andrea Spadaccini
    result = []
237 a8083063 Iustin Pop
    if self._children:
238 a8083063 Iustin Pop
      for child in self._children:
239 8584e922 Andrea Spadaccini
        result.extend(child.SetSyncParams(params))
240 a8083063 Iustin Pop
    return result
241 a8083063 Iustin Pop
242 a3fffcc6 René Nussbaumer
  def PauseResumeSync(self, pause):
243 a3fffcc6 René Nussbaumer
    """Pause/Resume the sync of the mirror.
244 a3fffcc6 René Nussbaumer

245 a3fffcc6 René Nussbaumer
    In case this is not a mirroring device, this is no-op.
246 a3fffcc6 René Nussbaumer

247 f2f57b6e Andrea Spadaccini
    @param pause: Whether to pause or resume
248 a3fffcc6 René Nussbaumer

249 a3fffcc6 René Nussbaumer
    """
250 a3fffcc6 René Nussbaumer
    result = True
251 a3fffcc6 René Nussbaumer
    if self._children:
252 a3fffcc6 René Nussbaumer
      for child in self._children:
253 a3fffcc6 René Nussbaumer
        result = result and child.PauseResumeSync(pause)
254 a3fffcc6 René Nussbaumer
    return result
255 a3fffcc6 René Nussbaumer
256 a8083063 Iustin Pop
  def GetSyncStatus(self):
257 a8083063 Iustin Pop
    """Returns the sync status of the device.
258 a8083063 Iustin Pop

259 a8083063 Iustin Pop
    If this device is a mirroring device, this function returns the
260 a8083063 Iustin Pop
    status of the mirror.
261 a8083063 Iustin Pop

262 0834c866 Iustin Pop
    If sync_percent is None, it means the device is not syncing.
263 a8083063 Iustin Pop

264 a8083063 Iustin Pop
    If estimated_time is None, it means we can't estimate
265 0834c866 Iustin Pop
    the time needed, otherwise it's the time left in seconds.
266 0834c866 Iustin Pop

267 a8083063 Iustin Pop
    If is_degraded is True, it means the device is missing
268 a8083063 Iustin Pop
    redundancy. This is usually a sign that something went wrong in
269 a8083063 Iustin Pop
    the device setup, if sync_percent is None.
270 a8083063 Iustin Pop

271 0834c866 Iustin Pop
    The ldisk parameter represents the degradation of the local
272 0834c866 Iustin Pop
    data. This is only valid for some devices, the rest will always
273 0834c866 Iustin Pop
    return False (not degraded).
274 0834c866 Iustin Pop

275 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
276 c41eea6e Iustin Pop

277 a8083063 Iustin Pop
    """
278 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
279 96acbc09 Michael Hanselmann
                                  major=self.major,
280 96acbc09 Michael Hanselmann
                                  minor=self.minor,
281 96acbc09 Michael Hanselmann
                                  sync_percent=None,
282 96acbc09 Michael Hanselmann
                                  estimated_time=None,
283 96acbc09 Michael Hanselmann
                                  is_degraded=False,
284 f208978a Michael Hanselmann
                                  ldisk_status=constants.LDS_OKAY)
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
  def CombinedSyncStatus(self):
287 a8083063 Iustin Pop
    """Calculate the mirror status recursively for our children.
288 a8083063 Iustin Pop

289 a8083063 Iustin Pop
    The return value is the same as for `GetSyncStatus()` except the
290 a8083063 Iustin Pop
    minimum percent and maximum time are calculated across our
291 a8083063 Iustin Pop
    children.
292 a8083063 Iustin Pop

293 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
294 96acbc09 Michael Hanselmann

295 a8083063 Iustin Pop
    """
296 96acbc09 Michael Hanselmann
    status = self.GetSyncStatus()
297 96acbc09 Michael Hanselmann
298 96acbc09 Michael Hanselmann
    min_percent = status.sync_percent
299 96acbc09 Michael Hanselmann
    max_time = status.estimated_time
300 96acbc09 Michael Hanselmann
    is_degraded = status.is_degraded
301 f208978a Michael Hanselmann
    ldisk_status = status.ldisk_status
302 96acbc09 Michael Hanselmann
303 a8083063 Iustin Pop
    if self._children:
304 a8083063 Iustin Pop
      for child in self._children:
305 96acbc09 Michael Hanselmann
        child_status = child.GetSyncStatus()
306 96acbc09 Michael Hanselmann
307 a8083063 Iustin Pop
        if min_percent is None:
308 96acbc09 Michael Hanselmann
          min_percent = child_status.sync_percent
309 96acbc09 Michael Hanselmann
        elif child_status.sync_percent is not None:
310 96acbc09 Michael Hanselmann
          min_percent = min(min_percent, child_status.sync_percent)
311 96acbc09 Michael Hanselmann
312 a8083063 Iustin Pop
        if max_time is None:
313 96acbc09 Michael Hanselmann
          max_time = child_status.estimated_time
314 96acbc09 Michael Hanselmann
        elif child_status.estimated_time is not None:
315 96acbc09 Michael Hanselmann
          max_time = max(max_time, child_status.estimated_time)
316 96acbc09 Michael Hanselmann
317 96acbc09 Michael Hanselmann
        is_degraded = is_degraded or child_status.is_degraded
318 f208978a Michael Hanselmann
319 f208978a Michael Hanselmann
        if ldisk_status is None:
320 f208978a Michael Hanselmann
          ldisk_status = child_status.ldisk_status
321 f208978a Michael Hanselmann
        elif child_status.ldisk_status is not None:
322 f208978a Michael Hanselmann
          ldisk_status = max(ldisk_status, child_status.ldisk_status)
323 96acbc09 Michael Hanselmann
324 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
325 96acbc09 Michael Hanselmann
                                  major=self.major,
326 96acbc09 Michael Hanselmann
                                  minor=self.minor,
327 96acbc09 Michael Hanselmann
                                  sync_percent=min_percent,
328 96acbc09 Michael Hanselmann
                                  estimated_time=max_time,
329 96acbc09 Michael Hanselmann
                                  is_degraded=is_degraded,
330 f208978a Michael Hanselmann
                                  ldisk_status=ldisk_status)
331 a8083063 Iustin Pop
332 a0c3fea1 Michael Hanselmann
  def SetInfo(self, text):
333 a0c3fea1 Michael Hanselmann
    """Update metadata with info text.
334 a0c3fea1 Michael Hanselmann

335 a0c3fea1 Michael Hanselmann
    Only supported for some device types.
336 a0c3fea1 Michael Hanselmann

337 a0c3fea1 Michael Hanselmann
    """
338 a0c3fea1 Michael Hanselmann
    for child in self._children:
339 a0c3fea1 Michael Hanselmann
      child.SetInfo(text)
340 a0c3fea1 Michael Hanselmann
341 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
342 1005d816 Iustin Pop
    """Grow the block device.
343 1005d816 Iustin Pop

344 7fe23d47 Iustin Pop
    @type amount: integer
345 c41eea6e Iustin Pop
    @param amount: the amount (in mebibytes) to grow with
346 7fe23d47 Iustin Pop
    @type dryrun: boolean
347 7fe23d47 Iustin Pop
    @param dryrun: whether to execute the operation in simulation mode
348 7fe23d47 Iustin Pop
        only, without actually increasing the size
349 cad0723b Iustin Pop
    @param backingstore: whether to execute the operation on backing storage
350 cad0723b Iustin Pop
        only, or on "logical" storage only; e.g. DRBD is logical storage,
351 cad0723b Iustin Pop
        whereas LVM, file, RBD are backing storage
352 1005d816 Iustin Pop

353 1005d816 Iustin Pop
    """
354 1005d816 Iustin Pop
    raise NotImplementedError
355 a0c3fea1 Michael Hanselmann
356 fcff3897 Iustin Pop
  def GetActualSize(self):
357 fcff3897 Iustin Pop
    """Return the actual disk size.
358 fcff3897 Iustin Pop

359 fcff3897 Iustin Pop
    @note: the device needs to be active when this is called
360 fcff3897 Iustin Pop

361 fcff3897 Iustin Pop
    """
362 fcff3897 Iustin Pop
    assert self.attached, "BlockDevice not attached in GetActualSize()"
363 fcff3897 Iustin Pop
    result = utils.RunCmd(["blockdev", "--getsize64", self.dev_path])
364 fcff3897 Iustin Pop
    if result.failed:
365 fcff3897 Iustin Pop
      _ThrowError("blockdev failed (%s): %s",
366 fcff3897 Iustin Pop
                  result.fail_reason, result.output)
367 fcff3897 Iustin Pop
    try:
368 fcff3897 Iustin Pop
      sz = int(result.output.strip())
369 fcff3897 Iustin Pop
    except (ValueError, TypeError), err:
370 fcff3897 Iustin Pop
      _ThrowError("Failed to parse blockdev output: %s", str(err))
371 fcff3897 Iustin Pop
    return sz
372 fcff3897 Iustin Pop
373 a8083063 Iustin Pop
  def __repr__(self):
374 a8083063 Iustin Pop
    return ("<%s: unique_id: %s, children: %s, %s:%s, %s>" %
375 a8083063 Iustin Pop
            (self.__class__, self.unique_id, self._children,
376 a8083063 Iustin Pop
             self.major, self.minor, self.dev_path))
377 a8083063 Iustin Pop
378 a8083063 Iustin Pop
379 a8083063 Iustin Pop
class LogicalVolume(BlockDev):
380 a8083063 Iustin Pop
  """Logical Volume block device.
381 a8083063 Iustin Pop

382 a8083063 Iustin Pop
  """
383 6136f8f0 Iustin Pop
  _VALID_NAME_RE = re.compile("^[a-zA-Z0-9+_.-]*$")
384 6136f8f0 Iustin Pop
  _INVALID_NAMES = frozenset([".", "..", "snapshot", "pvmove"])
385 6136f8f0 Iustin Pop
  _INVALID_SUBSTRINGS = frozenset(["_mlog", "_mimage"])
386 6136f8f0 Iustin Pop
387 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
388 a8083063 Iustin Pop
    """Attaches to a LV device.
389 a8083063 Iustin Pop

390 a8083063 Iustin Pop
    The unique_id is a tuple (vg_name, lv_name)
391 a8083063 Iustin Pop

392 a8083063 Iustin Pop
    """
393 94dcbdb0 Andrea Spadaccini
    super(LogicalVolume, self).__init__(unique_id, children, size, params)
394 a8083063 Iustin Pop
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
395 a8083063 Iustin Pop
      raise ValueError("Invalid configuration data %s" % str(unique_id))
396 a8083063 Iustin Pop
    self._vg_name, self._lv_name = unique_id
397 6136f8f0 Iustin Pop
    self._ValidateName(self._vg_name)
398 6136f8f0 Iustin Pop
    self._ValidateName(self._lv_name)
399 6136f8f0 Iustin Pop
    self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
400 99e8295c Iustin Pop
    self._degraded = True
401 38256320 Iustin Pop
    self.major = self.minor = self.pe_size = self.stripe_count = None
402 a8083063 Iustin Pop
    self.Attach()
403 a8083063 Iustin Pop
404 a8083063 Iustin Pop
  @classmethod
405 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
406 a8083063 Iustin Pop
    """Create a new logical volume.
407 a8083063 Iustin Pop

408 a8083063 Iustin Pop
    """
409 a8083063 Iustin Pop
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
410 6c626518 Iustin Pop
      raise errors.ProgrammerError("Invalid configuration data %s" %
411 6c626518 Iustin Pop
                                   str(unique_id))
412 a8083063 Iustin Pop
    vg_name, lv_name = unique_id
413 6136f8f0 Iustin Pop
    cls._ValidateName(vg_name)
414 6136f8f0 Iustin Pop
    cls._ValidateName(lv_name)
415 2070598f Iustin Pop
    pvs_info = cls.GetPVInfo([vg_name])
416 a8083063 Iustin Pop
    if not pvs_info:
417 82463074 Iustin Pop
      _ThrowError("Can't compute PV info for vg %s", vg_name)
418 a8083063 Iustin Pop
    pvs_info.sort()
419 a8083063 Iustin Pop
    pvs_info.reverse()
420 5b7b5d49 Guido Trotter
421 e687ec01 Michael Hanselmann
    pvlist = [pv[1] for pv in pvs_info]
422 403f5172 Guido Trotter
    if compat.any(":" in v for v in pvlist):
423 01b6558a Iustin Pop
      _ThrowError("Some of your PVs have the invalid character ':' in their"
424 01b6558a Iustin Pop
                  " name, this is not supported - please filter them out"
425 01b6558a Iustin Pop
                  " in lvm.conf using either 'filter' or 'preferred_names'")
426 e687ec01 Michael Hanselmann
    free_size = sum([pv[0] for pv in pvs_info])
427 fecbe9d5 Iustin Pop
    current_pvs = len(pvlist)
428 ac00bf1b Andrea Spadaccini
    desired_stripes = params[constants.LDP_STRIPES]
429 43e11798 Andrea Spadaccini
    stripes = min(current_pvs, desired_stripes)
430 43e11798 Andrea Spadaccini
    if stripes < desired_stripes:
431 43e11798 Andrea Spadaccini
      logging.warning("Could not use %d stripes for VG %s, as only %d PVs are"
432 43e11798 Andrea Spadaccini
                      " available.", desired_stripes, vg_name, current_pvs)
433 5b7b5d49 Guido Trotter
434 5b7b5d49 Guido Trotter
    # The size constraint should have been checked from the master before
435 5b7b5d49 Guido Trotter
    # calling the create function.
436 a8083063 Iustin Pop
    if free_size < size:
437 82463074 Iustin Pop
      _ThrowError("Not enough free space: required %s,"
438 82463074 Iustin Pop
                  " available %s", size, free_size)
439 fecbe9d5 Iustin Pop
    cmd = ["lvcreate", "-L%dm" % size, "-n%s" % lv_name]
440 fecbe9d5 Iustin Pop
    # If the free space is not well distributed, we won't be able to
441 fecbe9d5 Iustin Pop
    # create an optimally-striped volume; in that case, we want to try
442 fecbe9d5 Iustin Pop
    # with N, N-1, ..., 2, and finally 1 (non-stripped) number of
443 fecbe9d5 Iustin Pop
    # stripes
444 fecbe9d5 Iustin Pop
    for stripes_arg in range(stripes, 0, -1):
445 fecbe9d5 Iustin Pop
      result = utils.RunCmd(cmd + ["-i%d" % stripes_arg] + [vg_name] + pvlist)
446 fecbe9d5 Iustin Pop
      if not result.failed:
447 fecbe9d5 Iustin Pop
        break
448 a8083063 Iustin Pop
    if result.failed:
449 82463074 Iustin Pop
      _ThrowError("LV create failed (%s): %s",
450 82463074 Iustin Pop
                  result.fail_reason, result.output)
451 94dcbdb0 Andrea Spadaccini
    return LogicalVolume(unique_id, children, size, params)
452 a8083063 Iustin Pop
453 a8083063 Iustin Pop
  @staticmethod
454 197478f2 René Nussbaumer
  def _GetVolumeInfo(lvm_cmd, fields):
455 197478f2 René Nussbaumer
    """Returns LVM Volumen infos using lvm_cmd
456 197478f2 René Nussbaumer

457 197478f2 René Nussbaumer
    @param lvm_cmd: Should be one of "pvs", "vgs" or "lvs"
458 197478f2 René Nussbaumer
    @param fields: Fields to return
459 197478f2 René Nussbaumer
    @return: A list of dicts each with the parsed fields
460 197478f2 René Nussbaumer

461 197478f2 René Nussbaumer
    """
462 197478f2 René Nussbaumer
    if not fields:
463 197478f2 René Nussbaumer
      raise errors.ProgrammerError("No fields specified")
464 197478f2 René Nussbaumer
465 197478f2 René Nussbaumer
    sep = "|"
466 197478f2 René Nussbaumer
    cmd = [lvm_cmd, "--noheadings", "--nosuffix", "--units=m", "--unbuffered",
467 197478f2 René Nussbaumer
           "--separator=%s" % sep, "-o%s" % ",".join(fields)]
468 197478f2 René Nussbaumer
469 197478f2 René Nussbaumer
    result = utils.RunCmd(cmd)
470 197478f2 René Nussbaumer
    if result.failed:
471 197478f2 René Nussbaumer
      raise errors.CommandError("Can't get the volume information: %s - %s" %
472 197478f2 René Nussbaumer
                                (result.fail_reason, result.output))
473 197478f2 René Nussbaumer
474 197478f2 René Nussbaumer
    data = []
475 197478f2 René Nussbaumer
    for line in result.stdout.splitlines():
476 197478f2 René Nussbaumer
      splitted_fields = line.strip().split(sep)
477 197478f2 René Nussbaumer
478 197478f2 René Nussbaumer
      if len(fields) != len(splitted_fields):
479 197478f2 René Nussbaumer
        raise errors.CommandError("Can't parse %s output: line '%s'" %
480 197478f2 René Nussbaumer
                                  (lvm_cmd, line))
481 197478f2 René Nussbaumer
482 197478f2 René Nussbaumer
      data.append(splitted_fields)
483 197478f2 René Nussbaumer
484 197478f2 René Nussbaumer
    return data
485 197478f2 René Nussbaumer
486 197478f2 René Nussbaumer
  @classmethod
487 197478f2 René Nussbaumer
  def GetPVInfo(cls, vg_names, filter_allocatable=True):
488 a8083063 Iustin Pop
    """Get the free space info for PVs in a volume group.
489 a8083063 Iustin Pop

490 2070598f Iustin Pop
    @param vg_names: list of volume group names, if empty all will be returned
491 2070598f Iustin Pop
    @param filter_allocatable: whether to skip over unallocatable PVs
492 a8083063 Iustin Pop

493 c41eea6e Iustin Pop
    @rtype: list
494 c41eea6e Iustin Pop
    @return: list of tuples (free_space, name) with free_space in mebibytes
495 098c0958 Michael Hanselmann

496 a8083063 Iustin Pop
    """
497 197478f2 René Nussbaumer
    try:
498 197478f2 René Nussbaumer
      info = cls._GetVolumeInfo("pvs", ["pv_name", "vg_name", "pv_free",
499 197478f2 René Nussbaumer
                                        "pv_attr"])
500 197478f2 René Nussbaumer
    except errors.GenericError, err:
501 197478f2 René Nussbaumer
      logging.error("Can't get PV information: %s", err)
502 a8083063 Iustin Pop
      return None
503 197478f2 René Nussbaumer
504 a8083063 Iustin Pop
    data = []
505 197478f2 René Nussbaumer
    for pv_name, vg_name, pv_free, pv_attr in info:
506 2070598f Iustin Pop
      # (possibly) skip over pvs which are not allocatable
507 197478f2 René Nussbaumer
      if filter_allocatable and pv_attr[0] != "a":
508 a8083063 Iustin Pop
        continue
509 2070598f Iustin Pop
      # (possibly) skip over pvs which are not in the right volume group(s)
510 197478f2 René Nussbaumer
      if vg_names and vg_name not in vg_names:
511 2070598f Iustin Pop
        continue
512 197478f2 René Nussbaumer
      data.append((float(pv_free), pv_name, vg_name))
513 197478f2 René Nussbaumer
514 197478f2 René Nussbaumer
    return data
515 197478f2 René Nussbaumer
516 197478f2 René Nussbaumer
  @classmethod
517 197478f2 René Nussbaumer
  def GetVGInfo(cls, vg_names, filter_readonly=True):
518 197478f2 René Nussbaumer
    """Get the free space info for specific VGs.
519 197478f2 René Nussbaumer

520 197478f2 René Nussbaumer
    @param vg_names: list of volume group names, if empty all will be returned
521 197478f2 René Nussbaumer
    @param filter_readonly: whether to skip over readonly VGs
522 197478f2 René Nussbaumer

523 197478f2 René Nussbaumer
    @rtype: list
524 673cd9c4 René Nussbaumer
    @return: list of tuples (free_space, total_size, name) with free_space in
525 673cd9c4 René Nussbaumer
             MiB
526 197478f2 René Nussbaumer

527 197478f2 René Nussbaumer
    """
528 197478f2 René Nussbaumer
    try:
529 673cd9c4 René Nussbaumer
      info = cls._GetVolumeInfo("vgs", ["vg_name", "vg_free", "vg_attr",
530 673cd9c4 René Nussbaumer
                                        "vg_size"])
531 197478f2 René Nussbaumer
    except errors.GenericError, err:
532 197478f2 René Nussbaumer
      logging.error("Can't get VG information: %s", err)
533 197478f2 René Nussbaumer
      return None
534 197478f2 René Nussbaumer
535 197478f2 René Nussbaumer
    data = []
536 673cd9c4 René Nussbaumer
    for vg_name, vg_free, vg_attr, vg_size in info:
537 197478f2 René Nussbaumer
      # (possibly) skip over vgs which are not writable
538 197478f2 René Nussbaumer
      if filter_readonly and vg_attr[0] == "r":
539 197478f2 René Nussbaumer
        continue
540 197478f2 René Nussbaumer
      # (possibly) skip over vgs which are not in the right volume group(s)
541 197478f2 René Nussbaumer
      if vg_names and vg_name not in vg_names:
542 197478f2 René Nussbaumer
        continue
543 673cd9c4 René Nussbaumer
      data.append((float(vg_free), float(vg_size), vg_name))
544 a8083063 Iustin Pop
545 a8083063 Iustin Pop
    return data
546 a8083063 Iustin Pop
547 6136f8f0 Iustin Pop
  @classmethod
548 6136f8f0 Iustin Pop
  def _ValidateName(cls, name):
549 6136f8f0 Iustin Pop
    """Validates that a given name is valid as VG or LV name.
550 6136f8f0 Iustin Pop

551 6136f8f0 Iustin Pop
    The list of valid characters and restricted names is taken out of
552 6136f8f0 Iustin Pop
    the lvm(8) manpage, with the simplification that we enforce both
553 6136f8f0 Iustin Pop
    VG and LV restrictions on the names.
554 6136f8f0 Iustin Pop

555 6136f8f0 Iustin Pop
    """
556 6136f8f0 Iustin Pop
    if (not cls._VALID_NAME_RE.match(name) or
557 6136f8f0 Iustin Pop
        name in cls._INVALID_NAMES or
558 403f5172 Guido Trotter
        compat.any(substring in name for substring in cls._INVALID_SUBSTRINGS)):
559 6136f8f0 Iustin Pop
      _ThrowError("Invalid LVM name '%s'", name)
560 6136f8f0 Iustin Pop
561 a8083063 Iustin Pop
  def Remove(self):
562 a8083063 Iustin Pop
    """Remove this logical volume.
563 a8083063 Iustin Pop

564 a8083063 Iustin Pop
    """
565 a8083063 Iustin Pop
    if not self.minor and not self.Attach():
566 a8083063 Iustin Pop
      # the LV does not exist
567 0c6c04ec Iustin Pop
      return
568 a8083063 Iustin Pop
    result = utils.RunCmd(["lvremove", "-f", "%s/%s" %
569 a8083063 Iustin Pop
                           (self._vg_name, self._lv_name)])
570 a8083063 Iustin Pop
    if result.failed:
571 0c6c04ec Iustin Pop
      _ThrowError("Can't lvremove: %s - %s", result.fail_reason, result.output)
572 a8083063 Iustin Pop
573 f3e513ad Iustin Pop
  def Rename(self, new_id):
574 f3e513ad Iustin Pop
    """Rename this logical volume.
575 f3e513ad Iustin Pop

576 f3e513ad Iustin Pop
    """
577 f3e513ad Iustin Pop
    if not isinstance(new_id, (tuple, list)) or len(new_id) != 2:
578 f3e513ad Iustin Pop
      raise errors.ProgrammerError("Invalid new logical id '%s'" % new_id)
579 f3e513ad Iustin Pop
    new_vg, new_name = new_id
580 f3e513ad Iustin Pop
    if new_vg != self._vg_name:
581 f3e513ad Iustin Pop
      raise errors.ProgrammerError("Can't move a logical volume across"
582 f3e513ad Iustin Pop
                                   " volume groups (from %s to to %s)" %
583 f3e513ad Iustin Pop
                                   (self._vg_name, new_vg))
584 f3e513ad Iustin Pop
    result = utils.RunCmd(["lvrename", new_vg, self._lv_name, new_name])
585 f3e513ad Iustin Pop
    if result.failed:
586 82463074 Iustin Pop
      _ThrowError("Failed to rename the logical volume: %s", result.output)
587 be345db0 Iustin Pop
    self._lv_name = new_name
588 6136f8f0 Iustin Pop
    self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
589 be345db0 Iustin Pop
590 a8083063 Iustin Pop
  def Attach(self):
591 a8083063 Iustin Pop
    """Attach to an existing LV.
592 a8083063 Iustin Pop

593 a8083063 Iustin Pop
    This method will try to see if an existing and active LV exists
594 c99a3cc0 Manuel Franceschini
    which matches our name. If so, its major/minor will be
595 a8083063 Iustin Pop
    recorded.
596 a8083063 Iustin Pop

597 a8083063 Iustin Pop
    """
598 cb999543 Iustin Pop
    self.attached = False
599 99e8295c Iustin Pop
    result = utils.RunCmd(["lvs", "--noheadings", "--separator=,",
600 38256320 Iustin Pop
                           "--units=m", "--nosuffix",
601 38256320 Iustin Pop
                           "-olv_attr,lv_kernel_major,lv_kernel_minor,"
602 38256320 Iustin Pop
                           "vg_extent_size,stripes", self.dev_path])
603 a8083063 Iustin Pop
    if result.failed:
604 468c5f77 Iustin Pop
      logging.error("Can't find LV %s: %s, %s",
605 468c5f77 Iustin Pop
                    self.dev_path, result.fail_reason, result.output)
606 a8083063 Iustin Pop
      return False
607 38256320 Iustin Pop
    # the output can (and will) have multiple lines for multi-segment
608 38256320 Iustin Pop
    # LVs, as the 'stripes' parameter is a segment one, so we take
609 38256320 Iustin Pop
    # only the last entry, which is the one we're interested in; note
610 38256320 Iustin Pop
    # that with LVM2 anyway the 'stripes' value must be constant
611 38256320 Iustin Pop
    # across segments, so this is a no-op actually
612 38256320 Iustin Pop
    out = result.stdout.splitlines()
613 38256320 Iustin Pop
    if not out: # totally empty result? splitlines() returns at least
614 38256320 Iustin Pop
                # one line for any non-empty string
615 38256320 Iustin Pop
      logging.error("Can't parse LVS output, no lines? Got '%s'", str(out))
616 38256320 Iustin Pop
      return False
617 d0c8c01d Iustin Pop
    out = out[-1].strip().rstrip(",")
618 99e8295c Iustin Pop
    out = out.split(",")
619 38256320 Iustin Pop
    if len(out) != 5:
620 38256320 Iustin Pop
      logging.error("Can't parse LVS output, len(%s) != 5", str(out))
621 99e8295c Iustin Pop
      return False
622 99e8295c Iustin Pop
623 38256320 Iustin Pop
    status, major, minor, pe_size, stripes = out
624 0304f0ec Iustin Pop
    if len(status) < 6:
625 0304f0ec Iustin Pop
      logging.error("lvs lv_attr is not at least 6 characters (%s)", status)
626 99e8295c Iustin Pop
      return False
627 99e8295c Iustin Pop
628 99e8295c Iustin Pop
    try:
629 99e8295c Iustin Pop
      major = int(major)
630 99e8295c Iustin Pop
      minor = int(minor)
631 691744c4 Iustin Pop
    except (TypeError, ValueError), err:
632 468c5f77 Iustin Pop
      logging.error("lvs major/minor cannot be parsed: %s", str(err))
633 99e8295c Iustin Pop
634 38256320 Iustin Pop
    try:
635 38256320 Iustin Pop
      pe_size = int(float(pe_size))
636 38256320 Iustin Pop
    except (TypeError, ValueError), err:
637 38256320 Iustin Pop
      logging.error("Can't parse vg extent size: %s", err)
638 38256320 Iustin Pop
      return False
639 38256320 Iustin Pop
640 38256320 Iustin Pop
    try:
641 38256320 Iustin Pop
      stripes = int(stripes)
642 38256320 Iustin Pop
    except (TypeError, ValueError), err:
643 38256320 Iustin Pop
      logging.error("Can't parse the number of stripes: %s", err)
644 38256320 Iustin Pop
      return False
645 38256320 Iustin Pop
646 99e8295c Iustin Pop
    self.major = major
647 99e8295c Iustin Pop
    self.minor = minor
648 38256320 Iustin Pop
    self.pe_size = pe_size
649 38256320 Iustin Pop
    self.stripe_count = stripes
650 d0c8c01d Iustin Pop
    self._degraded = status[0] == "v" # virtual volume, i.e. doesn't backing
651 99e8295c Iustin Pop
                                      # storage
652 cb999543 Iustin Pop
    self.attached = True
653 99e8295c Iustin Pop
    return True
654 a8083063 Iustin Pop
655 a8083063 Iustin Pop
  def Assemble(self):
656 a8083063 Iustin Pop
    """Assemble the device.
657 a8083063 Iustin Pop

658 5bbd3f7f Michael Hanselmann
    We always run `lvchange -ay` on the LV to ensure it's active before
659 5574047a Iustin Pop
    use, as there were cases when xenvg was not active after boot
660 5574047a Iustin Pop
    (also possibly after disk issues).
661 a8083063 Iustin Pop

662 a8083063 Iustin Pop
    """
663 5574047a Iustin Pop
    result = utils.RunCmd(["lvchange", "-ay", self.dev_path])
664 5574047a Iustin Pop
    if result.failed:
665 1063abd1 Iustin Pop
      _ThrowError("Can't activate lv %s: %s", self.dev_path, result.output)
666 a8083063 Iustin Pop
667 a8083063 Iustin Pop
  def Shutdown(self):
668 a8083063 Iustin Pop
    """Shutdown the device.
669 a8083063 Iustin Pop

670 a8083063 Iustin Pop
    This is a no-op for the LV device type, as we don't deactivate the
671 a8083063 Iustin Pop
    volumes on shutdown.
672 a8083063 Iustin Pop

673 a8083063 Iustin Pop
    """
674 746f7476 Iustin Pop
    pass
675 a8083063 Iustin Pop
676 9db6dbce Iustin Pop
  def GetSyncStatus(self):
677 9db6dbce Iustin Pop
    """Returns the sync status of the device.
678 9db6dbce Iustin Pop

679 9db6dbce Iustin Pop
    If this device is a mirroring device, this function returns the
680 9db6dbce Iustin Pop
    status of the mirror.
681 9db6dbce Iustin Pop

682 9db6dbce Iustin Pop
    For logical volumes, sync_percent and estimated_time are always
683 9db6dbce Iustin Pop
    None (no recovery in progress, as we don't handle the mirrored LV
684 0834c866 Iustin Pop
    case). The is_degraded parameter is the inverse of the ldisk
685 0834c866 Iustin Pop
    parameter.
686 9db6dbce Iustin Pop

687 0834c866 Iustin Pop
    For the ldisk parameter, we check if the logical volume has the
688 0834c866 Iustin Pop
    'virtual' type, which means it's not backed by existing storage
689 0834c866 Iustin Pop
    anymore (read from it return I/O error). This happens after a
690 0834c866 Iustin Pop
    physical disk failure and subsequent 'vgreduce --removemissing' on
691 0834c866 Iustin Pop
    the volume group.
692 9db6dbce Iustin Pop

693 99e8295c Iustin Pop
    The status was already read in Attach, so we just return it.
694 99e8295c Iustin Pop

695 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
696 c41eea6e Iustin Pop

697 9db6dbce Iustin Pop
    """
698 f208978a Michael Hanselmann
    if self._degraded:
699 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_FAULTY
700 f208978a Michael Hanselmann
    else:
701 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_OKAY
702 f208978a Michael Hanselmann
703 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
704 96acbc09 Michael Hanselmann
                                  major=self.major,
705 96acbc09 Michael Hanselmann
                                  minor=self.minor,
706 96acbc09 Michael Hanselmann
                                  sync_percent=None,
707 96acbc09 Michael Hanselmann
                                  estimated_time=None,
708 96acbc09 Michael Hanselmann
                                  is_degraded=self._degraded,
709 f208978a Michael Hanselmann
                                  ldisk_status=ldisk_status)
710 9db6dbce Iustin Pop
711 a8083063 Iustin Pop
  def Open(self, force=False):
712 a8083063 Iustin Pop
    """Make the device ready for I/O.
713 a8083063 Iustin Pop

714 a8083063 Iustin Pop
    This is a no-op for the LV device type.
715 a8083063 Iustin Pop

716 a8083063 Iustin Pop
    """
717 fdbd668d Iustin Pop
    pass
718 a8083063 Iustin Pop
719 a8083063 Iustin Pop
  def Close(self):
720 a8083063 Iustin Pop
    """Notifies that the device will no longer be used for I/O.
721 a8083063 Iustin Pop

722 a8083063 Iustin Pop
    This is a no-op for the LV device type.
723 a8083063 Iustin Pop

724 a8083063 Iustin Pop
    """
725 fdbd668d Iustin Pop
    pass
726 a8083063 Iustin Pop
727 a8083063 Iustin Pop
  def Snapshot(self, size):
728 a8083063 Iustin Pop
    """Create a snapshot copy of an lvm block device.
729 a8083063 Iustin Pop

730 800ac399 Iustin Pop
    @returns: tuple (vg, lv)
731 800ac399 Iustin Pop

732 a8083063 Iustin Pop
    """
733 a8083063 Iustin Pop
    snap_name = self._lv_name + ".snap"
734 a8083063 Iustin Pop
735 a8083063 Iustin Pop
    # remove existing snapshot if found
736 94dcbdb0 Andrea Spadaccini
    snap = LogicalVolume((self._vg_name, snap_name), None, size, self.params)
737 0c6c04ec Iustin Pop
    _IgnoreError(snap.Remove)
738 a8083063 Iustin Pop
739 197478f2 René Nussbaumer
    vg_info = self.GetVGInfo([self._vg_name])
740 197478f2 René Nussbaumer
    if not vg_info:
741 197478f2 René Nussbaumer
      _ThrowError("Can't compute VG info for vg %s", self._vg_name)
742 673cd9c4 René Nussbaumer
    free_size, _, _ = vg_info[0]
743 a8083063 Iustin Pop
    if free_size < size:
744 82463074 Iustin Pop
      _ThrowError("Not enough free space: required %s,"
745 82463074 Iustin Pop
                  " available %s", size, free_size)
746 a8083063 Iustin Pop
747 a8083063 Iustin Pop
    result = utils.RunCmd(["lvcreate", "-L%dm" % size, "-s",
748 a8083063 Iustin Pop
                           "-n%s" % snap_name, self.dev_path])
749 a8083063 Iustin Pop
    if result.failed:
750 82463074 Iustin Pop
      _ThrowError("command: %s error: %s - %s",
751 82463074 Iustin Pop
                  result.cmd, result.fail_reason, result.output)
752 a8083063 Iustin Pop
753 800ac399 Iustin Pop
    return (self._vg_name, snap_name)
754 a8083063 Iustin Pop
755 a0c3fea1 Michael Hanselmann
  def SetInfo(self, text):
756 a0c3fea1 Michael Hanselmann
    """Update metadata with info text.
757 a0c3fea1 Michael Hanselmann

758 a0c3fea1 Michael Hanselmann
    """
759 a0c3fea1 Michael Hanselmann
    BlockDev.SetInfo(self, text)
760 a0c3fea1 Michael Hanselmann
761 a0c3fea1 Michael Hanselmann
    # Replace invalid characters
762 d0c8c01d Iustin Pop
    text = re.sub("^[^A-Za-z0-9_+.]", "_", text)
763 d0c8c01d Iustin Pop
    text = re.sub("[^-A-Za-z0-9_+.]", "_", text)
764 a0c3fea1 Michael Hanselmann
765 a0c3fea1 Michael Hanselmann
    # Only up to 128 characters are allowed
766 a0c3fea1 Michael Hanselmann
    text = text[:128]
767 a0c3fea1 Michael Hanselmann
768 a0c3fea1 Michael Hanselmann
    result = utils.RunCmd(["lvchange", "--addtag", text,
769 a0c3fea1 Michael Hanselmann
                           self.dev_path])
770 a0c3fea1 Michael Hanselmann
    if result.failed:
771 82463074 Iustin Pop
      _ThrowError("Command: %s error: %s - %s", result.cmd, result.fail_reason,
772 82463074 Iustin Pop
                  result.output)
773 82463074 Iustin Pop
774 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
775 1005d816 Iustin Pop
    """Grow the logical volume.
776 1005d816 Iustin Pop

777 1005d816 Iustin Pop
    """
778 cad0723b Iustin Pop
    if not backingstore:
779 cad0723b Iustin Pop
      return
780 38256320 Iustin Pop
    if self.pe_size is None or self.stripe_count is None:
781 38256320 Iustin Pop
      if not self.Attach():
782 38256320 Iustin Pop
        _ThrowError("Can't attach to LV during Grow()")
783 38256320 Iustin Pop
    full_stripe_size = self.pe_size * self.stripe_count
784 38256320 Iustin Pop
    rest = amount % full_stripe_size
785 38256320 Iustin Pop
    if rest != 0:
786 38256320 Iustin Pop
      amount += full_stripe_size - rest
787 7fe23d47 Iustin Pop
    cmd = ["lvextend", "-L", "+%dm" % amount]
788 7fe23d47 Iustin Pop
    if dryrun:
789 7fe23d47 Iustin Pop
      cmd.append("--test")
790 1005d816 Iustin Pop
    # we try multiple algorithms since the 'best' ones might not have
791 1005d816 Iustin Pop
    # space available in the right place, but later ones might (since
792 1005d816 Iustin Pop
    # they have less constraints); also note that only recent LVM
793 1005d816 Iustin Pop
    # supports 'cling'
794 1005d816 Iustin Pop
    for alloc_policy in "contiguous", "cling", "normal":
795 7fe23d47 Iustin Pop
      result = utils.RunCmd(cmd + ["--alloc", alloc_policy, self.dev_path])
796 1005d816 Iustin Pop
      if not result.failed:
797 1005d816 Iustin Pop
        return
798 82463074 Iustin Pop
    _ThrowError("Can't grow LV %s: %s", self.dev_path, result.output)
799 a0c3fea1 Michael Hanselmann
800 a0c3fea1 Michael Hanselmann
801 6b90c22e Iustin Pop
class DRBD8Status(object):
802 6b90c22e Iustin Pop
  """A DRBD status representation class.
803 6b90c22e Iustin Pop

804 6b90c22e Iustin Pop
  Note that this doesn't support unconfigured devices (cs:Unconfigured).
805 6b90c22e Iustin Pop

806 6b90c22e Iustin Pop
  """
807 767d52d3 Iustin Pop
  UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$")
808 01e2ce3a Iustin Pop
  LINE_RE = re.compile(r"\s*[0-9]+:\s*cs:(\S+)\s+(?:st|ro):([^/]+)/(\S+)"
809 6b90c22e Iustin Pop
                       "\s+ds:([^/]+)/(\S+)\s+.*$")
810 6b90c22e Iustin Pop
  SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*"
811 7a380ddf René Nussbaumer
                       # Due to a bug in drbd in the kernel, introduced in
812 7a380ddf René Nussbaumer
                       # commit 4b0715f096 (still unfixed as of 2011-08-22)
813 7a380ddf René Nussbaumer
                       "(?:\s|M)"
814 7a380ddf René Nussbaumer
                       "finish: ([0-9]+):([0-9]+):([0-9]+)\s.*$")
815 6b90c22e Iustin Pop
816 3c003d9d Iustin Pop
  CS_UNCONFIGURED = "Unconfigured"
817 3c003d9d Iustin Pop
  CS_STANDALONE = "StandAlone"
818 3c003d9d Iustin Pop
  CS_WFCONNECTION = "WFConnection"
819 3c003d9d Iustin Pop
  CS_WFREPORTPARAMS = "WFReportParams"
820 3c003d9d Iustin Pop
  CS_CONNECTED = "Connected"
821 3c003d9d Iustin Pop
  CS_STARTINGSYNCS = "StartingSyncS"
822 3c003d9d Iustin Pop
  CS_STARTINGSYNCT = "StartingSyncT"
823 3c003d9d Iustin Pop
  CS_WFBITMAPS = "WFBitMapS"
824 3c003d9d Iustin Pop
  CS_WFBITMAPT = "WFBitMapT"
825 3c003d9d Iustin Pop
  CS_WFSYNCUUID = "WFSyncUUID"
826 3c003d9d Iustin Pop
  CS_SYNCSOURCE = "SyncSource"
827 3c003d9d Iustin Pop
  CS_SYNCTARGET = "SyncTarget"
828 3c003d9d Iustin Pop
  CS_PAUSEDSYNCS = "PausedSyncS"
829 3c003d9d Iustin Pop
  CS_PAUSEDSYNCT = "PausedSyncT"
830 3c003d9d Iustin Pop
  CSET_SYNC = frozenset([
831 3c003d9d Iustin Pop
    CS_WFREPORTPARAMS,
832 3c003d9d Iustin Pop
    CS_STARTINGSYNCS,
833 3c003d9d Iustin Pop
    CS_STARTINGSYNCT,
834 3c003d9d Iustin Pop
    CS_WFBITMAPS,
835 3c003d9d Iustin Pop
    CS_WFBITMAPT,
836 3c003d9d Iustin Pop
    CS_WFSYNCUUID,
837 3c003d9d Iustin Pop
    CS_SYNCSOURCE,
838 3c003d9d Iustin Pop
    CS_SYNCTARGET,
839 3c003d9d Iustin Pop
    CS_PAUSEDSYNCS,
840 3c003d9d Iustin Pop
    CS_PAUSEDSYNCT,
841 3c003d9d Iustin Pop
    ])
842 3c003d9d Iustin Pop
843 3c003d9d Iustin Pop
  DS_DISKLESS = "Diskless"
844 3c003d9d Iustin Pop
  DS_ATTACHING = "Attaching" # transient state
845 3c003d9d Iustin Pop
  DS_FAILED = "Failed" # transient state, next: diskless
846 3c003d9d Iustin Pop
  DS_NEGOTIATING = "Negotiating" # transient state
847 3c003d9d Iustin Pop
  DS_INCONSISTENT = "Inconsistent" # while syncing or after creation
848 3c003d9d Iustin Pop
  DS_OUTDATED = "Outdated"
849 3c003d9d Iustin Pop
  DS_DUNKNOWN = "DUnknown" # shown for peer disk when not connected
850 3c003d9d Iustin Pop
  DS_CONSISTENT = "Consistent"
851 3c003d9d Iustin Pop
  DS_UPTODATE = "UpToDate" # normal state
852 3c003d9d Iustin Pop
853 3c003d9d Iustin Pop
  RO_PRIMARY = "Primary"
854 3c003d9d Iustin Pop
  RO_SECONDARY = "Secondary"
855 3c003d9d Iustin Pop
  RO_UNKNOWN = "Unknown"
856 3c003d9d Iustin Pop
857 6b90c22e Iustin Pop
  def __init__(self, procline):
858 767d52d3 Iustin Pop
    u = self.UNCONF_RE.match(procline)
859 767d52d3 Iustin Pop
    if u:
860 3c003d9d Iustin Pop
      self.cstatus = self.CS_UNCONFIGURED
861 767d52d3 Iustin Pop
      self.lrole = self.rrole = self.ldisk = self.rdisk = None
862 767d52d3 Iustin Pop
    else:
863 767d52d3 Iustin Pop
      m = self.LINE_RE.match(procline)
864 767d52d3 Iustin Pop
      if not m:
865 767d52d3 Iustin Pop
        raise errors.BlockDeviceError("Can't parse input data '%s'" % procline)
866 767d52d3 Iustin Pop
      self.cstatus = m.group(1)
867 767d52d3 Iustin Pop
      self.lrole = m.group(2)
868 767d52d3 Iustin Pop
      self.rrole = m.group(3)
869 767d52d3 Iustin Pop
      self.ldisk = m.group(4)
870 767d52d3 Iustin Pop
      self.rdisk = m.group(5)
871 767d52d3 Iustin Pop
872 767d52d3 Iustin Pop
    # end reading of data from the LINE_RE or UNCONF_RE
873 6b90c22e Iustin Pop
874 3c003d9d Iustin Pop
    self.is_standalone = self.cstatus == self.CS_STANDALONE
875 3c003d9d Iustin Pop
    self.is_wfconn = self.cstatus == self.CS_WFCONNECTION
876 3c003d9d Iustin Pop
    self.is_connected = self.cstatus == self.CS_CONNECTED
877 3c003d9d Iustin Pop
    self.is_primary = self.lrole == self.RO_PRIMARY
878 3c003d9d Iustin Pop
    self.is_secondary = self.lrole == self.RO_SECONDARY
879 3c003d9d Iustin Pop
    self.peer_primary = self.rrole == self.RO_PRIMARY
880 3c003d9d Iustin Pop
    self.peer_secondary = self.rrole == self.RO_SECONDARY
881 6b90c22e Iustin Pop
    self.both_primary = self.is_primary and self.peer_primary
882 6b90c22e Iustin Pop
    self.both_secondary = self.is_secondary and self.peer_secondary
883 6b90c22e Iustin Pop
884 3c003d9d Iustin Pop
    self.is_diskless = self.ldisk == self.DS_DISKLESS
885 3c003d9d Iustin Pop
    self.is_disk_uptodate = self.ldisk == self.DS_UPTODATE
886 6b90c22e Iustin Pop
887 3c003d9d Iustin Pop
    self.is_in_resync = self.cstatus in self.CSET_SYNC
888 3c003d9d Iustin Pop
    self.is_in_use = self.cstatus != self.CS_UNCONFIGURED
889 6b93ec9d Iustin Pop
890 6b90c22e Iustin Pop
    m = self.SYNC_RE.match(procline)
891 6b90c22e Iustin Pop
    if m:
892 6b90c22e Iustin Pop
      self.sync_percent = float(m.group(1))
893 6b90c22e Iustin Pop
      hours = int(m.group(2))
894 6b90c22e Iustin Pop
      minutes = int(m.group(3))
895 6b90c22e Iustin Pop
      seconds = int(m.group(4))
896 6b90c22e Iustin Pop
      self.est_time = hours * 3600 + minutes * 60 + seconds
897 6b90c22e Iustin Pop
    else:
898 3c003d9d Iustin Pop
      # we have (in this if branch) no percent information, but if
899 3c003d9d Iustin Pop
      # we're resyncing we need to 'fake' a sync percent information,
900 3c003d9d Iustin Pop
      # as this is how cmdlib determines if it makes sense to wait for
901 3c003d9d Iustin Pop
      # resyncing or not
902 3c003d9d Iustin Pop
      if self.is_in_resync:
903 3c003d9d Iustin Pop
        self.sync_percent = 0
904 3c003d9d Iustin Pop
      else:
905 3c003d9d Iustin Pop
        self.sync_percent = None
906 6b90c22e Iustin Pop
      self.est_time = None
907 6b90c22e Iustin Pop
908 6b90c22e Iustin Pop
909 b459a848 Andrea Spadaccini
class BaseDRBD(BlockDev): # pylint: disable=W0223
910 0f7f32d9 Iustin Pop
  """Base DRBD class.
911 a8083063 Iustin Pop

912 0f7f32d9 Iustin Pop
  This class contains a few bits of common functionality between the
913 0f7f32d9 Iustin Pop
  0.7 and 8.x versions of DRBD.
914 0f7f32d9 Iustin Pop

915 abdf0113 Iustin Pop
  """
916 fcee765d Manuel Franceschini
  _VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.\d+)?"
917 abdf0113 Iustin Pop
                           r" \(api:(\d+)/proto:(\d+)(?:-(\d+))?\)")
918 9122e60a Iustin Pop
  _VALID_LINE_RE = re.compile("^ *([0-9]+): cs:([^ ]+).*$")
919 9122e60a Iustin Pop
  _UNUSED_LINE_RE = re.compile("^ *([0-9]+): cs:Unconfigured$")
920 a8083063 Iustin Pop
921 abdf0113 Iustin Pop
  _DRBD_MAJOR = 147
922 abdf0113 Iustin Pop
  _ST_UNCONFIGURED = "Unconfigured"
923 abdf0113 Iustin Pop
  _ST_WFCONNECTION = "WFConnection"
924 abdf0113 Iustin Pop
  _ST_CONNECTED = "Connected"
925 a8083063 Iustin Pop
926 6b90c22e Iustin Pop
  _STATUS_FILE = "/proc/drbd"
927 549071a0 Luca Bigliardi
  _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
928 6b90c22e Iustin Pop
929 abdf0113 Iustin Pop
  @staticmethod
930 6b90c22e Iustin Pop
  def _GetProcData(filename=_STATUS_FILE):
931 abdf0113 Iustin Pop
    """Return data from /proc/drbd.
932 a8083063 Iustin Pop

933 a8083063 Iustin Pop
    """
934 abdf0113 Iustin Pop
    try:
935 13998ef2 Michael Hanselmann
      data = utils.ReadFile(filename).splitlines()
936 f6eaed12 Iustin Pop
    except EnvironmentError, err:
937 f6eaed12 Iustin Pop
      if err.errno == errno.ENOENT:
938 f6eaed12 Iustin Pop
        _ThrowError("The file %s cannot be opened, check if the module"
939 f6eaed12 Iustin Pop
                    " is loaded (%s)", filename, str(err))
940 f6eaed12 Iustin Pop
      else:
941 f6eaed12 Iustin Pop
        _ThrowError("Can't read the DRBD proc file %s: %s", filename, str(err))
942 abdf0113 Iustin Pop
    if not data:
943 82463074 Iustin Pop
      _ThrowError("Can't read any data from %s", filename)
944 abdf0113 Iustin Pop
    return data
945 a8083063 Iustin Pop
946 9122e60a Iustin Pop
  @classmethod
947 9122e60a Iustin Pop
  def _MassageProcData(cls, data):
948 abdf0113 Iustin Pop
    """Transform the output of _GetProdData into a nicer form.
949 a8083063 Iustin Pop

950 c41eea6e Iustin Pop
    @return: a dictionary of minor: joined lines from /proc/drbd
951 c41eea6e Iustin Pop
        for that minor
952 a8083063 Iustin Pop

953 a8083063 Iustin Pop
    """
954 abdf0113 Iustin Pop
    results = {}
955 abdf0113 Iustin Pop
    old_minor = old_line = None
956 abdf0113 Iustin Pop
    for line in data:
957 67d101d4 Iustin Pop
      if not line: # completely empty lines, as can be returned by drbd8.0+
958 67d101d4 Iustin Pop
        continue
959 9122e60a Iustin Pop
      lresult = cls._VALID_LINE_RE.match(line)
960 abdf0113 Iustin Pop
      if lresult is not None:
961 abdf0113 Iustin Pop
        if old_minor is not None:
962 abdf0113 Iustin Pop
          results[old_minor] = old_line
963 abdf0113 Iustin Pop
        old_minor = int(lresult.group(1))
964 abdf0113 Iustin Pop
        old_line = line
965 abdf0113 Iustin Pop
      else:
966 abdf0113 Iustin Pop
        if old_minor is not None:
967 abdf0113 Iustin Pop
          old_line += " " + line.strip()
968 abdf0113 Iustin Pop
    # add last line
969 abdf0113 Iustin Pop
    if old_minor is not None:
970 abdf0113 Iustin Pop
      results[old_minor] = old_line
971 abdf0113 Iustin Pop
    return results
972 a8083063 Iustin Pop
973 abdf0113 Iustin Pop
  @classmethod
974 fcee765d Manuel Franceschini
  def _GetVersion(cls, proc_data):
975 abdf0113 Iustin Pop
    """Return the DRBD version.
976 a8083063 Iustin Pop

977 abdf0113 Iustin Pop
    This will return a dict with keys:
978 c41eea6e Iustin Pop
      - k_major
979 c41eea6e Iustin Pop
      - k_minor
980 c41eea6e Iustin Pop
      - k_point
981 c41eea6e Iustin Pop
      - api
982 c41eea6e Iustin Pop
      - proto
983 c41eea6e Iustin Pop
      - proto2 (only on drbd > 8.2.X)
984 a8083063 Iustin Pop

985 a8083063 Iustin Pop
    """
986 abdf0113 Iustin Pop
    first_line = proc_data[0].strip()
987 abdf0113 Iustin Pop
    version = cls._VERSION_RE.match(first_line)
988 abdf0113 Iustin Pop
    if not version:
989 abdf0113 Iustin Pop
      raise errors.BlockDeviceError("Can't parse DRBD version from '%s'" %
990 abdf0113 Iustin Pop
                                    first_line)
991 a8083063 Iustin Pop
992 abdf0113 Iustin Pop
    values = version.groups()
993 5ae4945a Iustin Pop
    retval = {
994 5ae4945a Iustin Pop
      "k_major": int(values[0]),
995 5ae4945a Iustin Pop
      "k_minor": int(values[1]),
996 5ae4945a Iustin Pop
      "k_point": int(values[2]),
997 5ae4945a Iustin Pop
      "api": int(values[3]),
998 5ae4945a Iustin Pop
      "proto": int(values[4]),
999 5ae4945a Iustin Pop
      }
1000 abdf0113 Iustin Pop
    if values[5] is not None:
1001 d0c8c01d Iustin Pop
      retval["proto2"] = values[5]
1002 a8083063 Iustin Pop
1003 abdf0113 Iustin Pop
    return retval
1004 abdf0113 Iustin Pop
1005 abdf0113 Iustin Pop
  @staticmethod
1006 549071a0 Luca Bigliardi
  def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE):
1007 549071a0 Luca Bigliardi
    """Returns DRBD usermode_helper currently set.
1008 549071a0 Luca Bigliardi

1009 549071a0 Luca Bigliardi
    """
1010 549071a0 Luca Bigliardi
    try:
1011 549071a0 Luca Bigliardi
      helper = utils.ReadFile(filename).splitlines()[0]
1012 549071a0 Luca Bigliardi
    except EnvironmentError, err:
1013 549071a0 Luca Bigliardi
      if err.errno == errno.ENOENT:
1014 549071a0 Luca Bigliardi
        _ThrowError("The file %s cannot be opened, check if the module"
1015 549071a0 Luca Bigliardi
                    " is loaded (%s)", filename, str(err))
1016 549071a0 Luca Bigliardi
      else:
1017 549071a0 Luca Bigliardi
        _ThrowError("Can't read DRBD helper file %s: %s", filename, str(err))
1018 549071a0 Luca Bigliardi
    if not helper:
1019 549071a0 Luca Bigliardi
      _ThrowError("Can't read any data from %s", filename)
1020 549071a0 Luca Bigliardi
    return helper
1021 549071a0 Luca Bigliardi
1022 549071a0 Luca Bigliardi
  @staticmethod
1023 abdf0113 Iustin Pop
  def _DevPath(minor):
1024 abdf0113 Iustin Pop
    """Return the path to a drbd device for a given minor.
1025 a8083063 Iustin Pop

1026 a8083063 Iustin Pop
    """
1027 abdf0113 Iustin Pop
    return "/dev/drbd%d" % minor
1028 a8083063 Iustin Pop
1029 abdf0113 Iustin Pop
  @classmethod
1030 6d2e83d5 Iustin Pop
  def GetUsedDevs(cls):
1031 abdf0113 Iustin Pop
    """Compute the list of used DRBD devices.
1032 a8083063 Iustin Pop

1033 a8083063 Iustin Pop
    """
1034 abdf0113 Iustin Pop
    data = cls._GetProcData()
1035 a8083063 Iustin Pop
1036 abdf0113 Iustin Pop
    used_devs = {}
1037 abdf0113 Iustin Pop
    for line in data:
1038 9122e60a Iustin Pop
      match = cls._VALID_LINE_RE.match(line)
1039 abdf0113 Iustin Pop
      if not match:
1040 abdf0113 Iustin Pop
        continue
1041 abdf0113 Iustin Pop
      minor = int(match.group(1))
1042 abdf0113 Iustin Pop
      state = match.group(2)
1043 abdf0113 Iustin Pop
      if state == cls._ST_UNCONFIGURED:
1044 abdf0113 Iustin Pop
        continue
1045 abdf0113 Iustin Pop
      used_devs[minor] = state, line
1046 a8083063 Iustin Pop
1047 abdf0113 Iustin Pop
    return used_devs
1048 a8083063 Iustin Pop
1049 abdf0113 Iustin Pop
  def _SetFromMinor(self, minor):
1050 abdf0113 Iustin Pop
    """Set our parameters based on the given minor.
1051 0834c866 Iustin Pop

1052 abdf0113 Iustin Pop
    This sets our minor variable and our dev_path.
1053 a8083063 Iustin Pop

1054 a8083063 Iustin Pop
    """
1055 abdf0113 Iustin Pop
    if minor is None:
1056 abdf0113 Iustin Pop
      self.minor = self.dev_path = None
1057 cb999543 Iustin Pop
      self.attached = False
1058 a8083063 Iustin Pop
    else:
1059 abdf0113 Iustin Pop
      self.minor = minor
1060 abdf0113 Iustin Pop
      self.dev_path = self._DevPath(minor)
1061 cb999543 Iustin Pop
      self.attached = True
1062 a8083063 Iustin Pop
1063 a8083063 Iustin Pop
  @staticmethod
1064 abdf0113 Iustin Pop
  def _CheckMetaSize(meta_device):
1065 abdf0113 Iustin Pop
    """Check if the given meta device looks like a valid one.
1066 a8083063 Iustin Pop

1067 3bc145d8 Bernardo Dal Seno
    This currently only checks the size, which must be around
1068 abdf0113 Iustin Pop
    128MiB.
1069 a8083063 Iustin Pop

1070 a8083063 Iustin Pop
    """
1071 abdf0113 Iustin Pop
    result = utils.RunCmd(["blockdev", "--getsize", meta_device])
1072 abdf0113 Iustin Pop
    if result.failed:
1073 9c793cfb Iustin Pop
      _ThrowError("Failed to get device size: %s - %s",
1074 9c793cfb Iustin Pop
                  result.fail_reason, result.output)
1075 a8083063 Iustin Pop
    try:
1076 abdf0113 Iustin Pop
      sectors = int(result.stdout)
1077 691744c4 Iustin Pop
    except (TypeError, ValueError):
1078 9c793cfb Iustin Pop
      _ThrowError("Invalid output from blockdev: '%s'", result.stdout)
1079 c04bc777 Iustin Pop
    num_bytes = sectors * 512
1080 c04bc777 Iustin Pop
    if num_bytes < 128 * 1024 * 1024: # less than 128MiB
1081 c04bc777 Iustin Pop
      _ThrowError("Meta device too small (%.2fMib)", (num_bytes / 1024 / 1024))
1082 1dc10972 Iustin Pop
    # the maximum *valid* size of the meta device when living on top
1083 1dc10972 Iustin Pop
    # of LVM is hard to compute: it depends on the number of stripes
1084 1dc10972 Iustin Pop
    # and the PE size; e.g. a 2-stripe, 64MB PE will result in a 128MB
1085 1dc10972 Iustin Pop
    # (normal size), but an eight-stripe 128MB PE will result in a 1GB
1086 1dc10972 Iustin Pop
    # size meta device; as such, we restrict it to 1GB (a little bit
1087 1dc10972 Iustin Pop
    # too generous, but making assumptions about PE size is hard)
1088 c04bc777 Iustin Pop
    if num_bytes > 1024 * 1024 * 1024:
1089 c04bc777 Iustin Pop
      _ThrowError("Meta device too big (%.2fMiB)", (num_bytes / 1024 / 1024))
1090 a8083063 Iustin Pop
1091 abdf0113 Iustin Pop
  def Rename(self, new_id):
1092 abdf0113 Iustin Pop
    """Rename a device.
1093 a8083063 Iustin Pop

1094 abdf0113 Iustin Pop
    This is not supported for drbd devices.
1095 a8083063 Iustin Pop

1096 a8083063 Iustin Pop
    """
1097 abdf0113 Iustin Pop
    raise errors.ProgrammerError("Can't rename a drbd device")
1098 a8083063 Iustin Pop
1099 f3e513ad Iustin Pop
1100 a2cfdea2 Iustin Pop
class DRBD8(BaseDRBD):
1101 a2cfdea2 Iustin Pop
  """DRBD v8.x block device.
1102 a2cfdea2 Iustin Pop

1103 a2cfdea2 Iustin Pop
  This implements the local host part of the DRBD device, i.e. it
1104 a2cfdea2 Iustin Pop
  doesn't do anything to the supposed peer. If you need a fully
1105 a2cfdea2 Iustin Pop
  connected DRBD pair, you need to use this class on both hosts.
1106 a2cfdea2 Iustin Pop

1107 5c755a4d Iustin Pop
  The unique_id for the drbd device is a (local_ip, local_port,
1108 5c755a4d Iustin Pop
  remote_ip, remote_port, local_minor, secret) tuple, and it must have
1109 5c755a4d Iustin Pop
  two children: the data device and the meta_device. The meta device
1110 5c755a4d Iustin Pop
  is checked for valid size and is zeroed on create.
1111 a2cfdea2 Iustin Pop

1112 a2cfdea2 Iustin Pop
  """
1113 a2cfdea2 Iustin Pop
  _MAX_MINORS = 255
1114 a2cfdea2 Iustin Pop
  _PARSE_SHOW = None
1115 a2cfdea2 Iustin Pop
1116 cf8df3f3 Iustin Pop
  # timeout constants
1117 cf8df3f3 Iustin Pop
  _NET_RECONFIG_TIMEOUT = 60
1118 cf8df3f3 Iustin Pop
1119 8a69b3a8 Andrea Spadaccini
  # command line options for barriers
1120 8a69b3a8 Andrea Spadaccini
  _DISABLE_DISK_OPTION = "--no-disk-barrier"  # -a
1121 8a69b3a8 Andrea Spadaccini
  _DISABLE_DRAIN_OPTION = "--no-disk-drain"   # -D
1122 8a69b3a8 Andrea Spadaccini
  _DISABLE_FLUSH_OPTION = "--no-disk-flushes" # -i
1123 8a69b3a8 Andrea Spadaccini
  _DISABLE_META_FLUSH_OPTION = "--no-md-flushes"  # -m
1124 8a69b3a8 Andrea Spadaccini
1125 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
1126 fc1dc9d7 Iustin Pop
    if children and children.count(None) > 0:
1127 fc1dc9d7 Iustin Pop
      children = []
1128 310fbb64 Iustin Pop
    if len(children) not in (0, 2):
1129 310fbb64 Iustin Pop
      raise ValueError("Invalid configuration data %s" % str(children))
1130 310fbb64 Iustin Pop
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 6:
1131 310fbb64 Iustin Pop
      raise ValueError("Invalid configuration data %s" % str(unique_id))
1132 310fbb64 Iustin Pop
    (self._lhost, self._lport,
1133 310fbb64 Iustin Pop
     self._rhost, self._rport,
1134 310fbb64 Iustin Pop
     self._aminor, self._secret) = unique_id
1135 310fbb64 Iustin Pop
    if children:
1136 310fbb64 Iustin Pop
      if not _CanReadDevice(children[1].dev_path):
1137 310fbb64 Iustin Pop
        logging.info("drbd%s: Ignoring unreadable meta device", self._aminor)
1138 310fbb64 Iustin Pop
        children = []
1139 94dcbdb0 Andrea Spadaccini
    super(DRBD8, self).__init__(unique_id, children, size, params)
1140 a2cfdea2 Iustin Pop
    self.major = self._DRBD_MAJOR
1141 fcee765d Manuel Franceschini
    version = self._GetVersion(self._GetProcData())
1142 e687ec01 Michael Hanselmann
    if version["k_major"] != 8:
1143 82463074 Iustin Pop
      _ThrowError("Mismatch in DRBD kernel version and requested ganeti"
1144 82463074 Iustin Pop
                  " usage: kernel is %s.%s, ganeti wants 8.x",
1145 d0c8c01d Iustin Pop
                  version["k_major"], version["k_minor"])
1146 a2cfdea2 Iustin Pop
1147 ffa1c0dc Iustin Pop
    if (self._lhost is not None and self._lhost == self._rhost and
1148 ffa1c0dc Iustin Pop
        self._lport == self._rport):
1149 ffa1c0dc Iustin Pop
      raise ValueError("Invalid configuration data, same local/remote %s" %
1150 ffa1c0dc Iustin Pop
                       (unique_id,))
1151 a2cfdea2 Iustin Pop
    self.Attach()
1152 a2cfdea2 Iustin Pop
1153 a2cfdea2 Iustin Pop
  @classmethod
1154 a2cfdea2 Iustin Pop
  def _InitMeta(cls, minor, dev_path):
1155 a2cfdea2 Iustin Pop
    """Initialize a meta device.
1156 a2cfdea2 Iustin Pop

1157 a2cfdea2 Iustin Pop
    This will not work if the given minor is in use.
1158 a2cfdea2 Iustin Pop

1159 a2cfdea2 Iustin Pop
    """
1160 18e4dee6 Iustin Pop
    # Zero the metadata first, in order to make sure drbdmeta doesn't
1161 18e4dee6 Iustin Pop
    # try to auto-detect existing filesystems or similar (see
1162 18e4dee6 Iustin Pop
    # http://code.google.com/p/ganeti/issues/detail?id=182); we only
1163 18e4dee6 Iustin Pop
    # care about the first 128MB of data in the device, even though it
1164 18e4dee6 Iustin Pop
    # can be bigger
1165 18e4dee6 Iustin Pop
    result = utils.RunCmd([constants.DD_CMD,
1166 18e4dee6 Iustin Pop
                           "if=/dev/zero", "of=%s" % dev_path,
1167 18e4dee6 Iustin Pop
                           "bs=1048576", "count=128", "oflag=direct"])
1168 18e4dee6 Iustin Pop
    if result.failed:
1169 18e4dee6 Iustin Pop
      _ThrowError("Can't wipe the meta device: %s", result.output)
1170 18e4dee6 Iustin Pop
1171 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdmeta", "--force", cls._DevPath(minor),
1172 a2cfdea2 Iustin Pop
                           "v08", dev_path, "0", "create-md"])
1173 a2cfdea2 Iustin Pop
    if result.failed:
1174 82463074 Iustin Pop
      _ThrowError("Can't initialize meta device: %s", result.output)
1175 a2cfdea2 Iustin Pop
1176 a2cfdea2 Iustin Pop
  @classmethod
1177 a2cfdea2 Iustin Pop
  def _FindUnusedMinor(cls):
1178 a2cfdea2 Iustin Pop
    """Find an unused DRBD device.
1179 a2cfdea2 Iustin Pop

1180 a2cfdea2 Iustin Pop
    This is specific to 8.x as the minors are allocated dynamically,
1181 a2cfdea2 Iustin Pop
    so non-existing numbers up to a max minor count are actually free.
1182 a2cfdea2 Iustin Pop

1183 a2cfdea2 Iustin Pop
    """
1184 a2cfdea2 Iustin Pop
    data = cls._GetProcData()
1185 a2cfdea2 Iustin Pop
1186 a2cfdea2 Iustin Pop
    highest = None
1187 a2cfdea2 Iustin Pop
    for line in data:
1188 9122e60a Iustin Pop
      match = cls._UNUSED_LINE_RE.match(line)
1189 a2cfdea2 Iustin Pop
      if match:
1190 a2cfdea2 Iustin Pop
        return int(match.group(1))
1191 9122e60a Iustin Pop
      match = cls._VALID_LINE_RE.match(line)
1192 a2cfdea2 Iustin Pop
      if match:
1193 a2cfdea2 Iustin Pop
        minor = int(match.group(1))
1194 a2cfdea2 Iustin Pop
        highest = max(highest, minor)
1195 a2cfdea2 Iustin Pop
    if highest is None: # there are no minors in use at all
1196 a2cfdea2 Iustin Pop
      return 0
1197 a2cfdea2 Iustin Pop
    if highest >= cls._MAX_MINORS:
1198 468c5f77 Iustin Pop
      logging.error("Error: no free drbd minors!")
1199 a2cfdea2 Iustin Pop
      raise errors.BlockDeviceError("Can't find a free DRBD minor")
1200 a2cfdea2 Iustin Pop
    return highest + 1
1201 a2cfdea2 Iustin Pop
1202 a2cfdea2 Iustin Pop
  @classmethod
1203 a2cfdea2 Iustin Pop
  def _GetShowParser(cls):
1204 a2cfdea2 Iustin Pop
    """Return a parser for `drbd show` output.
1205 a2cfdea2 Iustin Pop

1206 3bc145d8 Bernardo Dal Seno
    This will either create or return an already-created parser for the
1207 a2cfdea2 Iustin Pop
    output of the command `drbd show`.
1208 a2cfdea2 Iustin Pop

1209 a2cfdea2 Iustin Pop
    """
1210 a2cfdea2 Iustin Pop
    if cls._PARSE_SHOW is not None:
1211 a2cfdea2 Iustin Pop
      return cls._PARSE_SHOW
1212 a2cfdea2 Iustin Pop
1213 a2cfdea2 Iustin Pop
    # pyparsing setup
1214 a2cfdea2 Iustin Pop
    lbrace = pyp.Literal("{").suppress()
1215 a2cfdea2 Iustin Pop
    rbrace = pyp.Literal("}").suppress()
1216 5a672c30 Manuel Franceschini
    lbracket = pyp.Literal("[").suppress()
1217 5a672c30 Manuel Franceschini
    rbracket = pyp.Literal("]").suppress()
1218 a2cfdea2 Iustin Pop
    semi = pyp.Literal(";").suppress()
1219 5a672c30 Manuel Franceschini
    colon = pyp.Literal(":").suppress()
1220 a2cfdea2 Iustin Pop
    # this also converts the value to an int
1221 c522ea02 Iustin Pop
    number = pyp.Word(pyp.nums).setParseAction(lambda s, l, t: int(t[0]))
1222 a2cfdea2 Iustin Pop
1223 e687ec01 Michael Hanselmann
    comment = pyp.Literal("#") + pyp.Optional(pyp.restOfLine)
1224 a2cfdea2 Iustin Pop
    defa = pyp.Literal("_is_default").suppress()
1225 a2cfdea2 Iustin Pop
    dbl_quote = pyp.Literal('"').suppress()
1226 a2cfdea2 Iustin Pop
1227 3ccb3a64 Michael Hanselmann
    keyword = pyp.Word(pyp.alphanums + "-")
1228 a2cfdea2 Iustin Pop
1229 a2cfdea2 Iustin Pop
    # value types
1230 3ccb3a64 Michael Hanselmann
    value = pyp.Word(pyp.alphanums + "_-/.:")
1231 a2cfdea2 Iustin Pop
    quoted = dbl_quote + pyp.CharsNotIn('"') + dbl_quote
1232 5a672c30 Manuel Franceschini
    ipv4_addr = (pyp.Optional(pyp.Literal("ipv4")).suppress() +
1233 5a672c30 Manuel Franceschini
                 pyp.Word(pyp.nums + ".") + colon + number)
1234 5a672c30 Manuel Franceschini
    ipv6_addr = (pyp.Optional(pyp.Literal("ipv6")).suppress() +
1235 5a672c30 Manuel Franceschini
                 pyp.Optional(lbracket) + pyp.Word(pyp.hexnums + ":") +
1236 5a672c30 Manuel Franceschini
                 pyp.Optional(rbracket) + colon + number)
1237 a2cfdea2 Iustin Pop
    # meta device, extended syntax
1238 5a672c30 Manuel Franceschini
    meta_value = ((value ^ quoted) + lbracket + number + rbracket)
1239 01e2ce3a Iustin Pop
    # device name, extended syntax
1240 01e2ce3a Iustin Pop
    device_value = pyp.Literal("minor").suppress() + number
1241 a2cfdea2 Iustin Pop
1242 a2cfdea2 Iustin Pop
    # a statement
1243 a2cfdea2 Iustin Pop
    stmt = (~rbrace + keyword + ~lbrace +
1244 5a672c30 Manuel Franceschini
            pyp.Optional(ipv4_addr ^ ipv6_addr ^ value ^ quoted ^ meta_value ^
1245 01e2ce3a Iustin Pop
                         device_value) +
1246 a2cfdea2 Iustin Pop
            pyp.Optional(defa) + semi +
1247 a2cfdea2 Iustin Pop
            pyp.Optional(pyp.restOfLine).suppress())
1248 a2cfdea2 Iustin Pop
1249 a2cfdea2 Iustin Pop
    # an entire section
1250 d0c8c01d Iustin Pop
    section_name = pyp.Word(pyp.alphas + "_")
1251 a2cfdea2 Iustin Pop
    section = section_name + lbrace + pyp.ZeroOrMore(pyp.Group(stmt)) + rbrace
1252 a2cfdea2 Iustin Pop
1253 a2cfdea2 Iustin Pop
    bnf = pyp.ZeroOrMore(pyp.Group(section ^ stmt))
1254 a2cfdea2 Iustin Pop
    bnf.ignore(comment)
1255 a2cfdea2 Iustin Pop
1256 a2cfdea2 Iustin Pop
    cls._PARSE_SHOW = bnf
1257 a2cfdea2 Iustin Pop
1258 a2cfdea2 Iustin Pop
    return bnf
1259 a2cfdea2 Iustin Pop
1260 a2cfdea2 Iustin Pop
  @classmethod
1261 3840729d Iustin Pop
  def _GetShowData(cls, minor):
1262 3840729d Iustin Pop
    """Return the `drbdsetup show` data for a minor.
1263 a2cfdea2 Iustin Pop

1264 a2cfdea2 Iustin Pop
    """
1265 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "show"])
1266 a2cfdea2 Iustin Pop
    if result.failed:
1267 468c5f77 Iustin Pop
      logging.error("Can't display the drbd config: %s - %s",
1268 468c5f77 Iustin Pop
                    result.fail_reason, result.output)
1269 3840729d Iustin Pop
      return None
1270 3840729d Iustin Pop
    return result.stdout
1271 3840729d Iustin Pop
1272 3840729d Iustin Pop
  @classmethod
1273 3840729d Iustin Pop
  def _GetDevInfo(cls, out):
1274 3840729d Iustin Pop
    """Parse details about a given DRBD minor.
1275 3840729d Iustin Pop

1276 3840729d Iustin Pop
    This return, if available, the local backing device (as a path)
1277 3840729d Iustin Pop
    and the local and remote (ip, port) information from a string
1278 3840729d Iustin Pop
    containing the output of the `drbdsetup show` command as returned
1279 3840729d Iustin Pop
    by _GetShowData.
1280 3840729d Iustin Pop

1281 3840729d Iustin Pop
    """
1282 3840729d Iustin Pop
    data = {}
1283 a2cfdea2 Iustin Pop
    if not out:
1284 a2cfdea2 Iustin Pop
      return data
1285 a2cfdea2 Iustin Pop
1286 a2cfdea2 Iustin Pop
    bnf = cls._GetShowParser()
1287 a2cfdea2 Iustin Pop
    # run pyparse
1288 a2cfdea2 Iustin Pop
1289 a2cfdea2 Iustin Pop
    try:
1290 a2cfdea2 Iustin Pop
      results = bnf.parseString(out)
1291 a2cfdea2 Iustin Pop
    except pyp.ParseException, err:
1292 82463074 Iustin Pop
      _ThrowError("Can't parse drbdsetup show output: %s", str(err))
1293 a2cfdea2 Iustin Pop
1294 a2cfdea2 Iustin Pop
    # and massage the results into our desired format
1295 a2cfdea2 Iustin Pop
    for section in results:
1296 a2cfdea2 Iustin Pop
      sname = section[0]
1297 a2cfdea2 Iustin Pop
      if sname == "_this_host":
1298 a2cfdea2 Iustin Pop
        for lst in section[1:]:
1299 a2cfdea2 Iustin Pop
          if lst[0] == "disk":
1300 a2cfdea2 Iustin Pop
            data["local_dev"] = lst[1]
1301 a2cfdea2 Iustin Pop
          elif lst[0] == "meta-disk":
1302 a2cfdea2 Iustin Pop
            data["meta_dev"] = lst[1]
1303 a2cfdea2 Iustin Pop
            data["meta_index"] = lst[2]
1304 a2cfdea2 Iustin Pop
          elif lst[0] == "address":
1305 a2cfdea2 Iustin Pop
            data["local_addr"] = tuple(lst[1:])
1306 a2cfdea2 Iustin Pop
      elif sname == "_remote_host":
1307 a2cfdea2 Iustin Pop
        for lst in section[1:]:
1308 a2cfdea2 Iustin Pop
          if lst[0] == "address":
1309 a2cfdea2 Iustin Pop
            data["remote_addr"] = tuple(lst[1:])
1310 a2cfdea2 Iustin Pop
    return data
1311 a2cfdea2 Iustin Pop
1312 a2cfdea2 Iustin Pop
  def _MatchesLocal(self, info):
1313 a2cfdea2 Iustin Pop
    """Test if our local config matches with an existing device.
1314 a2cfdea2 Iustin Pop

1315 a2cfdea2 Iustin Pop
    The parameter should be as returned from `_GetDevInfo()`. This
1316 a2cfdea2 Iustin Pop
    method tests if our local backing device is the same as the one in
1317 a2cfdea2 Iustin Pop
    the info parameter, in effect testing if we look like the given
1318 a2cfdea2 Iustin Pop
    device.
1319 a2cfdea2 Iustin Pop

1320 a2cfdea2 Iustin Pop
    """
1321 b00b95dd Iustin Pop
    if self._children:
1322 b00b95dd Iustin Pop
      backend, meta = self._children
1323 b00b95dd Iustin Pop
    else:
1324 b00b95dd Iustin Pop
      backend = meta = None
1325 b00b95dd Iustin Pop
1326 a2cfdea2 Iustin Pop
    if backend is not None:
1327 b00b95dd Iustin Pop
      retval = ("local_dev" in info and info["local_dev"] == backend.dev_path)
1328 a2cfdea2 Iustin Pop
    else:
1329 a2cfdea2 Iustin Pop
      retval = ("local_dev" not in info)
1330 b00b95dd Iustin Pop
1331 a2cfdea2 Iustin Pop
    if meta is not None:
1332 b00b95dd Iustin Pop
      retval = retval and ("meta_dev" in info and
1333 b00b95dd Iustin Pop
                           info["meta_dev"] == meta.dev_path)
1334 b00b95dd Iustin Pop
      retval = retval and ("meta_index" in info and
1335 b00b95dd Iustin Pop
                           info["meta_index"] == 0)
1336 a2cfdea2 Iustin Pop
    else:
1337 a2cfdea2 Iustin Pop
      retval = retval and ("meta_dev" not in info and
1338 a2cfdea2 Iustin Pop
                           "meta_index" not in info)
1339 a2cfdea2 Iustin Pop
    return retval
1340 a2cfdea2 Iustin Pop
1341 a2cfdea2 Iustin Pop
  def _MatchesNet(self, info):
1342 a2cfdea2 Iustin Pop
    """Test if our network config matches with an existing device.
1343 a2cfdea2 Iustin Pop

1344 a2cfdea2 Iustin Pop
    The parameter should be as returned from `_GetDevInfo()`. This
1345 a2cfdea2 Iustin Pop
    method tests if our network configuration is the same as the one
1346 a2cfdea2 Iustin Pop
    in the info parameter, in effect testing if we look like the given
1347 a2cfdea2 Iustin Pop
    device.
1348 a2cfdea2 Iustin Pop

1349 a2cfdea2 Iustin Pop
    """
1350 a2cfdea2 Iustin Pop
    if (((self._lhost is None and not ("local_addr" in info)) and
1351 a2cfdea2 Iustin Pop
         (self._rhost is None and not ("remote_addr" in info)))):
1352 a2cfdea2 Iustin Pop
      return True
1353 a2cfdea2 Iustin Pop
1354 a2cfdea2 Iustin Pop
    if self._lhost is None:
1355 a2cfdea2 Iustin Pop
      return False
1356 a2cfdea2 Iustin Pop
1357 a2cfdea2 Iustin Pop
    if not ("local_addr" in info and
1358 a2cfdea2 Iustin Pop
            "remote_addr" in info):
1359 a2cfdea2 Iustin Pop
      return False
1360 a2cfdea2 Iustin Pop
1361 a2cfdea2 Iustin Pop
    retval = (info["local_addr"] == (self._lhost, self._lport))
1362 a2cfdea2 Iustin Pop
    retval = (retval and
1363 a2cfdea2 Iustin Pop
              info["remote_addr"] == (self._rhost, self._rport))
1364 a2cfdea2 Iustin Pop
    return retval
1365 a2cfdea2 Iustin Pop
1366 8a69b3a8 Andrea Spadaccini
  def _AssembleLocal(self, minor, backend, meta, size):
1367 a2cfdea2 Iustin Pop
    """Configure the local part of a DRBD device.
1368 a2cfdea2 Iustin Pop

1369 a2cfdea2 Iustin Pop
    """
1370 8a69b3a8 Andrea Spadaccini
    args = ["drbdsetup", self._DevPath(minor), "disk",
1371 f069addf Iustin Pop
            backend, meta, "0",
1372 f069addf Iustin Pop
            "-e", "detach",
1373 f069addf Iustin Pop
            "--create-device"]
1374 60bca04a Iustin Pop
    if size:
1375 60bca04a Iustin Pop
      args.extend(["-d", "%sm" % size])
1376 8a69b3a8 Andrea Spadaccini
1377 8a69b3a8 Andrea Spadaccini
    version = self._GetVersion(self._GetProcData())
1378 8a69b3a8 Andrea Spadaccini
    vmaj = version["k_major"]
1379 8a69b3a8 Andrea Spadaccini
    vmin = version["k_minor"]
1380 8a69b3a8 Andrea Spadaccini
    vrel = version["k_point"]
1381 8a69b3a8 Andrea Spadaccini
1382 8a69b3a8 Andrea Spadaccini
    barrier_args = \
1383 8a69b3a8 Andrea Spadaccini
      self._ComputeDiskBarrierArgs(vmaj, vmin, vrel,
1384 ac00bf1b Andrea Spadaccini
                                   self.params[constants.LDP_BARRIERS],
1385 ac00bf1b Andrea Spadaccini
                                   self.params[constants.LDP_NO_META_FLUSH])
1386 8a69b3a8 Andrea Spadaccini
    args.extend(barrier_args)
1387 8a69b3a8 Andrea Spadaccini
1388 ad1dd4c7 Andrea Spadaccini
    if self.params[constants.LDP_DISK_CUSTOM]:
1389 ad1dd4c7 Andrea Spadaccini
      args.extend(shlex.split(self.params[constants.LDP_DISK_CUSTOM]))
1390 ad1dd4c7 Andrea Spadaccini
1391 333411a7 Guido Trotter
    result = utils.RunCmd(args)
1392 a2cfdea2 Iustin Pop
    if result.failed:
1393 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't attach local disk: %s", minor, result.output)
1394 a2cfdea2 Iustin Pop
1395 8a69b3a8 Andrea Spadaccini
  @classmethod
1396 8a69b3a8 Andrea Spadaccini
  def _ComputeDiskBarrierArgs(cls, vmaj, vmin, vrel, disabled_barriers,
1397 5ae4945a Iustin Pop
                              disable_meta_flush):
1398 8a69b3a8 Andrea Spadaccini
    """Compute the DRBD command line parameters for disk barriers
1399 8a69b3a8 Andrea Spadaccini

1400 8a69b3a8 Andrea Spadaccini
    Returns a list of the disk barrier parameters as requested via the
1401 8a69b3a8 Andrea Spadaccini
    disabled_barriers and disable_meta_flush arguments, and according to the
1402 8a69b3a8 Andrea Spadaccini
    supported ones in the DRBD version vmaj.vmin.vrel
1403 8a69b3a8 Andrea Spadaccini

1404 8a69b3a8 Andrea Spadaccini
    If the desired option is unsupported, raises errors.BlockDeviceError.
1405 8a69b3a8 Andrea Spadaccini

1406 8a69b3a8 Andrea Spadaccini
    """
1407 8a69b3a8 Andrea Spadaccini
    disabled_barriers_set = frozenset(disabled_barriers)
1408 8a69b3a8 Andrea Spadaccini
    if not disabled_barriers_set in constants.DRBD_VALID_BARRIER_OPT:
1409 8a69b3a8 Andrea Spadaccini
      raise errors.BlockDeviceError("%s is not a valid option set for DRBD"
1410 8a69b3a8 Andrea Spadaccini
                                    " barriers" % disabled_barriers)
1411 8a69b3a8 Andrea Spadaccini
1412 8a69b3a8 Andrea Spadaccini
    args = []
1413 8a69b3a8 Andrea Spadaccini
1414 8a69b3a8 Andrea Spadaccini
    # The following code assumes DRBD 8.x, with x < 4 and x != 1 (DRBD 8.1.x
1415 8a69b3a8 Andrea Spadaccini
    # does not exist)
1416 8a69b3a8 Andrea Spadaccini
    if not vmaj == 8 and vmin in (0, 2, 3):
1417 8a69b3a8 Andrea Spadaccini
      raise errors.BlockDeviceError("Unsupported DRBD version: %d.%d.%d" %
1418 8a69b3a8 Andrea Spadaccini
                                    (vmaj, vmin, vrel))
1419 8a69b3a8 Andrea Spadaccini
1420 8a69b3a8 Andrea Spadaccini
    def _AppendOrRaise(option, min_version):
1421 8a69b3a8 Andrea Spadaccini
      """Helper for DRBD options"""
1422 8a69b3a8 Andrea Spadaccini
      if min_version is not None and vrel >= min_version:
1423 8a69b3a8 Andrea Spadaccini
        args.append(option)
1424 8a69b3a8 Andrea Spadaccini
      else:
1425 8a69b3a8 Andrea Spadaccini
        raise errors.BlockDeviceError("Could not use the option %s as the"
1426 8a69b3a8 Andrea Spadaccini
                                      " DRBD version %d.%d.%d does not support"
1427 8a69b3a8 Andrea Spadaccini
                                      " it." % (option, vmaj, vmin, vrel))
1428 8a69b3a8 Andrea Spadaccini
1429 8a69b3a8 Andrea Spadaccini
    # the minimum version for each feature is encoded via pairs of (minor
1430 8a69b3a8 Andrea Spadaccini
    # version -> x) where x is version in which support for the option was
1431 8a69b3a8 Andrea Spadaccini
    # introduced.
1432 8a69b3a8 Andrea Spadaccini
    meta_flush_supported = disk_flush_supported = {
1433 8a69b3a8 Andrea Spadaccini
      0: 12,
1434 8a69b3a8 Andrea Spadaccini
      2: 7,
1435 8a69b3a8 Andrea Spadaccini
      3: 0,
1436 8a69b3a8 Andrea Spadaccini
      }
1437 8a69b3a8 Andrea Spadaccini
1438 8a69b3a8 Andrea Spadaccini
    disk_drain_supported = {
1439 8a69b3a8 Andrea Spadaccini
      2: 7,
1440 8a69b3a8 Andrea Spadaccini
      3: 0,
1441 8a69b3a8 Andrea Spadaccini
      }
1442 8a69b3a8 Andrea Spadaccini
1443 8a69b3a8 Andrea Spadaccini
    disk_barriers_supported = {
1444 8a69b3a8 Andrea Spadaccini
      3: 0,
1445 8a69b3a8 Andrea Spadaccini
      }
1446 8a69b3a8 Andrea Spadaccini
1447 8a69b3a8 Andrea Spadaccini
    # meta flushes
1448 8a69b3a8 Andrea Spadaccini
    if disable_meta_flush:
1449 8a69b3a8 Andrea Spadaccini
      _AppendOrRaise(cls._DISABLE_META_FLUSH_OPTION,
1450 8a69b3a8 Andrea Spadaccini
                     meta_flush_supported.get(vmin, None))
1451 8a69b3a8 Andrea Spadaccini
1452 8a69b3a8 Andrea Spadaccini
    # disk flushes
1453 8a69b3a8 Andrea Spadaccini
    if constants.DRBD_B_DISK_FLUSH in disabled_barriers_set:
1454 8a69b3a8 Andrea Spadaccini
      _AppendOrRaise(cls._DISABLE_FLUSH_OPTION,
1455 8a69b3a8 Andrea Spadaccini
                     disk_flush_supported.get(vmin, None))
1456 8a69b3a8 Andrea Spadaccini
1457 8a69b3a8 Andrea Spadaccini
    # disk drain
1458 8a69b3a8 Andrea Spadaccini
    if constants.DRBD_B_DISK_DRAIN in disabled_barriers_set:
1459 8a69b3a8 Andrea Spadaccini
      _AppendOrRaise(cls._DISABLE_DRAIN_OPTION,
1460 8a69b3a8 Andrea Spadaccini
                     disk_drain_supported.get(vmin, None))
1461 8a69b3a8 Andrea Spadaccini
1462 8a69b3a8 Andrea Spadaccini
    # disk barriers
1463 8a69b3a8 Andrea Spadaccini
    if constants.DRBD_B_DISK_BARRIERS in disabled_barriers_set:
1464 8a69b3a8 Andrea Spadaccini
      _AppendOrRaise(cls._DISABLE_DISK_OPTION,
1465 8a69b3a8 Andrea Spadaccini
                     disk_barriers_supported.get(vmin, None))
1466 8a69b3a8 Andrea Spadaccini
1467 8a69b3a8 Andrea Spadaccini
    return args
1468 8a69b3a8 Andrea Spadaccini
1469 6e9814a1 Andrea Spadaccini
  def _AssembleNet(self, minor, net_info, protocol,
1470 a2cfdea2 Iustin Pop
                   dual_pri=False, hmac=None, secret=None):
1471 a2cfdea2 Iustin Pop
    """Configure the network part of the device.
1472 a2cfdea2 Iustin Pop

1473 a2cfdea2 Iustin Pop
    """
1474 a2cfdea2 Iustin Pop
    lhost, lport, rhost, rport = net_info
1475 52857176 Iustin Pop
    if None in net_info:
1476 52857176 Iustin Pop
      # we don't want network connection and actually want to make
1477 52857176 Iustin Pop
      # sure its shutdown
1478 6e9814a1 Andrea Spadaccini
      self._ShutdownNet(minor)
1479 1063abd1 Iustin Pop
      return
1480 52857176 Iustin Pop
1481 7d585316 Iustin Pop
    # Workaround for a race condition. When DRBD is doing its dance to
1482 7d585316 Iustin Pop
    # establish a connection with its peer, it also sends the
1483 7d585316 Iustin Pop
    # synchronization speed over the wire. In some cases setting the
1484 7d585316 Iustin Pop
    # sync speed only after setting up both sides can race with DRBD
1485 7d585316 Iustin Pop
    # connecting, hence we set it here before telling DRBD anything
1486 7d585316 Iustin Pop
    # about its peer.
1487 8584e922 Andrea Spadaccini
    sync_errors = self._SetMinorSyncParams(minor, self.params)
1488 8584e922 Andrea Spadaccini
    if sync_errors:
1489 8584e922 Andrea Spadaccini
      _ThrowError("drbd%d: can't set the synchronization parameters: %s" %
1490 8584e922 Andrea Spadaccini
                  (minor, utils.CommaJoin(sync_errors)))
1491 7d585316 Iustin Pop
1492 8b312c1d Manuel Franceschini
    if netutils.IP6Address.IsValid(lhost):
1493 8b312c1d Manuel Franceschini
      if not netutils.IP6Address.IsValid(rhost):
1494 5a672c30 Manuel Franceschini
        _ThrowError("drbd%d: can't connect ip %s to ip %s" %
1495 5a672c30 Manuel Franceschini
                    (minor, lhost, rhost))
1496 5a672c30 Manuel Franceschini
      family = "ipv6"
1497 8b312c1d Manuel Franceschini
    elif netutils.IP4Address.IsValid(lhost):
1498 8b312c1d Manuel Franceschini
      if not netutils.IP4Address.IsValid(rhost):
1499 5a672c30 Manuel Franceschini
        _ThrowError("drbd%d: can't connect ip %s to ip %s" %
1500 5a672c30 Manuel Franceschini
                    (minor, lhost, rhost))
1501 5a672c30 Manuel Franceschini
      family = "ipv4"
1502 5a672c30 Manuel Franceschini
    else:
1503 5a672c30 Manuel Franceschini
      _ThrowError("drbd%d: Invalid ip %s" % (minor, lhost))
1504 5a672c30 Manuel Franceschini
1505 6e9814a1 Andrea Spadaccini
    args = ["drbdsetup", self._DevPath(minor), "net",
1506 5a672c30 Manuel Franceschini
            "%s:%s:%s" % (family, lhost, lport),
1507 5a672c30 Manuel Franceschini
            "%s:%s:%s" % (family, rhost, rport), protocol,
1508 f38478b2 Iustin Pop
            "-A", "discard-zero-changes",
1509 f38478b2 Iustin Pop
            "-B", "consensus",
1510 ab6cc81c Iustin Pop
            "--create-device",
1511 f38478b2 Iustin Pop
            ]
1512 a2cfdea2 Iustin Pop
    if dual_pri:
1513 a2cfdea2 Iustin Pop
      args.append("-m")
1514 a2cfdea2 Iustin Pop
    if hmac and secret:
1515 a2cfdea2 Iustin Pop
      args.extend(["-a", hmac, "-x", secret])
1516 ad1dd4c7 Andrea Spadaccini
1517 ad1dd4c7 Andrea Spadaccini
    if self.params[constants.LDP_NET_CUSTOM]:
1518 ad1dd4c7 Andrea Spadaccini
      args.extend(shlex.split(self.params[constants.LDP_NET_CUSTOM]))
1519 ad1dd4c7 Andrea Spadaccini
1520 a2cfdea2 Iustin Pop
    result = utils.RunCmd(args)
1521 a2cfdea2 Iustin Pop
    if result.failed:
1522 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't setup network: %s - %s",
1523 1063abd1 Iustin Pop
                  minor, result.fail_reason, result.output)
1524 a2cfdea2 Iustin Pop
1525 def8e2f6 Michael Hanselmann
    def _CheckNetworkConfig():
1526 6e9814a1 Andrea Spadaccini
      info = self._GetDevInfo(self._GetShowData(minor))
1527 a2cfdea2 Iustin Pop
      if not "local_addr" in info or not "remote_addr" in info:
1528 def8e2f6 Michael Hanselmann
        raise utils.RetryAgain()
1529 def8e2f6 Michael Hanselmann
1530 a2cfdea2 Iustin Pop
      if (info["local_addr"] != (lhost, lport) or
1531 a2cfdea2 Iustin Pop
          info["remote_addr"] != (rhost, rport)):
1532 def8e2f6 Michael Hanselmann
        raise utils.RetryAgain()
1533 def8e2f6 Michael Hanselmann
1534 def8e2f6 Michael Hanselmann
    try:
1535 def8e2f6 Michael Hanselmann
      utils.Retry(_CheckNetworkConfig, 1.0, 10.0)
1536 def8e2f6 Michael Hanselmann
    except utils.RetryTimeout:
1537 1063abd1 Iustin Pop
      _ThrowError("drbd%d: timeout while configuring network", minor)
1538 a2cfdea2 Iustin Pop
1539 b00b95dd Iustin Pop
  def AddChildren(self, devices):
1540 b00b95dd Iustin Pop
    """Add a disk to the DRBD device.
1541 b00b95dd Iustin Pop

1542 b00b95dd Iustin Pop
    """
1543 b00b95dd Iustin Pop
    if self.minor is None:
1544 82463074 Iustin Pop
      _ThrowError("drbd%d: can't attach to dbrd8 during AddChildren",
1545 82463074 Iustin Pop
                  self._aminor)
1546 b00b95dd Iustin Pop
    if len(devices) != 2:
1547 82463074 Iustin Pop
      _ThrowError("drbd%d: need two devices for AddChildren", self.minor)
1548 3840729d Iustin Pop
    info = self._GetDevInfo(self._GetShowData(self.minor))
1549 03ece5f3 Iustin Pop
    if "local_dev" in info:
1550 82463074 Iustin Pop
      _ThrowError("drbd%d: already attached to a local disk", self.minor)
1551 b00b95dd Iustin Pop
    backend, meta = devices
1552 b00b95dd Iustin Pop
    if backend.dev_path is None or meta.dev_path is None:
1553 82463074 Iustin Pop
      _ThrowError("drbd%d: children not ready during AddChildren", self.minor)
1554 b00b95dd Iustin Pop
    backend.Open()
1555 b00b95dd Iustin Pop
    meta.Open()
1556 9c793cfb Iustin Pop
    self._CheckMetaSize(meta.dev_path)
1557 b00b95dd Iustin Pop
    self._InitMeta(self._FindUnusedMinor(), meta.dev_path)
1558 b00b95dd Iustin Pop
1559 f069addf Iustin Pop
    self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path, self.size)
1560 b00b95dd Iustin Pop
    self._children = devices
1561 b00b95dd Iustin Pop
1562 b00b95dd Iustin Pop
  def RemoveChildren(self, devices):
1563 b00b95dd Iustin Pop
    """Detach the drbd device from local storage.
1564 b00b95dd Iustin Pop

1565 b00b95dd Iustin Pop
    """
1566 b00b95dd Iustin Pop
    if self.minor is None:
1567 82463074 Iustin Pop
      _ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
1568 82463074 Iustin Pop
                  self._aminor)
1569 03ece5f3 Iustin Pop
    # early return if we don't actually have backing storage
1570 3840729d Iustin Pop
    info = self._GetDevInfo(self._GetShowData(self.minor))
1571 03ece5f3 Iustin Pop
    if "local_dev" not in info:
1572 03ece5f3 Iustin Pop
      return
1573 b00b95dd Iustin Pop
    if len(self._children) != 2:
1574 82463074 Iustin Pop
      _ThrowError("drbd%d: we don't have two children: %s", self.minor,
1575 82463074 Iustin Pop
                  self._children)
1576 e739bd57 Iustin Pop
    if self._children.count(None) == 2: # we don't actually have children :)
1577 82463074 Iustin Pop
      logging.warning("drbd%d: requested detach while detached", self.minor)
1578 e739bd57 Iustin Pop
      return
1579 b00b95dd Iustin Pop
    if len(devices) != 2:
1580 82463074 Iustin Pop
      _ThrowError("drbd%d: we need two children in RemoveChildren", self.minor)
1581 e739bd57 Iustin Pop
    for child, dev in zip(self._children, devices):
1582 e739bd57 Iustin Pop
      if dev != child.dev_path:
1583 82463074 Iustin Pop
        _ThrowError("drbd%d: mismatch in local storage (%s != %s) in"
1584 82463074 Iustin Pop
                    " RemoveChildren", self.minor, dev, child.dev_path)
1585 b00b95dd Iustin Pop
1586 1063abd1 Iustin Pop
    self._ShutdownLocal(self.minor)
1587 b00b95dd Iustin Pop
    self._children = []
1588 b00b95dd Iustin Pop
1589 7d585316 Iustin Pop
  @classmethod
1590 f2f57b6e Andrea Spadaccini
  def _SetMinorSyncParams(cls, minor, params):
1591 f2f57b6e Andrea Spadaccini
    """Set the parameters of the DRBD syncer.
1592 a2cfdea2 Iustin Pop

1593 7d585316 Iustin Pop
    This is the low-level implementation.
1594 7d585316 Iustin Pop

1595 7d585316 Iustin Pop
    @type minor: int
1596 7d585316 Iustin Pop
    @param minor: the drbd minor whose settings we change
1597 f2f57b6e Andrea Spadaccini
    @type params: dict
1598 f2f57b6e Andrea Spadaccini
    @param params: LD level disk parameters related to the synchronization
1599 8584e922 Andrea Spadaccini
    @rtype: list
1600 8584e922 Andrea Spadaccini
    @return: a list of error messages
1601 7d585316 Iustin Pop

1602 a2cfdea2 Iustin Pop
    """
1603 f2f57b6e Andrea Spadaccini
1604 f2f57b6e Andrea Spadaccini
    args = ["drbdsetup", cls._DevPath(minor), "syncer"]
1605 f2f57b6e Andrea Spadaccini
    if params[constants.LDP_DYNAMIC_RESYNC]:
1606 f2f57b6e Andrea Spadaccini
      version = cls._GetVersion(cls._GetProcData())
1607 f2f57b6e Andrea Spadaccini
      vmin = version["k_minor"]
1608 f2f57b6e Andrea Spadaccini
      vrel = version["k_point"]
1609 f2f57b6e Andrea Spadaccini
1610 f2f57b6e Andrea Spadaccini
      # By definition we are using 8.x, so just check the rest of the version
1611 f2f57b6e Andrea Spadaccini
      # number
1612 f2f57b6e Andrea Spadaccini
      if vmin != 3 or vrel < 9:
1613 8584e922 Andrea Spadaccini
        msg = ("The current DRBD version (8.%d.%d) does not support the "
1614 8584e922 Andrea Spadaccini
               "dynamic resync speed controller" % (vmin, vrel))
1615 8584e922 Andrea Spadaccini
        logging.error(msg)
1616 8584e922 Andrea Spadaccini
        return [msg]
1617 8584e922 Andrea Spadaccini
1618 8584e922 Andrea Spadaccini
      if params[constants.LDP_PLAN_AHEAD] == 0:
1619 8584e922 Andrea Spadaccini
        msg = ("A value of 0 for c-plan-ahead disables the dynamic sync speed"
1620 8584e922 Andrea Spadaccini
               " controller at DRBD level. If you want to disable it, please"
1621 8584e922 Andrea Spadaccini
               " set the dynamic-resync disk parameter to False.")
1622 8584e922 Andrea Spadaccini
        logging.error(msg)
1623 8584e922 Andrea Spadaccini
        return [msg]
1624 f2f57b6e Andrea Spadaccini
1625 f2f57b6e Andrea Spadaccini
      # add the c-* parameters to args
1626 8584e922 Andrea Spadaccini
      args.extend(["--c-plan-ahead", params[constants.LDP_PLAN_AHEAD],
1627 8584e922 Andrea Spadaccini
                   "--c-fill-target", params[constants.LDP_FILL_TARGET],
1628 8584e922 Andrea Spadaccini
                   "--c-delay-target", params[constants.LDP_DELAY_TARGET],
1629 8584e922 Andrea Spadaccini
                   "--c-max-rate", params[constants.LDP_MAX_RATE],
1630 8584e922 Andrea Spadaccini
                   "--c-min-rate", params[constants.LDP_MIN_RATE],
1631 5ae4945a Iustin Pop
                   ])
1632 f2f57b6e Andrea Spadaccini
1633 f2f57b6e Andrea Spadaccini
    else:
1634 f2f57b6e Andrea Spadaccini
      args.extend(["-r", "%d" % params[constants.LDP_RESYNC_RATE]])
1635 f2f57b6e Andrea Spadaccini
1636 f2f57b6e Andrea Spadaccini
    args.append("--create-device")
1637 f2f57b6e Andrea Spadaccini
    result = utils.RunCmd(args)
1638 a2cfdea2 Iustin Pop
    if result.failed:
1639 8584e922 Andrea Spadaccini
      msg = ("Can't change syncer rate: %s - %s" %
1640 8584e922 Andrea Spadaccini
             (result.fail_reason, result.output))
1641 8584e922 Andrea Spadaccini
      logging.error(msg)
1642 e0b57a5c Michael Hanselmann
      return [msg]
1643 8584e922 Andrea Spadaccini
1644 8584e922 Andrea Spadaccini
    return []
1645 7d585316 Iustin Pop
1646 f2f57b6e Andrea Spadaccini
  def SetSyncParams(self, params):
1647 f2f57b6e Andrea Spadaccini
    """Set the synchronization parameters of the DRBD syncer.
1648 7d585316 Iustin Pop

1649 f2f57b6e Andrea Spadaccini
    @type params: dict
1650 f2f57b6e Andrea Spadaccini
    @param params: LD level disk parameters related to the synchronization
1651 8584e922 Andrea Spadaccini
    @rtype: list
1652 8584e922 Andrea Spadaccini
    @return: a list of error messages, emitted both by the current node and by
1653 8584e922 Andrea Spadaccini
    children. An empty list means no errors
1654 7d585316 Iustin Pop

1655 7d585316 Iustin Pop
    """
1656 7d585316 Iustin Pop
    if self.minor is None:
1657 8584e922 Andrea Spadaccini
      err = "Not attached during SetSyncParams"
1658 8584e922 Andrea Spadaccini
      logging.info(err)
1659 8584e922 Andrea Spadaccini
      return [err]
1660 8584e922 Andrea Spadaccini
1661 f2f57b6e Andrea Spadaccini
    children_result = super(DRBD8, self).SetSyncParams(params)
1662 8584e922 Andrea Spadaccini
    children_result.extend(self._SetMinorSyncParams(self.minor, params))
1663 8584e922 Andrea Spadaccini
    return children_result
1664 a2cfdea2 Iustin Pop
1665 a3fffcc6 René Nussbaumer
  def PauseResumeSync(self, pause):
1666 a3fffcc6 René Nussbaumer
    """Pauses or resumes the sync of a DRBD device.
1667 a3fffcc6 René Nussbaumer

1668 a3fffcc6 René Nussbaumer
    @param pause: Wether to pause or resume
1669 a3fffcc6 René Nussbaumer
    @return: the success of the operation
1670 a3fffcc6 René Nussbaumer

1671 a3fffcc6 René Nussbaumer
    """
1672 a3fffcc6 René Nussbaumer
    if self.minor is None:
1673 a3fffcc6 René Nussbaumer
      logging.info("Not attached during PauseSync")
1674 a3fffcc6 René Nussbaumer
      return False
1675 a3fffcc6 René Nussbaumer
1676 a3fffcc6 René Nussbaumer
    children_result = super(DRBD8, self).PauseResumeSync(pause)
1677 a3fffcc6 René Nussbaumer
1678 a3fffcc6 René Nussbaumer
    if pause:
1679 a3fffcc6 René Nussbaumer
      cmd = "pause-sync"
1680 a3fffcc6 René Nussbaumer
    else:
1681 a3fffcc6 René Nussbaumer
      cmd = "resume-sync"
1682 a3fffcc6 René Nussbaumer
1683 a3fffcc6 René Nussbaumer
    result = utils.RunCmd(["drbdsetup", self.dev_path, cmd])
1684 a3fffcc6 René Nussbaumer
    if result.failed:
1685 a3fffcc6 René Nussbaumer
      logging.error("Can't %s: %s - %s", cmd,
1686 a3fffcc6 René Nussbaumer
                    result.fail_reason, result.output)
1687 a3fffcc6 René Nussbaumer
    return not result.failed and children_result
1688 a3fffcc6 René Nussbaumer
1689 6b90c22e Iustin Pop
  def GetProcStatus(self):
1690 6b90c22e Iustin Pop
    """Return device data from /proc.
1691 6b90c22e Iustin Pop

1692 6b90c22e Iustin Pop
    """
1693 6b90c22e Iustin Pop
    if self.minor is None:
1694 82463074 Iustin Pop
      _ThrowError("drbd%d: GetStats() called while not attached", self._aminor)
1695 6b90c22e Iustin Pop
    proc_info = self._MassageProcData(self._GetProcData())
1696 6b90c22e Iustin Pop
    if self.minor not in proc_info:
1697 82463074 Iustin Pop
      _ThrowError("drbd%d: can't find myself in /proc", self.minor)
1698 6b90c22e Iustin Pop
    return DRBD8Status(proc_info[self.minor])
1699 6b90c22e Iustin Pop
1700 a2cfdea2 Iustin Pop
  def GetSyncStatus(self):
1701 a2cfdea2 Iustin Pop
    """Returns the sync status of the device.
1702 a2cfdea2 Iustin Pop

1703 a2cfdea2 Iustin Pop

1704 a2cfdea2 Iustin Pop
    If sync_percent is None, it means all is ok
1705 5bbd3f7f Michael Hanselmann
    If estimated_time is None, it means we can't estimate
1706 0834c866 Iustin Pop
    the time needed, otherwise it's the time left in seconds.
1707 0834c866 Iustin Pop

1708 0834c866 Iustin Pop

1709 0834c866 Iustin Pop
    We set the is_degraded parameter to True on two conditions:
1710 0834c866 Iustin Pop
    network not connected or local disk missing.
1711 0834c866 Iustin Pop

1712 5bbd3f7f Michael Hanselmann
    We compute the ldisk parameter based on whether we have a local
1713 0834c866 Iustin Pop
    disk or not.
1714 a2cfdea2 Iustin Pop

1715 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
1716 c41eea6e Iustin Pop

1717 a2cfdea2 Iustin Pop
    """
1718 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1719 82463074 Iustin Pop
      _ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
1720 96acbc09 Michael Hanselmann
1721 6b90c22e Iustin Pop
    stats = self.GetProcStatus()
1722 f208978a Michael Hanselmann
    is_degraded = not stats.is_connected or not stats.is_disk_uptodate
1723 f208978a Michael Hanselmann
1724 f208978a Michael Hanselmann
    if stats.is_disk_uptodate:
1725 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_OKAY
1726 f208978a Michael Hanselmann
    elif stats.is_diskless:
1727 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_FAULTY
1728 f208978a Michael Hanselmann
    else:
1729 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_UNKNOWN
1730 96acbc09 Michael Hanselmann
1731 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
1732 96acbc09 Michael Hanselmann
                                  major=self.major,
1733 96acbc09 Michael Hanselmann
                                  minor=self.minor,
1734 96acbc09 Michael Hanselmann
                                  sync_percent=stats.sync_percent,
1735 96acbc09 Michael Hanselmann
                                  estimated_time=stats.est_time,
1736 f208978a Michael Hanselmann
                                  is_degraded=is_degraded,
1737 f208978a Michael Hanselmann
                                  ldisk_status=ldisk_status)
1738 a2cfdea2 Iustin Pop
1739 a2cfdea2 Iustin Pop
  def Open(self, force=False):
1740 a2cfdea2 Iustin Pop
    """Make the local state primary.
1741 a2cfdea2 Iustin Pop

1742 f860ff4e Guido Trotter
    If the 'force' parameter is given, the '-o' option is passed to
1743 f860ff4e Guido Trotter
    drbdsetup. Since this is a potentially dangerous operation, the
1744 a2cfdea2 Iustin Pop
    force flag should be only given after creation, when it actually
1745 f860ff4e Guido Trotter
    is mandatory.
1746 a2cfdea2 Iustin Pop

1747 a2cfdea2 Iustin Pop
    """
1748 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1749 468c5f77 Iustin Pop
      logging.error("DRBD cannot attach to a device during open")
1750 a2cfdea2 Iustin Pop
      return False
1751 a2cfdea2 Iustin Pop
    cmd = ["drbdsetup", self.dev_path, "primary"]
1752 a2cfdea2 Iustin Pop
    if force:
1753 a2cfdea2 Iustin Pop
      cmd.append("-o")
1754 a2cfdea2 Iustin Pop
    result = utils.RunCmd(cmd)
1755 a2cfdea2 Iustin Pop
    if result.failed:
1756 82463074 Iustin Pop
      _ThrowError("drbd%d: can't make drbd device primary: %s", self.minor,
1757 82463074 Iustin Pop
                  result.output)
1758 a2cfdea2 Iustin Pop
1759 a2cfdea2 Iustin Pop
  def Close(self):
1760 a2cfdea2 Iustin Pop
    """Make the local state secondary.
1761 a2cfdea2 Iustin Pop

1762 a2cfdea2 Iustin Pop
    This will, of course, fail if the device is in use.
1763 a2cfdea2 Iustin Pop

1764 a2cfdea2 Iustin Pop
    """
1765 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1766 82463074 Iustin Pop
      _ThrowError("drbd%d: can't Attach() in Close()", self._aminor)
1767 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", self.dev_path, "secondary"])
1768 a2cfdea2 Iustin Pop
    if result.failed:
1769 82463074 Iustin Pop
      _ThrowError("drbd%d: can't switch drbd device to secondary: %s",
1770 82463074 Iustin Pop
                  self.minor, result.output)
1771 a2cfdea2 Iustin Pop
1772 cf8df3f3 Iustin Pop
  def DisconnectNet(self):
1773 cf8df3f3 Iustin Pop
    """Removes network configuration.
1774 cf8df3f3 Iustin Pop

1775 cf8df3f3 Iustin Pop
    This method shutdowns the network side of the device.
1776 cf8df3f3 Iustin Pop

1777 cf8df3f3 Iustin Pop
    The method will wait up to a hardcoded timeout for the device to
1778 cf8df3f3 Iustin Pop
    go into standalone after the 'disconnect' command before
1779 cf8df3f3 Iustin Pop
    re-configuring it, as sometimes it takes a while for the
1780 cf8df3f3 Iustin Pop
    disconnect to actually propagate and thus we might issue a 'net'
1781 cf8df3f3 Iustin Pop
    command while the device is still connected. If the device will
1782 cf8df3f3 Iustin Pop
    still be attached to the network and we time out, we raise an
1783 cf8df3f3 Iustin Pop
    exception.
1784 cf8df3f3 Iustin Pop

1785 cf8df3f3 Iustin Pop
    """
1786 cf8df3f3 Iustin Pop
    if self.minor is None:
1787 82463074 Iustin Pop
      _ThrowError("drbd%d: disk not attached in re-attach net", self._aminor)
1788 cf8df3f3 Iustin Pop
1789 cf8df3f3 Iustin Pop
    if None in (self._lhost, self._lport, self._rhost, self._rport):
1790 82463074 Iustin Pop
      _ThrowError("drbd%d: DRBD disk missing network info in"
1791 82463074 Iustin Pop
                  " DisconnectNet()", self.minor)
1792 cf8df3f3 Iustin Pop
1793 def8e2f6 Michael Hanselmann
    class _DisconnectStatus:
1794 def8e2f6 Michael Hanselmann
      def __init__(self, ever_disconnected):
1795 def8e2f6 Michael Hanselmann
        self.ever_disconnected = ever_disconnected
1796 cf8df3f3 Iustin Pop
1797 def8e2f6 Michael Hanselmann
    dstatus = _DisconnectStatus(_IgnoreError(self._ShutdownNet, self.minor))
1798 def8e2f6 Michael Hanselmann
1799 def8e2f6 Michael Hanselmann
    def _WaitForDisconnect():
1800 def8e2f6 Michael Hanselmann
      if self.GetProcStatus().is_standalone:
1801 def8e2f6 Michael Hanselmann
        return
1802 def8e2f6 Michael Hanselmann
1803 def8e2f6 Michael Hanselmann
      # retry the disconnect, it seems possible that due to a well-time
1804 def8e2f6 Michael Hanselmann
      # disconnect on the peer, my disconnect command might be ignored and
1805 def8e2f6 Michael Hanselmann
      # forgotten
1806 def8e2f6 Michael Hanselmann
      dstatus.ever_disconnected = \
1807 def8e2f6 Michael Hanselmann
        _IgnoreError(self._ShutdownNet, self.minor) or dstatus.ever_disconnected
1808 def8e2f6 Michael Hanselmann
1809 def8e2f6 Michael Hanselmann
      raise utils.RetryAgain()
1810 def8e2f6 Michael Hanselmann
1811 def8e2f6 Michael Hanselmann
    # Keep start time
1812 def8e2f6 Michael Hanselmann
    start_time = time.time()
1813 def8e2f6 Michael Hanselmann
1814 def8e2f6 Michael Hanselmann
    try:
1815 def8e2f6 Michael Hanselmann
      # Start delay at 100 milliseconds and grow up to 2 seconds
1816 def8e2f6 Michael Hanselmann
      utils.Retry(_WaitForDisconnect, (0.1, 1.5, 2.0),
1817 def8e2f6 Michael Hanselmann
                  self._NET_RECONFIG_TIMEOUT)
1818 def8e2f6 Michael Hanselmann
    except utils.RetryTimeout:
1819 def8e2f6 Michael Hanselmann
      if dstatus.ever_disconnected:
1820 82463074 Iustin Pop
        msg = ("drbd%d: device did not react to the"
1821 cf8df3f3 Iustin Pop
               " 'disconnect' command in a timely manner")
1822 cf8df3f3 Iustin Pop
      else:
1823 82463074 Iustin Pop
        msg = "drbd%d: can't shutdown network, even after multiple retries"
1824 def8e2f6 Michael Hanselmann
1825 82463074 Iustin Pop
      _ThrowError(msg, self.minor)
1826 cf8df3f3 Iustin Pop
1827 def8e2f6 Michael Hanselmann
    reconfig_time = time.time() - start_time
1828 def8e2f6 Michael Hanselmann
    if reconfig_time > (self._NET_RECONFIG_TIMEOUT * 0.25):
1829 82463074 Iustin Pop
      logging.info("drbd%d: DisconnectNet: detach took %.3f seconds",
1830 82463074 Iustin Pop
                   self.minor, reconfig_time)
1831 cf8df3f3 Iustin Pop
1832 cf8df3f3 Iustin Pop
  def AttachNet(self, multimaster):
1833 cf8df3f3 Iustin Pop
    """Reconnects the network.
1834 cf8df3f3 Iustin Pop

1835 cf8df3f3 Iustin Pop
    This method connects the network side of the device with a
1836 cf8df3f3 Iustin Pop
    specified multi-master flag. The device needs to be 'Standalone'
1837 cf8df3f3 Iustin Pop
    but have valid network configuration data.
1838 cf8df3f3 Iustin Pop

1839 cf8df3f3 Iustin Pop
    Args:
1840 cf8df3f3 Iustin Pop
      - multimaster: init the network in dual-primary mode
1841 cf8df3f3 Iustin Pop

1842 cf8df3f3 Iustin Pop
    """
1843 cf8df3f3 Iustin Pop
    if self.minor is None:
1844 82463074 Iustin Pop
      _ThrowError("drbd%d: device not attached in AttachNet", self._aminor)
1845 cf8df3f3 Iustin Pop
1846 cf8df3f3 Iustin Pop
    if None in (self._lhost, self._lport, self._rhost, self._rport):
1847 82463074 Iustin Pop
      _ThrowError("drbd%d: missing network info in AttachNet()", self.minor)
1848 cf8df3f3 Iustin Pop
1849 cf8df3f3 Iustin Pop
    status = self.GetProcStatus()
1850 cf8df3f3 Iustin Pop
1851 cf8df3f3 Iustin Pop
    if not status.is_standalone:
1852 82463074 Iustin Pop
      _ThrowError("drbd%d: device is not standalone in AttachNet", self.minor)
1853 cf8df3f3 Iustin Pop
1854 1063abd1 Iustin Pop
    self._AssembleNet(self.minor,
1855 1063abd1 Iustin Pop
                      (self._lhost, self._lport, self._rhost, self._rport),
1856 1063abd1 Iustin Pop
                      constants.DRBD_NET_PROTOCOL, dual_pri=multimaster,
1857 1063abd1 Iustin Pop
                      hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1858 cf8df3f3 Iustin Pop
1859 a2cfdea2 Iustin Pop
  def Attach(self):
1860 2d0c8319 Iustin Pop
    """Check if our minor is configured.
1861 2d0c8319 Iustin Pop

1862 2d0c8319 Iustin Pop
    This doesn't do any device configurations - it only checks if the
1863 2d0c8319 Iustin Pop
    minor is in a state different from Unconfigured.
1864 2d0c8319 Iustin Pop

1865 2d0c8319 Iustin Pop
    Note that this function will not change the state of the system in
1866 2d0c8319 Iustin Pop
    any way (except in case of side-effects caused by reading from
1867 2d0c8319 Iustin Pop
    /proc).
1868 2d0c8319 Iustin Pop

1869 2d0c8319 Iustin Pop
    """
1870 6d2e83d5 Iustin Pop
    used_devs = self.GetUsedDevs()
1871 2d0c8319 Iustin Pop
    if self._aminor in used_devs:
1872 2d0c8319 Iustin Pop
      minor = self._aminor
1873 2d0c8319 Iustin Pop
    else:
1874 2d0c8319 Iustin Pop
      minor = None
1875 2d0c8319 Iustin Pop
1876 2d0c8319 Iustin Pop
    self._SetFromMinor(minor)
1877 2d0c8319 Iustin Pop
    return minor is not None
1878 2d0c8319 Iustin Pop
1879 2d0c8319 Iustin Pop
  def Assemble(self):
1880 2d0c8319 Iustin Pop
    """Assemble the drbd.
1881 2d0c8319 Iustin Pop

1882 2d0c8319 Iustin Pop
    Method:
1883 2d0c8319 Iustin Pop
      - if we have a configured device, we try to ensure that it matches
1884 2d0c8319 Iustin Pop
        our config
1885 2d0c8319 Iustin Pop
      - if not, we create it from zero
1886 d529599f Andrea Spadaccini
      - anyway, set the device parameters
1887 2d0c8319 Iustin Pop

1888 2d0c8319 Iustin Pop
    """
1889 1063abd1 Iustin Pop
    super(DRBD8, self).Assemble()
1890 2d0c8319 Iustin Pop
1891 2d0c8319 Iustin Pop
    self.Attach()
1892 2d0c8319 Iustin Pop
    if self.minor is None:
1893 2d0c8319 Iustin Pop
      # local device completely unconfigured
1894 1063abd1 Iustin Pop
      self._FastAssemble()
1895 2d0c8319 Iustin Pop
    else:
1896 2d0c8319 Iustin Pop
      # we have to recheck the local and network status and try to fix
1897 2d0c8319 Iustin Pop
      # the device
1898 1063abd1 Iustin Pop
      self._SlowAssemble()
1899 2d0c8319 Iustin Pop
1900 8584e922 Andrea Spadaccini
    sync_errors = self.SetSyncParams(self.params)
1901 8584e922 Andrea Spadaccini
    if sync_errors:
1902 8584e922 Andrea Spadaccini
      _ThrowError("drbd%d: can't set the synchronization parameters: %s" %
1903 8584e922 Andrea Spadaccini
                  (self.minor, utils.CommaJoin(sync_errors)))
1904 d529599f Andrea Spadaccini
1905 2d0c8319 Iustin Pop
  def _SlowAssemble(self):
1906 2d0c8319 Iustin Pop
    """Assembles the DRBD device from a (partially) configured device.
1907 a2cfdea2 Iustin Pop

1908 a2cfdea2 Iustin Pop
    In case of partially attached (local device matches but no network
1909 a2cfdea2 Iustin Pop
    setup), we perform the network attach. If successful, we re-test
1910 a2cfdea2 Iustin Pop
    the attach if can return success.
1911 a2cfdea2 Iustin Pop

1912 a2cfdea2 Iustin Pop
    """
1913 527a15ac Iustin Pop
    # TODO: Rewrite to not use a for loop just because there is 'break'
1914 b459a848 Andrea Spadaccini
    # pylint: disable=W0631
1915 1063abd1 Iustin Pop
    net_data = (self._lhost, self._lport, self._rhost, self._rport)
1916 a1578d63 Iustin Pop
    for minor in (self._aminor,):
1917 3840729d Iustin Pop
      info = self._GetDevInfo(self._GetShowData(minor))
1918 a2cfdea2 Iustin Pop
      match_l = self._MatchesLocal(info)
1919 a2cfdea2 Iustin Pop
      match_r = self._MatchesNet(info)
1920 1063abd1 Iustin Pop
1921 a2cfdea2 Iustin Pop
      if match_l and match_r:
1922 1063abd1 Iustin Pop
        # everything matches
1923 a2cfdea2 Iustin Pop
        break
1924 1063abd1 Iustin Pop
1925 a2cfdea2 Iustin Pop
      if match_l and not match_r and "local_addr" not in info:
1926 1063abd1 Iustin Pop
        # disk matches, but not attached to network, attach and recheck
1927 1063abd1 Iustin Pop
        self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
1928 1063abd1 Iustin Pop
                          hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1929 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1930 1063abd1 Iustin Pop
          break
1931 1063abd1 Iustin Pop
        else:
1932 1063abd1 Iustin Pop
          _ThrowError("drbd%d: network attach successful, but 'drbdsetup"
1933 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1934 1063abd1 Iustin Pop
1935 fc1dc9d7 Iustin Pop
      if match_r and "local_dev" not in info:
1936 1063abd1 Iustin Pop
        # no local disk, but network attached and it matches
1937 1063abd1 Iustin Pop
        self._AssembleLocal(minor, self._children[0].dev_path,
1938 f069addf Iustin Pop
                            self._children[1].dev_path, self.size)
1939 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1940 1063abd1 Iustin Pop
          break
1941 1063abd1 Iustin Pop
        else:
1942 1063abd1 Iustin Pop
          _ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
1943 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1944 bf25af3b Iustin Pop
1945 bf25af3b Iustin Pop
      # this case must be considered only if we actually have local
1946 bf25af3b Iustin Pop
      # storage, i.e. not in diskless mode, because all diskless
1947 bf25af3b Iustin Pop
      # devices are equal from the point of view of local
1948 bf25af3b Iustin Pop
      # configuration
1949 bf25af3b Iustin Pop
      if (match_l and "local_dev" in info and
1950 bf25af3b Iustin Pop
          not match_r and "local_addr" in info):
1951 9cdbe77f Iustin Pop
        # strange case - the device network part points to somewhere
1952 9cdbe77f Iustin Pop
        # else, even though its local storage is ours; as we own the
1953 9cdbe77f Iustin Pop
        # drbd space, we try to disconnect from the remote peer and
1954 9cdbe77f Iustin Pop
        # reconnect to our correct one
1955 1063abd1 Iustin Pop
        try:
1956 1063abd1 Iustin Pop
          self._ShutdownNet(minor)
1957 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
1958 33bc6f01 Iustin Pop
          _ThrowError("drbd%d: device has correct local storage, wrong"
1959 33bc6f01 Iustin Pop
                      " remote peer and is unable to disconnect in order"
1960 33bc6f01 Iustin Pop
                      " to attach to the correct peer: %s", minor, str(err))
1961 9cdbe77f Iustin Pop
        # note: _AssembleNet also handles the case when we don't want
1962 9cdbe77f Iustin Pop
        # local storage (i.e. one or more of the _[lr](host|port) is
1963 9cdbe77f Iustin Pop
        # None)
1964 1063abd1 Iustin Pop
        self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
1965 1063abd1 Iustin Pop
                          hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1966 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1967 9cdbe77f Iustin Pop
          break
1968 1063abd1 Iustin Pop
        else:
1969 1063abd1 Iustin Pop
          _ThrowError("drbd%d: network attach successful, but 'drbdsetup"
1970 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1971 9cdbe77f Iustin Pop
1972 a2cfdea2 Iustin Pop
    else:
1973 a2cfdea2 Iustin Pop
      minor = None
1974 a2cfdea2 Iustin Pop
1975 a2cfdea2 Iustin Pop
    self._SetFromMinor(minor)
1976 1063abd1 Iustin Pop
    if minor is None:
1977 1063abd1 Iustin Pop
      _ThrowError("drbd%d: cannot activate, unknown or unhandled reason",
1978 1063abd1 Iustin Pop
                  self._aminor)
1979 a2cfdea2 Iustin Pop
1980 2d0c8319 Iustin Pop
  def _FastAssemble(self):
1981 2d0c8319 Iustin Pop
    """Assemble the drbd device from zero.
1982 a2cfdea2 Iustin Pop

1983 2d0c8319 Iustin Pop
    This is run when in Assemble we detect our minor is unused.
1984 a2cfdea2 Iustin Pop

1985 a2cfdea2 Iustin Pop
    """
1986 a1578d63 Iustin Pop
    minor = self._aminor
1987 fc1dc9d7 Iustin Pop
    if self._children and self._children[0] and self._children[1]:
1988 1063abd1 Iustin Pop
      self._AssembleLocal(minor, self._children[0].dev_path,
1989 f069addf Iustin Pop
                          self._children[1].dev_path, self.size)
1990 a2cfdea2 Iustin Pop
    if self._lhost and self._lport and self._rhost and self._rport:
1991 1063abd1 Iustin Pop
      self._AssembleNet(minor,
1992 1063abd1 Iustin Pop
                        (self._lhost, self._lport, self._rhost, self._rport),
1993 1063abd1 Iustin Pop
                        constants.DRBD_NET_PROTOCOL,
1994 1063abd1 Iustin Pop
                        hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1995 a2cfdea2 Iustin Pop
    self._SetFromMinor(minor)
1996 a2cfdea2 Iustin Pop
1997 a2cfdea2 Iustin Pop
  @classmethod
1998 b00b95dd Iustin Pop
  def _ShutdownLocal(cls, minor):
1999 b00b95dd Iustin Pop
    """Detach from the local device.
2000 b00b95dd Iustin Pop

2001 b00b95dd Iustin Pop
    I/Os will continue to be served from the remote device. If we
2002 b00b95dd Iustin Pop
    don't have a remote device, this operation will fail.
2003 b00b95dd Iustin Pop

2004 b00b95dd Iustin Pop
    """
2005 b00b95dd Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "detach"])
2006 b00b95dd Iustin Pop
    if result.failed:
2007 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't detach local disk: %s", minor, result.output)
2008 b00b95dd Iustin Pop
2009 b00b95dd Iustin Pop
  @classmethod
2010 f3e513ad Iustin Pop
  def _ShutdownNet(cls, minor):
2011 f3e513ad Iustin Pop
    """Disconnect from the remote peer.
2012 f3e513ad Iustin Pop

2013 f3e513ad Iustin Pop
    This fails if we don't have a local device.
2014 f3e513ad Iustin Pop

2015 f3e513ad Iustin Pop
    """
2016 f3e513ad Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "disconnect"])
2017 a8459f1c Iustin Pop
    if result.failed:
2018 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't shutdown network: %s", minor, result.output)
2019 f3e513ad Iustin Pop
2020 f3e513ad Iustin Pop
  @classmethod
2021 a2cfdea2 Iustin Pop
  def _ShutdownAll(cls, minor):
2022 a2cfdea2 Iustin Pop
    """Deactivate the device.
2023 a2cfdea2 Iustin Pop

2024 a2cfdea2 Iustin Pop
    This will, of course, fail if the device is in use.
2025 a2cfdea2 Iustin Pop

2026 a2cfdea2 Iustin Pop
    """
2027 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "down"])
2028 a2cfdea2 Iustin Pop
    if result.failed:
2029 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: can't shutdown drbd device: %s",
2030 33bc6f01 Iustin Pop
                  minor, result.output)
2031 a2cfdea2 Iustin Pop
2032 a2cfdea2 Iustin Pop
  def Shutdown(self):
2033 a2cfdea2 Iustin Pop
    """Shutdown the DRBD device.
2034 a2cfdea2 Iustin Pop

2035 a2cfdea2 Iustin Pop
    """
2036 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
2037 746f7476 Iustin Pop
      logging.info("drbd%d: not attached during Shutdown()", self._aminor)
2038 746f7476 Iustin Pop
      return
2039 746f7476 Iustin Pop
    minor = self.minor
2040 a2cfdea2 Iustin Pop
    self.minor = None
2041 a2cfdea2 Iustin Pop
    self.dev_path = None
2042 746f7476 Iustin Pop
    self._ShutdownAll(minor)
2043 a2cfdea2 Iustin Pop
2044 a2cfdea2 Iustin Pop
  def Remove(self):
2045 a2cfdea2 Iustin Pop
    """Stub remove for DRBD devices.
2046 a2cfdea2 Iustin Pop

2047 a2cfdea2 Iustin Pop
    """
2048 0c6c04ec Iustin Pop
    self.Shutdown()
2049 a2cfdea2 Iustin Pop
2050 a2cfdea2 Iustin Pop
  @classmethod
2051 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
2052 a2cfdea2 Iustin Pop
    """Create a new DRBD8 device.
2053 a2cfdea2 Iustin Pop

2054 a2cfdea2 Iustin Pop
    Since DRBD devices are not created per se, just assembled, this
2055 a2cfdea2 Iustin Pop
    function only initializes the metadata.
2056 a2cfdea2 Iustin Pop

2057 a2cfdea2 Iustin Pop
    """
2058 a2cfdea2 Iustin Pop
    if len(children) != 2:
2059 a2cfdea2 Iustin Pop
      raise errors.ProgrammerError("Invalid setup for the drbd device")
2060 767d52d3 Iustin Pop
    # check that the minor is unused
2061 767d52d3 Iustin Pop
    aminor = unique_id[4]
2062 767d52d3 Iustin Pop
    proc_info = cls._MassageProcData(cls._GetProcData())
2063 767d52d3 Iustin Pop
    if aminor in proc_info:
2064 767d52d3 Iustin Pop
      status = DRBD8Status(proc_info[aminor])
2065 767d52d3 Iustin Pop
      in_use = status.is_in_use
2066 767d52d3 Iustin Pop
    else:
2067 767d52d3 Iustin Pop
      in_use = False
2068 767d52d3 Iustin Pop
    if in_use:
2069 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: minor is already in use at Create() time", aminor)
2070 a2cfdea2 Iustin Pop
    meta = children[1]
2071 a2cfdea2 Iustin Pop
    meta.Assemble()
2072 a2cfdea2 Iustin Pop
    if not meta.Attach():
2073 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: can't attach to meta device '%s'",
2074 33bc6f01 Iustin Pop
                  aminor, meta)
2075 9c793cfb Iustin Pop
    cls._CheckMetaSize(meta.dev_path)
2076 3b559640 Iustin Pop
    cls._InitMeta(aminor, meta.dev_path)
2077 94dcbdb0 Andrea Spadaccini
    return cls(unique_id, children, size, params)
2078 a2cfdea2 Iustin Pop
2079 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
2080 1005d816 Iustin Pop
    """Resize the DRBD device and its backing storage.
2081 1005d816 Iustin Pop

2082 1005d816 Iustin Pop
    """
2083 1005d816 Iustin Pop
    if self.minor is None:
2084 82463074 Iustin Pop
      _ThrowError("drbd%d: Grow called while not attached", self._aminor)
2085 1005d816 Iustin Pop
    if len(self._children) != 2 or None in self._children:
2086 82463074 Iustin Pop
      _ThrowError("drbd%d: cannot grow diskless device", self.minor)
2087 cad0723b Iustin Pop
    self._children[0].Grow(amount, dryrun, backingstore)
2088 cad0723b Iustin Pop
    if dryrun or backingstore:
2089 cad0723b Iustin Pop
      # DRBD does not support dry-run mode and is not backing storage,
2090 cad0723b Iustin Pop
      # so we'll return here
2091 7fe23d47 Iustin Pop
      return
2092 38256320 Iustin Pop
    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize", "-s",
2093 38256320 Iustin Pop
                           "%dm" % (self.size + amount)])
2094 1005d816 Iustin Pop
    if result.failed:
2095 82463074 Iustin Pop
      _ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
2096 1005d816 Iustin Pop
2097 a8083063 Iustin Pop
2098 6f695a2e Manuel Franceschini
class FileStorage(BlockDev):
2099 6f695a2e Manuel Franceschini
  """File device.
2100 abdf0113 Iustin Pop

2101 6f695a2e Manuel Franceschini
  This class represents the a file storage backend device.
2102 6f695a2e Manuel Franceschini

2103 6f695a2e Manuel Franceschini
  The unique_id for the file device is a (file_driver, file_path) tuple.
2104 abdf0113 Iustin Pop

2105 6f695a2e Manuel Franceschini
  """
2106 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
2107 6f695a2e Manuel Franceschini
    """Initalizes a file device backend.
2108 6f695a2e Manuel Franceschini

2109 6f695a2e Manuel Franceschini
    """
2110 6f695a2e Manuel Franceschini
    if children:
2111 6f695a2e Manuel Franceschini
      raise errors.BlockDeviceError("Invalid setup for file device")
2112 94dcbdb0 Andrea Spadaccini
    super(FileStorage, self).__init__(unique_id, children, size, params)
2113 6f695a2e Manuel Franceschini
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2114 6f695a2e Manuel Franceschini
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2115 6f695a2e Manuel Franceschini
    self.driver = unique_id[0]
2116 6f695a2e Manuel Franceschini
    self.dev_path = unique_id[1]
2117 ecb091e3 Iustin Pop
    self.Attach()
2118 6f695a2e Manuel Franceschini
2119 6f695a2e Manuel Franceschini
  def Assemble(self):
2120 6f695a2e Manuel Franceschini
    """Assemble the device.
2121 6f695a2e Manuel Franceschini

2122 6f695a2e Manuel Franceschini
    Checks whether the file device exists, raises BlockDeviceError otherwise.
2123 6f695a2e Manuel Franceschini

2124 6f695a2e Manuel Franceschini
    """
2125 6f695a2e Manuel Franceschini
    if not os.path.exists(self.dev_path):
2126 1063abd1 Iustin Pop
      _ThrowError("File device '%s' does not exist" % self.dev_path)
2127 6f695a2e Manuel Franceschini
2128 6f695a2e Manuel Franceschini
  def Shutdown(self):
2129 6f695a2e Manuel Franceschini
    """Shutdown the device.
2130 6f695a2e Manuel Franceschini

2131 5bbd3f7f Michael Hanselmann
    This is a no-op for the file type, as we don't deactivate
2132 6f695a2e Manuel Franceschini
    the file on shutdown.
2133 6f695a2e Manuel Franceschini

2134 6f695a2e Manuel Franceschini
    """
2135 746f7476 Iustin Pop
    pass
2136 6f695a2e Manuel Franceschini
2137 6f695a2e Manuel Franceschini
  def Open(self, force=False):
2138 6f695a2e Manuel Franceschini
    """Make the device ready for I/O.
2139 6f695a2e Manuel Franceschini

2140 6f695a2e Manuel Franceschini
    This is a no-op for the file type.
2141 6f695a2e Manuel Franceschini

2142 6f695a2e Manuel Franceschini
    """
2143 6f695a2e Manuel Franceschini
    pass
2144 6f695a2e Manuel Franceschini
2145 6f695a2e Manuel Franceschini
  def Close(self):
2146 6f695a2e Manuel Franceschini
    """Notifies that the device will no longer be used for I/O.
2147 6f695a2e Manuel Franceschini

2148 6f695a2e Manuel Franceschini
    This is a no-op for the file type.
2149 6f695a2e Manuel Franceschini

2150 6f695a2e Manuel Franceschini
    """
2151 6f695a2e Manuel Franceschini
    pass
2152 6f695a2e Manuel Franceschini
2153 6f695a2e Manuel Franceschini
  def Remove(self):
2154 6f695a2e Manuel Franceschini
    """Remove the file backing the block device.
2155 6f695a2e Manuel Franceschini

2156 c41eea6e Iustin Pop
    @rtype: boolean
2157 c41eea6e Iustin Pop
    @return: True if the removal was successful
2158 6f695a2e Manuel Franceschini

2159 6f695a2e Manuel Franceschini
    """
2160 6f695a2e Manuel Franceschini
    try:
2161 6f695a2e Manuel Franceschini
      os.remove(self.dev_path)
2162 6f695a2e Manuel Franceschini
    except OSError, err:
2163 0c6c04ec Iustin Pop
      if err.errno != errno.ENOENT:
2164 0c6c04ec Iustin Pop
        _ThrowError("Can't remove file '%s': %s", self.dev_path, err)
2165 6f695a2e Manuel Franceschini
2166 bbe4cc16 Iustin Pop
  def Rename(self, new_id):
2167 bbe4cc16 Iustin Pop
    """Renames the file.
2168 bbe4cc16 Iustin Pop

2169 bbe4cc16 Iustin Pop
    """
2170 bbe4cc16 Iustin Pop
    # TODO: implement rename for file-based storage
2171 bbe4cc16 Iustin Pop
    _ThrowError("Rename is not supported for file-based storage")
2172 bbe4cc16 Iustin Pop
2173 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
2174 bbe4cc16 Iustin Pop
    """Grow the file
2175 bbe4cc16 Iustin Pop

2176 bbe4cc16 Iustin Pop
    @param amount: the amount (in mebibytes) to grow with
2177 bbe4cc16 Iustin Pop

2178 bbe4cc16 Iustin Pop
    """
2179 cad0723b Iustin Pop
    if not backingstore:
2180 cad0723b Iustin Pop
      return
2181 91e2d9ec Guido Trotter
    # Check that the file exists
2182 91e2d9ec Guido Trotter
    self.Assemble()
2183 91e2d9ec Guido Trotter
    current_size = self.GetActualSize()
2184 91e2d9ec Guido Trotter
    new_size = current_size + amount * 1024 * 1024
2185 91e2d9ec Guido Trotter
    assert new_size > current_size, "Cannot Grow with a negative amount"
2186 7fe23d47 Iustin Pop
    # We can't really simulate the growth
2187 7fe23d47 Iustin Pop
    if dryrun:
2188 7fe23d47 Iustin Pop
      return
2189 91e2d9ec Guido Trotter
    try:
2190 91e2d9ec Guido Trotter
      f = open(self.dev_path, "a+")
2191 91e2d9ec Guido Trotter
      f.truncate(new_size)
2192 91e2d9ec Guido Trotter
      f.close()
2193 91e2d9ec Guido Trotter
    except EnvironmentError, err:
2194 91e2d9ec Guido Trotter
      _ThrowError("Error in file growth: %", str(err))
2195 bbe4cc16 Iustin Pop
2196 6f695a2e Manuel Franceschini
  def Attach(self):
2197 6f695a2e Manuel Franceschini
    """Attach to an existing file.
2198 6f695a2e Manuel Franceschini

2199 6f695a2e Manuel Franceschini
    Check if this file already exists.
2200 6f695a2e Manuel Franceschini

2201 c41eea6e Iustin Pop
    @rtype: boolean
2202 c41eea6e Iustin Pop
    @return: True if file exists
2203 6f695a2e Manuel Franceschini

2204 6f695a2e Manuel Franceschini
    """
2205 ecb091e3 Iustin Pop
    self.attached = os.path.exists(self.dev_path)
2206 ecb091e3 Iustin Pop
    return self.attached
2207 6f695a2e Manuel Franceschini
2208 fcff3897 Iustin Pop
  def GetActualSize(self):
2209 fcff3897 Iustin Pop
    """Return the actual disk size.
2210 fcff3897 Iustin Pop

2211 fcff3897 Iustin Pop
    @note: the device needs to be active when this is called
2212 fcff3897 Iustin Pop

2213 fcff3897 Iustin Pop
    """
2214 fcff3897 Iustin Pop
    assert self.attached, "BlockDevice not attached in GetActualSize()"
2215 fcff3897 Iustin Pop
    try:
2216 fcff3897 Iustin Pop
      st = os.stat(self.dev_path)
2217 fcff3897 Iustin Pop
      return st.st_size
2218 fcff3897 Iustin Pop
    except OSError, err:
2219 fcff3897 Iustin Pop
      _ThrowError("Can't stat %s: %s", self.dev_path, err)
2220 fcff3897 Iustin Pop
2221 6f695a2e Manuel Franceschini
  @classmethod
2222 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
2223 6f695a2e Manuel Franceschini
    """Create a new file.
2224 6f695a2e Manuel Franceschini

2225 c41eea6e Iustin Pop
    @param size: the size of file in MiB
2226 6f695a2e Manuel Franceschini

2227 c41eea6e Iustin Pop
    @rtype: L{bdev.FileStorage}
2228 c41eea6e Iustin Pop
    @return: an instance of FileStorage
2229 6f695a2e Manuel Franceschini

2230 6f695a2e Manuel Franceschini
    """
2231 6f695a2e Manuel Franceschini
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2232 6f695a2e Manuel Franceschini
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2233 6f695a2e Manuel Franceschini
    dev_path = unique_id[1]
2234 6f695a2e Manuel Franceschini
    try:
2235 cdeefd9b Guido Trotter
      fd = os.open(dev_path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
2236 cdeefd9b Guido Trotter
      f = os.fdopen(fd, "w")
2237 6f695a2e Manuel Franceschini
      f.truncate(size * 1024 * 1024)
2238 6f695a2e Manuel Franceschini
      f.close()
2239 cdeefd9b Guido Trotter
    except EnvironmentError, err:
2240 cdeefd9b Guido Trotter
      if err.errno == errno.EEXIST:
2241 cdeefd9b Guido Trotter
        _ThrowError("File already existing: %s", dev_path)
2242 82463074 Iustin Pop
      _ThrowError("Error in file creation: %", str(err))
2243 6f695a2e Manuel Franceschini
2244 94dcbdb0 Andrea Spadaccini
    return FileStorage(unique_id, children, size, params)
2245 6f695a2e Manuel Franceschini
2246 6f695a2e Manuel Franceschini
2247 b6135bbc Apollon Oikonomopoulos
class PersistentBlockDevice(BlockDev):
2248 b6135bbc Apollon Oikonomopoulos
  """A block device with persistent node
2249 b6135bbc Apollon Oikonomopoulos

2250 b6135bbc Apollon Oikonomopoulos
  May be either directly attached, or exposed through DM (e.g. dm-multipath).
2251 b6135bbc Apollon Oikonomopoulos
  udev helpers are probably required to give persistent, human-friendly
2252 b6135bbc Apollon Oikonomopoulos
  names.
2253 b6135bbc Apollon Oikonomopoulos

2254 b6135bbc Apollon Oikonomopoulos
  For the time being, pathnames are required to lie under /dev.
2255 b6135bbc Apollon Oikonomopoulos

2256 b6135bbc Apollon Oikonomopoulos
  """
2257 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
2258 b6135bbc Apollon Oikonomopoulos
    """Attaches to a static block device.
2259 b6135bbc Apollon Oikonomopoulos

2260 b6135bbc Apollon Oikonomopoulos
    The unique_id is a path under /dev.
2261 b6135bbc Apollon Oikonomopoulos

2262 b6135bbc Apollon Oikonomopoulos
    """
2263 94dcbdb0 Andrea Spadaccini
    super(PersistentBlockDevice, self).__init__(unique_id, children, size,
2264 94dcbdb0 Andrea Spadaccini
                                                params)
2265 b6135bbc Apollon Oikonomopoulos
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2266 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2267 b6135bbc Apollon Oikonomopoulos
    self.dev_path = unique_id[1]
2268 d0c8c01d Iustin Pop
    if not os.path.realpath(self.dev_path).startswith("/dev/"):
2269 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Full path '%s' lies outside /dev" %
2270 b6135bbc Apollon Oikonomopoulos
                              os.path.realpath(self.dev_path))
2271 b6135bbc Apollon Oikonomopoulos
    # TODO: this is just a safety guard checking that we only deal with devices
2272 b6135bbc Apollon Oikonomopoulos
    # we know how to handle. In the future this will be integrated with
2273 b6135bbc Apollon Oikonomopoulos
    # external storage backends and possible values will probably be collected
2274 b6135bbc Apollon Oikonomopoulos
    # from the cluster configuration.
2275 b6135bbc Apollon Oikonomopoulos
    if unique_id[0] != constants.BLOCKDEV_DRIVER_MANUAL:
2276 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Got persistent block device of invalid type: %s" %
2277 b6135bbc Apollon Oikonomopoulos
                       unique_id[0])
2278 b6135bbc Apollon Oikonomopoulos
2279 b6135bbc Apollon Oikonomopoulos
    self.major = self.minor = None
2280 b6135bbc Apollon Oikonomopoulos
    self.Attach()
2281 b6135bbc Apollon Oikonomopoulos
2282 b6135bbc Apollon Oikonomopoulos
  @classmethod
2283 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
2284 b6135bbc Apollon Oikonomopoulos
    """Create a new device
2285 b6135bbc Apollon Oikonomopoulos

2286 b6135bbc Apollon Oikonomopoulos
    This is a noop, we only return a PersistentBlockDevice instance
2287 b6135bbc Apollon Oikonomopoulos

2288 b6135bbc Apollon Oikonomopoulos
    """
2289 94dcbdb0 Andrea Spadaccini
    return PersistentBlockDevice(unique_id, children, 0, params)
2290 b6135bbc Apollon Oikonomopoulos
2291 b6135bbc Apollon Oikonomopoulos
  def Remove(self):
2292 b6135bbc Apollon Oikonomopoulos
    """Remove a device
2293 b6135bbc Apollon Oikonomopoulos

2294 b6135bbc Apollon Oikonomopoulos
    This is a noop
2295 b6135bbc Apollon Oikonomopoulos

2296 b6135bbc Apollon Oikonomopoulos
    """
2297 b6135bbc Apollon Oikonomopoulos
    pass
2298 b6135bbc Apollon Oikonomopoulos
2299 b6135bbc Apollon Oikonomopoulos
  def Rename(self, new_id):
2300 b6135bbc Apollon Oikonomopoulos
    """Rename this device.
2301 b6135bbc Apollon Oikonomopoulos

2302 b6135bbc Apollon Oikonomopoulos
    """
2303 b6135bbc Apollon Oikonomopoulos
    _ThrowError("Rename is not supported for PersistentBlockDev storage")
2304 b6135bbc Apollon Oikonomopoulos
2305 b6135bbc Apollon Oikonomopoulos
  def Attach(self):
2306 b6135bbc Apollon Oikonomopoulos
    """Attach to an existing block device.
2307 b6135bbc Apollon Oikonomopoulos

2308 b6135bbc Apollon Oikonomopoulos

2309 b6135bbc Apollon Oikonomopoulos
    """
2310 b6135bbc Apollon Oikonomopoulos
    self.attached = False
2311 b6135bbc Apollon Oikonomopoulos
    try:
2312 b6135bbc Apollon Oikonomopoulos
      st = os.stat(self.dev_path)
2313 b6135bbc Apollon Oikonomopoulos
    except OSError, err:
2314 b6135bbc Apollon Oikonomopoulos
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
2315 b6135bbc Apollon Oikonomopoulos
      return False
2316 b6135bbc Apollon Oikonomopoulos
2317 b6135bbc Apollon Oikonomopoulos
    if not stat.S_ISBLK(st.st_mode):
2318 b6135bbc Apollon Oikonomopoulos
      logging.error("%s is not a block device", self.dev_path)
2319 b6135bbc Apollon Oikonomopoulos
      return False
2320 b6135bbc Apollon Oikonomopoulos
2321 b6135bbc Apollon Oikonomopoulos
    self.major = os.major(st.st_rdev)
2322 b6135bbc Apollon Oikonomopoulos
    self.minor = os.minor(st.st_rdev)
2323 b6135bbc Apollon Oikonomopoulos
    self.attached = True
2324 b6135bbc Apollon Oikonomopoulos
2325 b6135bbc Apollon Oikonomopoulos
    return True
2326 b6135bbc Apollon Oikonomopoulos
2327 b6135bbc Apollon Oikonomopoulos
  def Assemble(self):
2328 b6135bbc Apollon Oikonomopoulos
    """Assemble the device.
2329 b6135bbc Apollon Oikonomopoulos

2330 b6135bbc Apollon Oikonomopoulos
    """
2331 b6135bbc Apollon Oikonomopoulos
    pass
2332 b6135bbc Apollon Oikonomopoulos
2333 b6135bbc Apollon Oikonomopoulos
  def Shutdown(self):
2334 b6135bbc Apollon Oikonomopoulos
    """Shutdown the device.
2335 b6135bbc Apollon Oikonomopoulos

2336 b6135bbc Apollon Oikonomopoulos
    """
2337 b6135bbc Apollon Oikonomopoulos
    pass
2338 b6135bbc Apollon Oikonomopoulos
2339 b6135bbc Apollon Oikonomopoulos
  def Open(self, force=False):
2340 b6135bbc Apollon Oikonomopoulos
    """Make the device ready for I/O.
2341 b6135bbc Apollon Oikonomopoulos

2342 b6135bbc Apollon Oikonomopoulos
    """
2343 b6135bbc Apollon Oikonomopoulos
    pass
2344 b6135bbc Apollon Oikonomopoulos
2345 b6135bbc Apollon Oikonomopoulos
  def Close(self):
2346 b6135bbc Apollon Oikonomopoulos
    """Notifies that the device will no longer be used for I/O.
2347 b6135bbc Apollon Oikonomopoulos

2348 b6135bbc Apollon Oikonomopoulos
    """
2349 b6135bbc Apollon Oikonomopoulos
    pass
2350 b6135bbc Apollon Oikonomopoulos
2351 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
2352 b6135bbc Apollon Oikonomopoulos
    """Grow the logical volume.
2353 b6135bbc Apollon Oikonomopoulos

2354 b6135bbc Apollon Oikonomopoulos
    """
2355 b6135bbc Apollon Oikonomopoulos
    _ThrowError("Grow is not supported for PersistentBlockDev storage")
2356 b6135bbc Apollon Oikonomopoulos
2357 b6135bbc Apollon Oikonomopoulos
2358 7181fba0 Constantinos Venetsanopoulos
class RADOSBlockDevice(BlockDev):
2359 7181fba0 Constantinos Venetsanopoulos
  """A RADOS Block Device (rbd).
2360 7181fba0 Constantinos Venetsanopoulos

2361 7181fba0 Constantinos Venetsanopoulos
  This class implements the RADOS Block Device for the backend. You need
2362 7181fba0 Constantinos Venetsanopoulos
  the rbd kernel driver, the RADOS Tools and a working RADOS cluster for
2363 7181fba0 Constantinos Venetsanopoulos
  this to be functional.
2364 7181fba0 Constantinos Venetsanopoulos

2365 7181fba0 Constantinos Venetsanopoulos
  """
2366 7181fba0 Constantinos Venetsanopoulos
  def __init__(self, unique_id, children, size, params):
2367 7181fba0 Constantinos Venetsanopoulos
    """Attaches to an rbd device.
2368 7181fba0 Constantinos Venetsanopoulos

2369 7181fba0 Constantinos Venetsanopoulos
    """
2370 7181fba0 Constantinos Venetsanopoulos
    super(RADOSBlockDevice, self).__init__(unique_id, children, size, params)
2371 7181fba0 Constantinos Venetsanopoulos
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2372 7181fba0 Constantinos Venetsanopoulos
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2373 7181fba0 Constantinos Venetsanopoulos
2374 7181fba0 Constantinos Venetsanopoulos
    self.driver, self.rbd_name = unique_id
2375 7181fba0 Constantinos Venetsanopoulos
2376 7181fba0 Constantinos Venetsanopoulos
    self.major = self.minor = None
2377 7181fba0 Constantinos Venetsanopoulos
    self.Attach()
2378 7181fba0 Constantinos Venetsanopoulos
2379 7181fba0 Constantinos Venetsanopoulos
  @classmethod
2380 7181fba0 Constantinos Venetsanopoulos
  def Create(cls, unique_id, children, size, params):
2381 7181fba0 Constantinos Venetsanopoulos
    """Create a new rbd device.
2382 7181fba0 Constantinos Venetsanopoulos

2383 7181fba0 Constantinos Venetsanopoulos
    Provision a new rbd volume inside a RADOS pool.
2384 7181fba0 Constantinos Venetsanopoulos

2385 7181fba0 Constantinos Venetsanopoulos
    """
2386 7181fba0 Constantinos Venetsanopoulos
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2387 7181fba0 Constantinos Venetsanopoulos
      raise errors.ProgrammerError("Invalid configuration data %s" %
2388 7181fba0 Constantinos Venetsanopoulos
                                   str(unique_id))
2389 7181fba0 Constantinos Venetsanopoulos
    rbd_pool = params[constants.LDP_POOL]
2390 7181fba0 Constantinos Venetsanopoulos
    rbd_name = unique_id[1]
2391 7181fba0 Constantinos Venetsanopoulos
2392 7181fba0 Constantinos Venetsanopoulos
    # Provision a new rbd volume (Image) inside the RADOS cluster.
2393 7181fba0 Constantinos Venetsanopoulos
    cmd = [constants.RBD_CMD, "create", "-p", rbd_pool,
2394 7181fba0 Constantinos Venetsanopoulos
           rbd_name, "--size", "%s" % size]
2395 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(cmd)
2396 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2397 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd creation failed (%s): %s",
2398 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2399 7181fba0 Constantinos Venetsanopoulos
2400 7181fba0 Constantinos Venetsanopoulos
    return RADOSBlockDevice(unique_id, children, size, params)
2401 7181fba0 Constantinos Venetsanopoulos
2402 7181fba0 Constantinos Venetsanopoulos
  def Remove(self):
2403 7181fba0 Constantinos Venetsanopoulos
    """Remove the rbd device.
2404 7181fba0 Constantinos Venetsanopoulos

2405 7181fba0 Constantinos Venetsanopoulos
    """
2406 7181fba0 Constantinos Venetsanopoulos
    rbd_pool = self.params[constants.LDP_POOL]
2407 7181fba0 Constantinos Venetsanopoulos
    rbd_name = self.unique_id[1]
2408 7181fba0 Constantinos Venetsanopoulos
2409 7181fba0 Constantinos Venetsanopoulos
    if not self.minor and not self.Attach():
2410 7181fba0 Constantinos Venetsanopoulos
      # The rbd device doesn't exist.
2411 7181fba0 Constantinos Venetsanopoulos
      return
2412 7181fba0 Constantinos Venetsanopoulos
2413 7181fba0 Constantinos Venetsanopoulos
    # First shutdown the device (remove mappings).
2414 7181fba0 Constantinos Venetsanopoulos
    self.Shutdown()
2415 7181fba0 Constantinos Venetsanopoulos
2416 7181fba0 Constantinos Venetsanopoulos
    # Remove the actual Volume (Image) from the RADOS cluster.
2417 7181fba0 Constantinos Venetsanopoulos
    cmd = [constants.RBD_CMD, "rm", "-p", rbd_pool, rbd_name]
2418 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(cmd)
2419 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2420 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("Can't remove Volume from cluster with rbd rm: %s - %s",
2421 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2422 7181fba0 Constantinos Venetsanopoulos
2423 7181fba0 Constantinos Venetsanopoulos
  def Rename(self, new_id):
2424 7181fba0 Constantinos Venetsanopoulos
    """Rename this device.
2425 7181fba0 Constantinos Venetsanopoulos

2426 7181fba0 Constantinos Venetsanopoulos
    """
2427 7181fba0 Constantinos Venetsanopoulos
    pass
2428 7181fba0 Constantinos Venetsanopoulos
2429 7181fba0 Constantinos Venetsanopoulos
  def Attach(self):
2430 7181fba0 Constantinos Venetsanopoulos
    """Attach to an existing rbd device.
2431 7181fba0 Constantinos Venetsanopoulos

2432 7181fba0 Constantinos Venetsanopoulos
    This method maps the rbd volume that matches our name with
2433 7181fba0 Constantinos Venetsanopoulos
    an rbd device and then attaches to this device.
2434 7181fba0 Constantinos Venetsanopoulos

2435 7181fba0 Constantinos Venetsanopoulos
    """
2436 7181fba0 Constantinos Venetsanopoulos
    self.attached = False
2437 7181fba0 Constantinos Venetsanopoulos
2438 7181fba0 Constantinos Venetsanopoulos
    # Map the rbd volume to a block device under /dev
2439 7181fba0 Constantinos Venetsanopoulos
    self.dev_path = self._MapVolumeToBlockdev(self.unique_id)
2440 7181fba0 Constantinos Venetsanopoulos
2441 7181fba0 Constantinos Venetsanopoulos
    try:
2442 7181fba0 Constantinos Venetsanopoulos
      st = os.stat(self.dev_path)
2443 7181fba0 Constantinos Venetsanopoulos
    except OSError, err:
2444 7181fba0 Constantinos Venetsanopoulos
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
2445 7181fba0 Constantinos Venetsanopoulos
      return False
2446 7181fba0 Constantinos Venetsanopoulos
2447 7181fba0 Constantinos Venetsanopoulos
    if not stat.S_ISBLK(st.st_mode):
2448 7181fba0 Constantinos Venetsanopoulos
      logging.error("%s is not a block device", self.dev_path)
2449 7181fba0 Constantinos Venetsanopoulos
      return False
2450 7181fba0 Constantinos Venetsanopoulos
2451 7181fba0 Constantinos Venetsanopoulos
    self.major = os.major(st.st_rdev)
2452 7181fba0 Constantinos Venetsanopoulos
    self.minor = os.minor(st.st_rdev)
2453 7181fba0 Constantinos Venetsanopoulos
    self.attached = True
2454 7181fba0 Constantinos Venetsanopoulos
2455 7181fba0 Constantinos Venetsanopoulos
    return True
2456 7181fba0 Constantinos Venetsanopoulos
2457 7181fba0 Constantinos Venetsanopoulos
  def _MapVolumeToBlockdev(self, unique_id):
2458 7181fba0 Constantinos Venetsanopoulos
    """Maps existing rbd volumes to block devices.
2459 7181fba0 Constantinos Venetsanopoulos

2460 7181fba0 Constantinos Venetsanopoulos
    This method should be idempotent if the mapping already exists.
2461 7181fba0 Constantinos Venetsanopoulos

2462 7181fba0 Constantinos Venetsanopoulos
    @rtype: string
2463 7181fba0 Constantinos Venetsanopoulos
    @return: the block device path that corresponds to the volume
2464 7181fba0 Constantinos Venetsanopoulos

2465 7181fba0 Constantinos Venetsanopoulos
    """
2466 7181fba0 Constantinos Venetsanopoulos
    pool = self.params[constants.LDP_POOL]
2467 7181fba0 Constantinos Venetsanopoulos
    name = unique_id[1]
2468 7181fba0 Constantinos Venetsanopoulos
2469 7181fba0 Constantinos Venetsanopoulos
    # Check if the mapping already exists.
2470 7181fba0 Constantinos Venetsanopoulos
    showmap_cmd = [constants.RBD_CMD, "showmapped", "-p", pool]
2471 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(showmap_cmd)
2472 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2473 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd showmapped failed (%s): %s",
2474 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2475 7181fba0 Constantinos Venetsanopoulos
2476 7181fba0 Constantinos Venetsanopoulos
    rbd_dev = self._ParseRbdShowmappedOutput(result.output, name)
2477 7181fba0 Constantinos Venetsanopoulos
2478 7181fba0 Constantinos Venetsanopoulos
    if rbd_dev:
2479 7181fba0 Constantinos Venetsanopoulos
      # The mapping exists. Return it.
2480 7181fba0 Constantinos Venetsanopoulos
      return rbd_dev
2481 7181fba0 Constantinos Venetsanopoulos
2482 7181fba0 Constantinos Venetsanopoulos
    # The mapping doesn't exist. Create it.
2483 7181fba0 Constantinos Venetsanopoulos
    map_cmd = [constants.RBD_CMD, "map", "-p", pool, name]
2484 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(map_cmd)
2485 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2486 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd map failed (%s): %s",
2487 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2488 7181fba0 Constantinos Venetsanopoulos
2489 7181fba0 Constantinos Venetsanopoulos
    # Find the corresponding rbd device.
2490 7181fba0 Constantinos Venetsanopoulos
    showmap_cmd = [constants.RBD_CMD, "showmapped", "-p", pool]
2491 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(showmap_cmd)
2492 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2493 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd map succeeded, but showmapped failed (%s): %s",
2494 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2495 7181fba0 Constantinos Venetsanopoulos
2496 7181fba0 Constantinos Venetsanopoulos
    rbd_dev = self._ParseRbdShowmappedOutput(result.output, name)
2497 7181fba0 Constantinos Venetsanopoulos
2498 7181fba0 Constantinos Venetsanopoulos
    if not rbd_dev:
2499 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd map succeeded, but could not find the rbd block"
2500 7181fba0 Constantinos Venetsanopoulos
                  " device in output of showmapped, for volume: %s", name)
2501 7181fba0 Constantinos Venetsanopoulos
2502 7181fba0 Constantinos Venetsanopoulos
    # The device was successfully mapped. Return it.
2503 7181fba0 Constantinos Venetsanopoulos
    return rbd_dev
2504 7181fba0 Constantinos Venetsanopoulos
2505 7181fba0 Constantinos Venetsanopoulos
  @staticmethod
2506 7181fba0 Constantinos Venetsanopoulos
  def _ParseRbdShowmappedOutput(output, volume_name):
2507 7181fba0 Constantinos Venetsanopoulos
    """Parse the output of `rbd showmapped'.
2508 7181fba0 Constantinos Venetsanopoulos

2509 7181fba0 Constantinos Venetsanopoulos
    This method parses the output of `rbd showmapped' and returns
2510 7181fba0 Constantinos Venetsanopoulos
    the rbd block device path (e.g. /dev/rbd0) that matches the
2511 7181fba0 Constantinos Venetsanopoulos
    given rbd volume.
2512 7181fba0 Constantinos Venetsanopoulos

2513 7181fba0 Constantinos Venetsanopoulos
    @type output: string
2514 7181fba0 Constantinos Venetsanopoulos
    @param output: the whole output of `rbd showmapped'
2515 7181fba0 Constantinos Venetsanopoulos
    @type volume_name: string
2516 7181fba0 Constantinos Venetsanopoulos
    @param volume_name: the name of the volume whose device we search for
2517 7181fba0 Constantinos Venetsanopoulos
    @rtype: string or None
2518 7181fba0 Constantinos Venetsanopoulos
    @return: block device path if the volume is mapped, else None
2519 7181fba0 Constantinos Venetsanopoulos

2520 7181fba0 Constantinos Venetsanopoulos
    """
2521 7181fba0 Constantinos Venetsanopoulos
    allfields = 5
2522 7181fba0 Constantinos Venetsanopoulos
    volumefield = 2
2523 7181fba0 Constantinos Venetsanopoulos
    devicefield = 4
2524 7181fba0 Constantinos Venetsanopoulos
2525 7181fba0 Constantinos Venetsanopoulos
    field_sep = "\t"
2526 7181fba0 Constantinos Venetsanopoulos
2527 7181fba0 Constantinos Venetsanopoulos
    lines = output.splitlines()
2528 7181fba0 Constantinos Venetsanopoulos
    splitted_lines = map(lambda l: l.split(field_sep), lines)
2529 7181fba0 Constantinos Venetsanopoulos
2530 7181fba0 Constantinos Venetsanopoulos
    # Check empty output.
2531 7181fba0 Constantinos Venetsanopoulos
    if not splitted_lines:
2532 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd showmapped returned empty output")
2533 7181fba0 Constantinos Venetsanopoulos
2534 7181fba0 Constantinos Venetsanopoulos
    # Check showmapped header line, to determine number of fields.
2535 7181fba0 Constantinos Venetsanopoulos
    field_cnt = len(splitted_lines[0])
2536 7181fba0 Constantinos Venetsanopoulos
    if field_cnt != allfields:
2537 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("Cannot parse rbd showmapped output because its format"
2538 7181fba0 Constantinos Venetsanopoulos
                  " seems to have changed; expected %s fields, found %s",
2539 7181fba0 Constantinos Venetsanopoulos
                  allfields, field_cnt)
2540 7181fba0 Constantinos Venetsanopoulos
2541 7181fba0 Constantinos Venetsanopoulos
    matched_lines = \
2542 7181fba0 Constantinos Venetsanopoulos
      filter(lambda l: len(l) == allfields and l[volumefield] == volume_name,
2543 7181fba0 Constantinos Venetsanopoulos
             splitted_lines)
2544 7181fba0 Constantinos Venetsanopoulos
2545 7181fba0 Constantinos Venetsanopoulos
    if len(matched_lines) > 1:
2546 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("The rbd volume %s is mapped more than once."
2547 7181fba0 Constantinos Venetsanopoulos
                  " This shouldn't happen, try to unmap the extra"
2548 7181fba0 Constantinos Venetsanopoulos
                  " devices manually.", volume_name)
2549 7181fba0 Constantinos Venetsanopoulos
2550 7181fba0 Constantinos Venetsanopoulos
    if matched_lines:
2551 7181fba0 Constantinos Venetsanopoulos
      # rbd block device found. Return it.
2552 7181fba0 Constantinos Venetsanopoulos
      rbd_dev = matched_lines[0][devicefield]
2553 7181fba0 Constantinos Venetsanopoulos
      return rbd_dev
2554 7181fba0 Constantinos Venetsanopoulos
2555 7181fba0 Constantinos Venetsanopoulos
    # The given volume is not mapped.
2556 7181fba0 Constantinos Venetsanopoulos
    return None
2557 7181fba0 Constantinos Venetsanopoulos
2558 7181fba0 Constantinos Venetsanopoulos
  def Assemble(self):
2559 7181fba0 Constantinos Venetsanopoulos
    """Assemble the device.
2560 7181fba0 Constantinos Venetsanopoulos

2561 7181fba0 Constantinos Venetsanopoulos
    """
2562 7181fba0 Constantinos Venetsanopoulos
    pass
2563 7181fba0 Constantinos Venetsanopoulos
2564 7181fba0 Constantinos Venetsanopoulos
  def Shutdown(self):
2565 7181fba0 Constantinos Venetsanopoulos
    """Shutdown the device.
2566 7181fba0 Constantinos Venetsanopoulos

2567 7181fba0 Constantinos Venetsanopoulos
    """
2568 7181fba0 Constantinos Venetsanopoulos
    if not self.minor and not self.Attach():
2569 7181fba0 Constantinos Venetsanopoulos
      # The rbd device doesn't exist.
2570 7181fba0 Constantinos Venetsanopoulos
      return
2571 7181fba0 Constantinos Venetsanopoulos
2572 7181fba0 Constantinos Venetsanopoulos
    # Unmap the block device from the Volume.
2573 7181fba0 Constantinos Venetsanopoulos
    self._UnmapVolumeFromBlockdev(self.unique_id)
2574 7181fba0 Constantinos Venetsanopoulos
2575 7181fba0 Constantinos Venetsanopoulos
    self.minor = None
2576 7181fba0 Constantinos Venetsanopoulos
    self.dev_path = None
2577 7181fba0 Constantinos Venetsanopoulos
2578 7181fba0 Constantinos Venetsanopoulos
  def _UnmapVolumeFromBlockdev(self, unique_id):
2579 7181fba0 Constantinos Venetsanopoulos
    """Unmaps the rbd device from the Volume it is mapped.
2580 7181fba0 Constantinos Venetsanopoulos

2581 7181fba0 Constantinos Venetsanopoulos
    Unmaps the rbd device from the Volume it was previously mapped to.
2582 7181fba0 Constantinos Venetsanopoulos
    This method should be idempotent if the Volume isn't mapped.
2583 7181fba0 Constantinos Venetsanopoulos

2584 7181fba0 Constantinos Venetsanopoulos
    """
2585 7181fba0 Constantinos Venetsanopoulos
    pool = self.params[constants.LDP_POOL]
2586 7181fba0 Constantinos Venetsanopoulos
    name = unique_id[1]
2587 7181fba0 Constantinos Venetsanopoulos
2588 7181fba0 Constantinos Venetsanopoulos
    # Check if the mapping already exists.
2589 7181fba0 Constantinos Venetsanopoulos
    showmap_cmd = [constants.RBD_CMD, "showmapped", "-p", pool]
2590 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(showmap_cmd)
2591 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2592 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd showmapped failed [during unmap](%s): %s",
2593 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2594 7181fba0 Constantinos Venetsanopoulos
2595 7181fba0 Constantinos Venetsanopoulos
    rbd_dev = self._ParseRbdShowmappedOutput(result.output, name)
2596 7181fba0 Constantinos Venetsanopoulos
2597 7181fba0 Constantinos Venetsanopoulos
    if rbd_dev:
2598 7181fba0 Constantinos Venetsanopoulos
      # The mapping exists. Unmap the rbd device.
2599 7181fba0 Constantinos Venetsanopoulos
      unmap_cmd = [constants.RBD_CMD, "unmap", "%s" % rbd_dev]
2600 7181fba0 Constantinos Venetsanopoulos
      result = utils.RunCmd(unmap_cmd)
2601 7181fba0 Constantinos Venetsanopoulos
      if result.failed:
2602 7181fba0 Constantinos Venetsanopoulos
        _ThrowError("rbd unmap failed (%s): %s",
2603 7181fba0 Constantinos Venetsanopoulos
                    result.fail_reason, result.output)
2604 7181fba0 Constantinos Venetsanopoulos
2605 7181fba0 Constantinos Venetsanopoulos
  def Open(self, force=False):
2606 7181fba0 Constantinos Venetsanopoulos
    """Make the device ready for I/O.
2607 7181fba0 Constantinos Venetsanopoulos

2608 7181fba0 Constantinos Venetsanopoulos
    """
2609 7181fba0 Constantinos Venetsanopoulos
    pass
2610 7181fba0 Constantinos Venetsanopoulos
2611 7181fba0 Constantinos Venetsanopoulos
  def Close(self):
2612 7181fba0 Constantinos Venetsanopoulos
    """Notifies that the device will no longer be used for I/O.
2613 7181fba0 Constantinos Venetsanopoulos

2614 7181fba0 Constantinos Venetsanopoulos
    """
2615 7181fba0 Constantinos Venetsanopoulos
    pass
2616 7181fba0 Constantinos Venetsanopoulos
2617 cad0723b Iustin Pop
  def Grow(self, amount, dryrun, backingstore):
2618 7181fba0 Constantinos Venetsanopoulos
    """Grow the Volume.
2619 7181fba0 Constantinos Venetsanopoulos

2620 7181fba0 Constantinos Venetsanopoulos
    @type amount: integer
2621 7181fba0 Constantinos Venetsanopoulos
    @param amount: the amount (in mebibytes) to grow with
2622 7181fba0 Constantinos Venetsanopoulos
    @type dryrun: boolean
2623 7181fba0 Constantinos Venetsanopoulos
    @param dryrun: whether to execute the operation in simulation mode
2624 7181fba0 Constantinos Venetsanopoulos
        only, without actually increasing the size
2625 7181fba0 Constantinos Venetsanopoulos

2626 7181fba0 Constantinos Venetsanopoulos
    """
2627 cad0723b Iustin Pop
    if not backingstore:
2628 cad0723b Iustin Pop
      return
2629 7181fba0 Constantinos Venetsanopoulos
    if not self.Attach():
2630 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("Can't attach to rbd device during Grow()")
2631 7181fba0 Constantinos Venetsanopoulos
2632 7181fba0 Constantinos Venetsanopoulos
    if dryrun:
2633 7181fba0 Constantinos Venetsanopoulos
      # the rbd tool does not support dry runs of resize operations.
2634 7181fba0 Constantinos Venetsanopoulos
      # Since rbd volumes are thinly provisioned, we assume
2635 7181fba0 Constantinos Venetsanopoulos
      # there is always enough free space for the operation.
2636 7181fba0 Constantinos Venetsanopoulos
      return
2637 7181fba0 Constantinos Venetsanopoulos
2638 7181fba0 Constantinos Venetsanopoulos
    rbd_pool = self.params[constants.LDP_POOL]
2639 7181fba0 Constantinos Venetsanopoulos
    rbd_name = self.unique_id[1]
2640 7181fba0 Constantinos Venetsanopoulos
    new_size = self.size + amount
2641 7181fba0 Constantinos Venetsanopoulos
2642 7181fba0 Constantinos Venetsanopoulos
    # Resize the rbd volume (Image) inside the RADOS cluster.
2643 7181fba0 Constantinos Venetsanopoulos
    cmd = [constants.RBD_CMD, "resize", "-p", rbd_pool,
2644 7181fba0 Constantinos Venetsanopoulos
           rbd_name, "--size", "%s" % new_size]
2645 7181fba0 Constantinos Venetsanopoulos
    result = utils.RunCmd(cmd)
2646 7181fba0 Constantinos Venetsanopoulos
    if result.failed:
2647 7181fba0 Constantinos Venetsanopoulos
      _ThrowError("rbd resize failed (%s): %s",
2648 7181fba0 Constantinos Venetsanopoulos
                  result.fail_reason, result.output)
2649 7181fba0 Constantinos Venetsanopoulos
2650 7181fba0 Constantinos Venetsanopoulos
2651 a8083063 Iustin Pop
DEV_MAP = {
2652 fe96220b Iustin Pop
  constants.LD_LV: LogicalVolume,
2653 a1f445d3 Iustin Pop
  constants.LD_DRBD8: DRBD8,
2654 b6135bbc Apollon Oikonomopoulos
  constants.LD_BLOCKDEV: PersistentBlockDevice,
2655 7181fba0 Constantinos Venetsanopoulos
  constants.LD_RBD: RADOSBlockDevice,
2656 a8083063 Iustin Pop
  }
2657 a8083063 Iustin Pop
2658 4b97f902 Apollon Oikonomopoulos
if constants.ENABLE_FILE_STORAGE or constants.ENABLE_SHARED_FILE_STORAGE:
2659 cb7c0198 Iustin Pop
  DEV_MAP[constants.LD_FILE] = FileStorage
2660 cb7c0198 Iustin Pop
2661 a8083063 Iustin Pop
2662 94dcbdb0 Andrea Spadaccini
def _VerifyDiskType(dev_type):
2663 94dcbdb0 Andrea Spadaccini
  if dev_type not in DEV_MAP:
2664 94dcbdb0 Andrea Spadaccini
    raise errors.ProgrammerError("Invalid block device type '%s'" % dev_type)
2665 94dcbdb0 Andrea Spadaccini
2666 94dcbdb0 Andrea Spadaccini
2667 5ff82cc9 René Nussbaumer
def _VerifyDiskParams(disk):
2668 5ff82cc9 René Nussbaumer
  """Verifies if all disk parameters are set.
2669 5ff82cc9 René Nussbaumer

2670 5ff82cc9 René Nussbaumer
  """
2671 5ff82cc9 René Nussbaumer
  missing = set(constants.DISK_LD_DEFAULTS[disk.dev_type]) - set(disk.params)
2672 5ff82cc9 René Nussbaumer
  if missing:
2673 5ff82cc9 René Nussbaumer
    raise errors.ProgrammerError("Block device is missing disk parameters: %s" %
2674 5ff82cc9 René Nussbaumer
                                 missing)
2675 5ff82cc9 René Nussbaumer
2676 5ff82cc9 René Nussbaumer
2677 94dcbdb0 Andrea Spadaccini
def FindDevice(disk, children):
2678 a8083063 Iustin Pop
  """Search for an existing, assembled device.
2679 a8083063 Iustin Pop

2680 a8083063 Iustin Pop
  This will succeed only if the device exists and is assembled, but it
2681 a8083063 Iustin Pop
  does not do any actions in order to activate the device.
2682 a8083063 Iustin Pop

2683 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2684 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to find
2685 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2686 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2687 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2688 94dcbdb0 Andrea Spadaccini

2689 a8083063 Iustin Pop
  """
2690 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2691 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type](disk.physical_id, children, disk.size,
2692 c7c6606d René Nussbaumer
                                  disk.params)
2693 cb999543 Iustin Pop
  if not device.attached:
2694 a8083063 Iustin Pop
    return None
2695 ecb091e3 Iustin Pop
  return device
2696 a8083063 Iustin Pop
2697 a8083063 Iustin Pop
2698 94dcbdb0 Andrea Spadaccini
def Assemble(disk, children):
2699 a8083063 Iustin Pop
  """Try to attach or assemble an existing device.
2700 a8083063 Iustin Pop

2701 f96e3c4f Iustin Pop
  This will attach to assemble the device, as needed, to bring it
2702 f96e3c4f Iustin Pop
  fully up. It must be safe to run on already-assembled devices.
2703 a8083063 Iustin Pop

2704 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2705 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to assemble
2706 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2707 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2708 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2709 94dcbdb0 Andrea Spadaccini

2710 a8083063 Iustin Pop
  """
2711 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2712 5ff82cc9 René Nussbaumer
  _VerifyDiskParams(disk)
2713 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type](disk.physical_id, children, disk.size,
2714 c7c6606d René Nussbaumer
                                  disk.params)
2715 1063abd1 Iustin Pop
  device.Assemble()
2716 a8083063 Iustin Pop
  return device
2717 a8083063 Iustin Pop
2718 a8083063 Iustin Pop
2719 94dcbdb0 Andrea Spadaccini
def Create(disk, children):
2720 a8083063 Iustin Pop
  """Create a device.
2721 a8083063 Iustin Pop

2722 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2723 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to create
2724 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2725 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2726 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2727 94dcbdb0 Andrea Spadaccini

2728 a8083063 Iustin Pop
  """
2729 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2730 5ff82cc9 René Nussbaumer
  _VerifyDiskParams(disk)
2731 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type].Create(disk.physical_id, children, disk.size,
2732 c7c6606d René Nussbaumer
                                         disk.params)
2733 a8083063 Iustin Pop
  return device