Merge ~smoser/curtin:feature/add-fstest-battery into curtin:master

Proposed by Scott Moser
Status: Merged
Approved by: Scott Moser
Approved revision: ece93d5d40c56f5e07c3575f134de0e9ae915330
Merge reported by: Scott Moser
Merged at revision: 5b7ca31e32eb47eedf2862e7b323dbb9ecb2a781
Proposed branch: ~smoser/curtin:feature/add-fstest-battery
Merge into: curtin:master
Diff against target: 326 lines (+285/-1)
4 files modified
curtin/block/__init__.py (+4/-1)
curtin/block/mkfs.py (+1/-0)
examples/tests/filesystem_battery.yaml (+101/-0)
tests/vmtests/test_fs_battery.py (+179/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Ryan Harper (community) Approve
Review via email: mp+337244@code.launchpad.net

Commit message

vmtest: Add Filesystem Battery test.

This test exercises filesystem creation, mount and unmount of all
supported filesystem types.

Also here is a fix for jfs filesystem creation. mkfs_jfs requires a '-q'
argument to force/quiet. Otherwise it will prompt to ask if you
really want to do that.

Description of the change

see commit message

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

I still need to test that the things are mountable. So far I've only been through the installation of Bionic.

Revision history for this message
Ryan Harper (raharper) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Scott Moser (smoser) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
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 :

And it all passes? Nice work. One comment on where to store the blkid output parser.

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

its not completely generic blkid parser as it is.
but yes, i thought about putting that into the base class and just always collecting that info.

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 :

Let's confirm this passed on Jenkins and I'm +1

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

On diglet, I did:
 git

$ git rev-parse HEAD
ece93d5d40c56f5e07c3575f134de0e9ae915330

# full output: http://paste.ubuntu.com/p/GFZpHtjZ5k/
$ ./tools/jenkins-runner -p4 tests/vmtests/test_fs_battery.py
CURTIN_VMTEST_IMAGE_SYNC=0
CURTIN_VMTEST_ISCSI_PORTAL=10.245.168.20:5336
CURTIN_VMTEST_KEEP_DATA_FAIL=logs,collect
CURTIN_VMTEST_KEEP_DATA_PASS=logs,collect
CURTIN_VMTEST_LOG=/srv/smoser/curtin/curtin/output/debug.log
CURTIN_VMTEST_PARALLEL=4
CURTIN_VMTEST_REUSE_TOPDIR=0
CURTIN_VMTEST_TAR_DISKS=0
CURTIN_VMTEST_TOPDIR=/srv/smoser/curtin/curtin/output
TGT_IPC_SOCKET=/srv/smoser/curtin/curtin/output/tgt.d/socket
TGT_LOG_D=/srv/smoser/curtin/curtin/output/tgt.d
TGT_PID=17545
TGT_PORTAL=10.245.168.20:5336
http_proxy=
https_proxy=
no_proxy=
Quering synced ephemeral images/kernels in /srv/images
======================================================================================
 Release Codename ImageDate Arch/SubArch Path
--------------------------------------------------------------------------------------
   12.04 precise 20170424 amd64/hwe-t precise/amd64/20170424/root-image.gz
   14.04 trusty 20180302 amd64/hwe-t trusty/amd64/20180302/squashfs
   14.04 trusty 20180302 amd64/hwe-x trusty/amd64/20180302/squashfs
   16.04 xenial 20180306 amd64/ga-16.04 xenial/amd64/20180306/squashfs
   16.04 xenial 20180306 amd64/hwe-16.04 xenial/amd64/20180306/squashfs
   16.04 xenial 20180306 amd64/hwe-16.04-edge xenial/amd64/20180306/squashfs
   17.04 zesty 20171219 amd64/ga-17.04 zesty/amd64/20171219/squashfs
   17.10 artful 20180303 amd64/ga-17.10 artful/amd64/20180303/squashfs
   18.04 bionic 20180224 amd64/ga-18.04 bionic/amd64/20180224/squashfs
======================================================================================

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
diff --git a/curtin/block/__init__.py b/curtin/block/__init__.py
index a82ed57..50e953e 100644
--- a/curtin/block/__init__.py
+++ b/curtin/block/__init__.py
@@ -1051,13 +1051,16 @@ def detect_required_packages_mapping():
1051 'ext2': ['e2fsprogs'],1051 'ext2': ['e2fsprogs'],
1052 'ext3': ['e2fsprogs'],1052 'ext3': ['e2fsprogs'],
1053 'ext4': ['e2fsprogs'],1053 'ext4': ['e2fsprogs'],
1054 'jfs': ['jfsutils'],
1054 'lvm_partition': ['lvm2'],1055 'lvm_partition': ['lvm2'],
1055 'lvm_volgroup': ['lvm2'],1056 'lvm_volgroup': ['lvm2'],
1057 'ntfs': ['ntfs-3g'],
1056 'raid': ['mdadm'],1058 'raid': ['mdadm'],
1059 'reiserfs': ['reiserfsprogs'],
1057 'xfs': ['xfsprogs'],1060 'xfs': ['xfsprogs'],
1061 'zfsroot': ['zfsutils-linux', 'zfs-initramfs'],
1058 'zfs': ['zfsutils-linux', 'zfs-initramfs'],1062 'zfs': ['zfsutils-linux', 'zfs-initramfs'],
1059 'zpool': ['zfsutils-linux', 'zfs-initramfs'],1063 'zpool': ['zfsutils-linux', 'zfs-initramfs'],
1060 'zfsroot': ['zfsutils-linux', 'zfs-initramfs'],
1061 },1064 },
1062 },1065 },
1063 }1066 }
diff --git a/curtin/block/mkfs.py b/curtin/block/mkfs.py
index 5cdb87c..a199d05 100644
--- a/curtin/block/mkfs.py
+++ b/curtin/block/mkfs.py
@@ -54,6 +54,7 @@ family_flag_mappings = {
54 "force": {"btrfs": "--force",54 "force": {"btrfs": "--force",
55 "ext": "-F",55 "ext": "-F",
56 "fat": "-I",56 "fat": "-I",
57 "jfs": "-q",
57 "ntfs": "--force",58 "ntfs": "--force",
58 "reiserfs": "-f",59 "reiserfs": "-f",
59 "swap": "--force",60 "swap": "--force",
diff --git a/examples/tests/filesystem_battery.yaml b/examples/tests/filesystem_battery.yaml
60new file mode 10064461new file mode 100644
index 0000000..ba4fcac
--- /dev/null
+++ b/examples/tests/filesystem_battery.yaml
@@ -0,0 +1,101 @@
1showtrace: true
2early_commands:
3 "00": [apt-get, update, -qy]
4 "01": [apt-get, install, -qy, --no-install-recommends,
5 ntfs-3g, jfsutils, reiserfsprogs]
6storage:
7 version: 1
8 config:
9 - id: disk1
10 type: disk
11 ptable: msdos
12 model: QEMU HARDDISK
13 serial: disk-a
14 wipe: superblock
15 grub_device: true
16 - id: disk1p1
17 type: partition
18 number: 1
19 size: 3GB
20 device: disk1
21 flag: boot
22 - id: disk1p1_fs
23 type: format
24 fstype: ext4
25 volume: disk1p1
26 label: 'cloudimg-rootfs'
27 - id: disk1p1_mount
28 type: mount
29 path: /
30 device: disk1p1_fs
31 - id: disk2
32 type: disk
33 serial: fsbattery
34 wipe: superblock
35 ptable: gpt
36 - {id: d2p01, number: 1, device: disk2, type: partition, size: 500M}
37 - {id: d2p02, number: 2, device: disk2, type: partition, size: 500M}
38 - {id: d2p03, number: 3, device: disk2, type: partition, size: 500M}
39 - {id: d2p04, number: 4, device: disk2, type: partition, size: 500M}
40 - {id: d2p05, number: 5, device: disk2, type: partition, size: 500M}
41 - {id: d2p06, number: 6, device: disk2, type: partition, size: 500M}
42 - {id: d2p07, number: 7, device: disk2, type: partition, size: 500M}
43 - {id: d2p08, number: 8, device: disk2, type: partition, size: 500M}
44 - {id: d2p09, number: 9, device: disk2, type: partition, size: 500M}
45 - {id: d2p10, number: 10, device: disk2, type: partition, size: 500M}
46 - id: fs01
47 type: format
48 fstype: btrfs
49 label: mybtrfs
50 volume: d2p01
51 uuid: 8946d6ad-1e5f-4609-924c-4a39b6b561c9
52 - id: fs02
53 type: format
54 fstype: ext2
55 label: myext2
56 volume: d2p02
57 uuid: 5d60e5e8-0c41-11e8-a664-525400123456
58 - id: fs03
59 type: format
60 fstype: ext3
61 label: myext3
62 volume: d2p03
63 uuid: 5d7f4d30-0c41-11e8-a664-525400123456
64 - id: fs04
65 type: format
66 fstype: ext4
67 label: myext4
68 volume: d2p04
69 uuid: 5da136b6-0c41-11e8-a664-525400123456
70 - id: fs05
71 type: format
72 fstype: fat16
73 label: myvfat16
74 volume: d2p05
75 - id: fs06
76 type: format
77 fstype: fat32
78 label: myvfat32
79 volume: d2p06
80 - id: fs07
81 type: format
82 fstype: jfs
83 label: myjfs
84 volume: d2p07
85 - id: fs08
86 type: format
87 fstype: ntfs
88 label: myntfs
89 volume: d2p08
90 - id: fs09
91 type: format
92 fstype: reiserfs
93 label: myreiserfs
94 volume: d2p09
95 uuid: 5ed8308e-0c41-11e8-a664-525400123456
96 - id: fs10
97 type: format
98 fstype: xfs
99 label: myxfs
100 volume: d2p10
101 uuid: 9c537621-f2f4-4e24-a071-e05012a1a997
diff --git a/tests/vmtests/test_fs_battery.py b/tests/vmtests/test_fs_battery.py
0new file mode 100644102new file mode 100644
index 0000000..5798d48
--- /dev/null
+++ b/tests/vmtests/test_fs_battery.py
@@ -0,0 +1,179 @@
1# This file is part of curtin. See LICENSE file for copyright and license info.
2
3from . import VMBaseClass
4from .releases import base_vm_classes as relbase
5
6from curtin import config
7
8import os
9import textwrap
10
11
12def _parse_blkid_output(content):
13 """Parse the output of the 'blkid' calls in collect_script.
14
15 Input is groups of lines. Each line is key=value. Each group
16 has the first line with key DEVNAME and last line key RESULT.
17
18 returned value is a dictionary by shortened devname like:.
19 {'part1': {'devname': 'part1', 'label': '...'}}"""
20 def _record(lines):
21 record = {}
22 for line in lines:
23 key, _, val = line.partition("=")
24 if key == 'DEVNAME':
25 bname = os.path.basename(val)
26 # bname is 'virtio-fsbattery-partX'. get just 'partX'
27 record[key.lower()] = bname.rpartition("-")[2]
28 elif key in ('RESULT', 'LABEL', 'UUID', 'TYPE'):
29 record[key.lower()] = val
30 return record
31
32 lines = []
33 records = {}
34 for line in content.splitlines():
35 lines.append(line)
36 if line.startswith("RESULT"):
37 r = _record(lines)
38 records[r['devname']] = r
39 lines = []
40
41 return records
42
43
44class TestFsBattery(VMBaseClass):
45 interactive = False
46 conf_file = "examples/tests/filesystem_battery.yaml"
47 extra_disks = ['20G']
48 collect_scripts = VMBaseClass.collect_scripts + [textwrap.dedent("""
49 cd OUTPUT_COLLECT_D
50 blkid -o export > blkid.out
51 cat /proc/mounts > proc_mounts
52 cat /proc/partitions > proc_partitions
53 find /etc/network/interfaces.d > find_interfacesd
54 cat /proc/cmdline > cmdline
55
56 set +x
57 serial="fsbattery"
58 disk=$(echo /dev/disk/by-id/*-$serial)
59 [ -b "$disk" ] || { echo "No disk with serial $serial." exit 1; }
60
61 # not all blkid versions output DEVNAME, so do it ourselves.
62 blkid -o export "$disk" | grep -q DEVNAME= &&
63 hasdev=true || hasdev=false
64 for d in $disk-part*; do
65 $hasdev || echo DEVNAME=$d
66 blkid -o export "$d"
67 echo RESULT=$?
68 done > battery-blkid
69
70 mpbase=/tmp/mp;
71 mkdir -p /tmp/mp
72 for d in $disk-part*; do
73 fstype=$(blkid -o export "$d" |
74 awk -F= '$1 == "TYPE" { print $2 }')
75 if [ -z "$fstype" ]; then
76 msg="FAIL: blkid did not identify fstype"
77 else
78 mp="$mpbase/${d##*-}"
79 mkdir "$mp"
80 echo "${d##*-} $fstype" > "$mp.info"
81 if out=$(mount -t "$fstype" "$d" "$mp" 2>&1); then
82 msg="PASS"
83 else
84 rm -Rf "$mp.info" "$mp"
85 msg="FAIL: mount $fstype failed $?: $out"
86 fi
87 fi
88 echo "${d##*-} mount: $msg"
89 done > battery-mount-umount
90
91 awk '$5 ~ mp { print $0 }' "mp=$mpbase/" \
92 /proc/1/mountinfo > battery-mountinfo
93
94 for info in $mpbase/*.info; do
95 read part fstype < "$info"
96 mp="${info%.info}"
97 out=$(umount "$mp" 2>&1) &&
98 echo "$part umount: PASS" ||
99 echo "$part umount: FAIL: $out"
100 done >> battery-mount-umount
101 """)]
102
103 def get_fs_entries(self):
104 """Return a dictionary of fs entires in config by 'partX'."""
105 stgcfg = config.load_config(self.conf_file)['storage']['config']
106 fs_entries = {}
107 for entry in stgcfg:
108 if not entry['id'].startswith("fs"):
109 continue
110 part = "part%d" % int(entry['id'][2:])
111 fs_entries[part] = entry.copy()
112 return fs_entries
113
114 def test_blkid_output(self):
115 """Check the recorded output of 'blkid -o export' on each partition.
116
117 parse parse the 'battery-blkid' collected file, and compare it
118 to expected output from reading the storage config."""
119 results = _parse_blkid_output(self.load_collect_file("battery-blkid"))
120
121 # tools for these types do not support providing uuid.
122 no_uuid_types = ['vfat', 'jfs', 'fat16', 'fat32', 'ntfs']
123 if self.release in ('trusty'):
124 no_uuid_types += ['btrfs', 'xfs']
125
126 for k, v in results.items():
127 if v['type'] in no_uuid_types:
128 del v['uuid']
129
130 # these curtin "types" show in blkid output differently.
131 type2blkid = {'fat32': 'vfat', 'fat16': 'vfat'}
132 expected = {}
133 for part, entry in self.get_fs_entries().items():
134 record = {
135 'devname': part,
136 'label': entry['label'],
137 'type': type2blkid.get(entry['fstype'], entry['fstype']),
138 'result': "0",
139 }
140 if 'uuid' in entry and record['type'] not in no_uuid_types:
141 record['uuid'] = entry['uuid']
142 expected[record['devname']] = record
143
144 self.assertEqual(expected, results)
145
146 def test_mount_umount(self):
147 """Check output of mount and unmount operations for each fs."""
148 results = self.load_collect_file("battery-mount-umount").splitlines()
149 entries = self.get_fs_entries()
150 expected = (["%s mount: PASS" % k for k in entries] +
151 ["%s umount: PASS" % k for k in entries])
152 self.assertEqual(sorted(expected), sorted(results))
153
154
155class TrustyTestFsBattery(relbase.trusty, TestFsBattery):
156 __test__ = True
157
158
159class TrustyHWEXTestFsBattery(relbase.trusty_hwe_x, TestFsBattery):
160 __test__ = True
161
162
163class XenialGATestFsBattery(relbase.xenial_ga, TestFsBattery):
164 __test__ = True
165
166
167class XenialHWETestFsBattery(relbase.xenial_hwe, TestFsBattery):
168 __test__ = True
169
170
171class XenialEdgeTestFsBattery(relbase.xenial_edge, TestFsBattery):
172 __test__ = True
173
174
175class BionicTestFsBattery(relbase.bionic, TestFsBattery):
176 __test__ = True
177
178
179# vi: ts=4 expandtab syntax=python

Subscribers

People subscribed via source and target branches