import bootc-0.1.14-1.el9_4

c9 imports/c9/bootc-0.1.14-1.el9_4
MSVSphere Packaging Team 5 months ago
parent 246591d2b4
commit 63ae4000c8

@ -1,2 +1,2 @@
f1b1bc4ec3e566de914724b4e9285d3068a5ecf7 SOURCES/bootc-0.1.9-vendor.tar.zstd 991b2e05a2bb38d011e1d15a1bd6841e3ca8ad5a SOURCES/bootc-0.1.14-vendor.tar.zstd
0be0692496faa3b690fe5a7402cbde4b49985b0f SOURCES/bootc-0.1.9.tar.zstd 8aa9c8103f0eed46b9b59747021c6ccdc9e67f75 SOURCES/bootc-0.1.14.tar.zstd

4
.gitignore vendored

@ -1,2 +1,2 @@
SOURCES/bootc-0.1.9-vendor.tar.zstd SOURCES/bootc-0.1.14-vendor.tar.zstd
SOURCES/bootc-0.1.9.tar.zstd SOURCES/bootc-0.1.14.tar.zstd

@ -1,321 +0,0 @@
From 04baad3080246b1ce26df7a783874b2b1b3ddaa4 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Sat, 9 Mar 2024 15:33:27 -0500
Subject: [PATCH] Add a `rollback` verb and `rollbackQueued` status
I'd really hoped to do something more declarative here, and
really flesh out the intersections with automated upgrades
and automated rollbacks.
But, this just exposes the simple primitive, equivalent
to `rpm-ostree rollback`.
Signed-off-by: Colin Walters <walters@verbum.org>
---
lib/src/cli.rs | 33 ++++++++++++
lib/src/deploy.rs | 61 ++++++++++++++++++++++-
lib/src/spec.rs | 40 +++++++++++++++
lib/src/status.rs | 15 +++++-
tests/integration/playbooks/rollback.yaml | 4 +-
5 files changed, 148 insertions(+), 5 deletions(-)
diff --git a/lib/src/cli.rs b/lib/src/cli.rs
index 42bfbcc..623796a 100644
--- a/lib/src/cli.rs
+++ b/lib/src/cli.rs
@@ -89,6 +89,10 @@ pub(crate) struct SwitchOpts {
pub(crate) target: String,
}
+/// Options controlling rollback
+#[derive(Debug, Parser, PartialEq, Eq)]
+pub(crate) struct RollbackOpts {}
+
/// Perform an edit operation
#[derive(Debug, Parser, PartialEq, Eq)]
pub(crate) struct EditOpts {
@@ -214,6 +218,18 @@ pub(crate) enum Opt {
/// This operates in a very similar fashion to `upgrade`, but changes the container image reference
/// instead.
Switch(SwitchOpts),
+ /// Change the bootloader entry ordering; the deployment under `rollback` will be queued for the next boot,
+ /// and the current will become rollback. If there is a `staged` entry (an unapplied, queued upgrade)
+ /// then it will be discarded.
+ ///
+ /// Note that absent any additional control logic, if there is an active agent doing automated upgrades
+ /// (such as the default `bootc-fetch-apply-updates.timer` and associated `.service`) the
+ /// change here may be reverted. It's recommended to only use this in concert with an agent that
+ /// is in active control.
+ ///
+ /// A systemd journal message will be logged with `MESSAGE_ID=26f3b1eb24464d12aa5e7b544a6b5468` in
+ /// order to detect a rollback invocation.
+ Rollback(RollbackOpts),
/// Apply full changes to the host specification.
///
/// This command operates very similarly to `kubectl apply`; if invoked interactively,
@@ -500,6 +516,14 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
Ok(())
}
+/// Implementation of the `bootc rollback` CLI command.
+#[context("Rollback")]
+async fn rollback(_opts: RollbackOpts) -> Result<()> {
+ prepare_for_write().await?;
+ let sysroot = &get_locked_sysroot().await?;
+ crate::deploy::rollback(sysroot).await
+}
+
/// Implementation of the `bootc edit` CLI command.
#[context("Editing spec")]
async fn edit(opts: EditOpts) -> Result<()> {
@@ -522,7 +546,15 @@ async fn edit(opts: EditOpts) -> Result<()> {
println!("Edit cancelled, no changes made.");
return Ok(());
}
+ host.spec.verify_transition(&new_host.spec)?;
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
+
+ // We only support two state transitions right now; switching the image,
+ // or flipping the bootloader ordering.
+ if host.spec.boot_order != new_host.spec.boot_order {
+ return crate::deploy::rollback(sysroot).await;
+ }
+
let fetched = crate::deploy::pull(sysroot, new_spec.image, opts.quiet).await?;
// TODO gc old layers here
@@ -586,6 +618,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
match opt {
Opt::Upgrade(opts) => upgrade(opts).await,
Opt::Switch(opts) => switch(opts).await,
+ Opt::Rollback(opts) => rollback(opts).await,
Opt::Edit(opts) => edit(opts).await,
Opt::UsrOverlay => usroverlay().await,
#[cfg(feature = "install")]
diff --git a/lib/src/deploy.rs b/lib/src/deploy.rs
index 444ad8e..3eb31a8 100644
--- a/lib/src/deploy.rs
+++ b/lib/src/deploy.rs
@@ -5,7 +5,7 @@
use std::io::{BufRead, Write};
use anyhow::Ok;
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
use cap_std::fs::{Dir, MetadataExt};
use cap_std_ext::cap_std;
@@ -19,8 +19,8 @@ use ostree_ext::ostree;
use ostree_ext::ostree::Deployment;
use ostree_ext::sysroot::SysrootLock;
-use crate::spec::HostSpec;
use crate::spec::ImageReference;
+use crate::spec::{BootOrder, HostSpec};
use crate::status::labels_of_config;
// TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a
@@ -276,6 +276,63 @@ pub(crate) async fn stage(
Ok(())
}
+/// Implementation of rollback functionality
+pub(crate) async fn rollback(sysroot: &SysrootLock) -> Result<()> {
+ const ROLLBACK_JOURNAL_ID: &str = "26f3b1eb24464d12aa5e7b544a6b5468";
+ let repo = &sysroot.repo();
+ let (booted_deployment, deployments, host) = crate::status::get_status_require_booted(sysroot)?;
+
+ let new_spec = {
+ let mut new_spec = host.spec.clone();
+ new_spec.boot_order = new_spec.boot_order.swap();
+ new_spec
+ };
+
+ // Just to be sure
+ host.spec.verify_transition(&new_spec)?;
+
+ let reverting = new_spec.boot_order == BootOrder::Default;
+ if reverting {
+ println!("notice: Reverting queued rollback state");
+ }
+ let rollback_status = host
+ .status
+ .rollback
+ .ok_or_else(|| anyhow!("No rollback available"))?;
+ let rollback_image = rollback_status
+ .query_image(repo)?
+ .ok_or_else(|| anyhow!("Rollback is not container image based"))?;
+ let msg = format!("Rolling back to image: {}", rollback_image.manifest_digest);
+ libsystemd::logging::journal_send(
+ libsystemd::logging::Priority::Info,
+ &msg,
+ [
+ ("MESSAGE_ID", ROLLBACK_JOURNAL_ID),
+ ("BOOTC_MANIFEST_DIGEST", &rollback_image.manifest_digest),
+ ]
+ .into_iter(),
+ )?;
+ // SAFETY: If there's a rollback status, then there's a deployment
+ let rollback_deployment = deployments.rollback.expect("rollback deployment");
+ let new_deployments = if reverting {
+ [booted_deployment, rollback_deployment]
+ } else {
+ [rollback_deployment, booted_deployment]
+ };
+ let new_deployments = new_deployments
+ .into_iter()
+ .chain(deployments.other)
+ .collect::<Vec<_>>();
+ tracing::debug!("Writing new deployments: {new_deployments:?}");
+ sysroot.write_deployments(&new_deployments, gio::Cancellable::NONE)?;
+ if reverting {
+ println!("Next boot: current deployment");
+ } else {
+ println!("Next boot: rollback deployment");
+ }
+ Ok(())
+}
+
fn find_newest_deployment_name(deploysdir: &Dir) -> Result<String> {
let mut dirs = Vec::new();
for ent in deploysdir.entries()? {
diff --git a/lib/src/spec.rs b/lib/src/spec.rs
index 6de9639..5f6df93 100644
--- a/lib/src/spec.rs
+++ b/lib/src/spec.rs
@@ -28,12 +28,27 @@ pub struct Host {
pub status: HostStatus,
}
+/// Configuration for system boot ordering.
+
+#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
+#[serde(rename_all = "camelCase")]
+pub enum BootOrder {
+ /// The staged or booted deployment will be booted next
+ #[default]
+ Default,
+ /// The rollback deployment will be booted next
+ Rollback,
+}
+
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
/// The host specification
pub struct HostSpec {
/// The host image
pub image: Option<ImageReference>,
+ /// If set, and there is a rollback deployment, it will be set for the next boot.
+ #[serde(default)]
+ pub boot_order: BootOrder,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -121,6 +136,9 @@ pub struct HostStatus {
pub booted: Option<BootEntry>,
/// The previously booted image
pub rollback: Option<BootEntry>,
+ /// Set to true if the rollback entry is queued for the next boot.
+ #[serde(default)]
+ pub rollback_queued: bool,
/// The detected type of system
#[serde(rename = "type")]
@@ -152,6 +170,28 @@ impl Default for Host {
}
}
+impl HostSpec {
+ /// Validate a spec state transition; some changes cannot be made simultaneously,
+ /// such as fetching a new image and doing a rollback.
+ pub(crate) fn verify_transition(&self, new: &Self) -> anyhow::Result<()> {
+ let rollback = self.boot_order != new.boot_order;
+ let image_change = self.image != new.image;
+ if rollback && image_change {
+ anyhow::bail!("Invalid state transition: rollback and image change");
+ }
+ Ok(())
+ }
+}
+
+impl BootOrder {
+ pub(crate) fn swap(&self) -> Self {
+ match self {
+ BootOrder::Default => BootOrder::Rollback,
+ BootOrder::Rollback => BootOrder::Default,
+ }
+ }
+}
+
impl Display for ImageReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// For the default of fetching from a remote registry, just output the image name
diff --git a/lib/src/status.rs b/lib/src/status.rs
index dba4889..e8f1fa5 100644
--- a/lib/src/status.rs
+++ b/lib/src/status.rs
@@ -1,6 +1,6 @@
use std::collections::VecDeque;
-use crate::spec::{BootEntry, Host, HostSpec, HostStatus, HostType, ImageStatus};
+use crate::spec::{BootEntry, BootOrder, Host, HostSpec, HostStatus, HostType, ImageStatus};
use crate::spec::{ImageReference, ImageSignature};
use anyhow::{Context, Result};
use camino::Utf8Path;
@@ -224,11 +224,22 @@ pub(crate) fn get_status(
.iter()
.position(|d| d.is_staged())
.map(|i| related_deployments.remove(i).unwrap());
+ tracing::debug!("Staged: {staged:?}");
// Filter out the booted, the caller already found that
if let Some(booted) = booted_deployment.as_ref() {
related_deployments.retain(|f| !f.equal(booted));
}
let rollback = related_deployments.pop_front();
+ let rollback_queued = match (booted_deployment.as_ref(), rollback.as_ref()) {
+ (Some(booted), Some(rollback)) => rollback.index() < booted.index(),
+ _ => false,
+ };
+ let boot_order = if rollback_queued {
+ BootOrder::Rollback
+ } else {
+ BootOrder::Default
+ };
+ tracing::debug!("Rollback queued={rollback_queued:?}");
let other = {
related_deployments.extend(other_deployments);
related_deployments
@@ -262,6 +273,7 @@ pub(crate) fn get_status(
.and_then(|entry| entry.image.as_ref())
.map(|img| HostSpec {
image: Some(img.image.clone()),
+ boot_order,
})
.unwrap_or_default();
@@ -281,6 +293,7 @@ pub(crate) fn get_status(
staged,
booted,
rollback,
+ rollback_queued,
ty,
};
Ok((deployments, host))
diff --git a/tests/integration/playbooks/rollback.yaml b/tests/integration/playbooks/rollback.yaml
index a801656..e193ff5 100644
--- a/tests/integration/playbooks/rollback.yaml
+++ b/tests/integration/playbooks/rollback.yaml
@@ -6,8 +6,8 @@
failed_counter: "0"
tasks:
- - name: rpm-ostree rollback
- command: rpm-ostree rollback
+ - name: bootc rollback
+ command: bootc rollback
become: true
- name: Reboot to deploy new system
--
2.43.0

@ -1,8 +1,8 @@
%bcond_without check %bcond_without check
Name: bootc Name: bootc
Version: 0.1.9 Version: 0.1.14
Release: 3%{?dist} Release: 1%{?dist}
Summary: Bootable container system Summary: Bootable container system
# Apache-2.0 # Apache-2.0
@ -18,11 +18,10 @@ URL: https://github.com/containers/bootc
Source0: %{url}/releases/download/v%{version}/bootc-%{version}.tar.zstd Source0: %{url}/releases/download/v%{version}/bootc-%{version}.tar.zstd
Source1: %{url}/releases/download/v%{version}/bootc-%{version}-vendor.tar.zstd Source1: %{url}/releases/download/v%{version}/bootc-%{version}-vendor.tar.zstd
Patch0: 0001-Add-a-rollback-verb-and-rollbackQueued-status.patch
# https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval
ExcludeArch: %{ix86} ExcludeArch: %{ix86}
BuildRequires: libzstd-devel
BuildRequires: make BuildRequires: make
BuildRequires: ostree-devel BuildRequires: ostree-devel
BuildRequires: openssl-devel BuildRequires: openssl-devel
@ -83,6 +82,10 @@ Recommends: bootupd
%changelog %changelog
* Mon Jul 29 2024 Joseph Marrero <jmarrero@fedoraproject.org> - 0.1.14-1
- Update to 0.1.14
Resolves: #RHEL-50683, #RHEL-50684, #RHEL-50685
* Thu Mar 28 2024 Colin Walters <walters@verbum.org> - 0.1.9-3 * Thu Mar 28 2024 Colin Walters <walters@verbum.org> - 0.1.9-3
- Backport rollback - Backport rollback
Resolves: #RHEL-30879 Resolves: #RHEL-30879

Loading…
Cancel
Save