ceph backup support for EXCLUSIVE_LOCK and JOURNALING features
Ceph Jewel has introduced the ability to mirror its pools. If configured to do so, the rbd-mirror daemon will replay an image's journals to replicate the image at a remote Ceph store. In order for an image to be mirrored, the 'exclusive-lock' and 'journaling' feature bits need to be enabled per image. Ceph documentation recommends using "rbd features default = 125" in the Ceph configuration to enable these feature bits for all newly created images. However, if an image has an explicit set of feature bits asked for during its creation, that request overrides what is set for "rbd features default". The Ceph backup driver is specifcally asking for "stripingv2" and "layering"; thus ignoring what is set at "rbd features default". This patch adds a new configuration option, 'backup_ceph_image_journals' which adds these feature bits to the 'features' set returned by _get_rbd_support(). If 'backup_ceph_image_journals' is set to True and the underlying installation of RBD does not support either JOURNALING or EXCLUSIVE_LOCK, an error is logged and 'BackupCephInvalidArgs' is raised whenever an operation attempts to create a new Cepd object. Change-Id: Iea9dc18ab68891c99d008157220365d184caf508 Implements: blueprint backup-ceph-driver-journaling-exculsive-lock-features
This commit is contained in:
parent
0ed3a80d6c
commit
dc96c948f7
@ -88,6 +88,9 @@ service_opts = [
|
||||
help='RBD stripe unit to use when creating a backup image.'),
|
||||
cfg.IntOpt('backup_ceph_stripe_count', default=0,
|
||||
help='RBD stripe count to use when creating a backup image.'),
|
||||
cfg.BoolOpt('backup_ceph_image_journals', default=False,
|
||||
help='If True, apply JOURNALING and EXCLUSIVE_LOCK feature '
|
||||
'bits to the backup RBD objects to allow mirroring'),
|
||||
cfg.BoolOpt('restore_discard_excess_bytes', default=True,
|
||||
help='If True, always discard excess bytes when restoring '
|
||||
'volumes i.e. pad with zeroes.')
|
||||
@ -222,6 +225,16 @@ class CephBackupDriver(driver.BackupDriver):
|
||||
"""Determine if striping is supported by our version of librbd."""
|
||||
return hasattr(self.rbd, 'RBD_FEATURE_STRIPINGV2')
|
||||
|
||||
@property
|
||||
def _supports_exclusive_lock(self):
|
||||
"""Determine if exclusive-lock is supported by librbd."""
|
||||
return hasattr(self.rbd, 'RBD_FEATURE_EXCLUSIVE_LOCK')
|
||||
|
||||
@property
|
||||
def _supports_journaling(self):
|
||||
"""Determine if journaling is supported by our version of librbd."""
|
||||
return hasattr(self.rbd, 'RBD_FEATURE_JOURNALING')
|
||||
|
||||
def _get_rbd_support(self):
|
||||
"""Determine RBD features supported by our version of librbd."""
|
||||
old_format = True
|
||||
@ -233,6 +246,25 @@ class CephBackupDriver(driver.BackupDriver):
|
||||
old_format = False
|
||||
features |= self.rbd.RBD_FEATURE_STRIPINGV2
|
||||
|
||||
# journaling requires exclusive_lock; check both together
|
||||
if CONF.backup_ceph_image_journals:
|
||||
if self._supports_exclusive_lock and self._supports_journaling:
|
||||
old_format = False
|
||||
features |= (self.rbd.RBD_FEATURE_EXCLUSIVE_LOCK |
|
||||
self.rbd.RBD_FEATURE_JOURNALING)
|
||||
else:
|
||||
# FIXME (tasker): when the backup manager supports loading the
|
||||
# driver during its initialization, this exception should be
|
||||
# moved to the driver's initialization so that it can stop
|
||||
# the service from starting when the underyling RBD does not
|
||||
# support the requested features.
|
||||
LOG.error(_LE("RBD journaling not supported - unable to "
|
||||
"support per image mirroring in backup pool"))
|
||||
raise exception.BackupInvalidCephArgs(
|
||||
_("Image Journaling set but RBD backend does "
|
||||
"not support journaling")
|
||||
)
|
||||
|
||||
return (old_format, features)
|
||||
|
||||
def _connect_to_rados(self, pool=None):
|
||||
|
@ -22,6 +22,7 @@ import uuid
|
||||
import mock
|
||||
from os_brick.initiator import linuxrbd
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import units
|
||||
import six
|
||||
@ -42,6 +43,8 @@ from cinder.tests.unit import fake_constants as fake
|
||||
# NOTE: this must be initialised in test setUp().
|
||||
RAISED_EXCEPTIONS = []
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class MockException(Exception):
|
||||
|
||||
@ -202,8 +205,13 @@ class BackupCephTestCase(test.TestCase):
|
||||
def test_get_rbd_support(self):
|
||||
del self.service.rbd.RBD_FEATURE_LAYERING
|
||||
del self.service.rbd.RBD_FEATURE_STRIPINGV2
|
||||
del self.service.rbd.RBD_FEATURE_EXCLUSIVE_LOCK
|
||||
del self.service.rbd.RBD_FEATURE_JOURNALING
|
||||
self.assertFalse(hasattr(self.service.rbd, 'RBD_FEATURE_LAYERING'))
|
||||
self.assertFalse(hasattr(self.service.rbd, 'RBD_FEATURE_STRIPINGV2'))
|
||||
self.assertFalse(hasattr(self.service.rbd,
|
||||
'RBD_FEATURE_EXCLUSIVE_LOCK'))
|
||||
self.assertFalse(hasattr(self.service.rbd, 'RBD_FEATURE_JOURNALING'))
|
||||
|
||||
oldformat, features = self.service._get_rbd_support()
|
||||
self.assertTrue(oldformat)
|
||||
@ -221,6 +229,28 @@ class BackupCephTestCase(test.TestCase):
|
||||
self.assertFalse(oldformat)
|
||||
self.assertEqual(1 | 2, features)
|
||||
|
||||
# initially, backup_ceph_image_journals = False. test that
|
||||
# the flags are defined, but that they are not returned.
|
||||
self.service.rbd.RBD_FEATURE_EXCLUSIVE_LOCK = 4
|
||||
|
||||
oldformat, features = self.service._get_rbd_support()
|
||||
self.assertFalse(oldformat)
|
||||
self.assertEqual(1 | 2, features)
|
||||
|
||||
self.service.rbd.RBD_FEATURE_JOURNALING = 64
|
||||
|
||||
oldformat, features = self.service._get_rbd_support()
|
||||
self.assertFalse(oldformat)
|
||||
self.assertEqual(1 | 2, features)
|
||||
|
||||
# test that the config setting properly sets the FEATURE bits.
|
||||
# because journaling requires exclusive-lock, these are set
|
||||
# at the same time.
|
||||
CONF.set_override("backup_ceph_image_journals", True)
|
||||
oldformat, features = self.service._get_rbd_support()
|
||||
self.assertFalse(oldformat)
|
||||
self.assertEqual(1 | 2 | 4 | 64, features)
|
||||
|
||||
@common_mocks
|
||||
def test_get_most_recent_snap(self):
|
||||
last = 'backup.%s.snap.9824923.1212' % (uuid.uuid4())
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Added new BoolOpt ``backup_ceph_image_journals`` for enabling the Ceph
|
||||
image features required to support RBD mirroring of Cinder backup pool.
|
Loading…
Reference in New Issue
Block a user