Commit e8936ef7 authored by Helga Velroyen's avatar Helga Velroyen
Browse files

iallocator: use lookup by disk template



So far, the iallocator requested storage information
about all enabled disk templates but discarded all but
the LVM information, even if it was allocating space
for a non-LVM instance. With this patch, it now only
asks for the one that is relevant for
the allocation request.

This has the following advantages:
- less load in the RPC call
- meaningful storage information is used for non-LVM
  instance and thus better allocation

Note that this so far works only for instance allocation.
The code introduces some FIXMEs which will be resolved
when utilizing the improvements in other iallocator
requests as well.
Signed-off-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parent b669aa41
...@@ -399,10 +399,12 @@ class IAllocator(object): ...@@ -399,10 +399,12 @@ class IAllocator(object):
self._BuildInputData(req) self._BuildInputData(req)
def _ComputeClusterDataNodeInfo(self, node_list, cluster_info, def _ComputeClusterDataNodeInfo(self, disk_templates, node_list,
hypervisor_name): cluster_info, hypervisor_name):
"""Prepare and execute node info call. """Prepare and execute node info call.
@type disk_templates: list of string
@param disk_templates: the disk templates of the instances to be allocated
@type node_list: list of strings @type node_list: list of strings
@param node_list: list of nodes' UUIDs @param node_list: list of nodes' UUIDs
@type cluster_info: L{objects.Cluster} @type cluster_info: L{objects.Cluster}
...@@ -413,17 +415,23 @@ class IAllocator(object): ...@@ -413,17 +415,23 @@ class IAllocator(object):
@return: the result of the node info RPC call @return: the result of the node info RPC call
""" """
storage_units_raw = utils.storage.GetStorageUnitsOfCluster( if disk_templates:
self.cfg, include_spindles=True) storage_units_raw = utils.storage.GetStorageUnits(self.cfg,
disk_templates)
else:
# FIXME: eliminate this case
storage_units_raw = utils.storage.GetStorageUnitsOfCluster(
self.cfg, include_spindles=True)
storage_units = rpc.PrepareStorageUnitsForNodes(self.cfg, storage_units_raw, storage_units = rpc.PrepareStorageUnitsForNodes(self.cfg, storage_units_raw,
node_list) node_list)
hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])] hvspecs = [(hypervisor_name, cluster_info.hvparams[hypervisor_name])]
return self.rpc.call_node_info(node_list, storage_units, hvspecs) return self.rpc.call_node_info(node_list, storage_units, hvspecs)
def _ComputeClusterData(self): def _ComputeClusterData(self, disk_template=None):
"""Compute the generic allocator input data. """Compute the generic allocator input data.
This is the data that is independent of the actual operation. @type disk_template: list of string
@param disk_template: the disk templates of the instances to be allocated
""" """
cluster_info = self.cfg.GetClusterInfo() cluster_info = self.cfg.GetClusterInfo()
...@@ -452,9 +460,11 @@ class IAllocator(object): ...@@ -452,9 +460,11 @@ class IAllocator(object):
hypervisor_name = cluster_info.primary_hypervisor hypervisor_name = cluster_info.primary_hypervisor
node_whitelist = None node_whitelist = None
has_lvm = utils.storage.IsLvmEnabled(cluster_info.enabled_disk_templates) if not disk_template:
node_data = self._ComputeClusterDataNodeInfo(node_list, cluster_info, disk_template = cluster_info.enabled_disk_templates[0]
hypervisor_name)
node_data = self._ComputeClusterDataNodeInfo([disk_template], node_list,
cluster_info, hypervisor_name)
node_iinfo = \ node_iinfo = \
self.rpc.call_all_instances_info(node_list, self.rpc.call_all_instances_info(node_list,
...@@ -464,8 +474,8 @@ class IAllocator(object): ...@@ -464,8 +474,8 @@ class IAllocator(object):
data["nodegroups"] = self._ComputeNodeGroupData(self.cfg) data["nodegroups"] = self._ComputeNodeGroupData(self.cfg)
config_ndata = self._ComputeBasicNodeData(self.cfg, ninfo, node_whitelist) config_ndata = self._ComputeBasicNodeData(self.cfg, ninfo, node_whitelist)
data["nodes"] = self._ComputeDynamicNodeData(ninfo, node_data, node_iinfo, data["nodes"] = self._ComputeDynamicNodeData(
i_list, config_ndata, has_lvm) ninfo, node_data, node_iinfo, i_list, config_ndata, disk_template)
assert len(data["nodes"]) == len(ninfo), \ assert len(data["nodes"]) == len(ninfo), \
"Incomplete node data computed" "Incomplete node data computed"
...@@ -547,6 +557,49 @@ class IAllocator(object): ...@@ -547,6 +557,49 @@ class IAllocator(object):
(node_name, attr, value)) (node_name, attr, value))
return value return value
@staticmethod
def _ComputeStorageDataFromSpaceInfoByTemplate(
space_info, node_name, disk_template):
"""Extract storage data from node info.
@type space_info: see result of the RPC call node info
@param space_info: the storage reporting part of the result of the RPC call
node info
@type node_name: string
@param node_name: the node's name
@type disk_template: string
@param disk_template: the disk template to report space for
@rtype: 4-tuple of integers
@return: tuple of storage info (total_disk, free_disk, total_spindles,
free_spindles)
"""
storage_type = constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]
if storage_type not in constants.STS_REPORT:
total_disk = total_spindles = 0
free_disk = free_spindles = 0
else:
template_space_info = utils.storage.LookupSpaceInfoByDiskTemplate(
space_info, disk_template)
if not template_space_info:
raise errors.OpExecError("Node '%s' didn't return space info for disk"
"template '%s'" % (node_name, disk_template))
total_disk = template_space_info["storage_size"]
free_disk = template_space_info["storage_free"]
if disk_template in constants.DTS_LVM:
lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
space_info, constants.ST_LVM_PV)
if not lvm_pv_info:
raise errors.OpExecError("Node '%s' didn't return LVM pv space info."
% (node_name))
total_spindles = lvm_pv_info["storage_size"]
free_spindles = lvm_pv_info["storage_free"]
else:
total_spindles = 0
free_spindles = 0
return (total_disk, free_disk, total_spindles, free_spindles)
@staticmethod @staticmethod
def _ComputeStorageDataFromSpaceInfo(space_info, node_name, has_lvm): def _ComputeStorageDataFromSpaceInfo(space_info, node_name, has_lvm):
"""Extract storage data from node info. """Extract storage data from node info.
...@@ -574,7 +627,7 @@ class IAllocator(object): ...@@ -574,7 +627,7 @@ class IAllocator(object):
free_disk = lvm_vg_info["storage_free"] free_disk = lvm_vg_info["storage_free"]
lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType( lvm_pv_info = utils.storage.LookupSpaceInfoByStorageType(
space_info, constants.ST_LVM_PV) space_info, constants.ST_LVM_PV)
if not lvm_vg_info: if not lvm_pv_info:
raise errors.OpExecError("Node '%s' didn't return LVM pv space info." raise errors.OpExecError("Node '%s' didn't return LVM pv space info."
% (node_name)) % (node_name))
total_spindles = lvm_pv_info["storage_size"] total_spindles = lvm_pv_info["storage_size"]
...@@ -616,7 +669,7 @@ class IAllocator(object): ...@@ -616,7 +669,7 @@ class IAllocator(object):
return (i_p_mem, i_p_up_mem, mem_free) return (i_p_mem, i_p_up_mem, mem_free)
def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list, def _ComputeDynamicNodeData(self, node_cfg, node_data, node_iinfo, i_list,
node_results, has_lvm): node_results, disk_template):
"""Compute global node data. """Compute global node data.
@param node_results: the basic node structures as filled from the config @param node_results: the basic node structures as filled from the config
...@@ -642,8 +695,8 @@ class IAllocator(object): ...@@ -642,8 +695,8 @@ class IAllocator(object):
(i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory( (i_p_mem, i_p_up_mem, mem_free) = self._ComputeInstanceMemory(
i_list, node_iinfo, nuuid, mem_free) i_list, node_iinfo, nuuid, mem_free)
(total_disk, free_disk, total_spindles, free_spindles) = \ (total_disk, free_disk, total_spindles, free_spindles) = \
self._ComputeStorageDataFromSpaceInfo(space_info, ninfo.name, self._ComputeStorageDataFromSpaceInfoByTemplate(
has_lvm) space_info, ninfo.name, disk_template)
# compute memory used by instances # compute memory used by instances
pnr_dyn = { pnr_dyn = {
...@@ -715,9 +768,13 @@ class IAllocator(object): ...@@ -715,9 +768,13 @@ class IAllocator(object):
"""Build input data structures. """Build input data structures.
""" """
self._ComputeClusterData()
request = req.GetRequest(self.cfg) request = req.GetRequest(self.cfg)
disk_template = None
# FIXME: decide this based on request mode
if "disk_template" in request:
disk_template = request["disk_template"]
self._ComputeClusterData(disk_template=disk_template)
request["type"] = req.MODE request["type"] = req.MODE
self.in_data["request"] = request self.in_data["request"] = request
......
...@@ -217,6 +217,32 @@ class TestProcessStorageInfo(unittest.TestCase): ...@@ -217,6 +217,32 @@ class TestProcessStorageInfo(unittest.TestCase):
self.assertEqual(self.free_storage_lvm, free_disk) self.assertEqual(self.free_storage_lvm, free_disk)
self.assertEqual(self.total_storage_lvm, total_disk) self.assertEqual(self.total_storage_lvm, total_disk)
def testComputeStorageDataFromSpaceInfoByTemplate(self):
disk_template = constants.DT_FILE
node_name = "mynode"
(total_disk, free_disk, total_spindles, free_spindles) = \
iallocator.IAllocator._ComputeStorageDataFromSpaceInfoByTemplate(
self.space_info, node_name, disk_template)
self.assertEqual(self.free_storage_file, free_disk)
self.assertEqual(self.total_storage_file, total_disk)
def testComputeStorageDataFromSpaceInfoByTemplateLvm(self):
disk_template = constants.DT_PLAIN
node_name = "mynode"
(total_disk, free_disk, total_spindles, free_spindles) = \
iallocator.IAllocator._ComputeStorageDataFromSpaceInfoByTemplate(
self.space_info, node_name, disk_template)
self.assertEqual(self.free_storage_lvm, free_disk)
self.assertEqual(self.total_storage_lvm, total_disk)
def testComputeStorageDataFromSpaceInfoByTemplateNoReport(self):
disk_template = constants.DT_DISKLESS
node_name = "mynode"
(total_disk, free_disk, total_spindles, free_spindles) = \
iallocator.IAllocator._ComputeStorageDataFromSpaceInfoByTemplate(
self.space_info, node_name, disk_template)
self.assertEqual(0, free_disk)
self.assertEqual(0, total_disk)
if __name__ == "__main__": if __name__ == "__main__":
testutils.GanetiTestProgram() testutils.GanetiTestProgram()
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