]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/tests/test_iscsi.py
49dfc81d78c1031713ecbbf1bf67786d362a3ad4
1 # pylint: disable=too-many-public-methods
11 import unittest
.mock
as mock
13 from . import CmdException
, ControllerTestCase
, CLICommandTestMixin
, KVStoreMockMixin
15 from ..controllers
.iscsi
import Iscsi
, IscsiTarget
16 from ..services
.iscsi_client
import IscsiClient
17 from ..services
.orchestrator
import OrchClient
18 from ..rest_client
import RequestException
21 class IscsiTestCli(unittest
.TestCase
, CLICommandTestMixin
):
25 # pylint: disable=protected-access
26 IscsiClientMock
._instance
= IscsiClientMock()
27 IscsiClient
.instance
= IscsiClientMock
.instance
29 def test_cli_add_gateway_invalid_url(self
):
30 with self
.assertRaises(CmdException
) as ctx
:
31 self
.exec_cmd('iscsi-gateway-add', name
='node1',
32 service_url
='http:/hello.com')
34 self
.assertEqual(ctx
.exception
.retcode
, -errno
.EINVAL
)
35 self
.assertEqual(str(ctx
.exception
),
36 "Invalid service URL 'http:/hello.com'. Valid format: "
37 "'<scheme>://<username>:<password>@<host>[:port]'.")
39 def test_cli_add_gateway(self
):
40 self
.exec_cmd('iscsi-gateway-add', name
='node1',
41 service_url
='https://admin:admin@10.17.5.1:5001')
42 self
.exec_cmd('iscsi-gateway-add', name
='node2',
43 service_url
='https://admin:admin@10.17.5.2:5001')
44 iscsi_config
= json
.loads(self
.get_key("_iscsi_config"))
45 self
.assertEqual(iscsi_config
['gateways'], {
47 'service_url': 'https://admin:admin@10.17.5.1:5001'
50 'service_url': 'https://admin:admin@10.17.5.2:5001'
54 def test_cli_remove_gateway(self
):
55 self
.test_cli_add_gateway()
56 self
.exec_cmd('iscsi-gateway-rm', name
='node1')
57 iscsi_config
= json
.loads(self
.get_key("_iscsi_config"))
58 self
.assertEqual(iscsi_config
['gateways'], {
60 'service_url': 'https://admin:admin@10.17.5.2:5001'
65 class IscsiTestController(ControllerTestCase
, KVStoreMockMixin
):
68 def setup_server(cls
):
69 OrchClient
.instance().available
= lambda: False
70 mgr
.rados
.side_effect
= None
71 # pylint: disable=protected-access
72 Iscsi
._cp
_config
['tools.authenticate.on'] = False
73 IscsiTarget
._cp
_config
['tools.authenticate.on'] = False
74 cls
.setup_controllers([Iscsi
, IscsiTarget
])
78 self
.CONFIG_KEY_DICT
['_iscsi_config'] = '''
82 "service_url": "https://admin:admin@10.17.5.1:5001"
85 "service_url": "https://admin:admin@10.17.5.2:5001"
90 # pylint: disable=protected-access
91 IscsiClientMock
._instance
= IscsiClientMock()
92 IscsiClient
.instance
= IscsiClientMock
.instance
94 def test_enable_discoveryauth(self
):
96 'user': 'myiscsiusername',
97 'password': 'myiscsipassword',
98 'mutual_user': 'myiscsiusername2',
99 'mutual_password': 'myiscsipassword2'
101 self
._put
('/api/iscsi/discoveryauth', discoveryauth
)
102 self
.assertStatus(200)
103 self
.assertJsonBody(discoveryauth
)
104 self
._get
('/api/iscsi/discoveryauth')
105 self
.assertStatus(200)
106 self
.assertJsonBody(discoveryauth
)
108 def test_bad_discoveryauth(self
):
110 'user': 'myiscsiusername',
111 'password': 'myiscsipasswordmyiscsipasswordmyiscsipassword',
113 'mutual_password': ''
116 'detail': 'Bad authentication',
117 'code': 'target_bad_auth',
124 'mutual_password': ''
126 self
._put
('/api/iscsi/discoveryauth', discoveryauth
)
127 self
.assertStatus(400)
128 self
.assertJsonBody(put_response
)
129 self
._get
('/api/iscsi/discoveryauth')
130 self
.assertStatus(200)
131 self
.assertJsonBody(get_response
)
133 def test_disable_discoveryauth(self
):
138 'mutual_password': ''
140 self
._put
('/api/iscsi/discoveryauth', discoveryauth
)
141 self
.assertStatus(200)
142 self
.assertJsonBody(discoveryauth
)
143 self
._get
('/api/iscsi/discoveryauth')
144 self
.assertStatus(200)
145 self
.assertJsonBody(discoveryauth
)
147 def test_list_empty(self
):
148 self
._get
('/api/iscsi/target')
149 self
.assertStatus(200)
150 self
.assertJsonBody([])
152 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
153 def test_list(self
, _validate_image_mock
):
154 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw1"
155 request
= copy
.deepcopy(iscsi_target_request
)
156 request
['target_iqn'] = target_iqn
157 self
._task
_post
('/api/iscsi/target', request
)
158 self
.assertStatus(201)
159 self
._get
('/api/iscsi/target')
160 self
.assertStatus(200)
161 response
= copy
.deepcopy(iscsi_target_response
)
162 response
['target_iqn'] = target_iqn
163 self
.assertJsonBody([response
])
165 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
166 def test_create(self
, _validate_image_mock
):
167 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw2"
168 request
= copy
.deepcopy(iscsi_target_request
)
169 request
['target_iqn'] = target_iqn
170 self
._task
_post
('/api/iscsi/target', request
)
171 self
.assertStatus(201)
172 self
._get
('/api/iscsi/target/{}'.format(request
['target_iqn']))
173 self
.assertStatus(200)
174 response
= copy
.deepcopy(iscsi_target_response
)
175 response
['target_iqn'] = target_iqn
176 self
.assertJsonBody(response
)
178 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
179 def test_delete(self
, _validate_image_mock
):
180 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw3"
181 request
= copy
.deepcopy(iscsi_target_request
)
182 request
['target_iqn'] = target_iqn
183 self
._task
_post
('/api/iscsi/target', request
)
184 self
.assertStatus(201)
185 self
._task
_delete
('/api/iscsi/target/{}'.format(request
['target_iqn']))
186 self
.assertStatus(204)
187 self
._get
('/api/iscsi/target')
188 self
.assertStatus(200)
189 self
.assertJsonBody([])
191 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
192 def test_add_client(self
, _validate_image_mock
):
193 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw4"
194 create_request
= copy
.deepcopy(iscsi_target_request
)
195 create_request
['target_iqn'] = target_iqn
196 update_request
= copy
.deepcopy(create_request
)
197 update_request
['new_target_iqn'] = target_iqn
198 update_request
['clients'].append(
200 "luns": [{"image": "lun1", "pool": "rbd"}],
201 "client_iqn": "iqn.1994-05.com.redhat:rh7-client3",
203 "password": "myiscsipassword5",
204 "user": "myiscsiusername5",
205 "mutual_password": "myiscsipassword6",
206 "mutual_user": "myiscsiusername6"}
208 response
= copy
.deepcopy(iscsi_target_response
)
209 response
['target_iqn'] = target_iqn
210 response
['clients'].append(
212 "luns": [{"image": "lun1", "pool": "rbd"}],
213 "client_iqn": "iqn.1994-05.com.redhat:rh7-client3",
215 "password": "myiscsipassword5",
216 "user": "myiscsiusername5",
217 "mutual_password": "myiscsipassword6",
218 "mutual_user": "myiscsiusername6"},
225 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
227 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
228 def test_add_bad_client(self
, _validate_image_mock
):
229 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw4"
230 create_request
= copy
.deepcopy(iscsi_target_request
)
231 create_request
['target_iqn'] = target_iqn
232 update_request
= copy
.deepcopy(create_request
)
233 update_request
['new_target_iqn'] = target_iqn
234 update_request
['clients'].append(
236 "luns": [{"image": "lun1", "pool": "rbd"}],
237 "client_iqn": "iqn.1994-05.com.redhat:rh7-client4",
239 "password": "myiscsipassword7myiscsipassword7myiscsipasswo",
240 "user": "myiscsiusername7",
241 "mutual_password": "myiscsipassword8",
242 "mutual_user": "myiscsiusername8"}
244 response
= copy
.deepcopy(iscsi_target_response
)
245 response
['target_iqn'] = target_iqn
247 self
._task
_post
('/api/iscsi/target', create_request
)
248 self
.assertStatus(201)
249 self
._task
_put
('/api/iscsi/target/{}'.format(create_request
['target_iqn']), update_request
)
250 self
.assertStatus(400)
251 self
._get
('/api/iscsi/target/{}'.format(update_request
['new_target_iqn']))
252 self
.assertStatus(200)
253 self
.assertJsonBody(response
)
255 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
256 def test_change_client_password(self
, _validate_image_mock
):
257 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw5"
258 create_request
= copy
.deepcopy(iscsi_target_request
)
259 create_request
['target_iqn'] = target_iqn
260 update_request
= copy
.deepcopy(create_request
)
261 update_request
['new_target_iqn'] = target_iqn
262 update_request
['clients'][0]['auth']['password'] = 'MyNewPassword'
263 response
= copy
.deepcopy(iscsi_target_response
)
264 response
['target_iqn'] = target_iqn
265 response
['clients'][0]['auth']['password'] = 'MyNewPassword'
266 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
268 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
269 def test_rename_client(self
, _validate_image_mock
):
270 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw6"
271 create_request
= copy
.deepcopy(iscsi_target_request
)
272 create_request
['target_iqn'] = target_iqn
273 update_request
= copy
.deepcopy(create_request
)
274 update_request
['new_target_iqn'] = target_iqn
275 update_request
['clients'][0]['client_iqn'] = 'iqn.1994-05.com.redhat:rh7-client0'
276 response
= copy
.deepcopy(iscsi_target_response
)
277 response
['target_iqn'] = target_iqn
278 response
['clients'][0]['client_iqn'] = 'iqn.1994-05.com.redhat:rh7-client0'
279 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
281 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
282 def test_add_disk(self
, _validate_image_mock
):
283 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw7"
284 create_request
= copy
.deepcopy(iscsi_target_request
)
285 create_request
['target_iqn'] = target_iqn
286 update_request
= copy
.deepcopy(create_request
)
287 update_request
['new_target_iqn'] = target_iqn
288 update_request
['disks'].append(
293 "backstore": "user:rbd"
295 update_request
['clients'][0]['luns'].append({"image": "lun3", "pool": "rbd"})
296 response
= copy
.deepcopy(iscsi_target_response
)
297 response
['target_iqn'] = target_iqn
298 response
['disks'].append(
303 "backstore": "user:rbd",
304 "wwn": "64af6678-9694-4367-bacc-f8eb0baa2",
308 response
['clients'][0]['luns'].append({"image": "lun3", "pool": "rbd"})
309 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
311 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
312 def test_change_disk_image(self
, _validate_image_mock
):
313 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw8"
314 create_request
= copy
.deepcopy(iscsi_target_request
)
315 create_request
['target_iqn'] = target_iqn
316 update_request
= copy
.deepcopy(create_request
)
317 update_request
['new_target_iqn'] = target_iqn
318 update_request
['disks'][0]['image'] = 'lun0'
319 update_request
['clients'][0]['luns'][0]['image'] = 'lun0'
320 response
= copy
.deepcopy(iscsi_target_response
)
321 response
['target_iqn'] = target_iqn
322 response
['disks'][0]['image'] = 'lun0'
323 response
['clients'][0]['luns'][0]['image'] = 'lun0'
324 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
326 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
327 def test_change_disk_controls(self
, _validate_image_mock
):
328 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw9"
329 create_request
= copy
.deepcopy(iscsi_target_request
)
330 create_request
['target_iqn'] = target_iqn
331 update_request
= copy
.deepcopy(create_request
)
332 update_request
['new_target_iqn'] = target_iqn
333 update_request
['disks'][0]['controls'] = {"qfull_timeout": 15}
334 response
= copy
.deepcopy(iscsi_target_response
)
335 response
['target_iqn'] = target_iqn
336 response
['disks'][0]['controls'] = {"qfull_timeout": 15}
337 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
339 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
340 def test_rename_target(self
, _validate_image_mock
):
341 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw10"
342 new_target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw11"
343 create_request
= copy
.deepcopy(iscsi_target_request
)
344 create_request
['target_iqn'] = target_iqn
345 update_request
= copy
.deepcopy(create_request
)
346 update_request
['new_target_iqn'] = new_target_iqn
347 response
= copy
.deepcopy(iscsi_target_response
)
348 response
['target_iqn'] = new_target_iqn
349 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
351 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
352 def test_rename_group(self
, _validate_image_mock
):
353 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw12"
354 create_request
= copy
.deepcopy(iscsi_target_request
)
355 create_request
['target_iqn'] = target_iqn
356 update_request
= copy
.deepcopy(create_request
)
357 update_request
['new_target_iqn'] = target_iqn
358 update_request
['groups'][0]['group_id'] = 'mygroup0'
359 response
= copy
.deepcopy(iscsi_target_response
)
360 response
['target_iqn'] = target_iqn
361 response
['groups'][0]['group_id'] = 'mygroup0'
362 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
364 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
365 def test_add_client_to_group(self
, _validate_image_mock
):
366 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw13"
367 create_request
= copy
.deepcopy(iscsi_target_request
)
368 create_request
['target_iqn'] = target_iqn
369 update_request
= copy
.deepcopy(create_request
)
370 update_request
['new_target_iqn'] = target_iqn
371 update_request
['clients'].append(
374 "client_iqn": "iqn.1994-05.com.redhat:rh7-client3",
378 "mutual_password": None,
381 update_request
['groups'][0]['members'].append('iqn.1994-05.com.redhat:rh7-client3')
382 response
= copy
.deepcopy(iscsi_target_response
)
383 response
['target_iqn'] = target_iqn
384 response
['clients'].append(
387 "client_iqn": "iqn.1994-05.com.redhat:rh7-client3",
391 "mutual_password": None,
392 "mutual_user": None},
399 response
['groups'][0]['members'].append('iqn.1994-05.com.redhat:rh7-client3')
400 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
402 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
403 def test_remove_client_from_group(self
, _validate_image_mock
):
404 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw14"
405 create_request
= copy
.deepcopy(iscsi_target_request
)
406 create_request
['target_iqn'] = target_iqn
407 update_request
= copy
.deepcopy(create_request
)
408 update_request
['new_target_iqn'] = target_iqn
409 update_request
['groups'][0]['members'].remove('iqn.1994-05.com.redhat:rh7-client2')
410 response
= copy
.deepcopy(iscsi_target_response
)
411 response
['target_iqn'] = target_iqn
412 response
['groups'][0]['members'].remove('iqn.1994-05.com.redhat:rh7-client2')
413 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
415 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
416 def test_remove_groups(self
, _validate_image_mock
):
417 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw15"
418 create_request
= copy
.deepcopy(iscsi_target_request
)
419 create_request
['target_iqn'] = target_iqn
420 update_request
= copy
.deepcopy(create_request
)
421 update_request
['new_target_iqn'] = target_iqn
422 update_request
['groups'] = []
423 response
= copy
.deepcopy(iscsi_target_response
)
424 response
['target_iqn'] = target_iqn
425 response
['groups'] = []
426 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
428 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
429 def test_add_client_to_multiple_groups(self
, _validate_image_mock
):
430 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw16"
431 create_request
= copy
.deepcopy(iscsi_target_request
)
432 create_request
['target_iqn'] = target_iqn
433 create_request
['groups'].append(copy
.deepcopy(create_request
['groups'][0]))
434 create_request
['groups'][1]['group_id'] = 'mygroup2'
435 self
._task
_post
('/api/iscsi/target', create_request
)
436 self
.assertStatus(400)
437 self
.assertJsonBody({
438 'detail': 'Each initiator can only be part of 1 group at a time',
439 'code': 'initiator_in_multiple_groups',
443 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
444 def test_remove_client_lun(self
, _validate_image_mock
):
445 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw17"
446 create_request
= copy
.deepcopy(iscsi_target_request
)
447 create_request
['target_iqn'] = target_iqn
448 create_request
['clients'][0]['luns'] = [
449 {"image": "lun1", "pool": "rbd"},
450 {"image": "lun2", "pool": "rbd"},
451 {"image": "lun3", "pool": "rbd"}
453 update_request
= copy
.deepcopy(create_request
)
454 update_request
['new_target_iqn'] = target_iqn
455 update_request
['clients'][0]['luns'] = [
456 {"image": "lun1", "pool": "rbd"},
457 {"image": "lun3", "pool": "rbd"}
459 response
= copy
.deepcopy(iscsi_target_response
)
460 response
['target_iqn'] = target_iqn
461 response
['clients'][0]['luns'] = [
462 {"image": "lun1", "pool": "rbd"},
463 {"image": "lun3", "pool": "rbd"}
465 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
467 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
468 def test_change_client_auth(self
, _validate_image_mock
):
469 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw18"
470 create_request
= copy
.deepcopy(iscsi_target_request
)
471 create_request
['target_iqn'] = target_iqn
472 update_request
= copy
.deepcopy(create_request
)
473 update_request
['new_target_iqn'] = target_iqn
474 update_request
['clients'][0]['auth']['password'] = 'myiscsipasswordX'
475 response
= copy
.deepcopy(iscsi_target_response
)
476 response
['target_iqn'] = target_iqn
477 response
['clients'][0]['auth']['password'] = 'myiscsipasswordX'
478 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
480 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
481 def test_remove_client_logged_in(self
, _validate_image_mock
):
485 'state': {'LOGGED_IN': ['node1']}
487 # pylint: disable=protected-access
488 IscsiClientMock
._instance
.clientinfo
= client_info
489 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw19"
490 create_request
= copy
.deepcopy(iscsi_target_request
)
491 create_request
['target_iqn'] = target_iqn
492 update_request
= copy
.deepcopy(create_request
)
493 update_request
['new_target_iqn'] = target_iqn
494 update_request
['clients'].pop(0)
495 response
= copy
.deepcopy(iscsi_target_response
)
496 response
['target_iqn'] = target_iqn
497 for client
in response
['clients']:
498 client
['info'] = client_info
500 'detail': "Client 'iqn.1994-05.com.redhat:rh7-client' cannot be deleted until it's "
502 'code': 'client_logged_in',
505 self
._update
_iscsi
_target
(create_request
, update_request
, 400, update_response
, response
)
507 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
508 def test_remove_client(self
, _validate_image_mock
):
509 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw20"
510 create_request
= copy
.deepcopy(iscsi_target_request
)
511 create_request
['target_iqn'] = target_iqn
512 update_request
= copy
.deepcopy(create_request
)
513 update_request
['new_target_iqn'] = target_iqn
514 update_request
['clients'].pop(0)
515 response
= copy
.deepcopy(iscsi_target_response
)
516 response
['target_iqn'] = target_iqn
517 response
['clients'].pop(0)
518 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
520 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
521 def test_add_image_to_group_with_client_logged_in(self
, _validate_image_mock
):
525 'state': {'LOGGED_IN': ['node1']}
527 new_disk
= {"pool": "rbd", "image": "lun1"}
528 # pylint: disable=protected-access
529 IscsiClientMock
._instance
.clientinfo
= client_info
530 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw21"
531 create_request
= copy
.deepcopy(iscsi_target_request
)
532 create_request
['target_iqn'] = target_iqn
533 update_request
= copy
.deepcopy(create_request
)
534 update_request
['new_target_iqn'] = target_iqn
535 update_request
['groups'][0]['disks'].append(new_disk
)
536 response
= copy
.deepcopy(iscsi_target_response
)
537 response
['target_iqn'] = target_iqn
538 response
['groups'][0]['disks'].insert(0, new_disk
)
539 for client
in response
['clients']:
540 client
['info'] = client_info
541 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
543 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
544 def test_add_image_to_initiator_with_client_logged_in(self
, _validate_image_mock
):
548 'state': {'LOGGED_IN': ['node1']}
550 new_disk
= {"pool": "rbd", "image": "lun2"}
551 # pylint: disable=protected-access
552 IscsiClientMock
._instance
.clientinfo
= client_info
553 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw22"
554 create_request
= copy
.deepcopy(iscsi_target_request
)
555 create_request
['target_iqn'] = target_iqn
556 update_request
= copy
.deepcopy(create_request
)
557 update_request
['new_target_iqn'] = target_iqn
558 update_request
['clients'][0]['luns'].append(new_disk
)
559 response
= copy
.deepcopy(iscsi_target_response
)
560 response
['target_iqn'] = target_iqn
561 response
['clients'][0]['luns'].append(new_disk
)
562 for client
in response
['clients']:
563 client
['info'] = client_info
564 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
566 @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image')
567 def test_remove_image_from_group_with_client_logged_in(self
, _validate_image_mock
):
571 'state': {'LOGGED_IN': ['node1']}
573 # pylint: disable=protected-access
574 IscsiClientMock
._instance
.clientinfo
= client_info
575 target_iqn
= "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw23"
576 create_request
= copy
.deepcopy(iscsi_target_request
)
577 create_request
['target_iqn'] = target_iqn
578 update_request
= copy
.deepcopy(create_request
)
579 update_request
['new_target_iqn'] = target_iqn
580 update_request
['groups'][0]['disks'] = []
581 response
= copy
.deepcopy(iscsi_target_response
)
582 response
['target_iqn'] = target_iqn
583 response
['groups'][0]['disks'] = []
584 for client
in response
['clients']:
585 client
['info'] = client_info
586 self
._update
_iscsi
_target
(create_request
, update_request
, 200, None, response
)
588 def _update_iscsi_target(self
, create_request
, update_request
, update_response_code
,
589 update_response
, response
):
590 self
._task
_post
('/api/iscsi/target', create_request
)
591 self
.assertStatus(201)
592 self
._task
_put
('/api/iscsi/target/{}'.format(create_request
['target_iqn']), update_request
)
593 self
.assertStatus(update_response_code
)
594 self
.assertJsonBody(update_response
)
595 self
._get
('/api/iscsi/target/{}'.format(update_request
['new_target_iqn']))
596 self
.assertStatus(200)
597 self
.assertJsonBody(response
)
600 iscsi_target_request
= {
601 "target_iqn": "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw",
603 {"ip": "192.168.100.202", "host": "node2"},
604 {"ip": "10.0.2.15", "host": "node2"},
605 {"ip": "192.168.100.203", "host": "node3"}
608 {"image": "lun1", "pool": "rbd", "backstore": "user:rbd",
609 "controls": {"max_data_area_mb": 128}},
610 {"image": "lun2", "pool": "rbd", "backstore": "user:rbd",
611 "controls": {"max_data_area_mb": 128}}
615 "luns": [{"image": "lun1", "pool": "rbd"}],
616 "client_iqn": "iqn.1994-05.com.redhat:rh7-client",
618 "password": "myiscsipassword1",
619 "user": "myiscsiusername1",
620 "mutual_password": "myiscsipassword2",
621 "mutual_user": "myiscsiusername2"}
625 "client_iqn": "iqn.1994-05.com.redhat:rh7-client2",
627 "password": "myiscsipassword3",
628 "user": "myiscsiusername3",
629 "mutual_password": "myiscsipassword4",
630 "mutual_user": "myiscsiusername4"
638 "mutual_password": "",
640 "target_controls": {},
643 "group_id": "mygroup",
644 "disks": [{"pool": "rbd", "image": "lun2"}],
645 "members": ["iqn.1994-05.com.redhat:rh7-client2"]
650 iscsi_target_response
= {
651 'target_iqn': 'iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw',
653 {'host': 'node2', 'ip': '10.0.2.15'},
654 {'host': 'node2', 'ip': '192.168.100.202'},
655 {'host': 'node3', 'ip': '192.168.100.203'}
658 {'pool': 'rbd', 'image': 'lun1', 'backstore': 'user:rbd',
659 'wwn': '64af6678-9694-4367-bacc-f8eb0baa0', 'lun': 0,
660 'controls': {'max_data_area_mb': 128}},
661 {'pool': 'rbd', 'image': 'lun2', 'backstore': 'user:rbd',
662 'wwn': '64af6678-9694-4367-bacc-f8eb0baa1', 'lun': 1,
663 'controls': {'max_data_area_mb': 128}}
667 'client_iqn': 'iqn.1994-05.com.redhat:rh7-client',
668 'luns': [{'pool': 'rbd', 'image': 'lun1'}],
670 'user': 'myiscsiusername1',
671 'password': 'myiscsipassword1',
672 'mutual_password': 'myiscsipassword2',
673 'mutual_user': 'myiscsiusername2'
682 'client_iqn': 'iqn.1994-05.com.redhat:rh7-client2',
685 'user': 'myiscsiusername3',
686 'password': 'myiscsipassword3',
687 'mutual_password': 'myiscsipassword4',
688 'mutual_user': 'myiscsiusername4'
701 "mutual_password": "",
705 'group_id': 'mygroup',
706 'disks': [{'pool': 'rbd', 'image': 'lun2'}],
707 'members': ['iqn.1994-05.com.redhat:rh7-client2']
710 'target_controls': {},
717 class IscsiClientMock(object):
722 self
.gateway_name
= None
723 self
.service_url
= None
725 "created": "2019/01/17 08:57:16",
729 "password_encryption_enabled": False,
730 "mutual_username": "",
731 "mutual_password": "",
732 "mutual_password_encryption_enabled": False
748 def instance(cls
, gateway_name
=None, service_url
=None):
749 cls
._instance
.gateway_name
= gateway_name
750 cls
._instance
.service_url
= service_url
751 # pylint: disable=unused-argument
759 def get_settings(self
):
766 "minimum_gateways": 2
768 "default_backstore": "user:rbd",
769 "required_rbd_features": {
773 "unsupported_rbd_features": {
777 "disk_default_controls": {
779 "hw_max_sectors": 1024,
780 "max_data_area_mb": 8,
781 "osd_op_timeout": 30,
785 "target_default_controls": {
787 "dataout_timeout": 20,
788 "first_burst_length": 262144,
789 "immediate_data": "Yes",
790 "initial_r2t": "Yes",
791 "max_burst_length": 524288,
792 "max_outstanding_r2t": 1,
793 "max_recv_data_segment_length": 262144,
794 "max_xmit_data_segment_length": 262144,
795 "nopin_response_timeout": 5,
800 def get_config(self
):
801 return copy
.deepcopy(self
.config
)
803 def create_target(self
, target_iqn
, target_controls
):
804 self
.config
['targets'][target_iqn
] = {
810 "password_encryption_enabled": False,
811 "mutual_username": "",
812 "mutual_password": "",
813 "mutual_password_encryption_enabled": False
815 "controls": target_controls
,
816 "created": "2019/01/17 09:22:34",
822 def create_gateway(self
, target_iqn
, gateway_name
, ip_addresses
):
823 target_config
= self
.config
['targets'][target_iqn
]
824 if 'ip_list' not in target_config
:
825 target_config
['ip_list'] = []
826 target_config
['ip_list'] += ip_addresses
827 target_config
['portals'][gateway_name
] = {
828 "portal_ip_addresses": ip_addresses
831 def delete_gateway(self
, target_iqn
, gateway_name
):
832 target_config
= self
.config
['targets'][target_iqn
]
833 portal_config
= target_config
['portals'][gateway_name
]
834 for ip
in portal_config
['portal_ip_addresses']:
835 target_config
['ip_list'].remove(ip
)
836 target_config
['portals'].pop(gateway_name
)
838 def create_disk(self
, pool
, image
, backstore
, wwn
):
840 wwn
= '64af6678-9694-4367-bacc-f8eb0baa' + str(len(self
.config
['disks']))
841 image_id
= '{}/{}'.format(pool
, image
)
842 self
.config
['disks'][image_id
] = {
845 "backstore": backstore
,
850 def create_target_lun(self
, target_iqn
, image_id
, lun
):
851 target_config
= self
.config
['targets'][target_iqn
]
853 lun
= len(target_config
['disks'])
854 target_config
['disks'][image_id
] = {
857 self
.config
['disks'][image_id
]['owner'] = list(target_config
['portals'].keys())[0]
859 def reconfigure_disk(self
, pool
, image
, controls
):
860 image_id
= '{}/{}'.format(pool
, image
)
861 settings
= self
.get_settings()
862 backstore
= self
.config
['disks'][image_id
]['backstore']
863 disk_default_controls
= settings
['disk_default_controls'][backstore
]
865 for control_k
, control_v
in controls
.items():
866 if control_v
!= disk_default_controls
[control_k
]:
867 new_controls
[control_k
] = control_v
868 self
.config
['disks'][image_id
]['controls'] = new_controls
870 def create_client(self
, target_iqn
, client_iqn
):
871 target_config
= self
.config
['targets'][target_iqn
]
872 target_config
['clients'][client_iqn
] = {
876 "password_encryption_enabled": False,
877 "mutual_username": "",
878 "mutual_password": "",
879 "mutual_password_encryption_enabled": False
885 def create_client_lun(self
, target_iqn
, client_iqn
, image_id
):
886 target_config
= self
.config
['targets'][target_iqn
]
887 target_config
['clients'][client_iqn
]['luns'][image_id
] = {}
889 def delete_client_lun(self
, target_iqn
, client_iqn
, image_id
):
890 target_config
= self
.config
['targets'][target_iqn
]
891 del target_config
['clients'][client_iqn
]['luns'][image_id
]
893 def create_client_auth(self
, target_iqn
, client_iqn
, user
, password
, m_user
, m_password
):
894 target_config
= self
.config
['targets'][target_iqn
]
895 target_config
['clients'][client_iqn
]['auth']['username'] = user
896 target_config
['clients'][client_iqn
]['auth']['password'] = password
897 target_config
['clients'][client_iqn
]['auth']['mutual_username'] = m_user
898 target_config
['clients'][client_iqn
]['auth']['mutual_password'] = m_password
900 def create_group(self
, target_iqn
, group_name
, members
, image_ids
):
901 target_config
= self
.config
['targets'][target_iqn
]
902 target_config
['groups'][group_name
] = {
906 for image_id
in image_ids
:
907 target_config
['groups'][group_name
]['disks'][image_id
] = {}
908 target_config
['groups'][group_name
]['members'] = members
910 def update_group(self
, target_iqn
, group_name
, members
, image_ids
):
911 target_config
= self
.config
['targets'][target_iqn
]
912 group
= target_config
['groups'][group_name
]
913 old_members
= group
['members']
914 disks
= group
['disks']
915 target_config
['groups'][group_name
] = {
920 for image_id
in disks
.keys():
921 if image_id
not in image_ids
:
922 target_config
['groups'][group_name
]['disks'][image_id
] = {}
925 for member_iqn
in old_members
:
926 if member_iqn
not in members
:
927 new_members
.append(member_iqn
)
928 target_config
['groups'][group_name
]['members'] = new_members
930 def delete_group(self
, target_iqn
, group_name
):
931 target_config
= self
.config
['targets'][target_iqn
]
932 del target_config
['groups'][group_name
]
934 def delete_client(self
, target_iqn
, client_iqn
):
935 target_config
= self
.config
['targets'][target_iqn
]
936 del target_config
['clients'][client_iqn
]
938 def delete_target_lun(self
, target_iqn
, image_id
):
939 target_config
= self
.config
['targets'][target_iqn
]
940 target_config
['disks'].pop(image_id
)
941 del self
.config
['disks'][image_id
]['owner']
943 def delete_disk(self
, pool
, image
):
944 image_id
= '{}/{}'.format(pool
, image
)
945 del self
.config
['disks'][image_id
]
947 def delete_target(self
, target_iqn
):
948 del self
.config
['targets'][target_iqn
]
950 def get_ip_addresses(self
):
952 'node1': ['192.168.100.201'],
953 'node2': ['192.168.100.202', '10.0.2.15'],
954 'node3': ['192.168.100.203']
956 return {'data': ips
[self
.gateway_name
]}
958 def get_hostname(self
):
960 'https://admin:admin@10.17.5.1:5001': 'node1',
961 'https://admin:admin@10.17.5.2:5001': 'node2',
962 'https://admin:admin@10.17.5.3:5001': 'node3'
964 if self
.service_url
not in hostnames
:
965 raise RequestException('No route to host')
966 return {'data': hostnames
[self
.service_url
]}
968 def update_discoveryauth(self
, user
, password
, mutual_user
, mutual_password
):
969 self
.config
['discovery_auth']['username'] = user
970 self
.config
['discovery_auth']['password'] = password
971 self
.config
['discovery_auth']['mutual_username'] = mutual_user
972 self
.config
['discovery_auth']['mutual_password'] = mutual_password
974 def update_targetacl(self
, target_iqn
, action
):
975 self
.config
['targets'][target_iqn
]['acl_enabled'] = (action
== 'enable_acl')
977 def update_targetauth(self
, target_iqn
, user
, password
, mutual_user
, mutual_password
):
978 target_config
= self
.config
['targets'][target_iqn
]
979 target_config
['auth']['username'] = user
980 target_config
['auth']['password'] = password
981 target_config
['auth']['mutual_username'] = mutual_user
982 target_config
['auth']['mutual_password'] = mutual_password
984 def get_targetinfo(self
, target_iqn
):
985 # pylint: disable=unused-argument
990 def get_clientinfo(self
, target_iqn
, client_iqn
):
991 # pylint: disable=unused-argument
992 return self
.clientinfo