diff --git a/cinder/tests/unit/volume/drivers/test_rbd.py b/cinder/tests/unit/volume/drivers/test_rbd.py index 1a1bfc64042..ed896adae19 100644 --- a/cinder/tests/unit/volume/drivers/test_rbd.py +++ b/cinder/tests/unit/volume/drivers/test_rbd.py @@ -557,6 +557,33 @@ class RBDTestCase(test.TestCase): self.assertEqual([self.mock_rbd.ImageNotFound], RAISED_EXCEPTIONS) + @common_mocks + @mock.patch.object(driver.RBDDriver, '_get_image_status') + def test_get_manageable_volumes(self, mock_get_image_status): + cinder_vols = [{'id': '00000000-0000-0000-0000-000000000000'}] + vols = ['volume-00000000-0000-0000-0000-000000000000', 'vol1', 'vol2'] + self.mock_rbd.RBD.return_value.list.return_value = vols + image = self.mock_proxy.return_value.__enter__.return_value + image.size.side_effect = [2 * units.Gi, 4 * units.Gi, 6 * units.Gi] + mock_get_image_status.side_effect = [ + {'watchers': []}, + {'watchers': [{"address": "192.168.120.61:0\/3012034728", + "client": 44431941, "cookie": 94077162321152}]}] + res = self.driver.get_manageable_volumes( + cinder_vols, None, 1000, 0, ['size'], ['asc']) + exp = [{'size': 2, 'reason_not_safe': 'already managed', + 'extra_info': None, 'safe_to_manage': False, + 'reference': {'source-name': + 'volume-00000000-0000-0000-0000-000000000000'}, + 'cinder_id': '00000000-0000-0000-0000-000000000000'}, + {'size': 4, 'reason_not_safe': None, + 'safe_to_manage': True, 'reference': {'source-name': 'vol1'}, + 'cinder_id': None, 'extra_info': None}, + {'size': 6, 'reason_not_safe': 'volume in use', + 'safe_to_manage': False, 'reference': {'source-name': 'vol2'}, + 'cinder_id': None, 'extra_info': None}] + self.assertEqual(exp, res) + @common_mocks def test_delete_backup_snaps(self): self.driver.rbd.Image.remove_snap = mock.Mock() diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index 8f64dcffcfc..925b7220b10 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -37,7 +37,7 @@ from cinder.objects import fields from cinder import utils from cinder.volume import configuration from cinder.volume import driver - +from cinder.volume import utils as volume_utils try: import rados @@ -1389,6 +1389,52 @@ class RBDDriver(driver.CloneableImageVD, raise exception.VolumeBackendAPIException( data=exception_message) + def _get_image_status(self, image_name): + args = ['rbd', 'status', + '--pool', self.configuration.rbd_pool, + '--format=json', + image_name] + args.extend(self._ceph_args()) + out, _ = self._execute(*args) + return json.loads(out) + + def get_manageable_volumes(self, cinder_volumes, marker, limit, offset, + sort_keys, sort_dirs): + manageable_volumes = [] + cinder_ids = [resource['id'] for resource in cinder_volumes] + + with RADOSClient(self) as client: + for image_name in self.RBDProxy().list(client.ioctx): + image_id = volume_utils.extract_id_from_volume_name(image_name) + with RBDVolumeProxy(self, image_name, read_only=True) as image: + try: + image_info = { + 'reference': {'source-name': image_name}, + 'size': int(math.ceil( + float(image.size()) / units.Gi)), + 'cinder_id': None, + 'extra_info': None + } + if image_id in cinder_ids: + image_info['cinder_id'] = image_id + image_info['safe_to_manage'] = False + image_info['reason_not_safe'] = 'already managed' + elif len(self._get_image_status( + image_name)['watchers']) > 0: + # If the num of watchers of image is >= 1, then the + # image is considered to be used by client(s). + image_info['safe_to_manage'] = False + image_info['reason_not_safe'] = 'volume in use' + else: + image_info['safe_to_manage'] = True + image_info['reason_not_safe'] = None + manageable_volumes.append(image_info) + except self.rbd.ImageNotFound: + LOG.debug("Image %s is not found.", image_name) + + return volume_utils.paginate_entries_list( + manageable_volumes, marker, limit, offset, sort_keys, sort_dirs) + def unmanage(self, volume): pass diff --git a/releasenotes/notes/rbd-support-list-manageable-volumes-8a088a44e01d227f.yaml b/releasenotes/notes/rbd-support-list-manageable-volumes-8a088a44e01d227f.yaml new file mode 100644 index 00000000000..4aced7d124e --- /dev/null +++ b/releasenotes/notes/rbd-support-list-manageable-volumes-8a088a44e01d227f.yaml @@ -0,0 +1,3 @@ +--- +features: + - Allow rbd driver to list manageable volumes.