Merge ~smoser/curtin:ubuntu/devel into curtin:ubuntu/devel

Proposed by Scott Moser
Status: Rejected
Rejected by: Scott Moser
Proposed branch: ~smoser/curtin:ubuntu/devel
Merge into: curtin:ubuntu/devel
Diff against target: 772 lines (+412/-43)
19 files modified
curtin/block/clear_holders.py (+3/-0)
curtin/block/lvm.py (+23/-5)
curtin/block/mdadm.py (+2/-3)
curtin/commands/block_meta.py (+2/-1)
curtin/commands/install.py (+2/-1)
curtin/log.py (+43/-0)
curtin/udev.py (+2/-0)
curtin/util.py (+33/-8)
debian/changelog (+10/-0)
examples/tests/dirty_disks_config.yaml (+30/-3)
examples/tests/lvmoverraid.yaml (+98/-0)
examples/tests/vmtest_defaults.yaml (+14/-0)
tests/unittests/test_block_lvm.py (+13/-13)
tests/unittests/test_block_mdadm.py (+4/-5)
tests/unittests/test_clear_holders.py (+5/-2)
tests/unittests/test_util.py (+62/-0)
tests/vmtests/__init__.py (+15/-1)
tests/vmtests/test_lvm_raid.py (+50/-0)
tests/vmtests/test_lvm_root.py (+1/-1)
Reviewer Review Type Date Requested Status
Chad Smith Disapprove
Server Team CI bot continuous-integration Approve
Review via email: mp+353354@code.launchpad.net

Commit message

update changelog (New upstream snapshot 18.1-48-g6a776e15).

Description of the change

see commit message

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

rejected as ryan had a zfs branch that landed after this.
Just pulled in https://code.launchpad.net/~chad.smith/curtin/+git/curtin/+merge/353361 instead

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

going with chad's with one more upstream commit at
 https://code.launchpad.net/~chad.smith/curtin/+git/curtin/+merge/353361

Unmerged commits

cecdb41... by Scott Moser

update changelog (New upstream snapshot 18.1-48-g6a776e15).

cb7fc8d... by Scott Moser

merge from master at 18.1-48-g6a776e15

6a776e1... by Ryan Harper

clear-holders: rescan for lvm devices after assembling raid arrays

Lvm devices to be found after assembling raid arrays. Add a call after
lvm_scan to activate any discovered vgs and lvs.

LP: #1783413

40d682c... by Ryan Harper

vmtest: enable persistent journal and collect at boot time

Target OSes which use systemd-journald may or maynot enable a
persistent journal on the root filesystem. If the target release
supports journald, issue the commands to create a persistent
journal. During the boot phase, issue commands to flush the
journal and collect (and compress) the journal as the last
script before tar'ing the collect data.

Rename vmtest_pollinate.yaml to vmtest_defaults.yaml. This
file is included in all vmtest runs.

1b387fb... by Scott Moser

Add timing and logging functions.

This adds some decorators and functions to easily time function call.
It was originally done to get an idea on how much time we spend waiting
for udevadm settle, but the code is generally useful.

Note that the 'cmd_install' timer unfortunately doesn't make it
into the saved-off log as the message is appended after it is copied.

1a201e5... by Scott Moser

parse_dpkg_version: support non-numeric in version string.

This fixes parse_dpkg_version for packages with non-numeric (0-9.)
in their versions. It also improves it to work for native packages.
Native packages do not have '-'. Also adds tests of parse_dpkg_version.

LP: #1786795

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/curtin/block/clear_holders.py b/curtin/block/clear_holders.py
index 9d73b28..a2042d5 100644
--- a/curtin/block/clear_holders.py
+++ b/curtin/block/clear_holders.py
@@ -624,6 +624,9 @@ def start_clear_holders_deps():
624 # all disks and partitions should be sufficient to remove the mdadm624 # all disks and partitions should be sufficient to remove the mdadm
625 # metadata625 # metadata
626 mdadm.mdadm_assemble(scan=True, ignore_errors=True)626 mdadm.mdadm_assemble(scan=True, ignore_errors=True)
627 # scan and activate for logical volumes
628 lvm.lvm_scan()
629 lvm.activate_volgroups()
627 # the bcache module needs to be present to properly detect bcache devs630 # the bcache module needs to be present to properly detect bcache devs
628 # on some systems (precise without hwe kernel) it may not be possible to631 # on some systems (precise without hwe kernel) it may not be possible to
629 # lad the bcache module bcause it is not present in the kernel. if this632 # lad the bcache module bcause it is not present in the kernel. if this
diff --git a/curtin/block/lvm.py b/curtin/block/lvm.py
index 8643245..eca64f6 100644
--- a/curtin/block/lvm.py
+++ b/curtin/block/lvm.py
@@ -57,14 +57,32 @@ def lvmetad_running():
57 '/run/lvmetad.pid'))57 '/run/lvmetad.pid'))
5858
5959
60def lvm_scan():60def activate_volgroups():
61 """
62 Activate available volgroups and logical volumes within.
63
64 # found
65 % vgchange -ay
66 1 logical volume(s) in volume group "vg1sdd" now active
67
68 # none found (no output)
69 % vgchange -ay
70 """
71
72 # vgchange handles syncing with udev by default
73 # see man 8 vgchange and flag --noudevsync
74 out, _ = util.subp(['vgchange', '--activate=y'], capture=True)
75 if out:
76 LOG.info(out)
77
78
79def lvm_scan(activate=True):
61 """80 """
62 run full scan for volgroups, logical volumes and physical volumes81 run full scan for volgroups, logical volumes and physical volumes
63 """82 """
64 # the lvm tools lvscan, vgscan and pvscan on ubuntu precise do not83 # prior to xenial, lvmetad is not packaged, so even if a tool supports
65 # support the flag --cache. the flag is present for the tools in ubuntu84 # flag --cache it has no effect. In Xenial and newer the --cache flag is
66 # trusty and later. since lvmetad is used in current releases of85 # used (if lvmetad is running) to ensure that the data cached by
67 # ubuntu, the --cache flag is needed to ensure that the data cached by
68 # lvmetad is updated.86 # lvmetad is updated.
6987
70 # before appending the cache flag though, check if lvmetad is running. this88 # before appending the cache flag though, check if lvmetad is running. this
diff --git a/curtin/block/mdadm.py b/curtin/block/mdadm.py
index e0fe0d3..8eff7fb 100644
--- a/curtin/block/mdadm.py
+++ b/curtin/block/mdadm.py
@@ -184,7 +184,7 @@ def mdadm_create(md_devname, raidlevel, devices, spares=None, md_name=""):
184 cmd.append(device)184 cmd.append(device)
185185
186 # Create the raid device186 # Create the raid device
187 util.subp(["udevadm", "settle"])187 udev.udevadm_settle()
188 util.subp(["udevadm", "control", "--stop-exec-queue"])188 util.subp(["udevadm", "control", "--stop-exec-queue"])
189 try:189 try:
190 util.subp(cmd, capture=True)190 util.subp(cmd, capture=True)
@@ -208,8 +208,7 @@ def mdadm_create(md_devname, raidlevel, devices, spares=None, md_name=""):
208 raise208 raise
209209
210 util.subp(["udevadm", "control", "--start-exec-queue"])210 util.subp(["udevadm", "control", "--start-exec-queue"])
211 util.subp(["udevadm", "settle",211 udev.udevadm_settle(exists=md_devname)
212 "--exit-if-exists=%s" % md_devname])
213212
214213
215def mdadm_examine(devpath, export=MDADM_USE_EXPORT):214def mdadm_examine(devpath, export=MDADM_USE_EXPORT):
diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
index f5b82cf..63193f5 100644
--- a/curtin/commands/block_meta.py
+++ b/curtin/commands/block_meta.py
@@ -3,7 +3,7 @@
3from collections import OrderedDict, namedtuple3from collections import OrderedDict, namedtuple
4from curtin import (block, config, util)4from curtin import (block, config, util)
5from curtin.block import (bcache, mdadm, mkfs, clear_holders, lvm, iscsi, zfs)5from curtin.block import (bcache, mdadm, mkfs, clear_holders, lvm, iscsi, zfs)
6from curtin.log import LOG6from curtin.log import LOG, logged_time
7from curtin.reporter import events7from curtin.reporter import events
88
9from . import populate_one_subcmd9from . import populate_one_subcmd
@@ -48,6 +48,7 @@ CMD_ARGUMENTS = (
48)48)
4949
5050
51@logged_time("BLOCK_META")
51def block_meta(args):52def block_meta(args):
52 # main entry point for the block-meta command.53 # main entry point for the block-meta command.
53 state = util.load_command_environment()54 state = util.load_command_environment()
diff --git a/curtin/commands/install.py b/curtin/commands/install.py
index 9e5406c..4d2a13f 100644
--- a/curtin/commands/install.py
+++ b/curtin/commands/install.py
@@ -15,7 +15,7 @@ from curtin.block import iscsi
15from curtin import config15from curtin import config
16from curtin import util16from curtin import util
17from curtin import version17from curtin import version
18from curtin.log import LOG18from curtin.log import LOG, logged_time
19from curtin.reporter.legacy import load_reporter19from curtin.reporter.legacy import load_reporter
20from curtin.reporter import events20from curtin.reporter import events
21from . import populate_one_subcmd21from . import populate_one_subcmd
@@ -390,6 +390,7 @@ def migrate_proxy_settings(cfg):
390 cfg['proxy'] = proxy390 cfg['proxy'] = proxy
391391
392392
393@logged_time("INSTALL_COMMAND")
393def cmd_install(args):394def cmd_install(args):
394 from .collect_logs import create_log_tarfile395 from .collect_logs import create_log_tarfile
395 cfg = deepcopy(CONFIG_BUILTIN)396 cfg = deepcopy(CONFIG_BUILTIN)
diff --git a/curtin/log.py b/curtin/log.py
index 4844460..446ba2c 100644
--- a/curtin/log.py
+++ b/curtin/log.py
@@ -1,6 +1,9 @@
1# This file is part of curtin. See LICENSE file for copyright and license info.1# This file is part of curtin. See LICENSE file for copyright and license info.
22
3import logging3import logging
4import time
5
6from functools import wraps
47
5# Logging items for easy access8# Logging items for easy access
6getLogger = logging.getLogger9getLogger = logging.getLogger
@@ -56,6 +59,46 @@ def _getLogger(name='curtin'):
56if not logging.getLogger().handlers:59if not logging.getLogger().handlers:
57 logging.getLogger().addHandler(NullHandler())60 logging.getLogger().addHandler(NullHandler())
5861
62
63def _repr_call(name, *args, **kwargs):
64 return "%s(%s)" % (
65 name,
66 ', '.join([str(repr(a)) for a in args] +
67 ["%s=%s" % (k, repr(v)) for k, v in kwargs.items()]))
68
69
70def log_call(func, *args, **kwargs):
71 return log_time(
72 "TIMED %s: " % _repr_call(func.__name__, *args, **kwargs),
73 func, *args, **kwargs)
74
75
76def log_time(msg, func, *args, **kwargs):
77 start = time.time()
78 try:
79 return func(*args, **kwargs)
80 finally:
81 LOG.debug(msg + "%.3f", (time.time() - start))
82
83
84def logged_call():
85 def decorator(func):
86 @wraps(func)
87 def wrapper(*args, **kwargs):
88 return log_call(func, *args, **kwargs)
89 return wrapper
90 return decorator
91
92
93def logged_time(msg):
94 def decorator(func):
95 @wraps(func)
96 def wrapper(*args, **kwargs):
97 return log_time("TIMED %s: " % msg, func, *args, **kwargs)
98 return wrapper
99 return decorator
100
101
59LOG = _getLogger()102LOG = _getLogger()
60103
61# vi: ts=4 expandtab syntax=python104# vi: ts=4 expandtab syntax=python
diff --git a/curtin/udev.py b/curtin/udev.py
index 92e38ff..13d9cc5 100644
--- a/curtin/udev.py
+++ b/curtin/udev.py
@@ -2,6 +2,7 @@
22
3import os3import os
4from curtin import util4from curtin import util
5from curtin.log import logged_call
56
67
7def compose_udev_equality(key, value):8def compose_udev_equality(key, value):
@@ -40,6 +41,7 @@ def generate_udev_rule(interface, mac):
40 return '%s\n' % rule41 return '%s\n' % rule
4142
4243
44@logged_call()
43def udevadm_settle(exists=None, timeout=None):45def udevadm_settle(exists=None, timeout=None):
44 settle_cmd = ["udevadm", "settle"]46 settle_cmd = ["udevadm", "settle"]
45 if exists:47 if exists:
diff --git a/curtin/util.py b/curtin/util.py
index 7d06c09..29bf06e 100644
--- a/curtin/util.py
+++ b/curtin/util.py
@@ -38,7 +38,7 @@ except NameError:
38 # python3 does not have a long type.38 # python3 does not have a long type.
39 numeric_types = (int, float)39 numeric_types = (int, float)
4040
41from .log import LOG41from .log import LOG, log_call
4242
43_INSTALLED_HELPERS_PATH = 'usr/lib/curtin/helpers'43_INSTALLED_HELPERS_PATH = 'usr/lib/curtin/helpers'
44_INSTALLED_MAIN = 'usr/bin/curtin'44_INSTALLED_MAIN = 'usr/bin/curtin'
@@ -661,7 +661,7 @@ class ChrootableTarget(object):
661661
662 # if /dev is to be unmounted, udevadm settle (LP: #1462139)662 # if /dev is to be unmounted, udevadm settle (LP: #1462139)
663 if target_path(self.target, "/dev") in self.umounts:663 if target_path(self.target, "/dev") in self.umounts:
664 subp(['udevadm', 'settle'])664 log_call(subp, ['udevadm', 'settle'])
665665
666 for p in reversed(self.umounts):666 for p in reversed(self.umounts):
667 do_umount(p)667 do_umount(p)
@@ -810,13 +810,37 @@ def parse_dpkg_version(raw, name=None, semx=None):
810 """Parse a dpkg version string into various parts and calcualate a810 """Parse a dpkg version string into various parts and calcualate a
811 numerical value of the version for use in comparing package versions811 numerical value of the version for use in comparing package versions
812812
813 returns a dictionary with the results813 Native packages (without a '-'), will have the package version treated
814 as the upstream version.
815
816 returns a dictionary with fields:
817 'major' (int), 'minor' (int), 'micro' (int),
818 'semantic_version' (int),
819 'extra' (string), 'raw' (string), 'upstream' (string),
820 'name' (present only if name is not None)
814 """821 """
822 if not isinstance(raw, string_types):
823 raise TypeError(
824 "Invalid type %s for parse_dpkg_version" % raw.__class__)
825
815 if semx is None:826 if semx is None:
816 semx = (10000, 100, 1)827 semx = (10000, 100, 1)
817828
818 upstream = raw.split('-')[0]829 if "-" in raw:
819 toks = upstream.split(".", 2)830 upstream = raw.rsplit('-', 1)[0]
831 else:
832 # this is a native package, package version treated as upstream.
833 upstream = raw
834
835 match = re.search(r'[^0-9.]', upstream)
836 if match:
837 extra = upstream[match.start():]
838 upstream_base = upstream[:match.start()]
839 else:
840 upstream_base = upstream
841 extra = None
842
843 toks = upstream_base.split(".", 2)
820 if len(toks) == 3:844 if len(toks) == 3:
821 major, minor, micro = toks845 major, minor, micro = toks
822 elif len(toks) == 2:846 elif len(toks) == 2:
@@ -825,9 +849,10 @@ def parse_dpkg_version(raw, name=None, semx=None):
825 major, minor, micro = (toks[0], 0, 0)849 major, minor, micro = (toks[0], 0, 0)
826850
827 version = {851 version = {
828 'major': major,852 'major': int(major),
829 'minor': minor,853 'minor': int(minor),
830 'micro': micro,854 'micro': int(micro),
855 'extra': extra,
831 'raw': raw,856 'raw': raw,
832 'upstream': upstream,857 'upstream': upstream,
833 }858 }
diff --git a/debian/changelog b/debian/changelog
index 8f013e6..31c9a7c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
1curtin (18.1-48-g6a776e15-0ubuntu1) UNRELEASED; urgency=medium
2
3 * New upstream snapshot.
4 - clear-holders: rescan for lvm devices after assembling raid arrays
5 - vmtest: enable persistent journal and collect at boot time
6 - Add timing and logging functions.
7 - parse_dpkg_version: support non-numeric in version string.
8
9 -- Scott Moser <smoser@ubuntu.com> Fri, 17 Aug 2018 17:38:35 -0400
10
1curtin (18.1-44-g2b12b8fc-0ubuntu1) cosmic; urgency=medium11curtin (18.1-44-g2b12b8fc-0ubuntu1) cosmic; urgency=medium
212
3 * New upstream snapshot.13 * New upstream snapshot.
diff --git a/examples/tests/dirty_disks_config.yaml b/examples/tests/dirty_disks_config.yaml
index 75d44c3..fb9a0d6 100644
--- a/examples/tests/dirty_disks_config.yaml
+++ b/examples/tests/dirty_disks_config.yaml
@@ -27,6 +27,31 @@ bucket:
27 # disable any rpools to trigger disks with zfs_member label but inactive27 # disable any rpools to trigger disks with zfs_member label but inactive
28 # pools28 # pools
29 zpool export rpool ||:29 zpool export rpool ||:
30 - &lvm_stop |
31 #!/bin/sh
32 # This function disables any existing lvm logical volumes that
33 # have been created during the early storage config stage
34 # and simulates the effect of booting into a system with existing
35 # (but inactive) lvm configuration.
36 for vg in `pvdisplay -C --separator = -o vg_name --noheadings`; do
37 vgchange -an $vg ||:
38 done
39 # disable the automatic pvscan, we want to test that curtin
40 # can find/enable logical volumes without this service
41 command -v systemctl && systemctl mask lvm2-pvscan\@.service
42 # remove any existing metadata written from early disk config
43 rm -rf /etc/lvm/archive /etc/lvm/backup
44 - &mdadm_stop |
45 #!/bin/sh
46 # This function disables any existing raid devices which may
47 # have been created during the early storage config stage
48 # and simulates the effect of booting into a system with existing
49 # but inactive mdadm configuration.
50 for md in /dev/md*; do
51 mdadm --stop $md ||:
52 done
53 # remove any existing metadata written from early disk config
54 rm -f /etc/mdadm/mdadm.conf
3055
31early_commands:56early_commands:
32 # running block-meta custom from the install environment57 # running block-meta custom from the install environment
@@ -34,9 +59,11 @@ early_commands:
34 # the disks exactly as in this config before the rest of the install59 # the disks exactly as in this config before the rest of the install
35 # will just blow it all away. We have clean out other environment60 # will just blow it all away. We have clean out other environment
36 # that could unintentionally mess things up.61 # that could unintentionally mess things up.
37 blockmeta: [env, -u, OUTPUT_FSTAB,62 01-blockmeta: [env, -u, OUTPUT_FSTAB,
38 TARGET_MOUNT_POINT=/tmp/my.bdir/target,63 TARGET_MOUNT_POINT=/tmp/my.bdir/target,
39 WORKING_DIR=/tmp/my.bdir/work.d, 64 WORKING_DIR=/tmp/my.bdir/work.d,
40 curtin, --showtrace, -v, block-meta, --umount, custom]65 curtin, --showtrace, -v, block-meta, --umount, custom]
41 enable_swaps: [sh, -c, *swapon]66 02-enable_swaps: [sh, -c, *swapon]
42 disable_rpool: [sh, -c, *zpool_export]67 03-disable_rpool: [sh, -c, *zpool_export]
68 04-lvm_stop: [sh, -c, *lvm_stop]
69 05-mdadm_stop: [sh, -c, *mdadm_stop]
diff --git a/examples/tests/lvmoverraid.yaml b/examples/tests/lvmoverraid.yaml
43new file mode 10064470new file mode 100644
index 0000000..a1d41e9
--- /dev/null
+++ b/examples/tests/lvmoverraid.yaml
@@ -0,0 +1,98 @@
1storage:
2 config:
3 - grub_device: true
4 id: disk-0
5 model: QEMU_HARDDISK
6 name: 'main_disk'
7 serial: disk-a
8 preserve: false
9 ptable: gpt
10 type: disk
11 wipe: superblock
12 - grub_device: false
13 id: disk-2
14 name: 'disk-2'
15 serial: disk-b
16 preserve: false
17 type: disk
18 wipe: superblock
19 - grub_device: false
20 id: disk-1
21 name: 'disk-1'
22 serial: disk-c
23 preserve: false
24 type: disk
25 wipe: superblock
26 - grub_device: false
27 id: disk-3
28 name: 'disk-3'
29 serial: disk-d
30 preserve: false
31 type: disk
32 wipe: superblock
33 - grub_device: false
34 id: disk-4
35 name: 'disk-4'
36 serial: disk-e
37 preserve: false
38 type: disk
39 wipe: superblock
40 - device: disk-0
41 flag: bios_grub
42 id: part-0
43 preserve: false
44 size: 1048576
45 type: partition
46 - device: disk-0
47 flag: ''
48 id: part-1
49 preserve: false
50 size: 4G
51 type: partition
52 - devices:
53 - disk-2
54 - disk-1
55 id: raid-0
56 name: md0
57 raidlevel: 1
58 spare_devices: []
59 type: raid
60 - devices:
61 - disk-3
62 - disk-4
63 id: raid-1
64 name: md1
65 raidlevel: 1
66 spare_devices: []
67 type: raid
68 - devices:
69 - raid-0
70 - raid-1
71 id: vg-0
72 name: vg0
73 type: lvm_volgroup
74 - id: lv-0
75 name: lv-0
76 size: 3G
77 type: lvm_partition
78 volgroup: vg-0
79 - fstype: ext4
80 id: fs-0
81 preserve: false
82 type: format
83 volume: part-1
84 - fstype: ext4
85 id: fs-1
86 preserve: false
87 type: format
88 volume: lv-0
89 - device: fs-0
90 id: mount-0
91 path: /
92 type: mount
93 - device: fs-1
94 id: mount-1
95 path: /home
96 type: mount
97 version: 1
98
diff --git a/examples/tests/vmtest_pollinate.yaml b/examples/tests/vmtest_defaults.yaml
index e4fac06..b1512a8 100644
--- a/examples/tests/vmtest_pollinate.yaml
+++ b/examples/tests/vmtest_defaults.yaml
@@ -6,5 +6,19 @@ _vmtest_pollinate:
6 [ -d "${cfg%/*}" ] || exit 06 [ -d "${cfg%/*}" ] || exit 0
7 echo curtin/vmtest >> "$cfg"7 echo curtin/vmtest >> "$cfg"
88
9# this enables a persitent journald if target system has journald
10# and does not have /var/log/journal directory already
11_persist_journal:
12 - &persist_journal |
13 command -v journalctl && {
14 jdir=/var/log/journal
15 [ -e ${jdir} ] || {
16 mkdir -p ${jdir}
17 systemd-tmpfiles --create --prefix ${jdir}
18 }
19 }
20 exit 0
21
9late_commands:22late_commands:
10 01_vmtest_pollinate: ['curtin', 'in-target', '--', 'sh', '-c', *pvmtest]23 01_vmtest_pollinate: ['curtin', 'in-target', '--', 'sh', '-c', *pvmtest]
24 02_persist_journal: ['curtin', 'in-target', '--', 'sh', '-c', *persist_journal]
diff --git a/tests/unittests/test_block_lvm.py b/tests/unittests/test_block_lvm.py
index 341f2fa..22fb064 100644
--- a/tests/unittests/test_block_lvm.py
+++ b/tests/unittests/test_block_lvm.py
@@ -75,24 +75,24 @@ class TestBlockLvm(CiTestCase):
75 @mock.patch('curtin.block.lvm.util')75 @mock.patch('curtin.block.lvm.util')
76 def test_lvm_scan(self, mock_util, mock_lvmetad):76 def test_lvm_scan(self, mock_util, mock_lvmetad):
77 """check that lvm_scan formats commands correctly for each release"""77 """check that lvm_scan formats commands correctly for each release"""
78 cmds = [['pvscan'], ['vgscan', '--mknodes']]
78 for (count, (codename, lvmetad_status, use_cache)) in enumerate(79 for (count, (codename, lvmetad_status, use_cache)) in enumerate(
79 [('precise', False, False), ('precise', True, False),80 [('precise', False, False),
80 ('trusty', False, False), ('trusty', True, True),81 ('trusty', False, False),
81 ('vivid', False, False), ('vivid', True, True),
82 ('wily', False, False), ('wily', True, True),
83 ('xenial', False, False), ('xenial', True, True),82 ('xenial', False, False), ('xenial', True, True),
84 ('yakkety', True, True), ('UNAVAILABLE', True, True),
85 (None, True, True), (None, False, False)]):83 (None, True, True), (None, False, False)]):
86 mock_util.lsb_release.return_value = {'codename': codename}84 mock_util.lsb_release.return_value = {'codename': codename}
87 mock_lvmetad.return_value = lvmetad_status85 mock_lvmetad.return_value = lvmetad_status
88 lvm.lvm_scan()86 lvm.lvm_scan()
89 self.assertEqual(87 expected = [cmd for cmd in cmds]
90 len(mock_util.subp.call_args_list), 2 * (count + 1))88 for cmd in expected:
91 for (expected, actual) in zip(89 if lvmetad_status:
92 [['pvscan'], ['vgscan', '--mknodes']],90 cmd.append('--cache')
93 mock_util.subp.call_args_list[2 * count:2 * count + 2]):91
94 if use_cache:92 calls = [mock.call(cmd, capture=True) for cmd in expected]
95 expected.append('--cache')93 self.assertEqual(len(expected), len(mock_util.subp.call_args_list))
96 self.assertEqual(mock.call(expected, capture=True), actual)94 mock_util.subp.has_calls(calls)
95 mock_util.subp.reset_mock()
96
9797
98# vi: ts=4 expandtab syntax=python98# vi: ts=4 expandtab syntax=python
diff --git a/tests/unittests/test_block_mdadm.py b/tests/unittests/test_block_mdadm.py
index e2e109c..341e49d 100644
--- a/tests/unittests/test_block_mdadm.py
+++ b/tests/unittests/test_block_mdadm.py
@@ -90,6 +90,8 @@ class TestBlockMdadmCreate(CiTestCase):
90 self.add_patch('curtin.block.mdadm.util', 'mock_util')90 self.add_patch('curtin.block.mdadm.util', 'mock_util')
91 self.add_patch('curtin.block.mdadm.is_valid_device', 'mock_valid')91 self.add_patch('curtin.block.mdadm.is_valid_device', 'mock_valid')
92 self.add_patch('curtin.block.mdadm.get_holders', 'mock_holders')92 self.add_patch('curtin.block.mdadm.get_holders', 'mock_holders')
93 self.add_patch('curtin.block.mdadm.udev.udevadm_settle',
94 'm_udevadm_settle')
9395
94 # Common mock settings96 # Common mock settings
95 self.mock_valid.return_value = True97 self.mock_valid.return_value = True
@@ -115,8 +117,6 @@ class TestBlockMdadmCreate(CiTestCase):
115 expected_calls.append(117 expected_calls.append(
116 call(["mdadm", "--zero-superblock", d], capture=True))118 call(["mdadm", "--zero-superblock", d], capture=True))
117119
118 side_effects.append(("", "")) # udevadm settle
119 expected_calls.append(call(["udevadm", "settle"]))
120 side_effects.append(("", "")) # udevadm control --stop-exec-queue120 side_effects.append(("", "")) # udevadm control --stop-exec-queue
121 expected_calls.append(call(["udevadm", "control",121 expected_calls.append(call(["udevadm", "control",
122 "--stop-exec-queue"]))122 "--stop-exec-queue"]))
@@ -134,9 +134,6 @@ class TestBlockMdadmCreate(CiTestCase):
134 side_effects.append(("", "")) # udevadm control --start-exec-queue134 side_effects.append(("", "")) # udevadm control --start-exec-queue
135 expected_calls.append(call(["udevadm", "control",135 expected_calls.append(call(["udevadm", "control",
136 "--start-exec-queue"]))136 "--start-exec-queue"]))
137 side_effects.append(("", "")) # udevadm settle
138 expected_calls.append(call(["udevadm", "settle",
139 "--exit-if-exists=%s" % md_devname]))
140137
141 return (side_effects, expected_calls)138 return (side_effects, expected_calls)
142139
@@ -154,6 +151,8 @@ class TestBlockMdadmCreate(CiTestCase):
154 mdadm.mdadm_create(md_devname=md_devname, raidlevel=raidlevel,151 mdadm.mdadm_create(md_devname=md_devname, raidlevel=raidlevel,
155 devices=devices, spares=spares)152 devices=devices, spares=spares)
156 self.mock_util.subp.assert_has_calls(expected_calls)153 self.mock_util.subp.assert_has_calls(expected_calls)
154 self.m_udevadm_settle.assert_has_calls(
155 [call(), call(exists=md_devname)])
157156
158 def test_mdadm_create_raid0_devshort(self):157 def test_mdadm_create_raid0_devshort(self):
159 md_devname = "md0"158 md_devname = "md0"
diff --git a/tests/unittests/test_clear_holders.py b/tests/unittests/test_clear_holders.py
index 6c29171..21f76be 100644
--- a/tests/unittests/test_clear_holders.py
+++ b/tests/unittests/test_clear_holders.py
@@ -779,10 +779,12 @@ class TestClearHolders(CiTestCase):
779 mock_gen_holders_tree.return_value = self.example_holders_trees[1][1]779 mock_gen_holders_tree.return_value = self.example_holders_trees[1][1]
780 clear_holders.assert_clear(device)780 clear_holders.assert_clear(device)
781781
782 @mock.patch('curtin.block.clear_holders.lvm')
782 @mock.patch('curtin.block.clear_holders.zfs')783 @mock.patch('curtin.block.clear_holders.zfs')
783 @mock.patch('curtin.block.clear_holders.mdadm')784 @mock.patch('curtin.block.clear_holders.mdadm')
784 @mock.patch('curtin.block.clear_holders.util')785 @mock.patch('curtin.block.clear_holders.util')
785 def test_start_clear_holders_deps(self, mock_util, mock_mdadm, mock_zfs):786 def test_start_clear_holders_deps(self, mock_util, mock_mdadm, mock_zfs,
787 mock_lvm):
786 mock_zfs.zfs_supported.return_value = True788 mock_zfs.zfs_supported.return_value = True
787 clear_holders.start_clear_holders_deps()789 clear_holders.start_clear_holders_deps()
788 mock_mdadm.mdadm_assemble.assert_called_with(790 mock_mdadm.mdadm_assemble.assert_called_with(
@@ -790,11 +792,12 @@ class TestClearHolders(CiTestCase):
790 mock_util.load_kernel_module.assert_has_calls([792 mock_util.load_kernel_module.assert_has_calls([
791 mock.call('bcache'), mock.call('zfs')])793 mock.call('bcache'), mock.call('zfs')])
792794
795 @mock.patch('curtin.block.clear_holders.lvm')
793 @mock.patch('curtin.block.clear_holders.zfs')796 @mock.patch('curtin.block.clear_holders.zfs')
794 @mock.patch('curtin.block.clear_holders.mdadm')797 @mock.patch('curtin.block.clear_holders.mdadm')
795 @mock.patch('curtin.block.clear_holders.util')798 @mock.patch('curtin.block.clear_holders.util')
796 def test_start_clear_holders_deps_nozfs(self, mock_util, mock_mdadm,799 def test_start_clear_holders_deps_nozfs(self, mock_util, mock_mdadm,
797 mock_zfs):800 mock_zfs, mock_lvm):
798 """test that we skip zfs modprobe on unsupported platforms"""801 """test that we skip zfs modprobe on unsupported platforms"""
799 mock_zfs.zfs_supported.return_value = False802 mock_zfs.zfs_supported.return_value = False
800 clear_holders.start_clear_holders_deps()803 clear_holders.start_clear_holders_deps()
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 483cd5d..7fb332d 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -4,6 +4,7 @@ from unittest import skipIf
4import mock4import mock
5import os5import os
6import stat6import stat
7import sys
7from textwrap import dedent8from textwrap import dedent
89
9from curtin import util10from curtin import util
@@ -1035,4 +1036,65 @@ class TestLoadKernelModule(CiTestCase):
1035 self.assertEqual(0, self.m_subp.call_count)1036 self.assertEqual(0, self.m_subp.call_count)
10361037
10371038
1039class TestParseDpkgVersion(CiTestCase):
1040 """test parse_dpkg_version."""
1041
1042 def test_none_raises_type_error(self):
1043 self.assertRaises(TypeError, util.parse_dpkg_version, None)
1044
1045 @skipIf(sys.version_info.major < 3, "python 2 bytes are strings.")
1046 def test_bytes_raises_type_error(self):
1047 self.assertRaises(TypeError, util.parse_dpkg_version, b'1.2.3-0')
1048
1049 def test_simple_native_package_version(self):
1050 """dpkg versions must have a -. If not present expect value error."""
1051 self.assertEqual(
1052 {'major': 2, 'minor': 28, 'micro': 0, 'extra': None,
1053 'raw': '2.28', 'upstream': '2.28', 'name': 'germinate',
1054 'semantic_version': 22800},
1055 util.parse_dpkg_version('2.28', name='germinate'))
1056
1057 def test_complex_native_package_version(self):
1058 dver = '1.0.106ubuntu2+really1.0.97ubuntu1'
1059 self.assertEqual(
1060 {'major': 1, 'minor': 0, 'micro': 106,
1061 'extra': 'ubuntu2+really1.0.97ubuntu1',
1062 'raw': dver, 'upstream': dver, 'name': 'debootstrap',
1063 'semantic_version': 100106},
1064 util.parse_dpkg_version(dver, name='debootstrap',
1065 semx=(100000, 1000, 1)))
1066
1067 def test_simple_valid(self):
1068 self.assertEqual(
1069 {'major': 1, 'minor': 2, 'micro': 3, 'extra': None,
1070 'raw': '1.2.3-0', 'upstream': '1.2.3', 'name': 'foo',
1071 'semantic_version': 10203},
1072 util.parse_dpkg_version('1.2.3-0', name='foo'))
1073
1074 def test_simple_valid_with_semx(self):
1075 self.assertEqual(
1076 {'major': 1, 'minor': 2, 'micro': 3, 'extra': None,
1077 'raw': '1.2.3-0', 'upstream': '1.2.3',
1078 'semantic_version': 123},
1079 util.parse_dpkg_version('1.2.3-0', semx=(100, 10, 1)))
1080
1081 def test_upstream_with_hyphen(self):
1082 """upstream versions may have a hyphen."""
1083 cver = '18.2-14-g6d48d265-0ubuntu1'
1084 self.assertEqual(
1085 {'major': 18, 'minor': 2, 'micro': 0, 'extra': '-14-g6d48d265',
1086 'raw': cver, 'upstream': '18.2-14-g6d48d265',
1087 'name': 'cloud-init', 'semantic_version': 180200},
1088 util.parse_dpkg_version(cver, name='cloud-init'))
1089
1090 def test_upstream_with_plus(self):
1091 """multipath tools has a + in it."""
1092 mver = '0.5.0+git1.656f8865-5ubuntu2.5'
1093 self.assertEqual(
1094 {'major': 0, 'minor': 5, 'micro': 0, 'extra': '+git1.656f8865',
1095 'raw': mver, 'upstream': '0.5.0+git1.656f8865',
1096 'semantic_version': 500},
1097 util.parse_dpkg_version(mver))
1098
1099
1038# vi: ts=4 expandtab syntax=python1100# vi: ts=4 expandtab syntax=python
diff --git a/tests/vmtests/__init__.py b/tests/vmtests/__init__.py
index 68b7442..0249655 100644
--- a/tests/vmtests/__init__.py
+++ b/tests/vmtests/__init__.py
@@ -916,8 +916,9 @@ class VMBaseClass(TestCase):
916 # build iscsi disk args if needed916 # build iscsi disk args if needed
917 disks.extend(cls.build_iscsi_disks())917 disks.extend(cls.build_iscsi_disks())
918918
919 # class config file and vmtest defaults
920 configs = [cls.conf_file, 'examples/tests/vmtest_defaults.yaml']
919 # proxy config921 # proxy config
920 configs = [cls.conf_file, 'examples/tests/vmtest_pollinate.yaml']
921 cls.proxy = get_apt_proxy()922 cls.proxy = get_apt_proxy()
922 if cls.proxy is not None and not cls.td.restored:923 if cls.proxy is not None and not cls.td.restored:
923 proxy_config = os.path.join(cls.td.install, 'proxy.cfg')924 proxy_config = os.path.join(cls.td.install, 'proxy.cfg')
@@ -1800,6 +1801,19 @@ def generate_user_data(collect_scripts=None, apt_proxy=None,
1800 exit 0;1801 exit 0;
1801 """)1802 """)
18021803
1804 # add journal collection "last" before collect_post
1805 collect_journal = textwrap.dedent("""#!/bin/sh -x
1806 cd OUTPUT_COLLECT_D
1807 # sync and flush journal before copying (if journald enabled)
1808 [ -e /var/log/journal ] && {
1809 journalctl --sync --flush --rotate
1810 cp -a /var/log/journal ./var-log-journal
1811 gzip -9 ./var-log-journal/*/system*.journal
1812 }
1813 exit 0;
1814 """)
1815 collect_scripts.append(collect_journal)
1816
1803 scripts = ([collect_prep] + [copy_rootdir] + collect_scripts +1817 scripts = ([collect_prep] + [copy_rootdir] + collect_scripts +
1804 [collect_post] + [failsafe_poweroff])1818 [collect_post] + [failsafe_poweroff])
18051819
diff --git a/tests/vmtests/test_lvm_raid.py b/tests/vmtests/test_lvm_raid.py
1806new file mode 1006441820new file mode 100644
index 0000000..0c50941
--- /dev/null
+++ b/tests/vmtests/test_lvm_raid.py
@@ -0,0 +1,50 @@
1# This file is part of curtin. See LICENSE file for copyright and license info.
2
3from .releases import base_vm_classes as relbase
4from .test_mdadm_bcache import TestMdadmAbs
5from .test_lvm import TestLvmAbs
6
7import textwrap
8
9
10class TestLvmOverRaidAbs(TestMdadmAbs, TestLvmAbs):
11 conf_file = "examples/tests/lvmoverraid.yaml"
12 active_mdadm = "2"
13 nr_cpus = 2
14 dirty_disks = True
15 extra_disks = ['10G'] * 4
16
17 collect_scripts = TestLvmAbs.collect_scripts
18 collect_scripts += TestMdadmAbs.collect_scripts + [textwrap.dedent("""
19 cd OUTPUT_COLLECT_D
20 ls -al /dev/md* > dev_md
21 cp -a /etc/mdadm etc_mdadm
22 cp -a /etc/lvm etc_lvm
23 """)]
24
25 fstab_expected = {
26 '/dev/vg1/lv1': '/srv/data',
27 '/dev/vg1/lv2': '/srv/backup',
28 }
29 disk_to_check = [('main_disk', 1),
30 ('md0', 0),
31 ('md1', 0)]
32
33 def test_lvs(self):
34 self.check_file_strippedline("lvs", "lv-0=vg0")
35
36 def test_pvs(self):
37 self.check_file_strippedline("pvs", "vg0=/dev/md0")
38 self.check_file_strippedline("pvs", "vg0=/dev/md1")
39
40
41class CosmicTestLvmOverRaid(relbase.cosmic, TestLvmOverRaidAbs):
42 __test__ = True
43
44
45class BionicTestLvmOverRaid(relbase.bionic, TestLvmOverRaidAbs):
46 __test__ = True
47
48
49class XenialGATestLvmOverRaid(relbase.xenial_ga, TestLvmOverRaidAbs):
50 __test__ = True
diff --git a/tests/vmtests/test_lvm_root.py b/tests/vmtests/test_lvm_root.py
index 8ca69d4..bc8b047 100644
--- a/tests/vmtests/test_lvm_root.py
+++ b/tests/vmtests/test_lvm_root.py
@@ -113,7 +113,7 @@ class XenialTestUefiLvmRootXfs(relbase.xenial, TestUefiLvmRootAbs):
113 }113 }
114114
115115
116@VMBaseClass.skip_by_date("1652822", fixby="2019-06-01")116@VMBaseClass.skip_by_date("1652822", fixby="2019-06-01", install=False)
117class XenialTestUefiLvmRootXfsBootXfs(relbase.xenial, TestUefiLvmRootAbs):117class XenialTestUefiLvmRootXfsBootXfs(relbase.xenial, TestUefiLvmRootAbs):
118 """This tests xfs root and xfs boot with uefi.118 """This tests xfs root and xfs boot with uefi.
119119

Subscribers

People subscribed via source and target branches