Skip to content

Commit e6f7425

Browse files
author
Eric Fried
committed
Nix os-server-external-events 404 condition
The POST /os-server-external-events API had the following confusing behavior: With multiple events in the payload, if *some* (but not all) were dropped, the HTTP response was 207, with per-event 4xx error codes in the payload. But if *all* of the events were dropped, the overall HTTP response was 404 with no payload. Thus, especially for consumers sending only one event at a time, it was impossible to distinguish e.g. "you tried to send an event for a nonexistent instance" from "the instance you specified hasn't landed on a host yet". This fix gets rid of that sweeping 404 condition, so if *any* subset of the events are dropped (including *all* of them), the HTTP response will always be 207, and the payload will always contain granular per-event error codes. This effectively means the API can no longer return 404, ever. Closes-Bug: #1855752 Change-Id: Ibad1b51e2cf50d00102295039b6e82bc00bec058
1 parent e937c5c commit e6f7425

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

api-ref/source/os-server-external-events.inc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ updated ``code`` and ``status`` indicating their level of success.
3232
Normal response codes: 200, 207
3333

3434
A 200 will be returned if all events succeeded, 207 will be returned
35-
if some events could not be processed. The ``code`` attribute for the
35+
if any events could not be processed. The ``code`` attribute for the
3636
event will explain further what went wrong.
3737

38-
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
39-
itemNotFound(404)
38+
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
39+
40+
.. note:: Prior to the fix for `bug 1855752`_, error response code 404 may be
41+
erroneously returned when all events failed.
42+
43+
.. _bug 1855752: https://bugs.launchpad.net/nova/+bug/1855752
4044

4145
Request
4246
-------

nova/api/openstack/compute/server_external_events.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313
# under the License.
1414

1515
from oslo_log import log as logging
16-
import webob
1716

1817
from nova.api.openstack.compute.schemas import server_external_events
1918
from nova.api.openstack import wsgi
2019
from nova.api import validation
2120
from nova.compute import api as compute
2221
from nova import context as nova_context
23-
from nova.i18n import _
2422
from nova import objects
2523
from nova.policies import server_external_events as see_policies
2624

@@ -65,7 +63,7 @@ def _get_instances_all_cells(self, context, instance_uuids,
6563

6664
return instances
6765

68-
@wsgi.expected_errors((403, 404))
66+
@wsgi.expected_errors(403)
6967
@wsgi.response(200)
7068
@validation.schema(server_external_events.create, '2.0', '2.50')
7169
@validation.schema(server_external_events.create_v251, '2.51', '2.75')
@@ -146,9 +144,6 @@ def create(self, req, body):
146144
if accepted_events:
147145
self.compute_api.external_instance_event(
148146
context, accepted_instances, accepted_events)
149-
else:
150-
msg = _('No instances found for any event')
151-
raise webob.exc.HTTPNotFound(explanation=msg)
152147

153148
# FIXME(cyeoh): This needs some infrastructure support so that
154149
# we have a general way to do this

nova/tests/unit/api/openstack/compute/test_server_external_events.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import mock
1717
from oslo_utils.fixture import uuidsentinel as uuids
1818
import six
19-
import webob
2019

2120
from nova.api.openstack.compute import server_external_events \
2221
as server_external_events_v21
@@ -108,12 +107,17 @@ def _assert_call(self, body, expected_uuids, expected_events):
108107
result = response.obj
109108
code = response._code
110109

111-
self.assertEqual(1, api_method.call_count)
112-
call = api_method.call_args_list[0]
113-
args = call[0]
110+
if expected_events:
111+
self.assertEqual(1, api_method.call_count)
112+
call = api_method.call_args_list[0]
113+
args = call[0]
114114

115-
call_instances = args[1]
116-
call_events = args[2]
115+
call_instances = args[1]
116+
call_events = args[2]
117+
else:
118+
self.assertEqual(0, api_method.call_count)
119+
call_instances = []
120+
call_events = []
117121

118122
self.assertEqual(set(expected_uuids),
119123
set([instance.uuid for instance in call_instances]))
@@ -157,11 +161,14 @@ def test_create_event_instance_has_no_host(self):
157161
self.assertEqual(207, code)
158162

159163
def test_create_no_good_instances(self):
164+
"""Always 207 with granular codes even if all fail; see bug 1855752."""
160165
body = self.default_body
161166
body['events'][0]['server_uuid'] = MISSING_UUID
162-
body['events'][1]['server_uuid'] = MISSING_UUID
163-
self.assertRaises(webob.exc.HTTPNotFound,
164-
self.api.create, self.req, body=body)
167+
body['events'][1]['server_uuid'] = fake_instance_uuids[-1]
168+
result, code = self._assert_call(body, [], [])
169+
self.assertEqual(404, result['events'][0]['code'])
170+
self.assertEqual(422, result['events'][1]['code'])
171+
self.assertEqual(207, code)
165172

166173
def test_create_bad_status(self):
167174
body = self.default_body

0 commit comments

Comments
 (0)