If the rbd driver fails to connect to Ceph the exception
was not being properly caught resulting in the volume
remaining in the 'creating' state until the corresponding
task eventually times out (on top of the time it took
for the connect to fail).
Also added config option for rados connect timeout.
DocImpact: new config option 'rados_connect_timout'
Closes-Bug:
1211839
Change-Id: I5e6eaaaf6bed3e139ff476ecf9510ebe214a83f9
@common_mocks
def test_connect_to_rados(self):
+ # Default
+ self.cfg.rados_connect_timeout = -1
+
self.mock_rados.Rados.connect = mock.Mock()
self.mock_rados.Rados.shutdown = mock.Mock()
self.mock_rados.Rados.open_ioctx = mock.Mock()
# default configured pool
ret = self.driver._connect_to_rados()
self.assertTrue(self.mock_rados.Rados.connect.called)
+ # Expect no timeout if default is used
+ self.mock_rados.Rados.connect.assert_called_once_with()
self.assertTrue(self.mock_rados.Rados.open_ioctx.called)
self.assertIsInstance(ret[0], self.mock_rados.Rados)
self.assertEqual(ret[1], self.mock_rados.Rados.ioctx)
self.assertEqual(ret[1], self.mock_rados.Rados.ioctx)
self.mock_rados.Rados.open_ioctx.assert_called_with('alt_pool')
+ # With timeout
+ self.cfg.rados_connect_timeout = 1
+ self.mock_rados.Rados.connect.reset_mock()
+ self.driver._connect_to_rados()
+ self.mock_rados.Rados.connect.assert_called_once_with(timeout=1)
+
# error
self.mock_rados.Rados.open_ioctx.reset_mock()
self.mock_rados.Rados.shutdown.reset_mock()
self.mock_rados.Rados.open_ioctx.side_effect = self.mock_rados.Error
- self.assertRaises(self.mock_rados.Error, self.driver._connect_to_rados)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver._connect_to_rados)
self.mock_rados.Rados.open_ioctx.assert_called_once()
self.mock_rados.Rados.shutdown.assert_called_once()
cfg.IntOpt('rbd_store_chunk_size', default=4,
help=_('Volumes will be chunked into objects of this size '
'(in megabytes).')),
+ cfg.IntOpt('rados_connect_timeout', default=-1,
+ help=_('Timeout value (in seconds) used when connecting to '
+ 'ceph cluster. If value < 0, no timeout is set and '
+ 'default librados value is used.'))
]
CONF = cfg.CONF
return args
def _connect_to_rados(self, pool=None):
+ LOG.debug("opening connection to ceph cluster (timeout=%s)." %
+ (self.configuration.rados_connect_timeout))
+
client = self.rados.Rados(rados_id=self.configuration.rbd_user,
conffile=self.configuration.rbd_ceph_conf)
if pool is not None:
pool = self.configuration.rbd_pool
try:
- client.connect()
+ if self.configuration.rados_connect_timeout >= 0:
+ client.connect(timeout=
+ self.configuration.rados_connect_timeout)
+ else:
+ client.connect()
ioctx = client.open_ioctx(pool)
return client, ioctx
- except self.rados.Error:
+ except self.rados.Error as exc:
+ LOG.error("error connecting to ceph cluster.")
# shutdown cannot raise an exception
client.shutdown()
- raise
+ raise exception.VolumeBackendAPIException(data=str(exc))
def _disconnect_from_rados(self, client, ioctx):
# closing an ioctx cannot raise an exception
# megabytes). (integer value)
#rbd_store_chunk_size=4
+# Timeout value (in seconds) used when connecting to ceph
+# cluster. If value < 0, no timeout is set and default
+# librados value is used. (integer value)
+#rados_connect_timeout=-1
+
#
# Options defined in cinder.volume.drivers.san.hp.hp_3par_common