Skip to content

Commit 02f25b7

Browse files
committed
libvirt: Add creation timestamp to base disks output
Because it's useful to know. Signed-off-by: Colin Walters <walters@verbum.org>
1 parent b6a0a1f commit 02f25b7

6 files changed

Lines changed: 91 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/integration-tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ libtest-mimic = "0.7.3"
3131
tempfile = "3"
3232
uuid = { version = "1.18.1", features = ["v4"] }
3333
camino = "1.1.12"
34+
regex = "1"

crates/integration-tests/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ fn main() {
299299
tests::libvirt_base_disks::test_base_disks_list_command();
300300
Ok(())
301301
}),
302+
Trial::test("libvirt_base_disks_list_shows_timestamp", || {
303+
tests::libvirt_base_disks::test_base_disks_list_shows_timestamp();
304+
Ok(())
305+
}),
302306
Trial::test("libvirt_base_disks_prune_dry_run", || {
303307
tests::libvirt_base_disks::test_base_disks_prune_dry_run();
304308
Ok(())

crates/integration-tests/src/tests/libvirt_base_disks.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use std::process::Command;
1010

1111
use crate::{get_bck_command, get_test_image, run_bcvk};
12+
use regex::Regex;
1213

1314
/// Test that base disk is created and reused for multiple VMs
1415
pub fn test_base_disk_creation_and_reuse() {
@@ -131,6 +132,75 @@ pub fn test_base_disks_list_command() {
131132
}
132133
}
133134

135+
/// Test base-disks list shows creation timestamp
136+
pub fn test_base_disks_list_shows_timestamp() {
137+
let test_image = get_test_image();
138+
let bck = get_bck_command().unwrap();
139+
140+
println!("Testing base-disks list shows creation timestamp");
141+
142+
let timestamp = std::time::SystemTime::now()
143+
.duration_since(std::time::UNIX_EPOCH)
144+
.unwrap()
145+
.as_secs();
146+
let vm_name = format!("test-base-timestamp-{}", timestamp);
147+
148+
cleanup_domain(&vm_name);
149+
150+
// Create a VM to ensure we have at least one base disk
151+
println!("Creating VM to generate base disk...");
152+
let vm_output = run_bcvk(&[
153+
"libvirt",
154+
"run",
155+
"--name",
156+
&vm_name,
157+
"--filesystem",
158+
"ext4",
159+
&test_image,
160+
])
161+
.expect("Failed to create VM");
162+
163+
if !vm_output.success() {
164+
cleanup_domain(&vm_name);
165+
panic!("Failed to create VM: {}", vm_output.stderr);
166+
}
167+
168+
// Run base-disks list
169+
let output = Command::new(&bck)
170+
.args(["libvirt", "base-disks", "list"])
171+
.output()
172+
.expect("Failed to run base-disks list");
173+
174+
let stdout = String::from_utf8_lossy(&output.stdout);
175+
let stderr = String::from_utf8_lossy(&output.stderr);
176+
177+
cleanup_domain(&vm_name);
178+
179+
if output.status.success() {
180+
println!("base-disks list output:\n{}", stdout);
181+
182+
// Should have CREATED column in header
183+
assert!(
184+
stdout.contains("CREATED"),
185+
"Should show CREATED column in header"
186+
);
187+
188+
// Should show timestamp values (either a date or "unknown")
189+
// Timestamp format is YYYY-MM-DD HH:MM
190+
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}|unknown").unwrap();
191+
let has_timestamp = re.is_match(&stdout);
192+
assert!(
193+
has_timestamp,
194+
"Should show timestamp values in CREATED column"
195+
);
196+
197+
println!("✓ base-disks list shows creation timestamp");
198+
} else {
199+
println!("base-disks list failed: {}", stderr);
200+
panic!("Failed to run base-disks list: {}", stderr);
201+
}
202+
}
203+
134204
/// Test base-disks prune command with dry-run
135205
pub fn test_base_disks_prune_dry_run() {
136206
let bck = get_bck_command().unwrap();

crates/kit/src/libvirt/base_disks.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,10 @@ pub fn list_base_disks(connect_uri: Option<&str>) -> Result<Vec<BaseDiskInfo>> {
320320
)
321321
.unwrap_or(None);
322322

323-
// Get file size
324-
let size = entry.metadata().ok().map(|m| m.len());
323+
// Get file size and creation time
324+
let metadata = entry.metadata().ok();
325+
let size = metadata.as_ref().map(|m| m.len());
326+
let created = metadata.and_then(|m| m.created().ok());
325327

326328
// Count references
327329
let ref_count = count_base_disk_references(&path, &vm_disks)?;
@@ -331,6 +333,7 @@ pub fn list_base_disks(connect_uri: Option<&str>) -> Result<Vec<BaseDiskInfo>> {
331333
image_digest,
332334
size,
333335
ref_count,
336+
created,
334337
});
335338
}
336339
}
@@ -347,6 +350,7 @@ pub struct BaseDiskInfo {
347350
pub image_digest: Option<String>,
348351
pub size: Option<u64>,
349352
pub ref_count: usize,
353+
pub created: Option<std::time::SystemTime>,
350354
}
351355

352356
/// Prune unreferenced base disks

crates/kit/src/libvirt/base_disks_cli.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn run_list(connect_uri: Option<&str>, opts: ListOpts) -> Result<()> {
6666

6767
let mut table = Table::new();
6868
table.load_preset(UTF8_FULL);
69-
table.set_header(vec!["NAME", "SIZE", "REFS", "IMAGE DIGEST"]);
69+
table.set_header(vec!["NAME", "SIZE", "REFS", "CREATED", "IMAGE DIGEST"]);
7070

7171
for disk in &base_disks {
7272
let name = disk.path.file_name().unwrap_or("unknown");
@@ -78,6 +78,13 @@ fn run_list(connect_uri: Option<&str>, opts: ListOpts) -> Result<()> {
7878

7979
let refs = disk.ref_count.to_string();
8080

81+
let created = disk
82+
.created
83+
.and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
84+
.and_then(|d| chrono::DateTime::from_timestamp(d.as_secs() as i64, 0))
85+
.map(|dt| dt.format("%Y-%m-%d %H:%M").to_string())
86+
.unwrap_or_else(|| "unknown".to_string());
87+
8188
let digest = disk
8289
.image_digest
8390
.as_ref()
@@ -91,7 +98,7 @@ fn run_list(connect_uri: Option<&str>, opts: ListOpts) -> Result<()> {
9198
})
9299
.unwrap_or_else(|| "<no metadata>".to_string());
93100

94-
table.add_row(vec![name, &size, &refs, &digest]);
101+
table.add_row(vec![name, &size, &refs, &created, &digest]);
95102
}
96103

97104
println!("{}", table);

0 commit comments

Comments
 (0)