Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agent/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ fn zfs_get(dataset: &str, prop: &str) -> Result<String> {
Ok(l[0].to_string())
}

#[cfg_attr(not(target_os = "illumos"), expect(dead_code))]
fn zfs_set(dataset: &str, prop: &str, value: &str) -> Result<()> {
let out = Command::new("/sbin/zfs")
.arg("set")
Expand Down
4 changes: 3 additions & 1 deletion factory/gimlet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ buildomat-types = { path = "../../types" }
anyhow = { workspace = true }
chrono = { workspace = true }
debug_parser = { workspace = true }
devinfo = { workspace = true }
dropshot = { workspace = true }
getopts = { workspace = true }
hyper = { workspace = true }
Expand All @@ -33,3 +32,6 @@ tokio = { workspace = true }
toml = { workspace = true }
usdt = { workspace = true }
uuid = { workspace = true }

[target.'cfg(target_os = "illumos")'.dependencies]
devinfo = { workspace = true }
11 changes: 9 additions & 2 deletions factory/gimlet/src/cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ use std::{
use anyhow::{anyhow, bail, Result};
use buildomat_common::*;

use crate::{disks, efi};
use disks::Slot;
use crate::disks::{self, Slot};

#[derive(Debug)]
struct Status {
Expand Down Expand Up @@ -210,7 +209,10 @@ pub fn cleanup() -> Result<()> {
Ok(())
}

#[cfg(target_os = "illumos")]
fn prepare_m2() -> Result<()> {
use crate::efi;

let disks = disks::list_disks()?;

let Some(d) = disks.get(&Slot::M2(0)) else {
Expand Down Expand Up @@ -305,6 +307,11 @@ fn prepare_m2() -> Result<()> {
Ok(())
}

#[cfg(not(target_os = "illumos"))]
fn prepare_m2() -> Result<()> {
bail!("only works on illumos systems");
}

fn format_disks() -> Result<()> {
/*
* First, list the disks in the system. We expect there to be two M.2 SSDs
Expand Down
1 change: 1 addition & 0 deletions factory/gimlet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod cleanup;
mod config;
mod db;
mod disks;
#[cfg(target_os = "illumos")]
mod efi;
mod factory;
mod host;
Expand Down
1 change: 1 addition & 0 deletions factory/propolis/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod nocloud;
mod propolis;
mod serial;
mod svc;
#[cfg(target_os = "illumos")]
mod ucred;
mod vm;
mod zones;
Expand Down
23 changes: 18 additions & 5 deletions factory/propolis/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::{
time::Duration,
};

#[cfg(target_os = "illumos")]
use crate::ucred::PeerUCred;
use crate::zones::*;
use anyhow::{anyhow, bail, Result};
Expand All @@ -25,7 +26,7 @@ pub enum SerialData {

pub struct SerialForZone {
name: String,
zoneid: zoneid_t,
zoneid: ZoneId,
rx: tokio::sync::mpsc::Receiver<SerialData>,
shutdown: tokio::sync::watch::Sender<bool>,
inner: Arc<Inner>,
Expand All @@ -42,6 +43,7 @@ impl SerialForZone {
* Remove the zone from the active set and shut down any socket tasks.
*/
let mut zones = self.inner.zones.lock().unwrap();
#[cfg_attr(not(target_os = "illumos"), expect(unused))]
let removed = zones.remove(&self.zoneid).unwrap();
assert_eq!(removed.name, self.name);
assert_eq!(removed.zoneid, self.zoneid);
Expand Down Expand Up @@ -69,13 +71,13 @@ pub struct Serial(Arc<Inner>);
#[derive(Clone)]
struct Zone {
name: String,
zoneid: zoneid_t,
zoneid: ZoneId,
tx: tokio::sync::mpsc::Sender<SerialData>,
shutdown: tokio::sync::watch::Receiver<bool>,
}

pub struct Inner {
zones: Mutex<HashMap<zoneid_t, Zone>>,
zones: Mutex<HashMap<ZoneId, Zone>>,
}

impl Serial {
Expand Down Expand Up @@ -114,18 +116,23 @@ impl Serial {
Ok(s0)
}

#[cfg_attr(not(target_os = "illumos"), expect(unused))]
async fn accept_task(&self, log: Logger, listen: UnixListener) -> ! {
loop {
let (sock, zoneid) = match listen.accept().await {
let (sock, zoneid): (UnixStream, ZoneId) = match listen
.accept()
.await
{
Ok((sock, _)) => {
#[cfg(target_os = "illumos")]
match sock.peer_ucred() {
Ok(uc) => {
let Some(zoneid) = uc.zoneid() else {
error!(log, "could not get zone ID for sock");
continue;
};

if zoneid == 0 {
if zoneid.0 == 0 {
/*
* We never want connections from the global
* zone.
Expand All @@ -142,6 +149,12 @@ impl Serial {
}
}

#[cfg(not(target_os = "illumos"))]
{
error!(log, "only works on illumos");
continue;
}

/*
* Then we need to determine if this is a zone that we
* actually want to hear from or not.
Expand Down
6 changes: 4 additions & 2 deletions factory/propolis/src/ucred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
use std::os::fd::AsRawFd;

use anyhow::{bail, Result};
use libc::{getpeerucred, ucred_free, ucred_getzoneid, ucred_t, zoneid_t};
use libc::{getpeerucred, ucred_free, ucred_getzoneid, ucred_t};

use crate::zones::ZoneId;

pub trait PeerUCred: AsRawFd {
fn peer_ucred(&self) -> Result<UCred> {
Expand Down Expand Up @@ -37,7 +39,7 @@ impl Drop for UCred {
}

impl UCred {
pub fn zoneid(&self) -> Option<zoneid_t> {
pub fn zoneid(&self) -> Option<ZoneId> {
let zoneid = unsafe { ucred_getzoneid(self.uc) };
if zoneid < 0 {
None
Expand Down
45 changes: 36 additions & 9 deletions factory/propolis/src/zones.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,40 @@
* Copyright 2024 Oxide Computer Company
*/

use std::ffi::CString;

use anyhow::{bail, Result};
pub use libc::zoneid_t;

#[link(name = "c")]
extern "C" {
fn getzoneidbyname(name: *const libc::c_char) -> zoneid_t;
#[cfg(target_os = "illumos")]
type ZoneIdInner = libc::zoneid_t;
/*
* "Infallible" is the stable equivalent of the never type (!). It can not be
* instantiated, ensuring that we never construct a ZoneId outside illumos.
*/
#[cfg(not(target_os = "illumos"))]
type ZoneIdInner = std::convert::Infallible;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ZoneId(pub ZoneIdInner);

impl std::fmt::Display for ZoneId {
#[cfg(target_os = "illumos")]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}

#[cfg(not(target_os = "illumos"))]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ZoneId")
}
}

pub fn zone_name_to_id(name: &str) -> Result<Option<zoneid_t>> {
let cs = CString::new(name)?;
#[cfg(target_os = "illumos")]
pub fn zone_name_to_id(name: &str) -> Result<Option<ZoneId>> {
#[link(name = "c")]
extern "C" {
fn getzoneidbyname(name: *const libc::c_char) -> zoneid_t;
}

let cs = std::ffi::CString::new(name)?;

let id = unsafe { getzoneidbyname(cs.as_ptr()) };
if id < 0 {
Expand All @@ -30,7 +52,12 @@ pub fn zone_name_to_id(name: &str) -> Result<Option<zoneid_t>> {
bail!("getzoneidbyname({name}): {e}");
}

Ok(Some(id))
Ok(Some(ZoneId(id)))
}

#[cfg(not(target_os = "illumos"))]
pub fn zone_name_to_id(_name: &str) -> Result<Option<ZoneId>> {
bail!("only works on illumos systems");
}

pub fn zone_exists(name: &str) -> Result<bool> {
Expand Down