Extend RequestGroup object for mapping

This patch adds two new fields to the RequestGroup ovo, requester_id and
provider_uuids. These two fields are needed to be able to hold and
communicate the mapping between the requester of the RequestGroup (e.g.
Neutron port) and the resource providers that are fulfilling the request
(e.g. network device RPs). If the RequestGroup represents the un-numbered
group then more than one RP can fulfill the request hence provider_uuids
is a list.

These new fields later in the series will be populated based on some
logic in the nova-conductor. However in the long run we expect that
these fields will be populated from the Placement allocation
candidates response.

blueprint bandwidth-resource-provider

Change-Id: Ic4735f92542e5e0ca36b459874dc486f6b360317
This commit is contained in:
Balazs Gibizer
2018-11-20 12:54:28 +01:00
committed by Matt Riedemann
parent 03bc8b6a6b
commit b2a995f198
6 changed files with 54 additions and 6 deletions
+1
View File
@@ -1983,6 +1983,7 @@ class API(base_api.NetworkAPI):
resource_requests.append(
objects.RequestGroup.from_port_request(
context=None,
port_uuid=request_net.port_id,
port_resource_request=resource_request))
elif request_net.network_id and not request_net.auto_allocate:
+6
View File
@@ -1249,3 +1249,9 @@ class InstancePowerStateField(BaseEnumField):
class ListOfListsOfStringsField(fields.AutoTypedField):
AUTO_TYPE = List(List(fields.String()))
# TODO(mriedem): Replace this with the version from oslo.versiondobjects
# when https://review.openstack.org/#/c/634700/ is released.
class ListOfUUIDField(AutoTypedField):
AUTO_TYPE = List(fields.UUID())
+24 -3
View File
@@ -797,7 +797,9 @@ class RequestGroup(base.NovaObject):
"""Versioned object based on the unversioned
nova.api.openstack.placement.lib.RequestGroup object.
"""
VERSION = '1.0'
# Version 1.0: Initial version
# Version 1.1: add requester_id and provider_uuids fields
VERSION = '1.1'
fields = {
'use_same_provider': fields.BooleanField(default=True),
@@ -811,6 +813,13 @@ class RequestGroup(base.NovaObject):
# member of the aggregate aggregate_UUID1 and member of the aggregate
# aggregate_UUID2 or aggregate_UUID3 .
'aggregates': fields.ListOfListsOfStringsField(default=[]),
# The entity the request is coming from (e.g. the Neutron port uuid)
# which may not always be a UUID.
'requester_id': fields.StringField(nullable=True, default=None),
# The resource provider UUIDs that together fulfill the request
# NOTE(gibi): this can be more than one if this is the unnumbered
# request group (i.e. use_same_provider=False)
'provider_uuids': fields.ListOfUUIDField(default=[]),
}
def __init__(self, context=None, **kwargs):
@@ -818,10 +827,11 @@ class RequestGroup(base.NovaObject):
self.obj_set_defaults()
@classmethod
def from_port_request(cls, context, port_resource_request):
def from_port_request(cls, context, port_uuid, port_resource_request):
"""Init the group from the resource request of a neutron port
:param context: the request context
:param port_uuid: the port requesting the resources
:param port_resource_request: the resource_request attribute of the
neutron port
For example:
@@ -845,6 +855,17 @@ class RequestGroup(base.NovaObject):
use_same_provider=True,
resources=port_resource_request['resources'],
required_traits=set(port_resource_request.get(
'required', [])))
'required', [])),
requester_id=port_uuid)
obj.obj_set_defaults()
return obj
def obj_make_compatible(self, primitive, target_version):
super(RequestGroup, self).obj_make_compatible(
primitive, target_version)
target_version = versionutils.convert_version_to_tuple(target_version)
if target_version < (1, 1):
if 'requester_id' in primitive:
del primitive['requester_id']
if 'provider_uuids' in primitive:
del primitive['provider_uuids']
@@ -5325,9 +5325,11 @@ class TestNeutronv2WithMock(_TestNeutronv2Common):
mock_request_spec.assert_has_calls([
mock.call(
context=None,
port_uuid=uuids.portid_2,
port_resource_request=mock.sentinel.resource_request1),
mock.call(
context=None,
port_uuid=uuids.trusted_port,
port_resource_request=mock.sentinel.resource_request2),
])
+1 -1
View File
@@ -1142,7 +1142,7 @@ object_data = {
'PowerVMLiveMigrateData': '1.4-a745f4eda16b45e1bc5686a0c498f27e',
'Quotas': '1.3-40fcefe522111dddd3e5e6155702cf4e',
'QuotasNoOp': '1.3-347a039fc7cfee7b225b68b5181e0733',
'RequestGroup': '1.0-5f694d4237c00c7b01136a4e4bcacd6d',
'RequestGroup': '1.1-5a330f65df2d91356b1da19f10540ec8',
'RequestSpec': '1.12-25010470f219af9b6163f2a457a513f5',
'S3ImageMapping': '1.0-7dd7366a890d82660ed121de9092276e',
'SchedulerLimits': '1.0-249c4bd8e62a9b327b7026b7f19cc641',
+20 -2
View File
@@ -854,6 +854,8 @@ class TestRequestGroupObject(test.TestCase):
self.assertEqual(set(), rg.required_traits)
self.assertEqual(set(), rg.forbidden_traits)
self.assertEqual([], rg.aggregates)
self.assertIsNone(None, rg.requester_id)
self.assertEqual([], rg.provider_uuids)
def test_from_port_request(self):
port_resource_request = {
@@ -864,7 +866,7 @@ class TestRequestGroupObject(test.TestCase):
"CUSTOM_VNIC_TYPE_NORMAL"]
}
rg = request_spec.RequestGroup.from_port_request(
self.context, port_resource_request)
self.context, uuids.port_id, port_resource_request)
self.assertTrue(rg.use_same_provider)
self.assertEqual(
@@ -873,9 +875,11 @@ class TestRequestGroupObject(test.TestCase):
rg.resources)
self.assertEqual({"CUSTOM_PHYSNET_2", "CUSTOM_VNIC_TYPE_NORMAL"},
rg.required_traits)
self.assertEqual(uuids.port_id, rg.requester_id)
# and the rest is defaulted
self.assertEqual(set(), rg.forbidden_traits)
self.assertEqual([], rg.aggregates)
self.assertEqual([], rg.provider_uuids)
def test_from_port_request_without_traits(self):
port_resource_request = {
@@ -883,14 +887,28 @@ class TestRequestGroupObject(test.TestCase):
"NET_BW_IGR_KILOBIT_PER_SEC": 1000,
"NET_BW_EGR_KILOBIT_PER_SEC": 1000}}
rg = request_spec.RequestGroup.from_port_request(
self.context, port_resource_request)
self.context, uuids.port_id, port_resource_request)
self.assertTrue(rg.use_same_provider)
self.assertEqual(
{"NET_BW_IGR_KILOBIT_PER_SEC": 1000,
"NET_BW_EGR_KILOBIT_PER_SEC": 1000},
rg.resources)
self.assertEqual(uuids.port_id, rg.requester_id)
# and the rest is defaulted
self.assertEqual(set(), rg.required_traits)
self.assertEqual(set(), rg.forbidden_traits)
self.assertEqual([], rg.aggregates)
self.assertEqual([], rg.provider_uuids)
def test_compat_requester_and_provider(self):
req_obj = objects.RequestGroup(
requester_id=uuids.requester, provider_uuids=[uuids.rp1],
required_traits=set(['CUSTOM_PHYSNET_2']))
versions = ovo_base.obj_tree_get_versions('RequestGroup')
primitive = req_obj.obj_to_primitive(
target_version='1.0',
version_manifest=versions)['nova_object.data']
self.assertNotIn('requester_id', primitive)
self.assertNotIn('provider_uuids', primitive)
self.assertIn('required_traits', primitive)