10 import unittest
.mock
as mock
13 from ..controllers
.orchestrator
import Orchestrator
14 from ..controllers
.rbd_mirroring
import RbdMirroring
, \
15 RbdMirroringPoolBootstrap
, RbdMirroringStatus
, RbdMirroringSummary
, \
16 get_daemons
, get_pools
17 from ..controllers
.summary
import Summary
18 from ..services
import progress
19 from ..tests
import ControllerTestCase
21 mock_list_servers
= [{
22 'hostname': 'ceph-host',
23 'services': [{'id': 3, 'type': 'rbd-mirror'}]
29 'ceph_version': 'ceph version 13.0.0-5719 mimic (dev)'
35 'image_local_count': 5,
36 'image_remote_count': 6,
37 'image_error_count': 7,
38 'image_warning_count': 8,
43 mock_get_daemon_status
= {
44 'json': json
.dumps(_status
)
50 'application_metadata': {'rbd'}
55 class GetDaemonAndPoolsTest(unittest
.TestCase
):
58 mgr
.list_servers
.return_value
= mock_list_servers
59 mgr
.get_metadata
= mock
.Mock(return_value
=mock_get_metadata
)
60 mgr
.get_daemon_status
.return_value
= mock_get_daemon_status
61 mgr
.get
.side_effect
= lambda key
: {
62 'osd_map': mock_osd_map
,
63 'health': {'json': '{"status": 1}'},
64 'fs_map': {'filesystems': []},
67 'dashboard': 'https://ceph.dev:11000/'
72 mgr
.get_mgr_id
.return_value
= 0
73 mgr
.have_mon_connection
.return_value
= True
74 mgr
.version
= 'ceph version 13.1.0-534-g23d3751b89 ' \
75 '(23d3751b897b31d2bda57aeaf01acb5ff3c4a9cd) ' \
78 progress
.get_progress_tasks
= mock
.MagicMock()
79 progress
.get_progress_tasks
.return_value
= ([], [])
81 @mock.patch('rbd.RBD')
82 def test_get_pools_unknown(self
, mock_rbd
):
83 mock_rbd_instance
= mock_rbd
.return_value
84 mock_rbd_instance
.mirror_mode_get
.side_effect
= Exception
85 daemons
= get_daemons()
86 res
= get_pools(daemons
)
87 self
.assertTrue(res
['rbd']['mirror_mode'] == "unknown")
89 @mock.patch('rbd.RBD')
90 def test_get_pools_mode(self
, mock_rbd
):
92 daemons
= get_daemons()
93 mock_rbd_instance
= mock_rbd
.return_value
95 (rbd
.RBD_MIRROR_MODE_DISABLED
, "disabled"),
96 (rbd
.RBD_MIRROR_MODE_IMAGE
, "image"),
97 (rbd
.RBD_MIRROR_MODE_POOL
, "pool"),
99 mock_rbd_instance
.mirror_peer_list
.return_value
= []
100 for mirror_mode
, expected
in testcases
:
101 mock_rbd_instance
.mirror_mode_get
.return_value
= mirror_mode
102 res
= get_pools(daemons
)
103 self
.assertTrue(res
['rbd']['mirror_mode'] == expected
)
105 @mock.patch('rbd.RBD')
106 def test_get_pools_health(self
, mock_rbd
):
108 mock_rbd_instance
= mock_rbd
.return_value
109 mock_rbd_instance
.mirror_peer_list
.return_value
= []
110 test_cases
= self
._get
_pool
_test
_cases
()
111 for new_status
, mirror_mode
, expected_output
in test_cases
:
112 _status
[1].update(new_status
)
114 'json': json
.dumps(_status
)
116 mgr
.get_daemon_status
.return_value
= daemon_status
117 daemons
= get_daemons()
118 mock_rbd_instance
.mirror_mode_get
.return_value
= mirror_mode
119 res
= get_pools(daemons
)
120 for k
, v
in expected_output
.items():
121 self
.assertTrue(v
== res
['rbd'][k
])
122 mgr
.get_daemon_status
.return_value
= mock_get_daemon_status
# reset return value
124 def _get_pool_test_cases(self
):
128 'image_error_count': 7,
130 rbd
.RBD_MIRROR_MODE_IMAGE
,
132 'health_color': 'warning',
138 'image_error_count': 7,
140 rbd
.RBD_MIRROR_MODE_DISABLED
,
142 'health_color': 'error',
148 'image_error_count': 0,
149 'image_warning_count': 0,
152 rbd
.RBD_MIRROR_MODE_DISABLED
,
154 'health_color': 'info',
162 class RbdMirroringControllerTest(ControllerTestCase
):
165 def setup_server(cls
):
166 cls
.setup_controllers([RbdMirroring
])
168 @mock.patch('dashboard.controllers.rbd_mirroring.rbd.RBD')
169 def test_site_name(self
, mock_rbd
):
170 result
= {'site_name': 'fsid'}
171 mock_rbd_instance
= mock_rbd
.return_value
172 mock_rbd_instance
.mirror_site_name_get
.return_value
= \
175 self
._get
('/api/block/mirroring/site_name')
176 self
.assertStatus(200)
177 self
.assertJsonBody(result
)
179 result
['site_name'] = 'site-a'
180 mock_rbd_instance
.mirror_site_name_get
.return_value
= \
182 self
._put
('/api/block/mirroring/site_name', result
)
183 self
.assertStatus(200)
184 self
.assertJsonBody(result
)
185 mock_rbd_instance
.mirror_site_name_set
.assert_called_with(
186 mock
.ANY
, result
['site_name'])
189 class RbdMirroringPoolBootstrapControllerTest(ControllerTestCase
):
192 def setup_server(cls
):
193 cls
.setup_controllers([RbdMirroringPoolBootstrap
])
195 @mock.patch('dashboard.controllers.rbd_mirroring.rbd.RBD')
196 def test_token(self
, mock_rbd
):
197 mock_rbd_instance
= mock_rbd
.return_value
198 mock_rbd_instance
.mirror_peer_bootstrap_create
.return_value
= "1234"
200 self
._post
('/api/block/mirroring/pool/abc/bootstrap/token')
201 self
.assertStatus(200)
202 self
.assertJsonBody({"token": "1234"})
203 mgr
.rados
.open_ioctx
.assert_called_with("abc")
205 mock_rbd_instance
.mirror_peer_bootstrap_create
.assert_called()
207 @mock.patch('dashboard.controllers.rbd_mirroring.rbd')
208 def test_peer(self
, mock_rbd_module
):
209 mock_rbd_instance
= mock_rbd_module
.RBD
.return_value
212 "direction": "invalid",
215 self
._post
('/api/block/mirroring/pool/abc/bootstrap/peer', values
)
216 self
.assertStatus(500)
217 mgr
.rados
.open_ioctx
.assert_called_with("abc")
219 values
["direction"] = "rx"
220 self
._post
('/api/block/mirroring/pool/abc/bootstrap/peer', values
)
221 self
.assertStatus(200)
222 self
.assertJsonBody({})
223 mgr
.rados
.open_ioctx
.assert_called_with("abc")
225 mock_rbd_instance
.mirror_peer_bootstrap_import
.assert_called_with(
226 mock
.ANY
, mock_rbd_module
.RBD_MIRROR_PEER_DIRECTION_RX
, '1234')
229 class RbdMirroringSummaryControllerTest(ControllerTestCase
):
232 def setup_server(cls
):
233 mgr
.list_servers
.return_value
= mock_list_servers
234 mgr
.get_metadata
= mock
.Mock(return_value
=mock_get_metadata
)
235 mgr
.get_daemon_status
.return_value
= mock_get_daemon_status
236 mgr
.get
.side_effect
= lambda key
: {
237 'osd_map': mock_osd_map
,
238 'health': {'json': '{"status": 1}'},
239 'fs_map': {'filesystems': []},
242 'dashboard': 'https://ceph.dev:11000/'
247 mgr
.get_mgr_id
.return_value
= 0
248 mgr
.have_mon_connection
.return_value
= True
249 mgr
.version
= 'ceph version 13.1.0-534-g23d3751b89 ' \
250 '(23d3751b897b31d2bda57aeaf01acb5ff3c4a9cd) ' \
253 progress
.get_progress_tasks
= mock
.MagicMock()
254 progress
.get_progress_tasks
.return_value
= ([], [])
256 cls
.setup_controllers([RbdMirroringSummary
, Summary
], '/test')
258 @mock.patch('dashboard.controllers.rbd_mirroring.rbd.RBD')
259 def test_default(self
, mock_rbd
):
260 mock_rbd_instance
= mock_rbd
.return_value
261 mock_rbd_instance
.mirror_site_name_get
.return_value
= 'site-a'
263 self
._get
('/test/api/block/mirroring/summary')
264 result
= self
.json_body()
265 self
.assertStatus(200)
266 self
.assertEqual(result
['site_name'], 'site-a')
267 self
.assertEqual(result
['status'], 0)
268 for k
in ['daemons', 'pools', 'image_error', 'image_syncing', 'image_ready']:
269 self
.assertIn(k
, result
['content_data'])
271 @mock.patch('dashboard.controllers.BaseController._has_permissions')
272 @mock.patch('dashboard.controllers.rbd_mirroring.rbd.RBD')
273 def test_summary(self
, mock_rbd
, has_perms_mock
):
274 """We're also testing `summary`, as it also uses code from `rbd_mirroring.py`"""
275 mock_rbd_instance
= mock_rbd
.return_value
276 mock_rbd_instance
.mirror_site_name_get
.return_value
= 'site-a'
278 has_perms_mock
.return_value
= True
279 self
._get
('/test/api/summary')
280 self
.assertStatus(200)
282 summary
= self
.json_body()['rbd_mirroring']
283 self
.assertEqual(summary
, {'errors': 0, 'warnings': 1})
286 class RbdMirroringStatusControllerTest(ControllerTestCase
):
289 def setup_server(cls
):
290 cls
.setup_controllers([RbdMirroringStatus
, Orchestrator
])
292 @mock.patch('dashboard.controllers.orchestrator.OrchClient.instance')
293 def test_status(self
, instance
):
294 status
= {'available': False, 'description': ''}
295 fake_client
= mock
.Mock()
296 fake_client
.status
.return_value
= status
297 instance
.return_value
= fake_client
299 self
._get
('/ui-api/block/mirroring/status')
300 self
.assertStatus(200)
301 self
.assertJsonBody({'available': True, 'message': None})
303 def test_configure(self
):
304 self
._post
('/ui-api/block/mirroring/configure')
305 self
.assertStatus(200)