- f.write("%d" % (kbytes/2))
- finally:
- f.close()
- return result
-
-
- def GetSyncStatus(self):
- """Returns the sync status of the device.
-
- Returns:
- (sync_percent, estimated_time)
-
- If sync_percent is None, it means all is ok
- If estimated_time is None, it means we can't esimate
- the time needed, otherwise it's the time left in seconds
-
- """
- if self.minor is None and not self.Attach():
- raise errors.BlockDeviceError("Can't attach to device in GetSyncStatus")
- dev_info = self._GetDevInfo(self.minor)
- is_clean = ("state" in dev_info and
- len(dev_info["state"]) == 1 and
- dev_info["state"][0] in ("clean", "active"))
- sys_path = "/sys/block/md%s/md/" % self.minor
- f = file(sys_path + "sync_action")
- sync_status = f.readline().strip()
- f.close()
- if sync_status == "idle":
- return None, None, not is_clean
- f = file(sys_path + "sync_completed")
- sync_completed = f.readline().strip().split(" / ")
- f.close()
- if len(sync_completed) != 2:
- return 0, None, not is_clean
- sync_done, sync_total = [float(i) for i in sync_completed]
- sync_percent = 100.0*sync_done/sync_total
- f = file(sys_path + "sync_speed")
- sync_speed_k = int(f.readline().strip())
- if sync_speed_k == 0:
- time_est = None
- else:
- time_est = (sync_total - sync_done) / 2 / sync_speed_k
- return sync_percent, time_est, not is_clean
-
-
- def Open(self, force=False):
- """Make the device ready for I/O.
-
- This is a no-op for the MDRaid1 device type, although we could use
- the 2.6.18's new array_state thing.
-
- """
- return True
-
-
- def Close(self):
- """Notifies that the device will no longer be used for I/O.
-
- This is a no-op for the MDRaid1 device type, but see comment for
- `Open()`.
-
- """
- return True
-
-
-
-class DRBDev(BlockDev):
- """DRBD block device.
-
- This implements the local host part of the DRBD device, i.e. it
- doesn't do anything to the supposed peer. If you need a fully
- connected DRBD pair, you need to use this class on both hosts.
-
- The unique_id for the drbd device is the (local_ip, local_port,
- remote_ip, remote_port) tuple, and it must have two children: the
- data device and the meta_device. The meta device is checked for
- valid size and is zeroed on create.
-
- """
- _DRBD_MAJOR = 147
- _ST_UNCONFIGURED = "Unconfigured"
- _ST_WFCONNECTION = "WFConnection"
- _ST_CONNECTED = "Connected"
-
- def __init__(self, unique_id, children):
- super(DRBDev, self).__init__(unique_id, children)
- self.major = self._DRBD_MAJOR
- if len(children) != 2:
- raise ValueError("Invalid configuration data %s" % str(children))
- if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 4:
- raise ValueError("Invalid configuration data %s" % str(unique_id))
- self._lhost, self._lport, self._rhost, self._rport = unique_id
- self.Attach()
-
- @staticmethod
- def _DevPath(minor):
- """Return the path to a drbd device for a given minor.
-
- """
- return "/dev/drbd%d" % minor
-
- @staticmethod
- def _GetProcData():
- """Return data from /proc/drbd.
-
- """
- stat = open("/proc/drbd", "r")
- data = stat.read().splitlines()
- stat.close()
- return data
-
-
- @classmethod
- def _GetUsedDevs(cls):
- """Compute the list of used DRBD devices.
-
- """
- data = cls._GetProcData()
-
- used_devs = {}
- valid_line = re.compile("^ *([0-9]+): cs:([^ ]+).*$")
- for line in data:
- match = valid_line.match(line)
- if not match:
- continue
- minor = int(match.group(1))
- state = match.group(2)
- if state == cls._ST_UNCONFIGURED:
- continue
- used_devs[minor] = state, line
-
- return used_devs
-
-
- @classmethod
- def _FindUnusedMinor(cls):
- """Find an unused DRBD device.
-
- """
- data = cls._GetProcData()
-
- valid_line = re.compile("^ *([0-9]+): cs:Unconfigured$")
- for line in data:
- match = valid_line.match(line)
- if match:
- return int(match.group(1))
- logger.Error("Error: no free drbd minors!")
- return None
-
-
- @classmethod
- def _GetDevInfo(cls, minor):
- """Get details about a given DRBD minor.
-
- This return, if available, the local backing device in (major,
- minor) formant and the local and remote (ip, port) information.
-
- """
- data = {}
- result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "show"])
- if result.failed:
- logger.Error("Can't display the drbd config: %s" % result.fail_reason)
- return data
- out = result.stdout
- if out == "Not configured\n":
- return data
- for line in out.splitlines():
- if "local_dev" not in data:
- match = re.match("^Lower device: ([0-9]+):([0-9]+) .*$", line)
- if match:
- data["local_dev"] = (int(match.group(1)), int(match.group(2)))
- continue
- if "meta_dev" not in data:
- match = re.match("^Meta device: (([0-9]+):([0-9]+)|internal).*$", line)
- if match:
- if match.group(2) is not None and match.group(3) is not None:
- # matched on the major/minor
- data["meta_dev"] = (int(match.group(2)), int(match.group(3)))
- else:
- # matched on the "internal" string
- data["meta_dev"] = match.group(1)
- # in this case, no meta_index is in the output
- data["meta_index"] = -1
- continue
- if "meta_index" not in data:
- match = re.match("^Meta index: ([0-9]+).*$", line)
- if match:
- data["meta_index"] = int(match.group(1))
- continue
- if "local_addr" not in data:
- match = re.match("^Local address: ([0-9.]+):([0-9]+)$", line)
- if match:
- data["local_addr"] = (match.group(1), int(match.group(2)))
- continue
- if "remote_addr" not in data:
- match = re.match("^Remote address: ([0-9.]+):([0-9]+)$", line)
- if match:
- data["remote_addr"] = (match.group(1), int(match.group(2)))
- continue