Prepare _heal_allocations_for_instance for nested allocations
When no allocations exist for an instance the current heal code uses a report client call that can only handle allocations from a single RP. This call is now replaced with a more generic one so in a later patch port allocations can be added to this code path too. Related-Bug: #1819923 Change-Id: Ide343c1c922dac576b1944827dc24caefab59b74
This commit is contained in:
parent
9adcf53210
commit
307999c581
|
@ -1674,10 +1674,16 @@ class PlacementCommands(object):
|
||||||
{'instance': instance.uuid, 'node_uuid': node_uuid,
|
{'instance': instance.uuid, 'node_uuid': node_uuid,
|
||||||
'resources': resources})
|
'resources': resources})
|
||||||
else:
|
else:
|
||||||
if placement.put_allocations(
|
payload = {
|
||||||
ctxt, node_uuid, instance.uuid, resources,
|
'allocations': {
|
||||||
instance.project_id, instance.user_id,
|
node_uuid: {'resources': resources},
|
||||||
consumer_generation=None):
|
},
|
||||||
|
'project_id': instance.project_id,
|
||||||
|
'user_id': instance.user_id,
|
||||||
|
'consumer_generation': None
|
||||||
|
}
|
||||||
|
resp = placement.put_allocations(ctxt, instance.uuid, payload)
|
||||||
|
if resp:
|
||||||
output(_('Successfully created allocations for '
|
output(_('Successfully created allocations for '
|
||||||
'instance %(instance)s against resource '
|
'instance %(instance)s against resource '
|
||||||
'provider %(provider)s.') %
|
'provider %(provider)s.') %
|
||||||
|
@ -1688,21 +1694,16 @@ class PlacementCommands(object):
|
||||||
instance=instance.uuid, provider=node_uuid)
|
instance=instance.uuid, provider=node_uuid)
|
||||||
|
|
||||||
def _heal_missing_project_and_user_id(
|
def _heal_missing_project_and_user_id(
|
||||||
self, allocations, instance, dry_run, output, placement):
|
self, ctxt, allocations, instance, dry_run, output, placement):
|
||||||
|
|
||||||
allocations['project_id'] = instance.project_id
|
allocations['project_id'] = instance.project_id
|
||||||
allocations['user_id'] = instance.user_id
|
allocations['user_id'] = instance.user_id
|
||||||
# We use CONSUMER_GENERATION_VERSION for PUT
|
|
||||||
# /allocations/{consumer_id} to mirror the body structure from
|
|
||||||
# get_allocs_for_consumer.
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
output(_('[dry-run] Update allocations for instance '
|
output(_('[dry-run] Update allocations for instance '
|
||||||
'%(instance)s: %(allocations)s') %
|
'%(instance)s: %(allocations)s') %
|
||||||
{'instance': instance.uuid, 'allocations': allocations})
|
{'instance': instance.uuid, 'allocations': allocations})
|
||||||
else:
|
else:
|
||||||
resp = placement.put(
|
resp = placement.put_allocations(ctxt, instance.uuid, allocations)
|
||||||
'/allocations/%s' % instance.uuid,
|
|
||||||
allocations, version=report.CONSUMER_GENERATION_VERSION)
|
|
||||||
if resp:
|
if resp:
|
||||||
output(_('Successfully updated allocations for '
|
output(_('Successfully updated allocations for '
|
||||||
'instance %s.') % instance.uuid)
|
'instance %s.') % instance.uuid)
|
||||||
|
@ -1772,7 +1773,7 @@ class PlacementCommands(object):
|
||||||
# because we don't want to mess up shared or nested
|
# because we don't want to mess up shared or nested
|
||||||
# provider allocations.
|
# provider allocations.
|
||||||
return self._heal_missing_project_and_user_id(
|
return self._heal_missing_project_and_user_id(
|
||||||
allocations, instance, dry_run, output, placement)
|
ctxt, allocations, instance, dry_run, output, placement)
|
||||||
|
|
||||||
output(_('Instance %s already has allocations with '
|
output(_('Instance %s already has allocations with '
|
||||||
'matching consumer project/user.') % instance.uuid)
|
'matching consumer project/user.') % instance.uuid)
|
||||||
|
|
|
@ -1930,27 +1930,17 @@ class SchedulerReportClient(object):
|
||||||
'text': r.text})
|
'text': r.text})
|
||||||
return r.status_code == 204
|
return r.status_code == 204
|
||||||
|
|
||||||
|
# TODO(gibi): kill safe_connect
|
||||||
@safe_connect
|
@safe_connect
|
||||||
@retries
|
@retries
|
||||||
def put_allocations(self, context, rp_uuid, consumer_uuid, alloc_data,
|
def put_allocations(self, context, consumer_uuid, payload):
|
||||||
project_id, user_id, consumer_generation):
|
"""Creates allocation records for the supplied consumer UUID based on
|
||||||
"""Creates allocation records for the supplied instance UUID against
|
the provided allocation dict
|
||||||
the supplied resource provider.
|
|
||||||
|
|
||||||
:note Currently we only allocate against a single resource provider.
|
|
||||||
Once shared storage and things like NUMA allocations are a
|
|
||||||
reality, this will change to allocate against multiple providers.
|
|
||||||
|
|
||||||
:param context: The security context
|
:param context: The security context
|
||||||
:param rp_uuid: The UUID of the resource provider to allocate against.
|
|
||||||
:param consumer_uuid: The instance's UUID.
|
:param consumer_uuid: The instance's UUID.
|
||||||
:param alloc_data: Dict, keyed by resource class, of amounts to
|
:param payload: Dict in the format expected by the placement
|
||||||
consume.
|
PUT /allocations/{consumer_uuid} API
|
||||||
:param project_id: The project_id associated with the allocations.
|
|
||||||
:param user_id: The user_id associated with the allocations.
|
|
||||||
:param consumer_generation: The current generation of the consumer or
|
|
||||||
None if this the initial allocation of the
|
|
||||||
consumer
|
|
||||||
:returns: True if the allocations were created, False otherwise.
|
:returns: True if the allocations were created, False otherwise.
|
||||||
:raises: Retry if the operation should be retried due to a concurrent
|
:raises: Retry if the operation should be retried due to a concurrent
|
||||||
resource provider update.
|
resource provider update.
|
||||||
|
@ -1958,14 +1948,6 @@ class SchedulerReportClient(object):
|
||||||
generation conflict
|
generation conflict
|
||||||
"""
|
"""
|
||||||
|
|
||||||
payload = {
|
|
||||||
'allocations': {
|
|
||||||
rp_uuid: {'resources': alloc_data},
|
|
||||||
},
|
|
||||||
'project_id': project_id,
|
|
||||||
'user_id': user_id,
|
|
||||||
'consumer_generation': consumer_generation
|
|
||||||
}
|
|
||||||
r = self._put_allocations(context, consumer_uuid, payload)
|
r = self._put_allocations(context, consumer_uuid, payload)
|
||||||
if r.status_code != 204:
|
if r.status_code != 204:
|
||||||
err = r.json()['errors'][0]
|
err = r.json()['errors'][0]
|
||||||
|
|
|
@ -243,10 +243,16 @@ class SchedulerReportClientTests(SchedulerReportClientTestBase):
|
||||||
# Update allocations with our instance
|
# Update allocations with our instance
|
||||||
alloc_dict = utils.resources_from_flavor(self.instance,
|
alloc_dict = utils.resources_from_flavor(self.instance,
|
||||||
self.instance.flavor)
|
self.instance.flavor)
|
||||||
|
payload = {
|
||||||
|
"allocations": {
|
||||||
|
self.compute_uuid: {"resources": alloc_dict}
|
||||||
|
},
|
||||||
|
"project_id": self.instance.project_id,
|
||||||
|
"user_id": self.instance.user_id,
|
||||||
|
"consumer_generation": None
|
||||||
|
}
|
||||||
self.client.put_allocations(
|
self.client.put_allocations(
|
||||||
self.context, self.compute_uuid, self.instance_uuid,
|
self.context, self.instance_uuid, payload)
|
||||||
alloc_dict, self.instance.project_id, self.instance.user_id,
|
|
||||||
None)
|
|
||||||
|
|
||||||
# Check that allocations were made
|
# Check that allocations were made
|
||||||
resp = self.client.get('/allocations/%s' % self.instance_uuid)
|
resp = self.client.get('/allocations/%s' % self.instance_uuid)
|
||||||
|
@ -685,13 +691,18 @@ class SchedulerReportClientTests(SchedulerReportClientTestBase):
|
||||||
inv,
|
inv,
|
||||||
self.client._get_inventory(
|
self.client._get_inventory(
|
||||||
self.context, uuids.cn)['inventories'])
|
self.context, uuids.cn)['inventories'])
|
||||||
|
payload = {
|
||||||
|
"allocations": {
|
||||||
|
uuids.cn: {"resources": {orc.SRIOV_NET_VF: 1}}
|
||||||
|
},
|
||||||
|
"project_id": uuids.proj,
|
||||||
|
"user_id": uuids.user,
|
||||||
|
"consumer_generation": None
|
||||||
|
}
|
||||||
# Now set up an InventoryInUse case by creating a VF allocation...
|
# Now set up an InventoryInUse case by creating a VF allocation...
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
self.client.put_allocations(
|
self.client.put_allocations(
|
||||||
self.context, uuids.cn, uuids.consumer,
|
self.context, uuids.consumer, payload))
|
||||||
{orc.SRIOV_NET_VF: 1},
|
|
||||||
uuids.proj, uuids.user, None))
|
|
||||||
# ...and trying to delete the provider's VF inventory
|
# ...and trying to delete the provider's VF inventory
|
||||||
bad_inv = {
|
bad_inv = {
|
||||||
'CUSTOM_BANDWIDTH': {
|
'CUSTOM_BANDWIDTH': {
|
||||||
|
|
|
@ -269,14 +269,19 @@ class TestPutAllocations(SchedulerReportClientTestCase):
|
||||||
consumer_uuid = mock.sentinel.consumer
|
consumer_uuid = mock.sentinel.consumer
|
||||||
data = {"MEMORY_MB": 1024}
|
data = {"MEMORY_MB": 1024}
|
||||||
expected_url = "/allocations/%s" % consumer_uuid
|
expected_url = "/allocations/%s" % consumer_uuid
|
||||||
resp = self.client.put_allocations(self.context, rp_uuid,
|
payload = {
|
||||||
consumer_uuid, data,
|
"allocations": {
|
||||||
mock.sentinel.project_id,
|
rp_uuid: {"resources": data}
|
||||||
mock.sentinel.user_id,
|
},
|
||||||
mock.sentinel.consumer_generation)
|
"project_id": mock.sentinel.project_id,
|
||||||
|
"user_id": mock.sentinel.user_id,
|
||||||
|
"consumer_generation": mock.sentinel.consumer_generation
|
||||||
|
}
|
||||||
|
resp = self.client.put_allocations(
|
||||||
|
self.context, consumer_uuid, payload)
|
||||||
self.assertTrue(resp)
|
self.assertTrue(resp)
|
||||||
mock_put.assert_called_once_with(
|
mock_put.assert_called_once_with(
|
||||||
expected_url, mock.ANY, version='1.28',
|
expected_url, payload, version='1.28',
|
||||||
global_request_id=self.context.global_id)
|
global_request_id=self.context.global_id)
|
||||||
|
|
||||||
@mock.patch.object(report.LOG, 'warning')
|
@mock.patch.object(report.LOG, 'warning')
|
||||||
|
@ -288,14 +293,20 @@ class TestPutAllocations(SchedulerReportClientTestCase):
|
||||||
consumer_uuid = mock.sentinel.consumer
|
consumer_uuid = mock.sentinel.consumer
|
||||||
data = {"MEMORY_MB": 1024}
|
data = {"MEMORY_MB": 1024}
|
||||||
expected_url = "/allocations/%s" % consumer_uuid
|
expected_url = "/allocations/%s" % consumer_uuid
|
||||||
resp = self.client.put_allocations(self.context, rp_uuid,
|
payload = {
|
||||||
consumer_uuid, data,
|
"allocations": {
|
||||||
mock.sentinel.project_id,
|
rp_uuid: {"resources": data}
|
||||||
mock.sentinel.user_id,
|
},
|
||||||
mock.sentinel.consumer_generation)
|
"project_id": mock.sentinel.project_id,
|
||||||
|
"user_id": mock.sentinel.user_id,
|
||||||
|
"consumer_generation": mock.sentinel.consumer_generation
|
||||||
|
}
|
||||||
|
resp = self.client.put_allocations(
|
||||||
|
self.context, consumer_uuid, payload)
|
||||||
|
|
||||||
self.assertFalse(resp)
|
self.assertFalse(resp)
|
||||||
mock_put.assert_called_once_with(
|
mock_put.assert_called_once_with(
|
||||||
expected_url, mock.ANY, version='1.28',
|
expected_url, payload, version='1.28',
|
||||||
global_request_id=self.context.global_id)
|
global_request_id=self.context.global_id)
|
||||||
log_msg = mock_warn.call_args[0][0]
|
log_msg = mock_warn.call_args[0][0]
|
||||||
self.assertIn("Failed to save allocation for", log_msg)
|
self.assertIn("Failed to save allocation for", log_msg)
|
||||||
|
@ -313,13 +324,17 @@ class TestPutAllocations(SchedulerReportClientTestCase):
|
||||||
consumer_uuid = mock.sentinel.consumer
|
consumer_uuid = mock.sentinel.consumer
|
||||||
data = {"MEMORY_MB": 1024}
|
data = {"MEMORY_MB": 1024}
|
||||||
expected_url = "/allocations/%s" % consumer_uuid
|
expected_url = "/allocations/%s" % consumer_uuid
|
||||||
|
payload = {
|
||||||
|
"allocations": {
|
||||||
|
rp_uuid: {"resources": data}
|
||||||
|
},
|
||||||
|
"project_id": mock.sentinel.project_id,
|
||||||
|
"user_id": mock.sentinel.user_id,
|
||||||
|
"consumer_generation": mock.sentinel.consumer_generation
|
||||||
|
}
|
||||||
self.assertRaises(exception.AllocationUpdateFailed,
|
self.assertRaises(exception.AllocationUpdateFailed,
|
||||||
self.client.put_allocations,
|
self.client.put_allocations,
|
||||||
self.context, rp_uuid,
|
self.context, consumer_uuid, payload)
|
||||||
consumer_uuid, data,
|
|
||||||
mock.sentinel.project_id,
|
|
||||||
mock.sentinel.user_id,
|
|
||||||
mock.sentinel.consumer_generation)
|
|
||||||
|
|
||||||
mock_put.assert_called_once_with(
|
mock_put.assert_called_once_with(
|
||||||
expected_url, mock.ANY, version='1.28',
|
expected_url, mock.ANY, version='1.28',
|
||||||
|
@ -343,14 +358,19 @@ class TestPutAllocations(SchedulerReportClientTestCase):
|
||||||
consumer_uuid = mock.sentinel.consumer
|
consumer_uuid = mock.sentinel.consumer
|
||||||
data = {"MEMORY_MB": 1024}
|
data = {"MEMORY_MB": 1024}
|
||||||
expected_url = "/allocations/%s" % consumer_uuid
|
expected_url = "/allocations/%s" % consumer_uuid
|
||||||
resp = self.client.put_allocations(self.context, rp_uuid,
|
payload = {
|
||||||
consumer_uuid, data,
|
"allocations": {
|
||||||
mock.sentinel.project_id,
|
rp_uuid: {"resources": data}
|
||||||
mock.sentinel.user_id,
|
},
|
||||||
mock.sentinel.consumer_generation)
|
"project_id": mock.sentinel.project_id,
|
||||||
|
"user_id": mock.sentinel.user_id,
|
||||||
|
"consumer_generation": mock.sentinel.consumer_generation
|
||||||
|
}
|
||||||
|
resp = self.client.put_allocations(
|
||||||
|
self.context, consumer_uuid, payload)
|
||||||
self.assertTrue(resp)
|
self.assertTrue(resp)
|
||||||
mock_put.assert_has_calls([
|
mock_put.assert_has_calls([
|
||||||
mock.call(expected_url, mock.ANY, version='1.28',
|
mock.call(expected_url, payload, version='1.28',
|
||||||
global_request_id=self.context.global_id)] * 2)
|
global_request_id=self.context.global_id)] * 2)
|
||||||
|
|
||||||
@mock.patch('time.sleep', new=mock.Mock())
|
@mock.patch('time.sleep', new=mock.Mock())
|
||||||
|
@ -369,14 +389,19 @@ class TestPutAllocations(SchedulerReportClientTestCase):
|
||||||
consumer_uuid = mock.sentinel.consumer
|
consumer_uuid = mock.sentinel.consumer
|
||||||
data = {"MEMORY_MB": 1024}
|
data = {"MEMORY_MB": 1024}
|
||||||
expected_url = "/allocations/%s" % consumer_uuid
|
expected_url = "/allocations/%s" % consumer_uuid
|
||||||
resp = self.client.put_allocations(self.context, rp_uuid,
|
payload = {
|
||||||
consumer_uuid, data,
|
"allocations": {
|
||||||
mock.sentinel.project_id,
|
rp_uuid: {"resources": data}
|
||||||
mock.sentinel.user_id,
|
},
|
||||||
mock.sentinel.consumer_generation)
|
"project_id": mock.sentinel.project_id,
|
||||||
|
"user_id": mock.sentinel.user_id,
|
||||||
|
"consumer_generation": mock.sentinel.consumer_generation
|
||||||
|
}
|
||||||
|
resp = self.client.put_allocations(
|
||||||
|
self.context, consumer_uuid, payload)
|
||||||
self.assertFalse(resp)
|
self.assertFalse(resp)
|
||||||
mock_put.assert_has_calls([
|
mock_put.assert_has_calls([
|
||||||
mock.call(expected_url, mock.ANY, version='1.28',
|
mock.call(expected_url, payload, version='1.28',
|
||||||
global_request_id=self.context.global_id)] * 3)
|
global_request_id=self.context.global_id)] * 3)
|
||||||
|
|
||||||
def test_claim_resources_success(self):
|
def test_claim_resources_success(self):
|
||||||
|
|
|
@ -21,6 +21,7 @@ import ddt
|
||||||
import fixtures
|
import fixtures
|
||||||
import mock
|
import mock
|
||||||
from oslo_db import exception as db_exc
|
from oslo_db import exception as db_exc
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
from oslo_utils.fixture import uuidsentinel
|
from oslo_utils.fixture import uuidsentinel
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
from six.moves import StringIO
|
from six.moves import StringIO
|
||||||
|
@ -2469,8 +2470,9 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
return_value=objects.ComputeNode(uuid=uuidsentinel.node))
|
return_value=objects.ComputeNode(uuid=uuidsentinel.node))
|
||||||
@mock.patch('nova.scheduler.utils.resources_from_flavor',
|
@mock.patch('nova.scheduler.utils.resources_from_flavor',
|
||||||
return_value=mock.sentinel.resources)
|
return_value=mock.sentinel.resources)
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.put',
|
||||||
'put_allocations', return_value=False)
|
return_value=fake_requests.FakeResponse(
|
||||||
|
500, content=jsonutils.dumps({"errors": [{"code": ""}]})))
|
||||||
def test_heal_allocations_put_allocations_fails(
|
def test_heal_allocations_put_allocations_fails(
|
||||||
self, mock_put_allocations, mock_res_from_flavor,
|
self, mock_put_allocations, mock_res_from_flavor,
|
||||||
mock_get_compute_node, mock_get_allocs, mock_get_instances,
|
mock_get_compute_node, mock_get_allocs, mock_get_instances,
|
||||||
|
@ -2481,46 +2483,20 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
instance = mock_get_instances.return_value[0]
|
instance = mock_get_instances.return_value[0]
|
||||||
mock_res_from_flavor.assert_called_once_with(
|
mock_res_from_flavor.assert_called_once_with(
|
||||||
instance, instance.flavor)
|
instance, instance.flavor)
|
||||||
mock_put_allocations.assert_called_once_with(
|
|
||||||
test.MatchType(context.RequestContext), uuidsentinel.node,
|
|
||||||
uuidsentinel.instance, mock.sentinel.resources, 'fake-project',
|
|
||||||
'fake-user', consumer_generation=None)
|
|
||||||
|
|
||||||
@mock.patch('nova.objects.CellMappingList.get_all',
|
expected_payload = {
|
||||||
return_value=objects.CellMappingList(objects=[
|
'allocations': {
|
||||||
objects.CellMapping(name='cell1',
|
uuidsentinel.node: {
|
||||||
uuid=uuidsentinel.cell1)]))
|
'resources': mock.sentinel.resources
|
||||||
@mock.patch('nova.objects.InstanceList.get_by_filters',
|
}
|
||||||
return_value=objects.InstanceList(objects=[
|
},
|
||||||
objects.Instance(
|
'user_id': 'fake-user',
|
||||||
uuid=uuidsentinel.instance, host='fake', node='fake',
|
'project_id': 'fake-project',
|
||||||
task_state=None, flavor=objects.Flavor(),
|
'consumer_generation': None
|
||||||
project_id='fake-project', user_id='fake-user')]))
|
}
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
|
||||||
'get_allocs_for_consumer', return_value={})
|
|
||||||
@mock.patch('nova.objects.ComputeNode.get_by_host_and_nodename',
|
|
||||||
return_value=objects.ComputeNode(uuid=uuidsentinel.node))
|
|
||||||
@mock.patch('nova.scheduler.utils.resources_from_flavor',
|
|
||||||
return_value=mock.sentinel.resources)
|
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
|
||||||
'put_allocations',
|
|
||||||
side_effect=exception.AllocationUpdateFailed(
|
|
||||||
consumer_uuid=uuidsentinel.instance,
|
|
||||||
error="consumer generation conflict"))
|
|
||||||
def test_heal_allocations_put_allocations_fails_with_consumer_conflict(
|
|
||||||
self, mock_put_allocations, mock_res_from_flavor,
|
|
||||||
mock_get_compute_node, mock_get_allocs, mock_get_instances,
|
|
||||||
mock_get_all_cells):
|
|
||||||
self.assertEqual(3, self.cli.heal_allocations())
|
|
||||||
self.assertIn('Failed to update allocations for consumer',
|
|
||||||
self.output.getvalue())
|
|
||||||
instance = mock_get_instances.return_value[0]
|
|
||||||
mock_res_from_flavor.assert_called_once_with(
|
|
||||||
instance, instance.flavor)
|
|
||||||
mock_put_allocations.assert_called_once_with(
|
mock_put_allocations.assert_called_once_with(
|
||||||
test.MatchType(context.RequestContext), uuidsentinel.node,
|
'/allocations/%s' % instance.uuid, expected_payload,
|
||||||
uuidsentinel.instance, mock.sentinel.resources, 'fake-project',
|
global_request_id=mock.ANY, version='1.28')
|
||||||
'fake-user', consumer_generation=None)
|
|
||||||
|
|
||||||
@mock.patch('nova.objects.CellMappingList.get_all',
|
@mock.patch('nova.objects.CellMappingList.get_all',
|
||||||
new=mock.Mock(return_value=objects.CellMappingList(objects=[
|
new=mock.Mock(return_value=objects.CellMappingList(objects=[
|
||||||
|
@ -2560,8 +2536,8 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
return_value=objects.ComputeNode(uuid=uuidsentinel.node)))
|
return_value=objects.ComputeNode(uuid=uuidsentinel.node)))
|
||||||
@mock.patch('nova.scheduler.utils.resources_from_flavor',
|
@mock.patch('nova.scheduler.utils.resources_from_flavor',
|
||||||
new=mock.Mock(return_value=mock.sentinel.resources))
|
new=mock.Mock(return_value=mock.sentinel.resources))
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.'
|
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.put',
|
||||||
'put_allocations', return_value=True)
|
return_value=fake_requests.FakeResponse(204))
|
||||||
def test_heal_allocations_get_allocs_retrieval_fails(self, mock_put,
|
def test_heal_allocations_get_allocs_retrieval_fails(self, mock_put,
|
||||||
mock_getinst):
|
mock_getinst):
|
||||||
# This "succeeds"
|
# This "succeeds"
|
||||||
|
@ -2612,7 +2588,8 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"project_id": uuidsentinel.project_id,
|
"project_id": uuidsentinel.project_id,
|
||||||
"user_id": uuidsentinel.user_id
|
"user_id": uuidsentinel.user_id,
|
||||||
|
"consumer_generation": 12,
|
||||||
}
|
}
|
||||||
self.assertEqual(0, self.cli.heal_allocations(verbose=True))
|
self.assertEqual(0, self.cli.heal_allocations(verbose=True))
|
||||||
self.assertIn('Processed 1 instances.', self.output.getvalue())
|
self.assertIn('Processed 1 instances.', self.output.getvalue())
|
||||||
|
@ -2623,7 +2600,7 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
expected_put_data['user_id'] = 'fake-user'
|
expected_put_data['user_id'] = 'fake-user'
|
||||||
mock_put.assert_called_once_with(
|
mock_put.assert_called_once_with(
|
||||||
'/allocations/%s' % uuidsentinel.instance, expected_put_data,
|
'/allocations/%s' % uuidsentinel.instance, expected_put_data,
|
||||||
version='1.28')
|
global_request_id=mock.ANY, version='1.28')
|
||||||
|
|
||||||
@mock.patch('nova.objects.CellMappingList.get_all',
|
@mock.patch('nova.objects.CellMappingList.get_all',
|
||||||
return_value=objects.CellMappingList(objects=[
|
return_value=objects.CellMappingList(objects=[
|
||||||
|
@ -2639,8 +2616,11 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
'get_allocs_for_consumer')
|
'get_allocs_for_consumer')
|
||||||
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.put',
|
@mock.patch('nova.scheduler.client.report.SchedulerReportClient.put',
|
||||||
return_value=fake_requests.FakeResponse(
|
return_value=fake_requests.FakeResponse(
|
||||||
409, content='Inventory and/or allocations changed while '
|
409,
|
||||||
'attempting to allocate'))
|
content=jsonutils.dumps(
|
||||||
|
{"errors": [
|
||||||
|
{"code": "placement.concurrent_update",
|
||||||
|
"detail": "consumer generation conflict"}]})))
|
||||||
def test_heal_allocations_put_fails(
|
def test_heal_allocations_put_fails(
|
||||||
self, mock_put, mock_get_allocs, mock_get_instances,
|
self, mock_put, mock_get_allocs, mock_get_instances,
|
||||||
mock_get_all_cells):
|
mock_get_all_cells):
|
||||||
|
@ -2666,7 +2646,7 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
}
|
}
|
||||||
self.assertEqual(3, self.cli.heal_allocations(verbose=True))
|
self.assertEqual(3, self.cli.heal_allocations(verbose=True))
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
'Inventory and/or allocations changed', self.output.getvalue())
|
'consumer generation conflict', self.output.getvalue())
|
||||||
mock_get_allocs.assert_called_once_with(
|
mock_get_allocs.assert_called_once_with(
|
||||||
test.MatchType(context.RequestContext), uuidsentinel.instance)
|
test.MatchType(context.RequestContext), uuidsentinel.instance)
|
||||||
expected_put_data = mock_get_allocs.return_value
|
expected_put_data = mock_get_allocs.return_value
|
||||||
|
@ -2674,7 +2654,7 @@ class TestNovaManagePlacement(test.NoDBTestCase):
|
||||||
expected_put_data['user_id'] = 'fake-user'
|
expected_put_data['user_id'] = 'fake-user'
|
||||||
mock_put.assert_called_once_with(
|
mock_put.assert_called_once_with(
|
||||||
'/allocations/%s' % uuidsentinel.instance, expected_put_data,
|
'/allocations/%s' % uuidsentinel.instance, expected_put_data,
|
||||||
version='1.28')
|
global_request_id=mock.ANY, version='1.28')
|
||||||
|
|
||||||
@mock.patch('nova.compute.api.AggregateAPI.get_aggregate_list',
|
@mock.patch('nova.compute.api.AggregateAPI.get_aggregate_list',
|
||||||
return_value=objects.AggregateList(objects=[
|
return_value=objects.AggregateList(objects=[
|
||||||
|
|
Loading…
Reference in New Issue