mirror of
https://github.com/gryf/openstack.git
synced 2025-12-17 11:30:24 +01:00
Added another portion of Jay patches backported to Ocata
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
From 1374f28766d56361b9342d77a32c0e52034060f1 Mon Sep 17 00:00:00 2001
|
||||
From: Roman Dobosz <roman.dobosz@intel.com>
|
||||
Date: Wed, 10 Jan 2018 10:37:54 +0100
|
||||
Subject: [PATCH 3/3] get instance group's aggregate associations
|
||||
|
||||
Ocata backport for patch from Jay Pipes:
|
||||
https://review.openstack.org/#/c/531243/
|
||||
---
|
||||
nova/objects/instance_group.py | 36 +++++++-
|
||||
nova/tests/functional/db/test_instance_group.py | 112 ++++++++++++++++++++++++
|
||||
nova/tests/unit/objects/test_instance_group.py | 21 +++++
|
||||
nova/tests/unit/objects/test_objects.py | 2 +-
|
||||
4 files changed, 169 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/nova/objects/instance_group.py b/nova/objects/instance_group.py
|
||||
index 670813b77e..2be47278b2 100644
|
||||
--- a/nova/objects/instance_group.py
|
||||
+++ b/nova/objects/instance_group.py
|
||||
@@ -17,6 +17,7 @@ import copy
|
||||
from oslo_db import exception as db_exc
|
||||
from oslo_utils import uuidutils
|
||||
from oslo_utils import versionutils
|
||||
+import sqlalchemy as sa
|
||||
from sqlalchemy.orm import contains_eager
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
@@ -122,7 +123,8 @@ class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
|
||||
# Version 1.8: Add count_members_by_user()
|
||||
# Version 1.9: Add get_by_instance_uuid()
|
||||
# Version 1.10: Add hosts field
|
||||
- VERSION = '1.10'
|
||||
+ # Version 1.11: Add get_aggregate_uuids()
|
||||
+ VERSION = '1.11'
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
@@ -455,6 +457,38 @@ class InstanceGroup(base.NovaPersistentObject, base.NovaObject,
|
||||
if instance.host]))
|
||||
|
||||
@base.remotable
|
||||
+ def get_aggregate_uuids(self, exclude=None):
|
||||
+ """Returns a set of aggregate UUIDs associated with all compute nodes
|
||||
+ that are housing all non-deleted instances in the group
|
||||
+ """
|
||||
+ 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)
|
||||
+ instance_nodes = set([instance.node for instance in instances
|
||||
+ if instance.node])
|
||||
+ if not instance_nodes:
|
||||
+ return set()
|
||||
+ return self._get_aggregate_uuids(self._context, instance_nodes)
|
||||
+
|
||||
+ @staticmethod
|
||||
+ @db_api.api_context_manager.reader
|
||||
+ def _get_aggregate_uuids(ctx, instance_nodes):
|
||||
+ # Now find the aggregates associated with all those nodes
|
||||
+ agg_tbl = api_models.Aggregate.__table__
|
||||
+ agg_host_tbl = api_models.AggregateHost.__table__
|
||||
+ join = sa.join(agg_tbl, agg_host_tbl,
|
||||
+ agg_tbl.c.id == agg_host_tbl.c.aggregate_id)
|
||||
+ sel = sa.select([agg_tbl.c.uuid]).select_from(join)
|
||||
+ sel = sel.where(agg_host_tbl.c.host.in_(instance_nodes))
|
||||
+ sel = sel.group_by(agg_tbl.c.uuid)
|
||||
+ res = ctx.session.execute(sel)
|
||||
+ agg_uuids = [r[0] for r in res]
|
||||
+ return set(agg_uuids)
|
||||
+
|
||||
+ @base.remotable
|
||||
def count_members_by_user(self, user_id):
|
||||
"""Count the number of instances in a group belonging to a user."""
|
||||
filter_uuids = self.members
|
||||
diff --git a/nova/tests/functional/db/test_instance_group.py b/nova/tests/functional/db/test_instance_group.py
|
||||
index 4c4f627fe2..445ae655cc 100644
|
||||
--- a/nova/tests/functional/db/test_instance_group.py
|
||||
+++ b/nova/tests/functional/db/test_instance_group.py
|
||||
@@ -18,6 +18,7 @@ from nova.db.sqlalchemy import api as db_api
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.objects import base
|
||||
+from nova.objects import fields as obj_fields
|
||||
from nova.objects import instance_group
|
||||
from nova import test
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
@@ -238,3 +239,114 @@ class InstanceGroupObjectTestCase(test.TestCase):
|
||||
self.context, 100)
|
||||
self.assertEqual(0, total)
|
||||
self.assertEqual(0, done)
|
||||
+
|
||||
+
|
||||
+class InstanceGroupAggregatesTestCase(test.TestCase):
|
||||
+ def setUp(self):
|
||||
+ super(InstanceGroupAggregatesTestCase, self).setUp()
|
||||
+ self.ctx = context.RequestContext('fake-user', 'fake-project')
|
||||
+
|
||||
+ def _create_compute_node(self, host, node):
|
||||
+ cn = objects.ComputeNode(
|
||||
+ self.ctx,
|
||||
+ host=host,
|
||||
+ vcpus=2,
|
||||
+ memory_mb=2048,
|
||||
+ local_gb=100,
|
||||
+ vcpus_used=2,
|
||||
+ memory_mb_used=2048,
|
||||
+ local_gb_used=100,
|
||||
+ hypervisor_type='ironic',
|
||||
+ hypervisor_version=0,
|
||||
+ hypervisor_hostname=node,
|
||||
+ free_ram_mb=0,
|
||||
+ free_disk_gb=0,
|
||||
+ current_workload=0,
|
||||
+ running_vms=0,
|
||||
+ cpu_info='{}',
|
||||
+ disk_available_least=0,
|
||||
+ host_ip='1.1.1.1',
|
||||
+ supported_hv_specs=[
|
||||
+ objects.HVSpec.from_list([
|
||||
+ obj_fields.Architecture.I686,
|
||||
+ obj_fields.HVType.KVM,
|
||||
+ obj_fields.VMMode.HVM])
|
||||
+ ],
|
||||
+ metrics=None,
|
||||
+ pci_device_pools=None,
|
||||
+ extra_resources=None,
|
||||
+ stats={},
|
||||
+ numa_topology=None,
|
||||
+ cpu_allocation_ratio=1.0,
|
||||
+ ram_allocation_ratio=1.0,
|
||||
+ disk_allocation_ratio=1.0)
|
||||
+ cn.create()
|
||||
+ return cn
|
||||
+
|
||||
+ def test_get_aggregate_uuids(self):
|
||||
+ """Tests that when associating compute nodes to aggregates, and
|
||||
+ creating an instance group with instances on those compute nodes, that
|
||||
+ we are able to retrieve the correct set() of aggregate UUIDs from the
|
||||
+ instance group.
|
||||
+ """
|
||||
+ agg1 = objects.Aggregate(self.ctx, name='agg1')
|
||||
+ agg1.create()
|
||||
+ agg2 = objects.Aggregate(self.ctx, name='agg2')
|
||||
+ agg2.create()
|
||||
+
|
||||
+ # NOTE(gryf): creating bare instances doesn't propagate project_id
|
||||
+ # for some reason, so that test would fail.
|
||||
+ i1 = objects.Instance(self.ctx, host='host1', node='node1',
|
||||
+ project_id=self.ctx.project_id)
|
||||
+ i1.create()
|
||||
+ i2 = objects.Instance(self.ctx, host='host1', node='node2',
|
||||
+ project_id=self.ctx.project_id)
|
||||
+ i2.create()
|
||||
+ i3 = objects.Instance(self.ctx, host='host2', node='node3',
|
||||
+ project_id=self.ctx.project_id)
|
||||
+ i3.create()
|
||||
+
|
||||
+ all_insts = objects.InstanceList.get_all(self.ctx)
|
||||
+ exp_inst_uuids = set([i1.uuid, i2.uuid, i3.uuid])
|
||||
+ self.assertEqual(exp_inst_uuids,
|
||||
+ set([inst.uuid for inst in all_insts]))
|
||||
+
|
||||
+ # Create a server group with just i1 and i2 and verify no aggregate
|
||||
+ # UUIDs returned from InstanceGroup.get_aggregate_uuids() since the
|
||||
+ # compute nodes have not yet been associated with any aggregates
|
||||
+ g1 = objects.InstanceGroup(self.ctx,
|
||||
+ name='g1',
|
||||
+ user_id=self.ctx.user_id,
|
||||
+ project_id=self.ctx.project_id,
|
||||
+ members=[i1.uuid, i2.uuid],
|
||||
+ policies=['aggregate-affinity'])
|
||||
+ g1.create()
|
||||
+
|
||||
+ # Create a server group with just i1 and i2 and verify no aggregate
|
||||
+ # UUIDs returned from InstanceGroup.get_aggregate_uuids() since the
|
||||
+ # compute nodes have not yet been associated with any aggregates
|
||||
+ g2 = objects.InstanceGroup(self.ctx,
|
||||
+ name='g2',
|
||||
+ user_id=self.ctx.user_id,
|
||||
+ project_id=self.ctx.project_id,
|
||||
+ members=[i3.uuid],
|
||||
+ policies=['aggregate-anti-affinity'])
|
||||
+
|
||||
+ g1_agg_uuids = g1.get_aggregate_uuids()
|
||||
+ self.assertEqual(set(), g1_agg_uuids)
|
||||
+
|
||||
+ g2_agg_uuids = g2.get_aggregate_uuids()
|
||||
+ self.assertEqual(set(), g2_agg_uuids)
|
||||
+
|
||||
+ # OK, now associate the compute nodes with various aggregates and
|
||||
+ # verify the aggregate UUIDs returned by each instance group is
|
||||
+ # correct.
|
||||
+ agg1.add_host('node1')
|
||||
+ agg1.add_host('node2')
|
||||
+ agg2.add_host('node3')
|
||||
+
|
||||
+ g1_agg_uuids = g1.get_aggregate_uuids()
|
||||
+ self.assertEqual(set([agg1.uuid]), g1_agg_uuids)
|
||||
+
|
||||
+ g2_agg_uuids = g2.get_aggregate_uuids()
|
||||
+ self.assertEqual(set([agg2.uuid]), g2_agg_uuids)
|
||||
diff --git a/nova/tests/unit/objects/test_instance_group.py b/nova/tests/unit/objects/test_instance_group.py
|
||||
index d542c18afc..8da6712f6e 100644
|
||||
--- a/nova/tests/unit/objects/test_instance_group.py
|
||||
+++ b/nova/tests/unit/objects/test_instance_group.py
|
||||
@@ -241,6 +241,27 @@ class _TestInstanceGroupObject(object):
|
||||
mock_il_get.assert_called_once_with(self.context,
|
||||
filters=expected_filters)
|
||||
|
||||
+ @mock.patch('nova.objects.InstanceGroup._get_aggregate_uuids')
|
||||
+ @mock.patch('nova.objects.InstanceList.get_by_filters')
|
||||
+ @mock.patch('nova.objects.InstanceGroup._get_from_db_by_uuid',
|
||||
+ return_value=_INST_GROUP_DB)
|
||||
+ def test_get_aggregate_uuids(self, mock_get_db, mock_il_get,
|
||||
+ mock_internal):
|
||||
+ mock_il_get.return_value = [objects.Instance(node='node1'),
|
||||
+ objects.Instance(node='node2'),
|
||||
+ objects.Instance(node=None)]
|
||||
+ obj = objects.InstanceGroup.get_by_uuid(self.context, _DB_UUID)
|
||||
+ obj.get_aggregate_uuids()
|
||||
+ self.assertEqual(['instance_id1', 'instance_id2'], obj.members)
|
||||
+ expected_filters = {
|
||||
+ 'uuid': ['instance_id1', 'instance_id2'],
|
||||
+ 'deleted': False
|
||||
+ }
|
||||
+ mock_il_get.assert_called_once_with(self.context,
|
||||
+ filters=expected_filters)
|
||||
+ exp_nodes = set(['node1', 'node2'])
|
||||
+ mock_internal.assert_called_once_with(self.context, exp_nodes)
|
||||
+
|
||||
def test_obj_make_compatible(self):
|
||||
obj = objects.InstanceGroup(self.context, **_INST_GROUP_DB)
|
||||
obj_primitive = obj.obj_to_primitive()
|
||||
diff --git a/nova/tests/unit/objects/test_objects.py b/nova/tests/unit/objects/test_objects.py
|
||||
index 71b919597f..a577820d0c 100644
|
||||
--- a/nova/tests/unit/objects/test_objects.py
|
||||
+++ b/nova/tests/unit/objects/test_objects.py
|
||||
@@ -1106,7 +1106,7 @@ object_data = {
|
||||
'InstanceExternalEvent': '1.1-6e446ceaae5f475ead255946dd443417',
|
||||
'InstanceFault': '1.2-7ef01f16f1084ad1304a513d6d410a38',
|
||||
'InstanceFaultList': '1.2-6bb72de2872fe49ded5eb937a93f2451',
|
||||
- 'InstanceGroup': '1.10-1a0c8c7447dc7ecb9da53849430c4a5f',
|
||||
+ 'InstanceGroup': '1.11-bdd9fa6ab3c80e92fd43b3ba5393e368',
|
||||
'InstanceGroupList': '1.7-be18078220513316abd0ae1b2d916873',
|
||||
'InstanceInfoCache': '1.5-cd8b96fefe0fc8d4d337243ba0bf0e1e',
|
||||
'InstanceList': '2.2-ff71772c7bf6d72f6ef6eee0199fb1c9',
|
||||
--
|
||||
2.13.6
|
||||
|
||||
Reference in New Issue
Block a user