From 3ab0d5e6644885440bac6abd17b6d2637df5435f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 15 Aug 2017 11:22:21 -0400 Subject: [PATCH] lib/sysroot: Support /usr/lib/modules/$kver for kernel/initramfs This is the new Fedora kernel standard layout; it has the advantage of being in `/usr` like `/usr/lib/ostree-boot`, but it's not OSTree specific. Further, I think in practice forcing tree builders to compute the checksum is an annoying stumbling block; since we already switched to e.g. computing checksums always when doing pulls, the cost of doing another checksum for the kernel/initramfs is tiny. The "bootcsum" becomes more of an internal implementation detail. Now, there is a transition; my current thought for this is that rpm-ostree will change to default to injecting into both `/usr/lib/ostree-boot` and `/usr/lib/modules`, and stop doing `/boot`, then maybe next year say we drop the `/usr/lib/ostree-boot` by default. A twist here is that the default Fedora kernel RPM layout (and what's in rpm-ostree today) includes a kernel but *not* an initramfs in `/usr/lib/modules`. If we looked only there, we'd just find the kernel. So we need to look in both, and then special case this - pick the legacy layout if we have `/usr/lib/modules` but not an initramfs. While here, rework the code to have an `OstreeKernelLayout` struct which makes dealing with all of the variables nicer. Closes: #1079 Approved by: jlebon --- docs/manual/deployment.md | 9 +- src/libostree/ostree-sysroot-deploy.c | 379 +++++++++++++++++++------- tests/libtest.sh | 58 ++-- tests/test-admin-deploy-syslinux.sh | 45 ++- tests/test-admin-deploy-uboot.sh | 1 + 5 files changed, 364 insertions(+), 128 deletions(-) diff --git a/docs/manual/deployment.md b/docs/manual/deployment.md index 76d05701..0db03117 100644 --- a/docs/manual/deployment.md +++ b/docs/manual/deployment.md @@ -43,8 +43,13 @@ to a filesystem tree that represents the underlying basis of a deployment. For short, we will call this the "tree", to distinguish it from the concept of a deployment. -First, the tree must include a kernel stored as -`vmlinuz(-.*)?-$checksum` in either `/boot` or `/usr/lib/ostree-boot`. +First, the tree must include a kernel (and optionally an initramfs). The +current standard locations for these are `/usr/lib/modules/$kver/vmlinuz` and +`/usr/lib/modules/$kver/initramfs`. The "boot checksum" will be computed +automatically. This follows the current Fedora kernel layout, and is +the current recommended path. However, older versions of libostree don't +support this; you may need to also put kernels in the previous (legacy) +paths, which are `vmlinuz(-.*)?-$checksum` in either `/boot` or `/usr/lib/ostree-boot`. The checksum should be a SHA256 hash of the kernel contents; it must be pre-computed before storing the kernel in the repository. Optionally, the directory can also contain an initramfs, stored as diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 60fbc1d3..8b2f5e4b 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -882,46 +882,173 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, cancellable, error); } -/* Originally OSTree defined kernels to be found underneath /boot - * in the tree. But that means when mounting /boot at runtime - * we end up masking the content underneath, triggering a warning. - * - * For that reason, and also consistency with the "/usr defines the OS" model we - * later switched to defining the in-tree kernels to be found under - * /usr/lib/ostree-boot. - */ -static gboolean -get_kernel_from_tree (int deployment_dfd, - int *out_boot_dfd, - char **out_kernel_srcpath, - char **out_kernel_namever, - char **out_initramfs_srcpath, - char **out_initramfs_namever, - char **out_bootcsum, - GCancellable *cancellable, - GError **error) +typedef struct { + int boot_dfd; + char *kernel_srcpath; + char *kernel_namever; + char *initramfs_srcpath; + char *initramfs_namever; + char *bootcsum; +} OstreeKernelLayout; +static void +_ostree_kernel_layout_free (OstreeKernelLayout *layout) { - g_autofree char *ret_kernel_srcpath = NULL; - g_autofree char *ret_kernel_namever = NULL; - g_autofree char *ret_initramfs_srcpath = NULL; - g_autofree char *ret_initramfs_namever = NULL; - g_autofree char *kernel_checksum = NULL; - g_autofree char *initramfs_checksum = NULL; + if (layout->boot_dfd != -1) + (void) close (layout->boot_dfd); + g_free (layout->kernel_srcpath); + g_free (layout->kernel_namever); + g_free (layout->initramfs_srcpath); + g_free (layout->initramfs_namever); + g_free (layout->bootcsum); + g_free (layout); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeKernelLayout, _ostree_kernel_layout_free); - glnx_fd_close int ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE); - if (ret_boot_dfd == -1) +static OstreeKernelLayout* +_ostree_kernel_layout_new (void) +{ + OstreeKernelLayout *ret = g_new0 (OstreeKernelLayout, 1); + ret->boot_dfd = -1; + return ret; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_usrlib_modules (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *kver = NULL; + /* Look in usr/lib/modules */ + g_auto(GLnxDirFdIterator) mod_dfditer = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (deployment_dfd, "usr/lib/modules", &mod_dfditer, + &exists, error)) + return FALSE; + if (!exists) { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "%s", "openat(usr/lib/ostree-boot)"); - else - { - if (!glnx_opendirat (deployment_dfd, "boot", TRUE, &ret_boot_dfd, error)) - return FALSE; - } + /* No usr/lib/modules? We're done */ + *out_layout = NULL; + return TRUE; } + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + /* Reusable buffer for path string */ + g_autoptr(GString) pathbuf = g_string_new (""); + /* Loop until we find something that looks like a valid /usr/lib/modules/$kver */ + while (ret_layout->boot_dfd == -1) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&mod_dfditer, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + /* It's a directory, look for /vmlinuz as a regular file */ + g_string_truncate (pathbuf, 0); + g_string_append_printf (pathbuf, "%s/vmlinuz", dent->d_name); + if (fstatat (mod_dfditer.fd, pathbuf->str, &stbuf, 0) < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", pathbuf->str); + else + continue; + } + else + { + /* Not a regular file? Loop again */ + if (!S_ISREG (stbuf.st_mode)) + continue; + } + + /* Looks valid, this should exit the loop */ + if (!glnx_opendirat (mod_dfditer.fd, dent->d_name, FALSE, &ret_layout->boot_dfd, error)) + return FALSE; + kver = g_strdup (dent->d_name); + ret_layout->kernel_srcpath = g_strdup ("vmlinuz"); + ret_layout->kernel_namever = g_strdup_printf ("vmlinuz-%s", kver); + } + + if (ret_layout->boot_dfd == -1) + { + *out_layout = NULL; + /* No kernel found? We're done. */ + return TRUE; + } + + /* We found a module directory, compute the checksum */ + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + glnx_fd_close int fd = -1; + /* Checksum the kernel */ + if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error)) + return FALSE; + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + g_clear_object (&in); + (void) close (fd); fd = -1; + + /* Look for an initramfs, but it's optional */ + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "initramfs", &fd, error)) + return FALSE; + if (fd != -1) + { + ret_layout->initramfs_srcpath = g_strdup ("initramfs"); + ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s", kver); + in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + } + + ret_layout->bootcsum = g_strdup (g_checksum_get_string (checksum)); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_legacy_layouts (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + const char *legacy_paths[] = {"usr/lib/ostree-boot", "boot"}; + g_autofree char *kernel_checksum = NULL; + g_autofree char *initramfs_checksum = NULL; + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + for (guint i = 0; i < G_N_ELEMENTS (legacy_paths); i++) + { + const char *path = legacy_paths[i]; + ret_layout->boot_dfd = glnx_opendirat_with_errno (deployment_dfd, path, TRUE); + if (ret_layout->boot_dfd == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + } + else + break; + } + + if (ret_layout->boot_dfd == -1) + { + /* No legacy found? We're done */ + *out_layout = NULL; + return TRUE; + } + + /* ret_layout->boot_dfd will point to either /usr/lib/ostree-boot or /boot, let's + * inspect it. + */ g_auto(GLnxDirFdIterator) dfditer = { 0, }; - if (!glnx_dirfd_iterator_init_at (ret_boot_dfd, ".", FALSE, &dfditer, error)) + if (!glnx_dirfd_iterator_init_at (ret_layout->boot_dfd, ".", FALSE, &dfditer, error)) return FALSE; while (TRUE) @@ -930,62 +1057,143 @@ get_kernel_from_tree (int deployment_dfd, if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) return FALSE; - if (dent == NULL) break; const char *name = dent->d_name; - if (ret_kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) + /* See if this is the kernel */ + if (ret_layout->kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) { const char *dash = strrchr (name, '-'); g_assert (dash); + /* In this version, we require that the tree builder generated a + * sha256 of the kernel+initramfs and appended it to the file names. + */ if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { kernel_checksum = g_strdup (dash + 1); - ret_kernel_srcpath = g_strdup (name); - ret_kernel_namever = g_strndup (name, dash - name); + ret_layout->kernel_srcpath = g_strdup (name); + ret_layout->kernel_namever = g_strndup (name, dash - name); } } - else if (ret_initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) + /* See if this is the initramfs */ + else if (ret_layout->initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) { const char *dash = strrchr (name, '-'); g_assert (dash); if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { initramfs_checksum = g_strdup (dash + 1); - ret_initramfs_srcpath = g_strdup (name); - ret_initramfs_namever = g_strndup (name, dash - name); + ret_layout->initramfs_srcpath = g_strdup (name); + ret_layout->initramfs_namever = g_strndup (name, dash - name); } } - if (ret_kernel_srcpath != NULL && ret_initramfs_srcpath != NULL) + /* If we found both a kernel and initramfs, break out of the loop */ + if (ret_layout->kernel_srcpath != NULL && ret_layout->initramfs_srcpath != NULL) break; } - if (ret_kernel_srcpath == NULL) + /* No kernel found? We're done */ + if (ret_layout->kernel_srcpath == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Failed to find kernel in /usr/lib/ostree-boot or /boot"); - return FALSE; + *out_layout = NULL; + return TRUE; } - if (ret_initramfs_srcpath != NULL) + /* The kernel/initramfs checksums must be the same */ + if (ret_layout->initramfs_srcpath != NULL) { + g_assert (kernel_checksum != NULL); + g_assert (initramfs_checksum != NULL); if (strcmp (kernel_checksum, initramfs_checksum) != 0) + return glnx_throw (error, "Mismatched kernel checksum vs initrd"); + ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); + } + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* Locate kernel/initramfs in the tree; the current standard is to look in + * /usr/lib/modules/$kver/vmlinuz first. + * + * Originally OSTree defined kernels to be found underneath /boot + * in the tree. But that means when mounting /boot at runtime + * we end up masking the content underneath, triggering a warning. + * + * For that reason, and also consistency with the "/usr defines the OS" model we + * later switched to defining the in-tree kernels to be found under + * /usr/lib/ostree-boot. But since then, Fedora at least switched to storing the + * kernel in /usr/lib/modules, which makes sense and isn't ostree-specific, so + * we prefer that now. However, the default Fedora layout doesn't put the + * initramfs there, so we need to look in /usr/lib/ostree-boot first. + */ +static gboolean +get_kernel_from_tree (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeKernelLayout) usrlib_modules_layout = NULL; + g_autoptr(OstreeKernelLayout) legacy_layout = NULL; + + /* First, gather from usr/lib/modules/$kver if it exists */ + if (!get_kernel_from_tree_usrlib_modules (deployment_dfd, &usrlib_modules_layout, cancellable, error)) + return FALSE; + + /* Gather the legacy layout */ + if (!get_kernel_from_tree_legacy_layouts (deployment_dfd, &legacy_layout, cancellable, error)) + return FALSE; + + /* Evaluate the state of both layouts. If there's no legacy layout + * If a legacy layout exists, and it has + * an initramfs but the module layout doesn't, the legacy layout wins. This is + * what happens with rpm-ostree with Fedora today, until rpm-ostree learns the + * new layout. + */ + if (legacy_layout == NULL) + { + /* No legacy layout, let's see if we have a module layout...*/ + if (usrlib_modules_layout == NULL) { + /* Both layouts are not found? Throw. */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Mismatched kernel checksum vs initrd"); + "Failed to find kernel in /usr/lib/modules, /usr/lib/ostree-boot or /boot"); return FALSE; } + else + { + /* No legacy, just usr/lib/modules? We're done */ + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + } + else if (usrlib_modules_layout != NULL && + usrlib_modules_layout->initramfs_srcpath == NULL && + legacy_layout->initramfs_srcpath != NULL) + { + /* Does the module path not have an initramfs, but the legacy does? Prefer + * the latter then, to make rpm-ostree work as is today. + */ + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; + } + /* Prefer module layout */ + else if (usrlib_modules_layout != NULL) + { + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + else + { + /* And finally fall back to legacy; we know one exists since we + * checked first above. + */ + g_assert (legacy_layout->kernel_srcpath); + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; } - - *out_boot_dfd = glnx_steal_fd (&ret_boot_dfd); - *out_kernel_srcpath = g_steal_pointer (&ret_kernel_srcpath); - *out_kernel_namever = g_steal_pointer (&ret_kernel_namever); - *out_initramfs_srcpath = g_steal_pointer (&ret_initramfs_srcpath); - *out_initramfs_namever = g_steal_pointer (&ret_initramfs_namever); - *out_bootcsum = g_steal_pointer (&kernel_checksum); - return TRUE; } /* We used to syncfs(), but that doesn't flush the journal on XFS, @@ -1315,18 +1523,8 @@ install_deployment_kernel (OstreeSysroot *sysroot, return FALSE; /* Find the kernel/initramfs in the tree */ - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &tree_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; @@ -1336,7 +1534,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, const char *osname = ostree_deployment_get_osname (deployment); const char *bootcsum = ostree_deployment_get_bootcsum (deployment); - g_assert_cmpstr (bootcsum, ==, tree_bootcsum); + g_assert_cmpstr (kernel_layout->bootcsum, ==, bootcsum); g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum); g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion); g_autofree char *bootconf_name = g_strdup_printf ("ostree-%s-%d.conf", osname, @@ -1355,12 +1553,13 @@ install_deployment_kernel (OstreeSysroot *sysroot, * it doesn't exist already. */ struct stat stbuf; - if (fstatat (bootcsum_dfd, tree_kernel_namever, &stbuf, 0) != 0) + if (fstatat (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_kernel_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_srcpath, - bootcsum_dfd, tree_kernel_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->kernel_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, + kernel_layout->kernel_srcpath, + bootcsum_dfd, kernel_layout->kernel_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1369,15 +1568,15 @@ install_deployment_kernel (OstreeSysroot *sysroot, /* If we have an initramfs, then install it into * /boot/ostree/osname-${bootcsum} if it doesn't exist already. */ - if (tree_initramfs_srcpath) + if (kernel_layout->initramfs_srcpath) { - g_assert (tree_initramfs_namever); - if (fstatat (bootcsum_dfd, tree_initramfs_namever, &stbuf, 0) != 0) + g_assert (kernel_layout->initramfs_namever); + if (fstatat (bootcsum_dfd, kernel_layout->initramfs_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_initramfs_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_srcpath, - bootcsum_dfd, tree_initramfs_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->initramfs_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath, + bootcsum_dfd, kernel_layout->initramfs_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1458,12 +1657,12 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_kernel_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); - if (tree_initramfs_namever) + if (kernel_layout->initramfs_namever) { - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_initramfs_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); } @@ -2084,22 +2283,12 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, return FALSE; } - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &new_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; - _ostree_deployment_set_bootcsum (new_deployment, new_bootcsum); + _ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum); /* Create an empty boot configuration; we will merge things into * it as we go. diff --git a/tests/libtest.sh b/tests/libtest.sh index ff096505..ce7cc3d9 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -366,7 +366,7 @@ setup_os_repository () { shift bootmode=$1 shift - bootdir=${1:-usr/lib/ostree-boot} + bootdir=${1:-usr/lib/modules/3.6.0} oldpwd=`pwd` @@ -381,17 +381,24 @@ setup_os_repository () { cd ${test_tmpdir} mkdir osdata cd osdata - mkdir -p usr/bin usr/lib/modules/3.6.0 usr/share usr/etc - mkdir -p ${bootdir} - echo "a kernel" > ${bootdir}/vmlinuz-3.6.0 - echo "an initramfs" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + mkdir -p usr/bin ${bootdir} usr/lib/modules/3.6.0 usr/share usr/etc + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs + # /usr/lib/modules just uses "vmlinuz", since the version is in the module + # directory name. + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-3.6.0 + initramfs_path=${initramfs_path}-3.6.0 + fi + echo "a kernel" > ${kernel_path} + echo "an initramfs" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not # /usr/lib/modules. - if [[ $bootdir != usr/lib/modules ]]; then - mv ${bootdir}/vmlinuz-3.6.0{,-${bootcsum}} - mv ${bootdir}/initramfs-3.6.0{,-${bootcsum}} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} fi echo "an executable" > usr/bin/sh @@ -412,7 +419,7 @@ EOF echo "a default daemon file" > usr/etc/testdirectory/test ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" - + # Ensure these commits have distinct second timestamps sleep 2 echo "a new executable" > usr/bin/sh @@ -447,7 +454,7 @@ EOF setup_os_boot_grub2 "${bootmode}" ;; esac - + cd ${test_tmpdir} mkdir ${test_tmpdir}/httpd cd httpd @@ -465,17 +472,30 @@ os_repository_new_commit () branch=${3:-testos/buildmaster/x86_64-runtime} echo "BOOT ITERATION: $boot_checksum_iteration" cd ${test_tmpdir}/osdata - bootdir=usr/lib/ostree-boot - if ! test -d ${bootdir}; then - bootdir=boot + if test -f usr/lib/modules/3.6.0/vmlinuz; then + bootdir=usr/lib/modules/3.6.0 + else + if test -d usr/lib/ostree-boot; then + bootdir=usr/lib/ostree-boot + else + bootdir=boot + fi fi rm ${bootdir}/* - echo "new: a kernel ${boot_checksum_iteration}" > ${bootdir}/vmlinuz-3.6.0 - echo "new: an initramfs ${boot_checksum_iteration}" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-3.6.0 + initramfs_path=${initramfs_path}-3.6.0 + fi + echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path} + echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum - mv ${bootdir}/vmlinuz-3.6.0 ${bootdir}/vmlinuz-3.6.0-${bootcsum} - mv ${bootdir}/initramfs-3.6.0 ${bootdir}/initramfs-3.6.0-${bootcsum} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi echo "a new default config file" > usr/etc/a-new-default-config-file mkdir -p usr/etc/new-default-dir diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index b19a74f0..2a3c497d 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..20" +echo "1..22" . $(dirname $0)/libtest.sh @@ -28,22 +28,43 @@ setup_os_repository "archive-z2" "syslinux" . $(dirname $0)/admin-test.sh +# Test the legacy dirs +for test_bootdir in "boot" "usr/lib/ostree-boot"; do + cd ${test_tmpdir} + rm httpd osdata testos-repo sysroot -rf + setup_os_repository "archive" "syslinux" $test_bootdir + ${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) + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' + # kernel/initrams should also be in the tree's /boot with the checksum + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' + assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' + ${CMD_PREFIX} ostree admin status + validate_bootloader + echo "ok kernel in $test_bootdir" +done + +# And test that legacy overrides /usr/lib/modules cd ${test_tmpdir} rm httpd osdata testos-repo sysroot -rf -setup_os_repository "archive-z2" "syslinux" "boot" - +setup_os_repository "archive" "syslinux" "usr/lib/ostree-boot" +cd osdata +echo "this is a kernel without an initramfs like Fedora 26" > usr/lib/modules/3.6.0/vmlinuz +usrlib_modules_bootcsum=$(cat usr/lib/modules/3.6.0/vmlinuz | sha256sum | cut -f 1 -d ' ') +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" +cd ${test_tmpdir} ${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) ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' -assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' -# kernel/initrams should also be in the tree's /boot with the checksum -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/vmlinuz-3.6.0-${bootcsum} 'a kernel' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/initramfs-3.6.0-${bootcsum} 'an initramfs' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' -assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' -${CMD_PREFIX} ostree admin status -validate_bootloader -echo "ok kernel in tree's /boot" +# Note this bootcsum shouldn't be the modules one +assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" +echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 3685e31e..c7a6c751 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -30,6 +30,7 @@ setup_os_repository "archive-z2" "uboot" . $(dirname $0)/admin-test.sh cd ${test_tmpdir} +mkdir -p osdata/usr/lib/ostree-boot cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile}