Merge ~raharper/curtin:feature/s390x-zkey into curtin:master

Proposed by Ryan Harper
Status: Merged
Approved by: Ryan Harper
Approved revision: 55a46eb11ff0bea6835390d14e867cd7b58cad82
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~raharper/curtin:feature/s390x-zkey
Merge into: curtin:master
Diff against target: 476 lines (+349/-17)
6 files modified
curtin/block/__init__.py (+50/-6)
curtin/commands/block_meta.py (+39/-9)
curtin/commands/curthooks.py (+29/-0)
tests/unittests/test_block.py (+33/-0)
tests/unittests/test_commands_block_meta.py (+174/-0)
tests/unittests/test_curthooks.py (+24/-2)
Reviewer Review Type Date Requested Status
Ryan Harper (community) Approve
Server Team CI bot continuous-integration Approve
Dimitri John Ledkov (community) ship it Approve
Chad Smith Approve
Review via email: mp+368802@code.launchpad.net

Commit message

block: Add opportunistic zkey encryption if supported

On s390x, systems with a crypto accelerator may be present
and enabled for sure. When handling a type: dm_crypt block
configuration, curtin will test if zkey is available and if
so, use the zkey command to generate keys and encrypt the
block device using zkey-based secrets.

In the case that zkey is not available, curtin will fallback
to using normal cryptsetup.

To post a comment you must log in.
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) :
Revision history for this message
Ryan Harper (raharper) wrote :

Thanks for the review, I'll update with changes.

~raharper/curtin:feature/s390x-zkey updated
534f51b... by Ryan Harper

zkey: add strict boolean to toggle log level in error paths.

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 :

LGTM!thanks for the clarification and fixups.

review: Approve
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

Only minor questions, and a typo to fix.

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

Thanks for the review, I'll fix it up.

~raharper/curtin:feature/s390x-zkey updated
7b4fd22... by Ryan Harper

fix typo in copy_zkey_repository log message.

5d5667b... by Ryan Harper

Only install s390-tools-zkey if zkey_used

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

hahahhahahahahhaha

worse typo ever

hahahhahahahahhaha

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

vmtest detects the modprobe failure and fails the install even though it went fine.
I need to refactor the logged message when strict=False so that it doesn't trip up
the failure parsing.

~raharper/curtin:feature/s390x-zkey updated
55a46eb... by Ryan Harper

Reword logged error when strict=False to not trip up vmtest error detection.

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 :

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

----------------------------------------------------------------------
Ran 112 tests in 2362.318s

OK
Fri, 21 Jun 2019 20:38:24 +0000: vmtest end [0] in 2365s

Looks good.

review: Approve

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 5d1b1bd..f30c5df 100644
--- a/curtin/block/__init__.py
+++ b/curtin/block/__init__.py
@@ -668,6 +668,24 @@ def get_proc_mounts():
668 return mounts668 return mounts
669669
670670
671def _get_dev_disk_by_prefix(prefix):
672 """
673 Construct a dictionary mapping devname to disk/<prefix> paths
674
675 :returns: Dictionary populated by examining /dev/disk/<prefix>/*
676
677 {
678 '/dev/sda': '/dev/disk/<prefix>/virtio-aaaa',
679 '/dev/sda1': '/dev/disk/<prefix>/virtio-aaaa-part1',
680 }
681 """
682 return {
683 os.path.realpath(bypfx): bypfx
684 for bypfx in [os.path.join(prefix, path)
685 for path in os.listdir(prefix)]
686 }
687
688
671def get_dev_disk_byid():689def get_dev_disk_byid():
672 """690 """
673 Construct a dictionary mapping devname to disk/by-id paths691 Construct a dictionary mapping devname to disk/by-id paths
@@ -679,12 +697,7 @@ def get_dev_disk_byid():
679 '/dev/sda1': '/dev/disk/by-id/virtio-aaaa-part1',697 '/dev/sda1': '/dev/disk/by-id/virtio-aaaa-part1',
680 }698 }
681 """699 """
682700 return _get_dev_disk_by_prefix('/dev/disk/by-id')
683 prefix = '/dev/disk/by-id'
684 return {
685 os.path.realpath(byid): byid
686 for byid in [os.path.join(prefix, path) for path in os.listdir(prefix)]
687 }
688701
689702
690def disk_to_byid_path(kname):703def disk_to_byid_path(kname):
@@ -696,6 +709,15 @@ def disk_to_byid_path(kname):
696 return mapping.get(dev_path(kname))709 return mapping.get(dev_path(kname))
697710
698711
712def disk_to_bypath_path(kname):
713 """"
714 Return a /dev/disk/by-path path to kname if present.
715 """
716
717 mapping = _get_dev_disk_by_prefix('/dev/disk/by-path')
718 return mapping.get(dev_path(kname))
719
720
699def get_device_mapper_links(devpath, first=False):721def get_device_mapper_links(devpath, first=False):
700 """ Return the best devlink to device at devpath. """722 """ Return the best devlink to device at devpath. """
701 info = udevadm_info(devpath)723 info = udevadm_info(devpath)
@@ -892,6 +914,28 @@ def is_online(device):
892 return int(device_size) > 0914 return int(device_size) > 0
893915
894916
917def zkey_supported(strict=True):
918 """ Return True if zkey cmd present and can generate keys, else False."""
919 LOG.debug('Checking if zkey encryption is supported...')
920 try:
921 util.load_kernel_module('pkey')
922 except util.ProcessExecutionError as err:
923 msg = "Failed to load 'pkey' kernel module"
924 LOG.error(msg + ": %s" % err) if strict else LOG.warning(msg)
925 return False
926
927 try:
928 with tempfile.NamedTemporaryFile() as tf:
929 util.subp(['zkey', 'generate', tf.name], capture=True)
930 LOG.debug('zkey encryption supported.')
931 return True
932 except util.ProcessExecutionError as err:
933 msg = "zkey not supported"
934 LOG.error(msg + ": %s" % err) if strict else LOG.warning(msg)
935
936 return False
937
938
895@contextmanager939@contextmanager
896def exclusive_open(path, exclusive=True):940def exclusive_open(path, exclusive=True):
897 """941 """
diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
index 79493fc..a9110a9 100644
--- a/curtin/commands/block_meta.py
+++ b/curtin/commands/block_meta.py
@@ -1062,6 +1062,7 @@ def dm_crypt_handler(info, storage_config):
1062 dm_name = info.get('id')1062 dm_name = info.get('id')
10631063
1064 volume_path = get_path_to_storage_volume(volume, storage_config)1064 volume_path = get_path_to_storage_volume(volume, storage_config)
1065 volume_byid_path = block.disk_to_byid_path(volume_path)
10651066
1066 if 'keyfile' in info:1067 if 'keyfile' in info:
1067 if 'key' in info:1068 if 'key' in info:
@@ -1077,16 +1078,45 @@ def dm_crypt_handler(info, storage_config):
1077 else:1078 else:
1078 raise ValueError("encryption key or keyfile must be specified")1079 raise ValueError("encryption key or keyfile must be specified")
10791080
1080 cmd = ["cryptsetup"]1081 # if zkey is available, attempt to generate and use it; if it's not
1081 if cipher:1082 # available or fails to setup properly, fallback to normal cryptsetup
1082 cmd.extend(["--cipher", cipher])1083 # passing strict=False downgrades log messages to warnings
1083 if keysize:1084 zkey_used = None
1084 cmd.extend(["--key-size", keysize])1085 if block.zkey_supported(strict=False):
1085 cmd.extend(["luksFormat", volume_path, keyfile])1086 volume_name = "%s:%s" % (volume_byid_path, dm_name)
10861087 LOG.debug('Attempting to setup zkey for %s', volume_name)
1087 util.subp(cmd)1088 luks_type = 'luks2'
1089 gen_cmd = ['zkey', 'generate', '--xts', '--volume-type', luks_type,
1090 '--sector-size', '4096', '--name', dm_name,
1091 '--description',
1092 "curtin generated zkey for %s" % volume_name,
1093 '--volumes', volume_name]
1094 run_cmd = ['zkey', 'cryptsetup', '--run', '--volumes',
1095 volume_byid_path, '--batch-mode', '--key-file', keyfile]
1096 try:
1097 util.subp(gen_cmd, capture=True)
1098 util.subp(run_cmd, capture=True)
1099 zkey_used = os.path.join(os.path.split(state['fstab'])[0],
1100 "zkey_used")
1101 # mark in state that we used zkey
1102 util.write_file(zkey_used, "1")
1103 except util.ProcessExecutionError as e:
1104 LOG.exception(e)
1105 msg = 'Setup of zkey on %s failed, fallback to cryptsetup.'
1106 LOG.error(msg % volume_path)
1107
1108 if not zkey_used:
1109 LOG.debug('Using cryptsetup on %s', volume_path)
1110 luks_type = "luks"
1111 cmd = ["cryptsetup"]
1112 if cipher:
1113 cmd.extend(["--cipher", cipher])
1114 if keysize:
1115 cmd.extend(["--key-size", keysize])
1116 cmd.extend(["luksFormat", volume_path, keyfile])
1117 util.subp(cmd)
10881118
1089 cmd = ["cryptsetup", "open", "--type", "luks", volume_path, dm_name,1119 cmd = ["cryptsetup", "open", "--type", luks_type, volume_path, dm_name,
1090 "--key-file", keyfile]1120 "--key-file", keyfile]
10911121
1092 util.subp(cmd)1122 util.subp(cmd)
diff --git a/curtin/commands/curthooks.py b/curtin/commands/curthooks.py
index 75f5083..2869c6c 100644
--- a/curtin/commands/curthooks.py
+++ b/curtin/commands/curthooks.py
@@ -594,6 +594,28 @@ def copy_zpool_cache(zpool_cache, target):
594 shutil.copy(zpool_cache, os.path.sep.join([target, 'etc/zfs']))594 shutil.copy(zpool_cache, os.path.sep.join([target, 'etc/zfs']))
595595
596596
597def copy_zkey_repository(zkey_repository, target,
598 target_repo='etc/zkey/repository'):
599 if not zkey_repository:
600 LOG.warn("zkey repository path must be specified, not copying")
601 return
602
603 tdir = os.path.sep.join([target, target_repo])
604 if not os.path.exists(tdir):
605 util.ensure_dir(tdir)
606
607 files_copied = []
608 for src in os.listdir(zkey_repository):
609 source_path = os.path.join(zkey_repository, src)
610 target_path = os.path.join(tdir, src)
611 if not os.path.exists(target_path):
612 shutil.copy2(source_path, target_path)
613 files_copied.append(target_path)
614
615 LOG.debug('Imported zkey repo %s with files: %s',
616 zkey_repository, files_copied)
617
618
597def apply_networking(target, state):619def apply_networking(target, state):
598 netconf = state.get('network_config')620 netconf = state.get('network_config')
599 interfaces = state.get('interfaces')621 interfaces = state.get('interfaces')
@@ -1379,6 +1401,13 @@ def builtin_curthooks(cfg, target, state):
1379 if os.path.exists(zpool_cache):1401 if os.path.exists(zpool_cache):
1380 copy_zpool_cache(zpool_cache, target)1402 copy_zpool_cache(zpool_cache, target)
13811403
1404 zkey_repository = '/etc/zkey/repository'
1405 zkey_used = os.path.join(os.path.split(state['fstab'])[0], "zkey_used")
1406 if all(map(os.path.exists, [zkey_repository, zkey_used])):
1407 distro.install_packages(['s390-tools-zkey'], target=target,
1408 osfamily=osfamily)
1409 copy_zkey_repository(zkey_repository, target)
1410
1382 # If a crypttab file was created by block_meta than it needs to be1411 # If a crypttab file was created by block_meta than it needs to be
1383 # copied onto the target system, and update_initramfs() needs to be1412 # copied onto the target system, and update_initramfs() needs to be
1384 # run, so that the cryptsetup hooks are properly configured on the1413 # run, so that the cryptsetup hooks are properly configured on the
diff --git a/tests/unittests/test_block.py b/tests/unittests/test_block.py
index c7ebdcc..167a697 100644
--- a/tests/unittests/test_block.py
+++ b/tests/unittests/test_block.py
@@ -712,4 +712,37 @@ class TestGetSupportedFilesystems(CiTestCase):
712 self.assertEqual(0, mock_util.load_file.call_count)712 self.assertEqual(0, mock_util.load_file.call_count)
713713
714714
715class TestZkeySupported(CiTestCase):
716
717 @mock.patch('curtin.block.util')
718 def test_zkey_supported_loads_module(self, m_util):
719 block.zkey_supported()
720 m_util.load_kernel_module.assert_called_with('pkey')
721
722 @mock.patch('curtin.block.util.load_kernel_module')
723 def test_zkey_supported_returns_false_missing_kmod(self, m_kmod):
724 m_kmod.side_effect = (
725 util.ProcessExecutionError(stdout=self.random_string(),
726 stderr=self.random_string(),
727 exit_code=2))
728 self.assertFalse(block.zkey_supported())
729
730 @mock.patch('curtin.block.util.subp')
731 @mock.patch('curtin.block.util.load_kernel_module')
732 def test_zkey_supported_returns_false_zkey_error(self, m_kmod, m_subp):
733 m_subp.side_effect = (
734 util.ProcessExecutionError(stdout=self.random_string(),
735 stderr=self.random_string(),
736 exit_code=2))
737 self.assertFalse(block.zkey_supported())
738
739 @mock.patch('curtin.block.tempfile.NamedTemporaryFile')
740 @mock.patch('curtin.block.util')
741 def test_zkey_supported_calls_zkey_generate(self, m_util, m_temp):
742 testname = self.random_string()
743 m_temp.return_value.__enter__.return_value.name = testname
744 block.zkey_supported()
745 m_util.subp.assert_called_with(['zkey', 'generate', testname],
746 capture=True)
747
715# vi: ts=4 expandtab syntax=python748# vi: ts=4 expandtab syntax=python
diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py
index b4a9afa..b2e151e 100644
--- a/tests/unittests/test_commands_block_meta.py
+++ b/tests/unittests/test_commands_block_meta.py
@@ -913,4 +913,178 @@ class TestLvmPartitionHandler(CiTestCase):
913 self.assertIn(expected_size_str, call_args[0])913 self.assertIn(expected_size_str, call_args[0])
914914
915915
916class TestDmCryptHandler(CiTestCase):
917
918 def setUp(self):
919 super(TestDmCryptHandler, self).setUp()
920
921 basepath = 'curtin.commands.block_meta.'
922 self.add_patch(basepath + 'get_path_to_storage_volume', 'm_getpath')
923 self.add_patch(basepath + 'util.load_command_environment',
924 'm_load_env')
925 self.add_patch(basepath + 'util.which', 'm_which')
926 self.add_patch(basepath + 'util.subp', 'm_subp')
927 self.add_patch(basepath + 'block', 'm_block')
928
929 self.target = "my_target"
930 self.keyfile = self.random_string()
931 self.cipher = self.random_string()
932 self.keysize = self.random_string()
933 self.config = {
934 'storage': {
935 'version': 1,
936 'config': [
937 {'grub_device': True,
938 'id': 'sda',
939 'name': 'sda',
940 'path': '/wark/xxx',
941 'ptable': 'msdos',
942 'type': 'disk',
943 'wipe': 'superblock'},
944 {'device': 'sda',
945 'id': 'sda-part1',
946 'name': 'sda-part1',
947 'number': 1,
948 'size': '511705088B',
949 'type': 'partition'},
950 {'id': 'dmcrypt0',
951 'type': 'dm_crypt',
952 'dm_name': 'cryptroot',
953 'volume': 'sda-part1',
954 'cipher': self.cipher,
955 'keysize': self.keysize,
956 'keyfile': self.keyfile},
957 ],
958 }
959 }
960 self.storage_config = (
961 block_meta.extract_storage_ordered_dict(self.config))
962 self.m_block.zkey_supported.return_value = False
963 self.m_which.return_value = False
964 self.fstab = self.tmp_path('fstab')
965 self.crypttab = os.path.join(os.path.dirname(self.fstab), 'crypttab')
966 self.m_load_env.return_value = {'fstab': self.fstab,
967 'target': self.target}
968
969 def test_dm_crypt_calls_cryptsetup(self):
970 """ verify dm_crypt calls (format, open) w/ correct params"""
971 volume_path = self.random_string()
972 self.m_getpath.return_value = volume_path
973
974 info = self.storage_config['dmcrypt0']
975 block_meta.dm_crypt_handler(info, self.storage_config)
976 expected_calls = [
977 call(['cryptsetup', '--cipher', self.cipher,
978 '--key-size', self.keysize,
979 'luksFormat', volume_path, self.keyfile]),
980 call(['cryptsetup', 'open', '--type', 'luks', volume_path,
981 info['dm_name'], '--key-file', self.keyfile])
982 ]
983 self.m_subp.assert_has_calls(expected_calls)
984 self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
985
986 def test_dm_crypt_zkey_cryptsetup(self):
987 """ verify dm_crypt zkey calls generates and run before crypt open."""
988
989 # zkey binary is present
990 self.m_block.zkey_supported.return_value = True
991 self.m_which.return_value = "/my/path/to/zkey"
992 volume_path = self.random_string()
993 self.m_getpath.return_value = volume_path
994 volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path
995 self.m_block.disk_to_byid_path.return_value = volume_byid
996
997 info = self.storage_config['dmcrypt0']
998 volume_name = "%s:%s" % (volume_byid, info['dm_name'])
999 block_meta.dm_crypt_handler(info, self.storage_config)
1000 expected_calls = [
1001 call(['zkey', 'generate', '--xts', '--volume-type', 'luks2',
1002 '--sector-size', '4096', '--name', info['dm_name'],
1003 '--description',
1004 'curtin generated zkey for %s' % volume_name,
1005 '--volumes', volume_name], capture=True),
1006 call(['zkey', 'cryptsetup', '--run', '--volumes', volume_byid,
1007 '--batch-mode', '--key-file', self.keyfile], capture=True),
1008 call(['cryptsetup', 'open', '--type', 'luks2', volume_path,
1009 info['dm_name'], '--key-file', self.keyfile]),
1010 ]
1011 self.m_subp.assert_has_calls(expected_calls)
1012 self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
1013
1014 def test_dm_crypt_zkey_gen_failure_fallback_to_cryptsetup(self):
1015 """ verify dm_cyrpt zkey generate err falls back cryptsetup format. """
1016
1017 # zkey binary is present
1018 self.m_block.zkey_supported.return_value = True
1019 self.m_which.return_value = "/my/path/to/zkey"
1020
1021 self.m_subp.side_effect = iter([
1022 util.ProcessExecutionError("foobar"), # zkey generate
1023 (0, 0), # cryptsetup luksFormat
1024 (0, 0), # cryptsetup open
1025 ])
1026
1027 volume_path = self.random_string()
1028 self.m_getpath.return_value = volume_path
1029 volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path
1030 self.m_block.disk_to_byid_path.return_value = volume_byid
1031
1032 info = self.storage_config['dmcrypt0']
1033 volume_name = "%s:%s" % (volume_byid, info['dm_name'])
1034 block_meta.dm_crypt_handler(info, self.storage_config)
1035 expected_calls = [
1036 call(['zkey', 'generate', '--xts', '--volume-type', 'luks2',
1037 '--sector-size', '4096', '--name', info['dm_name'],
1038 '--description',
1039 'curtin generated zkey for %s' % volume_name,
1040 '--volumes', volume_name], capture=True),
1041 call(['cryptsetup', '--cipher', self.cipher,
1042 '--key-size', self.keysize,
1043 'luksFormat', volume_path, self.keyfile]),
1044 call(['cryptsetup', 'open', '--type', 'luks', volume_path,
1045 info['dm_name'], '--key-file', self.keyfile])
1046 ]
1047 self.m_subp.assert_has_calls(expected_calls)
1048 self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
1049
1050 def test_dm_crypt_zkey_run_failure_fallback_to_cryptsetup(self):
1051 """ verify dm_cyrpt zkey run err falls back on cryptsetup format. """
1052
1053 # zkey binary is present
1054 self.m_block.zkey_supported.return_value = True
1055 self.m_which.return_value = "/my/path/to/zkey"
1056
1057 self.m_subp.side_effect = iter([
1058 (0, 0), # zkey generate
1059 util.ProcessExecutionError("foobar"), # zkey cryptsetup --run
1060 (0, 0), # cryptsetup luksFormat
1061 (0, 0), # cryptsetup open
1062 ])
1063
1064 volume_path = self.random_string()
1065 self.m_getpath.return_value = volume_path
1066 volume_byid = "/dev/disk/by-id/ccw-%s" % volume_path
1067 self.m_block.disk_to_byid_path.return_value = volume_byid
1068
1069 info = self.storage_config['dmcrypt0']
1070 volume_name = "%s:%s" % (volume_byid, info['dm_name'])
1071 block_meta.dm_crypt_handler(info, self.storage_config)
1072 expected_calls = [
1073 call(['zkey', 'generate', '--xts', '--volume-type', 'luks2',
1074 '--sector-size', '4096', '--name', info['dm_name'],
1075 '--description',
1076 'curtin generated zkey for %s' % volume_name,
1077 '--volumes', volume_name], capture=True),
1078 call(['zkey', 'cryptsetup', '--run', '--volumes', volume_byid,
1079 '--batch-mode', '--key-file', self.keyfile], capture=True),
1080 call(['cryptsetup', '--cipher', self.cipher,
1081 '--key-size', self.keysize,
1082 'luksFormat', volume_path, self.keyfile]),
1083 call(['cryptsetup', 'open', '--type', 'luks', volume_path,
1084 info['dm_name'], '--key-file', self.keyfile])
1085 ]
1086 self.m_subp.assert_has_calls(expected_calls)
1087 self.assertEqual(len(util.load_file(self.crypttab).splitlines()), 1)
1088
1089
916# vi: ts=4 expandtab syntax=python1090# vi: ts=4 expandtab syntax=python
diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py
index 26a582c..e7d506e 100644
--- a/tests/unittests/test_curthooks.py
+++ b/tests/unittests/test_curthooks.py
@@ -9,7 +9,7 @@ from curtin import distro
9from curtin import util9from curtin import util
10from curtin import config10from curtin import config
11from curtin.reporter import events11from curtin.reporter import events
12from .helpers import CiTestCase, dir2dict12from .helpers import CiTestCase, dir2dict, populate_dir
1313
1414
15class TestGetFlashKernelPkgs(CiTestCase):15class TestGetFlashKernelPkgs(CiTestCase):
@@ -201,7 +201,8 @@ class TestInstallMissingPkgs(CiTestCase):
201 cfg = {}201 cfg = {}
202 curthooks.install_missing_packages(cfg, target=target)202 curthooks.install_missing_packages(cfg, target=target)
203 self.mock_install_packages.assert_called_with(203 self.mock_install_packages.assert_called_with(
204 ['s390-tools'], target=target, osfamily=self.distro_family)204 ['s390-tools'], target=target,
205 osfamily=self.distro_family)
205206
206 @patch.object(events, 'ReportEventStack')207 @patch.object(events, 'ReportEventStack')
207 def test_install_packages_s390x_has_zipl(self, mock_events):208 def test_install_packages_s390x_has_zipl(self, mock_events):
@@ -1140,4 +1141,25 @@ class TestCurthooksChzdev(CiTestCase):
1140 output = curthooks.chzdev_prepare_for_import(self.chzdev_export)1141 output = curthooks.chzdev_prepare_for_import(self.chzdev_export)
1141 self.assertEqual(self.chzdev_import, output)1142 self.assertEqual(self.chzdev_import, output)
11421143
1144
1145class TestCurthooksCopyZkey(CiTestCase):
1146 def setUp(self):
1147 super(TestCurthooksCopyZkey, self).setUp()
1148 self.add_patch('curtin.distro.install_packages', 'mock_instpkg')
1149
1150 self.target = self.tmp_dir()
1151 self.host_dir = self.tmp_dir()
1152 self.zkey_content = {
1153 '/etc/zkey/repository/mykey.info': "key info",
1154 '/etc/zkey/repository/mykey.skey': "key data",
1155 }
1156 self.files = populate_dir(self.host_dir, self.zkey_content)
1157 self.host_zkey = os.path.join(self.host_dir, 'etc/zkey/repository')
1158
1159 def test_copy_zkey_when_dir_present(self):
1160 curthooks.copy_zkey_repository(self.host_zkey, self.target)
1161 found_files = dir2dict(self.target, prefix=self.target)
1162 self.assertEqual(self.zkey_content, found_files)
1163
1164
1143# vi: ts=4 expandtab syntax=python1165# vi: ts=4 expandtab syntax=python

Subscribers

People subscribed via source and target branches