From 7d63c25c702373ae10556c43e2ebb17e5f0e4ccc Mon Sep 17 00:00:00 2001 From: wanghao Date: Wed, 6 May 2015 12:08:00 +0800 Subject: [PATCH] Notification with volume and snapshot metadata Now notify message to ceilometer do not contain volume metadata/glance_metadata and snapshot metadata, which are useful to bill and enrich resource information in ceilometer. This feature will add the metadata/glance_metadata of volume and metadata of snapshot to notification usage info. Change-Id: I04097be9f2da1d6bc45a2d5770bcd543a3f41887 Implements: blueprint notification-with-volume-and-snapshot-metadata --- cinder/tests/unit/test_volume.py | 4 +- cinder/tests/unit/test_volume_utils.py | 68 +++++++++++++++++++++++--- cinder/volume/utils.py | 23 ++++++--- 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/cinder/tests/unit/test_volume.py b/cinder/tests/unit/test_volume.py index 5b4a6a855..b197b088e 100644 --- a/cinder/tests/unit/test_volume.py +++ b/cinder/tests/unit/test_volume.py @@ -525,6 +525,7 @@ class VolumeTestCase(BaseVolumeTestCase): 'replication_status': 'disabled', 'replication_extended_status': None, 'replication_driver_data': None, + 'metadata': [], } self.assertDictMatch(expected, msg['payload']) msg = fake_notifier.NOTIFICATIONS[1] @@ -2823,7 +2824,8 @@ class VolumeTestCase(BaseVolumeTestCase): 'user_id': 'fake', 'volume_id': volume['id'], 'volume_size': 1, - 'availability_zone': 'nova' + 'availability_zone': 'nova', + 'metadata': '', } self.assertDictMatch(expected, msg['payload']) msg = fake_notifier.NOTIFICATIONS[3] diff --git a/cinder/tests/unit/test_volume_utils.py b/cinder/tests/unit/test_volume_utils.py index d97ce9961..604b5387b 100644 --- a/cinder/tests/unit/test_volume_utils.py +++ b/cinder/tests/unit/test_volume_utils.py @@ -15,7 +15,10 @@ """Tests For miscellaneous util methods used with volume.""" + +import datetime import mock + from oslo_concurrency import processutils from oslo_config import cfg from oslo_log import log as logging @@ -42,7 +45,8 @@ class NotifyUsageTestCase(test.TestCase): mock.sentinel.volume, 'test_suffix') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume) + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume) mock_rpc.get_notifier.assert_called_once_with('volume', 'host1') mock_rpc.get_notifier.return_value.info.assert_called_once_with( mock.sentinel.context, @@ -62,7 +66,8 @@ class NotifyUsageTestCase(test.TestCase): extra_usage_info={'a': 'b', 'c': 'd'}, host='host2') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume, a='b', c='d') + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume, a='b', c='d') mock_rpc.get_notifier.assert_called_once_with('volume', 'host2') mock_rpc.get_notifier.return_value.info.assert_called_once_with( mock.sentinel.context, @@ -80,7 +85,8 @@ class NotifyUsageTestCase(test.TestCase): mock.sentinel.volume, 'test_suffix') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume) + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume) mock_rpc.get_notifier.assert_called_once_with('replication', 'host1') mock_rpc.get_notifier.return_value.info.assert_called_once_with( mock.sentinel.context, @@ -100,7 +106,8 @@ class NotifyUsageTestCase(test.TestCase): extra_usage_info={'a': 'b', 'c': 'd'}, host='host2') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume, + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume, a='b', c='d') mock_rpc.get_notifier.assert_called_once_with('replication', 'host2') mock_rpc.get_notifier.return_value.info.assert_called_once_with( @@ -119,7 +126,8 @@ class NotifyUsageTestCase(test.TestCase): mock.sentinel.volume, 'test_suffix') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume) + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume) mock_rpc.get_notifier.assert_called_once_with('replication', 'host1') mock_rpc.get_notifier.return_value.error.assert_called_once_with( mock.sentinel.context, @@ -139,7 +147,8 @@ class NotifyUsageTestCase(test.TestCase): extra_error_info={'a': 'b', 'c': 'd'}, host='host2') self.assertIsNone(output) - mock_usage.assert_called_once_with(mock.sentinel.volume, + mock_usage.assert_called_once_with(mock.sentinel.context, + mock.sentinel.volume, a='b', c='d') mock_rpc.get_notifier.assert_called_once_with('replication', 'host2') mock_rpc.get_notifier.return_value.error.assert_called_once_with( @@ -198,6 +207,7 @@ class NotifyUsageTestCase(test.TestCase): 'created_at': '2014-12-11T10:10:00', 'status': 'pause', 'deleted': '', + 'metadata': {'fake_snap_meta_key': 'fake_snap_meta_value'}, } usage_info = volume_utils._usage_from_snapshot(raw_snapshot) expected_snapshot = { @@ -211,9 +221,55 @@ class NotifyUsageTestCase(test.TestCase): 'created_at': '2014-12-11T10:10:00', 'status': 'pause', 'deleted': '', + 'metadata': "{'fake_snap_meta_key': 'fake_snap_meta_value'}", } self.assertEqual(expected_snapshot, usage_info) + @mock.patch('cinder.db.volume_glance_metadata_get') + def test_usage_from_volume(self, mock_image_metadata): + mock_image_metadata.return_value = {'image_id': 'fake_image_id'} + raw_volume = { + 'project_id': '12b0330ec2584a', + 'user_id': '158cba1b8c2bb6008e', + 'host': 'fake_host', + 'availability_zone': 'nova', + 'volume_type_id': 'fake_volume_type_id', + 'id': 'fake_volume_id', + 'size': 1, + 'display_name': 'test_volume', + 'created_at': datetime.datetime(2015, 1, 1, 1, 1, 1), + 'launched_at': datetime.datetime(2015, 1, 1, 1, 1, 1), + 'snapshot_id': None, + 'replication_status': None, + 'replication_extended_status': None, + 'replication_driver_data': None, + 'status': 'available', + 'volume_metadata': {'fake_metadata_key': 'fake_metadata_value'}, + } + usage_info = volume_utils._usage_from_volume( + mock.sentinel.context, + raw_volume) + expected_volume = { + 'tenant_id': '12b0330ec2584a', + 'user_id': '158cba1b8c2bb6008e', + 'host': 'fake_host', + 'availability_zone': 'nova', + 'volume_type': 'fake_volume_type_id', + 'volume_id': 'fake_volume_id', + 'size': 1, + 'display_name': 'test_volume', + 'created_at': '2015-01-01T01:01:01', + 'launched_at': '2015-01-01T01:01:01', + 'snapshot_id': None, + 'replication_status': None, + 'replication_extended_status': None, + 'replication_driver_data': None, + 'status': 'available', + 'metadata': {'fake_metadata_key': 'fake_metadata_value'}, + 'glance_metadata': {'image_id': 'fake_image_id'}, + } + self.assertEqual(expected_volume, usage_info) + @mock.patch('cinder.volume.utils._usage_from_consistencygroup') @mock.patch('cinder.volume.utils.CONF') @mock.patch('cinder.volume.utils.rpc') diff --git a/cinder/volume/utils.py b/cinder/volume/utils.py index d136cd79f..aa14e7fc9 100644 --- a/cinder/volume/utils.py +++ b/cinder/volume/utils.py @@ -26,6 +26,7 @@ from oslo_utils import timeutils from oslo_utils import units from cinder.brick.local_dev import lvm as brick_lvm +from cinder import db from cinder import exception from cinder.i18n import _LI, _LW from cinder import rpc @@ -42,7 +43,7 @@ def null_safe_str(s): return str(s) if s else '' -def _usage_from_volume(volume_ref, **kw): +def _usage_from_volume(context, volume_ref, **kw): now = timeutils.utcnow() launched_at = volume_ref['launched_at'] or now created_at = volume_ref['created_at'] or now @@ -61,9 +62,18 @@ def _usage_from_volume(volume_ref, **kw): size=volume_ref['size'], replication_status=volume_ref['replication_status'], replication_extended_status=volume_ref['replication_extended_status'], - replication_driver_data=volume_ref['replication_driver_data'],) + replication_driver_data=volume_ref['replication_driver_data'], + metadata=volume_ref.get('volume_metadata'),) usage_info.update(kw) + try: + glance_meta = db.volume_glance_metadata_get(context, volume_ref['id']) + if glance_meta: + usage_info['glance_metadata'] = glance_meta + except exception.GlanceMetadataNotFound: + pass + except exception.VolumeNotFound: + LOG.debug("Can not find volume %s at notify usage", volume_ref['id']) return usage_info @@ -94,7 +104,7 @@ def notify_about_volume_usage(context, volume, event_suffix, if not extra_usage_info: extra_usage_info = {} - usage_info = _usage_from_volume(volume, **extra_usage_info) + usage_info = _usage_from_volume(context, volume, **extra_usage_info) rpc.get_notifier("volume", host).info(context, 'volume.%s' % event_suffix, usage_info) @@ -126,7 +136,8 @@ def _usage_from_snapshot(snapshot_ref, **extra_usage_info): 'display_name': snapshot_ref['display_name'], 'created_at': str(snapshot_ref['created_at']), 'status': snapshot_ref['status'], - 'deleted': null_safe_str(snapshot_ref['deleted']) + 'deleted': null_safe_str(snapshot_ref['deleted']), + 'metadata': null_safe_str(snapshot_ref.get('metadata')), } usage_info.update(extra_usage_info) @@ -156,7 +167,7 @@ def notify_about_replication_usage(context, volume, suffix, if not extra_usage_info: extra_usage_info = {} - usage_info = _usage_from_volume(volume, + usage_info = _usage_from_volume(context, volume, **extra_usage_info) rpc.get_notifier('replication', host).info(context, @@ -172,7 +183,7 @@ def notify_about_replication_error(context, volume, suffix, if not extra_error_info: extra_error_info = {} - usage_info = _usage_from_volume(volume, + usage_info = _usage_from_volume(context, volume, **extra_error_info) rpc.get_notifier('replication', host).error(context, -- 2.45.2