Skip to content

Commit 817cdf9

Browse files
authored
monitor: One-to-one relationship between guests and images (#75)
so far, we’ve managed the lifecycle of an image like servo-ubuntu2204 like this: - rebuild the image by building a new _profile guest_ (libvirt guest named “**servo-ubuntu2204**”) - destroy the guest with that name, if it exists - recreate the guest from profiles/servo-ubuntu2204/guest.xml - set the disk to /path/to/base/servo-ubuntu2204/base.img@[timestamp] - start the guest, so that it can install tooling, bake in cached builds, etc - destroy the libvirt guest - recreate the guest from profiles/servo-ubuntu2204/guest.xml - set the disk to /path/to/base/servo-ubuntu2204/base.img (symlink) - if successful, symlink /path/to/base/servo-ubuntu2204/base.img to base.img@[timestamp] - if unsuccessful, symlink /path/to/base/servo-ubuntu2204/base.img to base.img@[oldTimestamp] - create runners by cloning that guest into each _runner guest_ (“**ci-runner-servo-ubuntu2204.[number]**”) - clone the disks, but not the guests, with the monitor (so it can be parallelised) - clone the guest, but not the disks, with virt-clone that works well enough for our current setup with libvirt and ZFS, but some hypervisors, like UTM (#64), will require us to treat each virtual machine as a self-contained object, with its own configuration and image files. in UTM, it’s hard to destroy a guest without also destroying its disks. this patch moves the monitor closer to that world, by avoiding the destroy-recreate-configure pattern in image rebuilds. the lifecycle for servo-ubuntu2204 images now looks like this: - rebuild the image by building a new _rebuild guest_ (“**ci-rebuild-servo-ubuntu2204@[timestamp]**”) - create the guest from profiles/servo-ubuntu2204/guest.xml - set the disk to /path/to/base/servo-ubuntu2204/base.img@[timestamp] - start the guest, so that it can install tooling, bake in cached builds, etc - if successful, convert that guest to a new _template guest_ (“**ci-template-servo-ubuntu2204@[timestamp]**”) - conversion just means renaming the guest from “ci-rebuild-…” to “ci-template-…” - if unsuccessful, just destroy that guest - create runners by cloning that guest into each _runner guest_ (“**ci-runner-servo-ubuntu2204.[number]**”) - clone the disks, but not the guests, with the monitor (so it can be parallelised) - clone the guest, but not the disks, with virt-clone bonus: with this patch, failed rebuilds will no longer leave the template in an inconsistent state, with the old image data (good) but the new guest configuration (bad because it may be broken). <img width="771" height="519" alt="image" src="https://github.com/user-attachments/assets/21898110-d243-401a-9e0d-8852d2b74a9a" />
1 parent 23f7b83 commit 817cdf9

File tree

10 files changed

+361
-452
lines changed

10 files changed

+361
-452
lines changed

monitor.toml.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ base_image_max_age = 86400
5252
# Uncomment to skip cached Servo repo updates.
5353
# dont_update_cached_servo_repo = true
5454

55+
# Create libvirt guests for profile templates as “ci-template-<profile_name>.0”. Namespace must not be used by anything else!
56+
# libvirt_template_guest_prefix = "ci-template"
57+
58+
# Create libvirt guests for image rebuilds as “ci-rebuild-<profile_name>.0”. Namespace must not be used by anything else!
59+
# libvirt_rebuild_guest_prefix = "ci-rebuild"
60+
5561
# Create libvirt guests for runners as “ci-runner-<profile_name>.0”. Namespace must not be used by anything else!
5662
# libvirt_runner_guest_prefix = "ci-runner"
5763

monitor/settings/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub struct Toml {
8080
pub main_repo_path: String,
8181
base_image_max_age: u64,
8282
dont_update_cached_servo_repo: Option<bool>,
83+
libvirt_template_guest_prefix: Option<String>,
84+
libvirt_rebuild_guest_prefix: Option<String>,
8385
libvirt_runner_guest_prefix: Option<String>,
8486
pub available_1g_hugepages: usize,
8587
pub available_normal_memory: MemorySize,
@@ -242,6 +244,18 @@ impl Toml {
242244
self.queue_member.unwrap_or(false)
243245
}
244246

247+
pub fn libvirt_template_guest_prefix(&self) -> &str {
248+
self.libvirt_template_guest_prefix
249+
.as_deref()
250+
.unwrap_or("ci-template")
251+
}
252+
253+
pub fn libvirt_rebuild_guest_prefix(&self) -> &str {
254+
self.libvirt_rebuild_guest_prefix
255+
.as_deref()
256+
.unwrap_or("ci-rebuild")
257+
}
258+
245259
pub fn libvirt_runner_guest_prefix(&self) -> &str {
246260
self.libvirt_runner_guest_prefix
247261
.as_deref()

monitor/settings/src/profile.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use jane_eyre::eyre::{self, OptionExt};
12
use serde::{Deserialize, Serialize};
23

34
use crate::{TOML, units::MemorySize};
@@ -20,8 +21,24 @@ pub enum ImageType {
2021
}
2122

2223
impl Profile {
23-
pub fn profile_guest_name(&self) -> String {
24-
format!("{}", self.profile_name)
24+
pub fn snapshot_path_slug(&self, snapshot_name: &str) -> String {
25+
format!("{}@{snapshot_name}", self.profile_name)
26+
}
27+
28+
pub fn template_guest_name(&self, snapshot_name: &str) -> String {
29+
format!(
30+
"{}-{}@{snapshot_name}",
31+
TOML.libvirt_template_guest_prefix(),
32+
self.profile_name
33+
)
34+
}
35+
36+
pub fn rebuild_guest_name(&self, snapshot_name: &str) -> String {
37+
format!(
38+
"{}-{}@{snapshot_name}",
39+
TOML.libvirt_rebuild_guest_prefix(),
40+
self.profile_name
41+
)
2542
}
2643

2744
pub fn runner_guest_name(&self, id: usize) -> String {
@@ -33,3 +50,23 @@ impl Profile {
3350
)
3451
}
3552
}
53+
54+
pub fn parse_template_guest_name(template_guest_name: &str) -> eyre::Result<(&str, &str)> {
55+
let prefix = format!("{}-", TOML.libvirt_template_guest_prefix());
56+
let (profile_key, snapshot_name) = template_guest_name
57+
.strip_prefix(&prefix)
58+
.ok_or_eyre("Failed to strip template guest prefix")?
59+
.split_once("@")
60+
.ok_or_eyre("Failed to split snapshot path slug into profile key and snapshot name")?;
61+
Ok((profile_key, snapshot_name))
62+
}
63+
64+
pub fn parse_rebuild_guest_name(rebuild_guest_name: &str) -> eyre::Result<(&str, &str)> {
65+
let prefix = format!("{}-", TOML.libvirt_rebuild_guest_prefix());
66+
let (profile_key, snapshot_name) = rebuild_guest_name
67+
.strip_prefix(&prefix)
68+
.ok_or_eyre("Failed to strip rebuild guest prefix")?
69+
.split_once("@")
70+
.ok_or_eyre("Failed to split snapshot path slug into profile key and snapshot name")?;
71+
Ok((profile_key, snapshot_name))
72+
}

0 commit comments

Comments
 (0)