Skip to content

Commit c9226bb

Browse files
authored
[11/n] [sled-agent] move around ZoneImageFileSource logic (#8235)
* Move `ZoneImageFileSource` to illumos-utils and use it in the zone image builder. * Move default file name logic to sled-agent-zone-images, since it cares about that in the context of mupdate override logic. Depends on: * #8190 * everything before that
1 parent d70e0ad commit c9226bb

File tree

7 files changed

+94
-83
lines changed

7 files changed

+94
-83
lines changed

illumos-utils/src/running_zone.rs

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -891,9 +891,12 @@ pub enum InstallZoneError {
891891
err: crate::zone::AdmError,
892892
},
893893

894-
#[error("Failed to find zone image '{image}' from {paths:?}")]
895-
ImageNotFound { image: String, paths: Vec<Utf8PathBuf> },
896-
894+
#[error(
895+
"Failed to find zone image '{}' from {:?}",
896+
file_source.file_name,
897+
file_source.search_paths,
898+
)]
899+
ImageNotFound { file_source: ZoneImageFileSource },
897900
#[error("Attempted to call install() on underspecified ZoneBuilder")]
898901
IncompleteBuilder,
899902
}
@@ -1058,12 +1061,8 @@ pub struct ZoneBuilder<'a> {
10581061
underlay_vnic_allocator: Option<&'a VnicAllocator<Etherstub>>,
10591062
/// Filesystem path at which the installed zone will reside.
10601063
zone_root_path: Option<PathInPool>,
1061-
/// The directories that will be searched for the image tarball for the
1062-
/// provided zone type ([`Self::with_zone_type`]).
1063-
zone_image_paths: Option<&'a [Utf8PathBuf]>,
1064-
/// The file name of the zone image to search for in [`Self::zone_image_paths`].
1065-
/// If unset, defaults to `{zone_type}.tar.gz`.
1066-
zone_image_file_name: Option<&'a str>,
1064+
/// The file source.
1065+
file_source: Option<&'a ZoneImageFileSource>,
10671066
/// The name of the type of zone being created (e.g. "propolis-server")
10681067
zone_type: Option<&'a str>,
10691068
/// Unique ID of the instance of the zone being created. (optional)
@@ -1120,24 +1119,12 @@ impl<'a> ZoneBuilder<'a> {
11201119
self
11211120
}
11221121

1123-
/// The directories that will be searched for the image tarball for the
1124-
/// provided zone type ([`Self::with_zone_type`]).
1125-
pub fn with_zone_image_paths(
1126-
mut self,
1127-
image_paths: &'a [Utf8PathBuf],
1128-
) -> Self {
1129-
self.zone_image_paths = Some(image_paths);
1130-
self
1131-
}
1132-
1133-
/// The file name of the zone image to search for in the zone image
1134-
/// paths ([`Self::with_zone_image_paths`]). If unset, defaults to
1135-
/// `{zone_type}.tar.gz`.
1136-
pub fn with_zone_image_file_name(
1122+
/// The file name and image source.
1123+
pub fn with_file_source(
11371124
mut self,
1138-
image_file_name: &'a str,
1125+
file_source: &'a ZoneImageFileSource,
11391126
) -> Self {
1140-
self.zone_image_file_name = Some(image_file_name);
1127+
self.file_source = Some(file_source);
11411128
self
11421129
}
11431130

@@ -1260,8 +1247,7 @@ impl<'a> ZoneBuilder<'a> {
12601247
log: Some(log),
12611248
underlay_vnic_allocator: Some(underlay_vnic_allocator),
12621249
zone_root_path: Some(mut zone_root_path),
1263-
zone_image_paths: Some(zone_image_paths),
1264-
zone_image_file_name,
1250+
file_source: Some(file_source),
12651251
zone_type: Some(zone_type),
12661252
unique_name,
12671253
datasets: Some(datasets),
@@ -1289,23 +1275,16 @@ impl<'a> ZoneBuilder<'a> {
12891275
let full_zone_name =
12901276
InstalledZone::get_zone_name(zone_type, unique_name);
12911277

1292-
// Looks for the image within `zone_image_path`, in order.
1293-
let image_file_name = match zone_image_file_name {
1294-
Some(image) => image,
1295-
None => &format!("{}.tar.gz", zone_type),
1296-
};
1297-
let zone_image_path = zone_image_paths
1278+
// Look for the image within `file_source.search_paths`, in order.
1279+
let zone_image_path = file_source
1280+
.search_paths
12981281
.iter()
12991282
.find_map(|image_path| {
1300-
let path = image_path.join(image_file_name);
1283+
let path = image_path.join(&file_source.file_name);
13011284
if path.exists() { Some(path) } else { None }
13021285
})
13031286
.ok_or_else(|| InstallZoneError::ImageNotFound {
1304-
image: image_file_name.to_string(),
1305-
paths: zone_image_paths
1306-
.iter()
1307-
.map(|p| p.to_path_buf())
1308-
.collect(),
1287+
file_source: file_source.clone(),
13091288
})?;
13101289

13111290
let mut net_device_names: Vec<String> = opte_ports
@@ -1359,6 +1338,19 @@ impl<'a> ZoneBuilder<'a> {
13591338
}
13601339
}
13611340

1341+
/// Places to look for a zone's image.
1342+
#[derive(Clone, Debug)]
1343+
pub struct ZoneImageFileSource {
1344+
/// The file name to look for.
1345+
pub file_name: String,
1346+
1347+
/// The paths to look for the zone image in.
1348+
///
1349+
/// This represents a high-confidence belief, but not a guarantee, that the
1350+
/// zone image will be found in one of these locations.
1351+
pub search_paths: Vec<Utf8PathBuf>,
1352+
}
1353+
13621354
/// Return true if the service with the given FMRI appears to be an
13631355
/// Oxide-managed service.
13641356
pub fn is_oxide_smf_service(fmri: impl AsRef<str>) -> bool {

sled-agent/src/instance.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use rand::prelude::IteratorRandom;
3939
use sled_agent_config_reconciler::AvailableDatasetsReceiver;
4040
use sled_agent_types::instance::*;
4141
use sled_agent_types::zone_bundle::ZoneBundleCause;
42+
use sled_agent_zone_images::ramdisk_file_source;
4243
use slog::Logger;
4344
use std::net::IpAddr;
4445
use std::net::SocketAddr;
@@ -2003,7 +2004,7 @@ impl InstanceRunner {
20032004
.with_log(self.log.clone())
20042005
.with_underlay_vnic_allocator(&self.vnic_allocator)
20052006
.with_zone_root_path(root)
2006-
.with_zone_image_paths(&["/opt/oxide".into()])
2007+
.with_file_source(&ramdisk_file_source("propolis-server"))
20072008
.with_zone_type("propolis-server")
20082009
.with_unique_name(OmicronZoneUuid::from_untyped_uuid(
20092010
self.propolis_id.into_untyped_uuid(),

sled-agent/src/probe_manager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use sled_agent_config_reconciler::{
2323
AvailableDatasetsReceiver, CurrentlyManagedZpools,
2424
CurrentlyManagedZpoolsReceiver,
2525
};
26+
use sled_agent_zone_images::ramdisk_file_source;
2627
use slog::{Logger, error, warn};
2728
use std::collections::{HashMap, HashSet};
2829
use std::hash::{Hash, Hasher};
@@ -354,7 +355,7 @@ impl ProbeManagerInner {
354355
.with_log(self.log.clone())
355356
.with_underlay_vnic_allocator(&self.vnic_allocator)
356357
.with_zone_root_path(zone_root_path)
357-
.with_zone_image_paths(&["/opt/oxide".into()])
358+
.with_file_source(&ramdisk_file_source("probe"))
358359
.with_zone_type("probe")
359360
.with_unique_name(OmicronZoneUuid::from_untyped_uuid(probe.id))
360361
.with_datasets(&[])

sled-agent/src/services.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,13 @@ impl ServiceManager {
13551355
.map(|d| zone::Device { name: d.to_string() })
13561356
.collect();
13571357

1358+
let zone_type_str = match &request {
1359+
ZoneArgs::Omicron(zone_config) => {
1360+
zone_config.zone_type.kind().zone_prefix()
1361+
}
1362+
ZoneArgs::Switch(_) => "switch",
1363+
};
1364+
13581365
// TODO: `InstallDataset` should be renamed to something more accurate
13591366
// when all the major changes here have landed. Some zones are
13601367
// distributed from the host OS image and are never placed in the
@@ -1366,17 +1373,11 @@ impl ServiceManager {
13661373
ZoneArgs::Switch(_) => &OmicronZoneImageSource::InstallDataset,
13671374
};
13681375
let file_source = self.inner.zone_image_resolver.file_source_for(
1376+
zone_type_str,
13691377
image_source,
13701378
self.inner.internal_disks_rx.current(),
13711379
);
13721380

1373-
let zone_type_str = match &request {
1374-
ZoneArgs::Omicron(zone_config) => {
1375-
zone_config.zone_type.kind().zone_prefix()
1376-
}
1377-
ZoneArgs::Switch(_) => "switch",
1378-
};
1379-
13801381
// We use the fake initialiser for testing
13811382
let mut zone_builder = match self.inner.system_api.fake_install_dir() {
13821383
None => ZoneBuilderFactory::new().builder(),
@@ -1392,15 +1393,12 @@ impl ServiceManager {
13921393
if let Some(vnic) = bootstrap_vnic {
13931394
zone_builder = zone_builder.with_bootstrap_vnic(vnic);
13941395
}
1395-
if let Some(file_name) = &file_source.file_name {
1396-
zone_builder = zone_builder.with_zone_image_file_name(file_name);
1397-
}
13981396
let installed_zone = zone_builder
13991397
.with_log(self.inner.log.clone())
14001398
.with_underlay_vnic_allocator(&self.inner.underlay_vnic_allocator)
14011399
.with_zone_root_path(zone_root_path)
1402-
.with_zone_image_paths(file_source.search_paths.as_slice())
14031400
.with_zone_type(zone_type_str)
1401+
.with_file_source(&file_source)
14041402
.with_datasets(datasets.as_slice())
14051403
.with_filesystems(&filesystems)
14061404
.with_data_links(&data_links)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Utilities to construct `ZoneImageFileSource` instances.
6+
7+
use illumos_utils::running_zone::ZoneImageFileSource;
8+
9+
/// The location to look for images shipped with the RAM disk.
10+
pub const RAMDISK_IMAGE_PATH: &str = "/opt/oxide";
11+
12+
/// Constructs a file source for the RAM disk.
13+
///
14+
/// This accepts a `zone_type` string rather than a `ZoneType` or `ZoneKind`
15+
/// enum because it is used to manage non-Omicron zones like propolis-server.
16+
pub fn ramdisk_file_source(zone_type: &str) -> ZoneImageFileSource {
17+
ZoneImageFileSource {
18+
file_name: install_dataset_file_name(zone_type),
19+
search_paths: vec![RAMDISK_IMAGE_PATH.into()],
20+
}
21+
}
22+
23+
/// Returns the filename for install-dataset images.
24+
pub fn install_dataset_file_name(zone_type: &str) -> String {
25+
format!("{}.tar.gz", zone_type)
26+
}

sled-agent/zone-images/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! to move more code into this crate as appropriate.
99
1010
mod errors;
11+
mod file_source;
1112
mod install_dataset_metadata;
1213
mod mupdate_override;
1314
mod source_resolver;
@@ -16,6 +17,7 @@ mod test_utils;
1617
mod zone_manifest;
1718

1819
pub use errors::*;
20+
pub use file_source::*;
1921
pub use install_dataset_metadata::*;
2022
pub use mupdate_override::*;
2123
pub use source_resolver::*;

sled-agent/zone-images/src/source_resolver.rs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,18 @@
77
use crate::AllMupdateOverrides;
88
use crate::AllZoneManifests;
99
use crate::MupdateOverrideStatus;
10+
use crate::RAMDISK_IMAGE_PATH;
1011
use crate::ZoneManifestStatus;
12+
use crate::install_dataset_file_name;
1113
use camino::Utf8PathBuf;
14+
use illumos_utils::running_zone::ZoneImageFileSource;
1215
use nexus_sled_agent_shared::inventory::OmicronZoneImageSource;
1316
use sled_agent_config_reconciler::InternalDisks;
1417
use sled_agent_config_reconciler::InternalDisksWithBootDisk;
1518
use slog::o;
1619
use std::sync::Arc;
1720
use std::sync::Mutex;
1821

19-
/// Places to look for an Omicron zone image.
20-
pub struct ZoneImageFileSource {
21-
/// A custom file name to look for, if provided.
22-
///
23-
/// The default file name is `<zone_type>.tar.gz`.
24-
pub file_name: Option<String>,
25-
26-
/// The paths to look for the zone image in.
27-
///
28-
/// This represents a high-confidence belief, but not a guarantee, that the
29-
/// zone image will be found in one of these locations.
30-
pub search_paths: Vec<Utf8PathBuf>,
31-
}
32-
3322
/// Resolves [`OmicronZoneImageSource`] instances into file names and search
3423
/// paths.
3524
///
@@ -67,11 +56,12 @@ impl ZoneImageSourceResolver {
6756
/// list of potential paths to search, for a zone image.
6857
pub fn file_source_for(
6958
&self,
59+
zone_type: &str,
7060
image_source: &OmicronZoneImageSource,
7161
internal_disks: InternalDisks,
7262
) -> ZoneImageFileSource {
7363
let inner = self.inner.lock().unwrap();
74-
inner.file_source_for(image_source, internal_disks)
64+
inner.file_source_for(zone_type, image_source, internal_disks)
7565
}
7666
}
7767

@@ -119,22 +109,15 @@ impl ResolverInner {
119109

120110
fn file_source_for(
121111
&self,
112+
zone_type: &str,
122113
image_source: &OmicronZoneImageSource,
123114
internal_disks: InternalDisks,
124115
) -> ZoneImageFileSource {
125-
let file_name = match image_source {
126-
OmicronZoneImageSource::InstallDataset => {
127-
// Use the default file name for install-dataset lookups.
128-
None
129-
}
130-
OmicronZoneImageSource::Artifact { hash } => Some(hash.to_string()),
131-
};
132-
133-
let search_paths = match image_source {
116+
match image_source {
134117
OmicronZoneImageSource::InstallDataset => {
135118
// Look for the image in the ramdisk first
136119
let mut zone_image_paths =
137-
vec![Utf8PathBuf::from("/opt/oxide")];
120+
vec![Utf8PathBuf::from(RAMDISK_IMAGE_PATH)];
138121
// Inject an image path if requested by a test.
139122
if let Some(path) = &self.image_directory_override {
140123
zone_image_paths.push(path.clone());
@@ -146,16 +129,24 @@ impl ResolverInner {
146129
zone_image_paths.push(path);
147130
}
148131

149-
zone_image_paths
132+
ZoneImageFileSource {
133+
file_name: install_dataset_file_name(zone_type),
134+
search_paths: zone_image_paths,
135+
}
150136
}
151-
OmicronZoneImageSource::Artifact { .. } => {
137+
OmicronZoneImageSource::Artifact { hash } => {
152138
// Search both artifact datasets. This iterator starts with the
153139
// dataset for the boot disk (if it exists), and then is followed
154140
// by all other disks.
155-
internal_disks.all_artifact_datasets().collect()
141+
let search_paths =
142+
internal_disks.all_artifact_datasets().collect();
143+
ZoneImageFileSource {
144+
// Images in the artifact store are named by just their
145+
// hash.
146+
file_name: hash.to_string(),
147+
search_paths,
148+
}
156149
}
157-
};
158-
159-
ZoneImageFileSource { file_name, search_paths }
150+
}
160151
}
161152
}

0 commit comments

Comments
 (0)