Skip to content

Commit df4ffed

Browse files
cgwalters-botcgwalters
authored andcommitted
libvirt: Retry virsh when the session daemon is restarting
CI intermittently fails bcvk libvirt commands with "Failed to connect socket to '/run/user/1001/libvirt/libvirt-sock': No such file or directory" (bootc-dev/bootc#1843), typically right after a step that used no libvirt for two minutes, such as creating a base disk. The libvirt client auto-spawns the qemu:///session daemon with --timeout=120. When that daemon exits on idle it removes its socket first and releases its pidfile only after its drivers shut down. A client connecting in that window spawns a new daemon, which exits at once because the pidfile is still held, then waits five seconds for a socket nobody will create. A connection failure means virsh never ran its command, so it is safe to run it again; the retry spawns the daemon anew once the old one is gone. Route every virsh invocation through one VirshCommand type that does that for session connections, with a bounded backoff. It doesn't deref to Command, so a call chain can't bypass the retry. Generated-by: AI Signed-off-by: Colin Walters <walters@verbum.org>
1 parent b56c816 commit df4ffed

8 files changed

Lines changed: 285 additions & 35 deletions

File tree

‎crates/kit/src/domain_list.rs‎

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
//! This module provides functionality to list libvirt domains created by bcvk libvirt,
44
//! using libvirt as the source of truth instead of the VmRegistry cache.
55
6+
use crate::libvirt::virsh::VirshCommand;
67
use crate::xml_utils;
78
use base64::Engine;
89
use color_eyre::{eyre::Context, Result};
910
use serde::{Deserialize, Serialize};
10-
use std::process::Command;
1111
use std::time::SystemTime;
1212

1313
/// Information about a podman-bootc domain from libvirt
@@ -87,13 +87,8 @@ impl DomainLister {
8787
}
8888

8989
/// Build a virsh command with optional connection URI
90-
fn virsh_command(&self) -> Command {
91-
let mut cmd = Command::new("virsh");
92-
cmd.env("LC_ALL", "C");
93-
if let Some(ref uri) = self.connect_uri {
94-
cmd.arg("-c").arg(uri);
95-
}
96-
cmd
90+
fn virsh_command(&self) -> VirshCommand {
91+
VirshCommand::new(self.connect_uri.as_deref())
9792
}
9893

9994
/// List all domains (running and inactive)

‎crates/kit/src/libvirt/list_volumes.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
//! This module provides functionality to discover and list bootc volumes
44
//! with their container image metadata and creation information.
55
6+
use crate::libvirt::virsh::VirshCommand;
67
use clap::Parser;
78
use color_eyre::{eyre::eyre, Result};
89
use comfy_table::{presets::UTF8_FULL, Table};
910
use serde_json::{json, Value};
10-
use std::process::Command;
1111
use tracing::{debug, warn};
1212

1313
/// Configuration options for listing bootc volumes
@@ -71,7 +71,7 @@ impl BootcVolume {
7171

7272
impl LibvirtListVolumesOpts {
7373
/// Build a virsh command with optional connection URI
74-
fn virsh_command(&self, global_opts: &crate::libvirt::LibvirtOptions) -> Command {
74+
fn virsh_command(&self, global_opts: &crate::libvirt::LibvirtOptions) -> VirshCommand {
7575
global_opts.virsh_command()
7676
}
7777

‎crates/kit/src/libvirt/mod.rs‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub mod start;
4040
pub mod status;
4141
pub mod stop;
4242
pub mod upload;
43+
pub mod virsh;
4344

4445
/// Global options for libvirt operations
4546
#[derive(Debug, Clone, Default)]
@@ -50,13 +51,8 @@ pub struct LibvirtOptions {
5051

5152
impl LibvirtOptions {
5253
/// Create a virsh Command with the appropriate connection URI
53-
pub fn virsh_command(&self) -> std::process::Command {
54-
let mut cmd = std::process::Command::new("virsh");
55-
cmd.env("LC_ALL", "C");
56-
if let Some(ref uri) = self.connect {
57-
cmd.arg("-c").arg(uri);
58-
}
59-
cmd
54+
pub fn virsh_command(&self) -> virsh::VirshCommand {
55+
virsh::VirshCommand::new(self.connect.as_deref())
6056
}
6157
}
6258

‎crates/kit/src/libvirt/run.rs‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,8 @@ const SSH_WAIT_TIMEOUT_SECONDS: u64 = 180;
2727
const UPDATE_FROM_HOST_TRANSPORT: &str = "containers-storage";
2828

2929
/// Create a virsh command with optional connection URI
30-
pub(super) fn virsh_command(connect_uri: Option<&str>) -> Result<std::process::Command> {
31-
let mut cmd = std::process::Command::new("virsh");
32-
cmd.env("LC_ALL", "C");
33-
if let Some(uri) = connect_uri {
34-
cmd.arg("-c").arg(uri);
35-
}
36-
Ok(cmd)
30+
pub(super) fn virsh_command(connect_uri: Option<&str>) -> Result<super::virsh::VirshCommand> {
31+
Ok(super::virsh::VirshCommand::new(connect_uri))
3732
}
3833

3934
/// Run a virsh command and handle errors consistently

‎crates/kit/src/libvirt/status.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
//! This module provides a status command that outputs JSON metadata about
44
//! the libvirt environment, including version information and domain count.
55
6+
use crate::libvirt::virsh::VirshCommand;
67
use clap::Parser;
78
use color_eyre::{eyre::Context, Result};
89
use serde::{Deserialize, Serialize};
9-
use std::process::Command;
1010

1111
use crate::domain_list::DomainLister;
1212

@@ -98,7 +98,7 @@ fn parse_libvirt_version_from_output(version_output: &str) -> Option<LibvirtVers
9898

9999
/// Parse libvirt version from virsh version output
100100
pub fn parse_libvirt_version() -> Result<Option<LibvirtVersion>> {
101-
let output = Command::new("virsh")
101+
let output = VirshCommand::new(None)
102102
.args(&["version"])
103103
.output()
104104
.with_context(|| "Failed to check libvirt version")?;

‎crates/kit/src/libvirt/upload.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
66
use crate::common_opts::MemoryOpts;
77
use crate::install_options::InstallOptions;
8+
use crate::libvirt::virsh::VirshCommand;
89
use crate::to_disk::{run as to_disk, ToDiskAdditionalOpts, ToDiskOpts};
910
use crate::{images, utils};
1011
use camino::Utf8PathBuf;
1112
use clap::Parser;
1213
use color_eyre::{eyre::eyre, Result};
1314
use std::path::Path;
14-
use std::process::Command;
1515
use tracing::debug;
1616

1717
/// Configuration options for uploading a bootc disk image to libvirt
@@ -46,7 +46,7 @@ pub struct LibvirtUploadOpts {
4646

4747
impl LibvirtUploadOpts {
4848
/// Build a virsh command with optional connection URI
49-
fn virsh_command(&self, global_opts: &crate::libvirt::LibvirtOptions) -> Command {
49+
fn virsh_command(&self, global_opts: &crate::libvirt::LibvirtOptions) -> VirshCommand {
5050
global_opts.virsh_command()
5151
}
5252

0 commit comments

Comments
 (0)