summaryrefslogtreecommitdiff
path: root/ironic/nova
diff options
context:
space:
mode:
authorDevananda van der Veen <devananda.vdv@gmail.com>2014-07-09 10:16:27 -0700
committerDevananda van der Veen <devananda.vdv@gmail.com>2014-07-14 14:49:39 -0700
commitc30cb24dac3968779d95e2d739705feb48497f3e (patch)
tree246e6bae6d025304b51188398abae1685dfba096 /ironic/nova
parentb7a0b1be94c78b49dbc3deedcdc37a3c770dc489 (diff)
downloadironic-c30cb24dac3968779d95e2d739705feb48497f3e.tar.gz
Make ComputeCapabilitiesFilter work with Ironic
It is not currently possible to selectively associate a Nova flavor with certain nodes in Ironic, beyond variances in the cpu/ram/disk. The ComputeCapabilitiesFilter exists in Nova for just this purpose, but the nova.virt.ironic driver is not propagating the correct data up to the scheduler. This patch parses the node.properties['capabilities'] as a series of comma-separated k:v pairs and passes them up to Nova so that it can be matched against flavor.extra_specs['capabilities'] by the scheduler filter. Co-Author: Matthew Gilliard <matthew.gilliard@hp.com> DocImpact: adds the ability to specify multiple capabilities to a node for scheduling purposes Closes-bug: 1339816 Change-Id: Ide39f4a2796b169025bf0083e021166ae35f30f8
Diffstat (limited to 'ironic/nova')
-rw-r--r--ironic/nova/tests/virt/ironic/test_driver.py24
-rw-r--r--ironic/nova/virt/ironic/driver.py30
2 files changed, 50 insertions, 4 deletions
diff --git a/ironic/nova/tests/virt/ironic/test_driver.py b/ironic/nova/tests/virt/ironic/test_driver.py
index ec5921b66..1699fd525 100644
--- a/ironic/nova/tests/virt/ironic/test_driver.py
+++ b/ironic/nova/tests/virt/ironic/test_driver.py
@@ -150,6 +150,30 @@ class IronicDriverTestCase(test.NoDBTestCase):
self.assertEqual(node_uuid, result['hypervisor_hostname'])
self.assertEqual(stats, jsonutils.loads(result['stats']))
+ def test__node_resource_exposes_capabilities(self):
+ props = _get_properties()
+ props['capabilities'] = 'test:capability'
+ node = ironic_utils.get_test_node(properties=props)
+ result = self.driver._node_resource(node)
+ stats = jsonutils.loads(result['stats'])
+ self.assertIsNone(stats.get('capabilities'))
+ self.assertEqual('capability', stats.get('test'))
+
+ def test__node_resource_no_capabilities(self):
+ props = _get_properties()
+ props['capabilities'] = None
+ node = ironic_utils.get_test_node(properties=props)
+ result = self.driver._node_resource(node)
+ self.assertIsNone(jsonutils.loads(result['stats']).get('capabilities'))
+
+ def test__node_resource_malformed_capabilities(self):
+ props = _get_properties()
+ props['capabilities'] = 'test:capability,:no_key,no_val:'
+ node = ironic_utils.get_test_node(properties=props)
+ result = self.driver._node_resource(node)
+ stats = jsonutils.loads(result['stats'])
+ self.assertEqual('capability', stats.get('test'))
+
def test__node_resource_no_instance_uuid(self):
node_uuid = uuidutils.generate_uuid()
props = _get_properties()
diff --git a/ironic/nova/virt/ironic/driver.py b/ironic/nova/virt/ironic/driver.py
index c67d63911..0a3544565 100644
--- a/ironic/nova/virt/ironic/driver.py
+++ b/ironic/nova/virt/ironic/driver.py
@@ -167,12 +167,9 @@ class IronicDriver(virt_driver.ComputeDriver):
super(IronicDriver, self).__init__(virtapi)
self.firewall_driver = firewall.load_driver(default=_FIREWALL_DRIVER)
- # TODO(deva): sort out extra_specs and nova-scheduler interaction
extra_specs = {}
extra_specs["ironic_driver"] = \
"ironic.nova.virt.ironic.driver.IronicDriver"
- # cpu_arch set per node.
- extra_specs['cpu_arch'] = ''
for pair in CONF.ironic.instance_type_extra_specs:
keyval = pair.split(':', 1)
keyval[0] = keyval[0].strip()
@@ -201,9 +198,34 @@ class IronicDriver(virt_driver.ComputeDriver):
memory_mb = int(node.properties.get('memory_mb', 0))
local_gb = int(node.properties.get('local_gb', 0))
cpu_arch = str(node.properties.get('cpu_arch', 'NotFound'))
- nodes_extra_specs = self.extra_specs
+
+ nodes_extra_specs = self.extra_specs.copy()
+
+ # NOTE(deva): In Havana and Icehouse, the flavor was required to link
+ # to an arch-specific deploy kernel and ramdisk pair, and so the flavor
+ # also had to have extra_specs['cpu_arch'], which was matched against
+ # the ironic node.properties['cpu_arch'].
+ # With Juno, the deploy image(s) may be referenced directly by the
+ # node.driver_info, and a flavor no longer needs to contain any of
+ # these three extra specs, though the cpu_arch may still be used
+ # in a heterogeneous environment, if so desired.
nodes_extra_specs['cpu_arch'] = cpu_arch
+ # NOTE(gilliard): To assist with more precise scheduling, if the
+ # node.properties contains a key 'capabilities', we expect the value
+ # to be of the form "k1:v1,k2:v2,etc.." which we add directly as
+ # key/value pairs into the node_extra_specs to be used by the
+ # ComputeCapabilitiesFilter
+ capabilities = node.properties.get('capabilities')
+ if capabilities:
+ for capability in str(capabilities).split(','):
+ parts = capability.split(':')
+ if len(parts) == 2 and parts[0] and parts[1]:
+ nodes_extra_specs[parts[0]] = parts[1]
+ else:
+ LOG.warn(_LW("Ignoring malformed capability '%s'. "
+ "Format should be 'key:val'."), capability)
+
vcpus_used = 0
memory_mb_used = 0
local_gb_used = 0