Skip to content

Commit

Permalink
Merge pull request #206 from cgwalters/kargs-install
Browse files Browse the repository at this point in the history
install: Add `kargs` to installation config
  • Loading branch information
cgwalters committed Nov 19, 2023
2 parents ee35410 + 9ba17af commit b87d620
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 7 deletions.
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

0 comments on commit b87d620

Please sign in to comment.