Commit 32389d91 authored by Helga Velroyen's avatar Helga Velroyen
Browse files

Refactor NodeInfo RPC regarding storage reporting



The NodeInfo RPC call is refactored to handle now more than
just storage reporting for volume groups.

Since NodeInfo now returns storage space information not
necessarily for volume groups, but also for other storage
entities, it is no longer appropriate to call the fields
of the NodeInfo result "vg_free" and "vg_size". We rename
it to "storage_free" and "storage_size" instead.
Signed-off-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarThomas Thrainer <thomasth@google.com>
parent 683335b3
......@@ -589,8 +589,8 @@ def _GetVgInfo(name, excl_stor):
return {
"type": constants.ST_LVM_VG,
"name": name,
"vg_free": vg_free,
"vg_size": vg_size,
"storage_free": vg_free,
"storage_size": vg_size,
}
......@@ -614,8 +614,8 @@ def _GetVgSpindlesInfo(name, excl_stor):
return {
"type": constants.ST_LVM_PV,
"name": name,
"vg_free": vg_free,
"vg_size": vg_size,
"storage_free": vg_free,
"storage_size": vg_size,
}
......
......@@ -893,8 +893,6 @@ def _CheckNodesFreeDiskOnVG(lu, node_uuids, vg, requested):
"""
es_flags = rpc.GetExclusiveStorageForNodes(lu.cfg, node_uuids)
# FIXME: This maps everything to storage type 'lvm-vg' to maintain
# the current functionality. Refactor to make it more flexible.
hvname = lu.cfg.GetHypervisorType()
hvparams = lu.cfg.GetClusterInfo().hvparams
nodeinfo = lu.rpc.call_node_info(node_uuids, [(constants.ST_LVM_VG, vg)],
......@@ -906,7 +904,7 @@ def _CheckNodesFreeDiskOnVG(lu, node_uuids, vg, requested):
info.Raise("Cannot get current information from node %s" % node_name,
prereq=True, ecode=errors.ECODE_ENVIRON)
(_, (vg_info, ), _) = info.payload
vg_free = vg_info.get("vg_free", None)
vg_free = vg_info.get("storage_free", None)
if not isinstance(vg_free, int):
raise errors.OpPrereqError("Can't compute free disk space on node"
" %s for vg %s, result was '%s'" %
......
......@@ -1184,15 +1184,20 @@ class NodeQuery(QueryBase):
es_flags = rpc.GetExclusiveStorageForNodes(lu.cfg, toquery_node_uuids)
# FIXME: This currently maps everything to lvm, this should be more
# flexible
vg_req = rpc.BuildVgInfoQuery(lu.cfg)
lvm_enabled = utils.storage.IsLvmEnabled(
lu.cfg.GetClusterInfo().enabled_disk_templates)
storage_units = utils.storage.GetStorageUnitsOfCluster(
lu.cfg, include_spindles=True)
default_hypervisor = lu.cfg.GetHypervisorType()
hvparams = lu.cfg.GetClusterInfo().hvparams[default_hypervisor]
hvspecs = [(default_hypervisor, hvparams)]
node_data = lu.rpc.call_node_info(toquery_node_uuids, vg_req,
node_data = lu.rpc.call_node_info(toquery_node_uuids, storage_units,
hvspecs, es_flags)
live_data = dict((uuid, rpc.MakeLegacyNodeInfo(nresult.payload))
for (uuid, nresult) in node_data.items()
if not nresult.fail_msg and nresult.payload)
live_data = dict(
(uuid, rpc.MakeLegacyNodeInfo(nresult.payload,
require_vg_info=lvm_enabled))
for (uuid, nresult) in node_data.items()
if not nresult.fail_msg and nresult.payload)
else:
live_data = None
......
......@@ -431,10 +431,11 @@ class IAllocator(object):
node_whitelist = None
es_flags = rpc.GetExclusiveStorageForNodes(self.cfg, node_list)
vg_req = rpc.BuildVgInfoQuery(self.cfg)
has_lvm = bool(vg_req)
storage_units = utils.storage.GetStorageUnitsOfCluster(
self.cfg, include_spindles=True)
has_lvm = utils.storage.IsLvmEnabled(cluster_info.enabled_disk_templates)
hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])]
node_data = self.rpc.call_node_info(node_list, vg_req,
node_data = self.rpc.call_node_info(node_list, storage_units,
hvspecs, es_flags)
node_iinfo = \
self.rpc.call_all_instances_info(node_list,
......@@ -551,8 +552,8 @@ class IAllocator(object):
# TODO: replace this with proper storage reporting
if has_lvm:
total_disk = get_attr("vg_size")
free_disk = get_attr("vg_free")
total_disk = get_attr("storage_size")
free_disk = get_attr("storage_free")
total_spindles = get_attr("spindles_total")
free_spindles = get_attr("spindles_free")
else:
......
......@@ -1155,10 +1155,10 @@ _NODE_LIVE_FIELDS = {
"csockets": ("CSockets", QFT_NUMBER, "cpu_sockets",
"Number of physical CPU sockets (if exported by hypervisor)"),
"ctotal": ("CTotal", QFT_NUMBER, "cpu_total", "Number of logical processors"),
"dfree": ("DFree", QFT_UNIT, "vg_free",
"Available disk space in volume group"),
"dtotal": ("DTotal", QFT_UNIT, "vg_size",
"Total disk space in volume group used for instance disk"
"dfree": ("DFree", QFT_UNIT, "storage_free",
"Available storage space in storage unit"),
"dtotal": ("DTotal", QFT_UNIT, "storage_size",
"Total storage space in storage unit used for instance disk"
" allocation"),
"spfree": ("SpFree", QFT_NUMBER, "spindles_free",
"Available spindles in volume group (exclusive storage only)"),
......
......@@ -592,26 +592,56 @@ def _EncodeBlockdevRename(value):
return [(d.ToDict(), uid) for d, uid in value]
def BuildVgInfoQuery(cfg):
"""Build a query about the default VG for C{node_info}.
def _AddSpindlesToLegacyNodeInfo(result, space_info):
"""Extracts the spindle information from the space info and adds
it to the result dictionary.
@type result: dict of strings
@param result: dictionary holding the result of the legacy node info
@type space_info: list of dicts of strings
@param space_info: list, each row holding space information of one storage
unit
@rtype: None
@return: does not return anything, manipulates the C{result} variable
The result of the RPC can be parsed with L{MakeLegacyNodeInfo}.
"""
lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
space_info, constants.ST_LVM_PV)
if lvm_pv_info:
result["spindles_free"] = lvm_pv_info["storage_free"]
result["spindles_total"] = lvm_pv_info["storage_size"]
@type cfg: L{config.ConfigWriter}
@param cfg: Cluster configuration
@rtype: list
@return: argument suitable for L{rpc.RpcRunner.call_node_info}
def _AddDefaultStorageInfoToLegacyNodeInfo(result, space_info,
require_vg_info=True):
"""Extracts the storage space information of the default storage type from
the space info and adds it to the result dictionary.
@see: C{_AddSpindlesToLegacyNodeInfo} for parameter information.
@type require_vg_info: boolean
@param require_vg_info: indicates whether volume group information is
required or not
"""
vg_name = cfg.GetVGName()
if vg_name:
ret = [
(constants.ST_LVM_VG, vg_name),
(constants.ST_LVM_PV, vg_name),
]
# Check if there is at least one row for non-spindle storage info.
no_defaults = (len(space_info) < 1) or \
(space_info[0]["type"] == constants.ST_LVM_PV and len(space_info) == 1)
default_space_info = None
if no_defaults:
logging.warning("No storage info provided for default storage type.")
else:
ret = []
return ret
default_space_info = space_info[0]
if require_vg_info:
if no_defaults or not default_space_info["type"] == constants.ST_LVM_VG:
raise errors.OpExecError("LVM volume group info required, but not"
" provided.")
if default_space_info:
result["name"] = default_space_info["name"]
result["storage_free"] = default_space_info["storage_free"]
result["storage_size"] = default_space_info["storage_size"]
def MakeLegacyNodeInfo(data, require_vg_info=True):
......@@ -624,15 +654,13 @@ def MakeLegacyNodeInfo(data, require_vg_info=True):
doesn't have any values
"""
(bootid, vgs_info, (hv_info, )) = data
(bootid, space_info, (hv_info, )) = data
ret = utils.JoinDisjointDicts(hv_info, {"bootid": bootid})
if require_vg_info or vgs_info:
(vg0_info, vg0_spindles) = vgs_info
ret = utils.JoinDisjointDicts(vg0_info, ret)
ret["spindles_free"] = vg0_spindles["vg_free"]
ret["spindles_total"] = vg0_spindles["vg_size"]
_AddSpindlesToLegacyNodeInfo(ret, space_info)
_AddDefaultStorageInfoToLegacyNodeInfo(ret, space_info,
require_vg_info=require_vg_info)
return ret
......
......@@ -45,8 +45,8 @@ def GetFileStorageSpaceInfo(path):
size = (result.f_frsize * result.f_blocks) / (1024 * 1024)
return {"type": constants.ST_FILE,
"name": path,
"vg_size": size,
"vg_free": free}
"storage_size": size,
"storage_free": free}
except OSError, e:
raise errors.CommandError("Failed to retrieve file system information about"
" path: %s - %s" % (path, e.strerror))
......@@ -61,10 +61,10 @@ nodeLiveFieldsDefs =
"Number of physical CPU sockets (if exported by hypervisor)")
, ("ctotal", "CTotal", QFTNumber, "cpu_total",
"Number of logical processors")
, ("dfree", "DFree", QFTUnit, "vg_free",
"Available disk space in volume group")
, ("dtotal", "DTotal", QFTUnit, "vg_size",
"Total disk space in volume group used for instance disk allocation")
, ("dfree", "DFree", QFTUnit, "storage_free",
"Available storage space on storage unit")
, ("dtotal", "DTotal", QFTUnit, "storage_size",
"Total storage space on storage unit for instance disk allocation")
, ("spfree", "SpFree", QFTNumber, "spindles_free",
"Available spindles in volume group (exclusive storage only)")
, ("sptotal", "SpTotal", QFTNumber, "spindles_total",
......@@ -89,13 +89,13 @@ nodeLiveFieldExtract "csockets" res =
nodeLiveFieldExtract "ctotal" res =
jsonHead (rpcResNodeInfoHvInfo res) hvInfoCpuTotal
nodeLiveFieldExtract "dfree" res =
getMaybeJsonHead (rpcResNodeInfoVgInfo res) vgInfoVgFree
getMaybeJsonHead (rpcResNodeInfoStorageInfo res) storageInfoStorageFree
nodeLiveFieldExtract "dtotal" res =
getMaybeJsonHead (rpcResNodeInfoVgInfo res) vgInfoVgSize
getMaybeJsonHead (rpcResNodeInfoStorageInfo res) storageInfoStorageSize
nodeLiveFieldExtract "spfree" res =
getMaybeJsonElem (rpcResNodeInfoVgInfo res) 1 vgInfoVgFree
getMaybeJsonElem (rpcResNodeInfoStorageInfo res) 1 storageInfoStorageFree
nodeLiveFieldExtract "sptotal" res =
getMaybeJsonElem (rpcResNodeInfoVgInfo res) 1 vgInfoVgSize
getMaybeJsonElem (rpcResNodeInfoStorageInfo res) 1 storageInfoStorageSize
nodeLiveFieldExtract "mfree" res =
jsonHead (rpcResNodeInfoHvInfo res) hvInfoMemoryFree
nodeLiveFieldExtract "mnode" res =
......
......@@ -52,7 +52,7 @@ module Ganeti.Rpc
, RpcResultInstanceList(..)
, HvInfo(..)
, VgInfo(..)
, StorageInfo(..)
, RpcCallNodeInfo(..)
, RpcResultNodeInfo(..)
......@@ -342,11 +342,11 @@ $(buildObject "RpcCallNodeInfo" "rpcCallNodeInfo"
, simpleField "exclusive_storage" [t| Map.Map String Bool |]
])
$(buildObject "VgInfo" "vgInfo"
$(buildObject "StorageInfo" "storageInfo"
[ simpleField "name" [t| String |]
, simpleField "type" [t| String |]
, optionalField $ simpleField "vg_free" [t| Int |]
, optionalField $ simpleField "vg_size" [t| Int |]
, optionalField $ simpleField "storage_free" [t| Int |]
, optionalField $ simpleField "storage_size" [t| Int |]
])
-- | We only provide common fields as described in hv_base.py.
......@@ -361,7 +361,7 @@ $(buildObject "HvInfo" "hvInfo"
$(buildObject "RpcResultNodeInfo" "rpcResNodeInfo"
[ simpleField "boot_id" [t| String |]
, simpleField "vg_info" [t| [VgInfo] |]
, simpleField "storage_info" [t| [StorageInfo] |]
, simpleField "hv_info" [t| [HvInfo] |]
])
......
......@@ -900,26 +900,31 @@ class TestRpcRunner(unittest.TestCase):
class TestLegacyNodeInfo(unittest.TestCase):
KEY_BOOT = "bootid"
KEY_VG0 = "name"
KEY_VG1 = "vg_free"
KEY_VG2 = "vg_size"
KEY_VG1 = "storage_free"
KEY_VG2 = "storage_size"
KEY_HV = "cpu_count"
KEY_SP1 = "spindles_free"
KEY_SP2 = "spindles_total"
KEY_ST = "type" # key for storage type
VAL_BOOT = 0
VAL_VG0 = "xy"
VAL_VG1 = 11
VAL_VG2 = 12
VAL_VG3 = "lvm-vg"
VAL_HV = 2
VAL_SP0 = "ab"
VAL_SP1 = 31
VAL_SP2 = 32
VAL_SP3 = "lvm-pv"
DICT_VG = {
KEY_VG0: VAL_VG0,
KEY_VG1: VAL_VG1,
KEY_VG2: VAL_VG2,
KEY_ST: VAL_VG3,
}
DICT_HV = {KEY_HV: VAL_HV}
DICT_SP = {
KEY_ST: VAL_SP3,
KEY_VG0: VAL_SP0,
KEY_VG1: VAL_SP1,
KEY_VG2: VAL_SP2,
......@@ -941,7 +946,7 @@ class TestLegacyNodeInfo(unittest.TestCase):
def testReqVg(self):
my_lst = [self.VAL_BOOT, [], [self.DICT_HV]]
self.assertRaises(ValueError, rpc.MakeLegacyNodeInfo, my_lst)
self.assertRaises(errors.OpExecError, rpc.MakeLegacyNodeInfo, my_lst)
def testNoReqVg(self):
my_lst = [self.VAL_BOOT, [], [self.DICT_HV]]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment