Merge lp:~raharper/curtin/trunk.iscsi-stacked into lp:~curtin-dev/curtin/trunk

Proposed by Ryan Harper
Status: Merged
Merged at revision: 499
Proposed branch: lp:~raharper/curtin/trunk.iscsi-stacked
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 926 lines (+692/-57)
13 files modified
curtin/block/__init__.py (+28/-0)
curtin/block/iscsi.py (+20/-0)
curtin/commands/block_meta.py (+15/-23)
curtin/commands/install.py (+2/-2)
examples/tests/lvm_iscsi.yaml (+175/-0)
examples/tests/mdadm_iscsi.yaml (+87/-0)
tests/unittests/test_block.py (+118/-0)
tests/unittests/test_block_iscsi.py (+96/-1)
tests/vmtests/__init__.py (+10/-6)
tests/vmtests/test_iscsi.py (+23/-7)
tests/vmtests/test_lvm.py (+9/-18)
tests/vmtests/test_lvm_iscsi.py (+67/-0)
tests/vmtests/test_mdadm_iscsi.py (+42/-0)
To merge this branch: bzr merge lp:~raharper/curtin/trunk.iscsi-stacked
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Scott Moser (community) Approve
Review via email: mp+324005@code.launchpad.net

Description of the change

Fix stacked storage configurations with iSCSI

Currently, we fail to correctly handle more complex storage configurations where one or more members of a LVM or MD configuration are on iSCSI. We only check for disks and partitions if they are on iSCSI -- instead, in the mount_handler, check if the to-be-mounted volume (i.e., in the case of a disk or partition) is itself on iSCSI, or if any of the "slaves" of the kname for the to-be-mounted volume (i.e, in the case of LVM or MD) are on iSCSI.

LP: #1683910

To post a comment you must log in.
Revision history for this message
Ryan Harper (raharper) wrote :

I've pulled Nish's branch, refactored how we determine slave knames, in particular adding support for arbitrary level of nested block devices (vs. just one level deep) which allows us to find an iscsi device under a bcache used in a raid device with lvm's on top, etc...

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
499. By Ryan Harper

merge from trunk

500. By Ryan Harper

Add some verbose debugging for kname slaves, restructure stacked iscsi tests

501. By Ryan Harper

Unmount the devices before unplugging iscsi devices

502. By Ryan Harper

Check for _netdev within each of the fstab lines

503. By Ryan Harper

block: slaves_kname: Handle present but empty slaves dir

504. By Ryan Harper

vmtests: update stacked iscsi testfile configuration, add tunable

505. By Ryan Harper

Fix lint

506. By Ryan Harper

Try appending collect_scripts instead of clobbering

507. By Ryan Harper

Must manually build scripts from parent classes

508. By Ryan Harper

Rework syntax

509. By Ryan Harper

Fix up collect scripts for iscsi subclassed tests

510. By Ryan Harper

Refactor lvm_iscsi, use fs uuids so we can match fstab, skiptest for precise,trusty dname

511. By Ryan Harper

Fix vg name in lvm_iscsi test

512. By Ryan Harper

Drop verbose slave kname debugging

Revision history for this message
Ryan Harper (raharper) wrote :

After failing VMTest run, fix up a few issues and refactor the vmtests.

1) Make sure we run iscsi disconnect *after* install unmounts the target

This is the other critical fix for using iscsi devices.

2) Fix an issue with obtaining slave knames when a device has a 'slaves' sysfs entry but it is empty.

3) Update the iscsi vmtests to check for '_netdev' in fstab

4) Derive the lvm and mdadm iscsi tests from respective parent classes so we confirm that those devices are built as expected as well as ensuring the use of iscsi block devices at the bottom layer works.

Started new vmtest run of iscsi tests:

https://jenkins.ubuntu.com/server/job/curtin-vmtest-devel-debug/48/console

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

All tests look good, the one failure is ArtfulIscsi which won't pass till jenkins does it's nightly sync-images.

Revision history for this message
Scott Moser (smoser) wrote :

This looks really good. I'll approve, you are welcome to fix what you want and not what you dont.
I do think the unit tests are more implementation dependent than they really should be.

review: Approve
Revision history for this message
Ryan Harper (raharper) wrote :

Thanks for the review, will push an update and retest on jenkins.

513. By Ryan Harper

Switch to append

514. By Ryan Harper

Change Exception message on invalid input

515. By Ryan Harper

vmtests: modify output_files_{exist,dont_exist} to check all of the input

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'curtin/block/__init__.py'
2--- curtin/block/__init__.py 2017-05-04 17:23:42 +0000
3+++ curtin/block/__init__.py 2017-05-19 00:57:33 +0000
4@@ -176,6 +176,34 @@
5 return holders
6
7
8+def get_device_slave_knames(device):
9+ """
10+ Find the underlying knames of a given device by walking sysfs
11+ recursively.
12+
13+ Returns a list of knames
14+ """
15+ slave_knames = []
16+ slaves_dir_path = os.path.join(sys_block_path(device), 'slaves')
17+
18+ # if we find a 'slaves' dir, recurse and check
19+ # the underlying devices
20+ if os.path.exists(slaves_dir_path):
21+ slaves = os.listdir(slaves_dir_path)
22+ if len(slaves) > 0:
23+ for slave_kname in slaves:
24+ slave_knames.extend(get_device_slave_knames(slave_kname))
25+ else:
26+ slave_knames.append(path_to_kname(device))
27+
28+ return slave_knames
29+ else:
30+ # if a device has no 'slaves' attribute then
31+ # we've found the underlying device, return
32+ # the kname of the device
33+ return [path_to_kname(device)]
34+
35+
36 def _shlex_split(str_in):
37 # shlex.split takes a string
38 # but in python2 if input here is a unicode, encode it to a string.
39
40=== modified file 'curtin/block/iscsi.py'
41--- curtin/block/iscsi.py 2017-04-04 17:58:52 +0000
42+++ curtin/block/iscsi.py 2017-05-19 00:57:33 +0000
43@@ -27,6 +27,9 @@
44 import shutil
45
46 from curtin import (util, udev)
47+from curtin.block import (get_device_slave_knames,
48+ path_to_kname)
49+
50 from curtin.log import LOG
51
52 _ISCSI_DISKS = {}
53@@ -272,6 +275,23 @@
54 return False
55
56
57+def volpath_is_iscsi(volume_path):
58+ """ Determine if the volume_path's kname is backed by iSCSI.
59+ Recursively check volume_path's slave devices as well in
60+ case volume_path is a stacked block device (like LVM/MD)
61+
62+ returns a boolean
63+ """
64+ if not volume_path:
65+ raise ValueError("Invalid input for volume_path: '%s'", volume_path)
66+
67+ volume_path_slaves = get_device_slave_knames(volume_path)
68+ LOG.debug('volume_path=%s found slaves: %s', volume_path,
69+ volume_path_slaves)
70+ knames = [path_to_kname(volume_path)] + volume_path_slaves
71+ return any([kname_is_iscsi(kname) for kname in knames])
72+
73+
74 class IscsiDisk(object):
75 # Per Debian bug 804162, the iscsi specifier looks like
76 # TARGETSPEC=host:proto:port:lun:targetname
77
78=== modified file 'curtin/commands/block_meta.py'
79--- curtin/commands/block_meta.py 2017-04-12 01:38:04 +0000
80+++ curtin/commands/block_meta.py 2017-05-19 00:57:33 +0000
81@@ -640,6 +640,19 @@
82 # Mount volume
83 util.subp(['mount', volume_path, mount_point])
84
85+ path = "/%s" % path
86+
87+ options = ["defaults"]
88+ # If the volume_path's kname is backed by iSCSI or (in the case of
89+ # LVM/DM) if any of its slaves are backed by iSCSI, then we need to
90+ # append _netdev to the fstab line
91+ if iscsi.volpath_is_iscsi(volume_path):
92+ LOG.debug("Marking volume_path:%s as '_netdev'", volume_path)
93+ options.append("_netdev")
94+ else:
95+ path = "none"
96+ options = ["sw"]
97+
98 # Add volume to fstab
99 if state['fstab']:
100 with open(state['fstab'], "a") as fp:
101@@ -649,34 +662,13 @@
102 if len(uuid) > 0:
103 location = "UUID=%s" % uuid
104
105- if filesystem.get('fstype') == "swap":
106- path = "none"
107- options = "sw"
108- else:
109- path = "/%s" % path
110- if volume.get('type') == "partition":
111- disk_block_path = get_path_to_storage_volume(
112- volume.get('device'), storage_config)
113- disk_kname = block.path_to_kname(disk_block_path)
114- if iscsi.kname_is_iscsi(disk_kname):
115- options = "_netdev"
116- else:
117- options = "defaults"
118- elif volume.get('type') == "disk":
119- disk_kname = block.path_to_kname(location)
120- if iscsi.kname_is_iscsi(disk_kname):
121- options = "_netdev"
122- else:
123- options = "defaults"
124- else:
125- options = "defaults"
126-
127 if filesystem.get('fstype') in ["fat", "fat12", "fat16", "fat32",
128 "fat64"]:
129 fstype = "vfat"
130 else:
131 fstype = filesystem.get('fstype')
132- fp.write("%s %s %s %s 0 0\n" % (location, path, fstype, options))
133+ fp.write("%s %s %s %s 0 0\n" % (location, path, fstype,
134+ ",".join(options)))
135 else:
136 LOG.info("fstab not in environment, so not writing")
137
138
139=== modified file 'curtin/commands/install.py'
140--- curtin/commands/install.py 2017-04-20 15:57:21 +0000
141+++ curtin/commands/install.py 2017-05-19 00:57:33 +0000
142@@ -452,11 +452,11 @@
143 finally:
144 log_target_path = instcfg.get('save_install_log',
145 '/root/curtin-install.log')
146- # need to do some processing on iscsi disks to disconnect?
147- iscsi.disconnect_target_disks(workingd.target)
148 if log_target_path:
149 copy_install_log(logfile, workingd.target, log_target_path)
150 util.do_umount(workingd.target, recursive=True)
151+ # need to do some processing on iscsi disks to disconnect?
152+ iscsi.disconnect_target_disks(workingd.target)
153 shutil.rmtree(workingd.top)
154
155 apply_power_state(cfg.get('power_state'))
156
157=== added file 'examples/tests/lvm_iscsi.yaml'
158--- examples/tests/lvm_iscsi.yaml 1970-01-01 00:00:00 +0000
159+++ examples/tests/lvm_iscsi.yaml 2017-05-19 00:57:33 +0000
160@@ -0,0 +1,175 @@
161+storage:
162+ version: 1
163+ config:
164+ - id: vdb
165+ type: disk
166+ ptable: msdos
167+ model: QEMU HARDDISK
168+ path: /dev/vdb
169+ name: main_disk
170+ wipe: superblock
171+ grub_device: true
172+ - id: vdb1
173+ type: partition
174+ number: 1
175+ size: 3GB
176+ device: vdb
177+ flag: boot
178+ - id: vdb2
179+ type: partition
180+ number: 2
181+ size: 1GB
182+ device: vdb
183+ - id: vdb1_root
184+ type: format
185+ fstype: ext4
186+ volume: vdb1
187+ - id: vdb2_home
188+ type: format
189+ fstype: ext4
190+ volume: vdb2
191+ - id: vdb1_mount
192+ type: mount
193+ path: /
194+ device: vdb1_root
195+ - id: vdb2_mount
196+ type: mount
197+ path: /home
198+ device: vdb2_home
199+ - id: sda
200+ type: disk
201+ path: iscsi:__RFC4173__
202+ name: iscsi_disk1
203+ ptable: msdos
204+ wipe: superblock
205+ - id: sda_extended
206+ type: partition
207+ size: 5G
208+ flag: extended
209+ device: sda
210+ - id: sda1
211+ type: partition
212+ size: 2G
213+ flag: logical
214+ device: sda
215+ - id: sda2
216+ type: partition
217+ size: 3G
218+ flag: logical
219+ device: sda
220+ - id: volgroup1
221+ name: vg1
222+ type: lvm_volgroup
223+ devices:
224+ - sda1
225+ - sda2
226+ - id: lvmpart1
227+ name: lv1
228+ size: 1G
229+ type: lvm_partition
230+ volgroup: volgroup1
231+ - id: lvmpart2
232+ name: lv2
233+ type: lvm_partition
234+ volgroup: volgroup1
235+ - id: lv1_fs
236+ name: storage
237+ type: format
238+ fstype: ext4
239+ volume: lvmpart1
240+ uuid: 6de56115-9500-424b-8151-221b270ec708
241+ - id: lv2_fs
242+ name: storage
243+ type: format
244+ fstype: ext3
245+ volume: lvmpart2
246+ uuid: 9604e4c4-e5ae-40dd-ab1f-940de6b59047
247+ - id: lv1_mount
248+ type: mount
249+ path: /mnt/iscsi1
250+ device: lv1_fs
251+ - id: lv2_mount
252+ type: mount
253+ path: /mnt/iscsi2
254+ device: lv2_fs
255+ - id: sdb
256+ type: disk
257+ path: iscsi:__RFC4173__
258+ name: iscsi_disk2
259+ ptable: msdos
260+ wipe: superblock
261+ - id: sdb_extended
262+ type: partition
263+ size: 4G
264+ flag: extended
265+ device: sdb
266+ - id: sdb1
267+ type: partition
268+ size: 2G
269+ flag: logical
270+ device: sdb
271+ - id: sdb2
272+ type: partition
273+ size: 2G
274+ flag: logical
275+ device: sdb
276+ - id: volgroup2
277+ name: vg2
278+ type: lvm_volgroup
279+ devices:
280+ - sdb1
281+ - sdb2
282+ - id: lvmpart3
283+ name: lv3
284+ size: 1G
285+ type: lvm_partition
286+ volgroup: volgroup2
287+ - id: lvmpart4
288+ name: lv4
289+ type: lvm_partition
290+ volgroup: volgroup2
291+ - id: lv3_fs
292+ name: storage
293+ type: format
294+ fstype: ext4
295+ volume: lvmpart3
296+ uuid: 18bec31c-09a8-4a02-91c6-e9bf6efb6fad
297+ - id: lv4_fs
298+ name: storage
299+ type: format
300+ fstype: ext3
301+ volume: lvmpart4
302+ uuid: a98f706b-b064-4682-8eb2-6c2c1284060c
303+ - id: lv3_mount
304+ type: mount
305+ path: /mnt/iscsi3
306+ device: lv3_fs
307+ - id: lv4_mount
308+ type: mount
309+ path: /mnt/iscsi4
310+ device: lv4_fs
311+network:
312+ version: 1
313+ config:
314+ - type: physical
315+ name: interface0
316+ mac_address: "52:54:00:12:34:00"
317+ subnets:
318+ - type: dhcp
319+write_files:
320+ f1:
321+ path: /mnt/iscsi1/testfile
322+ content: "test1"
323+ permissions: 0777
324+ f2:
325+ path: /mnt/iscsi2/testfile
326+ content: "test2"
327+ permissions: 0777
328+ f3:
329+ path: /mnt/iscsi3/testfile
330+ content: "test3"
331+ permissions: 0777
332+ f4:
333+ path: /mnt/iscsi4/testfile
334+ content: "test4"
335+ permissions: 0777
336
337=== added file 'examples/tests/mdadm_iscsi.yaml'
338--- examples/tests/mdadm_iscsi.yaml 1970-01-01 00:00:00 +0000
339+++ examples/tests/mdadm_iscsi.yaml 2017-05-19 00:57:33 +0000
340@@ -0,0 +1,87 @@
341+storage:
342+ version: 1
343+ config:
344+ - id: vdb
345+ type: disk
346+ ptable: msdos
347+ model: QEMU HARDDISK
348+ path: /dev/vdb
349+ name: main_disk
350+ wipe: superblock
351+ grub_device: true
352+ - id: vdb1
353+ type: partition
354+ number: 1
355+ size: 3GB
356+ device: vdb
357+ flag: boot
358+ - id: vdb2
359+ type: partition
360+ number: 2
361+ size: 1GB
362+ device: vdb
363+ - id: vdb1_root
364+ type: format
365+ fstype: ext4
366+ volume: vdb1
367+ - id: vdb2_home
368+ type: format
369+ fstype: ext4
370+ volume: vdb2
371+ - id: vdb1_mount
372+ type: mount
373+ path: /
374+ device: vdb1_root
375+ - id: vdb2_mount
376+ type: mount
377+ path: /home
378+ device: vdb2_home
379+ - id: sda
380+ type: disk
381+ path: iscsi:__RFC4173__
382+ name: iscsi_disk1
383+ ptable: msdos
384+ wipe: superblock
385+ - id: sdb
386+ type: disk
387+ path: iscsi:__RFC4173__
388+ name: iscsi_disk2
389+ ptable: msdos
390+ wipe: superblock
391+ - id: sdc
392+ type: disk
393+ path: iscsi:__RFC4173__
394+ name: iscsi_disk3
395+ ptable: msdos
396+ wipe: superblock
397+ - devices:
398+ - sda
399+ - sdb
400+ - sdc
401+ id: md0
402+ name: md0
403+ raidlevel: 5
404+ spare_devices: []
405+ type: raid
406+ - fstype: ext4
407+ id: md0_format
408+ label: ''
409+ type: format
410+ volume: md0
411+ - device: md0_format
412+ id: md0_mount
413+ path: /mnt/iscsi1
414+ type: mount
415+network:
416+ version: 1
417+ config:
418+ - type: physical
419+ name: interface0
420+ mac_address: "52:54:00:12:34:00"
421+ subnets:
422+ - type: dhcp
423+write_files:
424+ f1:
425+ path: /mnt/iscsi1/testfile
426+ content: "test1"
427+ permissions: 0777
428
429=== modified file 'tests/unittests/test_block.py'
430--- tests/unittests/test_block.py 2017-02-08 15:19:42 +0000
431+++ tests/unittests/test_block.py 2017-05-19 00:57:33 +0000
432@@ -515,4 +515,122 @@
433 mock_subp.return_value = (out, err)
434 block.blkid()
435
436+
437+class TestSlaveKnames(TestCase):
438+ def add_patch(self, target, attr, autospec=True):
439+ """Patches specified target object and sets it as attr on test
440+ instance also schedules cleanup"""
441+ m = mock.patch(target, autospec=autospec)
442+ p = m.start()
443+ self.addCleanup(m.stop)
444+ setattr(self, attr, p)
445+
446+ def setUp(self):
447+ super(TestSlaveKnames, self).setUp()
448+ self.add_patch('curtin.block.get_blockdev_for_partition',
449+ 'm_blockdev_for_partition')
450+ self.add_patch('curtin.block.os.path.exists',
451+ 'm_os_path_exists')
452+ # trusty-p3 does not like autospec=True for os.listdir
453+ self.add_patch('curtin.block.os.listdir',
454+ 'm_os_listdir', autospec=False)
455+
456+ def _prepare_mocks(self, device, cfg):
457+ """
458+ Construct the correct sequence of mocks
459+ give a mapping of device and slaves
460+
461+ cfg = {
462+ 'wark': ['foo', 'bar'],
463+ 'foo': [],
464+ 'bar': [],
465+ }
466+ device = 'wark', slaves = ['foo, 'bar']
467+
468+ cfg = {
469+ 'wark': ['foo', 'bar'],
470+ 'foo': ['zip'],
471+ 'bar': [],
472+ 'zip': []
473+ }
474+ device = 'wark', slaves = ['zip', 'bar']
475+ """
476+ # kname side-effect mapping
477+ parts = [(k, None) for k in cfg.keys()]
478+ self.m_blockdev_for_partition.side_effect = iter(parts)
479+
480+ # construct side effects to os.path.exists
481+ # and os.listdir based on mapping.
482+ dirs = []
483+ exists = []
484+ for (dev, slvs) in cfg.items():
485+ # sys_block_dev checks if dev exists
486+ exists.append(True)
487+ if slvs:
488+ # os.path.exists on slaves dir
489+ exists.append(True)
490+ # result of os.listdir
491+ dirs.append(slvs)
492+ else:
493+ # os.path.exists on slaves dir
494+ exists.append(False)
495+
496+ self.m_os_path_exists.side_effect = iter(exists)
497+ self.m_os_listdir.side_effect = iter(dirs)
498+
499+ def test_get_device_slave_knames(self):
500+ #
501+ # /sys/class/block/wark/slaves/foo -> ../../foo
502+ # /sys/class/block/foo #
503+ # should return 'bar'
504+ cfg = OrderedDict([
505+ ('wark', ['foo']),
506+ ('foo', []),
507+ ])
508+ device = "/dev/wark"
509+ slaves = ["foo"]
510+ self._prepare_mocks(device, cfg)
511+ knames = block.get_device_slave_knames(device)
512+ self.assertEqual(slaves, knames)
513+
514+ def test_get_device_slave_knames_stacked(self):
515+ #
516+ # /sys/class/block/wark/slaves/foo -> ../../foo
517+ # /sys/class/block/wark/slaves/bar -> ../../bar
518+ # /sys/class/block/foo
519+ # /sys/class/block/bar
520+ #
521+ # should return ['foo', 'bar']
522+ cfg = OrderedDict([
523+ ('wark', ['foo', 'bar']),
524+ ('foo', []),
525+ ('bar', []),
526+ ])
527+ device = 'wark'
528+ slaves = ['foo', 'bar']
529+ self._prepare_mocks(device, cfg)
530+ knames = block.get_device_slave_knames(device)
531+ self.assertEqual(slaves, knames)
532+
533+ def test_get_device_slave_knames_double_stacked(self):
534+ # /sys/class/block/wark/slaves/foo -> ../../foo
535+ # /sys/class/block/wark/slaves/bar -> ../../bar
536+ # /sys/class/block/foo
537+ # /sys/class/block/bar/slaves/zip -> ../../zip
538+ # /sys/class/block/zip
539+ #
540+ # mapping of device:
541+ cfg = OrderedDict([
542+ ('wark', ['foo', 'bar']),
543+ ('foo', []),
544+ ('bar', ['zip']),
545+ ('zip', []),
546+ ])
547+ device = 'wark'
548+ slaves = ['foo', 'zip']
549+ self._prepare_mocks(device, cfg)
550+ knames = block.get_device_slave_knames(device)
551+ self.assertEqual(slaves, knames)
552+
553+
554 # vi: ts=4 expandtab syntax=python
555
556=== modified file 'tests/unittests/test_block_iscsi.py'
557--- tests/unittests/test_block_iscsi.py 2017-04-04 17:58:52 +0000
558+++ tests/unittests/test_block_iscsi.py 2017-05-19 00:57:33 +0000
559@@ -1,8 +1,23 @@
560+import mock
561+
562 from unittest import TestCase
563 from curtin.block import iscsi
564
565
566-class TestBlockIscsiPortalParsing(TestCase):
567+class IscsiTestBase(TestCase):
568+ def setUp(self):
569+ super(IscsiTestBase, self).setUp()
570+
571+ def add_patch(self, target, attr):
572+ """Patches specified target object and sets it as attr on test
573+ instance also schedules cleanup"""
574+ m = mock.patch(target, autospec=True)
575+ p = m.start()
576+ self.addCleanup(m.stop)
577+ setattr(self, attr, p)
578+
579+
580+class TestBlockIscsiPortalParsing(IscsiTestBase):
581 def test_iscsi_portal_parsing_string(self):
582 with self.assertRaisesRegexp(ValueError, 'not a string'):
583 iscsi.assert_valid_iscsi_portal(1234)
584@@ -474,4 +489,84 @@
585 self.assertEquals(i.lun, 0)
586 self.assertEquals(i.target, 'iqn.2017-04.com.example.test:target-name')
587
588+
589+class TestBlockIscsiVolPath(IscsiTestBase):
590+ # non-iscsi backed disk returns false
591+ # regular iscsi-backed disk returns true
592+ # layered setup without an iscsi member returns false
593+ # layered setup with an iscsi member returns true
594+
595+ def setUp(self):
596+ super(TestBlockIscsiVolPath, self).setUp()
597+ self.add_patch('curtin.block.iscsi.get_device_slave_knames',
598+ 'mock_get_device_slave_knames')
599+ self.add_patch('curtin.block.iscsi.path_to_kname',
600+ 'mock_path_to_kname')
601+ self.add_patch('curtin.block.iscsi.kname_is_iscsi',
602+ 'mock_kname_is_iscsi')
603+
604+ def test_volpath_is_iscsi_false(self):
605+ volume_path = '/dev/wark'
606+ kname = 'wark'
607+ slaves = []
608+ self.mock_get_device_slave_knames.return_value = slaves
609+ self.mock_path_to_kname.return_value = kname
610+ self.mock_kname_is_iscsi.return_value = 'iscsi' in kname
611+
612+ is_iscsi = iscsi.volpath_is_iscsi(volume_path)
613+
614+ self.assertFalse(is_iscsi)
615+ self.mock_get_device_slave_knames.assert_called_with(volume_path)
616+ self.mock_path_to_kname.assert_called_with(volume_path)
617+ self.mock_kname_is_iscsi.assert_called_with(kname)
618+
619+ def test_volpath_is_iscsi_true(self):
620+ volume_path = '/dev/wark'
621+ kname = 'wark-iscsi-lun-2'
622+ slaves = []
623+ self.mock_get_device_slave_knames.return_value = slaves
624+ self.mock_path_to_kname.return_value = kname
625+ self.mock_kname_is_iscsi.return_value = 'iscsi' in kname
626+
627+ is_iscsi = iscsi.volpath_is_iscsi(volume_path)
628+
629+ self.assertTrue(is_iscsi)
630+ self.mock_get_device_slave_knames.assert_called_with(volume_path)
631+ self.mock_path_to_kname.assert_called_with(volume_path)
632+ self.mock_kname_is_iscsi.assert_called_with(kname)
633+
634+ def test_volpath_is_iscsi_layered_true(self):
635+ volume_path = '/dev/wark'
636+ slaves = ['wark', 'bzr', 'super-iscsi-lun-27']
637+ self.mock_get_device_slave_knames.return_value = slaves
638+ self.mock_path_to_kname.side_effect = lambda x: x
639+ self.mock_kname_is_iscsi.side_effect = lambda x: 'iscsi' in x
640+
641+ is_iscsi = iscsi.volpath_is_iscsi(volume_path)
642+
643+ self.assertTrue(is_iscsi)
644+ self.mock_get_device_slave_knames.assert_called_with(volume_path)
645+ self.mock_path_to_kname.assert_called_with(volume_path)
646+ self.mock_kname_is_iscsi.assert_has_calls([
647+ mock.call(x) for x in slaves])
648+
649+ def test_volpath_is_iscsi_layered_false(self):
650+ volume_path = '/dev/wark'
651+ slaves = ['wark', 'bzr', 'nvmen27p47']
652+ self.mock_get_device_slave_knames.return_value = slaves
653+ self.mock_path_to_kname.side_effect = lambda x: x
654+ self.mock_kname_is_iscsi.side_effect = lambda x: 'iscsi' in x
655+
656+ is_iscsi = iscsi.volpath_is_iscsi(volume_path)
657+
658+ self.assertFalse(is_iscsi)
659+ self.mock_get_device_slave_knames.assert_called_with(volume_path)
660+ self.mock_path_to_kname.assert_called_with(volume_path)
661+ self.mock_kname_is_iscsi.assert_has_calls([
662+ mock.call(x) for x in slaves])
663+
664+ def test_volpath_is_iscsi_missing_param(self):
665+ with self.assertRaises(ValueError):
666+ iscsi.volpath_is_iscsi(None)
667+
668 # vi: ts=4 expandtab syntax=python
669
670=== modified file 'tests/vmtests/__init__.py'
671--- tests/vmtests/__init__.py 2017-04-25 20:30:31 +0000
672+++ tests/vmtests/__init__.py 2017-05-19 00:57:33 +0000
673@@ -973,14 +973,18 @@
674
675 # Misc functions that are useful for many tests
676 def output_files_exist(self, files):
677- for f in files:
678- logger.debug('checking file %s', f)
679- self.assertTrue(os.path.exists(os.path.join(self.td.collect, f)))
680+ logger.debug('checking files: %s', files)
681+ results = {f: os.path.exists(os.path.join(self.td.collect, f))
682+ for f in files}
683+ logger.debug('results: %s', results)
684+ self.assertTrue(False not in results.values())
685
686 def output_files_dont_exist(self, files):
687- for f in files:
688- logger.debug('checking file %s', f)
689- self.assertFalse(os.path.exists(os.path.join(self.td.collect, f)))
690+ logger.debug('checking files: %s', files)
691+ results = {f: os.path.exists(os.path.join(self.td.collect, f))
692+ for f in files}
693+ logger.debug('results: %s', results)
694+ self.assertTrue(True not in results.values())
695
696 def load_collect_file(self, filename, mode="r"):
697 with open(os.path.join(self.td.collect, filename), mode) as fp:
698
699=== modified file 'tests/vmtests/test_iscsi.py'
700--- tests/vmtests/test_iscsi.py 2017-04-26 16:14:04 +0000
701+++ tests/vmtests/test_iscsi.py 2017-05-19 00:57:33 +0000
702@@ -12,6 +12,7 @@
703 {'size': '5G', 'auth': 'user:passw0rd', 'iauth': 'iuser:ipassw0rd'},
704 {'size': '6G', 'iauth': 'iuser:ipassw0rd'}]
705 conf_file = "examples/tests/basic_iscsi.yaml"
706+ nr_testfiles = 4
707
708 collect_scripts = [textwrap.dedent(
709 """
710@@ -19,16 +20,31 @@
711 cat /etc/fstab > fstab
712 ls /dev/disk/by-dname/ > ls_dname
713 find /etc/network/interfaces.d > find_interfacesd
714- cat /mnt/iscsi1/testfile > testfile1
715- cat /mnt/iscsi2/testfile > testfile2
716- cat /mnt/iscsi3/testfile > testfile3
717- cat /mnt/iscsi4/testfile > testfile4
718+ bash -c \
719+ 'for f in /mnt/iscsi*; do cat $f/testfile > testfile${f: -1}; done'
720 """)]
721
722- def test_output_files_exist(self):
723+ def test_fstab_has_netdev_option(self):
724+ self.output_files_exist(["fstab"])
725+ fstab = self.load_collect_file("fstab").strip()
726+ self.assertTrue(any(["_netdev" in line
727+ for line in fstab.splitlines()]))
728+
729+ def test_iscsi_testfiles(self):
730 # add check by SN or UUID that the iSCSI disks are attached?
731- self.output_files_exist(["fstab", "testfile1", "testfile2",
732- "testfile3", "testfile4"])
733+ testfiles = ["testfile%s" % t for t in range(1, self.nr_testfiles + 1)]
734+
735+ # make sure all required files are present:
736+ print('Expecting testfiles: %s' % testfiles)
737+ self.output_files_exist(testfiles)
738+
739+ for testfile in testfiles:
740+ print('checking file content: %s' % testfile)
741+ expected_content = "test%s" % testfile[-1]
742+ content = self.load_collect_file(testfile).strip()
743+ self.assertEqual(expected_content, content,
744+ "Checking %s, expected:\n%s\nfound:\n%s" %
745+ (testfile, expected_content, content))
746
747
748 class PreciseTestIscsiBasic(relbase.precise, TestBasicIscsiAbs):
749
750=== modified file 'tests/vmtests/test_lvm.py'
751--- tests/vmtests/test_lvm.py 2017-04-26 16:14:04 +0000
752+++ tests/vmtests/test_lvm.py 2017-05-19 00:57:33 +0000
753@@ -1,5 +1,6 @@
754 from . import VMBaseClass
755 from .releases import base_vm_classes as relbase
756+from unittest import SkipTest
757
758 import textwrap
759
760@@ -38,16 +39,18 @@
761 self.output_files_exist(
762 ["fstab", "ls_dname"])
763
764+ # FIXME(LP: #1523037): dname does not work on precise|trusty, so we cannot
765+ # expect sda-part2 to exist in /dev/disk/by-dname as we can on other
766+ # releases when dname works on trusty, then we need to re-enable by
767+ # removing line.
768+ def test_dname(self):
769+ if self.release in ['precise', 'trusty']:
770+ raise SkipTest("test_dname does not work for %s" % self.release)
771+
772
773 class PreciseTestLvm(relbase.precise, TestLvmAbs):
774 __test__ = True
775
776- # FIXME(LP: #1523037): dname does not work on trusty, so we cannot expect
777- # sda-part2 to exist in /dev/disk/by-dname as we can on other releases
778- # when dname works on trusty, then we need to re-enable by removing line.
779- def test_dname(self):
780- print("test_dname does not work for Trusty")
781-
782
783 class PreciseHWETTestLvm(relbase.precise_hwe_t, PreciseTestLvm):
784 __test__ = True
785@@ -56,22 +59,10 @@
786 class TrustyTestLvm(relbase.trusty, TestLvmAbs):
787 __test__ = True
788
789- # FIXME(LP: #1523037): dname does not work on trusty, so we cannot expect
790- # sda-part2 to exist in /dev/disk/by-dname as we can on other releases
791- # when dname works on trusty, then we need to re-enable by removing line.
792- def test_dname(self):
793- print("test_dname does not work for Trusty")
794-
795
796 class TrustyHWEXTestLvm(relbase.trusty_hwe_x, TestLvmAbs):
797 __test__ = True
798
799- # FIXME(LP: #1523037): dname does not work on trusty, so we cannot expect
800- # sda-part2 to exist in /dev/disk/by-dname as we can on other releases
801- # when dname works on trusty, then we need to re-enable by removing line.
802- def test_dname(self):
803- print("test_dname does not work for Trusty")
804-
805
806 class WilyTestLvm(relbase.wily, TestLvmAbs):
807 # EOL - 2016-07-28
808
809=== added file 'tests/vmtests/test_lvm_iscsi.py'
810--- tests/vmtests/test_lvm_iscsi.py 1970-01-01 00:00:00 +0000
811+++ tests/vmtests/test_lvm_iscsi.py 2017-05-19 00:57:33 +0000
812@@ -0,0 +1,67 @@
813+from .releases import base_vm_classes as relbase
814+from .test_lvm import TestLvmAbs
815+from .test_iscsi import TestBasicIscsiAbs
816+
817+import textwrap
818+
819+
820+class TestLvmIscsiAbs(TestLvmAbs, TestBasicIscsiAbs):
821+ interactive = False
822+ iscsi_disks = [
823+ {'size': '6G'},
824+ {'size': '5G', 'auth': 'user:passw0rd', 'iauth': 'iuser:ipassw0rd'}]
825+ conf_file = "examples/tests/lvm_iscsi.yaml"
826+ nr_testfiles = 4
827+
828+ collect_scripts = TestLvmAbs.collect_scripts
829+ collect_scripts += TestBasicIscsiAbs.collect_scripts + [textwrap.dedent(
830+ """
831+ cd OUTPUT_COLLECT_D
832+ ls -al /sys/class/block/dm*/slaves/ > dm_slaves
833+ """)]
834+
835+ fstab_expected = {
836+ 'UUID=6de56115-9500-424b-8151-221b270ec708': '/mnt/iscsi1',
837+ 'UUID=9604e4c4-e5ae-40dd-ab1f-940de6b59047': '/mnt/iscsi2',
838+ 'UUID=18bec31c-09a8-4a02-91c6-e9bf6efb6fad': '/mnt/iscsi3',
839+ 'UUID=a98f706b-b064-4682-8eb2-6c2c1284060c': '/mnt/iscsi4',
840+ }
841+ disk_to_check = [('main_disk', 1),
842+ ('main_disk', 5),
843+ ('main_disk', 6),
844+ ('vg1-lv1', 0),
845+ ('vg1-lv2', 0),
846+ ('vg2-lv3', 0),
847+ ('vg2-lv4', 0)]
848+
849+ def test_lvs(self):
850+ self.check_file_strippedline("lvs", "lv1=vg1")
851+ self.check_file_strippedline("lvs", "lv2=vg1")
852+ self.check_file_strippedline("lvs", "lv3=vg2")
853+ self.check_file_strippedline("lvs", "lv4=vg2")
854+
855+ def test_pvs(self):
856+ self.check_file_strippedline("pvs", "vg1=/dev/sda5")
857+ self.check_file_strippedline("pvs", "vg1=/dev/sda6")
858+ self.check_file_strippedline("pvs", "vg2=/dev/sdb5")
859+ self.check_file_strippedline("pvs", "vg2=/dev/sdb6")
860+
861+
862+class PreciseTestIscsiLvm(relbase.precise, TestLvmIscsiAbs):
863+ __test__ = True
864+
865+
866+class TrustyTestIscsiLvm(relbase.trusty, TestLvmIscsiAbs):
867+ __test__ = True
868+
869+
870+class XenialTestIscsiLvm(relbase.xenial, TestLvmIscsiAbs):
871+ __test__ = True
872+
873+
874+class YakketyTestIscsiLvm(relbase.yakkety, TestLvmIscsiAbs):
875+ __test__ = True
876+
877+
878+class ZestyTestIscsiLvm(relbase.zesty, TestLvmIscsiAbs):
879+ __test__ = True
880
881=== added file 'tests/vmtests/test_mdadm_iscsi.py'
882--- tests/vmtests/test_mdadm_iscsi.py 1970-01-01 00:00:00 +0000
883+++ tests/vmtests/test_mdadm_iscsi.py 2017-05-19 00:57:33 +0000
884@@ -0,0 +1,42 @@
885+from .releases import base_vm_classes as relbase
886+from .test_mdadm_bcache import TestMdadmAbs
887+from .test_iscsi import TestBasicIscsiAbs
888+
889+import textwrap
890+
891+
892+class TestMdadmIscsiAbs(TestMdadmAbs, TestBasicIscsiAbs):
893+ interactive = False
894+ iscsi_disks = [
895+ {'size': '5G', 'auth': 'user:passw0rd'},
896+ {'size': '5G', 'auth': 'user:passw0rd', 'iauth': 'iuser:ipassw0rd'},
897+ {'size': '5G', 'iauth': 'iuser:ipassw0rd'}]
898+ conf_file = "examples/tests/mdadm_iscsi.yaml"
899+ nr_testfiles = 1
900+
901+ collect_scripts = TestMdadmAbs.collect_scripts
902+ collect_scripts += TestBasicIscsiAbs.collect_scripts + [textwrap.dedent(
903+ """
904+ cd OUTPUT_COLLECT_D
905+ ls -al /sys/class/block/md*/slaves/ > md_slaves
906+ """)]
907+
908+
909+class PreciseTestIscsiMdadm(relbase.precise, TestMdadmIscsiAbs):
910+ __test__ = True
911+
912+
913+class TrustyTestIscsiMdadm(relbase.trusty, TestMdadmIscsiAbs):
914+ __test__ = True
915+
916+
917+class XenialTestIscsiMdadm(relbase.xenial, TestMdadmIscsiAbs):
918+ __test__ = True
919+
920+
921+class YakketyTestIscsiMdadm(relbase.yakkety, TestMdadmIscsiAbs):
922+ __test__ = True
923+
924+
925+class ZestyTestIscsiMdadm(relbase.zesty, TestMdadmIscsiAbs):
926+ __test__ = True

Subscribers

People subscribed via source and target branches