Use ksa adapter for placement conf & requests

Switch usage of the placement API over to using the new
nova.utils.get_ksa_adapter method.  Now REST calls with the placement
API go through the resulting keystoneauth1 Adapter - which already
incorporates endpoint filtering - rather than a keystoneauth1 Session.

To make this fit, switch the placement conf over to using
nova.conf.utils.register_ksa_opts and get_ksa_adapter_opts.  In so
doing, deprecate os_interface and os_region_name in favor of the
imported Adapter opts valid_interfaces and region_name, respectively.

Change-Id: I69e9b30d96390a70198b12d74e7efa9bd61db217
Partial-Implements: bp use-ksa-adapter-for-endpoints
This commit is contained in:
Eric Fried 2017-08-09 15:09:14 -05:00 committed by Matt Riedemann
parent 8352d555a5
commit 987d451f4d
8 changed files with 203 additions and 234 deletions

View File

@ -26,7 +26,6 @@ import textwrap
import traceback import traceback
from keystoneauth1 import exceptions as ks_exc from keystoneauth1 import exceptions as ks_exc
from keystoneauth1 import loading as keystone
from oslo_config import cfg from oslo_config import cfg
import pkg_resources import pkg_resources
import prettytable import prettytable
@ -41,6 +40,7 @@ from nova.db.sqlalchemy import api as db_session
from nova.i18n import _ from nova.i18n import _
from nova.objects import cell_mapping as cell_mapping_obj from nova.objects import cell_mapping as cell_mapping_obj
from nova.objects import fields from nova.objects import fields
from nova import utils
from nova import version from nova import version
CONF = nova.conf.CONF CONF = nova.conf.CONF
@ -174,22 +174,16 @@ class UpgradeCommands(object):
return UpgradeCheckResult(UpgradeCheckCode.SUCCESS) return UpgradeCheckResult(UpgradeCheckCode.SUCCESS)
def _placement_get(self, path): @staticmethod
def _placement_get(path):
"""Do an HTTP get call against placement engine. """Do an HTTP get call against placement engine.
This is in a dedicated method to make it easier for unit This is in a dedicated method to make it easier for unit
testing purposes. testing purposes.
""" """
ks_filter = {'service_type': 'placement', client = utils.get_ksa_adapter('placement')
'region_name': CONF.placement.os_region_name, return client.get(path).json()
'interface': CONF.placement.os_interface}
auth = keystone.load_auth_from_conf_options(
CONF, 'placement')
client = keystone.load_session_from_conf_options(
CONF, 'placement', auth=auth)
return client.get(path, endpoint_filter=ks_filter).json()
def _check_placement(self): def _check_placement(self):
"""Checks to see if the placement API is ready for scheduling. """Checks to see if the placement API is ready for scheduling.
@ -198,6 +192,7 @@ class UpgradeCommands(object):
service catalog and that we can make requests against it. service catalog and that we can make requests against it.
""" """
try: try:
# TODO(efried): Use ksa's version filtering in _placement_get
versions = self._placement_get("/") versions = self._placement_get("/")
max_version = pkg_resources.parse_version( max_version = pkg_resources.parse_version(
versions["versions"][0]["max_version"]) versions["versions"][0]["max_version"])

View File

@ -13,14 +13,25 @@
from keystoneauth1 import loading as ks_loading from keystoneauth1 import loading as ks_loading
from oslo_config import cfg from oslo_config import cfg
from nova.conf import utils as confutils
DEFAULT_SERVICE_TYPE = 'placement'
placement_group = cfg.OptGroup( placement_group = cfg.OptGroup(
'placement', 'placement',
title='Placement Service Options', title='Placement Service Options',
help="Configuration options for connecting to the placement API service") help="Configuration options for connecting to the placement API service")
placement_opts = [ placement_opts = [
cfg.StrOpt('os_region_name', cfg.StrOpt(
help=""" 'os_region_name',
deprecated_for_removal=True,
deprecated_since='17.0.0',
deprecated_reason='Endpoint lookup uses the service catalog via '
'common keystoneauth1 Adapter configuration '
'options. Use the region_name option instead.',
help="""
Region name of this node. This is used when picking the URL in the service Region name of this node. This is used when picking the URL in the service
catalog. catalog.
@ -28,19 +39,32 @@ Possible values:
* Any string representing region name * Any string representing region name
"""), """),
cfg.StrOpt('os_interface', cfg.StrOpt(
help=""" 'os_interface',
deprecated_for_removal=True,
deprecated_since='17.0.0',
deprecated_reason='Endpoint lookup uses the service catalog via '
'common keystoneauth1 Adapter configuration '
'options. Use the valid_interfaces option instead.',
help="""
Endpoint interface for this node. This is used when picking the URL in the Endpoint interface for this node. This is used when picking the URL in the
service catalog. service catalog.
""") """)
] ]
deprecated_opts = {
'region_name': [cfg.DeprecatedOpt('os_region_name',
group=placement_group.name)],
'valid_interfaces': [cfg.DeprecatedOpt('os_interface',
group=placement_group.name)]
}
def register_opts(conf): def register_opts(conf):
conf.register_group(placement_group) conf.register_group(placement_group)
conf.register_opts(placement_opts, group=placement_group) conf.register_opts(placement_opts, group=placement_group)
ks_loading.register_session_conf_options(conf, placement_group.name) confutils.register_ksa_opts(conf, placement_group, DEFAULT_SERVICE_TYPE,
ks_loading.register_auth_conf_options(conf, placement_group.name) deprecated_opts=deprecated_opts)
def list_opts(): def list_opts():
@ -51,5 +75,7 @@ def list_opts():
ks_loading.get_auth_common_conf_options() + ks_loading.get_auth_common_conf_options() +
ks_loading.get_auth_plugin_conf_options('password') + ks_loading.get_auth_plugin_conf_options('password') +
ks_loading.get_auth_plugin_conf_options('v2password') + ks_loading.get_auth_plugin_conf_options('v2password') +
ks_loading.get_auth_plugin_conf_options('v3password')) ks_loading.get_auth_plugin_conf_options('v3password') +
confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE,
deprecated_opts=deprecated_opts))
} }

View File

@ -19,7 +19,6 @@ import re
import time import time
from keystoneauth1 import exceptions as ks_exc from keystoneauth1 import exceptions as ks_exc
from keystoneauth1 import loading as keystone
from oslo_log import log as logging from oslo_log import log as logging
from six.moves.urllib import parse from six.moves.urllib import parse
@ -246,9 +245,6 @@ class SchedulerReportClient(object):
self._client = self._create_client() self._client = self._create_client()
# NOTE(danms): Keep track of how naggy we've been # NOTE(danms): Keep track of how naggy we've been
self._warn_count = 0 self._warn_count = 0
self.ks_filter = {'service_type': 'placement',
'region_name': CONF.placement.os_region_name,
'interface': CONF.placement.os_interface}
@utils.synchronized(PLACEMENT_CLIENT_SEMAPHORE) @utils.synchronized(PLACEMENT_CLIENT_SEMAPHORE)
def _create_client(self): def _create_client(self):
@ -257,73 +253,36 @@ class SchedulerReportClient(object):
self._provider_tree = provider_tree.ProviderTree() self._provider_tree = provider_tree.ProviderTree()
self._provider_aggregate_map = {} self._provider_aggregate_map = {}
self.aggregate_refresh_time = {} self.aggregate_refresh_time = {}
auth_plugin = keystone.load_auth_from_conf_options( # TODO(mriedem): Perform some version discovery at some point.
CONF, 'placement') client = utils.get_ksa_adapter('placement')
return keystone.load_session_from_conf_options( # Set accept header on every request to ensure we notify placement
CONF, 'placement', auth=auth_plugin, # service of our response body media type preferences.
additional_headers={'accept': 'application/json'}) client.additional_headers = {'accept': 'application/json'}
return client
def get(self, url, version=None): def get(self, url, version=None):
kwargs = {} return self._client.get(url, raise_exc=False, microversion=version)
if version is not None:
# TODO(mriedem): Perform some version discovery at some point.
kwargs = {
'headers': {
'OpenStack-API-Version': 'placement %s' % version
},
}
return self._client.get(
url,
endpoint_filter=self.ks_filter, raise_exc=False, **kwargs)
def post(self, url, data, version=None): def post(self, url, data, version=None):
# NOTE(sdague): using json= instead of data= sets the # NOTE(sdague): using json= instead of data= sets the
# media type to application/json for us. Placement API is # media type to application/json for us. Placement API is
# more sensitive to this than other APIs in the OpenStack # more sensitive to this than other APIs in the OpenStack
# ecosystem. # ecosystem.
kwargs = {} return self._client.post(url, json=data, raise_exc=False,
if version is not None: microversion=version)
# TODO(mriedem): Perform some version discovery at some point.
kwargs = {
'headers': {
'OpenStack-API-Version': 'placement %s' % version
},
}
return self._client.post(
url, json=data,
endpoint_filter=self.ks_filter, raise_exc=False, **kwargs)
def put(self, url, data, version=None): def put(self, url, data, version=None):
# NOTE(sdague): using json= instead of data= sets the # NOTE(sdague): using json= instead of data= sets the
# media type to application/json for us. Placement API is # media type to application/json for us. Placement API is
# more sensitive to this than other APIs in the OpenStack # more sensitive to this than other APIs in the OpenStack
# ecosystem. # ecosystem.
kwargs = {} kwargs = {'microversion': version}
if version is not None:
# TODO(mriedem): Perform some version discovery at some point.
kwargs = {
'headers': {
'OpenStack-API-Version': 'placement %s' % version
},
}
if data: if data:
kwargs['json'] = data kwargs['json'] = data
return self._client.put( return self._client.put(url, raise_exc=False, **kwargs)
url, endpoint_filter=self.ks_filter, raise_exc=False,
**kwargs)
def delete(self, url, version=None): def delete(self, url, version=None):
kwargs = {} return self._client.delete(url, raise_exc=False, microversion=version)
if version is not None:
# TODO(mriedem): Perform some version discovery at some point.
kwargs = {
'headers': {
'OpenStack-API-Version': 'placement %s' % version
},
}
return self._client.delete(
url,
endpoint_filter=self.ks_filter, raise_exc=False, **kwargs)
@safe_connect @safe_connect
def get_allocation_candidates(self, resources): def get_allocation_candidates(self, resources):

View File

@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from keystoneauth1 import adapter
from keystoneauth1 import session from keystoneauth1 import session
import mock import mock
import requests import requests
@ -41,11 +42,10 @@ class NoAuthReportClient(report.SchedulerReportClient):
'x-auth-token': 'admin', 'x-auth-token': 'admin',
'OpenStack-API-Version': 'placement latest', 'OpenStack-API-Version': 'placement latest',
} }
self._client = session.Session( self._client = adapter.Adapter(
auth=None, session.Session(auth=None, session=request_session,
session=request_session, additional_headers=headers),
additional_headers=headers, service_type='placement')
)
class SchedulerReportClientTests(test.TestCase): class SchedulerReportClientTests(test.TestCase):

View File

@ -123,34 +123,33 @@ class TestPlacementCheck(test.NoDBTestCase):
self.assertIn('No credentials specified', res.details) self.assertIn('No credentials specified', res.details)
@mock.patch.object(keystone, "load_auth_from_conf_options") @mock.patch.object(keystone, "load_auth_from_conf_options")
@mock.patch.object(session.Session, 'get') @mock.patch.object(session.Session, 'request')
def _test_placement_get_interface( def _test_placement_get_interface(
self, expected_interface, mock_get, mock_auth): self, expected_interface, mock_get, mock_auth):
def fake_get(path, *a, **kw): def fake_request(path, method, *a, **kw):
self.assertEqual(mock.sentinel.path, path) self.assertEqual(mock.sentinel.path, path)
self.assertEqual('GET', method)
self.assertIn('endpoint_filter', kw) self.assertIn('endpoint_filter', kw)
self.assertEqual(expected_interface, self.assertEqual(expected_interface,
kw['endpoint_filter']['interface']) kw['endpoint_filter']['interface'])
return mock.Mock(autospec='requests.models.Response') return mock.Mock(autospec='requests.models.Response')
mock_get.side_effect = fake_get mock_get.side_effect = fake_request
self.cmd._placement_get(mock.sentinel.path) self.cmd._placement_get(mock.sentinel.path)
mock_auth.assert_called_once_with(status.CONF, 'placement') mock_auth.assert_called_once_with(status.CONF, 'placement')
self.assertTrue(mock_get.called) self.assertTrue(mock_get.called)
@mock.patch.object(keystone, "load_auth_from_conf_options") def test_placement_get_interface_default(self):
@mock.patch.object(session.Session, 'get') """Tests that we try internal, then public interface by default."""
def test_placement_get_interface_default(self, mock_get, mock_auth): self._test_placement_get_interface(['internal', 'public'])
"""Tests that None is specified for interface by default."""
self._test_placement_get_interface(None)
@mock.patch.object(keystone, "load_auth_from_conf_options") def test_placement_get_interface_internal(self):
@mock.patch.object(session.Session, 'get')
def test_placement_get_interface_internal(self, mock_get, mock_auth):
"""Tests that "internal" is specified for interface when configured.""" """Tests that "internal" is specified for interface when configured."""
self.flags(os_interface='internal', group='placement') # TODO(efried): Test that the deprecated opts (e.g. os_interface) still
self._test_placement_get_interface('internal') # work once bug #1709728 is resolved.
self.flags(valid_interfaces='internal', group='placement')
self._test_placement_get_interface(['internal'])
@mock.patch.object(status.UpgradeCommands, "_placement_get") @mock.patch.object(status.UpgradeCommands, "_placement_get")
def test_invalid_auth(self, get): def test_invalid_auth(self, get):

View File

@ -36,11 +36,8 @@ class SafeConnectedTestCase(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(SafeConnectedTestCase, self).setUp() super(SafeConnectedTestCase, self).setUp()
self.context = context.get_admin_context() self.context = context.get_admin_context()
self.ks_sess_mock = mock.Mock()
with test.nested( with mock.patch('keystoneauth1.loading.load_auth_from_conf_options'):
mock.patch('keystoneauth1.loading.load_auth_from_conf_options')
) as _auth_mock: # noqa
self.client = report.SchedulerReportClient() self.client = report.SchedulerReportClient()
@mock.patch('keystoneauth1.session.Session.request') @mock.patch('keystoneauth1.session.Session.request')
@ -157,21 +154,23 @@ class TestConstructor(test.NoDBTestCase):
load_auth_mock.assert_called_once_with(CONF, 'placement') load_auth_mock.assert_called_once_with(CONF, 'placement')
load_sess_mock.assert_called_once_with(CONF, 'placement', load_sess_mock.assert_called_once_with(CONF, 'placement',
additional_headers={'accept': 'application/json'}, auth=load_auth_mock.return_value)
auth=load_auth_mock.return_value) self.assertEqual(['internal', 'public'], client._client.interface)
self.assertIsNone(client.ks_filter['interface']) self.assertEqual({'accept': 'application/json'},
client._client.additional_headers)
@mock.patch('keystoneauth1.loading.load_session_from_conf_options') @mock.patch('keystoneauth1.loading.load_session_from_conf_options')
@mock.patch('keystoneauth1.loading.load_auth_from_conf_options') @mock.patch('keystoneauth1.loading.load_auth_from_conf_options')
def test_constructor_admin_interface(self, load_auth_mock, load_sess_mock): def test_constructor_admin_interface(self, load_auth_mock, load_sess_mock):
self.flags(os_interface='admin', group='placement') self.flags(valid_interfaces='admin', group='placement')
client = report.SchedulerReportClient() client = report.SchedulerReportClient()
load_auth_mock.assert_called_once_with(CONF, 'placement') load_auth_mock.assert_called_once_with(CONF, 'placement')
load_sess_mock.assert_called_once_with(CONF, 'placement', load_sess_mock.assert_called_once_with(CONF, 'placement',
additional_headers={'accept': 'application/json'}, auth=load_auth_mock.return_value)
auth=load_auth_mock.return_value) self.assertEqual(['admin'], client._client.interface)
self.assertEqual('admin', client.ks_filter['interface']) self.assertEqual({'accept': 'application/json'},
client._client.additional_headers)
class SchedulerReportClientTestCase(test.NoDBTestCase): class SchedulerReportClientTestCase(test.NoDBTestCase):
@ -179,7 +178,7 @@ class SchedulerReportClientTestCase(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(SchedulerReportClientTestCase, self).setUp() super(SchedulerReportClientTestCase, self).setUp()
self.context = context.get_admin_context() self.context = context.get_admin_context()
self.ks_sess_mock = mock.Mock() self.ks_adap_mock = mock.Mock()
self.compute_node = objects.ComputeNode( self.compute_node = objects.ComputeNode(
uuid=uuids.compute_node, uuid=uuids.compute_node,
hypervisor_hostname='foo', hypervisor_hostname='foo',
@ -192,10 +191,10 @@ class SchedulerReportClientTestCase(test.NoDBTestCase):
) )
with test.nested( with test.nested(
mock.patch('keystoneauth1.session.Session', mock.patch('keystoneauth1.adapter.Adapter',
return_value=self.ks_sess_mock), return_value=self.ks_adap_mock),
mock.patch('keystoneauth1.loading.load_auth_from_conf_options') mock.patch('keystoneauth1.loading.load_auth_from_conf_options')
) as (_auth_mock, _sess_mock): ):
self.client = report.SchedulerReportClient() self.client = report.SchedulerReportClient()
def _init_provider_tree(self, generation_override=None, def _init_provider_tree(self, generation_override=None,
@ -298,9 +297,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
get_resp_mock.json.return_value = { get_resp_mock.json.return_value = {
'allocations': {}, # build instance, not move 'allocations': {}, # build instance, not move
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=204) resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
alloc_req = { alloc_req = {
'allocations': { 'allocations': {
@ -323,10 +322,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
expected_payload = copy.deepcopy(alloc_req) expected_payload = copy.deepcopy(alloc_req)
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=expected_payload,
headers={'OpenStack-API-Version': 'placement 1.10'}, raise_exc=False)
json=expected_payload, raise_exc=False)
self.assertTrue(res) self.assertTrue(res)
@ -349,9 +347,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=204) resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
alloc_req = { alloc_req = {
'allocations': [ 'allocations': [
@ -399,13 +397,12 @@ class TestPutAllocations(SchedulerReportClientTestCase):
} }
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY,
headers={'OpenStack-API-Version': 'placement 1.10'}, raise_exc=False)
json=mock.ANY, raise_exc=False)
# We have to pull the json body from the mock call_args to validate # We have to pull the json body from the mock call_args to validate
# it separately otherwise hash seed issues get in the way. # it separately otherwise hash seed issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
@ -443,9 +440,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=204) resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
alloc_req = { alloc_req = {
'allocations': [ 'allocations': [
@ -510,14 +507,13 @@ class TestPutAllocations(SchedulerReportClientTestCase):
} }
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY,
headers={'OpenStack-API-Version': 'placement 1.10'}, raise_exc=False)
json=mock.ANY, raise_exc=False)
# We have to pull the allocations from the json body from the # We have to pull the allocations from the json body from the
# mock call_args to validate it separately otherwise hash seed # mock call_args to validate it separately otherwise hash seed
# issues get in the way. # issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
@ -548,9 +544,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
} }
self.ks_sess_mock.get.return_value = get_current_allocations_resp_mock self.ks_adap_mock.get.return_value = get_current_allocations_resp_mock
put_allocations_resp_mock = mock.Mock(status_code=204) put_allocations_resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = put_allocations_resp_mock self.ks_adap_mock.put.return_value = put_allocations_resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
# This is the resize-up allocation where VCPU, MEMORY_MB and DISK_GB # This is the resize-up allocation where VCPU, MEMORY_MB and DISK_GB
# are all being increased but on the same host. We also throw a custom # are all being increased but on the same host. We also throw a custom
@ -597,13 +593,11 @@ class TestPutAllocations(SchedulerReportClientTestCase):
} }
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY, raise_exc=False)
headers={'OpenStack-API-Version': 'placement 1.10'},
json=mock.ANY, raise_exc=False)
# We have to pull the json body from the mock call_args to validate # We have to pull the json body from the mock call_args to validate
# it separately otherwise hash seed issues get in the way. # it separately otherwise hash seed issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
@ -641,9 +635,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
} }
self.ks_sess_mock.get.return_value = get_current_allocations_resp_mock self.ks_adap_mock.get.return_value = get_current_allocations_resp_mock
put_allocations_resp_mock = mock.Mock(status_code=204) put_allocations_resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = put_allocations_resp_mock self.ks_adap_mock.put.return_value = put_allocations_resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
# This is the resize-up allocation where VCPU, MEMORY_MB and DISK_GB # This is the resize-up allocation where VCPU, MEMORY_MB and DISK_GB
# are all being increased but DISK_GB is on a shared storage provider. # are all being increased but DISK_GB is on a shared storage provider.
@ -700,13 +694,11 @@ class TestPutAllocations(SchedulerReportClientTestCase):
} }
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY, raise_exc=False)
headers={'OpenStack-API-Version': 'placement 1.10'},
json=mock.ANY, raise_exc=False)
# We have to pull the json body from the mock call_args to validate # We have to pull the json body from the mock call_args to validate
# it separately otherwise hash seed issues get in the way. # it separately otherwise hash seed issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
@ -721,7 +713,7 @@ class TestPutAllocations(SchedulerReportClientTestCase):
get_resp_mock.json.return_value = { get_resp_mock.json.return_value = {
'allocations': {}, # build instance, not move 'allocations': {}, # build instance, not move
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mocks = [ resp_mocks = [
mock.Mock( mock.Mock(
status_code=409, status_code=409,
@ -730,7 +722,7 @@ class TestPutAllocations(SchedulerReportClientTestCase):
'Please retry your update'), 'Please retry your update'),
mock.Mock(status_code=204), mock.Mock(status_code=204),
] ]
self.ks_sess_mock.put.side_effect = resp_mocks self.ks_adap_mock.put.side_effect = resp_mocks
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
alloc_req = { alloc_req = {
'allocations': [ 'allocations': [
@ -758,16 +750,11 @@ class TestPutAllocations(SchedulerReportClientTestCase):
# We should have exactly two calls to the placement API that look # We should have exactly two calls to the placement API that look
# identical since we're retrying the same HTTP request # identical since we're retrying the same HTTP request
expected_calls = [ expected_calls = [
mock.call(expected_url, endpoint_filter=mock.ANY, mock.call(expected_url, microversion='1.10', json=expected_payload,
headers={'OpenStack-API-Version': 'placement 1.10'}, raise_exc=False)] * 2
json=expected_payload, raise_exc=False),
mock.call(expected_url, endpoint_filter=mock.ANY,
headers={'OpenStack-API-Version': 'placement 1.10'},
json=expected_payload, raise_exc=False),
]
self.assertEqual(len(expected_calls), self.assertEqual(len(expected_calls),
self.ks_sess_mock.put.call_count) self.ks_adap_mock.put.call_count)
self.ks_sess_mock.put.assert_has_calls(expected_calls) self.ks_adap_mock.put.assert_has_calls(expected_calls)
self.assertTrue(res) self.assertTrue(res)
@ -777,9 +764,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
get_resp_mock.json.return_value = { get_resp_mock.json.return_value = {
'allocations': {}, # build instance, not move 'allocations': {}, # build instance, not move
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=409) resp_mock = mock.Mock(status_code=409)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
alloc_req = { alloc_req = {
'allocations': [ 'allocations': [
@ -804,10 +791,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
expected_payload = copy.deepcopy(alloc_req) expected_payload = copy.deepcopy(alloc_req)
expected_payload['project_id'] = project_id expected_payload['project_id'] = project_id
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=expected_payload,
headers={'OpenStack-API-Version': 'placement 1.10'}, raise_exc=False)
json=expected_payload, raise_exc=False)
self.assertFalse(res) self.assertFalse(res)
self.assertTrue(mock_log.called) self.assertTrue(mock_log.called)
@ -837,9 +823,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
}, },
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=204) resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
project_id = uuids.project_id project_id = uuids.project_id
user_id = uuids.user_id user_id = uuids.user_id
@ -865,17 +851,15 @@ class TestPutAllocations(SchedulerReportClientTestCase):
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
# We have to pull the json body from the mock call_args to validate # We have to pull the json body from the mock call_args to validate
# it separately otherwise hash seed issues get in the way. # it separately otherwise hash seed issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
actual_allocations = sorted(actual_payload['allocations'], actual_allocations = sorted(actual_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
self.assertEqual(expected_allocations, actual_allocations) self.assertEqual(expected_allocations, actual_allocations)
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY, raise_exc=False)
headers={'OpenStack-API-Version': 'placement 1.10'},
json=mock.ANY, raise_exc=False)
self.assertTrue(res) self.assertTrue(res)
@ -911,9 +895,9 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
}, },
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
resp_mock = mock.Mock(status_code=204) resp_mock = mock.Mock(status_code=204)
self.ks_sess_mock.put.return_value = resp_mock self.ks_adap_mock.put.return_value = resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
project_id = uuids.project_id project_id = uuids.project_id
user_id = uuids.user_id user_id = uuids.user_id
@ -947,17 +931,15 @@ class TestPutAllocations(SchedulerReportClientTestCase):
expected_payload['user_id'] = user_id expected_payload['user_id'] = user_id
# We have to pull the json body from the mock call_args to validate # We have to pull the json body from the mock call_args to validate
# it separately otherwise hash seed issues get in the way. # it separately otherwise hash seed issues get in the way.
actual_payload = self.ks_sess_mock.put.call_args[1]['json'] actual_payload = self.ks_adap_mock.put.call_args[1]['json']
sort_by_uuid = lambda x: x['resource_provider']['uuid'] sort_by_uuid = lambda x: x['resource_provider']['uuid']
expected_allocations = sorted(expected_payload['allocations'], expected_allocations = sorted(expected_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
actual_allocations = sorted(actual_payload['allocations'], actual_allocations = sorted(actual_payload['allocations'],
key=sort_by_uuid) key=sort_by_uuid)
self.assertEqual(expected_allocations, actual_allocations) self.assertEqual(expected_allocations, actual_allocations)
self.ks_sess_mock.put.assert_called_once_with( self.ks_adap_mock.put.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, expected_url, microversion='1.10', json=mock.ANY, raise_exc=False)
headers={'OpenStack-API-Version': 'placement 1.10'},
json=mock.ANY, raise_exc=False)
self.assertTrue(res) self.assertTrue(res)
@ -986,15 +968,15 @@ class TestPutAllocations(SchedulerReportClientTestCase):
}, },
}, },
} }
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
project_id = uuids.project_id project_id = uuids.project_id
user_id = uuids.user_id user_id = uuids.user_id
res = self.client.remove_provider_from_instance_allocation( res = self.client.remove_provider_from_instance_allocation(
consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) consumer_uuid, uuids.source, user_id, project_id, mock.Mock())
self.ks_sess_mock.get.assert_called() self.ks_adap_mock.get.assert_called()
self.ks_sess_mock.put.assert_not_called() self.ks_adap_mock.put.assert_not_called()
self.assertTrue(res) self.assertTrue(res)
@ -1004,15 +986,15 @@ class TestPutAllocations(SchedulerReportClientTestCase):
existing allocations fails for some reason existing allocations fails for some reason
""" """
get_resp_mock = mock.Mock(status_code=500) get_resp_mock = mock.Mock(status_code=500)
self.ks_sess_mock.get.return_value = get_resp_mock self.ks_adap_mock.get.return_value = get_resp_mock
consumer_uuid = uuids.consumer_uuid consumer_uuid = uuids.consumer_uuid
project_id = uuids.project_id project_id = uuids.project_id
user_id = uuids.user_id user_id = uuids.user_id
res = self.client.remove_provider_from_instance_allocation( res = self.client.remove_provider_from_instance_allocation(
consumer_uuid, uuids.source, user_id, project_id, mock.Mock()) consumer_uuid, uuids.source, user_id, project_id, mock.Mock())
self.ks_sess_mock.get.assert_called() self.ks_adap_mock.get.assert_called()
self.ks_sess_mock.put.assert_not_called() self.ks_adap_mock.put.assert_not_called()
self.assertFalse(res) self.assertFalse(res)
@ -1148,15 +1130,14 @@ class TestProviderOperations(SchedulerReportClientTestCase):
} }
resources = {'VCPU': 1, 'MEMORY_MB': 1024} resources = {'VCPU': 1, 'MEMORY_MB': 1024}
resp_mock.json.return_value = json_data resp_mock.json.return_value = json_data
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
alloc_reqs, p_sums = self.client.get_allocation_candidates(resources) alloc_reqs, p_sums = self.client.get_allocation_candidates(resources)
expected_url = '/allocation_candidates?%s' % parse.urlencode( expected_url = '/allocation_candidates?%s' % parse.urlencode(
{'resources': 'MEMORY_MB:1024,VCPU:1'}) {'resources': 'MEMORY_MB:1024,VCPU:1'})
self.ks_sess_mock.get.assert_called_once_with( self.ks_adap_mock.get.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, raise_exc=False, expected_url, raise_exc=False, microversion='1.10')
headers={'OpenStack-API-Version': 'placement 1.10'})
self.assertEqual(mock.sentinel.alloc_reqs, alloc_reqs) self.assertEqual(mock.sentinel.alloc_reqs, alloc_reqs)
self.assertEqual(mock.sentinel.p_sums, p_sums) self.assertEqual(mock.sentinel.p_sums, p_sums)
@ -1164,14 +1145,13 @@ class TestProviderOperations(SchedulerReportClientTestCase):
# Ensure _get_resource_provider() just returns None when the placement # Ensure _get_resource_provider() just returns None when the placement
# API doesn't find a resource provider matching a UUID # API doesn't find a resource provider matching a UUID
resp_mock = mock.Mock(status_code=404) resp_mock = mock.Mock(status_code=404)
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
res = self.client.get_allocation_candidates({'foo': 'bar'}) res = self.client.get_allocation_candidates({'foo': 'bar'})
expected_url = '/allocation_candidates?resources=foo%3Abar' expected_url = '/allocation_candidates?resources=foo%3Abar'
self.ks_sess_mock.get.assert_called_once_with( self.ks_adap_mock.get.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, raise_exc=False, expected_url, raise_exc=False, microversion='1.10')
headers={'OpenStack-API-Version': 'placement 1.10'})
self.assertIsNone(res[0]) self.assertIsNone(res[0])
self.assertIsNone(res[0]) self.assertIsNone(res[0])
@ -1186,7 +1166,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'generation': 42, 'generation': 42,
} }
resp_mock.json.return_value = json_data resp_mock.json.return_value = json_data
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
result = self.client._get_resource_provider(uuid) result = self.client._get_resource_provider(uuid)
@ -1196,24 +1176,22 @@ class TestProviderOperations(SchedulerReportClientTestCase):
generation=42, generation=42,
) )
expected_url = '/resource_providers/' + uuid expected_url = '/resource_providers/' + uuid
self.ks_sess_mock.get.assert_called_once_with(expected_url, self.ks_adap_mock.get.assert_called_once_with(
endpoint_filter=mock.ANY, expected_url, raise_exc=False, microversion=None)
raise_exc=False)
self.assertEqual(expected_provider_dict, result) self.assertEqual(expected_provider_dict, result)
def test_get_resource_provider_not_found(self): def test_get_resource_provider_not_found(self):
# Ensure _get_resource_provider() just returns None when the placement # Ensure _get_resource_provider() just returns None when the placement
# API doesn't find a resource provider matching a UUID # API doesn't find a resource provider matching a UUID
resp_mock = mock.Mock(status_code=404) resp_mock = mock.Mock(status_code=404)
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
uuid = uuids.compute_node uuid = uuids.compute_node
result = self.client._get_resource_provider(uuid) result = self.client._get_resource_provider(uuid)
expected_url = '/resource_providers/' + uuid expected_url = '/resource_providers/' + uuid
self.ks_sess_mock.get.assert_called_once_with(expected_url, self.ks_adap_mock.get.assert_called_once_with(
endpoint_filter=mock.ANY, expected_url, raise_exc=False, microversion=None)
raise_exc=False)
self.assertIsNone(result) self.assertIsNone(result)
@mock.patch.object(report.LOG, 'error') @mock.patch.object(report.LOG, 'error')
@ -1222,19 +1200,18 @@ class TestProviderOperations(SchedulerReportClientTestCase):
# communicate with the placement API and not getting an error we can # communicate with the placement API and not getting an error we can
# deal with # deal with
resp_mock = mock.Mock(status_code=503) resp_mock = mock.Mock(status_code=503)
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
self.ks_sess_mock.get.return_value.headers = { self.ks_adap_mock.get.return_value.headers = {
'openstack-request-id': uuids.request_id} 'openstack-request-id': uuids.request_id}
uuid = uuids.compute_node uuid = uuids.compute_node
result = self.client._get_resource_provider(uuid) result = self.client._get_resource_provider(uuid)
expected_url = '/resource_providers/' + uuid expected_url = '/resource_providers/' + uuid
self.ks_sess_mock.get.assert_called_once_with(expected_url, self.ks_adap_mock.get.assert_called_once_with(
endpoint_filter=mock.ANY, expected_url, raise_exc=False, microversion=None)
raise_exc=False) # A 503 Service Unavailable should trigger an error log
# A 503 Service Unavailable should trigger an error log that # that includes the placement request id and return None
# includes the placement request id and return None
# from _get_resource_provider() # from _get_resource_provider()
self.assertTrue(logging_mock.called) self.assertTrue(logging_mock.called)
self.assertIsNone(result) self.assertIsNone(result)
@ -1248,7 +1225,7 @@ class TestProviderOperations(SchedulerReportClientTestCase):
uuid = uuids.compute_node uuid = uuids.compute_node
name = 'computehost' name = 'computehost'
resp_mock = mock.Mock(status_code=201) resp_mock = mock.Mock(status_code=201)
self.ks_sess_mock.post.return_value = resp_mock self.ks_adap_mock.post.return_value = resp_mock
result = self.client._create_resource_provider(uuid, name) result = self.client._create_resource_provider(uuid, name)
@ -1262,11 +1239,9 @@ class TestProviderOperations(SchedulerReportClientTestCase):
generation=0, generation=0,
) )
expected_url = '/resource_providers' expected_url = '/resource_providers'
self.ks_sess_mock.post.assert_called_once_with( self.ks_adap_mock.post.assert_called_once_with(
expected_url, expected_url, json=expected_payload, raise_exc=False,
endpoint_filter=mock.ANY, microversion=None)
json=expected_payload,
raise_exc=False)
self.assertEqual(expected_provider_dict, result) self.assertEqual(expected_provider_dict, result)
@mock.patch.object(report.LOG, 'info') @mock.patch.object(report.LOG, 'info')
@ -1282,8 +1257,8 @@ class TestProviderOperations(SchedulerReportClientTestCase):
uuid = uuids.compute_node uuid = uuids.compute_node
name = 'computehost' name = 'computehost'
resp_mock = mock.Mock(status_code=409) resp_mock = mock.Mock(status_code=409)
self.ks_sess_mock.post.return_value = resp_mock self.ks_adap_mock.post.return_value = resp_mock
self.ks_sess_mock.post.return_value.headers = { self.ks_adap_mock.post.return_value.headers = {
'openstack-request-id': uuids.request_id} 'openstack-request-id': uuids.request_id}
get_rp_mock.return_value = mock.sentinel.get_rp get_rp_mock.return_value = mock.sentinel.get_rp
@ -1295,11 +1270,9 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'name': name, 'name': name,
} }
expected_url = '/resource_providers' expected_url = '/resource_providers'
self.ks_sess_mock.post.assert_called_once_with( self.ks_adap_mock.post.assert_called_once_with(
expected_url, expected_url, json=expected_payload, raise_exc=False,
endpoint_filter=mock.ANY, microversion=None)
json=expected_payload,
raise_exc=False)
self.assertEqual(mock.sentinel.get_rp, result) self.assertEqual(mock.sentinel.get_rp, result)
# The 409 response will produce a message to the info log. # The 409 response will produce a message to the info log.
self.assertTrue(logging_mock.called) self.assertTrue(logging_mock.called)
@ -1314,8 +1287,8 @@ class TestProviderOperations(SchedulerReportClientTestCase):
uuid = uuids.compute_node uuid = uuids.compute_node
name = 'computehost' name = 'computehost'
resp_mock = mock.Mock(status_code=503) resp_mock = mock.Mock(status_code=503)
self.ks_sess_mock.post.return_value = resp_mock self.ks_adap_mock.post.return_value = resp_mock
self.ks_sess_mock.post.return_value.headers = { self.ks_adap_mock.post.return_value.headers = {
'x-openstack-request-id': uuids.request_id} 'x-openstack-request-id': uuids.request_id}
result = self.client._create_resource_provider(uuid, name) result = self.client._create_resource_provider(uuid, name)
@ -1325,11 +1298,9 @@ class TestProviderOperations(SchedulerReportClientTestCase):
'name': name, 'name': name,
} }
expected_url = '/resource_providers' expected_url = '/resource_providers'
self.ks_sess_mock.post.assert_called_once_with( self.ks_adap_mock.post.assert_called_once_with(
expected_url, expected_url, json=expected_payload, raise_exc=False,
endpoint_filter=mock.ANY, microversion=None)
json=expected_payload,
raise_exc=False)
# A 503 Service Unavailable should log an error that # A 503 Service Unavailable should log an error that
# includes the placement request id and # includes the placement request id and
# _create_resource_provider() should return None # _create_resource_provider() should return None
@ -1353,7 +1324,7 @@ class TestAggregates(SchedulerReportClientTestCase):
], ],
} }
resp_mock.json.return_value = json_data resp_mock.json.return_value = json_data
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
result = self.client._get_provider_aggregates(uuid) result = self.client._get_provider_aggregates(uuid)
@ -1362,9 +1333,8 @@ class TestAggregates(SchedulerReportClientTestCase):
uuids.agg2, uuids.agg2,
]) ])
expected_url = '/resource_providers/' + uuid + '/aggregates' expected_url = '/resource_providers/' + uuid + '/aggregates'
self.ks_sess_mock.get.assert_called_once_with( self.ks_adap_mock.get.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, raise_exc=False, expected_url, raise_exc=False, microversion='1.1')
headers={'OpenStack-API-Version': 'placement 1.1'})
self.assertEqual(expected, result) self.assertEqual(expected, result)
@mock.patch.object(report.LOG, 'warning') @mock.patch.object(report.LOG, 'warning')
@ -1376,16 +1346,15 @@ class TestAggregates(SchedulerReportClientTestCase):
""" """
uuid = uuids.compute_node uuid = uuids.compute_node
resp_mock = mock.Mock(status_code=404) resp_mock = mock.Mock(status_code=404)
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
self.ks_sess_mock.get.return_value.headers = { self.ks_adap_mock.get.return_value.headers = {
'x-openstack-request-id': uuids.request_id} 'x-openstack-request-id': uuids.request_id}
result = self.client._get_provider_aggregates(uuid) result = self.client._get_provider_aggregates(uuid)
expected_url = '/resource_providers/' + uuid + '/aggregates' expected_url = '/resource_providers/' + uuid + '/aggregates'
self.ks_sess_mock.get.assert_called_once_with( self.ks_adap_mock.get.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, raise_exc=False, expected_url, raise_exc=False, microversion='1.1')
headers={'OpenStack-API-Version': 'placement 1.1'})
self.assertTrue(log_mock.called) self.assertTrue(log_mock.called)
self.assertEqual(uuids.request_id, self.assertEqual(uuids.request_id,
log_mock.call_args[0][1]['placement_req_id']) log_mock.call_args[0][1]['placement_req_id'])
@ -1398,16 +1367,15 @@ class TestAggregates(SchedulerReportClientTestCase):
""" """
uuid = uuids.compute_node uuid = uuids.compute_node
resp_mock = mock.Mock(status_code=400) resp_mock = mock.Mock(status_code=400)
self.ks_sess_mock.get.return_value = resp_mock self.ks_adap_mock.get.return_value = resp_mock
self.ks_sess_mock.get.return_value.headers = { self.ks_adap_mock.get.return_value.headers = {
'x-openstack-request-id': uuids.request_id} 'x-openstack-request-id': uuids.request_id}
result = self.client._get_provider_aggregates(uuid) result = self.client._get_provider_aggregates(uuid)
expected_url = '/resource_providers/' + uuid + '/aggregates' expected_url = '/resource_providers/' + uuid + '/aggregates'
self.ks_sess_mock.get.assert_called_once_with( self.ks_adap_mock.get.assert_called_once_with(
expected_url, endpoint_filter=mock.ANY, raise_exc=False, expected_url, raise_exc=False, microversion='1.1')
headers={'OpenStack-API-Version': 'placement 1.1'})
self.assertTrue(log_mock.called) self.assertTrue(log_mock.called)
self.assertEqual(uuids.request_id, self.assertEqual(uuids.request_id,
log_mock.call_args[0][1]['placement_req_id']) log_mock.call_args[0][1]['placement_req_id'])

View File

@ -1299,8 +1299,14 @@ def get_ksa_adapter(service_type, ksa_auth=None, ksa_session=None,
""" """
# Get the conf group corresponding to the service type. # Get the conf group corresponding to the service type.
confgrp = _SERVICE_TYPES.get_project_name(service_type) confgrp = _SERVICE_TYPES.get_project_name(service_type)
if not confgrp: if not confgrp or not hasattr(CONF, confgrp):
raise exception.ConfGroupForServiceTypeNotFound(stype=service_type) # Try the service type as the conf group. This is necessary for e.g.
# placement, while it's still part of the nova project.
# Note that this might become the first thing we try if/as we move to
# using service types for conf group names in general.
confgrp = service_type
if not confgrp or not hasattr(CONF, confgrp):
raise exception.ConfGroupForServiceTypeNotFound(stype=service_type)
# Ensure we have an auth. # Ensure we have an auth.
# NOTE(efried): This could be None, and that could be okay - e.g. if the # NOTE(efried): This could be None, and that could be okay - e.g. if the

View File

@ -0,0 +1,16 @@
---
upgrade:
- |
Nova now uses keystoneauth1 configuration to set up communication with the
placement service. Use keystoneauth1 loading parameters for auth, Session,
and Adapter setup in the ``[placement]`` conf section. Note that, by
default, the 'internal' interface will be tried first, followed by the
'public' interface. Use the conf option ``[placement].valid_interfaces``
to override this behavior.
deprecations:
- |
Configuration options in the ``[placement]`` section are deprecated as
follows:
* ``os_region_name`` is deprecated in favor of ``region_name``
* ``os_interface`` is deprecated in favor of ``valid_interfaces``