summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2019-11-04 11:52:51 +0000
committerGerrit Code Review <review@openstack.org>2019-11-04 11:52:51 +0000
commitc9f2e603d754660e5122992a1bcc28376ce699dc (patch)
tree01c476bbb0866770ad7163d9708a9f0298932e5c
parent9e8f1f2b8eb865433d2c70c8ff5f2626f13b8ad1 (diff)
parent32dbd2f585ef1902478170f3a1153b1f71e81db3 (diff)
downloadnova-20.0.1.tar.gz
Merge "Avoid error 500 on shelve task_state race" into stable/train20.0.1
-rw-r--r--nova/api/openstack/compute/shelve.py3
-rw-r--r--nova/tests/unit/api/openstack/compute/test_shelve.py17
2 files changed, 19 insertions, 1 deletions
diff --git a/nova/api/openstack/compute/shelve.py b/nova/api/openstack/compute/shelve.py
index b08a4ac7e9..ae8bea989c 100644
--- a/nova/api/openstack/compute/shelve.py
+++ b/nova/api/openstack/compute/shelve.py
@@ -48,7 +48,8 @@ class ShelveController(wsgi.Controller):
'project_id': instance.project_id})
try:
self.compute_api.shelve(context, instance)
- except exception.InstanceIsLocked as e:
+ except (exception.InstanceIsLocked,
+ exception.UnexpectedTaskStateError) as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error,
diff --git a/nova/tests/unit/api/openstack/compute/test_shelve.py b/nova/tests/unit/api/openstack/compute/test_shelve.py
index 88488b9b33..8d41490d86 100644
--- a/nova/tests/unit/api/openstack/compute/test_shelve.py
+++ b/nova/tests/unit/api/openstack/compute/test_shelve.py
@@ -21,6 +21,7 @@ import webob
from nova.api.openstack import api_version_request
from nova.api.openstack.compute import shelve as shelve_v21
+from nova.compute import task_states
from nova.compute import vm_states
from nova import exception
from nova import policy
@@ -47,6 +48,22 @@ class ShelvePolicyTestV21(test.NoDBTestCase):
self.req, uuidsentinel.fake, {})
@mock.patch('nova.api.openstack.common.get_instance')
+ @mock.patch('nova.objects.instance.Instance.save')
+ def test_shelve_task_state_race(self, mock_save, get_instance_mock):
+ instance = fake_instance.fake_instance_obj(
+ self.req.environ['nova.context'],
+ vm_state=vm_states.ACTIVE, task_state=None)
+ instance.launched_at = instance.created_at
+ get_instance_mock.return_value = instance
+ mock_save.side_effect = exception.UnexpectedTaskStateError(
+ instance_uuid=instance.uuid, expected=None,
+ actual=task_states.SHELVING)
+ ex = self.assertRaises(webob.exc.HTTPConflict, self.controller._shelve,
+ self.req, uuidsentinel.fake, body={'shelve': {}})
+ self.assertIn('Conflict updating instance', six.text_type(ex))
+ mock_save.assert_called_once_with(expected_task_state=[None])
+
+ @mock.patch('nova.api.openstack.common.get_instance')
def test_unshelve_locked_server(self, get_instance_mock):
get_instance_mock.return_value = (
fake_instance.fake_instance_obj(self.req.environ['nova.context']))