Merge ~alexsander-souza/curtin:sles_support into curtin:master
- Git
- lp:~alexsander-souza/curtin
- sles_support
- Merge into master
Status: | Merged |
---|---|
Approved by: | Dan Bungert |
Approved revision: | 1ab056d8a72ec86bc91726585b7a9d7e25454255 |
Merge reported by: | Server Team CI bot |
Merged at revision: | not available |
Proposed branch: | ~alexsander-souza/curtin:sles_support |
Merge into: | curtin:master |
Diff against target: |
488 lines (+303/-5) 8 files modified
curtin/block/deps.py (+19/-0) curtin/commands/curthooks.py (+17/-2) curtin/commands/install_grub.py (+20/-1) curtin/distro.py (+30/-2) curtin/net/deps.py (+8/-0) tests/unittests/test_commands_install_grub.py (+115/-0) tests/unittests/test_curthooks.py (+16/-0) tests/unittests/test_distro.py (+78/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Dan Bungert | Approve | ||
Michael Hudson-Doyle | Approve | ||
Review via email: mp+435914@code.launchpad.net |
Commit message
add SLES support
Description of the change
Dan Bungert (dbungert) wrote : | # |
Yes, mostly I'm wishing we had a better testing answer.
This is fine, I won't hold it up longer. Thank you Alexsander.
Server Team CI bot (server-team-bot) wrote : | # |
Autolanding: FAILED
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Dan Bungert (dbungert) wrote : | # |
Rebasing this branch, we just landed something else and the merge tool likes clean rebased branches only.
Dan Bungert (dbungert) wrote : | # |
oh right, I'm thinking of github functionality.
Alexsander, if you rebase to master and push, I will get it merged ASAP.
Server Team CI bot (server-team-bot) wrote : | # |
Autolanding: FAILED
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Server Team CI bot (server-team-bot) wrote : | # |
Autolanding: FAILED
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Server Team CI bot (server-team-bot) wrote : | # |
Autolanding: FAILED
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Dan Bungert (dbungert) wrote : | # |
moved back to needs review to stop the bot from running the merge in a loop
Server Team CI bot (server-team-bot) wrote : | # |
Autolanding: FAILED
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Alexsander de Souza (alexsander-souza) wrote : | # |
rebased
Server Team CI bot (server-team-bot) : | # |
Preview Diff
1 | diff --git a/curtin/block/deps.py b/curtin/block/deps.py |
2 | index 5cb23e0..ec5fe83 100644 |
3 | --- a/curtin/block/deps.py |
4 | +++ b/curtin/block/deps.py |
5 | @@ -94,6 +94,25 @@ def detect_required_packages_mapping(osfamily=DISTROS.debian): |
6 | 'zfs': [], |
7 | 'zpool': [], |
8 | }, |
9 | + DISTROS.suse: { |
10 | + 'bcache': ['bcache-tools'], |
11 | + 'btrfs': ['btrfsprogs'], |
12 | + 'dm_crypt': ['cryptsetup'], |
13 | + 'ext2': ['e2fsprogs'], |
14 | + 'ext3': ['e2fsprogs'], |
15 | + 'ext4': ['e2fsprogs'], |
16 | + 'jfs': ['jfsutils'], |
17 | + 'iscsi': [], |
18 | + 'lvm_partition': ['lvm2'], |
19 | + 'lvm_volgroup': ['lvm2'], |
20 | + 'ntfs': [], |
21 | + 'raid': ['mdadm'], |
22 | + 'reiserfs': [], |
23 | + 'xfs': ['xfsprogs'], |
24 | + 'zfsroot': [], |
25 | + 'zfs': [], |
26 | + 'zpool': [], |
27 | + }, |
28 | } |
29 | if osfamily not in distro_mapping: |
30 | raise ValueError('No block package mapping for distro: %s' % osfamily) |
31 | diff --git a/curtin/commands/curthooks.py b/curtin/commands/curthooks.py |
32 | index 03a53b1..69833a2 100644 |
33 | --- a/curtin/commands/curthooks.py |
34 | +++ b/curtin/commands/curthooks.py |
35 | @@ -1038,6 +1038,7 @@ def detect_and_handle_multipath(cfg, target, osfamily=DISTROS.debian): |
36 | DEFAULT_MULTIPATH_PACKAGES = { |
37 | DISTROS.debian: ['multipath-tools-boot'], |
38 | DISTROS.redhat: ['device-mapper-multipath'], |
39 | + DISTROS.suse: ['multipath-tools'], |
40 | } |
41 | if osfamily not in DEFAULT_MULTIPATH_PACKAGES: |
42 | raise ValueError( |
43 | @@ -1154,7 +1155,7 @@ def detect_and_handle_multipath(cfg, target, osfamily=DISTROS.debian): |
44 | grub_cfg = os.path.sep.join( |
45 | [target, '/etc/default/grub.d/50-curtin-multipath.cfg']) |
46 | omode = 'w' |
47 | - elif osfamily == DISTROS.redhat: |
48 | + elif osfamily in [DISTROS.redhat, DISTROS.suse]: |
49 | grub_cfg = os.path.sep.join([target, '/etc/default/grub']) |
50 | omode = 'a' |
51 | else: |
52 | @@ -1199,7 +1200,7 @@ def detect_and_handle_multipath(cfg, target, osfamily=DISTROS.debian): |
53 | # Initrams needs to be updated to include /etc/multipath.cfg |
54 | # and /etc/multipath/bindings files. |
55 | update_initramfs(target, all_kernels=True) |
56 | - elif osfamily == DISTROS.redhat: |
57 | + elif osfamily in [DISTROS.redhat, DISTROS.suse]: |
58 | # Write out initramfs/dracut config for multipath |
59 | dracut_conf_multipath = os.path.sep.join( |
60 | [target, '/etc/dracut.conf.d/10-curtin-multipath.conf']) |
61 | @@ -1308,6 +1309,12 @@ def install_missing_packages(cfg, target, osfamily=DISTROS.debian): |
62 | # SecureBoot support |
63 | if distro.has_pkg_available("shim-signed"): |
64 | uefi_pkgs.append("shim-signed") |
65 | + elif osfamily == DISTROS.suse: |
66 | + uefi_pkgs.extend(['grub2', 'grub2-branding-SLE']) |
67 | + arch = distro.get_architecture() |
68 | + if arch == 'amd64': |
69 | + arch = 'x86_64' |
70 | + uefi_pkgs.append('grub2-%s-efi' % arch) |
71 | else: |
72 | raise ValueError('Unknown grub2 package list for distro: %s' % |
73 | osfamily) |
74 | @@ -1753,6 +1760,14 @@ def builtin_curthooks(cfg, target, state): |
75 | description="setting up swap"): |
76 | add_swap(cfg, target, state.get('fstab')) |
77 | |
78 | + if osfamily == DISTROS.suse: |
79 | + # set cloud-init maas datasource for SuSE images |
80 | + if cfg.get('cloudconfig'): |
81 | + handle_cloudconfig( |
82 | + cfg['cloudconfig'], |
83 | + base_dir=paths.target_path(target, |
84 | + 'etc/cloud/cloud.cfg.d')) |
85 | + |
86 | if osfamily == DISTROS.redhat: |
87 | # set cloud-init maas datasource for centos images |
88 | if cfg.get('cloudconfig'): |
89 | diff --git a/curtin/commands/install_grub.py b/curtin/commands/install_grub.py |
90 | index 79b6695..38bf71a 100644 |
91 | --- a/curtin/commands/install_grub.py |
92 | +++ b/curtin/commands/install_grub.py |
93 | @@ -250,7 +250,7 @@ def get_grub_install_command(uefi, distroinfo, target): |
94 | # prefer grub-multi-install if present |
95 | if uefi and os.path.exists(target_path(target, GRUB_MULTI_INSTALL)): |
96 | grub_install_cmd = GRUB_MULTI_INSTALL |
97 | - elif distroinfo.family == distro.DISTROS.redhat: |
98 | + elif distroinfo.family in [distro.DISTROS.redhat, distro.DISTROS.suse]: |
99 | grub_install_cmd = 'grub2-install' |
100 | |
101 | LOG.debug('Using grub install command: %s', grub_install_cmd) |
102 | @@ -289,6 +289,23 @@ def gen_uefi_install_commands(grub_name, grub_target, grub_cmd, update_nvram, |
103 | '/boot/efi/EFI/%s/grub.cfg' % bootid]) |
104 | else: |
105 | post_cmds.append(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']) |
106 | + elif distroinfo.family == distro.DISTROS.suse: |
107 | + bootid = 'suse' |
108 | + grub_cfg = '/boot/grub2/grub.cfg' |
109 | + loader = find_efi_loader(target, bootid) |
110 | + if loader: |
111 | + grub_cmd = None |
112 | + grub_cfg = '/boot/efi/EFI/%s/grub.cfg' % bootid |
113 | + if update_nvram: |
114 | + efi_disk, efi_part_num = get_efi_disk_part(devices) |
115 | + # Add entry to the EFI boot menu |
116 | + install_cmds.append(['efibootmgr', '--create', |
117 | + '--write-signature', '--label', bootid, |
118 | + '--disk', efi_disk, |
119 | + '--part', efi_part_num, |
120 | + '--loader', |
121 | + efi_loader_esp_path(loader)]) |
122 | + post_cmds.append(['grub2-mkconfig', '-o', grub_cfg]) |
123 | else: |
124 | raise ValueError("Unsupported os family for grub " |
125 | "install: %s" % distroinfo.family) |
126 | @@ -315,6 +332,8 @@ def gen_install_commands(grub_name, grub_cmd, distroinfo, devices, |
127 | if distroinfo.family == distro.DISTROS.debian: |
128 | install_cmds.append(['dpkg-reconfigure', grub_name]) |
129 | install_cmds.append(['update-grub']) |
130 | + elif distroinfo.family == distro.DISTROS.suse: |
131 | + post_cmds.append(['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg']) |
132 | elif distroinfo.family == distro.DISTROS.redhat: |
133 | if rhel_ver in ["7", "8", "9"]: |
134 | post_cmds.append( |
135 | diff --git a/curtin/distro.py b/curtin/distro.py |
136 | index 618af47..4266278 100644 |
137 | --- a/curtin/distro.py |
138 | +++ b/curtin/distro.py |
139 | @@ -379,6 +379,26 @@ def rpm_get_dist_id(target=None): |
140 | return dist.rstrip() |
141 | |
142 | |
143 | +def run_zypper_command(mode, args=None, opts=None, env=None, target=None, |
144 | + execute=True, allow_daemons=False): |
145 | + defopts = ['--non-interactive', '--non-interactive-include-reboot-patches', |
146 | + '--quiet'] |
147 | + |
148 | + if args is None: |
149 | + args = [] |
150 | + |
151 | + if opts is None: |
152 | + opts = [] |
153 | + |
154 | + cmd = ['zypper'] |
155 | + cmd += defopts + opts + [mode] + args |
156 | + if not execute: |
157 | + return env, cmd |
158 | + |
159 | + with ChrootableTarget(target, allow_daemons=allow_daemons) as inchroot: |
160 | + return inchroot.subp(cmd, env=env) |
161 | + |
162 | + |
163 | def system_upgrade(opts=None, target=None, env=None, allow_daemons=False, |
164 | osfamily=None): |
165 | LOG.debug("Upgrading system in %s", target) |
166 | @@ -391,6 +411,8 @@ def system_upgrade(opts=None, target=None, env=None, allow_daemons=False, |
167 | 'subcommands': ('dist-upgrade', 'autoremove')}, |
168 | DISTROS.redhat: {'function': run_yum_command, |
169 | 'subcommands': ('upgrade',)}, |
170 | + DISTROS.suse: {'function': run_zypper_command, |
171 | + 'subcommands': ('refresh', 'update', 'purge-kernels',)}, |
172 | } |
173 | if osfamily not in distro_cfg: |
174 | raise ValueError('Distro "%s" does not have system_upgrade support', |
175 | @@ -414,6 +436,7 @@ def install_packages(pkglist, osfamily=None, opts=None, target=None, env=None, |
176 | installer_map = { |
177 | DISTROS.debian: run_apt_command, |
178 | DISTROS.redhat: run_yum_command, |
179 | + DISTROS.suse: run_zypper_command, |
180 | } |
181 | |
182 | install_cmd = installer_map.get(osfamily) |
183 | @@ -429,10 +452,15 @@ def has_pkg_available(pkg, target=None, osfamily=None): |
184 | if not osfamily: |
185 | osfamily = get_osfamily(target=target) |
186 | |
187 | - if osfamily not in [DISTROS.debian, DISTROS.redhat]: |
188 | + if osfamily not in [DISTROS.debian, DISTROS.redhat, DISTROS.suse]: |
189 | raise ValueError('has_pkg_available: unsupported distro family: %s', |
190 | osfamily) |
191 | |
192 | + if osfamily == DISTROS.suse: |
193 | + out, _ = subp(['zypper', '--quiet', 'search', |
194 | + '--match-exact', pkg], capture=True, target=target) |
195 | + return 'No matching items found.' not in out |
196 | + |
197 | if osfamily == DISTROS.debian: |
198 | out, _ = subp(['apt-cache', 'pkgnames'], capture=True, target=target) |
199 | for item in out.splitlines(): |
200 | @@ -603,7 +631,7 @@ def get_architecture(target=None, osfamily=None): |
201 | if osfamily == DISTROS.debian: |
202 | return dpkg_get_architecture(target=target) |
203 | |
204 | - if osfamily == DISTROS.redhat: |
205 | + if osfamily in [DISTROS.redhat, DISTROS.suse]: |
206 | return rpm_get_architecture(target=target) |
207 | |
208 | raise ValueError("Unhandled osfamily=%s" % osfamily) |
209 | diff --git a/curtin/net/deps.py b/curtin/net/deps.py |
210 | index b78654d..e019a9e 100644 |
211 | --- a/curtin/net/deps.py |
212 | +++ b/curtin/net/deps.py |
213 | @@ -75,6 +75,14 @@ def detect_required_packages_mapping(osfamily=DISTROS.debian): |
214 | 'openvswitch': ['openvswitch-switch'], |
215 | 'vlan': [], |
216 | 'vlans': []}, |
217 | + DISTROS.suse: { |
218 | + 'bond': [], |
219 | + 'bonds': [], |
220 | + 'bridge': ['bridge-utils'], |
221 | + 'bridges': ['bridge-utils'], |
222 | + 'openvswitch': ['openvswitch-switch'], |
223 | + 'vlan': ['vlan'], |
224 | + 'vlans': ['vlan']}, |
225 | } |
226 | if osfamily not in distro_mapping: |
227 | raise ValueError('No net package mapping for distro: %s' % osfamily) |
228 | diff --git a/tests/unittests/test_commands_install_grub.py b/tests/unittests/test_commands_install_grub.py |
229 | index 24f9476..ab52505 100644 |
230 | --- a/tests/unittests/test_commands_install_grub.py |
231 | +++ b/tests/unittests/test_commands_install_grub.py |
232 | @@ -830,6 +830,121 @@ class TestGenUefiInstallCommands(CiTestCase): |
233 | grub_name, grub_target, grub_cmd, update_nvram, distroinfo, |
234 | devices, self.target)) |
235 | |
236 | + def test_suse_install(self): |
237 | + self.m_os_release.return_value = {'ID': 'suse'} |
238 | + distroinfo = install_grub.distro.get_distroinfo() |
239 | + grub_name = 'grub2-efi-x64' |
240 | + grub_target = 'x86_64-efi' |
241 | + grub_cmd = 'grub2-install' |
242 | + update_nvram = True |
243 | + devices = ['/dev/disk-a-part1'] |
244 | + disk = '/dev/disk-a' |
245 | + part = '1' |
246 | + self.m_get_disk_part.return_value = (disk, part) |
247 | + |
248 | + expected_install = [ |
249 | + ['efibootmgr', '-v'], |
250 | + [grub_cmd, '--target=%s' % grub_target, |
251 | + '--efi-directory=/boot/efi', |
252 | + '--bootloader-id=suse', '--recheck'], |
253 | + ] |
254 | + expected_post = [ |
255 | + ['grub2-mkconfig', '-o', '/boot/grub2/grub.cfg'], |
256 | + ['efibootmgr', '-v'] |
257 | + ] |
258 | + self.assertEqual( |
259 | + (expected_install, expected_post), |
260 | + install_grub.gen_uefi_install_commands( |
261 | + grub_name, grub_target, grub_cmd, update_nvram, distroinfo, |
262 | + devices, self.target)) |
263 | + |
264 | + def test_suse_install_existing(self): |
265 | + # simulate existing bootloaders already installed in target system |
266 | + # by touching the files grub would have installed, including shim |
267 | + def _enable_loaders(bootid): |
268 | + efi_path = 'boot/efi/EFI' |
269 | + target_efi_path = os.path.join(self.target, efi_path) |
270 | + loaders = [ |
271 | + os.path.join(target_efi_path, bootid, 'shimx64.efi'), |
272 | + os.path.join(target_efi_path, 'BOOT', 'BOOTX64.EFI'), |
273 | + os.path.join(target_efi_path, bootid, 'grubx64.efi'), |
274 | + ] |
275 | + for loader in loaders: |
276 | + util.ensure_dir(os.path.dirname(loader)) |
277 | + with open(loader, 'w+') as fh: |
278 | + fh.write('\n') |
279 | + |
280 | + self.m_os_release.return_value = {'ID': 'suse'} |
281 | + distroinfo = install_grub.distro.get_distroinfo() |
282 | + _enable_loaders("suse") |
283 | + grub_name = 'grub2-efi-x64' |
284 | + grub_target = 'x86_64-efi' |
285 | + grub_cmd = 'grub2-install' |
286 | + update_nvram = True |
287 | + devices = ['/dev/disk-a-part1'] |
288 | + disk = '/dev/disk-a' |
289 | + part = '1' |
290 | + self.m_get_disk_part.return_value = (disk, part) |
291 | + |
292 | + expected_loader = '/EFI/suse/shimx64.efi' |
293 | + expected_install = [ |
294 | + ['efibootmgr', '-v'], |
295 | + ['efibootmgr', '--create', '--write-signature', |
296 | + '--label', 'suse', '--disk', disk, '--part', part, |
297 | + '--loader', expected_loader], |
298 | + ] |
299 | + expected_post = [ |
300 | + ['grub2-mkconfig', '-o', '/boot/efi/EFI/suse/grub.cfg'], |
301 | + ['efibootmgr', '-v'] |
302 | + ] |
303 | + |
304 | + self.assertEqual( |
305 | + (expected_install, expected_post), |
306 | + install_grub.gen_uefi_install_commands( |
307 | + grub_name, grub_target, grub_cmd, update_nvram, distroinfo, |
308 | + devices, self.target)) |
309 | + |
310 | + def test_suse_install_existing_no_nvram(self): |
311 | + # verify grub install command is not executed if update_nvram is False |
312 | + # on suse. |
313 | + def _enable_loaders(bootid): |
314 | + efi_path = 'boot/efi/EFI' |
315 | + target_efi_path = os.path.join(self.target, efi_path) |
316 | + loaders = [ |
317 | + os.path.join(target_efi_path, bootid, 'shimx64.efi'), |
318 | + os.path.join(target_efi_path, 'BOOT', 'BOOTX64.EFI'), |
319 | + os.path.join(target_efi_path, bootid, 'grubx64.efi'), |
320 | + ] |
321 | + for loader in loaders: |
322 | + util.write_file(loader, content="") |
323 | + |
324 | + self.m_os_release.return_value = {'ID': 'suse'} |
325 | + distroinfo = install_grub.distro.get_distroinfo() |
326 | + bootid = distroinfo.variant |
327 | + _enable_loaders(bootid) |
328 | + grub_name = 'grub2-efi-x64' |
329 | + grub_target = 'x86_64-efi' |
330 | + grub_cmd = 'grub2-install' |
331 | + update_nvram = False |
332 | + devices = ['/dev/disk-a-part1'] |
333 | + disk = '/dev/disk-a' |
334 | + part = '1' |
335 | + self.m_get_disk_part.return_value = (disk, part) |
336 | + |
337 | + expected_install = [ |
338 | + ['efibootmgr', '-v'], |
339 | + ] |
340 | + expected_post = [ |
341 | + ['grub2-mkconfig', '-o', '/boot/efi/EFI/%s/grub.cfg' % bootid], |
342 | + ['efibootmgr', '-v'] |
343 | + ] |
344 | + |
345 | + self.assertEqual( |
346 | + (expected_install, expected_post), |
347 | + install_grub.gen_uefi_install_commands( |
348 | + grub_name, grub_target, grub_cmd, update_nvram, distroinfo, |
349 | + devices, self.target)) |
350 | + |
351 | |
352 | class TestGenInstallCommands(CiTestCase): |
353 | |
354 | diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py |
355 | index a224819..c13434c 100644 |
356 | --- a/tests/unittests/test_curthooks.py |
357 | +++ b/tests/unittests/test_curthooks.py |
358 | @@ -479,6 +479,22 @@ class TestInstallMissingPkgs(CiTestCase): |
359 | expected_pkgs, target=target, osfamily=self.distro_family) |
360 | |
361 | @patch.object(events, 'ReportEventStack') |
362 | + def test_install_packages_on_uefi_amd64_sles(self, mock_events): |
363 | + arch = 'amd64' |
364 | + self.mock_arch.return_value = arch |
365 | + self.mock_machine.return_value = 'x86_64' |
366 | + expected_pkgs = ['efibootmgr', 'grub2', 'grub2-branding-SLE', |
367 | + 'grub2-x86_64-efi'] |
368 | + self.mock_uefi.return_value = True |
369 | + self.mock_haspkg.return_value = True |
370 | + target = "not-a-real-target" |
371 | + cfg = {} |
372 | + curthooks.install_missing_packages( |
373 | + cfg, target=target, osfamily=distro.DISTROS.suse) |
374 | + self.mock_install_packages.assert_called_with( |
375 | + expected_pkgs, target=target, osfamily=distro.DISTROS.suse) |
376 | + |
377 | + @patch.object(events, 'ReportEventStack') |
378 | def test_install_packages_on_uefi_amd64_centos(self, mock_events): |
379 | arch = 'amd64' |
380 | self.mock_arch.return_value = arch |
381 | diff --git a/tests/unittests/test_distro.py b/tests/unittests/test_distro.py |
382 | index 7532126..9851650 100644 |
383 | --- a/tests/unittests/test_distro.py |
384 | +++ b/tests/unittests/test_distro.py |
385 | @@ -370,6 +370,34 @@ class TestYumInstall(CiTestCase): |
386 | m_subp.assert_has_calls(expected_calls) |
387 | |
388 | |
389 | +class TestZypperInstall(CiTestCase): |
390 | + |
391 | + @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a) |
392 | + @mock.patch('curtin.util.subp') |
393 | + def test_zypper_install(self, m_subp): |
394 | + pkglist = ['foobar', 'wark'] |
395 | + target = 'mytarget' |
396 | + expected_calls = [ |
397 | + mock.call(['zypper', '--non-interactive', |
398 | + '--non-interactive-include-reboot-patches', |
399 | + '--quiet', 'install'] + pkglist, env=None, |
400 | + target=paths.target_path(target)) |
401 | + ] |
402 | + |
403 | + m_subp.reset_mock() |
404 | + self.assertFalse(m_subp.called) |
405 | + distro.run_zypper_command('install', pkglist, target=target) |
406 | + m_subp.assert_has_calls(expected_calls) |
407 | + |
408 | + # call zypper through install_packages; expect the same calls |
409 | + # so clear m_subp's call stack. |
410 | + m_subp.reset_mock() |
411 | + self.assertFalse(m_subp.called) |
412 | + osfamily = distro.DISTROS.suse |
413 | + distro.install_packages(pkglist, osfamily=osfamily, target=target) |
414 | + m_subp.assert_has_calls(expected_calls) |
415 | + |
416 | + |
417 | class TestSystemUpgrade(CiTestCase): |
418 | |
419 | @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a) |
420 | @@ -469,6 +497,35 @@ class TestSystemUpgrade(CiTestCase): |
421 | m_apt_update.assert_has_calls(apt_update_calls) |
422 | m_subp.assert_has_calls(expected_calls) |
423 | |
424 | + @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a) |
425 | + @mock.patch('curtin.util.subp') |
426 | + def test_system_upgrade_suse(self, m_subp): |
427 | + """system_upgrade osfamily=suse |
428 | + calls run_zypper_command mode=upgrade""" |
429 | + osfamily = distro.DISTROS.suse |
430 | + target = 'mytarget' |
431 | + expected_calls = [ |
432 | + mock.call(['zypper', '--non-interactive', |
433 | + '--non-interactive-include-reboot-patches', '--quiet', |
434 | + 'refresh'], env=None, |
435 | + target=paths.target_path(target)), |
436 | + mock.call(['zypper', '--non-interactive', |
437 | + '--non-interactive-include-reboot-patches', '--quiet', |
438 | + 'update'], env=None, |
439 | + target=paths.target_path(target)), |
440 | + mock.call(['zypper', '--non-interactive', |
441 | + '--non-interactive-include-reboot-patches', '--quiet', |
442 | + 'purge-kernels'], env=None, |
443 | + target=paths.target_path(target)), |
444 | + ] |
445 | + |
446 | + # call system_upgrade via osfamily; note that we expect the same calls |
447 | + # but to prevent a false positive we clear m_subp's call stack. |
448 | + m_subp.reset_mock() |
449 | + self.assertFalse(m_subp.called) |
450 | + distro.system_upgrade(target=target, osfamily=osfamily) |
451 | + m_subp.assert_has_calls(expected_calls) |
452 | + |
453 | |
454 | class TestHasPkgAvailable(CiTestCase): |
455 | |
456 | @@ -519,6 +576,18 @@ class TestHasPkgAvailable(CiTestCase): |
457 | self.assertEqual(pkg == self.package, result) |
458 | m_subp.assert_has_calls([mock.call('list', opts=['--cacheonly'])]) |
459 | |
460 | + @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a) |
461 | + @mock.patch('curtin.distro.subp') |
462 | + def test_has_pkg_available_suse_returns_false_not_avail(self, m_subp): |
463 | + osfamily = distro.DISTROS.suse |
464 | + m_subp.return_value = ('No matching items found.', '') |
465 | + result = distro.has_pkg_available(self.package, self.target, osfamily) |
466 | + self.assertEqual(False, result) |
467 | + m_subp.assert_has_calls([mock.call(['zypper', '--quiet', 'search', |
468 | + '--match-exact', self.package], |
469 | + capture=True, |
470 | + target=self.target)]) |
471 | + |
472 | |
473 | class TestGetArchitecture(CiTestCase): |
474 | |
475 | @@ -563,4 +632,13 @@ class TestGetArchitecture(CiTestCase): |
476 | self.m_rpm_get_arch.call_args_list) |
477 | self.assertEqual(0, self.m_dpkg_get_arch.call_count) |
478 | |
479 | + def test_suse_osfamily_calls_rpm_get_arch(self): |
480 | + osfamily = distro.DISTROS.suse |
481 | + expected_result = self.m_rpm_get_arch.return_value |
482 | + result = distro.get_architecture(target=self.target, osfamily=osfamily) |
483 | + self.assertEqual(expected_result, result) |
484 | + self.assertEqual([mock.call(target=self.target)], |
485 | + self.m_rpm_get_arch.call_args_list) |
486 | + self.assertEqual(0, self.m_dpkg_get_arch.call_count) |
487 | + |
488 | # vi: ts=4 expandtab syntax=python |
This looks fine to me, which mostly means that I am confident it won't regress non-sles installs :-) I guess I'd like Dan to take a look too.