I happened upon this while hacking on my WIP CellDatabases fixture patch. Some of the nova/tests/functional/test_server_group.py tests started failing with multiple cells and I found that it's because there's a database query objects.InstanceList.get_by_filters for all instances who are members of the server group, every time the ServerGroup[Anti|]AffinityFilter runs. The query for instances doesn't check all cells, so it fails to return any hosts that group members are currently on.
This makes the ServerGroup[Anti|]AffinityFilter a no-op for multiple cells. Affinity *is* however ultimately checked via the late-affinity check in compute, so affinity is not totally broken for multiple cells.
Aside from that, I would expect the database query to noticeably degrade performance of scheduling if the ServerGroup[Anti|]AffinityFilter is in enabled_filters, for both the single cell and multiple cell cases.
To fix this, I expect we'll need to pre-load RequestSpec.instance_group.hosts before we schedule each instance -- and make sure we query all cells for the instances. I'm not sure what special consideration we might need for multi-create.
This is the code that lazy-loads instance_group.hosts, which in turn calls InstanceGroup.get_hosts, which calls InstanceList.get_by_filters without targeting any cells:
nova/scheduler/filters/affinity_filter.py:
group_hosts = (spec_obj.instance_group.hosts if spec_obj.instance_group else [])
@base.remotable
def get_hosts(self, exclude=None):
"""Get a list of hosts for non-deleted instances in the group
This method allows you to get a list of the hosts where instances in
this group are currently running. There's also an option to exclude
certain instance UUIDs from this calculation.
""" filter_uuids = self.members
if exclude: filter_uuids = set(filter_uuids) - set(exclude)
filters = {'uuid': filter_uuids, 'deleted': False}
instances = objects.InstanceList.get_by_filters(self._context, filters=filters)
return list(set([instance.host for instance in instances if instance.host]))
I happened upon this while hacking on my WIP CellDatabases fixture patch. Some of the nova/tests/ functional/ test_server_ group.py tests started failing with multiple cells and I found that it's because there's a database query objects. InstanceList. get_by_ filters for all instances who are members of the server group, every time the ServerGroup[ Anti|]AffinityF ilter runs. The query for instances doesn't check all cells, so it fails to return any hosts that group members are currently on.
This makes the ServerGroup[ Anti|]AffinityF ilter a no-op for multiple cells. Affinity *is* however ultimately checked via the late-affinity check in compute, so affinity is not totally broken for multiple cells.
Aside from that, I would expect the database query to noticeably degrade performance of scheduling if the ServerGroup[ Anti|]AffinityF ilter is in enabled_filters, for both the single cell and multiple cell cases.
To fix this, I expect we'll need to pre-load RequestSpec. instance_ group.hosts before we schedule each instance -- and make sure we query all cells for the instances. I'm not sure what special consideration we might need for multi-create.
This is the code that lazy-loads instance_ group.hosts, which in turn calls InstanceGroup. get_hosts, which calls InstanceList. get_by_ filters without targeting any cells:
nova/scheduler/ filters/ affinity_ filter. py:
group_hosts = (spec_obj. instance_ group.hosts
if spec_obj. instance_ group else [])
nova/objects/ instance_ group.py:
def obj_load_attr(self, attrname):
self.obj_ reset_changes( ['hosts' ])
...
self.hosts = self.get_hosts()
...
@base.remotable
filter_ uuids = self.members
filter_ uuids = set(filter_uuids) - set(exclude) InstanceList. get_by_ filters( self._context,
filters= filters) [instance. host for instance in instances
if instance.host]))
def get_hosts(self, exclude=None):
"""Get a list of hosts for non-deleted instances in the group
This method allows you to get a list of the hosts where instances in
this group are currently running. There's also an option to exclude
certain instance UUIDs from this calculation.
"""
if exclude:
filters = {'uuid': filter_uuids, 'deleted': False}
instances = objects.
return list(set(