+def _FindDisks(nodes_ip, disks):
+ """Sets the physical ID on disks and returns the block devices.
+
+ """
+ # set the correct physical ID
+ my_name = utils.HostInfo().name
+ for cf in disks:
+ cf.SetPhysicalID(my_name, nodes_ip)
+
+ bdevs = []
+
+ for cf in disks:
+ rd = _RecursiveFindBD(cf)
+ if rd is None:
+ return (False, "Can't find device %s" % cf)
+ bdevs.append(rd)
+ return (True, bdevs)
+
+
+def DrbdDisconnectNet(nodes_ip, disks):
+ """Disconnects the network on a list of drbd devices.
+
+ """
+ status, bdevs = _FindDisks(nodes_ip, disks)
+ if not status:
+ return status, bdevs
+
+ # disconnect disks
+ for rd in bdevs:
+ try:
+ rd.DisconnectNet()
+ except errors.BlockDeviceError, err:
+ logging.exception("Failed to go into standalone mode")
+ return (False, "Can't change network configuration: %s" % str(err))
+ return (True, "All disks are now disconnected")
+
+
+def DrbdAttachNet(nodes_ip, disks, instance_name, multimaster):
+ """Attaches the network on a list of drbd devices.
+
+ """
+ status, bdevs = _FindDisks(nodes_ip, disks)
+ if not status:
+ return status, bdevs
+
+ if multimaster:
+ for idx, rd in enumerate(bdevs):
+ try:
+ _SymlinkBlockDev(instance_name, rd.dev_path, idx)
+ except EnvironmentError, err:
+ return (False, "Can't create symlink: %s" % str(err))
+ # reconnect disks, switch to new master configuration and if
+ # needed primary mode
+ for rd in bdevs:
+ try:
+ rd.AttachNet(multimaster)
+ except errors.BlockDeviceError, err:
+ return (False, "Can't change network configuration: %s" % str(err))
+ # wait until the disks are connected; we need to retry the re-attach
+ # if the device becomes standalone, as this might happen if the one
+ # node disconnects and reconnects in a different mode before the
+ # other node reconnects; in this case, one or both of the nodes will
+ # decide it has wrong configuration and switch to standalone
+ RECONNECT_TIMEOUT = 2 * 60
+ sleep_time = 0.100 # start with 100 miliseconds
+ timeout_limit = time.time() + RECONNECT_TIMEOUT
+ while time.time() < timeout_limit:
+ all_connected = True
+ for rd in bdevs:
+ stats = rd.GetProcStatus()
+ if not (stats.is_connected or stats.is_in_resync):
+ all_connected = False
+ if stats.is_standalone:
+ # peer had different config info and this node became
+ # standalone, even though this should not happen with the
+ # new staged way of changing disk configs
+ try:
+ rd.ReAttachNet(multimaster)
+ except errors.BlockDeviceError, err:
+ return (False, "Can't change network configuration: %s" % str(err))
+ if all_connected:
+ break
+ time.sleep(sleep_time)
+ sleep_time = min(5, sleep_time * 1.5)
+ if not all_connected:
+ return (False, "Timeout in disk reconnecting")
+ if multimaster:
+ # change to primary mode
+ for rd in bdevs:
+ try:
+ rd.Open()
+ except errors.BlockDeviceError, err:
+ return (False, "Can't change to primary mode: %s" % str(err))
+ if multimaster:
+ msg = "multi-master and primary"
+ else:
+ msg = "single-master"
+ return (True, "Disks are now configured as %s" % msg)
+
+
+def DrbdWaitSync(nodes_ip, disks):
+ """Wait until DRBDs have synchronized.
+
+ """
+ status, bdevs = _FindDisks(nodes_ip, disks)
+ if not status:
+ return status, bdevs
+
+ min_resync = 100
+ alldone = True
+ failure = False
+ for rd in bdevs:
+ stats = rd.GetProcStatus()
+ if not (stats.is_connected or stats.is_in_resync):
+ failure = True
+ break
+ alldone = alldone and (not stats.is_in_resync)
+ if stats.sync_percent is not None:
+ min_resync = min(min_resync, stats.sync_percent)
+ return (not failure, (alldone, min_resync))
+
+