RBD: get manageable volumes
This patch adds the ability to get manageable volumes to RBD driver. Co-Authored-By: qtlu<qtlu@fiberhome.com> Partial-Implements: blueprint list-manage-existing Change-Id: I0621358b13fc3f5a4acfb8d66232fb953d94b274
This commit is contained in:
parent
466ab2bf8f
commit
164246094e
@ -557,6 +557,33 @@ class RBDTestCase(test.TestCase):
|
|||||||
self.assertEqual([self.mock_rbd.ImageNotFound],
|
self.assertEqual([self.mock_rbd.ImageNotFound],
|
||||||
RAISED_EXCEPTIONS)
|
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
|
@common_mocks
|
||||||
def test_delete_backup_snaps(self):
|
def test_delete_backup_snaps(self):
|
||||||
self.driver.rbd.Image.remove_snap = mock.Mock()
|
self.driver.rbd.Image.remove_snap = mock.Mock()
|
||||||
|
@ -37,7 +37,7 @@ from cinder.objects import fields
|
|||||||
from cinder import utils
|
from cinder import utils
|
||||||
from cinder.volume import configuration
|
from cinder.volume import configuration
|
||||||
from cinder.volume import driver
|
from cinder.volume import driver
|
||||||
|
from cinder.volume import utils as volume_utils
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import rados
|
import rados
|
||||||
@ -1389,6 +1389,52 @@ class RBDDriver(driver.CloneableImageVD,
|
|||||||
raise exception.VolumeBackendAPIException(
|
raise exception.VolumeBackendAPIException(
|
||||||
data=exception_message)
|
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):
|
def unmanage(self, volume):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Allow rbd driver to list manageable volumes.
|
Loading…
x
Reference in New Issue
Block a user