]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | # pylint: disable=too-many-public-methods |
2 | ||
3 | import copy | |
4 | import errno | |
5 | import json | |
92f5a8d4 | 6 | import unittest |
11fdf7f2 | 7 | |
92f5a8d4 TL |
8 | try: |
9 | import mock | |
10 | except ImportError: | |
11 | import unittest.mock as mock | |
12 | ||
13 | from . import CmdException, ControllerTestCase, CLICommandTestMixin, KVStoreMockMixin | |
11fdf7f2 TL |
14 | from .. import mgr |
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 | |
19 | ||
20 | ||
92f5a8d4 | 21 | class IscsiTestCli(unittest.TestCase, CLICommandTestMixin): |
11fdf7f2 TL |
22 | |
23 | def setUp(self): | |
24 | self.mock_kv_store() | |
25 | # pylint: disable=protected-access | |
26 | IscsiClientMock._instance = IscsiClientMock() | |
27 | IscsiClient.instance = IscsiClientMock.instance | |
28 | ||
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') | |
33 | ||
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]'.") | |
38 | ||
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'], { | |
46 | 'node1': { | |
47 | 'service_url': 'https://admin:admin@10.17.5.1:5001' | |
48 | }, | |
49 | 'node2': { | |
50 | 'service_url': 'https://admin:admin@10.17.5.2:5001' | |
51 | } | |
52 | }) | |
53 | ||
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'], { | |
59 | 'node2': { | |
60 | 'service_url': 'https://admin:admin@10.17.5.2:5001' | |
61 | } | |
62 | }) | |
63 | ||
92f5a8d4 TL |
64 | |
65 | class IscsiTestController(ControllerTestCase, KVStoreMockMixin): | |
66 | ||
67 | @classmethod | |
68 | def setup_server(cls): | |
9f95a23c | 69 | OrchClient.instance().available = lambda: False |
92f5a8d4 TL |
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]) | |
75 | ||
76 | def setUp(self): | |
77 | self.mock_kv_store() | |
78 | self.CONFIG_KEY_DICT['_iscsi_config'] = ''' | |
79 | { | |
80 | "gateways": { | |
81 | "node1": { | |
82 | "service_url": "https://admin:admin@10.17.5.1:5001" | |
83 | }, | |
84 | "node2": { | |
85 | "service_url": "https://admin:admin@10.17.5.2:5001" | |
86 | } | |
87 | } | |
88 | } | |
89 | ''' | |
90 | # pylint: disable=protected-access | |
91 | IscsiClientMock._instance = IscsiClientMock() | |
92 | IscsiClient.instance = IscsiClientMock.instance | |
93 | ||
11fdf7f2 TL |
94 | def test_enable_discoveryauth(self): |
95 | discoveryauth = { | |
96 | 'user': 'myiscsiusername', | |
97 | 'password': 'myiscsipassword', | |
98 | 'mutual_user': 'myiscsiusername2', | |
99 | 'mutual_password': 'myiscsipassword2' | |
100 | } | |
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) | |
107 | ||
1911f103 TL |
108 | def test_bad_discoveryauth(self): |
109 | discoveryauth = { | |
110 | 'user': 'myiscsiusername', | |
111 | 'password': 'myiscsipasswordmyiscsipasswordmyiscsipassword', | |
112 | 'mutual_user': '', | |
113 | 'mutual_password': '' | |
114 | } | |
115 | put_response = { | |
116 | 'detail': 'Bad authentication', | |
117 | 'code': 'target_bad_auth', | |
118 | 'component': 'iscsi' | |
119 | } | |
120 | get_response = { | |
121 | 'user': '', | |
122 | 'password': '', | |
123 | 'mutual_user': '', | |
124 | 'mutual_password': '' | |
125 | } | |
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) | |
132 | ||
11fdf7f2 TL |
133 | def test_disable_discoveryauth(self): |
134 | discoveryauth = { | |
135 | 'user': '', | |
136 | 'password': '', | |
137 | 'mutual_user': '', | |
138 | 'mutual_password': '' | |
139 | } | |
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) | |
146 | ||
147 | def test_list_empty(self): | |
148 | self._get('/api/iscsi/target') | |
149 | self.assertStatus(200) | |
150 | self.assertJsonBody([]) | |
151 | ||
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 | |
eafe8130 | 157 | self._task_post('/api/iscsi/target', request) |
11fdf7f2 TL |
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]) | |
164 | ||
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 | |
eafe8130 | 170 | self._task_post('/api/iscsi/target', request) |
11fdf7f2 TL |
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) | |
177 | ||
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 | |
eafe8130 | 183 | self._task_post('/api/iscsi/target', request) |
11fdf7f2 | 184 | self.assertStatus(201) |
eafe8130 | 185 | self._task_delete('/api/iscsi/target/{}'.format(request['target_iqn'])) |
11fdf7f2 TL |
186 | self.assertStatus(204) |
187 | self._get('/api/iscsi/target') | |
188 | self.assertStatus(200) | |
189 | self.assertJsonBody([]) | |
190 | ||
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( | |
199 | { | |
200 | "luns": [{"image": "lun1", "pool": "rbd"}], | |
201 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client3", | |
202 | "auth": { | |
203 | "password": "myiscsipassword5", | |
204 | "user": "myiscsiusername5", | |
205 | "mutual_password": "myiscsipassword6", | |
206 | "mutual_user": "myiscsiusername6"} | |
207 | }) | |
208 | response = copy.deepcopy(iscsi_target_response) | |
209 | response['target_iqn'] = target_iqn | |
210 | response['clients'].append( | |
211 | { | |
212 | "luns": [{"image": "lun1", "pool": "rbd"}], | |
213 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client3", | |
214 | "auth": { | |
215 | "password": "myiscsipassword5", | |
216 | "user": "myiscsiusername5", | |
217 | "mutual_password": "myiscsipassword6", | |
494da23a TL |
218 | "mutual_user": "myiscsiusername6"}, |
219 | "info": { | |
220 | "alias": "", | |
221 | "ip_address": [], | |
222 | "state": {} | |
223 | } | |
11fdf7f2 | 224 | }) |
f6b5b4d7 | 225 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 | 226 | |
1911f103 TL |
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( | |
235 | { | |
236 | "luns": [{"image": "lun1", "pool": "rbd"}], | |
237 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client4", | |
238 | "auth": { | |
239 | "password": "myiscsipassword7myiscsipassword7myiscsipasswo", | |
240 | "user": "myiscsiusername7", | |
241 | "mutual_password": "myiscsipassword8", | |
242 | "mutual_user": "myiscsiusername8"} | |
243 | }) | |
244 | response = copy.deepcopy(iscsi_target_response) | |
245 | response['target_iqn'] = target_iqn | |
246 | ||
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) | |
254 | ||
11fdf7f2 TL |
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 | |
1911f103 | 262 | update_request['clients'][0]['auth']['password'] = 'MyNewPassword' |
11fdf7f2 TL |
263 | response = copy.deepcopy(iscsi_target_response) |
264 | response['target_iqn'] = target_iqn | |
1911f103 | 265 | response['clients'][0]['auth']['password'] = 'MyNewPassword' |
f6b5b4d7 | 266 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
267 | |
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' | |
f6b5b4d7 | 279 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
280 | |
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( | |
289 | { | |
290 | "image": "lun3", | |
291 | "pool": "rbd", | |
292 | "controls": {}, | |
293 | "backstore": "user:rbd" | |
294 | }) | |
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( | |
299 | { | |
300 | "image": "lun3", | |
301 | "pool": "rbd", | |
302 | "controls": {}, | |
eafe8130 TL |
303 | "backstore": "user:rbd", |
304 | "wwn": "64af6678-9694-4367-bacc-f8eb0baa2", | |
305 | "lun": 2 | |
306 | ||
11fdf7f2 TL |
307 | }) |
308 | response['clients'][0]['luns'].append({"image": "lun3", "pool": "rbd"}) | |
f6b5b4d7 | 309 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
310 | |
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' | |
f6b5b4d7 | 324 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
325 | |
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} | |
f6b5b4d7 | 337 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
338 | |
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 | |
f6b5b4d7 | 349 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
350 | |
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' | |
f6b5b4d7 | 362 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
363 | |
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( | |
372 | { | |
373 | "luns": [], | |
374 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client3", | |
375 | "auth": { | |
376 | "password": None, | |
377 | "user": None, | |
378 | "mutual_password": None, | |
379 | "mutual_user": None} | |
380 | }) | |
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( | |
385 | { | |
386 | "luns": [], | |
387 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client3", | |
388 | "auth": { | |
389 | "password": None, | |
390 | "user": None, | |
391 | "mutual_password": None, | |
494da23a TL |
392 | "mutual_user": None}, |
393 | "info": { | |
394 | "alias": "", | |
395 | "ip_address": [], | |
396 | "state": {} | |
397 | } | |
11fdf7f2 TL |
398 | }) |
399 | response['groups'][0]['members'].append('iqn.1994-05.com.redhat:rh7-client3') | |
f6b5b4d7 | 400 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
401 | |
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') | |
f6b5b4d7 | 413 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 TL |
414 | |
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'] = [] | |
f6b5b4d7 | 426 | self._update_iscsi_target(create_request, update_request, 200, None, response) |
11fdf7f2 | 427 | |
81eedcae TL |
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' | |
eafe8130 | 435 | self._task_post('/api/iscsi/target', create_request) |
81eedcae TL |
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', | |
440 | 'component': 'iscsi' | |
441 | }) | |
442 | ||
f6b5b4d7 TL |
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"} | |
452 | ] | |
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"} | |
458 | ] | |
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"} | |
464 | ] | |
465 | self._update_iscsi_target(create_request, update_request, 200, None, response) | |
466 | ||
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) | |
479 | ||
480 | @mock.patch('dashboard.controllers.iscsi.IscsiTarget._validate_image') | |
481 | def test_remove_client_logged_in(self, _validate_image_mock): | |
482 | client_info = { | |
483 | 'alias': '', | |
484 | 'ip_address': [], | |
485 | 'state': {'LOGGED_IN': ['node1']} | |
486 | } | |
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 | |
499 | update_response = { | |
500 | 'detail': "Client 'iqn.1994-05.com.redhat:rh7-client' cannot be deleted until it's " | |
501 | "logged out", | |
502 | 'code': 'client_logged_in', | |
503 | 'component': 'iscsi' | |
504 | } | |
505 | self._update_iscsi_target(create_request, update_request, 400, update_response, response) | |
506 | ||
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) | |
519 | ||
520 | def _update_iscsi_target(self, create_request, update_request, update_response_code, | |
521 | update_response, response): | |
eafe8130 | 522 | self._task_post('/api/iscsi/target', create_request) |
11fdf7f2 | 523 | self.assertStatus(201) |
eafe8130 | 524 | self._task_put('/api/iscsi/target/{}'.format(create_request['target_iqn']), update_request) |
f6b5b4d7 TL |
525 | self.assertStatus(update_response_code) |
526 | self.assertJsonBody(update_response) | |
11fdf7f2 TL |
527 | self._get('/api/iscsi/target/{}'.format(update_request['new_target_iqn'])) |
528 | self.assertStatus(200) | |
529 | self.assertJsonBody(response) | |
530 | ||
531 | ||
532 | iscsi_target_request = { | |
533 | "target_iqn": "iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw", | |
534 | "portals": [ | |
535 | {"ip": "192.168.100.202", "host": "node2"}, | |
536 | {"ip": "10.0.2.15", "host": "node2"}, | |
537 | {"ip": "192.168.100.203", "host": "node3"} | |
538 | ], | |
539 | "disks": [ | |
540 | {"image": "lun1", "pool": "rbd", "backstore": "user:rbd", | |
541 | "controls": {"max_data_area_mb": 128}}, | |
542 | {"image": "lun2", "pool": "rbd", "backstore": "user:rbd", | |
543 | "controls": {"max_data_area_mb": 128}} | |
544 | ], | |
545 | "clients": [ | |
546 | { | |
547 | "luns": [{"image": "lun1", "pool": "rbd"}], | |
548 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client", | |
549 | "auth": { | |
550 | "password": "myiscsipassword1", | |
551 | "user": "myiscsiusername1", | |
552 | "mutual_password": "myiscsipassword2", | |
553 | "mutual_user": "myiscsiusername2"} | |
554 | }, | |
555 | { | |
556 | "luns": [], | |
557 | "client_iqn": "iqn.1994-05.com.redhat:rh7-client2", | |
558 | "auth": { | |
559 | "password": "myiscsipassword3", | |
560 | "user": "myiscsiusername3", | |
561 | "mutual_password": "myiscsipassword4", | |
562 | "mutual_user": "myiscsiusername4" | |
563 | } | |
564 | } | |
565 | ], | |
566 | "acl_enabled": True, | |
eafe8130 TL |
567 | "auth": { |
568 | "password": "", | |
569 | "user": "", | |
570 | "mutual_password": "", | |
571 | "mutual_user": ""}, | |
11fdf7f2 TL |
572 | "target_controls": {}, |
573 | "groups": [ | |
574 | { | |
575 | "group_id": "mygroup", | |
576 | "disks": [{"pool": "rbd", "image": "lun2"}], | |
577 | "members": ["iqn.1994-05.com.redhat:rh7-client2"] | |
578 | } | |
579 | ] | |
580 | } | |
581 | ||
582 | iscsi_target_response = { | |
583 | 'target_iqn': 'iqn.2003-01.com.redhat.iscsi-gw:iscsi-igw', | |
584 | 'portals': [ | |
585 | {'host': 'node2', 'ip': '10.0.2.15'}, | |
586 | {'host': 'node2', 'ip': '192.168.100.202'}, | |
587 | {'host': 'node3', 'ip': '192.168.100.203'} | |
588 | ], | |
589 | 'disks': [ | |
590 | {'pool': 'rbd', 'image': 'lun1', 'backstore': 'user:rbd', | |
eafe8130 | 591 | 'wwn': '64af6678-9694-4367-bacc-f8eb0baa0', 'lun': 0, |
11fdf7f2 TL |
592 | 'controls': {'max_data_area_mb': 128}}, |
593 | {'pool': 'rbd', 'image': 'lun2', 'backstore': 'user:rbd', | |
eafe8130 | 594 | 'wwn': '64af6678-9694-4367-bacc-f8eb0baa1', 'lun': 1, |
11fdf7f2 TL |
595 | 'controls': {'max_data_area_mb': 128}} |
596 | ], | |
597 | 'clients': [ | |
598 | { | |
599 | 'client_iqn': 'iqn.1994-05.com.redhat:rh7-client', | |
600 | 'luns': [{'pool': 'rbd', 'image': 'lun1'}], | |
601 | 'auth': { | |
602 | 'user': 'myiscsiusername1', | |
603 | 'password': 'myiscsipassword1', | |
604 | 'mutual_password': 'myiscsipassword2', | |
605 | 'mutual_user': 'myiscsiusername2' | |
494da23a TL |
606 | }, |
607 | 'info': { | |
608 | 'alias': '', | |
609 | 'ip_address': [], | |
610 | 'state': {} | |
11fdf7f2 TL |
611 | } |
612 | }, | |
613 | { | |
614 | 'client_iqn': 'iqn.1994-05.com.redhat:rh7-client2', | |
615 | 'luns': [], | |
616 | 'auth': { | |
617 | 'user': 'myiscsiusername3', | |
618 | 'password': 'myiscsipassword3', | |
619 | 'mutual_password': 'myiscsipassword4', | |
620 | 'mutual_user': 'myiscsiusername4' | |
494da23a TL |
621 | }, |
622 | 'info': { | |
623 | 'alias': '', | |
624 | 'ip_address': [], | |
625 | 'state': {} | |
11fdf7f2 TL |
626 | } |
627 | } | |
628 | ], | |
629 | "acl_enabled": True, | |
eafe8130 TL |
630 | "auth": { |
631 | "password": "", | |
632 | "user": "", | |
633 | "mutual_password": "", | |
634 | "mutual_user": ""}, | |
11fdf7f2 TL |
635 | 'groups': [ |
636 | { | |
637 | 'group_id': 'mygroup', | |
638 | 'disks': [{'pool': 'rbd', 'image': 'lun2'}], | |
639 | 'members': ['iqn.1994-05.com.redhat:rh7-client2'] | |
640 | } | |
641 | ], | |
642 | 'target_controls': {}, | |
643 | 'info': { | |
644 | 'num_sessions': 0 | |
645 | } | |
646 | } | |
647 | ||
648 | ||
649 | class IscsiClientMock(object): | |
650 | ||
651 | _instance = None | |
652 | ||
653 | def __init__(self): | |
654 | self.gateway_name = None | |
655 | self.service_url = None | |
656 | self.config = { | |
657 | "created": "2019/01/17 08:57:16", | |
658 | "discovery_auth": { | |
659 | "username": "", | |
660 | "password": "", | |
661 | "password_encryption_enabled": False, | |
662 | "mutual_username": "", | |
663 | "mutual_password": "", | |
664 | "mutual_password_encryption_enabled": False | |
665 | }, | |
666 | "disks": {}, | |
667 | "epoch": 0, | |
668 | "gateways": {}, | |
669 | "targets": {}, | |
670 | "updated": "", | |
eafe8130 | 671 | "version": 11 |
11fdf7f2 | 672 | } |
f6b5b4d7 TL |
673 | self.clientinfo = { |
674 | 'alias': '', | |
675 | 'ip_address': [], | |
676 | 'state': {} | |
677 | } | |
11fdf7f2 TL |
678 | |
679 | @classmethod | |
680 | def instance(cls, gateway_name=None, service_url=None): | |
681 | cls._instance.gateway_name = gateway_name | |
682 | cls._instance.service_url = service_url | |
683 | # pylint: disable=unused-argument | |
684 | return cls._instance | |
685 | ||
686 | def ping(self): | |
687 | return { | |
688 | "message": "pong" | |
689 | } | |
690 | ||
691 | def get_settings(self): | |
692 | return { | |
1911f103 | 693 | "api_version": 2, |
11fdf7f2 TL |
694 | "backstores": [ |
695 | "user:rbd" | |
696 | ], | |
697 | "config": { | |
698 | "minimum_gateways": 2 | |
699 | }, | |
700 | "default_backstore": "user:rbd", | |
701 | "required_rbd_features": { | |
702 | "rbd": 0, | |
703 | "user:rbd": 4, | |
704 | }, | |
81eedcae TL |
705 | "unsupported_rbd_features": { |
706 | "rbd": 88, | |
707 | "user:rbd": 0, | |
11fdf7f2 TL |
708 | }, |
709 | "disk_default_controls": { | |
710 | "user:rbd": { | |
711 | "hw_max_sectors": 1024, | |
712 | "max_data_area_mb": 8, | |
713 | "osd_op_timeout": 30, | |
714 | "qfull_timeout": 5 | |
715 | } | |
716 | }, | |
717 | "target_default_controls": { | |
718 | "cmdsn_depth": 128, | |
719 | "dataout_timeout": 20, | |
720 | "first_burst_length": 262144, | |
721 | "immediate_data": "Yes", | |
722 | "initial_r2t": "Yes", | |
723 | "max_burst_length": 524288, | |
724 | "max_outstanding_r2t": 1, | |
725 | "max_recv_data_segment_length": 262144, | |
726 | "max_xmit_data_segment_length": 262144, | |
727 | "nopin_response_timeout": 5, | |
728 | "nopin_timeout": 5 | |
729 | } | |
730 | } | |
731 | ||
732 | def get_config(self): | |
eafe8130 | 733 | return copy.deepcopy(self.config) |
11fdf7f2 TL |
734 | |
735 | def create_target(self, target_iqn, target_controls): | |
736 | self.config['targets'][target_iqn] = { | |
737 | "clients": {}, | |
738 | "acl_enabled": True, | |
eafe8130 TL |
739 | "auth": { |
740 | "username": "", | |
741 | "password": "", | |
742 | "password_encryption_enabled": False, | |
743 | "mutual_username": "", | |
744 | "mutual_password": "", | |
745 | "mutual_password_encryption_enabled": False | |
746 | }, | |
11fdf7f2 TL |
747 | "controls": target_controls, |
748 | "created": "2019/01/17 09:22:34", | |
eafe8130 | 749 | "disks": {}, |
11fdf7f2 TL |
750 | "groups": {}, |
751 | "portals": {} | |
752 | } | |
753 | ||
494da23a | 754 | def create_gateway(self, target_iqn, gateway_name, ip_addresses): |
11fdf7f2 TL |
755 | target_config = self.config['targets'][target_iqn] |
756 | if 'ip_list' not in target_config: | |
757 | target_config['ip_list'] = [] | |
494da23a | 758 | target_config['ip_list'] += ip_addresses |
11fdf7f2 | 759 | target_config['portals'][gateway_name] = { |
494da23a | 760 | "portal_ip_addresses": ip_addresses |
11fdf7f2 TL |
761 | } |
762 | ||
494da23a TL |
763 | def delete_gateway(self, target_iqn, gateway_name): |
764 | target_config = self.config['targets'][target_iqn] | |
765 | portal_config = target_config['portals'][gateway_name] | |
766 | for ip in portal_config['portal_ip_addresses']: | |
767 | target_config['ip_list'].remove(ip) | |
768 | target_config['portals'].pop(gateway_name) | |
769 | ||
eafe8130 TL |
770 | def create_disk(self, pool, image, backstore, wwn): |
771 | if wwn is None: | |
772 | wwn = '64af6678-9694-4367-bacc-f8eb0baa' + str(len(self.config['disks'])) | |
11fdf7f2 TL |
773 | image_id = '{}/{}'.format(pool, image) |
774 | self.config['disks'][image_id] = { | |
775 | "pool": pool, | |
776 | "image": image, | |
777 | "backstore": backstore, | |
eafe8130 TL |
778 | "controls": {}, |
779 | "wwn": wwn | |
11fdf7f2 TL |
780 | } |
781 | ||
eafe8130 | 782 | def create_target_lun(self, target_iqn, image_id, lun): |
11fdf7f2 | 783 | target_config = self.config['targets'][target_iqn] |
eafe8130 TL |
784 | if lun is None: |
785 | lun = len(target_config['disks']) | |
786 | target_config['disks'][image_id] = { | |
787 | "lun_id": lun | |
788 | } | |
11fdf7f2 TL |
789 | self.config['disks'][image_id]['owner'] = list(target_config['portals'].keys())[0] |
790 | ||
791 | def reconfigure_disk(self, pool, image, controls): | |
792 | image_id = '{}/{}'.format(pool, image) | |
eafe8130 TL |
793 | settings = self.get_settings() |
794 | backstore = self.config['disks'][image_id]['backstore'] | |
795 | disk_default_controls = settings['disk_default_controls'][backstore] | |
796 | new_controls = {} | |
797 | for control_k, control_v in controls.items(): | |
798 | if control_v != disk_default_controls[control_k]: | |
799 | new_controls[control_k] = control_v | |
800 | self.config['disks'][image_id]['controls'] = new_controls | |
11fdf7f2 TL |
801 | |
802 | def create_client(self, target_iqn, client_iqn): | |
803 | target_config = self.config['targets'][target_iqn] | |
804 | target_config['clients'][client_iqn] = { | |
805 | "auth": { | |
806 | "username": "", | |
807 | "password": "", | |
808 | "password_encryption_enabled": False, | |
809 | "mutual_username": "", | |
810 | "mutual_password": "", | |
811 | "mutual_password_encryption_enabled": False | |
812 | }, | |
813 | "group_name": "", | |
814 | "luns": {} | |
815 | } | |
816 | ||
817 | def create_client_lun(self, target_iqn, client_iqn, image_id): | |
818 | target_config = self.config['targets'][target_iqn] | |
819 | target_config['clients'][client_iqn]['luns'][image_id] = {} | |
820 | ||
eafe8130 TL |
821 | def delete_client_lun(self, target_iqn, client_iqn, image_id): |
822 | target_config = self.config['targets'][target_iqn] | |
823 | del target_config['clients'][client_iqn]['luns'][image_id] | |
824 | ||
11fdf7f2 TL |
825 | def create_client_auth(self, target_iqn, client_iqn, user, password, m_user, m_password): |
826 | target_config = self.config['targets'][target_iqn] | |
827 | target_config['clients'][client_iqn]['auth']['username'] = user | |
828 | target_config['clients'][client_iqn]['auth']['password'] = password | |
829 | target_config['clients'][client_iqn]['auth']['mutual_username'] = m_user | |
830 | target_config['clients'][client_iqn]['auth']['mutual_password'] = m_password | |
831 | ||
832 | def create_group(self, target_iqn, group_name, members, image_ids): | |
833 | target_config = self.config['targets'][target_iqn] | |
834 | target_config['groups'][group_name] = { | |
835 | "disks": {}, | |
836 | "members": [] | |
837 | } | |
838 | for image_id in image_ids: | |
839 | target_config['groups'][group_name]['disks'][image_id] = {} | |
840 | target_config['groups'][group_name]['members'] = members | |
841 | ||
842 | def delete_group(self, target_iqn, group_name): | |
843 | target_config = self.config['targets'][target_iqn] | |
844 | del target_config['groups'][group_name] | |
845 | ||
846 | def delete_client(self, target_iqn, client_iqn): | |
847 | target_config = self.config['targets'][target_iqn] | |
848 | del target_config['clients'][client_iqn] | |
849 | ||
850 | def delete_target_lun(self, target_iqn, image_id): | |
851 | target_config = self.config['targets'][target_iqn] | |
eafe8130 | 852 | target_config['disks'].pop(image_id) |
11fdf7f2 TL |
853 | del self.config['disks'][image_id]['owner'] |
854 | ||
855 | def delete_disk(self, pool, image): | |
856 | image_id = '{}/{}'.format(pool, image) | |
857 | del self.config['disks'][image_id] | |
858 | ||
859 | def delete_target(self, target_iqn): | |
860 | del self.config['targets'][target_iqn] | |
861 | ||
862 | def get_ip_addresses(self): | |
863 | ips = { | |
864 | 'node1': ['192.168.100.201'], | |
865 | 'node2': ['192.168.100.202', '10.0.2.15'], | |
866 | 'node3': ['192.168.100.203'] | |
867 | } | |
868 | return {'data': ips[self.gateway_name]} | |
869 | ||
870 | def get_hostname(self): | |
871 | hostnames = { | |
872 | 'https://admin:admin@10.17.5.1:5001': 'node1', | |
873 | 'https://admin:admin@10.17.5.2:5001': 'node2', | |
874 | 'https://admin:admin@10.17.5.3:5001': 'node3' | |
875 | } | |
876 | if self.service_url not in hostnames: | |
877 | raise RequestException('No route to host') | |
878 | return {'data': hostnames[self.service_url]} | |
879 | ||
880 | def update_discoveryauth(self, user, password, mutual_user, mutual_password): | |
881 | self.config['discovery_auth']['username'] = user | |
882 | self.config['discovery_auth']['password'] = password | |
883 | self.config['discovery_auth']['mutual_username'] = mutual_user | |
884 | self.config['discovery_auth']['mutual_password'] = mutual_password | |
885 | ||
eafe8130 | 886 | def update_targetacl(self, target_iqn, action): |
11fdf7f2 TL |
887 | self.config['targets'][target_iqn]['acl_enabled'] = (action == 'enable_acl') |
888 | ||
eafe8130 TL |
889 | def update_targetauth(self, target_iqn, user, password, mutual_user, mutual_password): |
890 | target_config = self.config['targets'][target_iqn] | |
891 | target_config['auth']['username'] = user | |
892 | target_config['auth']['password'] = password | |
893 | target_config['auth']['mutual_username'] = mutual_user | |
894 | target_config['auth']['mutual_password'] = mutual_password | |
895 | ||
494da23a TL |
896 | def get_targetinfo(self, target_iqn): |
897 | # pylint: disable=unused-argument | |
11fdf7f2 TL |
898 | return { |
899 | 'num_sessions': 0 | |
900 | } | |
494da23a TL |
901 | |
902 | def get_clientinfo(self, target_iqn, client_iqn): | |
903 | # pylint: disable=unused-argument | |
f6b5b4d7 | 904 | return self.clientinfo |