diff --git a/api-ref/source/os-instance-actions.inc b/api-ref/source/os-instance-actions.inc index 9e2530703bde..df961d45e9b1 100644 --- a/api-ref/source/os-instance-actions.inc +++ b/api-ref/source/os-instance-actions.inc @@ -111,14 +111,16 @@ Response - events.finish_time: event_finish_time - events.result: event_result - events.traceback: event_traceback + - events.hostId: event_hostId + - events.host: event_host - updated_at: updated_instance_action -**Example Show Server Action Details For Admin (v2.1)** +**Example Show Server Action Details For Admin (v2.62)** -.. literalinclude:: ../../doc/api_samples/os-instance-actions/instance-action-get-resp.json +.. literalinclude:: ../../doc/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json :language: javascript -**Example Show Server Action Details For Non-Admin (v2.51)** +**Example Show Server Action Details For Non-Admin (v2.62)** -.. literalinclude:: ../../doc/api_samples/os-instance-actions/v2.51/instance-action-get-non-admin-resp.json +.. literalinclude:: ../../doc/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json :language: javascript diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index e3c1be0664ca..a1926f811de8 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -2357,6 +2357,29 @@ event_finish_time: in: body required: true type: string +event_host: + min_version: 2.62 + description: | + The name of the host on which the event occurred. + + Policy defaults enable only users with the administrative role to see + an instance action event host. Cloud providers can change these + permissions through the ``policy.json`` file. + in: body + required: false + type: string +event_hostId: + min_version: 2.62 + description: | + An obfuscated hashed host ID string, or the empty string if there is no + host for the event. This is a hashed value so will not actually look like + a hostname, and is hashed with data from the project_id, so the same + physical host as seen by two different project_ids will be different. + This is useful when within the same project you need to determine if two + events occurred on the same or different physical hosts. + in: body + required: true + type: string event_name: description: | The event name. A valid value is ``network-changed``, ``network-vif-plugged``, diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json b/doc/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json new file mode 100644 index 000000000000..115604d6ac89 --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json @@ -0,0 +1,21 @@ +{ + "instanceAction": { + "action": "stop", + "events": [ + { + "event": "compute_stop_instance", + "finish_time": "2018-04-25T01:26:34.784165", + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "result": "Success", + "start_time": "2018-04-25T01:26:34.612020" + } + ], + "instance_uuid": "79edaa44-ad4f-4af7-b994-154518c2b927", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-8eb28d4a-db6c-4337-bab8-ce154e9c620e", + "start_time": "2018-04-25T01:26:34.388280", + "updated_at": "2018-04-25T01:26:34.784165", + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json b/doc/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json new file mode 100644 index 000000000000..57ae490f023f --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json @@ -0,0 +1,23 @@ +{ + "instanceAction": { + "action": "stop", + "events": [ + { + "event": "compute_stop_instance", + "finish_time": "2018-04-25T01:26:36.790544", + "host": "compute", + "hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6", + "result": "Success", + "start_time": "2018-04-25T01:26:36.539271", + "traceback": null + } + ], + "instance_uuid": "4bf3473b-d550-4b65-9409-292d44ab14a2", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-0d819d5c-1527-4669-bdf0-ffad31b5105b", + "start_time": "2018-04-25T01:26:36.341290", + "updated_at": "2018-04-25T01:26:36.790544", + "user_id": "admin" + } +} \ No newline at end of file diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json new file mode 100644 index 000000000000..0b2254126b1d --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json @@ -0,0 +1,24 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "15835b6f-1e14-4cfa-9f66-1abea1a1c0d5", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-f04d4b92-6241-42da-b82d-2cedb225c58d", + "start_time": "2018-04-25T01:26:36.036697", + "updated_at": "2018-04-25T01:26:36.525308", + "user_id": "admin" + }, + { + "action": "create", + "instance_uuid": "15835b6f-1e14-4cfa-9f66-1abea1a1c0d5", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-d8790618-9bbf-4df0-8af8-fc9e24de29c0", + "start_time": "2018-04-25T01:26:33.692125", + "updated_at": "2018-04-25T01:26:35.993821", + "user_id": "admin" + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json new file mode 100644 index 000000000000..8b2c3bfd8e5c --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json @@ -0,0 +1,20 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "7a580cc0-3469-441a-9736-d5fce91003f9", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-b8ffb713-61a2-4e7c-a705-37052cba9d6e", + "start_time": "2018-04-25T01:26:28.955571", + "updated_at": "2018-04-25T01:26:29.414973", + "user_id": "fake" + } + ], + "links": [ + { + "href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/7a580cc0-3469-441a-9736-d5fce91003f9/os-instance-actions?limit=1&marker=req-b8ffb713-61a2-4e7c-a705-37052cba9d6e", + "rel": "next" + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json new file mode 100644 index 000000000000..3f6921cb795e --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json @@ -0,0 +1,14 @@ +{ + "instanceActions": [ + { + "action": "create", + "instance_uuid": "9bde1fd5-8435-45c5-afc1-bedd0605275b", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-4510fb10-447f-4572-a64d-c2324547d86c", + "start_time": "2018-04-25T01:26:33.710291", + "updated_at": "2018-04-25T01:26:35.374936", + "user_id": "fake" + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json new file mode 100644 index 000000000000..346c93af7a93 --- /dev/null +++ b/doc/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json @@ -0,0 +1,14 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "2150964c-30fe-4214-9547-8822375aa7d0", + "message": null, + "project_id": "6f70656e737461636b20342065766572", + "request_id": "req-0c3b2079-0a44-474d-a5b2-7466d4b4c642", + "start_time": "2018-04-25T01:26:29.594237", + "updated_at": "2018-04-25T01:26:30.065061", + "user_id": "admin" + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/versions/v21-version-get-resp.json b/doc/api_samples/versions/v21-version-get-resp.json index 6e50403cbabd..a25c2b0a4e25 100644 --- a/doc/api_samples/versions/v21-version-get-resp.json +++ b/doc/api_samples/versions/v21-version-get-resp.json @@ -19,7 +19,7 @@ } ], "status": "CURRENT", - "version": "2.61", + "version": "2.62", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/doc/api_samples/versions/versions-get-resp.json b/doc/api_samples/versions/versions-get-resp.json index 4d3c06a7caff..d4a531ca3503 100644 --- a/doc/api_samples/versions/versions-get-resp.json +++ b/doc/api_samples/versions/versions-get-resp.json @@ -22,7 +22,7 @@ } ], "status": "CURRENT", - "version": "2.61", + "version": "2.62", "min_version": "2.1", "updated": "2013-07-23T11:33:21Z" } diff --git a/nova/api/openstack/api_version_request.py b/nova/api/openstack/api_version_request.py index 4df2854c3592..12929d4ccc4c 100644 --- a/nova/api/openstack/api_version_request.py +++ b/nova/api/openstack/api_version_request.py @@ -146,6 +146,8 @@ REST_API_VERSION_HISTORY = """REST API Version History: * 2.61 - Exposes flavor extra_specs in the flavor representation. Flavor extra_specs will be included in Response body of GET, POST, PUT /flavors APIs. + * 2.62 - Add ``host`` and ``hostId`` fields to instance action detail API + responses. """ # The minimum and maximum versions of the API supported @@ -154,7 +156,7 @@ REST_API_VERSION_HISTORY = """REST API Version History: # Note(cyeoh): This only applies for the v2.1 API once microversions # support is fully merged. It does not affect the V2 API. _MIN_API_VERSION = "2.1" -_MAX_API_VERSION = "2.61" +_MAX_API_VERSION = "2.62" DEFAULT_API_VERSION = _MIN_API_VERSION # Almost all proxy APIs which are related to network, images and baremetal diff --git a/nova/api/openstack/compute/instance_actions.py b/nova/api/openstack/compute/instance_actions.py index f859131756df..aef7440340ce 100644 --- a/nova/api/openstack/compute/instance_actions.py +++ b/nova/api/openstack/compute/instance_actions.py @@ -53,13 +53,20 @@ class InstanceActionsController(wsgi.Controller): action[key] = action_raw.get(key) return action - def _format_event(self, event_raw, show_traceback=False): + def _format_event(self, event_raw, project_id, show_traceback=False, + show_host=False, show_hostid=False): event = {} for key in EVENT_KEYS: # By default, non-admins are not allowed to see traceback details. if key == 'traceback' and not show_traceback: continue event[key] = event_raw.get(key) + # By default, non-admins are not allowed to see host. + if show_host: + event['host'] = event_raw['host'] + if show_hostid: + event['hostId'] = utils.generate_hostid(event_raw['host'], + project_id) return event @wsgi.Controller.api_version("2.1", "2.20") @@ -138,18 +145,26 @@ class InstanceActionsController(wsgi.Controller): # by default. show_events = False show_traceback = False + show_host = False if context.can(ia_policies.POLICY_ROOT % 'events', fatal=False): # For all microversions, the user can see all event details # including the traceback. show_events = show_traceback = True + show_host = api_version_request.is_supported(req, '2.62') elif api_version_request.is_supported(req, '2.51'): # The user is not able to see all event details, but they can at # least see the non-traceback event details. show_events = True + # An obfuscated hashed host id is returned since microversion 2.62 + # for all users. + show_hostid = api_version_request.is_supported(req, '2.62') + if show_events: events_raw = self.action_api.action_events_get(context, instance, action_id) - action['events'] = [self._format_event(evt, show_traceback) - for evt in events_raw] + action['events'] = [self._format_event( + evt, action['project_id'], show_traceback=show_traceback, + show_host=show_host, show_hostid=show_hostid + ) for evt in events_raw] return {'instanceAction': action} diff --git a/nova/api/openstack/compute/rest_api_version_history.rst b/nova/api/openstack/compute/rest_api_version_history.rst index 42ff34513556..b1042f22fb15 100644 --- a/nova/api/openstack/compute/rest_api_version_history.rst +++ b/nova/api/openstack/compute/rest_api_version_history.rst @@ -780,3 +780,14 @@ Response body of the following APIs: * ``GET /flavors/{flavor_id}`` * ``POST /flavors`` * ``PUT /flavors/{flavor_id}`` + +2.62 +---- + +Adds ``host`` (hostname) and ``hostId`` (an obfuscated hashed host id string) +fields to the instance action +``GET /servers/{server_id}/os-instance-actions/{req_id}`` API. The display of +the newly added ``host`` field will be controlled via policy rule +``os_compute_api:os-instance-actions:events``, which is the same policy used +for the ``events.traceback`` field. If the user is prevented by policy, only +``hostId`` will be displayed. diff --git a/nova/policies/instance_actions.py b/nova/policies/instance_actions.py index 46a1e0df67d9..3d800b2bd62d 100644 --- a/nova/policies/instance_actions.py +++ b/nova/policies/instance_actions.py @@ -31,7 +31,10 @@ instance_actions_policies = [ This check is performed only after the check os_compute_api:os-instance-actions passes. Beginning with Microversion 2.51, events details are always included; traceback -information is provided per event if policy enforcement passes.""", +information is provided per event if policy enforcement passes. +Beginning with Microversion 2.62, each event includes a hashed +host identifier and, if policy enforcement passes, the name of +the host.""", [ { 'method': 'GET', diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json.tpl new file mode 100644 index 000000000000..7641428d17e6 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-non-admin-resp.json.tpl @@ -0,0 +1,21 @@ +{ + "instanceAction": { + "action": "stop", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null, + "events": [ + { + "event": "compute_stop_instance", + "start_time": "%(strtime)s", + "finish_time": "%(strtime)s", + "result": "Success", + "hostId": "%(event_hostId)s" + } + ] + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json.tpl new file mode 100644 index 000000000000..fe3a4eec8fcd --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-action-get-resp.json.tpl @@ -0,0 +1,23 @@ +{ + "instanceAction": { + "action": "stop", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null, + "events": [ + { + "event": "compute_stop_instance", + "start_time": "%(strtime)s", + "finish_time": "%(strtime)s", + "result": "Success", + "traceback": null, + "host": "%(event_host)s", + "hostId": "%(event_hostId)s" + } + ] + } +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json.tpl new file mode 100644 index 000000000000..19161da37483 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-resp.json.tpl @@ -0,0 +1,24 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null + }, + { + "action": "create", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json.tpl new file mode 100644 index 000000000000..dedbd8d8addc --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-limit-resp.json.tpl @@ -0,0 +1,20 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null + } + ], + "links": [ + { + "href": "%(versioned_compute_endpoint)s/servers/%(uuid)s/os-instance-actions?limit=1&marker=%(request_id)s", + "rel": "next" + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json.tpl new file mode 100644 index 000000000000..3e1f1efa8bb0 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-marker-resp.json.tpl @@ -0,0 +1,14 @@ +{ + "instanceActions": [ + { + "action": "create", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json.tpl new file mode 100644 index 000000000000..4b81af86b045 --- /dev/null +++ b/nova/tests/functional/api_sample_tests/api_samples/os-instance-actions/v2.62/instance-actions-list-with-timestamp-filter.json.tpl @@ -0,0 +1,14 @@ +{ + "instanceActions": [ + { + "action": "stop", + "instance_uuid": "%(uuid)s", + "request_id": "%(request_id)s", + "user_id": "%(user_id)s", + "project_id": "%(project_id)s", + "start_time": "%(strtime)s", + "updated_at": "%(strtime)s", + "message": null + } + ] +} diff --git a/nova/tests/functional/api_sample_tests/test_instance_actions.py b/nova/tests/functional/api_sample_tests/test_instance_actions.py index c36c62ceadc6..44b6c44be93c 100644 --- a/nova/tests/functional/api_sample_tests/test_instance_actions.py +++ b/nova/tests/functional/api_sample_tests/test_instance_actions.py @@ -122,3 +122,20 @@ class ServerActionsV258SampleJsonTest(ServerActionsV251AdminSampleJsonTest): class ServerActionsV258NonAdminSampleJsonTest(ServerActionsV258SampleJsonTest): ADMIN_API = False + + +class ServerActionsV262SampleJsonTest(ServerActionsV258SampleJsonTest): + microversion = '2.62' + scenarios = [('v2_62', {'api_major_version': 'v2.1'})] + + def _get_subs(self): + return { + 'uuid': self.uuid, + 'project_id': self.action_stop['project_id'], + 'event_host': r'\w+', + 'event_hostId': '[a-f0-9]+' + } + + +class ServerActionsV262NonAdminSampleJsonTest(ServerActionsV262SampleJsonTest): + ADMIN_API = False diff --git a/nova/tests/unit/api/openstack/compute/test_instance_actions.py b/nova/tests/unit/api/openstack/compute/test_instance_actions.py index 861baeb682e0..5b70f99787c6 100644 --- a/nova/tests/unit/api/openstack/compute/test_instance_actions.py +++ b/nova/tests/unit/api/openstack/compute/test_instance_actions.py @@ -38,7 +38,8 @@ FAKE_EVENT_ID = fake_server_actions.FAKE_ACTION_ID1 FAKE_REQUEST_NOTFOUND_ID = 'req-' + uuids.req_not_found -def format_action(action, expect_traceback=True): +def format_action(action, expect_traceback=True, expect_host=False, + expect_hostId=False): '''Remove keys that aren't serialized.''' to_delete = ('id', 'finish_time', 'created_at', 'updated_at', 'deleted_at', 'deleted') @@ -49,11 +50,14 @@ def format_action(action, expect_traceback=True): # NOTE(danms): Without WSGI above us, these will be just stringified action['start_time'] = str(action['start_time'].replace(tzinfo=None)) for event in action.get('events', []): - format_event(event, expect_traceback) + format_event(event, action.get('project_id'), + expect_traceback=expect_traceback, + expect_host=expect_host, expect_hostId=expect_hostId) return action -def format_event(event, expect_traceback=True, expect_host=False): +def format_event(event, project_id, expect_traceback=True, expect_host=False, + expect_hostId=False): '''Remove keys that aren't serialized.''' to_delete = ['id', 'created_at', 'updated_at', 'deleted_at', 'deleted', 'action_id'] @@ -61,6 +65,8 @@ def format_event(event, expect_traceback=True, expect_host=False): to_delete.append('traceback') if not expect_host: to_delete.append('host') + if not expect_hostId: + to_delete.append('hostId') for key in to_delete: if key in event: del(event[key]) @@ -116,6 +122,8 @@ class InstanceActionsTestV21(test.NoDBTestCase): instance_actions = instance_actions_v21 wsgi_api_version = os_wsgi.DEFAULT_API_VERSION expect_events_non_admin = False + expect_event_hostId = False + expect_event_host = False def fake_get(self, context, instance_uuid, expected_attrs=None): return objects.Instance(uuid=instance_uuid) @@ -181,8 +189,12 @@ class InstanceActionsTestV21(test.NoDBTestCase): fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID] fake_events = self.fake_events[fake_action['id']] fake_action['events'] = fake_events - self.assertEqual(format_action(fake_action), - format_action(res_dict['instanceAction'])) + self.assertEqual(format_action(fake_action, + expect_host=self.expect_event_host, + expect_hostId=self.expect_event_hostId), + format_action(res_dict['instanceAction'], + expect_host=self.expect_event_host, + expect_hostId=self.expect_event_hostId)) def test_get_action_with_events_not_allowed(self): def fake_get_action(context, uuid, request_id): @@ -201,10 +213,16 @@ class InstanceActionsTestV21(test.NoDBTestCase): if self.expect_events_non_admin: fake_event = fake_server_actions.FAKE_EVENTS[FAKE_EVENT_ID] fake_action['events'] = copy.deepcopy(fake_event) - # By default, non-admins are not allowed to see traceback details. - self.assertEqual(format_action(fake_action, expect_traceback=False), + # By default, non-admins are not allowed to see traceback details + # and event host. + self.assertEqual(format_action(fake_action, + expect_traceback=False, + expect_host=False, + expect_hostId=self.expect_event_hostId), format_action(res_dict['instanceAction'], - expect_traceback=False)) + expect_traceback=False, + expect_host=False, + expect_hostId=self.expect_event_hostId)) def test_action_not_found(self): def fake_no_action(context, uuid, action_id): @@ -294,3 +312,9 @@ class InstanceActionsTestV258(InstanceActionsTestV251): self.controller.index, req) self.assertIn('Invalid input for query parameters marker', six.text_type(ex)) + + +class InstanceActionsTestV262(InstanceActionsTestV251): + wsgi_api_version = "2.62" + expect_event_hostId = True + expect_event_host = True diff --git a/nova/tests/unit/fake_server_actions.py b/nova/tests/unit/fake_server_actions.py index e3ddee228941..5193f32c1b0a 100644 --- a/nova/tests/unit/fake_server_actions.py +++ b/nova/tests/unit/fake_server_actions.py @@ -20,6 +20,8 @@ FAKE_REQUEST_ID1 = 'req-3293a3f1-b44c-4609-b8d2-d81b105636b8' FAKE_REQUEST_ID2 = 'req-25517360-b757-47d3-be45-0e8d2a01b36a' FAKE_ACTION_ID1 = 123 FAKE_ACTION_ID2 = 456 +FAKE_HOST_ID1 = '74824069503a752aaa3abf194f73200fcdd117ef70ab28b576e5bf7a' +FAKE_HOST_ID2 = '858f5ed465b4967dd1306a38078e9b83b8705bdedfa7f16f898119b4' FAKE_ACTIONS = { FAKE_UUID: { @@ -70,7 +72,8 @@ FAKE_EVENTS = { 'updated_at': None, 'deleted_at': None, 'deleted': False, - 'host': 'host1' + 'host': 'host1', + 'hostId': FAKE_HOST_ID1 }, {'id': 2, 'action_id': FAKE_ACTION_ID1, @@ -85,7 +88,8 @@ FAKE_EVENTS = { 'updated_at': None, 'deleted_at': None, 'deleted': False, - 'host': 'host1' + 'host': 'host1', + 'hostId': FAKE_HOST_ID1 } ], FAKE_ACTION_ID2: [{'id': 3, @@ -101,7 +105,8 @@ FAKE_EVENTS = { 'updated_at': None, 'deleted_at': None, 'deleted': False, - 'host': 'host2' + 'host': 'host2', + 'hostId': FAKE_HOST_ID2 } ] } diff --git a/releasenotes/notes/add-host-to-instance-action-events-aad2cc18fe191afa.yaml b/releasenotes/notes/add-host-to-instance-action-events-aad2cc18fe191afa.yaml new file mode 100644 index 000000000000..037abcf03367 --- /dev/null +++ b/releasenotes/notes/add-host-to-instance-action-events-aad2cc18fe191afa.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + The microversion 2.62 adds ``host`` (hostname) and ``hostId`` (an + obfuscated hashed host id string) fields to the instance action + ``GET /servers/{server_id}/os-instance-actions/{req_id}`` API. The display + of the newly added ``host`` field will be controlled via policy rule + ``os_compute_api:os-instance-actions:events``, which is the same policy + used for the ``events.traceback`` field. If the user is prevented by + policy, only ``hostId`` will be displayed.