Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

install: Add kargs to installation config #206

Merged
merged 2 commits into from
Nov 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/Dockerfile.fcos
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ RUN make test-bin-archive

FROM quay.io/fedora/fedora-coreos:testing-devel
COPY --from=builder /src/target/bootc.tar.zst /tmp
COPY ci/usr usr
RUN tar -xvf /tmp/bootc.tar.zst && ostree container commit
2 changes: 2 additions & 0 deletions ci/usr/lib/bootc/install/50-test-kargs.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[install]
kargs = ["localtestkarg=somevalue", "otherlocalkarg=42"]
17 changes: 14 additions & 3 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,32 @@ in that case you will need to specify `--skip-fetch-check`.

### Operating system install configuration required

The container image **MUST** define its default install configuration. For example,
create `/usr/lib/bootc/install/00-exampleos.toml` with the contents:
The container image **MUST** define its default install configuration. A key choice
that bootc by default leaves up to the operating system image is the root filesystem
type.

To enable `bootc install` as part of your OS/distribution base image,
create a file named `/usr/lib/bootc/install/00-<osname>.toml` with the contents of the form:

```toml
[install]
root-fs-type = "xfs"
```

At the current time, `root-fs-type` is the only available configuration option, and it **MUST** be set.
The `root-fs-type` value **MUST** be set.

Configuration files found in this directory will be merged, with higher alphanumeric values
taking precedence. If for example you are building a derived container image from the above OS,
you could create a `50-myos.toml` that sets `root-fs-type = "btrfs"` which will override the
prior setting.

Other available options, also under the `[install]` section:

`kargs`: This allows setting kernel arguments which apply only at the time of `bootc install`.
This option is particularly useful when creating derived/layered images; for example, a cloud
image may want to have its default `console=` set, in contrast with a default base image.
The values in this field are space separated.

## Installing an "unconfigured" image

The bootc project aims to support generic/general-purpose operating
Expand Down
1 change: 1 addition & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ regex = "1.7.1"
rustix = { "version" = "0.38", features = ["thread", "fs", "system", "process"] }
schemars = { version = "0.8.6", features = ["chrono"] }
serde = { features = ["derive"], version = "1.0.125" }
serde_ignored = "0.1.9"
serde_json = "1.0.64"
serde_yaml = "0.9.17"
serde_with = ">= 1.9.4, < 2"
Expand Down
55 changes: 52 additions & 3 deletions lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,10 @@ pub(crate) mod config {
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename = "install", rename_all = "kebab-case", deny_unknown_fields)]
pub(crate) struct InstallConfiguration {
/// Root filesystem type
pub(crate) root_fs_type: Option<super::baseline::Filesystem>,
/// Kernel arguments, applied at installation time
pub(crate) kargs: Option<Vec<String>>,
}

impl InstallConfiguration {
Expand All @@ -392,7 +395,12 @@ pub(crate) mod config {
*s = Some(o);
}
}
mergeopt(&mut self.root_fs_type, other.root_fs_type)
mergeopt(&mut self.root_fs_type, other.root_fs_type);
if let Some(other_kargs) = other.kargs {
self.kargs
.get_or_insert_with(|| Default::default())
.extend(other_kargs)
}
}
}

Expand All @@ -405,10 +413,18 @@ pub(crate) mod config {
let mut config: Option<InstallConfiguration> = None;
for (_name, path) in fragments {
let buf = std::fs::read_to_string(&path)?;
let c: InstallConfigurationToplevel =
toml::from_str(&buf).with_context(|| format!("Parsing {path:?}"))?;
let mut unused = std::collections::HashSet::new();
let de = toml::Deserializer::new(&buf);
let c: InstallConfigurationToplevel = serde_ignored::deserialize(de, |path| {
unused.insert(path.to_string());
})
.with_context(|| format!("Parsing {path:?}"))?;
for key in unused {
eprintln!("warning: {path:?}: Unknown key {key}");
}
if let Some(config) = config.as_mut() {
if let Some(install) = c.install {
tracing::debug!("Merging install config: {install:?}");
config.merge(install);
}
} else {
Expand All @@ -434,10 +450,43 @@ root-fs-type = "xfs"
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: Some(Filesystem::Ext4),
kargs: None,
}),
};
install.merge(other.install.unwrap());
assert_eq!(install.root_fs_type.unwrap(), Filesystem::Ext4);

let c: InstallConfigurationToplevel = toml::from_str(
r##"[install]
root-fs-type = "ext4"
kargs = ["console=ttyS0", "foo=bar"]
"##,
)
.unwrap();
let mut install = c.install.unwrap();
assert_eq!(install.root_fs_type.unwrap(), Filesystem::Ext4);
let other = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: None,
kargs: Some(
["console=tty0", "nosmt"]
.into_iter()
.map(ToOwned::to_owned)
.collect(),
),
}),
};
install.merge(other.install.unwrap());
assert_eq!(install.root_fs_type.unwrap(), Filesystem::Ext4);
assert_eq!(
install.kargs,
Some(
["console=ttyS0", "foo=bar", "console=tty0", "nosmt"]
.into_iter()
.map(ToOwned::to_owned)
.collect()
)
)
}
}

Expand Down
8 changes: 8 additions & 0 deletions lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ pub(crate) fn install_create_rootfs(
.into_iter()
.flatten()
.chain([rootarg, RW_KARG.to_string(), bootarg].into_iter())
.chain(
state
.install_config
.kargs
.iter()
.flatten()
.map(ToOwned::to_owned),
)
.collect::<Vec<_>>();

mount::mount(&rootdev, &rootfs)?;
Expand Down
14 changes: 13 additions & 1 deletion tests/kolainst/install
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,24 @@ cd $(mktemp -d)

case "${AUTOPKGTEST_REBOOT_MARK:-}" in
"")
podman run --rm -ti --privileged --pid=host -v /usr/bin/bootc:/usr/bin/bootc ${IMAGE} bootc install --target-no-signature-verification --karg=foo=bar ${DEV}
mkdir -p ~/.config/containers
cp -a /etc/ostree/auth.json ~/.config/containers
mkdir -p usr/{lib,bin}
cp -a /usr/lib/bootc usr/lib
cp -a /usr/bin/bootc usr/bin
cat > Dockerfile << EOF
FROM ${IMAGE}
COPY usr usr
EOF
podman build -t localhost/testimage .
podman run --rm -ti --privileged --pid=host --env RUST_LOG=error,bootc_lib::install=debug \
localhost/testimage bootc install --target-no-signature-verification --skip-fetch-check --karg=foo=bar ${DEV}
# In theory we could e.g. wipe the bootloader setup on the primary disk, then reboot;
# but for now let's just sanity test that the install command executes.
lsblk ${DEV}
mount /dev/vda3 /var/mnt
grep foo=bar /var/mnt/loader/entries/*.conf
grep localtestkarg=somevalue /var/mnt/loader/entries/*.conf
grep -Ee '^linux /boot/ostree' /var/mnt/loader/entries/*.conf
umount /var/mnt
echo "ok install"
Expand Down