1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """DRBD block device related functionality"""
23
24 import errno
25 import logging
26 import time
27
28 from ganeti import constants
29 from ganeti import utils
30 from ganeti import errors
31 from ganeti import netutils
32 from ganeti import objects
33 from ganeti.storage import base
34 from ganeti.storage.drbd_info import DRBD8Info
35 from ganeti.storage import drbd_info
36 from ganeti.storage import drbd_cmdgen
37
38
39
40
41 _DEVICE_READ_SIZE = 128 * 1024
42
43
44 -class DRBD8(object):
45 """Various methods to deals with the DRBD system as a whole.
46
47 This class provides a set of methods to deal with the DRBD installation on
48 the node or with uninitialized devices as opposed to a DRBD device.
49
50 """
51 _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
52
53 _MAX_MINORS = 255
54
55 @staticmethod
57 """Returns DRBD usermode_helper currently set.
58
59 @type filename: string
60 @param filename: the filename to read the usermode helper from
61 @rtype: string
62 @return: the currently configured DRBD usermode helper
63
64 """
65 try:
66 helper = utils.ReadFile(filename).splitlines()[0]
67 except EnvironmentError, err:
68 if err.errno == errno.ENOENT:
69 base.ThrowError("The file %s cannot be opened, check if the module"
70 " is loaded (%s)", filename, str(err))
71 else:
72 base.ThrowError("Can't read DRBD helper file %s: %s",
73 filename, str(err))
74 if not helper:
75 base.ThrowError("Can't read any data from %s", filename)
76 return helper
77
78 @staticmethod
80 """Reads and parses information from /proc/drbd.
81
82 @rtype: DRBD8Info
83 @return: a L{DRBD8Info} instance containing the current /proc/drbd info
84
85 """
86 return DRBD8Info.CreateFromFile()
87
88 @staticmethod
90 """Compute the list of used DRBD minors.
91
92 @rtype: list of ints
93
94 """
95 info = DRBD8.GetProcInfo()
96 return filter(lambda m: not info.GetMinorStatus(m).is_unconfigured,
97 info.GetMinors())
98
99 @staticmethod
101 """Find an unused DRBD device.
102
103 This is specific to 8.x as the minors are allocated dynamically,
104 so non-existing numbers up to a max minor count are actually free.
105
106 @rtype: int
107
108 """
109 highest = None
110 info = DRBD8.GetProcInfo()
111 for minor in info.GetMinors():
112 status = info.GetMinorStatus(minor)
113 if not status.is_in_use:
114 return minor
115 highest = max(highest, minor)
116
117 if highest is None:
118 return 0
119 if highest >= DRBD8._MAX_MINORS:
120 logging.error("Error: no free drbd minors!")
121 raise errors.BlockDeviceError("Can't find a free DRBD minor")
122
123 return highest + 1
124
125 @staticmethod
138
139 @staticmethod
141 """Deactivate the device.
142
143 This will, of course, fail if the device is in use.
144
145 @type minor: int
146 @param minor: the minor to shut down
147
148 """
149 info = DRBD8.GetProcInfo()
150 cmd_gen = DRBD8.GetCmdGenerator(info)
151
152 cmd = cmd_gen.GenDownCmd(minor)
153 result = utils.RunCmd(cmd)
154 if result.failed:
155 base.ThrowError("drbd%d: can't shutdown drbd device: %s",
156 minor, result.output)
157
160 """DRBD v8.x block device.
161
162 This implements the local host part of the DRBD device, i.e. it
163 doesn't do anything to the supposed peer. If you need a fully
164 connected DRBD pair, you need to use this class on both hosts.
165
166 The unique_id for the drbd device is a (local_ip, local_port,
167 remote_ip, remote_port, local_minor, secret) tuple, and it must have
168 two children: the data device and the meta_device. The meta device
169 is checked for valid size and is zeroed on create.
170
171 """
172 _DRBD_MAJOR = 147
173
174
175 _NET_RECONFIG_TIMEOUT = 60
176
177 - def __init__(self, unique_id, children, size, params):
178 if children and children.count(None) > 0:
179 children = []
180 if len(children) not in (0, 2):
181 raise ValueError("Invalid configuration data %s" % str(children))
182 if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 6:
183 raise ValueError("Invalid configuration data %s" % str(unique_id))
184 (self._lhost, self._lport,
185 self._rhost, self._rport,
186 self._aminor, self._secret) = unique_id
187 if children:
188 if not _CanReadDevice(children[1].dev_path):
189 logging.info("drbd%s: Ignoring unreadable meta device", self._aminor)
190 children = []
191 super(DRBD8Dev, self).__init__(unique_id, children, size, params)
192 self.major = self._DRBD_MAJOR
193
194 info = DRBD8.GetProcInfo()
195 version = info.GetVersion()
196 if version["k_major"] != 8:
197 base.ThrowError("Mismatch in DRBD kernel version and requested ganeti"
198 " usage: kernel is %s.%s, ganeti wants 8.x",
199 version["k_major"], version["k_minor"])
200
201 if version["k_minor"] <= 3:
202 self._show_info_cls = drbd_info.DRBD83ShowInfo
203 else:
204 self._show_info_cls = drbd_info.DRBD84ShowInfo
205
206 self._cmd_gen = DRBD8.GetCmdGenerator(info)
207
208 if (self._lhost is not None and self._lhost == self._rhost and
209 self._lport == self._rport):
210 raise ValueError("Invalid configuration data, same local/remote %s" %
211 (unique_id,))
212 self.Attach()
213
214 @staticmethod
216 """Return the path to a drbd device for a given minor.
217
218 @type minor: int
219 @rtype: string
220
221 """
222 return "/dev/drbd%d" % minor
223
225 """Set our parameters based on the given minor.
226
227 This sets our minor variable and our dev_path.
228
229 @type minor: int
230
231 """
232 if minor is None:
233 self.minor = self.dev_path = None
234 self.attached = False
235 else:
236 self.minor = minor
237 self.dev_path = self._DevPath(minor)
238 self.attached = True
239
240 @staticmethod
272
274 """Return the `drbdsetup show` data.
275
276 @type minor: int
277 @param minor: the minor to collect show output for
278 @rtype: string
279
280 """
281 result = utils.RunCmd(self._cmd_gen.GenShowCmd(minor))
282 if result.failed:
283 logging.error("Can't display the drbd config: %s - %s",
284 result.fail_reason, result.output)
285 return None
286 return result.stdout
287
289 """Return parsed information from `drbdsetup show`.
290
291 @type minor: int
292 @param minor: the minor to return information for
293 @rtype: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
294
295 """
296 return self._show_info_cls.GetDevInfo(self._GetShowData(minor))
297
299 """Test if our local config matches with an existing device.
300
301 The parameter should be as returned from `_GetShowInfo()`. This
302 method tests if our local backing device is the same as the one in
303 the info parameter, in effect testing if we look like the given
304 device.
305
306 @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
307 @rtype: boolean
308
309 """
310 if self._children:
311 backend, meta = self._children
312 else:
313 backend = meta = None
314
315 if backend is not None:
316 retval = ("local_dev" in info and info["local_dev"] == backend.dev_path)
317 else:
318 retval = ("local_dev" not in info)
319
320 if meta is not None:
321 retval = retval and ("meta_dev" in info and
322 info["meta_dev"] == meta.dev_path)
323 if "meta_index" in info:
324 retval = retval and info["meta_index"] == 0
325 else:
326 retval = retval and ("meta_dev" not in info and
327 "meta_index" not in info)
328 return retval
329
331 """Test if our network config matches with an existing device.
332
333 The parameter should be as returned from `_GetShowInfo()`. This
334 method tests if our network configuration is the same as the one
335 in the info parameter, in effect testing if we look like the given
336 device.
337
338 @type info: dict as described in L{drbd_info.BaseShowInfo.GetDevInfo}
339 @rtype: boolean
340
341 """
342 if (((self._lhost is None and not ("local_addr" in info)) and
343 (self._rhost is None and not ("remote_addr" in info)))):
344 return True
345
346 if self._lhost is None:
347 return False
348
349 if not ("local_addr" in info and
350 "remote_addr" in info):
351 return False
352
353 retval = (info["local_addr"] == (self._lhost, self._lport))
354 retval = (retval and
355 info["remote_addr"] == (self._rhost, self._rport))
356 return retval
357
359 """Configure the local part of a DRBD device.
360
361 @type minor: int
362 @param minor: the minor to assemble locally
363 @type backend: string
364 @param backend: path to the data device to use
365 @type meta: string
366 @param meta: path to the meta device to use
367 @type size: int
368 @param size: size in MiB
369
370 """
371 cmds = self._cmd_gen.GenLocalInitCmds(minor, backend, meta,
372 size, self.params)
373
374 for cmd in cmds:
375 result = utils.RunCmd(cmd)
376 if result.failed:
377 base.ThrowError("drbd%d: can't attach local disk: %s",
378 minor, result.output)
379
380 - def _AssembleNet(self, minor, net_info, dual_pri=False, hmac=None,
381 secret=None):
382 """Configure the network part of the device.
383
384 @type minor: int
385 @param minor: the minor to assemble the network for
386 @type net_info: (string, int, string, int)
387 @param net_info: tuple containing the local address, local port, remote
388 address and remote port
389 @type dual_pri: boolean
390 @param dual_pri: whether two primaries should be allowed or not
391 @type hmac: string
392 @param hmac: the HMAC algorithm to use
393 @type secret: string
394 @param secret: the shared secret to use
395
396 """
397 lhost, lport, rhost, rport = net_info
398 if None in net_info:
399
400
401 self._ShutdownNet(minor)
402 return
403
404 if dual_pri:
405 protocol = constants.DRBD_MIGRATION_NET_PROTOCOL
406 else:
407 protocol = self.params[constants.LDP_PROTOCOL]
408
409
410
411
412
413
414
415 sync_errors = self._SetMinorSyncParams(minor, self.params)
416 if sync_errors:
417 base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
418 (minor, utils.CommaJoin(sync_errors)))
419
420 family = self._GetNetFamily(minor, lhost, rhost)
421
422 cmd = self._cmd_gen.GenNetInitCmd(minor, family, lhost, lport,
423 rhost, rport, protocol,
424 dual_pri, hmac, secret, self.params)
425
426 result = utils.RunCmd(cmd)
427 if result.failed:
428 base.ThrowError("drbd%d: can't setup network: %s - %s",
429 minor, result.fail_reason, result.output)
430
431 def _CheckNetworkConfig():
432 info = self._GetShowInfo(minor)
433 if not "local_addr" in info or not "remote_addr" in info:
434 raise utils.RetryAgain()
435
436 if (info["local_addr"] != (lhost, lport) or
437 info["remote_addr"] != (rhost, rport)):
438 raise utils.RetryAgain()
439
440 try:
441 utils.Retry(_CheckNetworkConfig, 1.0, 10.0)
442 except utils.RetryTimeout:
443 base.ThrowError("drbd%d: timeout while configuring network", minor)
444
445 @staticmethod
459
461 """Add a disk to the DRBD device.
462
463 @type devices: list of L{BlockDev}
464 @param devices: a list of exactly two L{BlockDev} objects; the first
465 denotes the data device, the second the meta device for this DRBD device
466
467 """
468 if self.minor is None:
469 base.ThrowError("drbd%d: can't attach to dbrd8 during AddChildren",
470 self._aminor)
471 if len(devices) != 2:
472 base.ThrowError("drbd%d: need two devices for AddChildren", self.minor)
473 info = self._GetShowInfo(self.minor)
474 if "local_dev" in info:
475 base.ThrowError("drbd%d: already attached to a local disk", self.minor)
476 backend, meta = devices
477 if backend.dev_path is None or meta.dev_path is None:
478 base.ThrowError("drbd%d: children not ready during AddChildren",
479 self.minor)
480 backend.Open()
481 meta.Open()
482 self._CheckMetaSize(meta.dev_path)
483 self._InitMeta(DRBD8.FindUnusedMinor(), meta.dev_path)
484
485 self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path, self.size)
486 self._children = devices
487
489 """Detach the drbd device from local storage.
490
491 @type devices: list of L{BlockDev}
492 @param devices: a list of exactly two L{BlockDev} objects; the first
493 denotes the data device, the second the meta device for this DRBD device
494
495 """
496 if self.minor is None:
497 base.ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
498 self._aminor)
499
500 info = self._GetShowInfo(self.minor)
501 if "local_dev" not in info:
502 return
503 if len(self._children) != 2:
504 base.ThrowError("drbd%d: we don't have two children: %s", self.minor,
505 self._children)
506 if self._children.count(None) == 2:
507 logging.warning("drbd%d: requested detach while detached", self.minor)
508 return
509 if len(devices) != 2:
510 base.ThrowError("drbd%d: we need two children in RemoveChildren",
511 self.minor)
512 for child, dev in zip(self._children, devices):
513 if dev != child.dev_path:
514 base.ThrowError("drbd%d: mismatch in local storage (%s != %s) in"
515 " RemoveChildren", self.minor, dev, child.dev_path)
516
517 self._ShutdownLocal(self.minor)
518 self._children = []
519
521 """Set the parameters of the DRBD syncer.
522
523 This is the low-level implementation.
524
525 @type minor: int
526 @param minor: the drbd minor whose settings we change
527 @type params: dict
528 @param params: LD level disk parameters related to the synchronization
529 @rtype: list
530 @return: a list of error messages
531
532 """
533 cmd = self._cmd_gen.GenSyncParamsCmd(minor, params)
534 result = utils.RunCmd(cmd)
535 if result.failed:
536 msg = ("Can't change syncer rate: %s - %s" %
537 (result.fail_reason, result.output))
538 logging.error(msg)
539 return [msg]
540
541 return []
542
544 """Set the synchronization parameters of the DRBD syncer.
545
546 See L{BlockDev.SetSyncParams} for parameter description.
547
548 """
549 if self.minor is None:
550 err = "Not attached during SetSyncParams"
551 logging.info(err)
552 return [err]
553
554 children_result = super(DRBD8Dev, self).SetSyncParams(params)
555 children_result.extend(self._SetMinorSyncParams(self.minor, params))
556 return children_result
557
559 """Pauses or resumes the sync of a DRBD device.
560
561 See L{BlockDev.PauseResumeSync} for parameter description.
562
563 """
564 if self.minor is None:
565 logging.info("Not attached during PauseSync")
566 return False
567
568 children_result = super(DRBD8Dev, self).PauseResumeSync(pause)
569
570 if pause:
571 cmd = self._cmd_gen.GenPauseSyncCmd(self.minor)
572 else:
573 cmd = self._cmd_gen.GenResumeSyncCmd(self.minor)
574
575 result = utils.RunCmd(cmd)
576 if result.failed:
577 logging.error("Can't %s: %s - %s", cmd,
578 result.fail_reason, result.output)
579 return not result.failed and children_result
580
582 """Return the current status data from /proc/drbd for this device.
583
584 @rtype: DRBD8Status
585
586 """
587 if self.minor is None:
588 base.ThrowError("drbd%d: GetStats() called while not attached",
589 self._aminor)
590 info = DRBD8.GetProcInfo()
591 if not info.HasMinorStatus(self.minor):
592 base.ThrowError("drbd%d: can't find myself in /proc", self.minor)
593 return info.GetMinorStatus(self.minor)
594
596 """Returns the sync status of the device.
597
598 If sync_percent is None, it means all is ok
599 If estimated_time is None, it means we can't estimate
600 the time needed, otherwise it's the time left in seconds.
601
602 We set the is_degraded parameter to True on two conditions:
603 network not connected or local disk missing.
604
605 We compute the ldisk parameter based on whether we have a local
606 disk or not.
607
608 @rtype: objects.BlockDevStatus
609
610 """
611 if self.minor is None and not self.Attach():
612 base.ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
613
614 stats = self.GetProcStatus()
615 is_degraded = not stats.is_connected or not stats.is_disk_uptodate
616
617 if stats.is_disk_uptodate:
618 ldisk_status = constants.LDS_OKAY
619 elif stats.is_diskless:
620 ldisk_status = constants.LDS_FAULTY
621 else:
622 ldisk_status = constants.LDS_UNKNOWN
623
624 return objects.BlockDevStatus(dev_path=self.dev_path,
625 major=self.major,
626 minor=self.minor,
627 sync_percent=stats.sync_percent,
628 estimated_time=stats.est_time,
629 is_degraded=is_degraded,
630 ldisk_status=ldisk_status)
631
632 - def Open(self, force=False):
633 """Make the local state primary.
634
635 If the 'force' parameter is given, DRBD is instructed to switch the device
636 into primary mode. Since this is a potentially dangerous operation, the
637 force flag should be only given after creation, when it actually is
638 mandatory.
639
640 """
641 if self.minor is None and not self.Attach():
642 logging.error("DRBD cannot attach to a device during open")
643 return False
644
645 cmd = self._cmd_gen.GenPrimaryCmd(self.minor, force)
646
647 result = utils.RunCmd(cmd)
648 if result.failed:
649 base.ThrowError("drbd%d: can't make drbd device primary: %s", self.minor,
650 result.output)
651
653 """Make the local state secondary.
654
655 This will, of course, fail if the device is in use.
656
657 """
658 if self.minor is None and not self.Attach():
659 base.ThrowError("drbd%d: can't Attach() in Close()", self._aminor)
660 cmd = self._cmd_gen.GenSecondaryCmd(self.minor)
661 result = utils.RunCmd(cmd)
662 if result.failed:
663 base.ThrowError("drbd%d: can't switch drbd device to secondary: %s",
664 self.minor, result.output)
665
667 """Removes network configuration.
668
669 This method shutdowns the network side of the device.
670
671 The method will wait up to a hardcoded timeout for the device to
672 go into standalone after the 'disconnect' command before
673 re-configuring it, as sometimes it takes a while for the
674 disconnect to actually propagate and thus we might issue a 'net'
675 command while the device is still connected. If the device will
676 still be attached to the network and we time out, we raise an
677 exception.
678
679 """
680 if self.minor is None:
681 base.ThrowError("drbd%d: disk not attached in re-attach net",
682 self._aminor)
683
684 if None in (self._lhost, self._lport, self._rhost, self._rport):
685 base.ThrowError("drbd%d: DRBD disk missing network info in"
686 " DisconnectNet()", self.minor)
687
688 class _DisconnectStatus:
689 def __init__(self, ever_disconnected):
690 self.ever_disconnected = ever_disconnected
691
692 dstatus = _DisconnectStatus(base.IgnoreError(self._ShutdownNet, self.minor))
693
694 def _WaitForDisconnect():
695 if self.GetProcStatus().is_standalone:
696 return
697
698
699
700
701 dstatus.ever_disconnected = \
702 base.IgnoreError(self._ShutdownNet, self.minor) or \
703 dstatus.ever_disconnected
704
705 raise utils.RetryAgain()
706
707
708 start_time = time.time()
709
710 try:
711
712 utils.Retry(_WaitForDisconnect, (0.1, 1.5, 2.0),
713 self._NET_RECONFIG_TIMEOUT)
714 except utils.RetryTimeout:
715 if dstatus.ever_disconnected:
716 msg = ("drbd%d: device did not react to the"
717 " 'disconnect' command in a timely manner")
718 else:
719 msg = "drbd%d: can't shutdown network, even after multiple retries"
720
721 base.ThrowError(msg, self.minor)
722
723 reconfig_time = time.time() - start_time
724 if reconfig_time > (self._NET_RECONFIG_TIMEOUT * 0.25):
725 logging.info("drbd%d: DisconnectNet: detach took %.3f seconds",
726 self.minor, reconfig_time)
727
729 """Reconnects the network.
730
731 This method connects the network side of the device with a
732 specified multi-master flag. The device needs to be 'Standalone'
733 but have valid network configuration data.
734
735 @type multimaster: boolean
736 @param multimaster: init the network in dual-primary mode
737
738 """
739 if self.minor is None:
740 base.ThrowError("drbd%d: device not attached in AttachNet", self._aminor)
741
742 if None in (self._lhost, self._lport, self._rhost, self._rport):
743 base.ThrowError("drbd%d: missing network info in AttachNet()", self.minor)
744
745 status = self.GetProcStatus()
746
747 if not status.is_standalone:
748 base.ThrowError("drbd%d: device is not standalone in AttachNet",
749 self.minor)
750
751 self._AssembleNet(self.minor,
752 (self._lhost, self._lport, self._rhost, self._rport),
753 dual_pri=multimaster, hmac=constants.DRBD_HMAC_ALG,
754 secret=self._secret)
755
757 """Check if our minor is configured.
758
759 This doesn't do any device configurations - it only checks if the
760 minor is in a state different from Unconfigured.
761
762 Note that this function will not change the state of the system in
763 any way (except in case of side-effects caused by reading from
764 /proc).
765
766 """
767 used_devs = DRBD8.GetUsedDevs()
768 if self._aminor in used_devs:
769 minor = self._aminor
770 else:
771 minor = None
772
773 self._SetFromMinor(minor)
774 return minor is not None
775
777 """Assemble the drbd.
778
779 Method:
780 - if we have a configured device, we try to ensure that it matches
781 our config
782 - if not, we create it from zero
783 - anyway, set the device parameters
784
785 """
786 super(DRBD8Dev, self).Assemble()
787
788 self.Attach()
789 if self.minor is None:
790
791 self._FastAssemble()
792 else:
793
794
795 self._SlowAssemble()
796
797 sync_errors = self.SetSyncParams(self.params)
798 if sync_errors:
799 base.ThrowError("drbd%d: can't set the synchronization parameters: %s" %
800 (self.minor, utils.CommaJoin(sync_errors)))
801
803 """Assembles the DRBD device from a (partially) configured device.
804
805 In case of partially attached (local device matches but no network
806 setup), we perform the network attach. If successful, we re-test
807 the attach if can return success.
808
809 """
810
811
812 net_data = (self._lhost, self._lport, self._rhost, self._rport)
813 for minor in (self._aminor,):
814 info = self._GetShowInfo(minor)
815 match_l = self._MatchesLocal(info)
816 match_r = self._MatchesNet(info)
817
818 if match_l and match_r:
819
820 break
821
822 if match_l and not match_r and "local_addr" not in info:
823
824 self._AssembleNet(minor, net_data, hmac=constants.DRBD_HMAC_ALG,
825 secret=self._secret)
826 if self._MatchesNet(self._GetShowInfo(minor)):
827 break
828 else:
829 base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
830 " show' disagrees", minor)
831
832 if match_r and "local_dev" not in info:
833
834 self._AssembleLocal(minor, self._children[0].dev_path,
835 self._children[1].dev_path, self.size)
836 if self._MatchesLocal(self._GetShowInfo(minor)):
837 break
838 else:
839 base.ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
840 " show' disagrees", minor)
841
842
843
844
845
846 if (match_l and "local_dev" in info and
847 not match_r and "local_addr" in info):
848
849
850
851
852 try:
853 self._ShutdownNet(minor)
854 except errors.BlockDeviceError, err:
855 base.ThrowError("drbd%d: device has correct local storage, wrong"
856 " remote peer and is unable to disconnect in order"
857 " to attach to the correct peer: %s", minor, str(err))
858
859
860
861 self._AssembleNet(minor, net_data, hmac=constants.DRBD_HMAC_ALG,
862 secret=self._secret)
863 if self._MatchesNet(self._GetShowInfo(minor)):
864 break
865 else:
866 base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
867 " show' disagrees", minor)
868
869 else:
870 minor = None
871
872 self._SetFromMinor(minor)
873 if minor is None:
874 base.ThrowError("drbd%d: cannot activate, unknown or unhandled reason",
875 self._aminor)
876
878 """Assemble the drbd device from zero.
879
880 This is run when in Assemble we detect our minor is unused.
881
882 """
883 minor = self._aminor
884 if self._children and self._children[0] and self._children[1]:
885 self._AssembleLocal(minor, self._children[0].dev_path,
886 self._children[1].dev_path, self.size)
887 if self._lhost and self._lport and self._rhost and self._rport:
888 self._AssembleNet(minor,
889 (self._lhost, self._lport, self._rhost, self._rport),
890 hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
891 self._SetFromMinor(minor)
892
894 """Detach from the local device.
895
896 I/Os will continue to be served from the remote device. If we
897 don't have a remote device, this operation will fail.
898
899 @type minor: int
900 @param minor: the device to detach from the local device
901
902 """
903 cmd = self._cmd_gen.GenDetachCmd(minor)
904 result = utils.RunCmd(cmd)
905 if result.failed:
906 base.ThrowError("drbd%d: can't detach local disk: %s",
907 minor, result.output)
908
910 """Disconnect from the remote peer.
911
912 This fails if we don't have a local device.
913
914 @type minor: boolean
915 @param minor: the device to disconnect from the remote peer
916
917 """
918 family = self._GetNetFamily(minor, self._lhost, self._rhost)
919 cmd = self._cmd_gen.GenDisconnectCmd(minor, family,
920 self._lhost, self._lport,
921 self._rhost, self._rport)
922 result = utils.RunCmd(cmd)
923 if result.failed:
924 base.ThrowError("drbd%d: can't shutdown network: %s",
925 minor, result.output)
926
928 """Shutdown the DRBD device.
929
930 """
931 if self.minor is None and not self.Attach():
932 logging.info("drbd%d: not attached during Shutdown()", self._aminor)
933 return
934
935 try:
936 DRBD8.ShutdownAll(self.minor)
937 finally:
938 self.minor = None
939 self.dev_path = None
940
942 """Stub remove for DRBD devices.
943
944 """
945 self.Shutdown()
946
948 """Rename a device.
949
950 This is not supported for drbd devices.
951
952 """
953 raise errors.ProgrammerError("Can't rename a drbd device")
954
955 - def Grow(self, amount, dryrun, backingstore, excl_stor):
956 """Resize the DRBD device and its backing storage.
957
958 See L{BlockDev.Grow} for parameter description.
959
960 """
961 if self.minor is None:
962 base.ThrowError("drbd%d: Grow called while not attached", self._aminor)
963 if len(self._children) != 2 or None in self._children:
964 base.ThrowError("drbd%d: cannot grow diskless device", self.minor)
965 self._children[0].Grow(amount, dryrun, backingstore, excl_stor)
966 if dryrun or backingstore:
967
968
969 return
970 cmd = self._cmd_gen.GenResizeCmd(self.minor, self.size + amount)
971 result = utils.RunCmd(cmd)
972 if result.failed:
973 base.ThrowError("drbd%d: resize failed: %s", self.minor, result.output)
974
975 @classmethod
1006
1007 @classmethod
1008 - def Create(cls, unique_id, children, size, spindles, params, excl_stor):
1009 """Create a new DRBD8 device.
1010
1011 Since DRBD devices are not created per se, just assembled, this
1012 function only initializes the metadata.
1013
1014 """
1015 if len(children) != 2:
1016 raise errors.ProgrammerError("Invalid setup for the drbd device")
1017 if excl_stor:
1018 raise errors.ProgrammerError("DRBD device requested with"
1019 " exclusive_storage")
1020
1021 aminor = unique_id[4]
1022
1023 info = DRBD8.GetProcInfo()
1024 if info.HasMinorStatus(aminor):
1025 status = info.GetMinorStatus(aminor)
1026 in_use = status.is_in_use
1027 else:
1028 in_use = False
1029 if in_use:
1030 base.ThrowError("drbd%d: minor is already in use at Create() time",
1031 aminor)
1032 meta = children[1]
1033 meta.Assemble()
1034 if not meta.Attach():
1035 base.ThrowError("drbd%d: can't attach to meta device '%s'",
1036 aminor, meta)
1037 cls._CheckMetaSize(meta.dev_path)
1038 cls._InitMeta(aminor, meta.dev_path)
1039 return cls(unique_id, children, size, params)
1040
1043 """Check if we can read from the given device.
1044
1045 This tries to read the first 128k of the device.
1046
1047 @type path: string
1048
1049 """
1050 try:
1051 utils.ReadFile(path, size=_DEVICE_READ_SIZE)
1052 return True
1053 except EnvironmentError:
1054 logging.warning("Can't read from device %s", path, exc_info=True)
1055 return False
1056