Skip to content
Draft
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
44 changes: 42 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,49 @@ jobs:
name: tmt-log-PR-${{ github.event.number }}-fedora-43-coreos-${{ env.ARCH }}
path: /var/tmp/tmt

# Test Anaconda installation with SSH verification
# Tests the complete Anaconda workflow including SSH access to installed systems
test-anaconda:
needs: package
runs-on: ubuntu-24.04

strategy:
fail-fast: false
matrix:
test_os: [fedora-43, centos-9]

steps:
- uses: actions/checkout@v6
- name: Bootc Ubuntu Setup
uses: bootc-dev/actions/bootc-ubuntu-setup@main
with:
libvirt: true

- name: Setup env
run: |
BASE=$(just pullspec-for-os base ${{ matrix.test_os }})
echo "BOOTC_base=${BASE}" >> $GITHUB_ENV
echo "BOOTC_variant=ostree" >> $GITHUB_ENV

- name: Download package artifacts
uses: actions/download-artifact@v7
with:
name: packages-${{ matrix.test_os }}
path: target/packages/

- name: Build container and run Anaconda SSH test
run: |
BOOTC_SKIP_PACKAGE=1 just build
# Run Anaconda test with SSH verification directly
just test-anaconda localhost/bootc /tmp/bootc-anaconda-${{ matrix.test_os }}.raw --ssh -- bootc status
just clean-local-images



# Sentinel job for required checks - configure this job name in repository settings
required-checks:
if: always()
needs: [cargo-deny, validate, package, test-integration, test-coreos]
needs: [cargo-deny, validate, package, test-integration, test-coreos, test-anaconda]
runs-on: ubuntu-latest
steps:
- run: exit 1
Expand All @@ -279,4 +318,5 @@ jobs:
needs.validate.result != 'success' ||
needs.package.result != 'success' ||
needs.test-integration.result != 'success' ||
needs.test-coreos.result != 'success'
needs.test-coreos.result != 'success' ||
needs.test-anaconda.result != 'success'
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ test-tmt *ARGS: build
[group('core')]
test-container: build build-units
podman run --rm --read-only localhost/bootc-units /usr/bin/bootc-units
podman run --rm --env=BOOTC_variant={{variant}} --env=BOOTC_base={{base}} {{base_img}} bootc-integration-tests container
podman run --rm --env=BOOTC_variant={{variant}} --env=BOOTC_base={{base}} --mount=type=image,source={{base_img}},target=/run/target {{base_img}} bootc-integration-tests container

# Build and test sealed composefs images
[group('core')]
Expand Down Expand Up @@ -132,6 +132,21 @@ test-tmt-on-coreos *ARGS:
run-container-external-tests:
./tests/container/run {{base_img}}

# Run end-to-end Anaconda installation test
[group('testing')]
test-anaconda IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
cargo xtask anaconda {{IMAGE}} {{OUTPUT}} {{ARGS}}

# Test with auto-detected installer
[group('testing')]
test-anaconda-auto IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
cargo xtask anaconda --installer-type auto {{IMAGE}} {{OUTPUT}} {{ARGS}}

# Test with CentOS Stream installer
[group('testing')]
test-anaconda-centos IMAGE=base_img OUTPUT="test-disk.raw" *ARGS:
cargo xtask anaconda --installer-type centos-stream {{IMAGE}} {{OUTPUT}} {{ARGS}}

# Remove all test VMs created by tmt tests
[group('testing')]
tmt-vm-cleanup:
Expand Down
59 changes: 59 additions & 0 deletions crates/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,45 @@ pub(crate) enum ContainerOpts {
#[clap(last = true)]
args: Vec<OsString>,
},
/// Export container filesystem as a tar archive.
///
/// This command exports the container filesystem in a bootable format with proper
/// SELinux labeling. The output is written to stdout by default or to a specified file.
///
/// Example:
/// bootc container export --experimental /target > output.tar
#[clap(hide = true)]
Export {
/// Acknowledge that this is an experimental command that may change or be removed.
#[clap(long)]
experimental: bool,

/// Format for export output
#[clap(long, default_value = "tar")]
format: ExportFormat,

/// Output file (defaults to stdout)
#[clap(long, short = 'o')]
output: Option<Utf8PathBuf>,

/// Copy kernel and initramfs from /usr/lib/modules to /boot for legacy compatibility.
/// This is useful for installers that expect the kernel in /boot.
#[clap(long)]
kernel_in_boot: bool,

/// Disable SELinux labeling in the exported archive.
#[clap(long)]
disable_selinux: bool,

/// Path to the container filesystem root
target: Utf8PathBuf,
},
}

#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
pub(crate) enum ExportFormat {
/// Export as tar archive
Tar,
}

/// Subcommands which operate on images.
Expand Down Expand Up @@ -1626,6 +1665,26 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
kargs,
args,
} => crate::ukify::build_ukify(&rootfs, &kargs, &args),
ContainerOpts::Export {
experimental,
format,
target,
output,
kernel_in_boot,
disable_selinux,
} => {
if !experimental {
anyhow::bail!("This command requires --experimental");
}
crate::container_export::export(
&format,
&target,
output.as_deref(),
kernel_in_boot,
disable_selinux,
)
.await
}
},
Opt::Completion { shell } => {
use clap_complete::aot::generate;
Expand Down
Loading
Loading