diff --git a/nova/scheduler/client/report.py b/nova/scheduler/client/report.py index d245196a78d9..da82c4f34cfb 100644 --- a/nova/scheduler/client/report.py +++ b/nova/scheduler/client/report.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import copy import functools import math import re @@ -886,6 +887,32 @@ class SchedulerReportClient(object): LOG.info(_LI('Submitted allocation for instance'), instance=instance) + def claim_resources(self, consumer_uuid, alloc_request, project_id, + user_id): + """Creates allocation records for the supplied instance UUID against + the supplied resource providers. + + :param consumer_uuid: The instance's UUID. + :param alloc_request: The JSON body of the request to make to the + placement's PUT /allocations API + :param project_id: The project_id associated with the allocations. + :param user_id: The user_id associated with the allocations. + :returns: True if the allocations were created, False otherwise. + """ + url = '/allocations/%s' % consumer_uuid + payload = copy.deepcopy(alloc_request) + payload['project_id'] = project_id + payload['user_id'] = user_id + r = self.put(url, payload, version='1.10') + if r.status_code != 204: + LOG.warning( + 'Unable to submit allocation for instance ' + '%(uuid)s (%(code)i %(text)s)', + {'uuid': consumer_uuid, + 'code': r.status_code, + 'text': r.text}) + return r.status_code == 204 + @safe_connect def put_allocations(self, rp_uuid, consumer_uuid, alloc_data, project_id, user_id): diff --git a/nova/tests/unit/scheduler/client/test_report.py b/nova/tests/unit/scheduler/client/test_report.py index 21c7b0ff6ae7..4d44112ca34e 100644 --- a/nova/tests/unit/scheduler/client/test_report.py +++ b/nova/tests/unit/scheduler/client/test_report.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + from keystoneauth1 import exceptions as ks_exc import mock import six @@ -233,6 +235,72 @@ class TestPutAllocations(SchedulerReportClientTestCase): log_msg = mock_warn.call_args[0][0] self.assertIn("Unable to submit allocation for instance", log_msg) + def test_claim_resources_success(self): + resp_mock = mock.Mock(status_code=204) + self.ks_sess_mock.put.return_value = resp_mock + consumer_uuid = uuids.consumer_uuid + alloc_req = { + 'allocations': { + 'resource_provider': { + 'uuid': uuids.cn1, + }, + 'resources': { + 'VCPU': 1, + 'MEMORY_MB': 1024, + }, + }, + } + + project_id = uuids.project_id + user_id = uuids.user_id + res = self.client.claim_resources(consumer_uuid, alloc_req, project_id, + user_id) + + expected_url = "/allocations/%s" % consumer_uuid + expected_payload = copy.deepcopy(alloc_req) + expected_payload['project_id'] = project_id + expected_payload['user_id'] = user_id + self.ks_sess_mock.put.assert_called_once_with( + expected_url, endpoint_filter=mock.ANY, + headers={'OpenStack-API-Version': 'placement 1.10'}, + json=expected_payload, raise_exc=False) + + self.assertTrue(res) + + @mock.patch.object(report.LOG, 'warning') + def test_claim_resources_failure(self, mock_log): + resp_mock = mock.Mock(status_code=409) + self.ks_sess_mock.put.return_value = resp_mock + consumer_uuid = uuids.consumer_uuid + alloc_req = { + 'allocations': { + 'resource_provider': { + 'uuid': uuids.cn1, + }, + 'resources': { + 'VCPU': 1, + 'MEMORY_MB': 1024, + }, + }, + } + + project_id = uuids.project_id + user_id = uuids.user_id + res = self.client.claim_resources(consumer_uuid, alloc_req, project_id, + user_id) + + expected_url = "/allocations/%s" % consumer_uuid + expected_payload = copy.deepcopy(alloc_req) + expected_payload['project_id'] = project_id + expected_payload['user_id'] = user_id + self.ks_sess_mock.put.assert_called_once_with( + expected_url, endpoint_filter=mock.ANY, + headers={'OpenStack-API-Version': 'placement 1.10'}, + json=expected_payload, raise_exc=False) + + self.assertFalse(res) + self.assertTrue(mock_log.called) + class TestProviderOperations(SchedulerReportClientTestCase): @mock.patch('nova.scheduler.client.report.SchedulerReportClient.'