Notify the transfer volume action in cinder

Now when we transfer a volume, there is not corresponding action
notification that is sent to ceilometer. Include the actions of create,
accept and delete.

The bp that this patch implements, proposes adding those action to enrich
the notification in cinder.

Notify is added in Create, Accept, and Delete actions.

Change-Id: I9d71c55d103cc501f60585b64902d364af21d4d9
Implements:  blueprint notify-the-transfer-volume-action-in-cinder
This commit is contained in:
wanghao 2015-05-26 15:32:42 +08:00
parent 2cd5904eb8
commit 8446f245b5
2 changed files with 49 additions and 3 deletions

View File

@ -15,6 +15,7 @@
import datetime
import mock
from oslo_log import log as logging
from cinder import context
@ -36,7 +37,8 @@ class VolumeTransferTestCase(test.TestCase):
project_id='project_id')
self.updated_at = datetime.datetime(1, 1, 1, 1, 1, 1)
def test_transfer_volume_create_delete(self):
@mock.patch('cinder.volume.utils.notify_about_volume_usage')
def test_transfer_volume_create_delete(self, mock_notify):
tx_api = transfer_api.API()
utils.create_volume(self.ctxt, id='1',
updated_at=self.updated_at)
@ -44,10 +46,18 @@ class VolumeTransferTestCase(test.TestCase):
volume = db.volume_get(self.ctxt, '1')
self.assertEqual('awaiting-transfer', volume['status'],
'Unexpected state')
calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"),
mock.call(self.ctxt, mock.ANY, "transfer.create.end")]
mock_notify.assert_has_calls(calls)
self.assertEqual(2, mock_notify.call_count)
tx_api.delete(self.ctxt, response['id'])
volume = db.volume_get(self.ctxt, '1')
self.assertEqual('available', volume['status'], 'Unexpected state')
calls = [mock.call(self.ctxt, mock.ANY, "transfer.delete.start"),
mock.call(self.ctxt, mock.ANY, "transfer.delete.end")]
mock_notify.assert_has_calls(calls)
self.assertEqual(4, mock_notify.call_count)
def test_transfer_invalid_volume(self):
tx_api = transfer_api.API()
@ -59,7 +69,8 @@ class VolumeTransferTestCase(test.TestCase):
volume = db.volume_get(self.ctxt, '1')
self.assertEqual('in-use', volume['status'], 'Unexpected state')
def test_transfer_accept(self):
@mock.patch('cinder.volume.utils.notify_about_volume_usage')
def test_transfer_accept(self, mock_notify):
svc = self.start_service('volume', host='test_host')
tx_api = transfer_api.API()
utils.create_volume(self.ctxt, id='1',
@ -77,12 +88,23 @@ class VolumeTransferTestCase(test.TestCase):
tx_api.accept,
self.ctxt, transfer['id'], 'wrong')
calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"),
mock.call(self.ctxt, mock.ANY, "transfer.create.end")]
mock_notify.assert_has_calls(calls)
self.assertEqual(2, mock_notify.call_count)
db.volume_update(self.ctxt, '1', {'status': 'wrong'})
self.assertRaises(exception.InvalidVolume,
tx_api.accept,
self.ctxt, transfer['id'], transfer['auth_key'])
db.volume_update(self.ctxt, '1', {'status': 'awaiting-transfer'})
# Because the InvalidVolume exception is raised in tx_api, so there is
# only transfer.accept.start called and missing transfer.accept.end.
calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start")]
mock_notify.assert_has_calls(calls)
self.assertEqual(3, mock_notify.call_count)
self.ctxt.user_id = 'new_user_id'
self.ctxt.project_id = 'new_project_id'
response = tx_api.accept(self.ctxt,
@ -99,6 +121,11 @@ class VolumeTransferTestCase(test.TestCase):
self.assertEqual(transfer['id'], response['id'],
'Unexpected transfer id in response.')
calls = [mock.call(self.ctxt, mock.ANY, "transfer.accept.start"),
mock.call(self.ctxt, mock.ANY, "transfer.accept.end")]
mock_notify.assert_has_calls(calls)
self.assertEqual(5, mock_notify.call_count)
svc.stop()
def test_transfer_get(self):
@ -123,7 +150,8 @@ class VolumeTransferTestCase(test.TestCase):
ts = tx_api.get_all(nctxt)
self.assertEqual(len(ts), 0, 'Unexpected transfers listed.')
def test_delete_transfer_with_deleted_volume(self):
@mock.patch('cinder.volume.utils.notify_about_volume_usage')
def test_delete_transfer_with_deleted_volume(self, mock_notify):
# create a volume
volume = utils.create_volume(self.ctxt, id='1',
updated_at=self.updated_at)
@ -132,6 +160,11 @@ class VolumeTransferTestCase(test.TestCase):
transfer = tx_api.create(self.ctxt, volume['id'], 'Description')
t = tx_api.get(self.ctxt, transfer['id'])
self.assertEqual(t['id'], transfer['id'], 'Unexpected transfer id')
calls = [mock.call(self.ctxt, mock.ANY, "transfer.create.start"),
mock.call(self.ctxt, mock.ANY, "transfer.create.end")]
mock_notify.assert_has_calls(calls)
self.assertEqual(2, mock_notify.call_count)
# force delete volume
db.volume_destroy(context.get_admin_context(), volume['id'])
# Make sure transfer has been deleted.

View File

@ -31,6 +31,7 @@ from cinder import exception
from cinder.i18n import _, _LE, _LI, _LW
from cinder import quota
from cinder.volume import api as volume_api
from cinder.volume import utils as volume_utils
volume_transfer_opts = [
@ -64,9 +65,13 @@ class API(base.Base):
transfer = self.db.transfer_get(context, transfer_id)
volume_ref = self.db.volume_get(context, transfer.volume_id)
volume_utils.notify_about_volume_usage(context, volume_ref,
"transfer.delete.start")
if volume_ref['status'] != 'awaiting-transfer':
LOG.error(_LE("Volume in unexpected state"))
self.db.transfer_destroy(context, transfer_id)
volume_utils.notify_about_volume_usage(context, volume_ref,
"transfer.delete.end")
def get_all(self, context, filters=None):
filters = filters or {}
@ -105,6 +110,8 @@ class API(base.Base):
if volume_ref['status'] != "available":
raise exception.InvalidVolume(reason=_("status must be available"))
volume_utils.notify_about_volume_usage(context, volume_ref,
"transfer.create.start")
# The salt is just a short random string.
salt = self._get_random_string(CONF.volume_transfer_salt_length)
auth_key = self._get_random_string(CONF.volume_transfer_key_length)
@ -123,6 +130,8 @@ class API(base.Base):
LOG.error(_LE("Failed to create transfer record "
"for %s"), volume_id)
raise
volume_utils.notify_about_volume_usage(context, volume_ref,
"transfer.create.end")
return {'id': transfer['id'],
'volume_id': transfer['volume_id'],
'display_name': transfer['display_name'],
@ -145,6 +154,8 @@ class API(base.Base):
volume_id = transfer['volume_id']
vol_ref = self.db.volume_get(context.elevated(), volume_id)
volume_utils.notify_about_volume_usage(context, vol_ref,
"transfer.accept.start")
try:
reservations = QUOTAS.reserve(context, volumes=1,
@ -210,6 +221,8 @@ class API(base.Base):
project_id=donor_id)
vol_ref = self.db.volume_get(context, volume_id)
volume_utils.notify_about_volume_usage(context, vol_ref,
"transfer.accept.end")
return {'id': transfer_id,
'display_name': transfer['display_name'],
'volume_id': vol_ref['id']}