summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin_Zheng <zhengzhenyu@huawei.com>2017-11-29 11:37:43 +0800
committerMatt Riedemann <mriedem.os@gmail.com>2017-12-08 15:19:54 -0500
commit0aa7aafdd754629e1b3922853fa0b441ace76330 (patch)
treefa111a6f347c1d1dba331b4c37fa4598acaf99b7
parent1d88440eb421929438e77c637caf502075b43f56 (diff)
downloadnova-0aa7aafdd754629e1b3922853fa0b441ace76330.tar.gz
Add instance action record for backup instances
We currently don't record backup instance actions. This is useful for auditing and debugging. This patch adds instance backup actions. Note that because of how backup works for cellsv1, the API call from the top isn't replayed in the child cell, so we have to create the instance action in nova/cells/messaging so the action is in the child cell database when nova-compute looks it up via wrap_instance_event. Change-Id: I878015fa211a5f2b5062902b3bfbd571d56efb76 partial-implements: blueprint fill-the-gap-for-instance-action-records
-rw-r--r--nova/cells/messaging.py6
-rw-r--r--nova/compute/api.py3
-rw-r--r--nova/compute/instance_actions.py1
-rw-r--r--nova/compute/manager.py1
-rw-r--r--nova/tests/unit/cells/test_cells_messaging.py9
-rw-r--r--nova/tests/unit/compute/test_compute.py15
-rw-r--r--nova/tests/unit/compute/test_compute_api.py6
-rw-r--r--releasenotes/notes/fill-instance-action-record-gaps-14b36eba313d6d87.yaml1
8 files changed, 34 insertions, 8 deletions
diff --git a/nova/cells/messaging.py b/nova/cells/messaging.py
index 75fb015cb7..f7e7c575fc 100644
--- a/nova/cells/messaging.py
+++ b/nova/cells/messaging.py
@@ -44,6 +44,7 @@ from six.moves import range
from nova.cells import state as cells_state
from nova.cells import utils as cells_utils
from nova import compute
+from nova.compute import instance_actions
from nova.compute import rpcapi as compute_rpcapi
from nova.compute import task_states
from nova.compute import vm_states
@@ -918,6 +919,11 @@ class _TargetedMessageMethods(_BaseMessageMethods):
instance.refresh()
instance.task_state = task_states.IMAGE_BACKUP
instance.save(expected_task_state=[None])
+
+ objects.InstanceAction.action_start(
+ message.ctxt, instance.uuid, instance_actions.BACKUP,
+ want_result=False)
+
self.compute_rpcapi.backup_instance(message.ctxt,
instance,
image_id,
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 85a4a8d429..7b1b94b37b 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -2597,6 +2597,9 @@ class API(base.Base):
instance.task_state = task_states.IMAGE_BACKUP
instance.save(expected_task_state=[None])
+ self._record_action_start(context, instance,
+ instance_actions.BACKUP)
+
self.compute_rpcapi.backup_instance(context, instance,
image_meta['id'],
backup_type,
diff --git a/nova/compute/instance_actions.py b/nova/compute/instance_actions.py
index fe5e5448f6..ec6e0e77a3 100644
--- a/nova/compute/instance_actions.py
+++ b/nova/compute/instance_actions.py
@@ -68,3 +68,4 @@ DETACH_VOLUME = 'detach_volume'
SWAP_VOLUME = 'swap_volume'
LOCK = 'lock'
UNLOCK = 'unlock'
+BACKUP = 'createBackup'
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 046e443db8..fbb19dde65 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -3215,6 +3215,7 @@ class ComputeManager(manager.Manager):
@wrap_exception()
@reverts_task_state
+ @wrap_instance_event(prefix='compute')
@wrap_instance_fault
def backup_instance(self, context, image_id, instance, backup_type,
rotation):
diff --git a/nova/tests/unit/cells/test_cells_messaging.py b/nova/tests/unit/cells/test_cells_messaging.py
index 3e3640727a..5d6d5f2cd6 100644
--- a/nova/tests/unit/cells/test_cells_messaging.py
+++ b/nova/tests/unit/cells/test_cells_messaging.py
@@ -26,6 +26,7 @@ from oslo_utils import timeutils
from nova.cells import messaging
from nova.cells import rpcapi as cells_rpcapi
from nova.cells import utils as cells_utils
+from nova.compute import instance_actions
from nova.compute import task_states
from nova.compute import vm_states
import nova.conf
@@ -1371,8 +1372,9 @@ class CellsTargetedMethodsTestCase(test.NoDBTestCase):
meth_cls.snapshot_instance(message, inst, image_id='image-id')
- def test_backup_instance(self):
- inst = objects.Instance()
+ @mock.patch.object(objects.InstanceAction, 'action_start')
+ def test_backup_instance(self, action_start):
+ inst = objects.Instance(uuid=uuids.instance)
meth_cls = self.tgt_methods_cls
self.mox.StubOutWithMock(inst, 'refresh')
@@ -1404,6 +1406,9 @@ class CellsTargetedMethodsTestCase(test.NoDBTestCase):
image_id='image-id',
backup_type='backup-type',
rotation='rotation')
+ action_start.assert_called_once_with(
+ message.ctxt, inst.uuid, instance_actions.BACKUP,
+ want_result=False)
def test_set_admin_password(self):
args = ['fake-password']
diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py
index 220a873c26..3f74ca25f6 100644
--- a/nova/tests/unit/compute/test_compute.py
+++ b/nova/tests/unit/compute/test_compute.py
@@ -3398,11 +3398,16 @@ class ComputeTestCase(BaseTestCase,
self.context, image_id='fakesnap',
instance=inst_obj)
else:
- self.assertRaises(test.TestingException,
- self.compute.backup_instance,
- self.context, image_id='fakesnap',
- instance=inst_obj, backup_type='fake',
- rotation=1)
+ with mock.patch.object(compute_utils,
+ 'EventReporter') as mock_event:
+ self.assertRaises(test.TestingException,
+ self.compute.backup_instance,
+ self.context, image_id='fakesnap',
+ instance=inst_obj, backup_type='fake',
+ rotation=1)
+ mock_event.assert_called_once_with(self.context,
+ 'compute_backup_instance',
+ inst_obj.uuid)
self.assertEqual(expected_state, self.fake_image_delete_called)
self._assert_state({'task_state': None})
diff --git a/nova/tests/unit/compute/test_compute_api.py b/nova/tests/unit/compute/test_compute_api.py
index abc5ded184..8eb4aee888 100644
--- a/nova/tests/unit/compute/test_compute_api.py
+++ b/nova/tests/unit/compute/test_compute_api.py
@@ -2485,7 +2485,8 @@ class _ComputeAPIUnitTestMixIn(object):
_do_test()
- def _test_snapshot_and_backup(self, is_snapshot=True,
+ @mock.patch.object(compute_api.API, '_record_action_start')
+ def _test_snapshot_and_backup(self, mock_record, is_snapshot=True,
with_base_ref=False, min_ram=None,
min_disk=None,
create_fails=False,
@@ -2599,6 +2600,9 @@ class _ComputeAPIUnitTestMixIn(object):
'fake-backup-type',
'fake-rotation',
extra_properties=extra_props)
+ mock_record.assert_called_once_with(self.context,
+ instance,
+ instance_actions.BACKUP)
self.assertEqual(fake_image, res)
except test.TestingException:
got_exc = True
diff --git a/releasenotes/notes/fill-instance-action-record-gaps-14b36eba313d6d87.yaml b/releasenotes/notes/fill-instance-action-record-gaps-14b36eba313d6d87.yaml
index a60a723acd..817117d91e 100644
--- a/releasenotes/notes/fill-instance-action-record-gaps-14b36eba313d6d87.yaml
+++ b/releasenotes/notes/fill-instance-action-record-gaps-14b36eba313d6d87.yaml
@@ -11,3 +11,4 @@ features:
* lock
* unlock
* shelveOffload
+ * createBackup