Browse Source

Fix an error when generating a host ID

When instance action events are created by periodic tasks,
the project IDs of them become null (None).
It causes an error when 'hostId' is generated
in the "Show Server Action Details"
(GET /servers/{server_id}/os-instance-actions/{request_id})
API.

Fix the issue by using the project ID of the server
if the project ID of the event is None.

Conflicts:
    nova/tests/unit/api/openstack/compute/test_instance_actions.py

    The conflicts are due to not having the following
    changes in Rocky.

    I7f5f08691ca3f73073c66c29dddb996fb2c2b266
    If91c179e3823c8b0da744a9363906b0f7b05c326
    I44546bc9798708a48a250cc3a21bdbcabe2649e1

Change-Id: Iac07fcddd4cc3321c6efe702066eb8af6a875418
Closes-Bug: #1817542
(cherry picked from commit 31fe7c7600)
tags/18.2.0
Takashi NATSUME 6 months ago
parent
commit
e2185168f8

+ 8
- 1
nova/api/openstack/compute/instance_actions.py View File

@@ -163,8 +163,15 @@ class InstanceActionsController(wsgi.Controller):
163 163
         if show_events:
164 164
             events_raw = self.action_api.action_events_get(context, instance,
165 165
                                                            action_id)
166
+            # NOTE(takashin): The project IDs of instance action events
167
+            # become null (None) when instance action events are created
168
+            # by periodic tasks. If the project ID is null (None),
169
+            # it causes an error when 'hostId' is generated.
170
+            # If the project ID is null (None), pass the project ID of
171
+            # the server instead of that of instance action events.
166 172
             action['events'] = [self._format_event(
167
-                evt, action['project_id'], show_traceback=show_traceback,
173
+                evt, action['project_id'] or instance.project_id,
174
+                show_traceback=show_traceback,
168 175
                 show_host=show_host, show_hostid=show_hostid
169 176
             ) for evt in events_raw]
170 177
         return {'instanceAction': action}

+ 62
- 1
nova/tests/unit/api/openstack/compute/test_instance_actions.py View File

@@ -14,6 +14,7 @@
14 14
 #    under the License.
15 15
 
16 16
 import copy
17
+import datetime
17 18
 
18 19
 import mock
19 20
 from oslo_policy import policy as oslo_policy
@@ -31,6 +32,8 @@ from nova import test
31 32
 from nova.tests.unit.api.openstack import fakes
32 33
 from nova.tests.unit import fake_server_actions
33 34
 from nova.tests import uuidsentinel as uuids
35
+from nova import utils
36
+
34 37
 
35 38
 FAKE_UUID = fake_server_actions.FAKE_UUID
36 39
 FAKE_REQUEST_ID = fake_server_actions.FAKE_REQUEST_ID1
@@ -314,7 +317,65 @@ class InstanceActionsTestV258(InstanceActionsTestV251):
314 317
                       six.text_type(ex))
315 318
 
316 319
 
317
-class InstanceActionsTestV262(InstanceActionsTestV251):
320
+class InstanceActionsTestV262(InstanceActionsTestV258):
318 321
     wsgi_api_version = "2.62"
319 322
     expect_event_hostId = True
320 323
     expect_event_host = True
324
+    instance_project_id = '26cde4489f6749a08834741678df3c4a'
325
+
326
+    def fake_get(self, context, instance_uuid, expected_attrs=None,
327
+                 cell_down_support=False):
328
+        return objects.Instance(uuid=instance_uuid,
329
+                                project_id=self.instance_project_id)
330
+
331
+    @mock.patch.object(compute_api.InstanceActionAPI, 'action_events_get')
332
+    @mock.patch.object(compute_api.InstanceActionAPI,
333
+                       'action_get_by_request_id')
334
+    def test_get_action_with_events_project_id_none(self, mock_action_get,
335
+                                                    mock_action_events):
336
+        fake_request_id = 'req-%s' % uuids.req1
337
+
338
+        mock_action_get.return_value = objects.InstanceAction(
339
+            id=789,
340
+            action='stop',
341
+            instance_uuid=uuids.instance,
342
+            request_id=fake_request_id,
343
+            user_id=None,
344
+            project_id=None,
345
+            start_time=datetime.datetime(2019, 2, 28, 14, 28, 0, 0),
346
+            finish_time=None,
347
+            message='',
348
+            created_at=None,
349
+            updated_at=None,
350
+            deleted_at=None,
351
+            deleted=False)
352
+
353
+        mock_action_events.return_value = [
354
+            objects.InstanceActionEvent(
355
+                id=5,
356
+                action_id=789,
357
+                event='compute_stop_instance',
358
+                start_time=datetime.datetime(2019, 2, 28, 14, 28, 0, 0),
359
+                finish_time=datetime.datetime(2019, 2, 28, 14, 30, 0, 0),
360
+                result='Success',
361
+                traceback='',
362
+                created_at=None,
363
+                updated_at=None,
364
+                deleted_at=None,
365
+                deleted=False,
366
+                host='host2')]
367
+
368
+        req = self._get_http_req('os-instance-actions/1',
369
+                                 use_admin_context=True)
370
+        res_dict = self.controller.show(req, uuids.instance, fake_request_id)
371
+
372
+        # Assert that 'project_id' is null (None) in the response
373
+        self.assertIsNone(res_dict['instanceAction']['project_id'])
374
+        self.assertEqual('host2',
375
+                         res_dict['instanceAction']['events'][0]['host'])
376
+        # Assert that the 'hostId' is based on 'host' and the project ID
377
+        # of the server
378
+        self.assertEqual(utils.generate_hostid(
379
+            res_dict['instanceAction']['events'][0]['host'],
380
+            self.instance_project_id),
381
+            res_dict['instanceAction']['events'][0]['hostId'])

Loading…
Cancel
Save