Merge "rbd: implement get_volume_stats()"

This commit is contained in:
Jenkins 2013-02-20 17:50:07 +00:00 committed by Gerrit Code Review
commit c529b1f6be
2 changed files with 97 additions and 0 deletions

View File

@ -30,6 +30,7 @@ from cinder.tests.image import fake as fake_image
from cinder.tests.test_volume import DriverTestCase from cinder.tests.test_volume import DriverTestCase
from cinder.volume import configuration as conf from cinder.volume import configuration as conf
from cinder.volume.drivers.rbd import RBDDriver from cinder.volume.drivers.rbd import RBDDriver
from cinder.volume.drivers.rbd import VERSION as DRIVER_VERSION
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -38,6 +39,38 @@ class FakeImageService:
def download(self, context, image_id, path): def download(self, context, image_id, path):
pass pass
RADOS_DF_OUT = """
{
"total_space" : "958931232",
"total_used" : "123906196",
"total_objects" : "4221",
"total_avail" : "787024012",
"pools" : [
{
"name" : "volumes",
"categories" : [
{
"write_bytes" : "226833",
"size_kb" : "17038386",
"read_bytes" : "221865",
"num_objects" : "4186",
"name" : "",
"size_bytes" : "17447306589",
"write_kb" : "20302730",
"num_object_copies" : "8372",
"read_kb" : "30",
"num_objects_unfound" : "0",
"num_object_clones" : "9",
"num_objects_missing_on_primary" : "0",
"num_objects_degraded" : "0"
}
],
"id" : "4"
}
]
}
"""
class RBDTestCase(test.TestCase): class RBDTestCase(test.TestCase):
@ -117,6 +150,36 @@ class RBDTestCase(test.TestCase):
self.flags(volume_tmp_dir='/var/run/cinder/tmp') self.flags(volume_tmp_dir='/var/run/cinder/tmp')
self._copy_image() self._copy_image()
def test_update_volume_stats(self):
def fake_stats(*args):
return RADOS_DF_OUT, ''
self.stubs.Set(self.driver, '_execute', fake_stats)
expected = dict(
volume_backend_name='RBD',
vendor_name='Open Source',
driver_version=DRIVER_VERSION,
storage_protocol='ceph',
total_capacity_gb=914,
free_capacity_gb=750,
reserved_percentage=0)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)
def test_update_volume_stats_error(self):
def fake_exc(*args):
raise exception.ProcessExecutionError()
self.stubs.Set(self.driver, '_execute', fake_exc)
expected = dict(
volume_backend_name='RBD',
vendor_name='Open Source',
driver_version=DRIVER_VERSION,
storage_protocol='ceph',
total_capacity_gb='unknown',
free_capacity_gb='unknown',
reserved_percentage=0)
actual = self.driver.get_volume_stats(True)
self.assertDictMatch(expected, actual)
class ManagedRBDTestCase(DriverTestCase): class ManagedRBDTestCase(DriverTestCase):
driver_name = "cinder.volume.drivers.rbd.RBDDriver" driver_name = "cinder.volume.drivers.rbd.RBDDriver"

View File

@ -15,6 +15,7 @@
RADOS Block Device Driver RADOS Block Device Driver
""" """
import json
import os import os
import tempfile import tempfile
import urllib import urllib
@ -49,12 +50,22 @@ rbd_opts = [
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
FLAGS.register_opts(rbd_opts) FLAGS.register_opts(rbd_opts)
VERSION = '1.0'
class RBDDriver(driver.VolumeDriver): class RBDDriver(driver.VolumeDriver):
"""Implements RADOS block device (RBD) volume commands""" """Implements RADOS block device (RBD) volume commands"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RBDDriver, self).__init__(*args, **kwargs) super(RBDDriver, self).__init__(*args, **kwargs)
self.configuration.append_config_values(rbd_opts) self.configuration.append_config_values(rbd_opts)
self._stats = dict(
volume_backend_name='RBD',
vendor_name='Open Source',
driver_version=VERSION,
storage_protocol='ceph',
total_capacity_gb='unknown',
free_capacity_gb='unknown',
reserved_percentage=0)
def check_for_setup_error(self): def check_for_setup_error(self):
"""Returns an error if prerequisites aren't met""" """Returns an error if prerequisites aren't met"""
@ -65,6 +76,29 @@ class RBDDriver(driver.VolumeDriver):
self.configuration.rbd_pool) self.configuration.rbd_pool)
raise exception.VolumeBackendAPIException(data=exception_message) raise exception.VolumeBackendAPIException(data=exception_message)
def _update_volume_stats(self):
stats = dict(
total_capacity_gb='unknown',
free_capacity_gb='unknown')
try:
stdout, _err = self._execute('rados', 'df', '--format', 'json')
new_stats = json.loads(stdout)
total = int(new_stats['total_space']) / 1024 ** 2
free = int(new_stats['total_avail']) / 1024 ** 2
stats['total_capacity_gb'] = total
stats['free_capacity_gb'] = free
except exception.ProcessExecutionError:
# just log and return unknown capacities
LOG.exception(_('error refreshing volume stats'))
self._stats.update(stats)
def get_volume_stats(self, refresh=False):
"""Return the current state of the volume service. If 'refresh' is
True, run the update first."""
if refresh:
self._update_volume_stats()
return self._stats
def _supports_layering(self): def _supports_layering(self):
stdout, _ = self._execute('rbd', '--help') stdout, _ = self._execute('rbd', '--help')
return 'clone' in stdout return 'clone' in stdout