← Back to team overview

openstack team mailing list archive

[nova] RFC - filtering compute nodes in a mixed environment

 

In a previous thread [1], I mentioned two possibilities for controlling
the scheduling of instances to an appropriate compute node in a mixed
node (Xen, KVM) environment.  The first approach uses availability
zones, the second uses the existing vm_mode image property.  Folks
seemed to agree on the latter, and the attached patch adds a check to
the compute filter to ensure the compute node can accommodate the
instance type.

The compute filter seems like the right place to add this check, but
posting as a RFC since I'm not sure if this would be agreeable to
everyone as compared to a custom filter for example.

Regards,
Jim

[1]
http://openstack.markmail.org/search/?q=improve%20xen#query:improve%20xen+page:1+mid:knmnylknf2imnruy+state:results

>From bb8777a415d5db22b83971357882261fbef092a9 Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig@xxxxxxxx>
Date: Mon, 25 Jun 2012 15:54:43 -0600
Subject: [PATCH] Add check for vm_mode in compute filter

Add a check in the scheduler compute filter to see if the compute service
supports the vm_mode specified in the instance properties.

As mentioned in a previous thread [1], there needs to be a way to control
scheduling of instances to an appropriate node in a mixed compute node
environment.  The existing vm_mode property, in conjuction with the
additional_compute_capabilities flag, provides a mechanism to filter
appropriate nodes.

[1] http://openstack.markmail.org/search/?q=improve%20xen#query:improve%20xen+page:1+mid:knmnylknf2imnruy+state:results
---
 nova/scheduler/filters/compute_filter.py  |   20 +++++++++++++++++++-
 nova/tests/scheduler/test_host_filters.py |   26 ++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/nova/scheduler/filters/compute_filter.py b/nova/scheduler/filters/compute_filter.py
index 5409d3d..5187c39 100644
--- a/nova/scheduler/filters/compute_filter.py
+++ b/nova/scheduler/filters/compute_filter.py
@@ -22,7 +22,8 @@ LOG = logging.getLogger(__name__)
 
 
 class ComputeFilter(filters.BaseHostFilter):
-    """HostFilter hard-coded to work with InstanceType records."""
+    """HostFilter hard-coded to work with InstanceType and
+    InstanceProperties records."""
 
     def _satisfies_extra_specs(self, capabilities, instance_type):
         """Check that the capabilities provided by the compute service
@@ -38,8 +39,21 @@ class ComputeFilter(filters.BaseHostFilter):
                 return False
         return True
 
+    def _satisfies_capabilities(self, capabilities, instance_props):
+        """Check that the capabilities provided by the compute service
+        satisfies properties defined in the instance."""
+        vm_mode = instance_props.get('vm_mode')
+        if not vm_mode:
+            return True
+        if capabilities.get(vm_mode, None):
+            return True
+        else:
+            return False
+
     def host_passes(self, host_state, filter_properties):
         """Return a list of hosts that can create instance_type."""
+        spec = filter_properties.get('request_spec', {})
+        instance_props = spec.get('instance_properties', {})
         instance_type = filter_properties.get('instance_type')
         if host_state.topic != 'compute' or not instance_type:
             return True
@@ -57,4 +71,8 @@ class ComputeFilter(filters.BaseHostFilter):
             LOG.debug(_("%(host_state)s fails instance_type extra_specs "
                     "requirements"), locals())
             return False
+        if not self._satisfies_capabilities(capabilities, instance_props):
+            LOG.debug(_("%(host_state)s fails instance_properties "
+                    "requirements"), locals())
+            return False
         return True
diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py
index 80da5ac..3a99292 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -349,6 +349,32 @@ class HostFiltersTestCase(test.TestCase):
 
         self.assertFalse(filt_cls.host_passes(host, filter_properties))
 
+    def test_compute_filter_passes_additional_caps(self):
+        self._stub_service_is_up(True)
+        filt_cls = self.class_map['ComputeFilter']()
+        req_spec = {'instance_properties': {'vm_mode': 'pv'}}
+        capabilities = {'enabled': True, 'pv': True, 'hvm': True}
+        service = {'disabled': False}
+        filter_properties = {'instance_type': {'memory_mb': 1024},
+                             'request_spec' : req_spec}
+        host = fakes.FakeHostState('host1', 'compute',
+                {'free_ram_mb': 1024, 'capabilities': capabilities,
+                 'service': service})
+        self.assertTrue(filt_cls.host_passes(host, filter_properties))
+
+    def test_compute_filter_fails_additional_caps(self):
+        self._stub_service_is_up(True)
+        filt_cls = self.class_map['ComputeFilter']()
+        req_spec = {'instance_properties': {'vm_mode': 'pv'}}
+        capabilities = {'enabled': True}
+        service = {'disabled': False}
+        filter_properties = {'instance_type': {'memory_mb': 1024},
+                             'request_spec': req_spec}
+        host = fakes.FakeHostState('host1', 'compute',
+                {'free_ram_mb': 1024, 'capabilities': capabilities,
+                 'service': service})
+        self.assertFalse(filt_cls.host_passes(host, filter_properties))
+
     def test_isolated_hosts_fails_isolated_on_non_isolated(self):
         self.flags(isolated_images=['isolated'], isolated_hosts=['isolated'])
         filt_cls = self.class_map['IsolatedHostsFilter']()
-- 
1.7.9.2