Statistics
| Branch: | Tag: | Revision:

root / lib / bdev.py @ 0ec2ce46

History | View | Annotate | Download (75.8 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 4b97f902 Apollon Oikonomopoulos
# Copyright (C) 2006, 2007, 2010, 2011 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 b6135bbc Apollon Oikonomopoulos
import stat
28 a2cfdea2 Iustin Pop
import pyparsing as pyp
29 6f695a2e Manuel Franceschini
import os
30 468c5f77 Iustin Pop
import logging
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import utils
33 a8083063 Iustin Pop
from ganeti import errors
34 fe96220b Iustin Pop
from ganeti import constants
35 96acbc09 Michael Hanselmann
from ganeti import objects
36 cea881e5 Michael Hanselmann
from ganeti import compat
37 a744b676 Manuel Franceschini
from ganeti import netutils
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
40 310fbb64 Iustin Pop
# Size of reads in _CanReadDevice
41 310fbb64 Iustin Pop
_DEVICE_READ_SIZE = 128 * 1024
42 310fbb64 Iustin Pop
43 310fbb64 Iustin Pop
44 82463074 Iustin Pop
def _IgnoreError(fn, *args, **kwargs):
45 82463074 Iustin Pop
  """Executes the given function, ignoring BlockDeviceErrors.
46 82463074 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

220 a8083063 Iustin Pop
    """
221 a8083063 Iustin Pop
    raise NotImplementedError
222 a8083063 Iustin Pop
223 a8083063 Iustin Pop
  def SetSyncSpeed(self, speed):
224 a8083063 Iustin Pop
    """Adjust the sync speed of the mirror.
225 a8083063 Iustin Pop

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

228 a8083063 Iustin Pop
    """
229 a8083063 Iustin Pop
    result = True
230 a8083063 Iustin Pop
    if self._children:
231 a8083063 Iustin Pop
      for child in self._children:
232 a8083063 Iustin Pop
        result = result and child.SetSyncSpeed(speed)
233 a8083063 Iustin Pop
    return result
234 a8083063 Iustin Pop
235 a3fffcc6 Renรฉ Nussbaumer
  def PauseResumeSync(self, pause):
236 a3fffcc6 Renรฉ Nussbaumer
    """Pause/Resume the sync of the mirror.
237 a3fffcc6 Renรฉ Nussbaumer

238 a3fffcc6 Renรฉ Nussbaumer
    In case this is not a mirroring device, this is no-op.
239 a3fffcc6 Renรฉ Nussbaumer

240 a3fffcc6 Renรฉ Nussbaumer
    @param pause: Wheater to pause or resume
241 a3fffcc6 Renรฉ Nussbaumer

242 a3fffcc6 Renรฉ Nussbaumer
    """
243 a3fffcc6 Renรฉ Nussbaumer
    result = True
244 a3fffcc6 Renรฉ Nussbaumer
    if self._children:
245 a3fffcc6 Renรฉ Nussbaumer
      for child in self._children:
246 a3fffcc6 Renรฉ Nussbaumer
        result = result and child.PauseResumeSync(pause)
247 a3fffcc6 Renรฉ Nussbaumer
    return result
248 a3fffcc6 Renรฉ Nussbaumer
249 a8083063 Iustin Pop
  def GetSyncStatus(self):
250 a8083063 Iustin Pop
    """Returns the sync status of the device.
251 a8083063 Iustin Pop

252 a8083063 Iustin Pop
    If this device is a mirroring device, this function returns the
253 a8083063 Iustin Pop
    status of the mirror.
254 a8083063 Iustin Pop

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

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

260 a8083063 Iustin Pop
    If is_degraded is True, it means the device is missing
261 a8083063 Iustin Pop
    redundancy. This is usually a sign that something went wrong in
262 a8083063 Iustin Pop
    the device setup, if sync_percent is None.
263 a8083063 Iustin Pop

264 0834c866 Iustin Pop
    The ldisk parameter represents the degradation of the local
265 0834c866 Iustin Pop
    data. This is only valid for some devices, the rest will always
266 0834c866 Iustin Pop
    return False (not degraded).
267 0834c866 Iustin Pop

268 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
269 c41eea6e Iustin Pop

270 a8083063 Iustin Pop
    """
271 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
272 96acbc09 Michael Hanselmann
                                  major=self.major,
273 96acbc09 Michael Hanselmann
                                  minor=self.minor,
274 96acbc09 Michael Hanselmann
                                  sync_percent=None,
275 96acbc09 Michael Hanselmann
                                  estimated_time=None,
276 96acbc09 Michael Hanselmann
                                  is_degraded=False,
277 f208978a Michael Hanselmann
                                  ldisk_status=constants.LDS_OKAY)
278 a8083063 Iustin Pop
279 a8083063 Iustin Pop
  def CombinedSyncStatus(self):
280 a8083063 Iustin Pop
    """Calculate the mirror status recursively for our children.
281 a8083063 Iustin Pop

282 a8083063 Iustin Pop
    The return value is the same as for `GetSyncStatus()` except the
283 a8083063 Iustin Pop
    minimum percent and maximum time are calculated across our
284 a8083063 Iustin Pop
    children.
285 a8083063 Iustin Pop

286 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
287 96acbc09 Michael Hanselmann

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

328 a0c3fea1 Michael Hanselmann
    Only supported for some device types.
329 a0c3fea1 Michael Hanselmann

330 a0c3fea1 Michael Hanselmann
    """
331 a0c3fea1 Michael Hanselmann
    for child in self._children:
332 a0c3fea1 Michael Hanselmann
      child.SetInfo(text)
333 a0c3fea1 Michael Hanselmann
334 7fe23d47 Iustin Pop
  def Grow(self, amount, dryrun):
335 1005d816 Iustin Pop
    """Grow the block device.
336 1005d816 Iustin Pop

337 7fe23d47 Iustin Pop
    @type amount: integer
338 c41eea6e Iustin Pop
    @param amount: the amount (in mebibytes) to grow with
339 7fe23d47 Iustin Pop
    @type dryrun: boolean
340 7fe23d47 Iustin Pop
    @param dryrun: whether to execute the operation in simulation mode
341 7fe23d47 Iustin Pop
        only, without actually increasing the size
342 1005d816 Iustin Pop

343 1005d816 Iustin Pop
    """
344 1005d816 Iustin Pop
    raise NotImplementedError
345 a0c3fea1 Michael Hanselmann
346 fcff3897 Iustin Pop
  def GetActualSize(self):
347 fcff3897 Iustin Pop
    """Return the actual disk size.
348 fcff3897 Iustin Pop

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

351 fcff3897 Iustin Pop
    """
352 fcff3897 Iustin Pop
    assert self.attached, "BlockDevice not attached in GetActualSize()"
353 fcff3897 Iustin Pop
    result = utils.RunCmd(["blockdev", "--getsize64", self.dev_path])
354 fcff3897 Iustin Pop
    if result.failed:
355 fcff3897 Iustin Pop
      _ThrowError("blockdev failed (%s): %s",
356 fcff3897 Iustin Pop
                  result.fail_reason, result.output)
357 fcff3897 Iustin Pop
    try:
358 fcff3897 Iustin Pop
      sz = int(result.output.strip())
359 fcff3897 Iustin Pop
    except (ValueError, TypeError), err:
360 fcff3897 Iustin Pop
      _ThrowError("Failed to parse blockdev output: %s", str(err))
361 fcff3897 Iustin Pop
    return sz
362 fcff3897 Iustin Pop
363 a8083063 Iustin Pop
  def __repr__(self):
364 a8083063 Iustin Pop
    return ("<%s: unique_id: %s, children: %s, %s:%s, %s>" %
365 a8083063 Iustin Pop
            (self.__class__, self.unique_id, self._children,
366 a8083063 Iustin Pop
             self.major, self.minor, self.dev_path))
367 a8083063 Iustin Pop
368 a8083063 Iustin Pop
369 a8083063 Iustin Pop
class LogicalVolume(BlockDev):
370 a8083063 Iustin Pop
  """Logical Volume block device.
371 a8083063 Iustin Pop

372 a8083063 Iustin Pop
  """
373 6136f8f0 Iustin Pop
  _VALID_NAME_RE = re.compile("^[a-zA-Z0-9+_.-]*$")
374 6136f8f0 Iustin Pop
  _INVALID_NAMES = frozenset([".", "..", "snapshot", "pvmove"])
375 6136f8f0 Iustin Pop
  _INVALID_SUBSTRINGS = frozenset(["_mlog", "_mimage"])
376 6136f8f0 Iustin Pop
377 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
378 a8083063 Iustin Pop
    """Attaches to a LV device.
379 a8083063 Iustin Pop

380 a8083063 Iustin Pop
    The unique_id is a tuple (vg_name, lv_name)
381 a8083063 Iustin Pop

382 a8083063 Iustin Pop
    """
383 94dcbdb0 Andrea Spadaccini
    super(LogicalVolume, self).__init__(unique_id, children, size, params)
384 a8083063 Iustin Pop
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
385 a8083063 Iustin Pop
      raise ValueError("Invalid configuration data %s" % str(unique_id))
386 a8083063 Iustin Pop
    self._vg_name, self._lv_name = unique_id
387 6136f8f0 Iustin Pop
    self._ValidateName(self._vg_name)
388 6136f8f0 Iustin Pop
    self._ValidateName(self._lv_name)
389 6136f8f0 Iustin Pop
    self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
390 99e8295c Iustin Pop
    self._degraded = True
391 38256320 Iustin Pop
    self.major = self.minor = self.pe_size = self.stripe_count = None
392 a8083063 Iustin Pop
    self.Attach()
393 a8083063 Iustin Pop
394 a8083063 Iustin Pop
  @classmethod
395 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
396 a8083063 Iustin Pop
    """Create a new logical volume.
397 a8083063 Iustin Pop

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

447 197478f2 Renรฉ Nussbaumer
    @param lvm_cmd: Should be one of "pvs", "vgs" or "lvs"
448 197478f2 Renรฉ Nussbaumer
    @param fields: Fields to return
449 197478f2 Renรฉ Nussbaumer
    @return: A list of dicts each with the parsed fields
450 197478f2 Renรฉ Nussbaumer

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

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

483 c41eea6e Iustin Pop
    @rtype: list
484 c41eea6e Iustin Pop
    @return: list of tuples (free_space, name) with free_space in mebibytes
485 098c0958 Michael Hanselmann

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

510 197478f2 Renรฉ Nussbaumer
    @param vg_names: list of volume group names, if empty all will be returned
511 197478f2 Renรฉ Nussbaumer
    @param filter_readonly: whether to skip over readonly VGs
512 197478f2 Renรฉ Nussbaumer

513 197478f2 Renรฉ Nussbaumer
    @rtype: list
514 673cd9c4 Renรฉ Nussbaumer
    @return: list of tuples (free_space, total_size, name) with free_space in
515 673cd9c4 Renรฉ Nussbaumer
             MiB
516 197478f2 Renรฉ Nussbaumer

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

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

545 6136f8f0 Iustin Pop
    """
546 6136f8f0 Iustin Pop
    if (not cls._VALID_NAME_RE.match(name) or
547 6136f8f0 Iustin Pop
        name in cls._INVALID_NAMES or
548 403f5172 Guido Trotter
        compat.any(substring in name for substring in cls._INVALID_SUBSTRINGS)):
549 6136f8f0 Iustin Pop
      _ThrowError("Invalid LVM name '%s'", name)
550 6136f8f0 Iustin Pop
551 a8083063 Iustin Pop
  def Remove(self):
552 a8083063 Iustin Pop
    """Remove this logical volume.
553 a8083063 Iustin Pop

554 a8083063 Iustin Pop
    """
555 a8083063 Iustin Pop
    if not self.minor and not self.Attach():
556 a8083063 Iustin Pop
      # the LV does not exist
557 0c6c04ec Iustin Pop
      return
558 a8083063 Iustin Pop
    result = utils.RunCmd(["lvremove", "-f", "%s/%s" %
559 a8083063 Iustin Pop
                           (self._vg_name, self._lv_name)])
560 a8083063 Iustin Pop
    if result.failed:
561 0c6c04ec Iustin Pop
      _ThrowError("Can't lvremove: %s - %s", result.fail_reason, result.output)
562 a8083063 Iustin Pop
563 f3e513ad Iustin Pop
  def Rename(self, new_id):
564 f3e513ad Iustin Pop
    """Rename this logical volume.
565 f3e513ad Iustin Pop

566 f3e513ad Iustin Pop
    """
567 f3e513ad Iustin Pop
    if not isinstance(new_id, (tuple, list)) or len(new_id) != 2:
568 f3e513ad Iustin Pop
      raise errors.ProgrammerError("Invalid new logical id '%s'" % new_id)
569 f3e513ad Iustin Pop
    new_vg, new_name = new_id
570 f3e513ad Iustin Pop
    if new_vg != self._vg_name:
571 f3e513ad Iustin Pop
      raise errors.ProgrammerError("Can't move a logical volume across"
572 f3e513ad Iustin Pop
                                   " volume groups (from %s to to %s)" %
573 f3e513ad Iustin Pop
                                   (self._vg_name, new_vg))
574 f3e513ad Iustin Pop
    result = utils.RunCmd(["lvrename", new_vg, self._lv_name, new_name])
575 f3e513ad Iustin Pop
    if result.failed:
576 82463074 Iustin Pop
      _ThrowError("Failed to rename the logical volume: %s", result.output)
577 be345db0 Iustin Pop
    self._lv_name = new_name
578 6136f8f0 Iustin Pop
    self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
579 be345db0 Iustin Pop
580 a8083063 Iustin Pop
  def Attach(self):
581 a8083063 Iustin Pop
    """Attach to an existing LV.
582 a8083063 Iustin Pop

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

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

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

652 a8083063 Iustin Pop
    """
653 5574047a Iustin Pop
    result = utils.RunCmd(["lvchange", "-ay", self.dev_path])
654 5574047a Iustin Pop
    if result.failed:
655 1063abd1 Iustin Pop
      _ThrowError("Can't activate lv %s: %s", self.dev_path, result.output)
656 a8083063 Iustin Pop
657 a8083063 Iustin Pop
  def Shutdown(self):
658 a8083063 Iustin Pop
    """Shutdown the device.
659 a8083063 Iustin Pop

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

663 a8083063 Iustin Pop
    """
664 746f7476 Iustin Pop
    pass
665 a8083063 Iustin Pop
666 9db6dbce Iustin Pop
  def GetSyncStatus(self):
667 9db6dbce Iustin Pop
    """Returns the sync status of the device.
668 9db6dbce Iustin Pop

669 9db6dbce Iustin Pop
    If this device is a mirroring device, this function returns the
670 9db6dbce Iustin Pop
    status of the mirror.
671 9db6dbce Iustin Pop

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

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

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

685 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
686 c41eea6e Iustin Pop

687 9db6dbce Iustin Pop
    """
688 f208978a Michael Hanselmann
    if self._degraded:
689 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_FAULTY
690 f208978a Michael Hanselmann
    else:
691 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_OKAY
692 f208978a Michael Hanselmann
693 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
694 96acbc09 Michael Hanselmann
                                  major=self.major,
695 96acbc09 Michael Hanselmann
                                  minor=self.minor,
696 96acbc09 Michael Hanselmann
                                  sync_percent=None,
697 96acbc09 Michael Hanselmann
                                  estimated_time=None,
698 96acbc09 Michael Hanselmann
                                  is_degraded=self._degraded,
699 f208978a Michael Hanselmann
                                  ldisk_status=ldisk_status)
700 9db6dbce Iustin Pop
701 a8083063 Iustin Pop
  def Open(self, force=False):
702 a8083063 Iustin Pop
    """Make the device ready for I/O.
703 a8083063 Iustin Pop

704 a8083063 Iustin Pop
    This is a no-op for the LV device type.
705 a8083063 Iustin Pop

706 a8083063 Iustin Pop
    """
707 fdbd668d Iustin Pop
    pass
708 a8083063 Iustin Pop
709 a8083063 Iustin Pop
  def Close(self):
710 a8083063 Iustin Pop
    """Notifies that the device will no longer be used for I/O.
711 a8083063 Iustin Pop

712 a8083063 Iustin Pop
    This is a no-op for the LV device type.
713 a8083063 Iustin Pop

714 a8083063 Iustin Pop
    """
715 fdbd668d Iustin Pop
    pass
716 a8083063 Iustin Pop
717 a8083063 Iustin Pop
  def Snapshot(self, size):
718 a8083063 Iustin Pop
    """Create a snapshot copy of an lvm block device.
719 a8083063 Iustin Pop

720 800ac399 Iustin Pop
    @returns: tuple (vg, lv)
721 800ac399 Iustin Pop

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

748 a0c3fea1 Michael Hanselmann
    """
749 a0c3fea1 Michael Hanselmann
    BlockDev.SetInfo(self, text)
750 a0c3fea1 Michael Hanselmann
751 a0c3fea1 Michael Hanselmann
    # Replace invalid characters
752 d0c8c01d Iustin Pop
    text = re.sub("^[^A-Za-z0-9_+.]", "_", text)
753 d0c8c01d Iustin Pop
    text = re.sub("[^-A-Za-z0-9_+.]", "_", text)
754 a0c3fea1 Michael Hanselmann
755 a0c3fea1 Michael Hanselmann
    # Only up to 128 characters are allowed
756 a0c3fea1 Michael Hanselmann
    text = text[:128]
757 a0c3fea1 Michael Hanselmann
758 a0c3fea1 Michael Hanselmann
    result = utils.RunCmd(["lvchange", "--addtag", text,
759 a0c3fea1 Michael Hanselmann
                           self.dev_path])
760 a0c3fea1 Michael Hanselmann
    if result.failed:
761 82463074 Iustin Pop
      _ThrowError("Command: %s error: %s - %s", result.cmd, result.fail_reason,
762 82463074 Iustin Pop
                  result.output)
763 82463074 Iustin Pop
764 7fe23d47 Iustin Pop
  def Grow(self, amount, dryrun):
765 1005d816 Iustin Pop
    """Grow the logical volume.
766 1005d816 Iustin Pop

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

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

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

900 0f7f32d9 Iustin Pop
  This class contains a few bits of common functionality between the
901 0f7f32d9 Iustin Pop
  0.7 and 8.x versions of DRBD.
902 0f7f32d9 Iustin Pop

903 abdf0113 Iustin Pop
  """
904 fcee765d Manuel Franceschini
  _VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.\d+)?"
905 abdf0113 Iustin Pop
                           r" \(api:(\d+)/proto:(\d+)(?:-(\d+))?\)")
906 9122e60a Iustin Pop
  _VALID_LINE_RE = re.compile("^ *([0-9]+): cs:([^ ]+).*$")
907 9122e60a Iustin Pop
  _UNUSED_LINE_RE = re.compile("^ *([0-9]+): cs:Unconfigured$")
908 a8083063 Iustin Pop
909 abdf0113 Iustin Pop
  _DRBD_MAJOR = 147
910 abdf0113 Iustin Pop
  _ST_UNCONFIGURED = "Unconfigured"
911 abdf0113 Iustin Pop
  _ST_WFCONNECTION = "WFConnection"
912 abdf0113 Iustin Pop
  _ST_CONNECTED = "Connected"
913 a8083063 Iustin Pop
914 6b90c22e Iustin Pop
  _STATUS_FILE = "/proc/drbd"
915 549071a0 Luca Bigliardi
  _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
916 6b90c22e Iustin Pop
917 abdf0113 Iustin Pop
  @staticmethod
918 6b90c22e Iustin Pop
  def _GetProcData(filename=_STATUS_FILE):
919 abdf0113 Iustin Pop
    """Return data from /proc/drbd.
920 a8083063 Iustin Pop

921 a8083063 Iustin Pop
    """
922 abdf0113 Iustin Pop
    try:
923 13998ef2 Michael Hanselmann
      data = utils.ReadFile(filename).splitlines()
924 f6eaed12 Iustin Pop
    except EnvironmentError, err:
925 f6eaed12 Iustin Pop
      if err.errno == errno.ENOENT:
926 f6eaed12 Iustin Pop
        _ThrowError("The file %s cannot be opened, check if the module"
927 f6eaed12 Iustin Pop
                    " is loaded (%s)", filename, str(err))
928 f6eaed12 Iustin Pop
      else:
929 f6eaed12 Iustin Pop
        _ThrowError("Can't read the DRBD proc file %s: %s", filename, str(err))
930 abdf0113 Iustin Pop
    if not data:
931 82463074 Iustin Pop
      _ThrowError("Can't read any data from %s", filename)
932 abdf0113 Iustin Pop
    return data
933 a8083063 Iustin Pop
934 9122e60a Iustin Pop
  @classmethod
935 9122e60a Iustin Pop
  def _MassageProcData(cls, data):
936 abdf0113 Iustin Pop
    """Transform the output of _GetProdData into a nicer form.
937 a8083063 Iustin Pop

938 c41eea6e Iustin Pop
    @return: a dictionary of minor: joined lines from /proc/drbd
939 c41eea6e Iustin Pop
        for that minor
940 a8083063 Iustin Pop

941 a8083063 Iustin Pop
    """
942 abdf0113 Iustin Pop
    results = {}
943 abdf0113 Iustin Pop
    old_minor = old_line = None
944 abdf0113 Iustin Pop
    for line in data:
945 67d101d4 Iustin Pop
      if not line: # completely empty lines, as can be returned by drbd8.0+
946 67d101d4 Iustin Pop
        continue
947 9122e60a Iustin Pop
      lresult = cls._VALID_LINE_RE.match(line)
948 abdf0113 Iustin Pop
      if lresult is not None:
949 abdf0113 Iustin Pop
        if old_minor is not None:
950 abdf0113 Iustin Pop
          results[old_minor] = old_line
951 abdf0113 Iustin Pop
        old_minor = int(lresult.group(1))
952 abdf0113 Iustin Pop
        old_line = line
953 abdf0113 Iustin Pop
      else:
954 abdf0113 Iustin Pop
        if old_minor is not None:
955 abdf0113 Iustin Pop
          old_line += " " + line.strip()
956 abdf0113 Iustin Pop
    # add last line
957 abdf0113 Iustin Pop
    if old_minor is not None:
958 abdf0113 Iustin Pop
      results[old_minor] = old_line
959 abdf0113 Iustin Pop
    return results
960 a8083063 Iustin Pop
961 abdf0113 Iustin Pop
  @classmethod
962 fcee765d Manuel Franceschini
  def _GetVersion(cls, proc_data):
963 abdf0113 Iustin Pop
    """Return the DRBD version.
964 a8083063 Iustin Pop

965 abdf0113 Iustin Pop
    This will return a dict with keys:
966 c41eea6e Iustin Pop
      - k_major
967 c41eea6e Iustin Pop
      - k_minor
968 c41eea6e Iustin Pop
      - k_point
969 c41eea6e Iustin Pop
      - api
970 c41eea6e Iustin Pop
      - proto
971 c41eea6e Iustin Pop
      - proto2 (only on drbd > 8.2.X)
972 a8083063 Iustin Pop

973 a8083063 Iustin Pop
    """
974 abdf0113 Iustin Pop
    first_line = proc_data[0].strip()
975 abdf0113 Iustin Pop
    version = cls._VERSION_RE.match(first_line)
976 abdf0113 Iustin Pop
    if not version:
977 abdf0113 Iustin Pop
      raise errors.BlockDeviceError("Can't parse DRBD version from '%s'" %
978 abdf0113 Iustin Pop
                                    first_line)
979 a8083063 Iustin Pop
980 abdf0113 Iustin Pop
    values = version.groups()
981 d0c8c01d Iustin Pop
    retval = {"k_major": int(values[0]),
982 d0c8c01d Iustin Pop
              "k_minor": int(values[1]),
983 d0c8c01d Iustin Pop
              "k_point": int(values[2]),
984 d0c8c01d Iustin Pop
              "api": int(values[3]),
985 d0c8c01d Iustin Pop
              "proto": int(values[4]),
986 abdf0113 Iustin Pop
             }
987 abdf0113 Iustin Pop
    if values[5] is not None:
988 d0c8c01d Iustin Pop
      retval["proto2"] = values[5]
989 a8083063 Iustin Pop
990 abdf0113 Iustin Pop
    return retval
991 abdf0113 Iustin Pop
992 abdf0113 Iustin Pop
  @staticmethod
993 549071a0 Luca Bigliardi
  def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE):
994 549071a0 Luca Bigliardi
    """Returns DRBD usermode_helper currently set.
995 549071a0 Luca Bigliardi

996 549071a0 Luca Bigliardi
    """
997 549071a0 Luca Bigliardi
    try:
998 549071a0 Luca Bigliardi
      helper = utils.ReadFile(filename).splitlines()[0]
999 549071a0 Luca Bigliardi
    except EnvironmentError, err:
1000 549071a0 Luca Bigliardi
      if err.errno == errno.ENOENT:
1001 549071a0 Luca Bigliardi
        _ThrowError("The file %s cannot be opened, check if the module"
1002 549071a0 Luca Bigliardi
                    " is loaded (%s)", filename, str(err))
1003 549071a0 Luca Bigliardi
      else:
1004 549071a0 Luca Bigliardi
        _ThrowError("Can't read DRBD helper file %s: %s", filename, str(err))
1005 549071a0 Luca Bigliardi
    if not helper:
1006 549071a0 Luca Bigliardi
      _ThrowError("Can't read any data from %s", filename)
1007 549071a0 Luca Bigliardi
    return helper
1008 549071a0 Luca Bigliardi
1009 549071a0 Luca Bigliardi
  @staticmethod
1010 abdf0113 Iustin Pop
  def _DevPath(minor):
1011 abdf0113 Iustin Pop
    """Return the path to a drbd device for a given minor.
1012 a8083063 Iustin Pop

1013 a8083063 Iustin Pop
    """
1014 abdf0113 Iustin Pop
    return "/dev/drbd%d" % minor
1015 a8083063 Iustin Pop
1016 abdf0113 Iustin Pop
  @classmethod
1017 6d2e83d5 Iustin Pop
  def GetUsedDevs(cls):
1018 abdf0113 Iustin Pop
    """Compute the list of used DRBD devices.
1019 a8083063 Iustin Pop

1020 a8083063 Iustin Pop
    """
1021 abdf0113 Iustin Pop
    data = cls._GetProcData()
1022 a8083063 Iustin Pop
1023 abdf0113 Iustin Pop
    used_devs = {}
1024 abdf0113 Iustin Pop
    for line in data:
1025 9122e60a Iustin Pop
      match = cls._VALID_LINE_RE.match(line)
1026 abdf0113 Iustin Pop
      if not match:
1027 abdf0113 Iustin Pop
        continue
1028 abdf0113 Iustin Pop
      minor = int(match.group(1))
1029 abdf0113 Iustin Pop
      state = match.group(2)
1030 abdf0113 Iustin Pop
      if state == cls._ST_UNCONFIGURED:
1031 abdf0113 Iustin Pop
        continue
1032 abdf0113 Iustin Pop
      used_devs[minor] = state, line
1033 a8083063 Iustin Pop
1034 abdf0113 Iustin Pop
    return used_devs
1035 a8083063 Iustin Pop
1036 abdf0113 Iustin Pop
  def _SetFromMinor(self, minor):
1037 abdf0113 Iustin Pop
    """Set our parameters based on the given minor.
1038 0834c866 Iustin Pop

1039 abdf0113 Iustin Pop
    This sets our minor variable and our dev_path.
1040 a8083063 Iustin Pop

1041 a8083063 Iustin Pop
    """
1042 abdf0113 Iustin Pop
    if minor is None:
1043 abdf0113 Iustin Pop
      self.minor = self.dev_path = None
1044 cb999543 Iustin Pop
      self.attached = False
1045 a8083063 Iustin Pop
    else:
1046 abdf0113 Iustin Pop
      self.minor = minor
1047 abdf0113 Iustin Pop
      self.dev_path = self._DevPath(minor)
1048 cb999543 Iustin Pop
      self.attached = True
1049 a8083063 Iustin Pop
1050 a8083063 Iustin Pop
  @staticmethod
1051 abdf0113 Iustin Pop
  def _CheckMetaSize(meta_device):
1052 abdf0113 Iustin Pop
    """Check if the given meta device looks like a valid one.
1053 a8083063 Iustin Pop

1054 abdf0113 Iustin Pop
    This currently only check the size, which must be around
1055 abdf0113 Iustin Pop
    128MiB.
1056 a8083063 Iustin Pop

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

1081 abdf0113 Iustin Pop
    This is not supported for drbd devices.
1082 a8083063 Iustin Pop

1083 a8083063 Iustin Pop
    """
1084 abdf0113 Iustin Pop
    raise errors.ProgrammerError("Can't rename a drbd device")
1085 a8083063 Iustin Pop
1086 f3e513ad Iustin Pop
1087 a2cfdea2 Iustin Pop
class DRBD8(BaseDRBD):
1088 a2cfdea2 Iustin Pop
  """DRBD v8.x block device.
1089 a2cfdea2 Iustin Pop

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

1094 a2cfdea2 Iustin Pop
  The unique_id for the drbd device is the (local_ip, local_port,
1095 a2cfdea2 Iustin Pop
  remote_ip, remote_port) tuple, and it must have two children: the
1096 a2cfdea2 Iustin Pop
  data device and the meta_device. The meta device is checked for
1097 a2cfdea2 Iustin Pop
  valid size and is zeroed on create.
1098 a2cfdea2 Iustin Pop

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

1144 a2cfdea2 Iustin Pop
    This will not work if the given minor is in use.
1145 a2cfdea2 Iustin Pop

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

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

1170 a2cfdea2 Iustin Pop
    """
1171 a2cfdea2 Iustin Pop
    data = cls._GetProcData()
1172 a2cfdea2 Iustin Pop
1173 a2cfdea2 Iustin Pop
    highest = None
1174 a2cfdea2 Iustin Pop
    for line in data:
1175 9122e60a Iustin Pop
      match = cls._UNUSED_LINE_RE.match(line)
1176 a2cfdea2 Iustin Pop
      if match:
1177 a2cfdea2 Iustin Pop
        return int(match.group(1))
1178 9122e60a Iustin Pop
      match = cls._VALID_LINE_RE.match(line)
1179 a2cfdea2 Iustin Pop
      if match:
1180 a2cfdea2 Iustin Pop
        minor = int(match.group(1))
1181 a2cfdea2 Iustin Pop
        highest = max(highest, minor)
1182 a2cfdea2 Iustin Pop
    if highest is None: # there are no minors in use at all
1183 a2cfdea2 Iustin Pop
      return 0
1184 a2cfdea2 Iustin Pop
    if highest >= cls._MAX_MINORS:
1185 468c5f77 Iustin Pop
      logging.error("Error: no free drbd minors!")
1186 a2cfdea2 Iustin Pop
      raise errors.BlockDeviceError("Can't find a free DRBD minor")
1187 a2cfdea2 Iustin Pop
    return highest + 1
1188 a2cfdea2 Iustin Pop
1189 a2cfdea2 Iustin Pop
  @classmethod
1190 a2cfdea2 Iustin Pop
  def _GetShowParser(cls):
1191 a2cfdea2 Iustin Pop
    """Return a parser for `drbd show` output.
1192 a2cfdea2 Iustin Pop

1193 a2cfdea2 Iustin Pop
    This will either create or return an already-create parser for the
1194 a2cfdea2 Iustin Pop
    output of the command `drbd show`.
1195 a2cfdea2 Iustin Pop

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

1251 a2cfdea2 Iustin Pop
    """
1252 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "show"])
1253 a2cfdea2 Iustin Pop
    if result.failed:
1254 468c5f77 Iustin Pop
      logging.error("Can't display the drbd config: %s - %s",
1255 468c5f77 Iustin Pop
                    result.fail_reason, result.output)
1256 3840729d Iustin Pop
      return None
1257 3840729d Iustin Pop
    return result.stdout
1258 3840729d Iustin Pop
1259 3840729d Iustin Pop
  @classmethod
1260 3840729d Iustin Pop
  def _GetDevInfo(cls, out):
1261 3840729d Iustin Pop
    """Parse details about a given DRBD minor.
1262 3840729d Iustin Pop

1263 3840729d Iustin Pop
    This return, if available, the local backing device (as a path)
1264 3840729d Iustin Pop
    and the local and remote (ip, port) information from a string
1265 3840729d Iustin Pop
    containing the output of the `drbdsetup show` command as returned
1266 3840729d Iustin Pop
    by _GetShowData.
1267 3840729d Iustin Pop

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

1302 a2cfdea2 Iustin Pop
    The parameter should be as returned from `_GetDevInfo()`. This
1303 a2cfdea2 Iustin Pop
    method tests if our local backing device is the same as the one in
1304 a2cfdea2 Iustin Pop
    the info parameter, in effect testing if we look like the given
1305 a2cfdea2 Iustin Pop
    device.
1306 a2cfdea2 Iustin Pop

1307 a2cfdea2 Iustin Pop
    """
1308 b00b95dd Iustin Pop
    if self._children:
1309 b00b95dd Iustin Pop
      backend, meta = self._children
1310 b00b95dd Iustin Pop
    else:
1311 b00b95dd Iustin Pop
      backend = meta = None
1312 b00b95dd Iustin Pop
1313 a2cfdea2 Iustin Pop
    if backend is not None:
1314 b00b95dd Iustin Pop
      retval = ("local_dev" in info and info["local_dev"] == backend.dev_path)
1315 a2cfdea2 Iustin Pop
    else:
1316 a2cfdea2 Iustin Pop
      retval = ("local_dev" not in info)
1317 b00b95dd Iustin Pop
1318 a2cfdea2 Iustin Pop
    if meta is not None:
1319 b00b95dd Iustin Pop
      retval = retval and ("meta_dev" in info and
1320 b00b95dd Iustin Pop
                           info["meta_dev"] == meta.dev_path)
1321 b00b95dd Iustin Pop
      retval = retval and ("meta_index" in info and
1322 b00b95dd Iustin Pop
                           info["meta_index"] == 0)
1323 a2cfdea2 Iustin Pop
    else:
1324 a2cfdea2 Iustin Pop
      retval = retval and ("meta_dev" not in info and
1325 a2cfdea2 Iustin Pop
                           "meta_index" not in info)
1326 a2cfdea2 Iustin Pop
    return retval
1327 a2cfdea2 Iustin Pop
1328 a2cfdea2 Iustin Pop
  def _MatchesNet(self, info):
1329 a2cfdea2 Iustin Pop
    """Test if our network config matches with an existing device.
1330 a2cfdea2 Iustin Pop

1331 a2cfdea2 Iustin Pop
    The parameter should be as returned from `_GetDevInfo()`. This
1332 a2cfdea2 Iustin Pop
    method tests if our network configuration is the same as the one
1333 a2cfdea2 Iustin Pop
    in the info parameter, in effect testing if we look like the given
1334 a2cfdea2 Iustin Pop
    device.
1335 a2cfdea2 Iustin Pop

1336 a2cfdea2 Iustin Pop
    """
1337 a2cfdea2 Iustin Pop
    if (((self._lhost is None and not ("local_addr" in info)) and
1338 a2cfdea2 Iustin Pop
         (self._rhost is None and not ("remote_addr" in info)))):
1339 a2cfdea2 Iustin Pop
      return True
1340 a2cfdea2 Iustin Pop
1341 a2cfdea2 Iustin Pop
    if self._lhost is None:
1342 a2cfdea2 Iustin Pop
      return False
1343 a2cfdea2 Iustin Pop
1344 a2cfdea2 Iustin Pop
    if not ("local_addr" in info and
1345 a2cfdea2 Iustin Pop
            "remote_addr" in info):
1346 a2cfdea2 Iustin Pop
      return False
1347 a2cfdea2 Iustin Pop
1348 a2cfdea2 Iustin Pop
    retval = (info["local_addr"] == (self._lhost, self._lport))
1349 a2cfdea2 Iustin Pop
    retval = (retval and
1350 a2cfdea2 Iustin Pop
              info["remote_addr"] == (self._rhost, self._rport))
1351 a2cfdea2 Iustin Pop
    return retval
1352 a2cfdea2 Iustin Pop
1353 8a69b3a8 Andrea Spadaccini
  def _AssembleLocal(self, minor, backend, meta, size):
1354 a2cfdea2 Iustin Pop
    """Configure the local part of a DRBD device.
1355 a2cfdea2 Iustin Pop

1356 a2cfdea2 Iustin Pop
    """
1357 8a69b3a8 Andrea Spadaccini
    args = ["drbdsetup", self._DevPath(minor), "disk",
1358 f069addf Iustin Pop
            backend, meta, "0",
1359 f069addf Iustin Pop
            "-e", "detach",
1360 f069addf Iustin Pop
            "--create-device"]
1361 60bca04a Iustin Pop
    if size:
1362 60bca04a Iustin Pop
      args.extend(["-d", "%sm" % size])
1363 8a69b3a8 Andrea Spadaccini
1364 8a69b3a8 Andrea Spadaccini
    version = self._GetVersion(self._GetProcData())
1365 8a69b3a8 Andrea Spadaccini
    vmaj = version["k_major"]
1366 8a69b3a8 Andrea Spadaccini
    vmin = version["k_minor"]
1367 8a69b3a8 Andrea Spadaccini
    vrel = version["k_point"]
1368 8a69b3a8 Andrea Spadaccini
1369 8a69b3a8 Andrea Spadaccini
    barrier_args = \
1370 8a69b3a8 Andrea Spadaccini
      self._ComputeDiskBarrierArgs(vmaj, vmin, vrel,
1371 8a69b3a8 Andrea Spadaccini
                                   self.params[constants.BARRIERS],
1372 8a69b3a8 Andrea Spadaccini
                                   self.params[constants.NO_META_FLUSH])
1373 8a69b3a8 Andrea Spadaccini
    args.extend(barrier_args)
1374 8a69b3a8 Andrea Spadaccini
1375 333411a7 Guido Trotter
    result = utils.RunCmd(args)
1376 a2cfdea2 Iustin Pop
    if result.failed:
1377 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't attach local disk: %s", minor, result.output)
1378 a2cfdea2 Iustin Pop
1379 8a69b3a8 Andrea Spadaccini
  @classmethod
1380 8a69b3a8 Andrea Spadaccini
  def _ComputeDiskBarrierArgs(cls, vmaj, vmin, vrel, disabled_barriers,
1381 8a69b3a8 Andrea Spadaccini
      disable_meta_flush):
1382 8a69b3a8 Andrea Spadaccini
    """Compute the DRBD command line parameters for disk barriers
1383 8a69b3a8 Andrea Spadaccini

1384 8a69b3a8 Andrea Spadaccini
    Returns a list of the disk barrier parameters as requested via the
1385 8a69b3a8 Andrea Spadaccini
    disabled_barriers and disable_meta_flush arguments, and according to the
1386 8a69b3a8 Andrea Spadaccini
    supported ones in the DRBD version vmaj.vmin.vrel
1387 8a69b3a8 Andrea Spadaccini

1388 8a69b3a8 Andrea Spadaccini
    If the desired option is unsupported, raises errors.BlockDeviceError.
1389 8a69b3a8 Andrea Spadaccini

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

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

1520 b00b95dd Iustin Pop
    """
1521 b00b95dd Iustin Pop
    if self.minor is None:
1522 82463074 Iustin Pop
      _ThrowError("drbd%d: can't attach to dbrd8 during AddChildren",
1523 82463074 Iustin Pop
                  self._aminor)
1524 b00b95dd Iustin Pop
    if len(devices) != 2:
1525 82463074 Iustin Pop
      _ThrowError("drbd%d: need two devices for AddChildren", self.minor)
1526 3840729d Iustin Pop
    info = self._GetDevInfo(self._GetShowData(self.minor))
1527 03ece5f3 Iustin Pop
    if "local_dev" in info:
1528 82463074 Iustin Pop
      _ThrowError("drbd%d: already attached to a local disk", self.minor)
1529 b00b95dd Iustin Pop
    backend, meta = devices
1530 b00b95dd Iustin Pop
    if backend.dev_path is None or meta.dev_path is None:
1531 82463074 Iustin Pop
      _ThrowError("drbd%d: children not ready during AddChildren", self.minor)
1532 b00b95dd Iustin Pop
    backend.Open()
1533 b00b95dd Iustin Pop
    meta.Open()
1534 9c793cfb Iustin Pop
    self._CheckMetaSize(meta.dev_path)
1535 b00b95dd Iustin Pop
    self._InitMeta(self._FindUnusedMinor(), meta.dev_path)
1536 b00b95dd Iustin Pop
1537 f069addf Iustin Pop
    self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path, self.size)
1538 b00b95dd Iustin Pop
    self._children = devices
1539 b00b95dd Iustin Pop
1540 b00b95dd Iustin Pop
  def RemoveChildren(self, devices):
1541 b00b95dd Iustin Pop
    """Detach the drbd device from local storage.
1542 b00b95dd Iustin Pop

1543 b00b95dd Iustin Pop
    """
1544 b00b95dd Iustin Pop
    if self.minor is None:
1545 82463074 Iustin Pop
      _ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
1546 82463074 Iustin Pop
                  self._aminor)
1547 03ece5f3 Iustin Pop
    # early return if we don't actually have backing storage
1548 3840729d Iustin Pop
    info = self._GetDevInfo(self._GetShowData(self.minor))
1549 03ece5f3 Iustin Pop
    if "local_dev" not in info:
1550 03ece5f3 Iustin Pop
      return
1551 b00b95dd Iustin Pop
    if len(self._children) != 2:
1552 82463074 Iustin Pop
      _ThrowError("drbd%d: we don't have two children: %s", self.minor,
1553 82463074 Iustin Pop
                  self._children)
1554 e739bd57 Iustin Pop
    if self._children.count(None) == 2: # we don't actually have children :)
1555 82463074 Iustin Pop
      logging.warning("drbd%d: requested detach while detached", self.minor)
1556 e739bd57 Iustin Pop
      return
1557 b00b95dd Iustin Pop
    if len(devices) != 2:
1558 82463074 Iustin Pop
      _ThrowError("drbd%d: we need two children in RemoveChildren", self.minor)
1559 e739bd57 Iustin Pop
    for child, dev in zip(self._children, devices):
1560 e739bd57 Iustin Pop
      if dev != child.dev_path:
1561 82463074 Iustin Pop
        _ThrowError("drbd%d: mismatch in local storage (%s != %s) in"
1562 82463074 Iustin Pop
                    " RemoveChildren", self.minor, dev, child.dev_path)
1563 b00b95dd Iustin Pop
1564 1063abd1 Iustin Pop
    self._ShutdownLocal(self.minor)
1565 b00b95dd Iustin Pop
    self._children = []
1566 b00b95dd Iustin Pop
1567 7d585316 Iustin Pop
  @classmethod
1568 7d585316 Iustin Pop
  def _SetMinorSyncSpeed(cls, minor, kbytes):
1569 a2cfdea2 Iustin Pop
    """Set the speed of the DRBD syncer.
1570 a2cfdea2 Iustin Pop

1571 7d585316 Iustin Pop
    This is the low-level implementation.
1572 7d585316 Iustin Pop

1573 7d585316 Iustin Pop
    @type minor: int
1574 7d585316 Iustin Pop
    @param minor: the drbd minor whose settings we change
1575 7d585316 Iustin Pop
    @type kbytes: int
1576 7d585316 Iustin Pop
    @param kbytes: the speed in kbytes/second
1577 7d585316 Iustin Pop
    @rtype: boolean
1578 7d585316 Iustin Pop
    @return: the success of the operation
1579 7d585316 Iustin Pop

1580 a2cfdea2 Iustin Pop
    """
1581 7d585316 Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "syncer",
1582 7d585316 Iustin Pop
                           "-r", "%d" % kbytes, "--create-device"])
1583 a2cfdea2 Iustin Pop
    if result.failed:
1584 468c5f77 Iustin Pop
      logging.error("Can't change syncer rate: %s - %s",
1585 468c5f77 Iustin Pop
                    result.fail_reason, result.output)
1586 7d585316 Iustin Pop
    return not result.failed
1587 7d585316 Iustin Pop
1588 7d585316 Iustin Pop
  def SetSyncSpeed(self, kbytes):
1589 7d585316 Iustin Pop
    """Set the speed of the DRBD syncer.
1590 7d585316 Iustin Pop

1591 7d585316 Iustin Pop
    @type kbytes: int
1592 7d585316 Iustin Pop
    @param kbytes: the speed in kbytes/second
1593 7d585316 Iustin Pop
    @rtype: boolean
1594 7d585316 Iustin Pop
    @return: the success of the operation
1595 7d585316 Iustin Pop

1596 7d585316 Iustin Pop
    """
1597 7d585316 Iustin Pop
    if self.minor is None:
1598 7d585316 Iustin Pop
      logging.info("Not attached during SetSyncSpeed")
1599 7d585316 Iustin Pop
      return False
1600 7d585316 Iustin Pop
    children_result = super(DRBD8, self).SetSyncSpeed(kbytes)
1601 7d585316 Iustin Pop
    return self._SetMinorSyncSpeed(self.minor, kbytes) and children_result
1602 a2cfdea2 Iustin Pop
1603 a3fffcc6 Renรฉ Nussbaumer
  def PauseResumeSync(self, pause):
1604 a3fffcc6 Renรฉ Nussbaumer
    """Pauses or resumes the sync of a DRBD device.
1605 a3fffcc6 Renรฉ Nussbaumer

1606 a3fffcc6 Renรฉ Nussbaumer
    @param pause: Wether to pause or resume
1607 a3fffcc6 Renรฉ Nussbaumer
    @return: the success of the operation
1608 a3fffcc6 Renรฉ Nussbaumer

1609 a3fffcc6 Renรฉ Nussbaumer
    """
1610 a3fffcc6 Renรฉ Nussbaumer
    if self.minor is None:
1611 a3fffcc6 Renรฉ Nussbaumer
      logging.info("Not attached during PauseSync")
1612 a3fffcc6 Renรฉ Nussbaumer
      return False
1613 a3fffcc6 Renรฉ Nussbaumer
1614 a3fffcc6 Renรฉ Nussbaumer
    children_result = super(DRBD8, self).PauseResumeSync(pause)
1615 a3fffcc6 Renรฉ Nussbaumer
1616 a3fffcc6 Renรฉ Nussbaumer
    if pause:
1617 a3fffcc6 Renรฉ Nussbaumer
      cmd = "pause-sync"
1618 a3fffcc6 Renรฉ Nussbaumer
    else:
1619 a3fffcc6 Renรฉ Nussbaumer
      cmd = "resume-sync"
1620 a3fffcc6 Renรฉ Nussbaumer
1621 a3fffcc6 Renรฉ Nussbaumer
    result = utils.RunCmd(["drbdsetup", self.dev_path, cmd])
1622 a3fffcc6 Renรฉ Nussbaumer
    if result.failed:
1623 a3fffcc6 Renรฉ Nussbaumer
      logging.error("Can't %s: %s - %s", cmd,
1624 a3fffcc6 Renรฉ Nussbaumer
                    result.fail_reason, result.output)
1625 a3fffcc6 Renรฉ Nussbaumer
    return not result.failed and children_result
1626 a3fffcc6 Renรฉ Nussbaumer
1627 6b90c22e Iustin Pop
  def GetProcStatus(self):
1628 6b90c22e Iustin Pop
    """Return device data from /proc.
1629 6b90c22e Iustin Pop

1630 6b90c22e Iustin Pop
    """
1631 6b90c22e Iustin Pop
    if self.minor is None:
1632 82463074 Iustin Pop
      _ThrowError("drbd%d: GetStats() called while not attached", self._aminor)
1633 6b90c22e Iustin Pop
    proc_info = self._MassageProcData(self._GetProcData())
1634 6b90c22e Iustin Pop
    if self.minor not in proc_info:
1635 82463074 Iustin Pop
      _ThrowError("drbd%d: can't find myself in /proc", self.minor)
1636 6b90c22e Iustin Pop
    return DRBD8Status(proc_info[self.minor])
1637 6b90c22e Iustin Pop
1638 a2cfdea2 Iustin Pop
  def GetSyncStatus(self):
1639 a2cfdea2 Iustin Pop
    """Returns the sync status of the device.
1640 a2cfdea2 Iustin Pop

1641 a2cfdea2 Iustin Pop

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

1646 0834c866 Iustin Pop

1647 0834c866 Iustin Pop
    We set the is_degraded parameter to True on two conditions:
1648 0834c866 Iustin Pop
    network not connected or local disk missing.
1649 0834c866 Iustin Pop

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

1653 96acbc09 Michael Hanselmann
    @rtype: objects.BlockDevStatus
1654 c41eea6e Iustin Pop

1655 a2cfdea2 Iustin Pop
    """
1656 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1657 82463074 Iustin Pop
      _ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
1658 96acbc09 Michael Hanselmann
1659 6b90c22e Iustin Pop
    stats = self.GetProcStatus()
1660 f208978a Michael Hanselmann
    is_degraded = not stats.is_connected or not stats.is_disk_uptodate
1661 f208978a Michael Hanselmann
1662 f208978a Michael Hanselmann
    if stats.is_disk_uptodate:
1663 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_OKAY
1664 f208978a Michael Hanselmann
    elif stats.is_diskless:
1665 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_FAULTY
1666 f208978a Michael Hanselmann
    else:
1667 f208978a Michael Hanselmann
      ldisk_status = constants.LDS_UNKNOWN
1668 96acbc09 Michael Hanselmann
1669 96acbc09 Michael Hanselmann
    return objects.BlockDevStatus(dev_path=self.dev_path,
1670 96acbc09 Michael Hanselmann
                                  major=self.major,
1671 96acbc09 Michael Hanselmann
                                  minor=self.minor,
1672 96acbc09 Michael Hanselmann
                                  sync_percent=stats.sync_percent,
1673 96acbc09 Michael Hanselmann
                                  estimated_time=stats.est_time,
1674 f208978a Michael Hanselmann
                                  is_degraded=is_degraded,
1675 f208978a Michael Hanselmann
                                  ldisk_status=ldisk_status)
1676 a2cfdea2 Iustin Pop
1677 a2cfdea2 Iustin Pop
  def Open(self, force=False):
1678 a2cfdea2 Iustin Pop
    """Make the local state primary.
1679 a2cfdea2 Iustin Pop

1680 f860ff4e Guido Trotter
    If the 'force' parameter is given, the '-o' option is passed to
1681 f860ff4e Guido Trotter
    drbdsetup. Since this is a potentially dangerous operation, the
1682 a2cfdea2 Iustin Pop
    force flag should be only given after creation, when it actually
1683 f860ff4e Guido Trotter
    is mandatory.
1684 a2cfdea2 Iustin Pop

1685 a2cfdea2 Iustin Pop
    """
1686 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1687 468c5f77 Iustin Pop
      logging.error("DRBD cannot attach to a device during open")
1688 a2cfdea2 Iustin Pop
      return False
1689 a2cfdea2 Iustin Pop
    cmd = ["drbdsetup", self.dev_path, "primary"]
1690 a2cfdea2 Iustin Pop
    if force:
1691 a2cfdea2 Iustin Pop
      cmd.append("-o")
1692 a2cfdea2 Iustin Pop
    result = utils.RunCmd(cmd)
1693 a2cfdea2 Iustin Pop
    if result.failed:
1694 82463074 Iustin Pop
      _ThrowError("drbd%d: can't make drbd device primary: %s", self.minor,
1695 82463074 Iustin Pop
                  result.output)
1696 a2cfdea2 Iustin Pop
1697 a2cfdea2 Iustin Pop
  def Close(self):
1698 a2cfdea2 Iustin Pop
    """Make the local state secondary.
1699 a2cfdea2 Iustin Pop

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

1702 a2cfdea2 Iustin Pop
    """
1703 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1704 82463074 Iustin Pop
      _ThrowError("drbd%d: can't Attach() in Close()", self._aminor)
1705 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", self.dev_path, "secondary"])
1706 a2cfdea2 Iustin Pop
    if result.failed:
1707 82463074 Iustin Pop
      _ThrowError("drbd%d: can't switch drbd device to secondary: %s",
1708 82463074 Iustin Pop
                  self.minor, result.output)
1709 a2cfdea2 Iustin Pop
1710 cf8df3f3 Iustin Pop
  def DisconnectNet(self):
1711 cf8df3f3 Iustin Pop
    """Removes network configuration.
1712 cf8df3f3 Iustin Pop

1713 cf8df3f3 Iustin Pop
    This method shutdowns the network side of the device.
1714 cf8df3f3 Iustin Pop

1715 cf8df3f3 Iustin Pop
    The method will wait up to a hardcoded timeout for the device to
1716 cf8df3f3 Iustin Pop
    go into standalone after the 'disconnect' command before
1717 cf8df3f3 Iustin Pop
    re-configuring it, as sometimes it takes a while for the
1718 cf8df3f3 Iustin Pop
    disconnect to actually propagate and thus we might issue a 'net'
1719 cf8df3f3 Iustin Pop
    command while the device is still connected. If the device will
1720 cf8df3f3 Iustin Pop
    still be attached to the network and we time out, we raise an
1721 cf8df3f3 Iustin Pop
    exception.
1722 cf8df3f3 Iustin Pop

1723 cf8df3f3 Iustin Pop
    """
1724 cf8df3f3 Iustin Pop
    if self.minor is None:
1725 82463074 Iustin Pop
      _ThrowError("drbd%d: disk not attached in re-attach net", self._aminor)
1726 cf8df3f3 Iustin Pop
1727 cf8df3f3 Iustin Pop
    if None in (self._lhost, self._lport, self._rhost, self._rport):
1728 82463074 Iustin Pop
      _ThrowError("drbd%d: DRBD disk missing network info in"
1729 82463074 Iustin Pop
                  " DisconnectNet()", self.minor)
1730 cf8df3f3 Iustin Pop
1731 def8e2f6 Michael Hanselmann
    class _DisconnectStatus:
1732 def8e2f6 Michael Hanselmann
      def __init__(self, ever_disconnected):
1733 def8e2f6 Michael Hanselmann
        self.ever_disconnected = ever_disconnected
1734 cf8df3f3 Iustin Pop
1735 def8e2f6 Michael Hanselmann
    dstatus = _DisconnectStatus(_IgnoreError(self._ShutdownNet, self.minor))
1736 def8e2f6 Michael Hanselmann
1737 def8e2f6 Michael Hanselmann
    def _WaitForDisconnect():
1738 def8e2f6 Michael Hanselmann
      if self.GetProcStatus().is_standalone:
1739 def8e2f6 Michael Hanselmann
        return
1740 def8e2f6 Michael Hanselmann
1741 def8e2f6 Michael Hanselmann
      # retry the disconnect, it seems possible that due to a well-time
1742 def8e2f6 Michael Hanselmann
      # disconnect on the peer, my disconnect command might be ignored and
1743 def8e2f6 Michael Hanselmann
      # forgotten
1744 def8e2f6 Michael Hanselmann
      dstatus.ever_disconnected = \
1745 def8e2f6 Michael Hanselmann
        _IgnoreError(self._ShutdownNet, self.minor) or dstatus.ever_disconnected
1746 def8e2f6 Michael Hanselmann
1747 def8e2f6 Michael Hanselmann
      raise utils.RetryAgain()
1748 def8e2f6 Michael Hanselmann
1749 def8e2f6 Michael Hanselmann
    # Keep start time
1750 def8e2f6 Michael Hanselmann
    start_time = time.time()
1751 def8e2f6 Michael Hanselmann
1752 def8e2f6 Michael Hanselmann
    try:
1753 def8e2f6 Michael Hanselmann
      # Start delay at 100 milliseconds and grow up to 2 seconds
1754 def8e2f6 Michael Hanselmann
      utils.Retry(_WaitForDisconnect, (0.1, 1.5, 2.0),
1755 def8e2f6 Michael Hanselmann
                  self._NET_RECONFIG_TIMEOUT)
1756 def8e2f6 Michael Hanselmann
    except utils.RetryTimeout:
1757 def8e2f6 Michael Hanselmann
      if dstatus.ever_disconnected:
1758 82463074 Iustin Pop
        msg = ("drbd%d: device did not react to the"
1759 cf8df3f3 Iustin Pop
               " 'disconnect' command in a timely manner")
1760 cf8df3f3 Iustin Pop
      else:
1761 82463074 Iustin Pop
        msg = "drbd%d: can't shutdown network, even after multiple retries"
1762 def8e2f6 Michael Hanselmann
1763 82463074 Iustin Pop
      _ThrowError(msg, self.minor)
1764 cf8df3f3 Iustin Pop
1765 def8e2f6 Michael Hanselmann
    reconfig_time = time.time() - start_time
1766 def8e2f6 Michael Hanselmann
    if reconfig_time > (self._NET_RECONFIG_TIMEOUT * 0.25):
1767 82463074 Iustin Pop
      logging.info("drbd%d: DisconnectNet: detach took %.3f seconds",
1768 82463074 Iustin Pop
                   self.minor, reconfig_time)
1769 cf8df3f3 Iustin Pop
1770 cf8df3f3 Iustin Pop
  def AttachNet(self, multimaster):
1771 cf8df3f3 Iustin Pop
    """Reconnects the network.
1772 cf8df3f3 Iustin Pop

1773 cf8df3f3 Iustin Pop
    This method connects the network side of the device with a
1774 cf8df3f3 Iustin Pop
    specified multi-master flag. The device needs to be 'Standalone'
1775 cf8df3f3 Iustin Pop
    but have valid network configuration data.
1776 cf8df3f3 Iustin Pop

1777 cf8df3f3 Iustin Pop
    Args:
1778 cf8df3f3 Iustin Pop
      - multimaster: init the network in dual-primary mode
1779 cf8df3f3 Iustin Pop

1780 cf8df3f3 Iustin Pop
    """
1781 cf8df3f3 Iustin Pop
    if self.minor is None:
1782 82463074 Iustin Pop
      _ThrowError("drbd%d: device not attached in AttachNet", self._aminor)
1783 cf8df3f3 Iustin Pop
1784 cf8df3f3 Iustin Pop
    if None in (self._lhost, self._lport, self._rhost, self._rport):
1785 82463074 Iustin Pop
      _ThrowError("drbd%d: missing network info in AttachNet()", self.minor)
1786 cf8df3f3 Iustin Pop
1787 cf8df3f3 Iustin Pop
    status = self.GetProcStatus()
1788 cf8df3f3 Iustin Pop
1789 cf8df3f3 Iustin Pop
    if not status.is_standalone:
1790 82463074 Iustin Pop
      _ThrowError("drbd%d: device is not standalone in AttachNet", self.minor)
1791 cf8df3f3 Iustin Pop
1792 1063abd1 Iustin Pop
    self._AssembleNet(self.minor,
1793 1063abd1 Iustin Pop
                      (self._lhost, self._lport, self._rhost, self._rport),
1794 1063abd1 Iustin Pop
                      constants.DRBD_NET_PROTOCOL, dual_pri=multimaster,
1795 1063abd1 Iustin Pop
                      hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1796 cf8df3f3 Iustin Pop
1797 a2cfdea2 Iustin Pop
  def Attach(self):
1798 2d0c8319 Iustin Pop
    """Check if our minor is configured.
1799 2d0c8319 Iustin Pop

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

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

1807 2d0c8319 Iustin Pop
    """
1808 6d2e83d5 Iustin Pop
    used_devs = self.GetUsedDevs()
1809 2d0c8319 Iustin Pop
    if self._aminor in used_devs:
1810 2d0c8319 Iustin Pop
      minor = self._aminor
1811 2d0c8319 Iustin Pop
    else:
1812 2d0c8319 Iustin Pop
      minor = None
1813 2d0c8319 Iustin Pop
1814 2d0c8319 Iustin Pop
    self._SetFromMinor(minor)
1815 2d0c8319 Iustin Pop
    return minor is not None
1816 2d0c8319 Iustin Pop
1817 2d0c8319 Iustin Pop
  def Assemble(self):
1818 2d0c8319 Iustin Pop
    """Assemble the drbd.
1819 2d0c8319 Iustin Pop

1820 2d0c8319 Iustin Pop
    Method:
1821 2d0c8319 Iustin Pop
      - if we have a configured device, we try to ensure that it matches
1822 2d0c8319 Iustin Pop
        our config
1823 2d0c8319 Iustin Pop
      - if not, we create it from zero
1824 d529599f Andrea Spadaccini
      - anyway, set the device parameters
1825 2d0c8319 Iustin Pop

1826 2d0c8319 Iustin Pop
    """
1827 1063abd1 Iustin Pop
    super(DRBD8, self).Assemble()
1828 2d0c8319 Iustin Pop
1829 2d0c8319 Iustin Pop
    self.Attach()
1830 2d0c8319 Iustin Pop
    if self.minor is None:
1831 2d0c8319 Iustin Pop
      # local device completely unconfigured
1832 1063abd1 Iustin Pop
      self._FastAssemble()
1833 2d0c8319 Iustin Pop
    else:
1834 2d0c8319 Iustin Pop
      # we have to recheck the local and network status and try to fix
1835 2d0c8319 Iustin Pop
      # the device
1836 1063abd1 Iustin Pop
      self._SlowAssemble()
1837 2d0c8319 Iustin Pop
1838 6e9814a1 Andrea Spadaccini
    sync_speed = self.params.get(constants.RESYNC_RATE)
1839 6e9814a1 Andrea Spadaccini
    self.SetSyncSpeed(sync_speed)
1840 d529599f Andrea Spadaccini
1841 2d0c8319 Iustin Pop
  def _SlowAssemble(self):
1842 2d0c8319 Iustin Pop
    """Assembles the DRBD device from a (partially) configured device.
1843 a2cfdea2 Iustin Pop

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

1848 a2cfdea2 Iustin Pop
    """
1849 527a15ac Iustin Pop
    # TODO: Rewrite to not use a for loop just because there is 'break'
1850 b459a848 Andrea Spadaccini
    # pylint: disable=W0631
1851 1063abd1 Iustin Pop
    net_data = (self._lhost, self._lport, self._rhost, self._rport)
1852 a1578d63 Iustin Pop
    for minor in (self._aminor,):
1853 3840729d Iustin Pop
      info = self._GetDevInfo(self._GetShowData(minor))
1854 a2cfdea2 Iustin Pop
      match_l = self._MatchesLocal(info)
1855 a2cfdea2 Iustin Pop
      match_r = self._MatchesNet(info)
1856 1063abd1 Iustin Pop
1857 a2cfdea2 Iustin Pop
      if match_l and match_r:
1858 1063abd1 Iustin Pop
        # everything matches
1859 a2cfdea2 Iustin Pop
        break
1860 1063abd1 Iustin Pop
1861 a2cfdea2 Iustin Pop
      if match_l and not match_r and "local_addr" not in info:
1862 1063abd1 Iustin Pop
        # disk matches, but not attached to network, attach and recheck
1863 1063abd1 Iustin Pop
        self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
1864 1063abd1 Iustin Pop
                          hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1865 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1866 1063abd1 Iustin Pop
          break
1867 1063abd1 Iustin Pop
        else:
1868 1063abd1 Iustin Pop
          _ThrowError("drbd%d: network attach successful, but 'drbdsetup"
1869 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1870 1063abd1 Iustin Pop
1871 fc1dc9d7 Iustin Pop
      if match_r and "local_dev" not in info:
1872 1063abd1 Iustin Pop
        # no local disk, but network attached and it matches
1873 1063abd1 Iustin Pop
        self._AssembleLocal(minor, self._children[0].dev_path,
1874 f069addf Iustin Pop
                            self._children[1].dev_path, self.size)
1875 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1876 1063abd1 Iustin Pop
          break
1877 1063abd1 Iustin Pop
        else:
1878 1063abd1 Iustin Pop
          _ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
1879 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1880 bf25af3b Iustin Pop
1881 bf25af3b Iustin Pop
      # this case must be considered only if we actually have local
1882 bf25af3b Iustin Pop
      # storage, i.e. not in diskless mode, because all diskless
1883 bf25af3b Iustin Pop
      # devices are equal from the point of view of local
1884 bf25af3b Iustin Pop
      # configuration
1885 bf25af3b Iustin Pop
      if (match_l and "local_dev" in info and
1886 bf25af3b Iustin Pop
          not match_r and "local_addr" in info):
1887 9cdbe77f Iustin Pop
        # strange case - the device network part points to somewhere
1888 9cdbe77f Iustin Pop
        # else, even though its local storage is ours; as we own the
1889 9cdbe77f Iustin Pop
        # drbd space, we try to disconnect from the remote peer and
1890 9cdbe77f Iustin Pop
        # reconnect to our correct one
1891 1063abd1 Iustin Pop
        try:
1892 1063abd1 Iustin Pop
          self._ShutdownNet(minor)
1893 1063abd1 Iustin Pop
        except errors.BlockDeviceError, err:
1894 33bc6f01 Iustin Pop
          _ThrowError("drbd%d: device has correct local storage, wrong"
1895 33bc6f01 Iustin Pop
                      " remote peer and is unable to disconnect in order"
1896 33bc6f01 Iustin Pop
                      " to attach to the correct peer: %s", minor, str(err))
1897 9cdbe77f Iustin Pop
        # note: _AssembleNet also handles the case when we don't want
1898 9cdbe77f Iustin Pop
        # local storage (i.e. one or more of the _[lr](host|port) is
1899 9cdbe77f Iustin Pop
        # None)
1900 1063abd1 Iustin Pop
        self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
1901 1063abd1 Iustin Pop
                          hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1902 1063abd1 Iustin Pop
        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
1903 9cdbe77f Iustin Pop
          break
1904 1063abd1 Iustin Pop
        else:
1905 1063abd1 Iustin Pop
          _ThrowError("drbd%d: network attach successful, but 'drbdsetup"
1906 1063abd1 Iustin Pop
                      " show' disagrees", minor)
1907 9cdbe77f Iustin Pop
1908 a2cfdea2 Iustin Pop
    else:
1909 a2cfdea2 Iustin Pop
      minor = None
1910 a2cfdea2 Iustin Pop
1911 a2cfdea2 Iustin Pop
    self._SetFromMinor(minor)
1912 1063abd1 Iustin Pop
    if minor is None:
1913 1063abd1 Iustin Pop
      _ThrowError("drbd%d: cannot activate, unknown or unhandled reason",
1914 1063abd1 Iustin Pop
                  self._aminor)
1915 a2cfdea2 Iustin Pop
1916 2d0c8319 Iustin Pop
  def _FastAssemble(self):
1917 2d0c8319 Iustin Pop
    """Assemble the drbd device from zero.
1918 a2cfdea2 Iustin Pop

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

1921 a2cfdea2 Iustin Pop
    """
1922 a1578d63 Iustin Pop
    minor = self._aminor
1923 fc1dc9d7 Iustin Pop
    if self._children and self._children[0] and self._children[1]:
1924 1063abd1 Iustin Pop
      self._AssembleLocal(minor, self._children[0].dev_path,
1925 f069addf Iustin Pop
                          self._children[1].dev_path, self.size)
1926 a2cfdea2 Iustin Pop
    if self._lhost and self._lport and self._rhost and self._rport:
1927 1063abd1 Iustin Pop
      self._AssembleNet(minor,
1928 1063abd1 Iustin Pop
                        (self._lhost, self._lport, self._rhost, self._rport),
1929 1063abd1 Iustin Pop
                        constants.DRBD_NET_PROTOCOL,
1930 1063abd1 Iustin Pop
                        hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
1931 a2cfdea2 Iustin Pop
    self._SetFromMinor(minor)
1932 a2cfdea2 Iustin Pop
1933 a2cfdea2 Iustin Pop
  @classmethod
1934 b00b95dd Iustin Pop
  def _ShutdownLocal(cls, minor):
1935 b00b95dd Iustin Pop
    """Detach from the local device.
1936 b00b95dd Iustin Pop

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

1940 b00b95dd Iustin Pop
    """
1941 b00b95dd Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "detach"])
1942 b00b95dd Iustin Pop
    if result.failed:
1943 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't detach local disk: %s", minor, result.output)
1944 b00b95dd Iustin Pop
1945 b00b95dd Iustin Pop
  @classmethod
1946 f3e513ad Iustin Pop
  def _ShutdownNet(cls, minor):
1947 f3e513ad Iustin Pop
    """Disconnect from the remote peer.
1948 f3e513ad Iustin Pop

1949 f3e513ad Iustin Pop
    This fails if we don't have a local device.
1950 f3e513ad Iustin Pop

1951 f3e513ad Iustin Pop
    """
1952 f3e513ad Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "disconnect"])
1953 a8459f1c Iustin Pop
    if result.failed:
1954 1063abd1 Iustin Pop
      _ThrowError("drbd%d: can't shutdown network: %s", minor, result.output)
1955 f3e513ad Iustin Pop
1956 f3e513ad Iustin Pop
  @classmethod
1957 a2cfdea2 Iustin Pop
  def _ShutdownAll(cls, minor):
1958 a2cfdea2 Iustin Pop
    """Deactivate the device.
1959 a2cfdea2 Iustin Pop

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

1962 a2cfdea2 Iustin Pop
    """
1963 a2cfdea2 Iustin Pop
    result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "down"])
1964 a2cfdea2 Iustin Pop
    if result.failed:
1965 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: can't shutdown drbd device: %s",
1966 33bc6f01 Iustin Pop
                  minor, result.output)
1967 a2cfdea2 Iustin Pop
1968 a2cfdea2 Iustin Pop
  def Shutdown(self):
1969 a2cfdea2 Iustin Pop
    """Shutdown the DRBD device.
1970 a2cfdea2 Iustin Pop

1971 a2cfdea2 Iustin Pop
    """
1972 a2cfdea2 Iustin Pop
    if self.minor is None and not self.Attach():
1973 746f7476 Iustin Pop
      logging.info("drbd%d: not attached during Shutdown()", self._aminor)
1974 746f7476 Iustin Pop
      return
1975 746f7476 Iustin Pop
    minor = self.minor
1976 a2cfdea2 Iustin Pop
    self.minor = None
1977 a2cfdea2 Iustin Pop
    self.dev_path = None
1978 746f7476 Iustin Pop
    self._ShutdownAll(minor)
1979 a2cfdea2 Iustin Pop
1980 a2cfdea2 Iustin Pop
  def Remove(self):
1981 a2cfdea2 Iustin Pop
    """Stub remove for DRBD devices.
1982 a2cfdea2 Iustin Pop

1983 a2cfdea2 Iustin Pop
    """
1984 0c6c04ec Iustin Pop
    self.Shutdown()
1985 a2cfdea2 Iustin Pop
1986 a2cfdea2 Iustin Pop
  @classmethod
1987 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
1988 a2cfdea2 Iustin Pop
    """Create a new DRBD8 device.
1989 a2cfdea2 Iustin Pop

1990 a2cfdea2 Iustin Pop
    Since DRBD devices are not created per se, just assembled, this
1991 a2cfdea2 Iustin Pop
    function only initializes the metadata.
1992 a2cfdea2 Iustin Pop

1993 a2cfdea2 Iustin Pop
    """
1994 a2cfdea2 Iustin Pop
    if len(children) != 2:
1995 a2cfdea2 Iustin Pop
      raise errors.ProgrammerError("Invalid setup for the drbd device")
1996 767d52d3 Iustin Pop
    # check that the minor is unused
1997 767d52d3 Iustin Pop
    aminor = unique_id[4]
1998 767d52d3 Iustin Pop
    proc_info = cls._MassageProcData(cls._GetProcData())
1999 767d52d3 Iustin Pop
    if aminor in proc_info:
2000 767d52d3 Iustin Pop
      status = DRBD8Status(proc_info[aminor])
2001 767d52d3 Iustin Pop
      in_use = status.is_in_use
2002 767d52d3 Iustin Pop
    else:
2003 767d52d3 Iustin Pop
      in_use = False
2004 767d52d3 Iustin Pop
    if in_use:
2005 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: minor is already in use at Create() time", aminor)
2006 a2cfdea2 Iustin Pop
    meta = children[1]
2007 a2cfdea2 Iustin Pop
    meta.Assemble()
2008 a2cfdea2 Iustin Pop
    if not meta.Attach():
2009 33bc6f01 Iustin Pop
      _ThrowError("drbd%d: can't attach to meta device '%s'",
2010 33bc6f01 Iustin Pop
                  aminor, meta)
2011 9c793cfb Iustin Pop
    cls._CheckMetaSize(meta.dev_path)
2012 3b559640 Iustin Pop
    cls._InitMeta(aminor, meta.dev_path)
2013 94dcbdb0 Andrea Spadaccini
    return cls(unique_id, children, size, params)
2014 a2cfdea2 Iustin Pop
2015 7fe23d47 Iustin Pop
  def Grow(self, amount, dryrun):
2016 1005d816 Iustin Pop
    """Resize the DRBD device and its backing storage.
2017 1005d816 Iustin Pop

2018 1005d816 Iustin Pop
    """
2019 1005d816 Iustin Pop
    if self.minor is None:
2020 82463074 Iustin Pop
      _ThrowError("drbd%d: Grow called while not attached", self._aminor)
2021 1005d816 Iustin Pop
    if len(self._children) != 2 or None in self._children:
2022 82463074 Iustin Pop
      _ThrowError("drbd%d: cannot grow diskless device", self.minor)
2023 7fe23d47 Iustin Pop
    self._children[0].Grow(amount, dryrun)
2024 7fe23d47 Iustin Pop
    if dryrun:
2025 7fe23d47 Iustin Pop
      # DRBD does not support dry-run mode, so we'll return here
2026 7fe23d47 Iustin Pop
      return
2027 38256320 Iustin Pop
    result = utils.RunCmd(["drbdsetup", self.dev_path, "resize", "-s",
2028 38256320 Iustin Pop
                           "%dm" % (self.size + amount)])
2029 1005d816 Iustin Pop
    if result.failed:
2030 82463074 Iustin Pop
      _ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
2031 1005d816 Iustin Pop
2032 a8083063 Iustin Pop
2033 6f695a2e Manuel Franceschini
class FileStorage(BlockDev):
2034 6f695a2e Manuel Franceschini
  """File device.
2035 abdf0113 Iustin Pop

2036 6f695a2e Manuel Franceschini
  This class represents the a file storage backend device.
2037 6f695a2e Manuel Franceschini

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

2040 6f695a2e Manuel Franceschini
  """
2041 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
2042 6f695a2e Manuel Franceschini
    """Initalizes a file device backend.
2043 6f695a2e Manuel Franceschini

2044 6f695a2e Manuel Franceschini
    """
2045 6f695a2e Manuel Franceschini
    if children:
2046 6f695a2e Manuel Franceschini
      raise errors.BlockDeviceError("Invalid setup for file device")
2047 94dcbdb0 Andrea Spadaccini
    super(FileStorage, self).__init__(unique_id, children, size, params)
2048 6f695a2e Manuel Franceschini
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2049 6f695a2e Manuel Franceschini
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2050 6f695a2e Manuel Franceschini
    self.driver = unique_id[0]
2051 6f695a2e Manuel Franceschini
    self.dev_path = unique_id[1]
2052 ecb091e3 Iustin Pop
    self.Attach()
2053 6f695a2e Manuel Franceschini
2054 6f695a2e Manuel Franceschini
  def Assemble(self):
2055 6f695a2e Manuel Franceschini
    """Assemble the device.
2056 6f695a2e Manuel Franceschini

2057 6f695a2e Manuel Franceschini
    Checks whether the file device exists, raises BlockDeviceError otherwise.
2058 6f695a2e Manuel Franceschini

2059 6f695a2e Manuel Franceschini
    """
2060 6f695a2e Manuel Franceschini
    if not os.path.exists(self.dev_path):
2061 1063abd1 Iustin Pop
      _ThrowError("File device '%s' does not exist" % self.dev_path)
2062 6f695a2e Manuel Franceschini
2063 6f695a2e Manuel Franceschini
  def Shutdown(self):
2064 6f695a2e Manuel Franceschini
    """Shutdown the device.
2065 6f695a2e Manuel Franceschini

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

2069 6f695a2e Manuel Franceschini
    """
2070 746f7476 Iustin Pop
    pass
2071 6f695a2e Manuel Franceschini
2072 6f695a2e Manuel Franceschini
  def Open(self, force=False):
2073 6f695a2e Manuel Franceschini
    """Make the device ready for I/O.
2074 6f695a2e Manuel Franceschini

2075 6f695a2e Manuel Franceschini
    This is a no-op for the file type.
2076 6f695a2e Manuel Franceschini

2077 6f695a2e Manuel Franceschini
    """
2078 6f695a2e Manuel Franceschini
    pass
2079 6f695a2e Manuel Franceschini
2080 6f695a2e Manuel Franceschini
  def Close(self):
2081 6f695a2e Manuel Franceschini
    """Notifies that the device will no longer be used for I/O.
2082 6f695a2e Manuel Franceschini

2083 6f695a2e Manuel Franceschini
    This is a no-op for the file type.
2084 6f695a2e Manuel Franceschini

2085 6f695a2e Manuel Franceschini
    """
2086 6f695a2e Manuel Franceschini
    pass
2087 6f695a2e Manuel Franceschini
2088 6f695a2e Manuel Franceschini
  def Remove(self):
2089 6f695a2e Manuel Franceschini
    """Remove the file backing the block device.
2090 6f695a2e Manuel Franceschini

2091 c41eea6e Iustin Pop
    @rtype: boolean
2092 c41eea6e Iustin Pop
    @return: True if the removal was successful
2093 6f695a2e Manuel Franceschini

2094 6f695a2e Manuel Franceschini
    """
2095 6f695a2e Manuel Franceschini
    try:
2096 6f695a2e Manuel Franceschini
      os.remove(self.dev_path)
2097 6f695a2e Manuel Franceschini
    except OSError, err:
2098 0c6c04ec Iustin Pop
      if err.errno != errno.ENOENT:
2099 0c6c04ec Iustin Pop
        _ThrowError("Can't remove file '%s': %s", self.dev_path, err)
2100 6f695a2e Manuel Franceschini
2101 bbe4cc16 Iustin Pop
  def Rename(self, new_id):
2102 bbe4cc16 Iustin Pop
    """Renames the file.
2103 bbe4cc16 Iustin Pop

2104 bbe4cc16 Iustin Pop
    """
2105 bbe4cc16 Iustin Pop
    # TODO: implement rename for file-based storage
2106 bbe4cc16 Iustin Pop
    _ThrowError("Rename is not supported for file-based storage")
2107 bbe4cc16 Iustin Pop
2108 7fe23d47 Iustin Pop
  def Grow(self, amount, dryrun):
2109 bbe4cc16 Iustin Pop
    """Grow the file
2110 bbe4cc16 Iustin Pop

2111 bbe4cc16 Iustin Pop
    @param amount: the amount (in mebibytes) to grow with
2112 bbe4cc16 Iustin Pop

2113 bbe4cc16 Iustin Pop
    """
2114 91e2d9ec Guido Trotter
    # Check that the file exists
2115 91e2d9ec Guido Trotter
    self.Assemble()
2116 91e2d9ec Guido Trotter
    current_size = self.GetActualSize()
2117 91e2d9ec Guido Trotter
    new_size = current_size + amount * 1024 * 1024
2118 91e2d9ec Guido Trotter
    assert new_size > current_size, "Cannot Grow with a negative amount"
2119 7fe23d47 Iustin Pop
    # We can't really simulate the growth
2120 7fe23d47 Iustin Pop
    if dryrun:
2121 7fe23d47 Iustin Pop
      return
2122 91e2d9ec Guido Trotter
    try:
2123 91e2d9ec Guido Trotter
      f = open(self.dev_path, "a+")
2124 91e2d9ec Guido Trotter
      f.truncate(new_size)
2125 91e2d9ec Guido Trotter
      f.close()
2126 91e2d9ec Guido Trotter
    except EnvironmentError, err:
2127 91e2d9ec Guido Trotter
      _ThrowError("Error in file growth: %", str(err))
2128 bbe4cc16 Iustin Pop
2129 6f695a2e Manuel Franceschini
  def Attach(self):
2130 6f695a2e Manuel Franceschini
    """Attach to an existing file.
2131 6f695a2e Manuel Franceschini

2132 6f695a2e Manuel Franceschini
    Check if this file already exists.
2133 6f695a2e Manuel Franceschini

2134 c41eea6e Iustin Pop
    @rtype: boolean
2135 c41eea6e Iustin Pop
    @return: True if file exists
2136 6f695a2e Manuel Franceschini

2137 6f695a2e Manuel Franceschini
    """
2138 ecb091e3 Iustin Pop
    self.attached = os.path.exists(self.dev_path)
2139 ecb091e3 Iustin Pop
    return self.attached
2140 6f695a2e Manuel Franceschini
2141 fcff3897 Iustin Pop
  def GetActualSize(self):
2142 fcff3897 Iustin Pop
    """Return the actual disk size.
2143 fcff3897 Iustin Pop

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

2146 fcff3897 Iustin Pop
    """
2147 fcff3897 Iustin Pop
    assert self.attached, "BlockDevice not attached in GetActualSize()"
2148 fcff3897 Iustin Pop
    try:
2149 fcff3897 Iustin Pop
      st = os.stat(self.dev_path)
2150 fcff3897 Iustin Pop
      return st.st_size
2151 fcff3897 Iustin Pop
    except OSError, err:
2152 fcff3897 Iustin Pop
      _ThrowError("Can't stat %s: %s", self.dev_path, err)
2153 fcff3897 Iustin Pop
2154 6f695a2e Manuel Franceschini
  @classmethod
2155 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
2156 6f695a2e Manuel Franceschini
    """Create a new file.
2157 6f695a2e Manuel Franceschini

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

2160 c41eea6e Iustin Pop
    @rtype: L{bdev.FileStorage}
2161 c41eea6e Iustin Pop
    @return: an instance of FileStorage
2162 6f695a2e Manuel Franceschini

2163 6f695a2e Manuel Franceschini
    """
2164 6f695a2e Manuel Franceschini
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2165 6f695a2e Manuel Franceschini
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2166 6f695a2e Manuel Franceschini
    dev_path = unique_id[1]
2167 6f695a2e Manuel Franceschini
    try:
2168 cdeefd9b Guido Trotter
      fd = os.open(dev_path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
2169 cdeefd9b Guido Trotter
      f = os.fdopen(fd, "w")
2170 6f695a2e Manuel Franceschini
      f.truncate(size * 1024 * 1024)
2171 6f695a2e Manuel Franceschini
      f.close()
2172 cdeefd9b Guido Trotter
    except EnvironmentError, err:
2173 cdeefd9b Guido Trotter
      if err.errno == errno.EEXIST:
2174 cdeefd9b Guido Trotter
        _ThrowError("File already existing: %s", dev_path)
2175 82463074 Iustin Pop
      _ThrowError("Error in file creation: %", str(err))
2176 6f695a2e Manuel Franceschini
2177 94dcbdb0 Andrea Spadaccini
    return FileStorage(unique_id, children, size, params)
2178 6f695a2e Manuel Franceschini
2179 6f695a2e Manuel Franceschini
2180 b6135bbc Apollon Oikonomopoulos
class PersistentBlockDevice(BlockDev):
2181 b6135bbc Apollon Oikonomopoulos
  """A block device with persistent node
2182 b6135bbc Apollon Oikonomopoulos

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

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

2189 b6135bbc Apollon Oikonomopoulos
  """
2190 94dcbdb0 Andrea Spadaccini
  def __init__(self, unique_id, children, size, params):
2191 b6135bbc Apollon Oikonomopoulos
    """Attaches to a static block device.
2192 b6135bbc Apollon Oikonomopoulos

2193 b6135bbc Apollon Oikonomopoulos
    The unique_id is a path under /dev.
2194 b6135bbc Apollon Oikonomopoulos

2195 b6135bbc Apollon Oikonomopoulos
    """
2196 94dcbdb0 Andrea Spadaccini
    super(PersistentBlockDevice, self).__init__(unique_id, children, size,
2197 94dcbdb0 Andrea Spadaccini
                                                params)
2198 b6135bbc Apollon Oikonomopoulos
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
2199 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Invalid configuration data %s" % str(unique_id))
2200 b6135bbc Apollon Oikonomopoulos
    self.dev_path = unique_id[1]
2201 d0c8c01d Iustin Pop
    if not os.path.realpath(self.dev_path).startswith("/dev/"):
2202 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Full path '%s' lies outside /dev" %
2203 b6135bbc Apollon Oikonomopoulos
                              os.path.realpath(self.dev_path))
2204 b6135bbc Apollon Oikonomopoulos
    # TODO: this is just a safety guard checking that we only deal with devices
2205 b6135bbc Apollon Oikonomopoulos
    # we know how to handle. In the future this will be integrated with
2206 b6135bbc Apollon Oikonomopoulos
    # external storage backends and possible values will probably be collected
2207 b6135bbc Apollon Oikonomopoulos
    # from the cluster configuration.
2208 b6135bbc Apollon Oikonomopoulos
    if unique_id[0] != constants.BLOCKDEV_DRIVER_MANUAL:
2209 b6135bbc Apollon Oikonomopoulos
      raise ValueError("Got persistent block device of invalid type: %s" %
2210 b6135bbc Apollon Oikonomopoulos
                       unique_id[0])
2211 b6135bbc Apollon Oikonomopoulos
2212 b6135bbc Apollon Oikonomopoulos
    self.major = self.minor = None
2213 b6135bbc Apollon Oikonomopoulos
    self.Attach()
2214 b6135bbc Apollon Oikonomopoulos
2215 b6135bbc Apollon Oikonomopoulos
  @classmethod
2216 94dcbdb0 Andrea Spadaccini
  def Create(cls, unique_id, children, size, params):
2217 b6135bbc Apollon Oikonomopoulos
    """Create a new device
2218 b6135bbc Apollon Oikonomopoulos

2219 b6135bbc Apollon Oikonomopoulos
    This is a noop, we only return a PersistentBlockDevice instance
2220 b6135bbc Apollon Oikonomopoulos

2221 b6135bbc Apollon Oikonomopoulos
    """
2222 94dcbdb0 Andrea Spadaccini
    return PersistentBlockDevice(unique_id, children, 0, params)
2223 b6135bbc Apollon Oikonomopoulos
2224 b6135bbc Apollon Oikonomopoulos
  def Remove(self):
2225 b6135bbc Apollon Oikonomopoulos
    """Remove a device
2226 b6135bbc Apollon Oikonomopoulos

2227 b6135bbc Apollon Oikonomopoulos
    This is a noop
2228 b6135bbc Apollon Oikonomopoulos

2229 b6135bbc Apollon Oikonomopoulos
    """
2230 b6135bbc Apollon Oikonomopoulos
    pass
2231 b6135bbc Apollon Oikonomopoulos
2232 b6135bbc Apollon Oikonomopoulos
  def Rename(self, new_id):
2233 b6135bbc Apollon Oikonomopoulos
    """Rename this device.
2234 b6135bbc Apollon Oikonomopoulos

2235 b6135bbc Apollon Oikonomopoulos
    """
2236 b6135bbc Apollon Oikonomopoulos
    _ThrowError("Rename is not supported for PersistentBlockDev storage")
2237 b6135bbc Apollon Oikonomopoulos
2238 b6135bbc Apollon Oikonomopoulos
  def Attach(self):
2239 b6135bbc Apollon Oikonomopoulos
    """Attach to an existing block device.
2240 b6135bbc Apollon Oikonomopoulos

2241 b6135bbc Apollon Oikonomopoulos

2242 b6135bbc Apollon Oikonomopoulos
    """
2243 b6135bbc Apollon Oikonomopoulos
    self.attached = False
2244 b6135bbc Apollon Oikonomopoulos
    try:
2245 b6135bbc Apollon Oikonomopoulos
      st = os.stat(self.dev_path)
2246 b6135bbc Apollon Oikonomopoulos
    except OSError, err:
2247 b6135bbc Apollon Oikonomopoulos
      logging.error("Error stat()'ing %s: %s", self.dev_path, str(err))
2248 b6135bbc Apollon Oikonomopoulos
      return False
2249 b6135bbc Apollon Oikonomopoulos
2250 b6135bbc Apollon Oikonomopoulos
    if not stat.S_ISBLK(st.st_mode):
2251 b6135bbc Apollon Oikonomopoulos
      logging.error("%s is not a block device", self.dev_path)
2252 b6135bbc Apollon Oikonomopoulos
      return False
2253 b6135bbc Apollon Oikonomopoulos
2254 b6135bbc Apollon Oikonomopoulos
    self.major = os.major(st.st_rdev)
2255 b6135bbc Apollon Oikonomopoulos
    self.minor = os.minor(st.st_rdev)
2256 b6135bbc Apollon Oikonomopoulos
    self.attached = True
2257 b6135bbc Apollon Oikonomopoulos
2258 b6135bbc Apollon Oikonomopoulos
    return True
2259 b6135bbc Apollon Oikonomopoulos
2260 b6135bbc Apollon Oikonomopoulos
  def Assemble(self):
2261 b6135bbc Apollon Oikonomopoulos
    """Assemble the device.
2262 b6135bbc Apollon Oikonomopoulos

2263 b6135bbc Apollon Oikonomopoulos
    """
2264 b6135bbc Apollon Oikonomopoulos
    pass
2265 b6135bbc Apollon Oikonomopoulos
2266 b6135bbc Apollon Oikonomopoulos
  def Shutdown(self):
2267 b6135bbc Apollon Oikonomopoulos
    """Shutdown the device.
2268 b6135bbc Apollon Oikonomopoulos

2269 b6135bbc Apollon Oikonomopoulos
    """
2270 b6135bbc Apollon Oikonomopoulos
    pass
2271 b6135bbc Apollon Oikonomopoulos
2272 b6135bbc Apollon Oikonomopoulos
  def Open(self, force=False):
2273 b6135bbc Apollon Oikonomopoulos
    """Make the device ready for I/O.
2274 b6135bbc Apollon Oikonomopoulos

2275 b6135bbc Apollon Oikonomopoulos
    """
2276 b6135bbc Apollon Oikonomopoulos
    pass
2277 b6135bbc Apollon Oikonomopoulos
2278 b6135bbc Apollon Oikonomopoulos
  def Close(self):
2279 b6135bbc Apollon Oikonomopoulos
    """Notifies that the device will no longer be used for I/O.
2280 b6135bbc Apollon Oikonomopoulos

2281 b6135bbc Apollon Oikonomopoulos
    """
2282 b6135bbc Apollon Oikonomopoulos
    pass
2283 b6135bbc Apollon Oikonomopoulos
2284 7fe23d47 Iustin Pop
  def Grow(self, amount, dryrun):
2285 b6135bbc Apollon Oikonomopoulos
    """Grow the logical volume.
2286 b6135bbc Apollon Oikonomopoulos

2287 b6135bbc Apollon Oikonomopoulos
    """
2288 b6135bbc Apollon Oikonomopoulos
    _ThrowError("Grow is not supported for PersistentBlockDev storage")
2289 b6135bbc Apollon Oikonomopoulos
2290 b6135bbc Apollon Oikonomopoulos
2291 a8083063 Iustin Pop
DEV_MAP = {
2292 fe96220b Iustin Pop
  constants.LD_LV: LogicalVolume,
2293 a1f445d3 Iustin Pop
  constants.LD_DRBD8: DRBD8,
2294 b6135bbc Apollon Oikonomopoulos
  constants.LD_BLOCKDEV: PersistentBlockDevice,
2295 a8083063 Iustin Pop
  }
2296 a8083063 Iustin Pop
2297 4b97f902 Apollon Oikonomopoulos
if constants.ENABLE_FILE_STORAGE or constants.ENABLE_SHARED_FILE_STORAGE:
2298 cb7c0198 Iustin Pop
  DEV_MAP[constants.LD_FILE] = FileStorage
2299 cb7c0198 Iustin Pop
2300 a8083063 Iustin Pop
2301 94dcbdb0 Andrea Spadaccini
def _VerifyDiskType(dev_type):
2302 94dcbdb0 Andrea Spadaccini
  if dev_type not in DEV_MAP:
2303 94dcbdb0 Andrea Spadaccini
    raise errors.ProgrammerError("Invalid block device type '%s'" % dev_type)
2304 94dcbdb0 Andrea Spadaccini
2305 94dcbdb0 Andrea Spadaccini
2306 94dcbdb0 Andrea Spadaccini
def FindDevice(disk, children):
2307 a8083063 Iustin Pop
  """Search for an existing, assembled device.
2308 a8083063 Iustin Pop

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

2312 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2313 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to find
2314 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2315 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2316 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2317 94dcbdb0 Andrea Spadaccini

2318 a8083063 Iustin Pop
  """
2319 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2320 94dcbdb0 Andrea Spadaccini
  dev_params = objects.FillDict(constants.DISK_LD_DEFAULTS[disk.dev_type],
2321 94dcbdb0 Andrea Spadaccini
                                disk.params)
2322 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type](disk.physical_id, children, disk.size,
2323 94dcbdb0 Andrea Spadaccini
                                  dev_params)
2324 cb999543 Iustin Pop
  if not device.attached:
2325 a8083063 Iustin Pop
    return None
2326 ecb091e3 Iustin Pop
  return device
2327 a8083063 Iustin Pop
2328 a8083063 Iustin Pop
2329 94dcbdb0 Andrea Spadaccini
def Assemble(disk, children):
2330 a8083063 Iustin Pop
  """Try to attach or assemble an existing device.
2331 a8083063 Iustin Pop

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

2335 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2336 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to assemble
2337 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2338 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2339 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2340 94dcbdb0 Andrea Spadaccini

2341 a8083063 Iustin Pop
  """
2342 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2343 94dcbdb0 Andrea Spadaccini
  dev_params = objects.FillDict(constants.DISK_LD_DEFAULTS[disk.dev_type],
2344 94dcbdb0 Andrea Spadaccini
                                disk.params)
2345 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type](disk.physical_id, children, disk.size,
2346 94dcbdb0 Andrea Spadaccini
                                  dev_params)
2347 1063abd1 Iustin Pop
  device.Assemble()
2348 a8083063 Iustin Pop
  return device
2349 a8083063 Iustin Pop
2350 a8083063 Iustin Pop
2351 94dcbdb0 Andrea Spadaccini
def Create(disk, children):
2352 a8083063 Iustin Pop
  """Create a device.
2353 a8083063 Iustin Pop

2354 94dcbdb0 Andrea Spadaccini
  @type disk: L{objects.Disk}
2355 94dcbdb0 Andrea Spadaccini
  @param disk: the disk object to create
2356 94dcbdb0 Andrea Spadaccini
  @type children: list of L{bdev.BlockDev}
2357 94dcbdb0 Andrea Spadaccini
  @param children: the list of block devices that are children of the device
2358 94dcbdb0 Andrea Spadaccini
                  represented by the disk parameter
2359 94dcbdb0 Andrea Spadaccini

2360 a8083063 Iustin Pop
  """
2361 94dcbdb0 Andrea Spadaccini
  _VerifyDiskType(disk.dev_type)
2362 94dcbdb0 Andrea Spadaccini
  dev_params = objects.FillDict(constants.DISK_LD_DEFAULTS[disk.dev_type],
2363 94dcbdb0 Andrea Spadaccini
                                disk.params)
2364 94dcbdb0 Andrea Spadaccini
  device = DEV_MAP[disk.dev_type].Create(disk.physical_id, children, disk.size,
2365 94dcbdb0 Andrea Spadaccini
                                         dev_params)
2366 a8083063 Iustin Pop
  return device