diff options
author | Devananda van der Veen <devananda.vdv@gmail.com> | 2014-07-09 10:16:27 -0700 |
---|---|---|
committer | Devananda van der Veen <devananda.vdv@gmail.com> | 2014-07-14 14:49:39 -0700 |
commit | c30cb24dac3968779d95e2d739705feb48497f3e (patch) | |
tree | 246e6bae6d025304b51188398abae1685dfba096 /ironic/nova | |
parent | b7a0b1be94c78b49dbc3deedcdc37a3c770dc489 (diff) | |
download | ironic-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.py | 24 | ||||
-rw-r--r-- | ironic/nova/virt/ironic/driver.py | 30 |
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 |