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:
parent
8352d555a5
commit
987d451f4d
|
@ -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"])
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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``
|
Loading…
Reference in New Issue