site_name = self._get('/api/block/mirroring/site_name')
self.assertStatus(200)
self.assertEqual(expected_site_name, site_name)
+
+ def test_bootstrap(self):
+ self.update_pool('rbd', 'image')
+ token_data = self._task_post('/api/block/mirroring/pool/rbd/bootstrap/token', {})
+ self.assertStatus(200)
+
+ import_data = {
+ 'token': token_data['token'],
+ 'direction': 'invalid'}
+ self._task_post('/api/block/mirroring/pool/rbd/bootstrap/peer', import_data)
+ self.assertStatus(400)
+
+ # cannot import "youself" as peer
+ import_data['direction'] = 'rx'
+ self._task_post('/api/block/mirroring/pool/rbd/bootstrap/peer', import_data)
+ self.assertStatus(400)
return _rbd_call(pool_name, None, _edit, mirror_mode)
+@ApiController('/block/mirroring/pool/{pool_name}/bootstrap',
+ Scope.RBD_MIRRORING)
+class RbdMirroringPoolBootstrap(BaseController):
+
+ @Endpoint(method='POST', path='token')
+ @handle_rbd_mirror_error()
+ @UpdatePermission
+ def create_token(self, pool_name):
+ ioctx = mgr.rados.open_ioctx(pool_name)
+ token = rbd.RBD().mirror_peer_bootstrap_create(ioctx)
+ return {'token': token}
+
+ @Endpoint(method='POST', path='peer')
+ @handle_rbd_mirror_error()
+ @UpdatePermission
+ def import_token(self, pool_name, direction, token):
+ ioctx = mgr.rados.open_ioctx(pool_name)
+
+ directions = {
+ 'rx': rbd.RBD_MIRROR_PEER_DIRECTION_RX,
+ 'rx-tx': rbd.RBD_MIRROR_PEER_DIRECTION_RX_TX
+ }
+
+ direction_enum = directions.get(direction)
+ if direction_enum is None:
+ raise rbd.Error('invalid direction "{}"'.format(direction))
+
+ rbd.RBD().mirror_peer_bootstrap_import(ioctx, direction_enum, token)
+ return {}
+
+
@ApiController('/block/mirroring/pool/{pool_name}/peer', Scope.RBD_MIRRORING)
class RbdMirroringPoolPeer(RESTController):
from . import ControllerTestCase
from .. import mgr
from ..controllers.summary import Summary
-from ..controllers.rbd_mirroring import RbdMirroring, RbdMirroringSummary
+from ..controllers.rbd_mirroring import RbdMirroring, RbdMirroringSummary, \
+ RbdMirroringPoolBootstrap
from ..services import progress
mock.ANY, result['site_name'])
+class RbdMirroringPoolBootstrapControllerTest(ControllerTestCase):
+
+ @classmethod
+ def setup_server(cls):
+ # pylint: disable=protected-access
+ RbdMirroringPoolBootstrap._cp_config['tools.authenticate.on'] = False
+ # pylint: enable=protected-access
+
+ cls.setup_controllers([RbdMirroringPoolBootstrap])
+
+ @mock.patch('dashboard.controllers.rbd_mirroring.rbd.RBD')
+ def test_token(self, mock_rbd):
+ mock_rbd_instance = mock_rbd.return_value
+ mock_rbd_instance.mirror_peer_bootstrap_create.return_value = "1234"
+
+ self._post('/api/block/mirroring/pool/abc/bootstrap/token')
+ self.assertStatus(200)
+ self.assertJsonBody({"token": "1234"})
+ mgr.rados.open_ioctx.assert_called_with("abc")
+
+ mock_rbd_instance.mirror_peer_bootstrap_create.assert_called()
+
+ @mock.patch('dashboard.controllers.rbd_mirroring.rbd')
+ def test_peer(self, mock_rbd_module):
+ mock_rbd_instance = mock_rbd_module.RBD.return_value
+
+ values = {
+ "direction": "invalid",
+ "token": "1234"
+ }
+ self._post('/api/block/mirroring/pool/abc/bootstrap/peer', values)
+ self.assertStatus(500)
+ mgr.rados.open_ioctx.assert_called_with("abc")
+
+ values["direction"] = "rx"
+ self._post('/api/block/mirroring/pool/abc/bootstrap/peer', values)
+ self.assertStatus(200)
+ self.assertJsonBody({})
+ mgr.rados.open_ioctx.assert_called_with("abc")
+
+ mock_rbd_instance.mirror_peer_bootstrap_import.assert_called_with(
+ mock.ANY, mock_rbd_module.RBD_MIRROR_PEER_DIRECTION_RX, '1234')
+
+
class RbdMirroringSummaryControllerTest(ControllerTestCase):
@classmethod