Hi, I implemented selective block device handling, revised patch follows.
Apollon --- Add bdev_list RPC call to query block devices about their size. The RPC call accepts a list of block devices to query. If no list is given, then all block devices under constants.BLOCKDEV_DIR are queried. By default constants.BLOCKDEV_DIR is set to '/dev/disk', where persistent symlinks for block devices are expected to reside, created by auxiliary means, such as udev rules. Signed-off-by: Apollon Oikonomopoulos <[email protected]> --- daemons/ganeti-noded | 9 +++++++++ lib/backend.py | 33 +++++++++++++++++++++++++++++++++ lib/constants.py | 1 + lib/rpc.py | 9 +++++++++ 4 files changed, 52 insertions(+), 0 deletions(-) diff --git a/daemons/ganeti-noded b/daemons/ganeti-noded index 21227fa..939e61a 100755 --- a/daemons/ganeti-noded +++ b/daemons/ganeti-noded @@ -409,6 +409,15 @@ class NodeHttpServer(http.server.HttpServer): export = params[0] return backend.RemoveExport(export) + # block device --------------------- + @staticmethod + def perspective_bdev_list(params): + """Query the list of block devices + + """ + devices = params[0] + return backend.GetBlockdevList(devices) + # volume -------------------------- @staticmethod diff --git a/lib/backend.py b/lib/backend.py index f37b0c4..e3d81c4 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -605,6 +605,39 @@ def VerifyNode(what, cluster_name): return result +def GetBlockdevList(devices): + """Compute the list of block devices and their size + + @rtype: dict + @return: + dictionary of all block devices under /dev/disk (key). The value is their + size in MiB. + + {'/dev/disk/by-uuid/123456-12321231-312312-312': 124} + + """ + blockdevs = {} + if not devices: + for root, dirs, files in os.walk(constants.BLOCKDEV_DIR): + for dev in files: + devices.append(os.path.join(root,dev)) + + for device in devices: + if os.path.exists(device): + if stat.S_ISBLK(os.stat(device)[stat.ST_MODE]): + result = utils.RunCmd(["blockdev", "--getsize64", device]) + if result.failed: + # We don't want to fail, just warn and do not list this device + # as available + logging.warn("Warning: unable to determine the size of %s: %s" % + (device, result.stderr)) + continue + + size = int(result.stdout) / (1024 * 1024) + blockdevs[device] = size + return blockdevs + + def GetVolumeList(vg_name): """Compute list of logical volumes and their size. diff --git a/lib/constants.py b/lib/constants.py index 6b8802f..1f0b3aa 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -102,6 +102,7 @@ CRYPTO_KEYS_DIR = RUN_GANETI_DIR + "/crypto" CRYPTO_KEYS_DIR_MODE = SECURE_DIR_MODE IMPORT_EXPORT_DIR = RUN_GANETI_DIR + "/import-export" IMPORT_EXPORT_DIR_MODE = 0755 +BLOCKDEV_DIR = "/dev/disk" # keep RUN_GANETI_DIR first here, to make sure all get created when the node # daemon is started (this takes care of RUN_DIR being tmpfs) SUB_RUN_DIRS = [ RUN_GANETI_DIR, BDEV_CACHE_DIR, DISK_LINKS_DIR ] diff --git a/lib/rpc.py b/lib/rpc.py index 57dd960..e7c2386 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -492,6 +492,15 @@ class RpcRunner(object): # Begin RPC calls # + @_RpcTimeout(_TMO_NORMAL) + def call_bdev_list(self, node_list, devices=[]): + """Gets the list of block devices present on a node + + This is a multi-node call. + + """ + return self._MultiNodeCall(node_list, "bdev_list", [devices]) + @_RpcTimeout(_TMO_URGENT) def call_lv_list(self, node_list, vg_name): """Gets the logical volumes present in a given volume group. -- 1.7.1
