From 6c2610e8774c74dec9c7a35c59ed2bb6aef2c32e Mon Sep 17 00:00:00 2001 From: Robert Fairley Date: Fri, 24 May 2019 01:34:24 -0400 Subject: [PATCH] Support kargs.d directories for default kargs Add the following config directories for setting default kernel arguments: /etc/ostree/kargs.d (host config) /usr/lib/ostree-boot/kargs.d (base config) These directories contain files whose contents consist of a karg snippet, which is a collection kernel parameter keys and values. Example of a snippet: ``` KEY=VALUE ANOTHERKEY SAMEKEY=VALUE2 FIRSTKEY=1 SAMEKEY=VALUE3 SECONDKEY=2 KEY= KEY.KEY-KEY_KEY="some space-separated values" ``` The bootconfig key `ostree-kargs-generated-from-config` indicates whether the kargs were generated by ostree from the kargs.d directories (`true`), or copied from the previous deployment (`false`). Editing the kargs through the command line (e.g. `ostree admin deploy --karg=`) will set the flag to `false`, and kargs will be copied from the previous deployment for subsequent deployments. Also add support for `ostree admin instutil set-kargs` so that installer programs using this command (such as Anaconda) remain managed by the kargs.d directories from the first deployment. Closes: #479 --- Makefile-tests.am | 1 + src/libostree/ostree-sysroot-deploy.c | 364 ++++++++++++++++++++++-- src/libostree/ostree-sysroot-private.h | 2 + tests/libtest.sh | 49 ++++ tests/test-admin-deploy-karg-default.sh | 151 ++++++++++ tests/test-admin-deploy-karg.sh | 23 +- tests/test-admin-instutil-set-kargs.sh | 43 ++- 7 files changed, 608 insertions(+), 25 deletions(-) create mode 100755 tests/test-admin-deploy-karg-default.sh diff --git a/Makefile-tests.am b/Makefile-tests.am index 2c0916f620..b93f084776 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -98,6 +98,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-admin-deploy-syslinux.sh \ tests/test-admin-deploy-2.sh \ tests/test-admin-deploy-karg.sh \ + tests/test-admin-deploy-karg-default.sh \ tests/test-admin-deploy-switch.sh \ tests/test-admin-deploy-etcmerge-cornercases.sh \ tests/test-admin-deploy-uboot.sh \ diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 1096b0b071..823dd2145c 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -2448,6 +2448,17 @@ allocate_deployserial (OstreeSysroot *self, return TRUE; } +static void +bootconfig_set_kargs (OstreeBootconfigParser *bootconfig, + const char *opts, + gboolean generated) +{ + ostree_bootconfig_parser_set (bootconfig, "options", opts); + ostree_bootconfig_parser_set (bootconfig, + "ostree-kargs-generated-from-config", + generated ? "true" : "false"); +} + void _ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment, char **override_kernel_argv) @@ -2466,7 +2477,7 @@ _ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment, g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new (); _ostree_kernel_args_append_argv (kargs, override_kernel_argv); g_autofree char *new_options = _ostree_kernel_args_to_string (kargs); - ostree_bootconfig_parser_set (bootconfig, "options", new_options); + bootconfig_set_kargs (bootconfig, new_options, FALSE); } } @@ -2564,40 +2575,257 @@ get_var_dfd (OstreeSysroot *self, return glnx_opendirat (base_dfd, base_path, TRUE, ret_fd, error); } +/* Get a GFile* referring to the commit object at ref for the file at path. */ +static GFile* +get_file_from_repo (OstreeRepo *repo, + const char *ref, + const char *path, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, ref, &root, + NULL, cancellable, error)) + return NULL; + return g_file_resolve_relative_path (root, path); +} + static gboolean -sysroot_finalize_deployment (OstreeSysroot *self, - OstreeDeployment *deployment, - char **override_kernel_argv, - OstreeDeployment *merge_deployment, - GCancellable *cancellable, - GError **error) +add_kargs_from_filesystem (GTree *kargs_configs, + int deployment_dfd, + const char *dirpath, + GCancellable *cancellable, + GError **error) { - g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); - glnx_autofd int deployment_dfd = -1; - if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) + int kargs_dfd = -1; + if (!ot_openat_ignore_enoent (deployment_dfd, dirpath, + &kargs_dfd, error)) return FALSE; + if (kargs_dfd > 0) + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (kargs_dfd, ".", TRUE, &dfd_iter, error)) + return FALSE; + while (TRUE) + { + struct dirent *dent = NULL; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, + cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (!(dent->d_type == DT_REG || dent->d_type == DT_LNK)) + continue; + + const char *karg_name = dent->d_name; + if (g_tree_lookup (kargs_configs, karg_name)) + continue; + + g_autofree char *karg_contents = NULL; + if (!(karg_contents = glnx_file_get_contents_utf8_at (kargs_dfd, + karg_name, NULL, + cancellable, + error))) + return FALSE; + + g_tree_insert (kargs_configs, g_strdup (karg_name), + g_steal_pointer (&karg_contents)); + } + } + + return TRUE; +} + +static gboolean +add_kargs_from_commit (OstreeSysroot *sysroot, + GTree *kargs_configs, + int deployment_dfd, + const char *dirpath, + const char *revision, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + if (!glnx_fstatat_allow_noent (deployment_dfd, dirpath, &stbuf, 0, error)) + return FALSE; + const gboolean dir_exists = (errno == 0); + + if (dir_exists) + { + g_autoptr(GFile) karg_file = get_file_from_repo (ostree_sysroot_repo (sysroot), + revision, + dirpath, + cancellable, + error); + g_autoptr(GFileEnumerator) dir_enum = NULL; + g_autoptr(GFile) child = NULL; + g_autoptr(GFileInfo) child_info = NULL; + g_autoptr(GError) temp_error = NULL; + dir_enum = g_file_enumerate_children (karg_file, + OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!dir_enum) + return FALSE; + + while ((child_info = g_file_enumerator_next_file (dir_enum, NULL, + &temp_error)) != NULL) + { + g_clear_object (&child); + const char *karg_name = g_file_info_get_name (child_info); + child = g_file_get_child (karg_file, karg_name); + + g_autofree char *karg_contents = NULL; + if (!g_file_load_contents (child, cancellable, &karg_contents, NULL, + NULL, &temp_error)) + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + if (karg_contents && !g_tree_lookup (kargs_configs, karg_name)) + g_tree_insert (kargs_configs, g_strdup (karg_name), + g_steal_pointer (&karg_contents)); + g_clear_object (&child_info); + } + if (temp_error) + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +collect_karg (gpointer key, + gpointer value, + gpointer kargs_data) +{ + const char *karg_contents = value; + OstreeKernelArgs *kargs = kargs_data; + + _ostree_kernel_args_parse_append (kargs, karg_contents); + + return FALSE; +} + +static gboolean +sysroot_regenerate_kargs (OstreeSysroot *self, + const char *revision, + int deployment_dfd, + char **out_kargs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GTree) kargs_configs = g_tree_new_full ((GCompareDataFunc)g_ascii_strcasecmp, + NULL, g_free, g_free); + + if (!add_kargs_from_filesystem (kargs_configs, deployment_dfd, + _OSTREE_SYSROOT_KARGS_HOST, cancellable, + error)) + return FALSE; + + if (revision) + { + if (!add_kargs_from_commit (self, kargs_configs, deployment_dfd, + _OSTREE_SYSROOT_KARGS_BASE, revision, + cancellable, error)) + return FALSE; + } + else + { + if (!add_kargs_from_filesystem (kargs_configs, deployment_dfd, + _OSTREE_SYSROOT_KARGS_BASE, + cancellable, error)) + return FALSE; + } + + g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new (); + g_tree_foreach (kargs_configs, (GTraverseFunc)collect_karg, kargs); + g_autofree char *kargs_contents = _ostree_kernel_args_to_string (kargs); - /* Only use the merge if we didn't get an override */ + ot_transfer_out_value (out_kargs, &kargs_contents); + return TRUE; +} + +static gboolean +sysroot_finalize_kargs (OstreeSysroot *self, + OstreeDeployment *merge_deployment, + OstreeDeployment *deployment, + int deployment_dfd, + const char *revision, + char **override_kernel_argv, + GCancellable *cancellable, + GError **error) +{ + /* If we didn't get an override in this deployment, and we got a merge + * deployment, check if we should copy the kargs from the merge + * deployment. */ + gboolean kargs_generated_from_config = FALSE; if (!override_kernel_argv && merge_deployment) { - /* Override the bootloader arguments */ OstreeBootconfigParser *merge_bootconfig = ostree_deployment_get_bootconfig (merge_deployment); if (merge_bootconfig) { - const char *opts = ostree_bootconfig_parser_get (merge_bootconfig, "options"); - ostree_bootconfig_parser_set (ostree_deployment_get_bootconfig (deployment), "options", opts); + kargs_generated_from_config = g_strcmp0 (ostree_bootconfig_parser_get (merge_bootconfig, + "ostree-kargs-generated-from-config"), + "true") == 0; + if (!kargs_generated_from_config) + { + /* Copy kargs from the merge deployment. */ + const char *opts = ostree_bootconfig_parser_get (merge_bootconfig, + "options"); + bootconfig_set_kargs (ostree_deployment_get_bootconfig (deployment), + opts, FALSE); + } } + } + /* If we didn't get an override in this deployment, and we received + * indication to regenerate kargs from the deployment config, regenerate + * the kargs. If there is no merge deployment (e.g. this is the first + * deployment), then default to regenerating kargs from this deployment. */ + if (!override_kernel_argv && (kargs_generated_from_config || !merge_deployment)) + { + g_autofree char *opts = NULL; + if (!sysroot_regenerate_kargs (self, revision, deployment_dfd, &opts, + cancellable, error)) + return FALSE; + bootconfig_set_kargs (ostree_deployment_get_bootconfig (deployment), + opts, TRUE); } + return TRUE; +} + +static gboolean +sysroot_finalize_deployment (OstreeSysroot *self, + OstreeDeployment *deployment, + const char *revision, + char **override_kernel_argv, + OstreeDeployment *merge_deployment, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) + return FALSE; + if (merge_deployment) { - /* And do the /etc merge */ - if (!merge_configuration_from (self, merge_deployment, deployment, deployment_dfd, - cancellable, error)) + /* Do the /etc merge. */ + if (!merge_configuration_from (self, merge_deployment, deployment, + deployment_dfd, cancellable, error)) return FALSE; } + if (!sysroot_finalize_kargs (self, merge_deployment, deployment, deployment_dfd, + revision, override_kernel_argv, cancellable, error)) + return FALSE; + const char *osdeploypath = glnx_strjoina ("ostree/deploy/", ostree_deployment_get_osname (deployment)); glnx_autofd int os_deploy_dfd = -1; if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error)) @@ -2676,7 +2904,8 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, &deployment, cancellable, error)) return FALSE; - if (!sysroot_finalize_deployment (self, deployment, override_kernel_argv, + if (!sysroot_finalize_deployment (self, deployment, revision, + override_kernel_argv, provided_merge_deployment, cancellable, error)) return FALSE; @@ -2743,7 +2972,6 @@ _ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, bootcsum, -1); } - /** * ostree_sysroot_stage_tree: * @self: Sysroot @@ -2949,8 +3177,9 @@ _ostree_sysroot_finalize_staged (OstreeSysroot *self, if (!glnx_unlinkat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, 0, error)) return FALSE; - if (!sysroot_finalize_deployment (self, self->staged_deployment, kargs, merge_deployment, - cancellable, error)) + const char *revision = self->staged_deployment->csum; + if (!sysroot_finalize_deployment (self, self->staged_deployment, revision, + kargs, merge_deployment, cancellable, error)) return FALSE; /* Now, take ownership of the staged state, as normally the API below strips @@ -2980,6 +3209,70 @@ _ostree_sysroot_finalize_staged (OstreeSysroot *self, return TRUE; } +/* Import kargs into the deployment, by first writing an empty file + * in the host kargs config for every karg snippet in the commit base config + * to clear the kargs, then writing a new file import_kargs_name containing + * the new kargs in import_kargs_contents. */ +static gboolean +deployment_import_kargs (int deployment_dfd, + const char *import_kargs_name, + const char *import_kargs_contents, + GCancellable *cancellable, + GError **error) +{ + if (!glnx_shutil_mkdir_p_at (deployment_dfd, _OSTREE_SYSROOT_KARGS_HOST, + 0755, cancellable, error)) + return FALSE; + int host_kargs_dfd = -1; + if (!glnx_opendirat (deployment_dfd, _OSTREE_SYSROOT_KARGS_HOST, TRUE, + &host_kargs_dfd, error)) + return FALSE; + + int base_kargs_dfd = -1; + if (!ot_openat_ignore_enoent (deployment_dfd, _OSTREE_SYSROOT_KARGS_BASE, + &base_kargs_dfd, error)) + return FALSE; + if (base_kargs_dfd > 0) + { + g_auto(GLnxDirFdIterator) base_dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (base_kargs_dfd, ".", TRUE, + &base_dfd_iter, error)) + return FALSE; + while (TRUE) + { + struct dirent *dent = NULL; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&base_dfd_iter, + &dent, cancellable, + error)) + return FALSE; + if (dent == NULL) + break; + + if (!(dent->d_type == DT_REG || dent->d_type == DT_LNK)) + continue; + + const char *base_karg_name = dent->d_name; + g_autofree char *empty_string = g_strdup (""); + if (!glnx_file_replace_contents_at (host_kargs_dfd, + base_karg_name, + (guint8*)empty_string, + strlen(empty_string), + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + } + } + + if (!glnx_file_replace_contents_at (host_kargs_dfd, import_kargs_name, + (guint8*)import_kargs_contents, + strlen(import_kargs_contents), + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + return TRUE; +} + /** * ostree_sysroot_deployment_set_kargs: * @self: Sysroot @@ -3002,12 +3295,39 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self, g_assert (!ostree_deployment_is_staged (deployment)); g_autoptr(OstreeDeployment) new_deployment = ostree_deployment_clone (deployment); + OstreeBootconfigParser *prev_bootconfig = ostree_deployment_get_bootconfig (deployment); OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (new_deployment); g_autoptr(OstreeKernelArgs) kargs = _ostree_kernel_args_new (); _ostree_kernel_args_append_argv (kargs, new_kargs); g_autofree char *new_options = _ostree_kernel_args_to_string (kargs); - ostree_bootconfig_parser_set (new_bootconfig, "options", new_options); + + const gboolean kargs_generated_from_config = g_strcmp0 (ostree_bootconfig_parser_get (prev_bootconfig, + "ostree-kargs-generated-from-config"), + "true") == 0; + if (kargs_generated_from_config) + { + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, new_deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, + &deployment_dfd, error)) + return FALSE; + + if (!deployment_import_kargs (deployment_dfd, "4000_ostree_instutil", + new_options, cancellable, error)) + return FALSE; + + g_autofree char *opts = NULL; + if (!sysroot_regenerate_kargs (self, NULL, deployment_dfd, &opts, + cancellable, error)) + return FALSE; + + bootconfig_set_kargs (new_bootconfig, opts, TRUE); + } + else + { + bootconfig_set_kargs (new_bootconfig, new_options, FALSE); + } g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); for (guint i = 0; i < self->deployments->len; i++) diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index e4b2039e2f..f94902707d 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -79,6 +79,8 @@ struct OstreeSysroot { #define _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED "/run/ostree/staged-deployment-locked" #define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/" #define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development" +#define _OSTREE_SYSROOT_KARGS_HOST "etc/ostree/kargs.d" +#define _OSTREE_SYSROOT_KARGS_BASE "usr/lib/ostree-boot/kargs.d" void _ostree_sysroot_emit_journal_msg (OstreeSysroot *self, diff --git a/tests/libtest.sh b/tests/libtest.sh index e0022512e0..7980d46610 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -512,6 +512,55 @@ os_repository_new_commit () cd ${test_tmpdir} } +# TODO: deduplicate this with os_repository_new_commit() +os_repository_commit () +{ + repo=${1:-testos-repo} + boot_checksum_iteration=${2:-0} + content_iteration=${3:-0} + branch=${4:-testos/buildmaster/x86_64-runtime} + export version=${5:-$(date "+%Y%m%d.${content_iteration}")} + echo "BOOT ITERATION: $boot_checksum_iteration" + cd ${test_tmpdir}/osdata + kver=3.6.0 + if test -f usr/lib/modules/${kver}/vmlinuz; then + bootdir=usr/lib/modules/${kver} + else + if test -d usr/lib/ostree-boot; then + bootdir=usr/lib/ostree-boot + else + bootdir=boot + fi + fi + rm ${bootdir}/* + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + 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 + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/${repo} commit --add-metadata-string "version=${version}" -b $branch -s "Build" + cd ${test_tmpdir} +} + +os_tree_write_file () +{ + path=${1} + contents="${2}" + cd ${test_tmpdir}/osdata + echo "${contents}" > ${path} + cd ${test_tmpdir} +} + _have_user_xattrs='' have_user_xattrs() { assert_has_setfattr diff --git a/tests/test-admin-deploy-karg-default.sh b/tests/test-admin-deploy-karg-default.sh new file mode 100755 index 0000000000..9d7a184e1a --- /dev/null +++ b/tests/test-admin-deploy-karg-default.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# +# Copyright (C) 2019 Robert Fairley +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..7" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} +# Check we generate kargs from the kargs.d configs from the first deployment. +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'ostree-kargs-generated-from-config.*true' + +initial_rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "initial_rev=${initial_rev}" + +# Configure kargs stored in the ostree commit. +mkdir -p osdata/usr/lib/ostree-boot/kargs.d +os_tree_write_file "usr/lib/ostree-boot/kargs.d/4000_FOO" "FOO=USR_1" +os_tree_write_file "usr/lib/ostree-boot/kargs.d/4001_FOO2" "FOO2=USR_2" +os_repository_commit "testos-repo" + +# Upgrade to tree with newly-committed kargs files. +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +# Sanity check a new boot directory was created after upgrading. +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=USR_1.*FOO2=USR_2' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs base config" + +# Configure kargs stored in the default configuration (/usr/etc). +mkdir -p osdata/usr/etc/ostree/kargs.d +os_tree_write_file "usr/etc/ostree/kargs.d/8000_MOO" "MOO=ETC_USR_1" +os_tree_write_file "usr/etc/ostree/kargs.d/8001_MOO2" "MOO2=ETC_USR_2" +os_repository_commit "testos-repo" + +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=USR_1.*FOO2=USR_2.*MOO=ETC_USR_1.*MOO2=ETC_USR_2' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs default config" + +# Configure kargs through the host config file. +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" +etc=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc +assert_has_dir ${etc} +mkdir -p ${etc}/ostree/kargs.d +# Configure a new karg (append). +echo "HELLO=ETC_1" > ${etc}/ostree/kargs.d/2000_HELLO +# Overwrite existing karg from /usr/etc/ostree/kargs.d (replace). +echo "MOO=ETC_2" > ${etc}/ostree/kargs.d/8000_MOO +# Overwrite existing karg from /usr/lib/ostree-boot/kargs.d (replace). +echo "FOO=ETC_3" > ${etc}/ostree/kargs.d/4000_FOO + +# Re-deploy with host-configured kernel args. +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*HELLO=ETC_1.*FOO=ETC_3.*FOO2=USR_2.*MOO=ETC_2.*MOO2=ETC_USR_2' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'MOO=ETC_USR_1' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO=USR_1' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs host config" + +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" +etc=sysroot/ostree/deploy/testos/deploy/${rev}.1/etc +mkdir -p ${etc}/ostree/kargs.d +# Clear base kargs by writing an empty file which overrides them (delete). +echo "" > ${etc}/ostree/kargs.d/8000_MOO +echo "" > ${etc}/ostree/kargs.d/4000_FOO + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*HELLO=ETC_1.*FOO2=USR_2.*MOO2=ETC_USR_2' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'MOO\>' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO\>' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs delete empty file" + +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" +etc=sysroot/ostree/deploy/testos/deploy/${rev}.2/etc +mkdir -p ${etc}/ostree/kargs.d +rm ${etc}/ostree/kargs.d/8000_MOO +rm ${etc}/ostree/kargs.d/4000_FOO +# Clear base kargs by symlinking to /dev/null. +ln -s /dev/null ${etc}/ostree/kargs.d/8000_MOO +ln -s /dev/null ${etc}/ostree/kargs.d/4000_FOO + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*HELLO=ETC_1.*FOO2=USR_2.*MOO2=ETC_USR_2' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'MOO\>' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO\>' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs delete /dev/null" + +${CMD_PREFIX} ostree admin upgrade --os=testos --allow-downgrade --override-commit=${initial_rev} + +# Only the config in /etc/ostree/kargs.d remains. +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*HELLO=ETC_1' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'MOO=ETC_USR_1' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'MOO2=ETC_USR_2' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO=USR_1' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO2=USR_2' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs downgrade" + +${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=TESTARG=TESTVALUE testos:testos/buildmaster/x86_64-runtime + +# Check we carry over previous deployment kargs, after passing in a kargs +# override. +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*HELLO=ETC_1.*TESTARG=TESTVALUE' +# Check we won't regenerate from the config again. +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok default kargs overridden" diff --git a/tests/test-admin-deploy-karg.sh b/tests/test-admin-deploy-karg.sh index aade011ce9..2cc8b7d966 100755 --- a/tests/test-admin-deploy-karg.sh +++ b/tests/test-admin-deploy-karg.sh @@ -26,13 +26,15 @@ set -euo pipefail # Exports OSTREE_SYSROOT so --sysroot not needed. setup_os_repository "archive" "syslinux" -echo "1..3" +echo "1..5" ${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 deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +# Check the kargs are not being updated from the kargs.d configs. +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'ostree-kargs-generated-from-config.*true' ${CMD_PREFIX} ostree admin deploy --karg=FOO=BAR --os=testos testos:testos/buildmaster/x86_64-runtime ${CMD_PREFIX} ostree admin deploy --karg=TESTARG=TESTVALUE --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAR' @@ -61,9 +63,26 @@ echo "ok deploy --karg-proc-cmdline" ${CMD_PREFIX} ostree admin status ${CMD_PREFIX} ostree admin undeploy 0 -${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=APPENDARG=VALAPPEND --karg-append=APPENDARG=2NDAPPEND testos:testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=APPENDARG=VALAPPEND --karg-append=APPENDARG=2NDAPPEND testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=BAR' assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*TESTARG=TESTVALUE' assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*APPENDARG=VALAPPEND .*APPENDARG=2NDAPPEND' +# Check the kargs are still not being updated from the kargs.d configs. +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' echo "ok deploy --karg-append" + +${CMD_PREFIX} ostree admin status +${CMD_PREFIX} ostree admin undeploy 0 + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok no true kargs generated from config flag" + +${CMD_PREFIX} ostree admin status + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +echo "ok no true kargs generated from config flag persists" diff --git a/tests/test-admin-instutil-set-kargs.sh b/tests/test-admin-instutil-set-kargs.sh index 1cb32189dc..e065c64dfe 100755 --- a/tests/test-admin-instutil-set-kargs.sh +++ b/tests/test-admin-instutil-set-kargs.sh @@ -27,16 +27,27 @@ set -euo pipefail # Exports OSTREE_SYSROOT so --sysroot not needed. setup_os_repository "archive" "syslinux" -echo "1..5" +echo "1..6" ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +# Check we generate kargs from the kargs.d configs from the first deployment. +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'ostree-kargs-generated-from-config.*true' + +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" +etc=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc ${CMD_PREFIX} ostree admin instutil set-kargs FOO=BAR ${CMD_PREFIX} ostree admin instutil set-kargs FOO=BAZ FOO=BIF TESTARG=TESTVALUE KEYWORD EMPTYLIST= assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAR' assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAZ .*FOO=BIF' assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*TESTARG=TESTVALUE KEYWORD EMPTYLIST=' + +# Check that the configured kargs flags and snippet were written. +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'ostree-kargs-generated-from-config.*true' +assert_file_has_content ${etc}/ostree/kargs.d/4000_ostree_instutil 'FOO=BAZ .*FOO=BIF.*TESTARG=TESTVALUE KEYWORD EMPTYLIST=' + echo "ok instutil set-kargs (basic)" ${CMD_PREFIX} ostree admin instutil set-kargs --merge FOO=BAR @@ -67,3 +78,33 @@ for arg in $(cat /proc/cmdline); do esac done echo "ok instutil set-kargs --import-proc-cmdline" + +# Configure kargs stored in the ostree commit. +mkdir -p osdata/usr/lib/ostree-boot/kargs.d +os_tree_write_file "usr/lib/ostree-boot/kargs.d/4000_FOO" "FOO=USR_1" +os_tree_write_file "usr/lib/ostree-boot/kargs.d/4001_FOO2" "FOO2=USR_2" +os_repository_commit "testos-repo" + +# Upgrade to tree with newly-committed kargs files. +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +# Sanity check a new boot directory was created after upgrading. +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=USR_1.*FOO2=USR_2' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' + +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" +etc=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc + +# Check that set-kargs overrides any existing default kargs in /usr/lib/ostree-boot/kargs.d. +${CMD_PREFIX} ostree admin instutil set-kargs FOO=BAR + +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=BAR' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO=USR_1' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'FOO2=USR_2' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'ostree-kargs-generated-from-config.*true' +assert_file_has_content ${etc}/ostree/kargs.d/4000_ostree_instutil 'FOO=BAR' + +echo "ok instutil set-kargs default kargs"