Statistics
| Branch: | Tag: | Revision:

root / lib / storage / drbd.py @ 8f8442d6

History | View | Annotate | Download (34.7 kB)

1 89ff748d Thomas Thrainer
#
2 89ff748d Thomas Thrainer
#
3 89ff748d Thomas Thrainer
4 89ff748d Thomas Thrainer
# Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Google Inc.
5 89ff748d Thomas Thrainer
#
6 89ff748d Thomas Thrainer
# This program is free software; you can redistribute it and/or modify
7 89ff748d Thomas Thrainer
# it under the terms of the GNU General Public License as published by
8 89ff748d Thomas Thrainer
# the Free Software Foundation; either version 2 of the License, or
9 89ff748d Thomas Thrainer
# (at your option) any later version.
10 89ff748d Thomas Thrainer
#
11 89ff748d Thomas Thrainer
# This program is distributed in the hope that it will be useful, but
12 89ff748d Thomas Thrainer
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 89ff748d Thomas Thrainer
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 89ff748d Thomas Thrainer
# General Public License for more details.
15 89ff748d Thomas Thrainer
#
16 89ff748d Thomas Thrainer
# You should have received a copy of the GNU General Public License
17 89ff748d Thomas Thrainer
# along with this program; if not, write to the Free Software
18 89ff748d Thomas Thrainer
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 89ff748d Thomas Thrainer
# 02110-1301, USA.
20 89ff748d Thomas Thrainer
21 89ff748d Thomas Thrainer
22 89ff748d Thomas Thrainer
"""DRBD block device related functionality"""
23 89ff748d Thomas Thrainer
24 89ff748d Thomas Thrainer
import errno
25 89ff748d Thomas Thrainer
import logging
26 89ff748d Thomas Thrainer
import time
27 89ff748d Thomas Thrainer
28 89ff748d Thomas Thrainer
from ganeti import constants
29 89ff748d Thomas Thrainer
from ganeti import utils
30 89ff748d Thomas Thrainer
from ganeti import errors
31 89ff748d Thomas Thrainer
from ganeti import netutils
32 89ff748d Thomas Thrainer
from ganeti import objects
33 cde49218 Helga Velroyen
from ganeti.storage import base
34 cde49218 Helga Velroyen
from ganeti.storage.drbd_info import DRBD8Info
35 cde49218 Helga Velroyen
from ganeti.storage import drbd_info
36 cde49218 Helga Velroyen
from ganeti.storage import drbd_cmdgen
37 89ff748d Thomas Thrainer
38 89ff748d Thomas Thrainer
39 89ff748d Thomas Thrainer
# Size of reads in _CanReadDevice
40 89ff748d Thomas Thrainer
41 89ff748d Thomas Thrainer
_DEVICE_READ_SIZE = 128 * 1024
42 89ff748d Thomas Thrainer
43 89ff748d Thomas Thrainer
44 47e0abee Thomas Thrainer
class DRBD8(object):
45 47e0abee Thomas Thrainer
  """Various methods to deals with the DRBD system as a whole.
46 47e0abee Thomas Thrainer

47 47e0abee Thomas Thrainer
  This class provides a set of methods to deal with the DRBD installation on
48 47e0abee Thomas Thrainer
  the node or with uninitialized devices as opposed to a DRBD device.
49 47e0abee Thomas Thrainer

50 47e0abee Thomas Thrainer
  """
51 47e0abee Thomas Thrainer
  _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
52 47e0abee Thomas Thrainer
53 47e0abee Thomas Thrainer
  _MAX_MINORS = 255
54 47e0abee Thomas Thrainer
55 47e0abee Thomas Thrainer
  @staticmethod
56 47e0abee Thomas Thrainer
  def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE):
57 47e0abee Thomas Thrainer
    """Returns DRBD usermode_helper currently set.
58 47e0abee Thomas Thrainer

59 47e0abee Thomas Thrainer
    @type filename: string
60 47e0abee Thomas Thrainer
    @param filename: the filename to read the usermode helper from
61 47e0abee Thomas Thrainer
    @rtype: string
62 47e0abee Thomas Thrainer
    @return: the currently configured DRBD usermode helper
63 47e0abee Thomas Thrainer

64 47e0abee Thomas Thrainer
    """
65 47e0abee Thomas Thrainer
    try:
66 47e0abee Thomas Thrainer
      helper = utils.ReadFile(filename).splitlines()[0]
67 47e0abee Thomas Thrainer
    except EnvironmentError, err:
68 47e0abee Thomas Thrainer
      if err.errno == errno.ENOENT:
69 47e0abee Thomas Thrainer
        base.ThrowError("The file %s cannot be opened, check if the module"
70 47e0abee Thomas Thrainer
                        " is loaded (%s)", filename, str(err))
71 47e0abee Thomas Thrainer
      else:
72 47e0abee Thomas Thrainer
        base.ThrowError("Can't read DRBD helper file %s: %s",
73 47e0abee Thomas Thrainer
                        filename, str(err))
74 47e0abee Thomas Thrainer
    if not helper:
75 47e0abee Thomas Thrainer
      base.ThrowError("Can't read any data from %s", filename)
76 47e0abee Thomas Thrainer
    return helper
77 47e0abee Thomas Thrainer
78 47e0abee Thomas Thrainer
  @staticmethod
79 47e0abee Thomas Thrainer
  def GetProcInfo():
80 47e0abee Thomas Thrainer
    """Reads and parses information from /proc/drbd.
81 47e0abee Thomas Thrainer

82 47e0abee Thomas Thrainer
    @rtype: DRBD8Info
83 47e0abee Thomas Thrainer
    @return: a L{DRBD8Info} instance containing the current /proc/drbd info
84 47e0abee Thomas Thrainer

85 47e0abee Thomas Thrainer
    """
86 47e0abee Thomas Thrainer
    return DRBD8Info.CreateFromFile()
87 47e0abee Thomas Thrainer
88 47e0abee Thomas Thrainer
  @staticmethod
89 47e0abee Thomas Thrainer
  def GetUsedDevs():
90 47e0abee Thomas Thrainer
    """Compute the list of used DRBD minors.
91 47e0abee Thomas Thrainer

92 47e0abee Thomas Thrainer
    @rtype: list of ints
93 47e0abee Thomas Thrainer

94 47e0abee Thomas Thrainer
    """
95 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
96 47e0abee Thomas Thrainer
    return filter(lambda m: not info.GetMinorStatus(m).is_unconfigured,
97 47e0abee Thomas Thrainer
                  info.GetMinors())
98 47e0abee Thomas Thrainer
99 47e0abee Thomas Thrainer
  @staticmethod
100 47e0abee Thomas Thrainer
  def FindUnusedMinor():
101 47e0abee Thomas Thrainer
    """Find an unused DRBD device.
102 47e0abee Thomas Thrainer

103 47e0abee Thomas Thrainer
    This is specific to 8.x as the minors are allocated dynamically,
104 47e0abee Thomas Thrainer
    so non-existing numbers up to a max minor count are actually free.
105 47e0abee Thomas Thrainer

106 47e0abee Thomas Thrainer
    @rtype: int
107 47e0abee Thomas Thrainer

108 47e0abee Thomas Thrainer
    """
109 47e0abee Thomas Thrainer
    highest = None
110 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
111 47e0abee Thomas Thrainer
    for minor in info.GetMinors():
112 47e0abee Thomas Thrainer
      status = info.GetMinorStatus(minor)
113 47e0abee Thomas Thrainer
      if not status.is_in_use:
114 47e0abee Thomas Thrainer
        return minor
115 47e0abee Thomas Thrainer
      highest = max(highest, minor)
116 47e0abee Thomas Thrainer
117 47e0abee Thomas Thrainer
    if highest is None: # there are no minors in use at all
118 47e0abee Thomas Thrainer
      return 0
119 47e0abee Thomas Thrainer
    if highest >= DRBD8._MAX_MINORS:
120 47e0abee Thomas Thrainer
      logging.error("Error: no free drbd minors!")
121 47e0abee Thomas Thrainer
      raise errors.BlockDeviceError("Can't find a free DRBD minor")
122 47e0abee Thomas Thrainer
123 47e0abee Thomas Thrainer
    return highest + 1
124 47e0abee Thomas Thrainer
125 47e0abee Thomas Thrainer
  @staticmethod
126 47e0abee Thomas Thrainer
  def GetCmdGenerator(info):
127 47e0abee Thomas Thrainer
    """Creates a suitable L{BaseDRBDCmdGenerator} based on the given info.
128 47e0abee Thomas Thrainer

129 47e0abee Thomas Thrainer
    @type info: DRBD8Info
130 47e0abee Thomas Thrainer
    @rtype: BaseDRBDCmdGenerator
131 47e0abee Thomas Thrainer

132 47e0abee Thomas Thrainer
    """
133 47e0abee Thomas Thrainer
    version = info.GetVersion()
134 47e0abee Thomas Thrainer
    if version["k_minor"] <= 3:
135 47e0abee Thomas Thrainer
      return drbd_cmdgen.DRBD83CmdGenerator(version)
136 47e0abee Thomas Thrainer
    else:
137 47e0abee Thomas Thrainer
      return drbd_cmdgen.DRBD84CmdGenerator(version)
138 47e0abee Thomas Thrainer
139 47e0abee Thomas Thrainer
  @staticmethod
140 47e0abee Thomas Thrainer
  def ShutdownAll(minor):
141 47e0abee Thomas Thrainer
    """Deactivate the device.
142 47e0abee Thomas Thrainer

143 47e0abee Thomas Thrainer
    This will, of course, fail if the device is in use.
144 47e0abee Thomas Thrainer

145 47e0abee Thomas Thrainer
    @type minor: int
146 47e0abee Thomas Thrainer
    @param minor: the minor to shut down
147 47e0abee Thomas Thrainer

148 47e0abee Thomas Thrainer
    """
149 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
150 47e0abee Thomas Thrainer
    cmd_gen = DRBD8.GetCmdGenerator(info)
151 47e0abee Thomas Thrainer
152 47e0abee Thomas Thrainer
    cmd = cmd_gen.GenDownCmd(minor)
153 47e0abee Thomas Thrainer
    result = utils.RunCmd(cmd)
154 47e0abee Thomas Thrainer
    if result.failed:
155 47e0abee Thomas Thrainer
      base.ThrowError("drbd%d: can't shutdown drbd device: %s",
156 47e0abee Thomas Thrainer
                      minor, result.output)
157 47e0abee Thomas Thrainer
158 47e0abee Thomas Thrainer
159 239364d0 Thomas Thrainer
class DRBD8Dev(base.BlockDev):
160 fd300bc7 Thomas Thrainer
  """DRBD v8.x block device.
161 fd300bc7 Thomas Thrainer

162 fd300bc7 Thomas Thrainer
  This implements the local host part of the DRBD device, i.e. it
163 fd300bc7 Thomas Thrainer
  doesn't do anything to the supposed peer. If you need a fully
164 fd300bc7 Thomas Thrainer
  connected DRBD pair, you need to use this class on both hosts.
165 fd300bc7 Thomas Thrainer

166 fd300bc7 Thomas Thrainer
  The unique_id for the drbd device is a (local_ip, local_port,
167 fd300bc7 Thomas Thrainer
  remote_ip, remote_port, local_minor, secret) tuple, and it must have
168 fd300bc7 Thomas Thrainer
  two children: the data device and the meta_device. The meta device
169 fd300bc7 Thomas Thrainer
  is checked for valid size and is zeroed on create.
170 89ff748d Thomas Thrainer

171 89ff748d Thomas Thrainer
  """
172 89ff748d Thomas Thrainer
  _DRBD_MAJOR = 147
173 89ff748d Thomas Thrainer
174 fd300bc7 Thomas Thrainer
  # timeout constants
175 fd300bc7 Thomas Thrainer
  _NET_RECONFIG_TIMEOUT = 60
176 fd300bc7 Thomas Thrainer
177 fd300bc7 Thomas Thrainer
  def __init__(self, unique_id, children, size, params):
178 fd300bc7 Thomas Thrainer
    if children and children.count(None) > 0:
179 fd300bc7 Thomas Thrainer
      children = []
180 fd300bc7 Thomas Thrainer
    if len(children) not in (0, 2):
181 fd300bc7 Thomas Thrainer
      raise ValueError("Invalid configuration data %s" % str(children))
182 fd300bc7 Thomas Thrainer
    if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 6:
183 fd300bc7 Thomas Thrainer
      raise ValueError("Invalid configuration data %s" % str(unique_id))
184 fd300bc7 Thomas Thrainer
    (self._lhost, self._lport,
185 fd300bc7 Thomas Thrainer
     self._rhost, self._rport,
186 fd300bc7 Thomas Thrainer
     self._aminor, self._secret) = unique_id
187 fd300bc7 Thomas Thrainer
    if children:
188 fd300bc7 Thomas Thrainer
      if not _CanReadDevice(children[1].dev_path):
189 fd300bc7 Thomas Thrainer
        logging.info("drbd%s: Ignoring unreadable meta device", self._aminor)
190 fd300bc7 Thomas Thrainer
        children = []
191 239364d0 Thomas Thrainer
    super(DRBD8Dev, self).__init__(unique_id, children, size, params)
192 fd300bc7 Thomas Thrainer
    self.major = self._DRBD_MAJOR
193 2fe690f1 Thomas Thrainer
194 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
195 47e0abee Thomas Thrainer
    version = info.GetVersion()
196 fd300bc7 Thomas Thrainer
    if version["k_major"] != 8:
197 fd300bc7 Thomas Thrainer
      base.ThrowError("Mismatch in DRBD kernel version and requested ganeti"
198 fd300bc7 Thomas Thrainer
                      " usage: kernel is %s.%s, ganeti wants 8.x",
199 fd300bc7 Thomas Thrainer
                      version["k_major"], version["k_minor"])
200 fd300bc7 Thomas Thrainer
201 27c7d9c3 Thomas Thrainer
    if version["k_minor"] <= 3:
202 47e0abee Thomas Thrainer
      self._show_info_cls = drbd_info.DRBD83ShowInfo
203 27c7d9c3 Thomas Thrainer
    else:
204 47e0abee Thomas Thrainer
      self._show_info_cls = drbd_info.DRBD84ShowInfo
205 daec28a7 Thomas Thrainer
206 47e0abee Thomas Thrainer
    self._cmd_gen = DRBD8.GetCmdGenerator(info)
207 27c7d9c3 Thomas Thrainer
208 fd300bc7 Thomas Thrainer
    if (self._lhost is not None and self._lhost == self._rhost and
209 fd300bc7 Thomas Thrainer
            self._lport == self._rport):
210 fd300bc7 Thomas Thrainer
      raise ValueError("Invalid configuration data, same local/remote %s" %
211 fd300bc7 Thomas Thrainer
                       (unique_id,))
212 fd300bc7 Thomas Thrainer
    self.Attach()
213 fd300bc7 Thomas Thrainer
214 89ff748d Thomas Thrainer
  @staticmethod
215 89ff748d Thomas Thrainer
  def _DevPath(minor):
216 89ff748d Thomas Thrainer
    """Return the path to a drbd device for a given minor.
217 89ff748d Thomas Thrainer

218 47e0abee Thomas Thrainer
    @type minor: int
219 47e0abee Thomas Thrainer
    @rtype: string
220 89ff748d Thomas Thrainer

221 89ff748d Thomas Thrainer
    """
222 47e0abee Thomas Thrainer
    return "/dev/drbd%d" % minor
223 89ff748d Thomas Thrainer
224 89ff748d Thomas Thrainer
  def _SetFromMinor(self, minor):
225 89ff748d Thomas Thrainer
    """Set our parameters based on the given minor.
226 89ff748d Thomas Thrainer

227 89ff748d Thomas Thrainer
    This sets our minor variable and our dev_path.
228 89ff748d Thomas Thrainer

229 47e0abee Thomas Thrainer
    @type minor: int
230 47e0abee Thomas Thrainer

231 89ff748d Thomas Thrainer
    """
232 89ff748d Thomas Thrainer
    if minor is None:
233 89ff748d Thomas Thrainer
      self.minor = self.dev_path = None
234 89ff748d Thomas Thrainer
      self.attached = False
235 89ff748d Thomas Thrainer
    else:
236 89ff748d Thomas Thrainer
      self.minor = minor
237 89ff748d Thomas Thrainer
      self.dev_path = self._DevPath(minor)
238 89ff748d Thomas Thrainer
      self.attached = True
239 89ff748d Thomas Thrainer
240 89ff748d Thomas Thrainer
  @staticmethod
241 89ff748d Thomas Thrainer
  def _CheckMetaSize(meta_device):
242 89ff748d Thomas Thrainer
    """Check if the given meta device looks like a valid one.
243 89ff748d Thomas Thrainer

244 89ff748d Thomas Thrainer
    This currently only checks the size, which must be around
245 89ff748d Thomas Thrainer
    128MiB.
246 89ff748d Thomas Thrainer

247 47e0abee Thomas Thrainer
    @type meta_device: string
248 47e0abee Thomas Thrainer
    @param meta_device: the path to the device to check
249 47e0abee Thomas Thrainer

250 89ff748d Thomas Thrainer
    """
251 89ff748d Thomas Thrainer
    result = utils.RunCmd(["blockdev", "--getsize", meta_device])
252 89ff748d Thomas Thrainer
    if result.failed:
253 89ff748d Thomas Thrainer
      base.ThrowError("Failed to get device size: %s - %s",
254 89ff748d Thomas Thrainer
                      result.fail_reason, result.output)
255 89ff748d Thomas Thrainer
    try:
256 89ff748d Thomas Thrainer
      sectors = int(result.stdout)
257 89ff748d Thomas Thrainer
    except (TypeError, ValueError):
258 89ff748d Thomas Thrainer
      base.ThrowError("Invalid output from blockdev: '%s'", result.stdout)
259 89ff748d Thomas Thrainer
    num_bytes = sectors * 512
260 89ff748d Thomas Thrainer
    if num_bytes < 128 * 1024 * 1024: # less than 128MiB
261 89ff748d Thomas Thrainer
      base.ThrowError("Meta device too small (%.2fMib)",
262 89ff748d Thomas Thrainer
                      (num_bytes / 1024 / 1024))
263 89ff748d Thomas Thrainer
    # the maximum *valid* size of the meta device when living on top
264 89ff748d Thomas Thrainer
    # of LVM is hard to compute: it depends on the number of stripes
265 89ff748d Thomas Thrainer
    # and the PE size; e.g. a 2-stripe, 64MB PE will result in a 128MB
266 89ff748d Thomas Thrainer
    # (normal size), but an eight-stripe 128MB PE will result in a 1GB
267 89ff748d Thomas Thrainer
    # size meta device; as such, we restrict it to 1GB (a little bit
268 89ff748d Thomas Thrainer
    # too generous, but making assumptions about PE size is hard)
269 89ff748d Thomas Thrainer
    if num_bytes > 1024 * 1024 * 1024:
270 89ff748d Thomas Thrainer
      base.ThrowError("Meta device too big (%.2fMiB)",
271 89ff748d Thomas Thrainer
                      (num_bytes / 1024 / 1024))
272 89ff748d Thomas Thrainer
273 09a78e1c Thomas Thrainer
  def _GetShowData(self, minor):
274 47e0abee Thomas Thrainer
    """Return the `drbdsetup show` data.
275 47e0abee Thomas Thrainer

276 47e0abee Thomas Thrainer
    @type minor: int
277 47e0abee Thomas Thrainer
    @param minor: the minor to collect show output for
278 47e0abee Thomas Thrainer
    @rtype: string
279 89ff748d Thomas Thrainer

280 89ff748d Thomas Thrainer
    """
281 09a78e1c Thomas Thrainer
    result = utils.RunCmd(self._cmd_gen.GenShowCmd(minor))
282 89ff748d Thomas Thrainer
    if result.failed:
283 89ff748d Thomas Thrainer
      logging.error("Can't display the drbd config: %s - %s",
284 89ff748d Thomas Thrainer
                    result.fail_reason, result.output)
285 89ff748d Thomas Thrainer
      return None
286 89ff748d Thomas Thrainer
    return result.stdout
287 89ff748d Thomas Thrainer
288 27c7d9c3 Thomas Thrainer
  def _GetShowInfo(self, minor):
289 47e0abee Thomas Thrainer
    """Return parsed information from `drbdsetup show`.
290 47e0abee Thomas Thrainer

291 47e0abee Thomas Thrainer
    @type minor: int
292 47e0abee Thomas Thrainer
    @param minor: the minor to return information for
293 47e0abee Thomas Thrainer
    @rtype: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
294 47e0abee Thomas Thrainer

295 47e0abee Thomas Thrainer
    """
296 27c7d9c3 Thomas Thrainer
    return self._show_info_cls.GetDevInfo(self._GetShowData(minor))
297 27c7d9c3 Thomas Thrainer
298 89ff748d Thomas Thrainer
  def _MatchesLocal(self, info):
299 89ff748d Thomas Thrainer
    """Test if our local config matches with an existing device.
300 89ff748d Thomas Thrainer

301 47e0abee Thomas Thrainer
    The parameter should be as returned from `_GetShowInfo()`. This
302 89ff748d Thomas Thrainer
    method tests if our local backing device is the same as the one in
303 89ff748d Thomas Thrainer
    the info parameter, in effect testing if we look like the given
304 89ff748d Thomas Thrainer
    device.
305 89ff748d Thomas Thrainer

306 47e0abee Thomas Thrainer
    @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
307 47e0abee Thomas Thrainer
    @rtype: boolean
308 47e0abee Thomas Thrainer

309 89ff748d Thomas Thrainer
    """
310 89ff748d Thomas Thrainer
    if self._children:
311 89ff748d Thomas Thrainer
      backend, meta = self._children
312 89ff748d Thomas Thrainer
    else:
313 89ff748d Thomas Thrainer
      backend = meta = None
314 89ff748d Thomas Thrainer
315 89ff748d Thomas Thrainer
    if backend is not None:
316 89ff748d Thomas Thrainer
      retval = ("local_dev" in info and info["local_dev"] == backend.dev_path)
317 89ff748d Thomas Thrainer
    else:
318 89ff748d Thomas Thrainer
      retval = ("local_dev" not in info)
319 89ff748d Thomas Thrainer
320 89ff748d Thomas Thrainer
    if meta is not None:
321 89ff748d Thomas Thrainer
      retval = retval and ("meta_dev" in info and
322 89ff748d Thomas Thrainer
                           info["meta_dev"] == meta.dev_path)
323 085b8e24 Thomas Thrainer
      if "meta_index" in info:
324 085b8e24 Thomas Thrainer
        retval = retval and info["meta_index"] == 0
325 89ff748d Thomas Thrainer
    else:
326 89ff748d Thomas Thrainer
      retval = retval and ("meta_dev" not in info and
327 89ff748d Thomas Thrainer
                           "meta_index" not in info)
328 89ff748d Thomas Thrainer
    return retval
329 89ff748d Thomas Thrainer
330 89ff748d Thomas Thrainer
  def _MatchesNet(self, info):
331 89ff748d Thomas Thrainer
    """Test if our network config matches with an existing device.
332 89ff748d Thomas Thrainer

333 47e0abee Thomas Thrainer
    The parameter should be as returned from `_GetShowInfo()`. This
334 89ff748d Thomas Thrainer
    method tests if our network configuration is the same as the one
335 89ff748d Thomas Thrainer
    in the info parameter, in effect testing if we look like the given
336 89ff748d Thomas Thrainer
    device.
337 89ff748d Thomas Thrainer

338 47e0abee Thomas Thrainer
    @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
339 47e0abee Thomas Thrainer
    @rtype: boolean
340 47e0abee Thomas Thrainer

341 89ff748d Thomas Thrainer
    """
342 89ff748d Thomas Thrainer
    if (((self._lhost is None and not ("local_addr" in info)) and
343 89ff748d Thomas Thrainer
         (self._rhost is None and not ("remote_addr" in info)))):
344 89ff748d Thomas Thrainer
      return True
345 89ff748d Thomas Thrainer
346 89ff748d Thomas Thrainer
    if self._lhost is None:
347 89ff748d Thomas Thrainer
      return False
348 89ff748d Thomas Thrainer
349 89ff748d Thomas Thrainer
    if not ("local_addr" in info and
350 89ff748d Thomas Thrainer
            "remote_addr" in info):
351 89ff748d Thomas Thrainer
      return False
352 89ff748d Thomas Thrainer
353 89ff748d Thomas Thrainer
    retval = (info["local_addr"] == (self._lhost, self._lport))
354 89ff748d Thomas Thrainer
    retval = (retval and
355 89ff748d Thomas Thrainer
              info["remote_addr"] == (self._rhost, self._rport))
356 89ff748d Thomas Thrainer
    return retval
357 89ff748d Thomas Thrainer
358 89ff748d Thomas Thrainer
  def _AssembleLocal(self, minor, backend, meta, size):
359 89ff748d Thomas Thrainer
    """Configure the local part of a DRBD device.
360 89ff748d Thomas Thrainer

361 47e0abee Thomas Thrainer
    @type minor: int
362 47e0abee Thomas Thrainer
    @param minor: the minor to assemble locally
363 47e0abee Thomas Thrainer
    @type backend: string
364 47e0abee Thomas Thrainer
    @param backend: path to the data device to use
365 47e0abee Thomas Thrainer
    @type meta: string
366 47e0abee Thomas Thrainer
    @param meta: path to the meta device to use
367 47e0abee Thomas Thrainer
    @type size: int
368 47e0abee Thomas Thrainer
    @param size: size in MiB
369 47e0abee Thomas Thrainer

370 89ff748d Thomas Thrainer
    """
371 09a78e1c Thomas Thrainer
    cmds = self._cmd_gen.GenLocalInitCmds(minor, backend, meta,
372 09a78e1c Thomas Thrainer
                                          size, self.params)
373 89ff748d Thomas Thrainer
374 09a78e1c Thomas Thrainer
    for cmd in cmds:
375 09a78e1c Thomas Thrainer
      result = utils.RunCmd(cmd)
376 09a78e1c Thomas Thrainer
      if result.failed:
377 09a78e1c Thomas Thrainer
        base.ThrowError("drbd%d: can't attach local disk: %s",
378 09a78e1c Thomas Thrainer
                        minor, result.output)
379 89ff748d Thomas Thrainer
380 65fc2388 Thomas Thrainer
  def _AssembleNet(self, minor, net_info, dual_pri=False, hmac=None,
381 65fc2388 Thomas Thrainer
                   secret=None):
382 89ff748d Thomas Thrainer
    """Configure the network part of the device.
383 89ff748d Thomas Thrainer

384 47e0abee Thomas Thrainer
    @type minor: int
385 47e0abee Thomas Thrainer
    @param minor: the minor to assemble the network for
386 47e0abee Thomas Thrainer
    @type net_info: (string, int, string, int)
387 47e0abee Thomas Thrainer
    @param net_info: tuple containing the local address, local port, remote
388 47e0abee Thomas Thrainer
      address and remote port
389 47e0abee Thomas Thrainer
    @type dual_pri: boolean
390 47e0abee Thomas Thrainer
    @param dual_pri: whether two primaries should be allowed or not
391 47e0abee Thomas Thrainer
    @type hmac: string
392 47e0abee Thomas Thrainer
    @param hmac: the HMAC algorithm to use
393 47e0abee Thomas Thrainer
    @type secret: string
394 47e0abee Thomas Thrainer
    @param secret: the shared secret to use
395 47e0abee Thomas Thrainer

396 89ff748d Thomas Thrainer
    """
397 89ff748d Thomas Thrainer
    lhost, lport, rhost, rport = net_info
398 89ff748d Thomas Thrainer
    if None in net_info:
399 89ff748d Thomas Thrainer
      # we don't want network connection and actually want to make
400 89ff748d Thomas Thrainer
      # sure its shutdown
401 89ff748d Thomas Thrainer
      self._ShutdownNet(minor)
402 89ff748d Thomas Thrainer
      return
403 89ff748d Thomas Thrainer
404 65fc2388 Thomas Thrainer
    if dual_pri:
405 65fc2388 Thomas Thrainer
      protocol = constants.DRBD_MIGRATION_NET_PROTOCOL
406 65fc2388 Thomas Thrainer
    else:
407 65fc2388 Thomas Thrainer
      protocol = self.params[constants.LDP_PROTOCOL]
408 65fc2388 Thomas Thrainer
409 89ff748d Thomas Thrainer
    # Workaround for a race condition. When DRBD is doing its dance to
410 89ff748d Thomas Thrainer
    # establish a connection with its peer, it also sends the
411 89ff748d Thomas Thrainer
    # synchronization speed over the wire. In some cases setting the
412 89ff748d Thomas Thrainer
    # sync speed only after setting up both sides can race with DRBD
413 89ff748d Thomas Thrainer
    # connecting, hence we set it here before telling DRBD anything
414 89ff748d Thomas Thrainer
    # about its peer.
415 89ff748d Thomas Thrainer
    sync_errors = self._SetMinorSyncParams(minor, self.params)
416 89ff748d Thomas Thrainer
    if sync_errors:
417 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
418 89ff748d Thomas Thrainer
                      (minor, utils.CommaJoin(sync_errors)))
419 89ff748d Thomas Thrainer
420 daec28a7 Thomas Thrainer
    family = self._GetNetFamily(minor, lhost, rhost)
421 89ff748d Thomas Thrainer
422 09a78e1c Thomas Thrainer
    cmd = self._cmd_gen.GenNetInitCmd(minor, family, lhost, lport,
423 09a78e1c Thomas Thrainer
                                      rhost, rport, protocol,
424 09a78e1c Thomas Thrainer
                                      dual_pri, hmac, secret, self.params)
425 09a78e1c Thomas Thrainer
426 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
427 89ff748d Thomas Thrainer
    if result.failed:
428 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't setup network: %s - %s",
429 89ff748d Thomas Thrainer
                      minor, result.fail_reason, result.output)
430 89ff748d Thomas Thrainer
431 89ff748d Thomas Thrainer
    def _CheckNetworkConfig():
432 27c7d9c3 Thomas Thrainer
      info = self._GetShowInfo(minor)
433 89ff748d Thomas Thrainer
      if not "local_addr" in info or not "remote_addr" in info:
434 89ff748d Thomas Thrainer
        raise utils.RetryAgain()
435 89ff748d Thomas Thrainer
436 89ff748d Thomas Thrainer
      if (info["local_addr"] != (lhost, lport) or
437 89ff748d Thomas Thrainer
          info["remote_addr"] != (rhost, rport)):
438 89ff748d Thomas Thrainer
        raise utils.RetryAgain()
439 89ff748d Thomas Thrainer
440 89ff748d Thomas Thrainer
    try:
441 89ff748d Thomas Thrainer
      utils.Retry(_CheckNetworkConfig, 1.0, 10.0)
442 89ff748d Thomas Thrainer
    except utils.RetryTimeout:
443 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: timeout while configuring network", minor)
444 89ff748d Thomas Thrainer
445 daec28a7 Thomas Thrainer
  @staticmethod
446 daec28a7 Thomas Thrainer
  def _GetNetFamily(minor, lhost, rhost):
447 daec28a7 Thomas Thrainer
    if netutils.IP6Address.IsValid(lhost):
448 daec28a7 Thomas Thrainer
      if not netutils.IP6Address.IsValid(rhost):
449 daec28a7 Thomas Thrainer
        base.ThrowError("drbd%d: can't connect ip %s to ip %s" %
450 daec28a7 Thomas Thrainer
                        (minor, lhost, rhost))
451 daec28a7 Thomas Thrainer
      return "ipv6"
452 daec28a7 Thomas Thrainer
    elif netutils.IP4Address.IsValid(lhost):
453 daec28a7 Thomas Thrainer
      if not netutils.IP4Address.IsValid(rhost):
454 daec28a7 Thomas Thrainer
        base.ThrowError("drbd%d: can't connect ip %s to ip %s" %
455 daec28a7 Thomas Thrainer
                        (minor, lhost, rhost))
456 daec28a7 Thomas Thrainer
      return "ipv4"
457 daec28a7 Thomas Thrainer
    else:
458 daec28a7 Thomas Thrainer
      base.ThrowError("drbd%d: Invalid ip %s" % (minor, lhost))
459 daec28a7 Thomas Thrainer
460 89ff748d Thomas Thrainer
  def AddChildren(self, devices):
461 89ff748d Thomas Thrainer
    """Add a disk to the DRBD device.
462 89ff748d Thomas Thrainer

463 47e0abee Thomas Thrainer
    @type devices: list of L{BlockDev}
464 47e0abee Thomas Thrainer
    @param devices: a list of exactly two L{BlockDev} objects; the first
465 47e0abee Thomas Thrainer
      denotes the data device, the second the meta device for this DRBD device
466 47e0abee Thomas Thrainer

467 89ff748d Thomas Thrainer
    """
468 89ff748d Thomas Thrainer
    if self.minor is None:
469 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't attach to dbrd8 during AddChildren",
470 89ff748d Thomas Thrainer
                      self._aminor)
471 89ff748d Thomas Thrainer
    if len(devices) != 2:
472 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: need two devices for AddChildren", self.minor)
473 27c7d9c3 Thomas Thrainer
    info = self._GetShowInfo(self.minor)
474 89ff748d Thomas Thrainer
    if "local_dev" in info:
475 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: already attached to a local disk", self.minor)
476 89ff748d Thomas Thrainer
    backend, meta = devices
477 89ff748d Thomas Thrainer
    if backend.dev_path is None or meta.dev_path is None:
478 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: children not ready during AddChildren",
479 89ff748d Thomas Thrainer
                      self.minor)
480 89ff748d Thomas Thrainer
    backend.Open()
481 89ff748d Thomas Thrainer
    meta.Open()
482 89ff748d Thomas Thrainer
    self._CheckMetaSize(meta.dev_path)
483 47e0abee Thomas Thrainer
    self._InitMeta(DRBD8.FindUnusedMinor(), meta.dev_path)
484 89ff748d Thomas Thrainer
485 89ff748d Thomas Thrainer
    self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path, self.size)
486 89ff748d Thomas Thrainer
    self._children = devices
487 89ff748d Thomas Thrainer
488 89ff748d Thomas Thrainer
  def RemoveChildren(self, devices):
489 89ff748d Thomas Thrainer
    """Detach the drbd device from local storage.
490 89ff748d Thomas Thrainer

491 47e0abee Thomas Thrainer
    @type devices: list of L{BlockDev}
492 47e0abee Thomas Thrainer
    @param devices: a list of exactly two L{BlockDev} objects; the first
493 47e0abee Thomas Thrainer
      denotes the data device, the second the meta device for this DRBD device
494 47e0abee Thomas Thrainer

495 89ff748d Thomas Thrainer
    """
496 89ff748d Thomas Thrainer
    if self.minor is None:
497 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
498 89ff748d Thomas Thrainer
                      self._aminor)
499 89ff748d Thomas Thrainer
    # early return if we don't actually have backing storage
500 27c7d9c3 Thomas Thrainer
    info = self._GetShowInfo(self.minor)
501 89ff748d Thomas Thrainer
    if "local_dev" not in info:
502 89ff748d Thomas Thrainer
      return
503 89ff748d Thomas Thrainer
    if len(self._children) != 2:
504 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: we don't have two children: %s", self.minor,
505 89ff748d Thomas Thrainer
                      self._children)
506 89ff748d Thomas Thrainer
    if self._children.count(None) == 2: # we don't actually have children :)
507 89ff748d Thomas Thrainer
      logging.warning("drbd%d: requested detach while detached", self.minor)
508 89ff748d Thomas Thrainer
      return
509 89ff748d Thomas Thrainer
    if len(devices) != 2:
510 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: we need two children in RemoveChildren",
511 89ff748d Thomas Thrainer
                      self.minor)
512 89ff748d Thomas Thrainer
    for child, dev in zip(self._children, devices):
513 89ff748d Thomas Thrainer
      if dev != child.dev_path:
514 89ff748d Thomas Thrainer
        base.ThrowError("drbd%d: mismatch in local storage (%s != %s) in"
515 89ff748d Thomas Thrainer
                        " RemoveChildren", self.minor, dev, child.dev_path)
516 89ff748d Thomas Thrainer
517 89ff748d Thomas Thrainer
    self._ShutdownLocal(self.minor)
518 89ff748d Thomas Thrainer
    self._children = []
519 89ff748d Thomas Thrainer
520 2fe690f1 Thomas Thrainer
  def _SetMinorSyncParams(self, minor, params):
521 89ff748d Thomas Thrainer
    """Set the parameters of the DRBD syncer.
522 89ff748d Thomas Thrainer

523 89ff748d Thomas Thrainer
    This is the low-level implementation.
524 89ff748d Thomas Thrainer

525 89ff748d Thomas Thrainer
    @type minor: int
526 89ff748d Thomas Thrainer
    @param minor: the drbd minor whose settings we change
527 89ff748d Thomas Thrainer
    @type params: dict
528 89ff748d Thomas Thrainer
    @param params: LD level disk parameters related to the synchronization
529 89ff748d Thomas Thrainer
    @rtype: list
530 89ff748d Thomas Thrainer
    @return: a list of error messages
531 89ff748d Thomas Thrainer

532 89ff748d Thomas Thrainer
    """
533 09a78e1c Thomas Thrainer
    cmd = self._cmd_gen.GenSyncParamsCmd(minor, params)
534 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
535 89ff748d Thomas Thrainer
    if result.failed:
536 89ff748d Thomas Thrainer
      msg = ("Can't change syncer rate: %s - %s" %
537 89ff748d Thomas Thrainer
             (result.fail_reason, result.output))
538 89ff748d Thomas Thrainer
      logging.error(msg)
539 89ff748d Thomas Thrainer
      return [msg]
540 89ff748d Thomas Thrainer
541 89ff748d Thomas Thrainer
    return []
542 89ff748d Thomas Thrainer
543 89ff748d Thomas Thrainer
  def SetSyncParams(self, params):
544 89ff748d Thomas Thrainer
    """Set the synchronization parameters of the DRBD syncer.
545 89ff748d Thomas Thrainer

546 47e0abee Thomas Thrainer
    See L{BlockDev.SetSyncParams} for parameter description.
547 89ff748d Thomas Thrainer

548 89ff748d Thomas Thrainer
    """
549 89ff748d Thomas Thrainer
    if self.minor is None:
550 89ff748d Thomas Thrainer
      err = "Not attached during SetSyncParams"
551 89ff748d Thomas Thrainer
      logging.info(err)
552 89ff748d Thomas Thrainer
      return [err]
553 89ff748d Thomas Thrainer
554 239364d0 Thomas Thrainer
    children_result = super(DRBD8Dev, self).SetSyncParams(params)
555 89ff748d Thomas Thrainer
    children_result.extend(self._SetMinorSyncParams(self.minor, params))
556 89ff748d Thomas Thrainer
    return children_result
557 89ff748d Thomas Thrainer
558 89ff748d Thomas Thrainer
  def PauseResumeSync(self, pause):
559 89ff748d Thomas Thrainer
    """Pauses or resumes the sync of a DRBD device.
560 89ff748d Thomas Thrainer

561 47e0abee Thomas Thrainer
    See L{BlockDev.PauseResumeSync} for parameter description.
562 89ff748d Thomas Thrainer

563 89ff748d Thomas Thrainer
    """
564 89ff748d Thomas Thrainer
    if self.minor is None:
565 89ff748d Thomas Thrainer
      logging.info("Not attached during PauseSync")
566 89ff748d Thomas Thrainer
      return False
567 89ff748d Thomas Thrainer
568 239364d0 Thomas Thrainer
    children_result = super(DRBD8Dev, self).PauseResumeSync(pause)
569 89ff748d Thomas Thrainer
570 89ff748d Thomas Thrainer
    if pause:
571 09a78e1c Thomas Thrainer
      cmd = self._cmd_gen.GenPauseSyncCmd(self.minor)
572 89ff748d Thomas Thrainer
    else:
573 09a78e1c Thomas Thrainer
      cmd = self._cmd_gen.GenResumeSyncCmd(self.minor)
574 89ff748d Thomas Thrainer
575 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
576 89ff748d Thomas Thrainer
    if result.failed:
577 89ff748d Thomas Thrainer
      logging.error("Can't %s: %s - %s", cmd,
578 89ff748d Thomas Thrainer
                    result.fail_reason, result.output)
579 89ff748d Thomas Thrainer
    return not result.failed and children_result
580 89ff748d Thomas Thrainer
581 89ff748d Thomas Thrainer
  def GetProcStatus(self):
582 47e0abee Thomas Thrainer
    """Return the current status data from /proc/drbd for this device.
583 47e0abee Thomas Thrainer

584 47e0abee Thomas Thrainer
    @rtype: DRBD8Status
585 89ff748d Thomas Thrainer

586 89ff748d Thomas Thrainer
    """
587 89ff748d Thomas Thrainer
    if self.minor is None:
588 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: GetStats() called while not attached",
589 89ff748d Thomas Thrainer
                      self._aminor)
590 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
591 47e0abee Thomas Thrainer
    if not info.HasMinorStatus(self.minor):
592 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't find myself in /proc", self.minor)
593 47e0abee Thomas Thrainer
    return info.GetMinorStatus(self.minor)
594 89ff748d Thomas Thrainer
595 89ff748d Thomas Thrainer
  def GetSyncStatus(self):
596 89ff748d Thomas Thrainer
    """Returns the sync status of the device.
597 89ff748d Thomas Thrainer

598 89ff748d Thomas Thrainer
    If sync_percent is None, it means all is ok
599 89ff748d Thomas Thrainer
    If estimated_time is None, it means we can't estimate
600 89ff748d Thomas Thrainer
    the time needed, otherwise it's the time left in seconds.
601 89ff748d Thomas Thrainer

602 89ff748d Thomas Thrainer
    We set the is_degraded parameter to True on two conditions:
603 89ff748d Thomas Thrainer
    network not connected or local disk missing.
604 89ff748d Thomas Thrainer

605 89ff748d Thomas Thrainer
    We compute the ldisk parameter based on whether we have a local
606 89ff748d Thomas Thrainer
    disk or not.
607 89ff748d Thomas Thrainer

608 89ff748d Thomas Thrainer
    @rtype: objects.BlockDevStatus
609 89ff748d Thomas Thrainer

610 89ff748d Thomas Thrainer
    """
611 89ff748d Thomas Thrainer
    if self.minor is None and not self.Attach():
612 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
613 89ff748d Thomas Thrainer
614 89ff748d Thomas Thrainer
    stats = self.GetProcStatus()
615 89ff748d Thomas Thrainer
    is_degraded = not stats.is_connected or not stats.is_disk_uptodate
616 89ff748d Thomas Thrainer
617 89ff748d Thomas Thrainer
    if stats.is_disk_uptodate:
618 89ff748d Thomas Thrainer
      ldisk_status = constants.LDS_OKAY
619 89ff748d Thomas Thrainer
    elif stats.is_diskless:
620 89ff748d Thomas Thrainer
      ldisk_status = constants.LDS_FAULTY
621 89ff748d Thomas Thrainer
    else:
622 89ff748d Thomas Thrainer
      ldisk_status = constants.LDS_UNKNOWN
623 89ff748d Thomas Thrainer
624 89ff748d Thomas Thrainer
    return objects.BlockDevStatus(dev_path=self.dev_path,
625 89ff748d Thomas Thrainer
                                  major=self.major,
626 89ff748d Thomas Thrainer
                                  minor=self.minor,
627 89ff748d Thomas Thrainer
                                  sync_percent=stats.sync_percent,
628 89ff748d Thomas Thrainer
                                  estimated_time=stats.est_time,
629 89ff748d Thomas Thrainer
                                  is_degraded=is_degraded,
630 89ff748d Thomas Thrainer
                                  ldisk_status=ldisk_status)
631 89ff748d Thomas Thrainer
632 89ff748d Thomas Thrainer
  def Open(self, force=False):
633 89ff748d Thomas Thrainer
    """Make the local state primary.
634 89ff748d Thomas Thrainer

635 47e0abee Thomas Thrainer
    If the 'force' parameter is given, DRBD is instructed to switch the device
636 47e0abee Thomas Thrainer
    into primary mode. Since this is a potentially dangerous operation, the
637 47e0abee Thomas Thrainer
    force flag should be only given after creation, when it actually is
638 47e0abee Thomas Thrainer
    mandatory.
639 89ff748d Thomas Thrainer

640 89ff748d Thomas Thrainer
    """
641 89ff748d Thomas Thrainer
    if self.minor is None and not self.Attach():
642 89ff748d Thomas Thrainer
      logging.error("DRBD cannot attach to a device during open")
643 89ff748d Thomas Thrainer
      return False
644 09a78e1c Thomas Thrainer
645 09a78e1c Thomas Thrainer
    cmd = self._cmd_gen.GenPrimaryCmd(self.minor, force)
646 09a78e1c Thomas Thrainer
647 89ff748d Thomas Thrainer
    result = utils.RunCmd(cmd)
648 89ff748d Thomas Thrainer
    if result.failed:
649 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't make drbd device primary: %s", self.minor,
650 89ff748d Thomas Thrainer
                      result.output)
651 89ff748d Thomas Thrainer
652 89ff748d Thomas Thrainer
  def Close(self):
653 89ff748d Thomas Thrainer
    """Make the local state secondary.
654 89ff748d Thomas Thrainer

655 89ff748d Thomas Thrainer
    This will, of course, fail if the device is in use.
656 89ff748d Thomas Thrainer

657 89ff748d Thomas Thrainer
    """
658 89ff748d Thomas Thrainer
    if self.minor is None and not self.Attach():
659 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't Attach() in Close()", self._aminor)
660 09a78e1c Thomas Thrainer
    cmd = self._cmd_gen.GenSecondaryCmd(self.minor)
661 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
662 89ff748d Thomas Thrainer
    if result.failed:
663 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't switch drbd device to secondary: %s",
664 89ff748d Thomas Thrainer
                      self.minor, result.output)
665 89ff748d Thomas Thrainer
666 89ff748d Thomas Thrainer
  def DisconnectNet(self):
667 89ff748d Thomas Thrainer
    """Removes network configuration.
668 89ff748d Thomas Thrainer

669 89ff748d Thomas Thrainer
    This method shutdowns the network side of the device.
670 89ff748d Thomas Thrainer

671 89ff748d Thomas Thrainer
    The method will wait up to a hardcoded timeout for the device to
672 89ff748d Thomas Thrainer
    go into standalone after the 'disconnect' command before
673 89ff748d Thomas Thrainer
    re-configuring it, as sometimes it takes a while for the
674 89ff748d Thomas Thrainer
    disconnect to actually propagate and thus we might issue a 'net'
675 89ff748d Thomas Thrainer
    command while the device is still connected. If the device will
676 89ff748d Thomas Thrainer
    still be attached to the network and we time out, we raise an
677 89ff748d Thomas Thrainer
    exception.
678 89ff748d Thomas Thrainer

679 89ff748d Thomas Thrainer
    """
680 89ff748d Thomas Thrainer
    if self.minor is None:
681 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: disk not attached in re-attach net",
682 89ff748d Thomas Thrainer
                      self._aminor)
683 89ff748d Thomas Thrainer
684 89ff748d Thomas Thrainer
    if None in (self._lhost, self._lport, self._rhost, self._rport):
685 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: DRBD disk missing network info in"
686 89ff748d Thomas Thrainer
                      " DisconnectNet()", self.minor)
687 89ff748d Thomas Thrainer
688 89ff748d Thomas Thrainer
    class _DisconnectStatus:
689 89ff748d Thomas Thrainer
      def __init__(self, ever_disconnected):
690 89ff748d Thomas Thrainer
        self.ever_disconnected = ever_disconnected
691 89ff748d Thomas Thrainer
692 89ff748d Thomas Thrainer
    dstatus = _DisconnectStatus(base.IgnoreError(self._ShutdownNet, self.minor))
693 89ff748d Thomas Thrainer
694 89ff748d Thomas Thrainer
    def _WaitForDisconnect():
695 89ff748d Thomas Thrainer
      if self.GetProcStatus().is_standalone:
696 89ff748d Thomas Thrainer
        return
697 89ff748d Thomas Thrainer
698 89ff748d Thomas Thrainer
      # retry the disconnect, it seems possible that due to a well-time
699 89ff748d Thomas Thrainer
      # disconnect on the peer, my disconnect command might be ignored and
700 89ff748d Thomas Thrainer
      # forgotten
701 89ff748d Thomas Thrainer
      dstatus.ever_disconnected = \
702 89ff748d Thomas Thrainer
        base.IgnoreError(self._ShutdownNet, self.minor) or \
703 89ff748d Thomas Thrainer
        dstatus.ever_disconnected
704 89ff748d Thomas Thrainer
705 89ff748d Thomas Thrainer
      raise utils.RetryAgain()
706 89ff748d Thomas Thrainer
707 89ff748d Thomas Thrainer
    # Keep start time
708 89ff748d Thomas Thrainer
    start_time = time.time()
709 89ff748d Thomas Thrainer
710 89ff748d Thomas Thrainer
    try:
711 89ff748d Thomas Thrainer
      # Start delay at 100 milliseconds and grow up to 2 seconds
712 89ff748d Thomas Thrainer
      utils.Retry(_WaitForDisconnect, (0.1, 1.5, 2.0),
713 89ff748d Thomas Thrainer
                  self._NET_RECONFIG_TIMEOUT)
714 89ff748d Thomas Thrainer
    except utils.RetryTimeout:
715 89ff748d Thomas Thrainer
      if dstatus.ever_disconnected:
716 89ff748d Thomas Thrainer
        msg = ("drbd%d: device did not react to the"
717 89ff748d Thomas Thrainer
               " 'disconnect' command in a timely manner")
718 89ff748d Thomas Thrainer
      else:
719 89ff748d Thomas Thrainer
        msg = "drbd%d: can't shutdown network, even after multiple retries"
720 89ff748d Thomas Thrainer
721 89ff748d Thomas Thrainer
      base.ThrowError(msg, self.minor)
722 89ff748d Thomas Thrainer
723 89ff748d Thomas Thrainer
    reconfig_time = time.time() - start_time
724 89ff748d Thomas Thrainer
    if reconfig_time > (self._NET_RECONFIG_TIMEOUT * 0.25):
725 89ff748d Thomas Thrainer
      logging.info("drbd%d: DisconnectNet: detach took %.3f seconds",
726 89ff748d Thomas Thrainer
                   self.minor, reconfig_time)
727 89ff748d Thomas Thrainer
728 89ff748d Thomas Thrainer
  def AttachNet(self, multimaster):
729 89ff748d Thomas Thrainer
    """Reconnects the network.
730 89ff748d Thomas Thrainer

731 89ff748d Thomas Thrainer
    This method connects the network side of the device with a
732 89ff748d Thomas Thrainer
    specified multi-master flag. The device needs to be 'Standalone'
733 89ff748d Thomas Thrainer
    but have valid network configuration data.
734 89ff748d Thomas Thrainer

735 47e0abee Thomas Thrainer
    @type multimaster: boolean
736 47e0abee Thomas Thrainer
    @param multimaster: init the network in dual-primary mode
737 89ff748d Thomas Thrainer

738 89ff748d Thomas Thrainer
    """
739 89ff748d Thomas Thrainer
    if self.minor is None:
740 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: device not attached in AttachNet", self._aminor)
741 89ff748d Thomas Thrainer
742 89ff748d Thomas Thrainer
    if None in (self._lhost, self._lport, self._rhost, self._rport):
743 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: missing network info in AttachNet()", self.minor)
744 89ff748d Thomas Thrainer
745 89ff748d Thomas Thrainer
    status = self.GetProcStatus()
746 89ff748d Thomas Thrainer
747 89ff748d Thomas Thrainer
    if not status.is_standalone:
748 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: device is not standalone in AttachNet",
749 89ff748d Thomas Thrainer
                      self.minor)
750 89ff748d Thomas Thrainer
751 89ff748d Thomas Thrainer
    self._AssembleNet(self.minor,
752 89ff748d Thomas Thrainer
                      (self._lhost, self._lport, self._rhost, self._rport),
753 65fc2388 Thomas Thrainer
                      dual_pri=multimaster, hmac=constants.DRBD_HMAC_ALG,
754 65fc2388 Thomas Thrainer
                      secret=self._secret)
755 89ff748d Thomas Thrainer
756 89ff748d Thomas Thrainer
  def Attach(self):
757 89ff748d Thomas Thrainer
    """Check if our minor is configured.
758 89ff748d Thomas Thrainer

759 89ff748d Thomas Thrainer
    This doesn't do any device configurations - it only checks if the
760 89ff748d Thomas Thrainer
    minor is in a state different from Unconfigured.
761 89ff748d Thomas Thrainer

762 89ff748d Thomas Thrainer
    Note that this function will not change the state of the system in
763 89ff748d Thomas Thrainer
    any way (except in case of side-effects caused by reading from
764 89ff748d Thomas Thrainer
    /proc).
765 89ff748d Thomas Thrainer

766 89ff748d Thomas Thrainer
    """
767 47e0abee Thomas Thrainer
    used_devs = DRBD8.GetUsedDevs()
768 89ff748d Thomas Thrainer
    if self._aminor in used_devs:
769 89ff748d Thomas Thrainer
      minor = self._aminor
770 89ff748d Thomas Thrainer
    else:
771 89ff748d Thomas Thrainer
      minor = None
772 89ff748d Thomas Thrainer
773 89ff748d Thomas Thrainer
    self._SetFromMinor(minor)
774 89ff748d Thomas Thrainer
    return minor is not None
775 89ff748d Thomas Thrainer
776 89ff748d Thomas Thrainer
  def Assemble(self):
777 89ff748d Thomas Thrainer
    """Assemble the drbd.
778 89ff748d Thomas Thrainer

779 89ff748d Thomas Thrainer
    Method:
780 89ff748d Thomas Thrainer
      - if we have a configured device, we try to ensure that it matches
781 89ff748d Thomas Thrainer
        our config
782 89ff748d Thomas Thrainer
      - if not, we create it from zero
783 89ff748d Thomas Thrainer
      - anyway, set the device parameters
784 89ff748d Thomas Thrainer

785 89ff748d Thomas Thrainer
    """
786 239364d0 Thomas Thrainer
    super(DRBD8Dev, self).Assemble()
787 89ff748d Thomas Thrainer
788 89ff748d Thomas Thrainer
    self.Attach()
789 89ff748d Thomas Thrainer
    if self.minor is None:
790 89ff748d Thomas Thrainer
      # local device completely unconfigured
791 89ff748d Thomas Thrainer
      self._FastAssemble()
792 89ff748d Thomas Thrainer
    else:
793 89ff748d Thomas Thrainer
      # we have to recheck the local and network status and try to fix
794 89ff748d Thomas Thrainer
      # the device
795 89ff748d Thomas Thrainer
      self._SlowAssemble()
796 89ff748d Thomas Thrainer
797 89ff748d Thomas Thrainer
    sync_errors = self.SetSyncParams(self.params)
798 89ff748d Thomas Thrainer
    if sync_errors:
799 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
800 89ff748d Thomas Thrainer
                      (self.minor, utils.CommaJoin(sync_errors)))
801 89ff748d Thomas Thrainer
802 89ff748d Thomas Thrainer
  def _SlowAssemble(self):
803 89ff748d Thomas Thrainer
    """Assembles the DRBD device from a (partially) configured device.
804 89ff748d Thomas Thrainer

805 89ff748d Thomas Thrainer
    In case of partially attached (local device matches but no network
806 89ff748d Thomas Thrainer
    setup), we perform the network attach. If successful, we re-test
807 89ff748d Thomas Thrainer
    the attach if can return success.
808 89ff748d Thomas Thrainer

809 89ff748d Thomas Thrainer
    """
810 89ff748d Thomas Thrainer
    # TODO: Rewrite to not use a for loop just because there is 'break'
811 89ff748d Thomas Thrainer
    # pylint: disable=W0631
812 89ff748d Thomas Thrainer
    net_data = (self._lhost, self._lport, self._rhost, self._rport)
813 89ff748d Thomas Thrainer
    for minor in (self._aminor,):
814 27c7d9c3 Thomas Thrainer
      info = self._GetShowInfo(minor)
815 89ff748d Thomas Thrainer
      match_l = self._MatchesLocal(info)
816 89ff748d Thomas Thrainer
      match_r = self._MatchesNet(info)
817 89ff748d Thomas Thrainer
818 89ff748d Thomas Thrainer
      if match_l and match_r:
819 89ff748d Thomas Thrainer
        # everything matches
820 89ff748d Thomas Thrainer
        break
821 89ff748d Thomas Thrainer
822 89ff748d Thomas Thrainer
      if match_l and not match_r and "local_addr" not in info:
823 89ff748d Thomas Thrainer
        # disk matches, but not attached to network, attach and recheck
824 65fc2388 Thomas Thrainer
        self._AssembleNet(minor, net_data, hmac=constants.DRBD_HMAC_ALG,
825 65fc2388 Thomas Thrainer
                          secret=self._secret)
826 27c7d9c3 Thomas Thrainer
        if self._MatchesNet(self._GetShowInfo(minor)):
827 89ff748d Thomas Thrainer
          break
828 89ff748d Thomas Thrainer
        else:
829 89ff748d Thomas Thrainer
          base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
830 89ff748d Thomas Thrainer
                          " show' disagrees", minor)
831 89ff748d Thomas Thrainer
832 89ff748d Thomas Thrainer
      if match_r and "local_dev" not in info:
833 89ff748d Thomas Thrainer
        # no local disk, but network attached and it matches
834 89ff748d Thomas Thrainer
        self._AssembleLocal(minor, self._children[0].dev_path,
835 89ff748d Thomas Thrainer
                            self._children[1].dev_path, self.size)
836 085b8e24 Thomas Thrainer
        if self._MatchesLocal(self._GetShowInfo(minor)):
837 89ff748d Thomas Thrainer
          break
838 89ff748d Thomas Thrainer
        else:
839 89ff748d Thomas Thrainer
          base.ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
840 89ff748d Thomas Thrainer
                          " show' disagrees", minor)
841 89ff748d Thomas Thrainer
842 89ff748d Thomas Thrainer
      # this case must be considered only if we actually have local
843 89ff748d Thomas Thrainer
      # storage, i.e. not in diskless mode, because all diskless
844 89ff748d Thomas Thrainer
      # devices are equal from the point of view of local
845 89ff748d Thomas Thrainer
      # configuration
846 89ff748d Thomas Thrainer
      if (match_l and "local_dev" in info and
847 89ff748d Thomas Thrainer
          not match_r and "local_addr" in info):
848 89ff748d Thomas Thrainer
        # strange case - the device network part points to somewhere
849 89ff748d Thomas Thrainer
        # else, even though its local storage is ours; as we own the
850 89ff748d Thomas Thrainer
        # drbd space, we try to disconnect from the remote peer and
851 89ff748d Thomas Thrainer
        # reconnect to our correct one
852 89ff748d Thomas Thrainer
        try:
853 89ff748d Thomas Thrainer
          self._ShutdownNet(minor)
854 89ff748d Thomas Thrainer
        except errors.BlockDeviceError, err:
855 89ff748d Thomas Thrainer
          base.ThrowError("drbd%d: device has correct local storage, wrong"
856 89ff748d Thomas Thrainer
                          " remote peer and is unable to disconnect in order"
857 89ff748d Thomas Thrainer
                          " to attach to the correct peer: %s", minor, str(err))
858 89ff748d Thomas Thrainer
        # note: _AssembleNet also handles the case when we don't want
859 89ff748d Thomas Thrainer
        # local storage (i.e. one or more of the _[lr](host|port) is
860 89ff748d Thomas Thrainer
        # None)
861 65fc2388 Thomas Thrainer
        self._AssembleNet(minor, net_data, hmac=constants.DRBD_HMAC_ALG,
862 65fc2388 Thomas Thrainer
                          secret=self._secret)
863 27c7d9c3 Thomas Thrainer
        if self._MatchesNet(self._GetShowInfo(minor)):
864 89ff748d Thomas Thrainer
          break
865 89ff748d Thomas Thrainer
        else:
866 89ff748d Thomas Thrainer
          base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
867 89ff748d Thomas Thrainer
                          " show' disagrees", minor)
868 89ff748d Thomas Thrainer
869 89ff748d Thomas Thrainer
    else:
870 89ff748d Thomas Thrainer
      minor = None
871 89ff748d Thomas Thrainer
872 89ff748d Thomas Thrainer
    self._SetFromMinor(minor)
873 89ff748d Thomas Thrainer
    if minor is None:
874 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: cannot activate, unknown or unhandled reason",
875 89ff748d Thomas Thrainer
                      self._aminor)
876 89ff748d Thomas Thrainer
877 89ff748d Thomas Thrainer
  def _FastAssemble(self):
878 89ff748d Thomas Thrainer
    """Assemble the drbd device from zero.
879 89ff748d Thomas Thrainer

880 89ff748d Thomas Thrainer
    This is run when in Assemble we detect our minor is unused.
881 89ff748d Thomas Thrainer

882 89ff748d Thomas Thrainer
    """
883 89ff748d Thomas Thrainer
    minor = self._aminor
884 89ff748d Thomas Thrainer
    if self._children and self._children[0] and self._children[1]:
885 89ff748d Thomas Thrainer
      self._AssembleLocal(minor, self._children[0].dev_path,
886 89ff748d Thomas Thrainer
                          self._children[1].dev_path, self.size)
887 89ff748d Thomas Thrainer
    if self._lhost and self._lport and self._rhost and self._rport:
888 89ff748d Thomas Thrainer
      self._AssembleNet(minor,
889 89ff748d Thomas Thrainer
                        (self._lhost, self._lport, self._rhost, self._rport),
890 89ff748d Thomas Thrainer
                        hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
891 89ff748d Thomas Thrainer
    self._SetFromMinor(minor)
892 89ff748d Thomas Thrainer
893 09a78e1c Thomas Thrainer
  def _ShutdownLocal(self, minor):
894 89ff748d Thomas Thrainer
    """Detach from the local device.
895 89ff748d Thomas Thrainer

896 89ff748d Thomas Thrainer
    I/Os will continue to be served from the remote device. If we
897 89ff748d Thomas Thrainer
    don't have a remote device, this operation will fail.
898 89ff748d Thomas Thrainer

899 47e0abee Thomas Thrainer
    @type minor: int
900 47e0abee Thomas Thrainer
    @param minor: the device to detach from the local device
901 47e0abee Thomas Thrainer

902 89ff748d Thomas Thrainer
    """
903 09a78e1c Thomas Thrainer
    cmd = self._cmd_gen.GenDetachCmd(minor)
904 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
905 89ff748d Thomas Thrainer
    if result.failed:
906 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't detach local disk: %s",
907 89ff748d Thomas Thrainer
                      minor, result.output)
908 89ff748d Thomas Thrainer
909 09a78e1c Thomas Thrainer
  def _ShutdownNet(self, minor):
910 89ff748d Thomas Thrainer
    """Disconnect from the remote peer.
911 89ff748d Thomas Thrainer

912 89ff748d Thomas Thrainer
    This fails if we don't have a local device.
913 89ff748d Thomas Thrainer

914 47e0abee Thomas Thrainer
    @type minor: boolean
915 47e0abee Thomas Thrainer
    @param minor: the device to disconnect from the remote peer
916 47e0abee Thomas Thrainer

917 89ff748d Thomas Thrainer
    """
918 daec28a7 Thomas Thrainer
    family = self._GetNetFamily(minor, self._lhost, self._rhost)
919 daec28a7 Thomas Thrainer
    cmd = self._cmd_gen.GenDisconnectCmd(minor, family,
920 daec28a7 Thomas Thrainer
                                         self._lhost, self._lport,
921 daec28a7 Thomas Thrainer
                                         self._rhost, self._rport)
922 09a78e1c Thomas Thrainer
    result = utils.RunCmd(cmd)
923 89ff748d Thomas Thrainer
    if result.failed:
924 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't shutdown network: %s",
925 89ff748d Thomas Thrainer
                      minor, result.output)
926 89ff748d Thomas Thrainer
927 89ff748d Thomas Thrainer
  def Shutdown(self):
928 89ff748d Thomas Thrainer
    """Shutdown the DRBD device.
929 89ff748d Thomas Thrainer

930 89ff748d Thomas Thrainer
    """
931 89ff748d Thomas Thrainer
    if self.minor is None and not self.Attach():
932 89ff748d Thomas Thrainer
      logging.info("drbd%d: not attached during Shutdown()", self._aminor)
933 89ff748d Thomas Thrainer
      return
934 d0d7d7cf Thomas Thrainer
935 d0d7d7cf Thomas Thrainer
    try:
936 d0d7d7cf Thomas Thrainer
      DRBD8.ShutdownAll(self.minor)
937 d0d7d7cf Thomas Thrainer
    finally:
938 d0d7d7cf Thomas Thrainer
      self.minor = None
939 d0d7d7cf Thomas Thrainer
      self.dev_path = None
940 89ff748d Thomas Thrainer
941 89ff748d Thomas Thrainer
  def Remove(self):
942 89ff748d Thomas Thrainer
    """Stub remove for DRBD devices.
943 89ff748d Thomas Thrainer

944 89ff748d Thomas Thrainer
    """
945 89ff748d Thomas Thrainer
    self.Shutdown()
946 89ff748d Thomas Thrainer
947 fd300bc7 Thomas Thrainer
  def Rename(self, new_id):
948 fd300bc7 Thomas Thrainer
    """Rename a device.
949 fd300bc7 Thomas Thrainer

950 fd300bc7 Thomas Thrainer
    This is not supported for drbd devices.
951 fd300bc7 Thomas Thrainer

952 fd300bc7 Thomas Thrainer
    """
953 fd300bc7 Thomas Thrainer
    raise errors.ProgrammerError("Can't rename a drbd device")
954 fd300bc7 Thomas Thrainer
955 be9150ea Bernardo Dal Seno
  def Grow(self, amount, dryrun, backingstore, excl_stor):
956 47e0abee Thomas Thrainer
    """Resize the DRBD device and its backing storage.
957 47e0abee Thomas Thrainer

958 47e0abee Thomas Thrainer
    See L{BlockDev.Grow} for parameter description.
959 47e0abee Thomas Thrainer

960 47e0abee Thomas Thrainer
    """
961 47e0abee Thomas Thrainer
    if self.minor is None:
962 47e0abee Thomas Thrainer
      base.ThrowError("drbd%d: Grow called while not attached", self._aminor)
963 47e0abee Thomas Thrainer
    if len(self._children) != 2 or None in self._children:
964 47e0abee Thomas Thrainer
      base.ThrowError("drbd%d: cannot grow diskless device", self.minor)
965 be9150ea Bernardo Dal Seno
    self._children[0].Grow(amount, dryrun, backingstore, excl_stor)
966 47e0abee Thomas Thrainer
    if dryrun or backingstore:
967 47e0abee Thomas Thrainer
      # DRBD does not support dry-run mode and is not backing storage,
968 47e0abee Thomas Thrainer
      # so we'll return here
969 47e0abee Thomas Thrainer
      return
970 47e0abee Thomas Thrainer
    cmd = self._cmd_gen.GenResizeCmd(self.minor, self.size + amount)
971 47e0abee Thomas Thrainer
    result = utils.RunCmd(cmd)
972 47e0abee Thomas Thrainer
    if result.failed:
973 47e0abee Thomas Thrainer
      base.ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
974 47e0abee Thomas Thrainer
975 47e0abee Thomas Thrainer
  @classmethod
976 47e0abee Thomas Thrainer
  def _InitMeta(cls, minor, dev_path):
977 47e0abee Thomas Thrainer
    """Initialize a meta device.
978 47e0abee Thomas Thrainer

979 47e0abee Thomas Thrainer
    This will not work if the given minor is in use.
980 47e0abee Thomas Thrainer

981 47e0abee Thomas Thrainer
    @type minor: int
982 47e0abee Thomas Thrainer
    @param minor: the DRBD minor whose (future) meta device should be
983 47e0abee Thomas Thrainer
      initialized
984 47e0abee Thomas Thrainer
    @type dev_path: string
985 47e0abee Thomas Thrainer
    @param dev_path: path to the meta device to initialize
986 47e0abee Thomas Thrainer

987 47e0abee Thomas Thrainer
    """
988 47e0abee Thomas Thrainer
    # Zero the metadata first, in order to make sure drbdmeta doesn't
989 47e0abee Thomas Thrainer
    # try to auto-detect existing filesystems or similar (see
990 47e0abee Thomas Thrainer
    # http://code.google.com/p/ganeti/issues/detail?id=182); we only
991 47e0abee Thomas Thrainer
    # care about the first 128MB of data in the device, even though it
992 47e0abee Thomas Thrainer
    # can be bigger
993 47e0abee Thomas Thrainer
    result = utils.RunCmd([constants.DD_CMD,
994 47e0abee Thomas Thrainer
                           "if=/dev/zero", "of=%s" % dev_path,
995 47e0abee Thomas Thrainer
                           "bs=1048576", "count=128", "oflag=direct"])
996 47e0abee Thomas Thrainer
    if result.failed:
997 47e0abee Thomas Thrainer
      base.ThrowError("Can't wipe the meta device: %s", result.output)
998 47e0abee Thomas Thrainer
999 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
1000 47e0abee Thomas Thrainer
    cmd_gen = DRBD8.GetCmdGenerator(info)
1001 47e0abee Thomas Thrainer
    cmd = cmd_gen.GenInitMetaCmd(minor, dev_path)
1002 47e0abee Thomas Thrainer
1003 47e0abee Thomas Thrainer
    result = utils.RunCmd(cmd)
1004 47e0abee Thomas Thrainer
    if result.failed:
1005 47e0abee Thomas Thrainer
      base.ThrowError("Can't initialize meta device: %s", result.output)
1006 47e0abee Thomas Thrainer
1007 89ff748d Thomas Thrainer
  @classmethod
1008 24c06acb Bernardo Dal Seno
  def Create(cls, unique_id, children, size, spindles, params, excl_stor):
1009 89ff748d Thomas Thrainer
    """Create a new DRBD8 device.
1010 89ff748d Thomas Thrainer

1011 89ff748d Thomas Thrainer
    Since DRBD devices are not created per se, just assembled, this
1012 89ff748d Thomas Thrainer
    function only initializes the metadata.
1013 89ff748d Thomas Thrainer

1014 89ff748d Thomas Thrainer
    """
1015 89ff748d Thomas Thrainer
    if len(children) != 2:
1016 89ff748d Thomas Thrainer
      raise errors.ProgrammerError("Invalid setup for the drbd device")
1017 89ff748d Thomas Thrainer
    if excl_stor:
1018 89ff748d Thomas Thrainer
      raise errors.ProgrammerError("DRBD device requested with"
1019 89ff748d Thomas Thrainer
                                   " exclusive_storage")
1020 89ff748d Thomas Thrainer
    # check that the minor is unused
1021 89ff748d Thomas Thrainer
    aminor = unique_id[4]
1022 2fe690f1 Thomas Thrainer
1023 47e0abee Thomas Thrainer
    info = DRBD8.GetProcInfo()
1024 47e0abee Thomas Thrainer
    if info.HasMinorStatus(aminor):
1025 47e0abee Thomas Thrainer
      status = info.GetMinorStatus(aminor)
1026 89ff748d Thomas Thrainer
      in_use = status.is_in_use
1027 89ff748d Thomas Thrainer
    else:
1028 89ff748d Thomas Thrainer
      in_use = False
1029 89ff748d Thomas Thrainer
    if in_use:
1030 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: minor is already in use at Create() time",
1031 89ff748d Thomas Thrainer
                      aminor)
1032 89ff748d Thomas Thrainer
    meta = children[1]
1033 89ff748d Thomas Thrainer
    meta.Assemble()
1034 89ff748d Thomas Thrainer
    if not meta.Attach():
1035 89ff748d Thomas Thrainer
      base.ThrowError("drbd%d: can't attach to meta device '%s'",
1036 89ff748d Thomas Thrainer
                      aminor, meta)
1037 89ff748d Thomas Thrainer
    cls._CheckMetaSize(meta.dev_path)
1038 89ff748d Thomas Thrainer
    cls._InitMeta(aminor, meta.dev_path)
1039 89ff748d Thomas Thrainer
    return cls(unique_id, children, size, params)
1040 89ff748d Thomas Thrainer
1041 89ff748d Thomas Thrainer
1042 89ff748d Thomas Thrainer
def _CanReadDevice(path):
1043 89ff748d Thomas Thrainer
  """Check if we can read from the given device.
1044 89ff748d Thomas Thrainer

1045 89ff748d Thomas Thrainer
  This tries to read the first 128k of the device.
1046 89ff748d Thomas Thrainer

1047 47e0abee Thomas Thrainer
  @type path: string
1048 47e0abee Thomas Thrainer

1049 89ff748d Thomas Thrainer
  """
1050 89ff748d Thomas Thrainer
  try:
1051 89ff748d Thomas Thrainer
    utils.ReadFile(path, size=_DEVICE_READ_SIZE)
1052 89ff748d Thomas Thrainer
    return True
1053 89ff748d Thomas Thrainer
  except EnvironmentError:
1054 89ff748d Thomas Thrainer
    logging.warning("Can't read from device %s", path, exc_info=True)
1055 89ff748d Thomas Thrainer
    return False