Modify Aggregate filters for RequestSpec
Change-Id: I032d718fbe034ee898c661acd7bbadb6eb73e2f9 Partially-Implements: blueprint request-spec-object-mitaka
This commit is contained in:
parent
15389435aa
commit
5fbc515f27
@ -40,16 +40,14 @@ class AggregateImagePropertiesIsolation(filters.BaseHostFilter):
|
||||
# Aggregate data and instance type does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
def host_passes(self, host_state, spec_obj):
|
||||
"""Checks a host in an aggregate that metadata key/value match
|
||||
with image properties.
|
||||
"""
|
||||
cfg_namespace = CONF.aggregate_image_properties_isolation_namespace
|
||||
cfg_separator = CONF.aggregate_image_properties_isolation_separator
|
||||
|
||||
spec = filter_properties.get('request_spec', {})
|
||||
image_props = spec.get('image', {}).get('properties', {})
|
||||
image_props = spec_obj.image.properties if spec_obj.image else {}
|
||||
metadata = utils.aggregate_metadata_get_by_host(host_state)
|
||||
|
||||
for key, options in six.iteritems(metadata):
|
||||
@ -57,7 +55,10 @@ class AggregateImagePropertiesIsolation(filters.BaseHostFilter):
|
||||
not key.startswith(cfg_namespace + cfg_separator)):
|
||||
continue
|
||||
prop = image_props.get(key)
|
||||
if prop and prop not in options:
|
||||
# NOTE(sbauza): Aggregate metadata is only strings, we need to
|
||||
# stringify the property to match with the option
|
||||
# TODO(sbauza): Fix that very ugly pattern matching
|
||||
if prop and str(prop) not in options:
|
||||
LOG.debug("%(host_state)s fails image aggregate properties "
|
||||
"requirements. Property %(prop)s does not "
|
||||
"match %(options)s.",
|
||||
|
@ -33,22 +33,22 @@ class AggregateInstanceExtraSpecsFilter(filters.BaseHostFilter):
|
||||
# Aggregate data and instance type does not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
def host_passes(self, host_state, spec_obj):
|
||||
"""Return a list of hosts that can create instance_type
|
||||
|
||||
Check that the extra specs associated with the instance type match
|
||||
the metadata provided by aggregates. If not present return False.
|
||||
"""
|
||||
instance_type = filter_properties.get('instance_type')
|
||||
instance_type = spec_obj.flavor
|
||||
# If 'extra_specs' is not present or extra_specs are empty then we
|
||||
# need not proceed further
|
||||
if not instance_type.get('extra_specs'):
|
||||
if (not instance_type.obj_attr_is_set('extra_specs')
|
||||
or not instance_type.extra_specs):
|
||||
return True
|
||||
|
||||
metadata = utils.aggregate_metadata_get_by_host(host_state)
|
||||
|
||||
for key, req in six.iteritems(instance_type['extra_specs']):
|
||||
for key, req in six.iteritems(instance_type.extra_specs):
|
||||
# Either not scope format, or aggregate_instance_extra_specs scope
|
||||
scope = key.split(':', 1)
|
||||
if len(scope) > 1:
|
||||
|
@ -28,8 +28,7 @@ class AggregateMultiTenancyIsolation(filters.BaseHostFilter):
|
||||
# Aggregate data and tenant do not change within a request
|
||||
run_filter_once_per_request = True
|
||||
|
||||
@filters.compat_legacy_props
|
||||
def host_passes(self, host_state, filter_properties):
|
||||
def host_passes(self, host_state, spec_obj):
|
||||
"""If a host is in an aggregate that has the metadata key
|
||||
"filter_tenant_id" it can only create instances from that tenant(s).
|
||||
A host can be in different aggregates.
|
||||
@ -37,9 +36,7 @@ class AggregateMultiTenancyIsolation(filters.BaseHostFilter):
|
||||
If a host doesn't belong to an aggregate with the metadata key
|
||||
"filter_tenant_id" it can create instances from all tenants.
|
||||
"""
|
||||
spec = filter_properties.get('request_spec', {})
|
||||
props = spec.get('instance_properties', {})
|
||||
tenant_id = props.get('project_id')
|
||||
tenant_id = spec_obj.project_id
|
||||
|
||||
metadata = utils.aggregate_metadata_get_by_host(host_state,
|
||||
key="filter_tenant_id")
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
import mock
|
||||
|
||||
from nova import objects
|
||||
from nova.scheduler.filters import aggregate_image_properties_isolation as aipi
|
||||
from nova import test
|
||||
from nova.tests.unit.scheduler import fakes
|
||||
@ -25,83 +26,80 @@ class TestAggImagePropsIsolationFilter(test.NoDBTestCase):
|
||||
self.filt_cls = aipi.AggregateImagePropertiesIsolation()
|
||||
|
||||
def test_aggregate_image_properties_isolation_passes(self, agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'bar'}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm')))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_passes_comma(self, agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar,bar2'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'bar'}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm,xen'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm')))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_multi_props_passes(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar', 'foo2': 'bar2'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'bar',
|
||||
'foo2': 'bar2'}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm', 'hw_cpu_cores': '2'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm', hw_cpu_cores=2)))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_props_with_meta_passes(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps()))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_props_imgprops_passes(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'bar'}}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm')))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_props_not_match_fails(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'no-bar'}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='xen')))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_props_not_match2_fails(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'foo': 'bar', 'foo2': 'bar2'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'foo': 'bar',
|
||||
'foo2': 'bar3'}}}}
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm', 'hw_cpu_cores': '1'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm', hw_cpu_cores=2)))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_image_properties_isolation_props_namespace(self,
|
||||
agg_mock):
|
||||
self.flags(aggregate_image_properties_isolation_namespace="np")
|
||||
agg_mock.return_value = {'np.foo': 'bar', 'foo2': 'bar2'}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'image': {
|
||||
'properties': {'np.foo': 'bar',
|
||||
'foo2': 'bar3'}}}}
|
||||
self.flags(aggregate_image_properties_isolation_namespace="hw")
|
||||
self.flags(aggregate_image_properties_isolation_separator="_")
|
||||
agg_mock.return_value = {'hw_vm_mode': 'hvm', 'img_owner_id': 'foo'}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
image=objects.ImageMeta(properties=objects.ImageMetaProps(
|
||||
hw_vm_mode='hvm', img_owner_id='wrong')))
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
import mock
|
||||
|
||||
from nova import objects
|
||||
from nova.scheduler.filters import aggregate_instance_extra_specs as agg_specs
|
||||
from nova import test
|
||||
from nova.tests.unit.scheduler import fakes
|
||||
@ -27,28 +28,31 @@ class TestAggregateInstanceExtraSpecsFilter(test.NoDBTestCase):
|
||||
def test_aggregate_filter_passes_no_extra_specs(self, agg_mock):
|
||||
capabilities = {'opt1': 1, 'opt2': 2}
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx, 'instance_type':
|
||||
{'memory_mb': 1024}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
flavor=objects.Flavor(memory_mb=1024))
|
||||
host = fakes.FakeHostState('host1', 'node1', capabilities)
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
self.assertFalse(agg_mock.called)
|
||||
|
||||
def test_aggregate_filter_passes_empty_extra_specs(self, agg_mock):
|
||||
capabilities = {'opt1': 1, 'opt2': 2}
|
||||
|
||||
filter_properties = {'context': mock.sentinel.ctx, 'instance_type':
|
||||
{'memory_mb': 1024, 'extra_specs': {}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
flavor=objects.Flavor(memory_mb=1024, extra_specs={}))
|
||||
host = fakes.FakeHostState('host1', 'node1', capabilities)
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
self.assertFalse(agg_mock.called)
|
||||
|
||||
def _do_test_aggregate_filter_extra_specs(self, especs, passes):
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'instance_type': {'memory_mb': 1024, 'extra_specs': especs}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx,
|
||||
flavor=objects.Flavor(memory_mb=1024, extra_specs=especs))
|
||||
host = fakes.FakeHostState('host1', 'node1',
|
||||
{'free_ram_mb': 1024})
|
||||
assertion = self.assertTrue if passes else self.assertFalse
|
||||
assertion(self.filt_cls.host_passes(host, filter_properties))
|
||||
assertion(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_filter_passes_extra_specs_simple(self, agg_mock):
|
||||
agg_mock.return_value = {'opt1': '1', 'opt2': '2'}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
import mock
|
||||
|
||||
from nova import objects
|
||||
from nova.scheduler.filters import aggregate_multitenancy_isolation as ami
|
||||
from nova import test
|
||||
from nova.tests.unit.scheduler import fakes
|
||||
@ -27,48 +28,38 @@ class TestAggregateMultitenancyIsolationFilter(test.NoDBTestCase):
|
||||
def test_aggregate_multi_tenancy_isolation_with_meta_passes(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'filter_tenant_id': set(['my_tenantid'])}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'instance_properties': {
|
||||
'project_id': 'my_tenantid'}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx, project_id='my_tenantid')
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_multi_tenancy_isolation_with_meta_passes_comma(self,
|
||||
agg_mock):
|
||||
agg_mock.return_value = {'filter_tenant_id':
|
||||
set(['my_tenantid', 'mytenantid2'])}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'instance_properties': {
|
||||
'project_id': 'my_tenantid'}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx, project_id='my_tenantid')
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_multi_tenancy_isolation_fails(self, agg_mock):
|
||||
agg_mock.return_value = {'filter_tenant_id': set(['other_tenantid'])}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'instance_properties': {
|
||||
'project_id': 'my_tenantid'}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx, project_id='my_tenantid')
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_multi_tenancy_isolation_fails_comma(self, agg_mock):
|
||||
agg_mock.return_value = {'filter_tenant_id':
|
||||
set(['other_tenantid', 'other_tenantid2'])}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'instance_properties': {
|
||||
'project_id': 'my_tenantid'}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx, project_id='my_tenantid')
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertFalse(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertFalse(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
||||
def test_aggregate_multi_tenancy_isolation_no_meta_passes(self, agg_mock):
|
||||
agg_mock.return_value = {}
|
||||
filter_properties = {'context': mock.sentinel.ctx,
|
||||
'request_spec': {
|
||||
'instance_properties': {
|
||||
'project_id': 'my_tenantid'}}}
|
||||
spec_obj = objects.RequestSpec(
|
||||
context=mock.sentinel.ctx, project_id='my_tenantid')
|
||||
host = fakes.FakeHostState('host1', 'compute', {})
|
||||
self.assertTrue(self.filt_cls.host_passes(host, filter_properties))
|
||||
self.assertTrue(self.filt_cls.host_passes(host, spec_obj))
|
||||
|
Loading…
x
Reference in New Issue
Block a user