From 2a4952da6c5b9739a56201662d05841185420484 Mon Sep 17 00:00:00 2001 From: rpm-build Date: Sat, 30 May 2015 11:19:53 -0400 Subject: [PATCH] Rebase PR116 --- Makefile-tests.am | 4 ++ src/libostree/ostree-sysroot.c | 47 ++++++++++----- tests/admin-test.sh | 24 ++++++-- tests/grub2-entries-crosscheck.py | 105 ++++++++++++++++++++++++++++++++++ tests/syslinux-entries-crosscheck.py | 107 +++++++++++++++++++++++++++++++++++ 5 files changed, 269 insertions(+), 18 deletions(-) create mode 100644 tests/grub2-entries-crosscheck.py create mode 100644 tests/syslinux-entries-crosscheck.py diff --git a/Makefile-tests.am b/Makefile-tests.am index 46bf499..06db55b 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -72,6 +72,10 @@ insttest_DATA = tests/archive-test.sh \ tests/corrupt-repo-ref.js \ $(NULL) +insttest_SCRIPTS += \ + tests/syslinux-entries-crosscheck.py \ + $(NULL) + gpginsttestdir = $(pkglibexecdir)/installed-tests/gpghome gpginsttest_DATA = tests/gpghome/secring.gpg \ tests/gpghome/trustdb.gpg diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 6255803..b15ddf5 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -355,6 +355,35 @@ _ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, return ret; } +static gint +compare_boot_loader_configs (OstreeBootconfigParser *a, + OstreeBootconfigParser *b) +{ + const char *a_version = ostree_bootconfig_parser_get (a, "version"); + const char *b_version = ostree_bootconfig_parser_get (b, "version"); + + if (a_version && b_version) + { + int r = strverscmp (a_version, b_version); + /* Reverse */ + return -r; + } + else if (a_version) + return -1; + else + return 1; +} + +static int +compare_loader_configs_for_sorting (gconstpointer a_pp, + gconstpointer b_pp) +{ + OstreeBootconfigParser *a = *((OstreeBootconfigParser**)a_pp); + OstreeBootconfigParser *b = *((OstreeBootconfigParser**)b_pp); + + return compare_boot_loader_configs (a, b); +} + gboolean _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, @@ -421,6 +450,9 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, } } + /* Callers expect us to give them a sorted array */ + g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting); + done: gs_transfer_out_value (out_loader_configs, &ret_loader_configs); ret = TRUE; @@ -700,19 +732,8 @@ compare_deployments_by_boot_loader_version_reversed (gconstpointer a_pp, OstreeDeployment *b = *((OstreeDeployment**)b_pp); OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a); OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b); - const char *a_version = ostree_bootconfig_parser_get (a_bootconfig, "version"); - const char *b_version = ostree_bootconfig_parser_get (b_bootconfig, "version"); - - if (a_version && b_version) - { - int r = strverscmp (a_version, b_version); - /* Reverse */ - return -r; - } - else if (a_version) - return -1; - else - return 1; + + return compare_boot_loader_configs (a_bootconfig, b_bootconfig); } /** diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 4278e01..f7fbb92 100755 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -20,17 +20,20 @@ set -e echo "1..10" +function validate_bootloader() { + (cd ${test_tmpdir}; + if test -f sysroot/boot/syslinux/syslinux.cfg; then + $(dirname $0)/syslinux-entries-crosscheck.py sysroot + fi) +} + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) export rev # This initial deployment gets kicked off with some kernel arguments ${CMD_PREFIX} ostree admin --sysroot=sysroot deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime ${CMD_PREFIX} ostree admin --sysroot=sysroot status | tee status.txt - -assert_file_has_content status.txt 'Version: 1.0.10' -if test -f sysroot/boot/loader/syslinux.cfg; then - assert_file_has_content sysroot/boot/loader/syslinux.cfg 'TestOS 42 1.0.10' -fi +validate_bootloader echo "ok deploy command" @@ -66,6 +69,7 @@ assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'option assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.0/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok second deploy" @@ -77,6 +81,7 @@ assert_not_has_dir sysroot/boot/loader.1 assert_has_dir sysroot/ostree/boot.0.0 assert_not_has_dir sysroot/ostree/boot.0.1 ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok third deploy (swap)" @@ -90,6 +95,7 @@ assert_has_file sysroot/boot/loader/entries/ostree-otheros-0.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/deploy/otheros/deploy/${rev}.0/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok independent deploy" @@ -101,6 +107,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.2/etc/os-rele assert_has_file sysroot/boot/loader/entries/ostree-testos-2.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok fourth deploy (retain)" @@ -116,6 +123,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/os-rele assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-config-file 'a new local config file' assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok deploy with modified /etc" @@ -133,6 +141,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/new- # And persist /etc changes from before assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok upgrade bare" @@ -145,6 +154,7 @@ newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildm assert_not_streq ${rev} ${newrev} assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok upgrade" @@ -155,6 +165,7 @@ assert_file_has_content "${originfile}" "bacon:testos/buildmaster/x86_64-runtime ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote list -u > remotes.txt assert_file_has_content remotes.txt 'bacon.*http://tasty.com' cp saved-origin ${originfile} +validate_bootloader echo "ok set-origin" @@ -167,6 +178,7 @@ assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0 ${CMD_PREFIX} ostree admin --sysroot=sysroot undeploy 0 assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${newrev}.0 ${CMD_PREFIX} ostree admin --sysroot=sysroot status +validate_bootloader echo "ok undeploy" @@ -178,6 +190,7 @@ echo "ok deploy with unknown OS" ${CMD_PREFIX} ostree admin --sysroot=sysroot deploy --os=testos --karg-append=console=/dev/foo --karg-append=console=/dev/bar testos:testos/buildmaster/x86_64-runtime ${CMD_PREFIX} ostree admin --sysroot=sysroot deploy --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'console=/dev/foo.*console=/dev/bar' +validate_bootloader echo "ok deploy with multiple kernel args" @@ -187,5 +200,6 @@ ${CMD_PREFIX} ostree admin --sysroot=sysroot upgrade --os=testos newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) assert_not_streq ${origrev} ${newrev} assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'console=/dev/foo.*console=/dev/bar' +validate_bootloader echo "ok upgrade with multiple kernel args" diff --git a/tests/grub2-entries-crosscheck.py b/tests/grub2-entries-crosscheck.py new file mode 100644 index 0000000..d68394d --- /dev/null +++ b/tests/grub2-entries-crosscheck.py @@ -0,0 +1,105 @@ +#!/usr/bin/python +# +# Copyright (C) 2015 Red Hat +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import sys + +if len(sys.argv) == 1: + loaderpath = '/boot/loader/entries' + grub2path = '/boot/grub2/grub.cfg' +else: + loaderpath = sys.argv[1] + grub2path = sys.argv[2] + +def fatal(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + sys.exit(1) + +def compare_entries_descending(a, b): + return int(b['version']) - int(a['version']) + +def get_ostree_option(optionstring): + for o in optionstring.split(): + if o.startswith('ostree='): + return o[8:] + raise ValueError('ostree= not found') + +entries = [] +grub2_entries = [] + +# Parse loader configs +for fname in os.listdir(loaderpath): + path = os.path.join(loaderpath, fname) + with open(path) as f: + entry = {} + for line in f: + line = line.strip() + if (line == '' or line.startswith('#')): + continue + s = line.find(' ') + assert s > 0 + k = line[0:s] + v = line[s+1:] + entry[k] = v + entries.append(entry) + entries.sort(compare_entries_descending) + +# Parse GRUB2 config +with open(grub2path) as f: + in_ostree_config = False + grub2_entry = None + for line in f: + if line.startswith('### BEGIN /etc/grub.d/15_ostree ###'): + in_ostree_config = True + elif line.startswith('### END /etc/grub.d/15_ostree ###'): + in_ostree_config = False + if grub2_entry is not None: + grub2_entries.append(grub2_entry) + elif in_ostree_config: + if line.startswith('menuentry '): + if grub2_entry is not None: + grub2_entries.append(grub2_entry) + grub2_entry = {} + elif line.startswith('linux'): + parts = line.split() + grub2_entry['linux'] = parts[1] + grub2_entry['options'] = ' '.join(parts[2:]) + elif line.startswith('initrd'): + grub2_entry['initrd'] = line.split()[1] + +if len(entries) != len(grub2_entries): + fatal("Found {0} loader entries, but {1} GRUB2 entries\n".format(len(entries), len(grub2_entries))) + +def assert_matches_key(a, b, key): + aval = a[key] + bval = b[key] + if aval != bval: + fatal("Mismatch on {0}: {1} != {2}".format(key, aval, bval)) + +for i,(entry,grub2entry) in enumerate(zip(entries, grub2_entries)): + assert_matches_key(entry, grub2entry, 'linux') + assert_matches_key(entry, grub2entry, 'initrd') + entry_ostree = get_ostree_option(entry['options']) + grub2_ostree = get_ostree_option(grub2entry['options']) + if entry_ostree != grub2_ostree: + fatal("Mismatch on ostree option: {0} != {1}".format(entry_ostree, grub2_ostree)) + +sys.stdout.write('GRUB2 configuration validated\n') +sys.exit(0) diff --git a/tests/syslinux-entries-crosscheck.py b/tests/syslinux-entries-crosscheck.py new file mode 100644 index 0000000..8b58ed4 --- /dev/null +++ b/tests/syslinux-entries-crosscheck.py @@ -0,0 +1,107 @@ +#!/usr/bin/python +# +# Copyright (C) 2015 Red Hat +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import sys + +if len(sys.argv) == 1: + sysroot = '' +else: + sysroot = sys.argv[1] + +loaderpath = sysroot + '/boot/loader/entries' +syslinuxpath = sysroot + '/boot/syslinux/syslinux.cfg' + +def fatal(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + sys.exit(1) + +def compare_entries_descending(a, b): + return int(b['version']) - int(a['version']) + +def get_ostree_option(optionstring): + for o in optionstring.split(): + if o.startswith('ostree='): + return o[8:] + raise ValueError('ostree= not found') + +entries = [] +syslinux_entries = [] + +# Parse loader configs +for fname in os.listdir(loaderpath): + path = os.path.join(loaderpath, fname) + with open(path) as f: + entry = {} + for line in f: + line = line.strip() + if (line == '' or line.startswith('#')): + continue + s = line.find(' ') + assert s > 0 + k = line[0:s] + v = line[s+1:] + entry[k] = v + entries.append(entry) + entries.sort(compare_entries_descending) + +# Parse SYSLINUX config +with open(syslinuxpath) as f: + in_ostree_config = False + syslinux_entry = None + syslinux_default = None + for line in f: + line = line.strip() + if line.startswith('DEFAULT '): + if syslinux_entry is not None: + syslinux_default = line.split(' ', 1)[1] + elif line.startswith('LABEL '): + if syslinux_entry is not None: + syslinux_entries.append(syslinux_entry) + syslinux_entry = {} + syslinux_entry['title'] = line.split(' ', 1)[1] + elif line.startswith('KERNEL '): + syslinux_entry['linux'] = line.split(' ', 1)[1] + elif line.startswith('INITRD '): + syslinux_entry['initrd'] = line.split(' ', 1)[1] + elif line.startswith('APPEND '): + syslinux_entry['options'] = line.split(' ', 1)[1] + if syslinux_entry is not None: + syslinux_entries.append(syslinux_entry) + +if len(entries) != len(syslinux_entries): + fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(len(entries), len(syslinux_entries))) + +def assert_matches_key(a, b, key): + aval = a[key] + bval = b[key] + if aval != bval: + fatal("Mismatch on {0}: {1} != {2}".format(key, aval, bval)) + +for i,(entry,syslinuxentry) in enumerate(zip(entries, syslinux_entries)): + assert_matches_key(entry, syslinuxentry, 'linux') + assert_matches_key(entry, syslinuxentry, 'initrd') + entry_ostree = get_ostree_option(entry['options']) + syslinux_ostree = get_ostree_option(syslinuxentry['options']) + if entry_ostree != syslinux_ostree: + fatal("Mismatch on ostree option: {0} != {1}".format(entry_ostree, syslinux_ostree)) + +sys.stdout.write('SYSLINUX configuration validated\n') +sys.exit(0) -- 1.8.3.1