From 2be7273ccdad115169ab0f8765f3fe66d0aeff47 Mon Sep 17 00:00:00 2001
From: Apollon Oikonomopoulos <apollon@noc.grnet.gr>
Date: Fri, 4 Mar 2011 16:28:58 +0200
Subject: [PATCH] Add bdev_sizes RPC call

The bdev_sizes multi-node RPC call returns the sizes of the requested
block devices on the desired nodes. Its intended use is to verify the
existence of a block device on a given node for shared block storage
support.

Block device paths are expected to lie under constants.BLOCKDEV_DIR
("/dev/disk" by default), where persistent symlinks for block devices
are assumed to exist.

Signed-off-by: Apollon Oikonomopoulos <apollon@noc.grnet.gr>
[iustin@google.com: small changes in backend.py]
Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/backend.py      | 38 ++++++++++++++++++++++++++++++++++++++
 lib/rpc.py          |  9 +++++++++
 lib/server/noded.py |  9 +++++++++
 3 files changed, 56 insertions(+)

diff --git a/lib/backend.py b/lib/backend.py
index 391bb7a0a..44e5b7e74 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -647,6 +647,44 @@ def VerifyNode(what, cluster_name):
   return result
 
 
+def GetBlockDevSizes(devices):
+  """Return the size of the given block devices
+
+  @type devices: list
+  @param devices: list of block device nodes to query
+  @rtype: dict
+  @return:
+    dictionary of all block devices under /dev (key). The value is their
+    size in MiB.
+
+    {'/dev/disk/by-uuid/123456-12321231-312312-312': 124}
+
+  """
+  DEV_PREFIX = "/dev/"
+  blockdevs = {}
+
+  for devpath in devices:
+    if os.path.commonprefix([DEV_PREFIX, devpath]) != DEV_PREFIX:
+      continue
+
+    try:
+      st = os.stat(devpath)
+    except EnvironmentError, err:
+      logging.warning("Error stat()'ing device %s: %s", devpath, str(err))
+      continue
+
+    if stat.S_ISBLK(st.st_mode):
+      result = utils.RunCmd(["blockdev", "--getsize64", devpath])
+      if result.failed:
+        # We don't want to fail, just do not list this device as available
+        logging.warning("Cannot get size for block device %s", devpath)
+        continue
+
+      size = int(result.stdout) / (1024 * 1024)
+      blockdevs[devpath] = size
+  return blockdevs
+
+
 def GetVolumeList(vg_names):
   """Compute list of logical volumes and their size.
 
diff --git a/lib/rpc.py b/lib/rpc.py
index 4e2693e55..2eeec0628 100644
--- a/lib/rpc.py
+++ b/lib/rpc.py
@@ -589,6 +589,15 @@ class RpcRunner(object):
   # Begin RPC calls
   #
 
+  @_RpcTimeout(_TMO_URGENT)
+  def call_bdev_sizes(self, node_list, devices):
+    """Gets the sizes of requested block devices present on a node
+
+    This is a multi-node call.
+
+    """
+    return self._MultiNodeCall(node_list, "bdev_sizes", [devices])
+
   @_RpcTimeout(_TMO_URGENT)
   def call_lv_list(self, node_list, vg_name):
     """Gets the logical volumes present in a given volume group.
diff --git a/lib/server/noded.py b/lib/server/noded.py
index decc87449..0090efb7d 100644
--- a/lib/server/noded.py
+++ b/lib/server/noded.py
@@ -457,6 +457,15 @@ class NodeHttpServer(http.server.HttpServer):
     export = params[0]
     return backend.RemoveExport(export)
 
+  # block device ---------------------
+  @staticmethod
+  def perspective_bdev_sizes(params):
+    """Query the list of block devices
+
+    """
+    devices = params[0]
+    return backend.GetBlockDevSizes(devices)
+
   # volume  --------------------------
 
   @staticmethod
-- 
GitLab