diff --git a/common/src/api/internal/mod.rs b/common/src/api/internal/mod.rs index dee9229037..8b4ef670b9 100644 --- a/common/src/api/internal/mod.rs +++ b/common/src/api/internal/mod.rs @@ -5,4 +5,3 @@ //! Internally facing APIs. pub mod nexus; -pub mod sled_agent; diff --git a/common/src/api/internal/sled_agent.rs b/common/src/api/internal/sled_agent.rs deleted file mode 100644 index 58cf07b04f..0000000000 --- a/common/src/api/internal/sled_agent.rs +++ /dev/null @@ -1,177 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -//! APIs exposed by Sled Agent. - -use crate::api::{external, internal}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use std::fmt::{Debug, Display, Formatter, Result as FormatResult}; -use std::net::SocketAddr; -use uuid::Uuid; - -/// Describes the instance hardware. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -pub struct InstanceHardware { - pub runtime: internal::nexus::InstanceRuntimeState, - pub nics: Vec, -} - -/// Sent to a sled agent to establish the runtime state of an Instance -#[derive(Serialize, Deserialize, JsonSchema)] -pub struct InstanceEnsureBody { - /// Last runtime state of the Instance known to Nexus (used if the agent - /// has never seen this Instance before). - pub initial: InstanceHardware, - /// requested runtime state of the Instance - pub target: InstanceRuntimeStateRequested, - /// If we're migrating this instance, the details needed to drive the migration - pub migrate: Option, -} - -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct InstanceMigrateParams { - pub src_propolis_uuid: Uuid, - pub src_propolis_addr: SocketAddr, -} - -/// Requestable running state of an Instance. -/// -/// A subset of [`external::InstanceState`]. -#[derive( - Copy, - Clone, - Debug, - Deserialize, - Eq, - Ord, - PartialEq, - PartialOrd, - Serialize, - JsonSchema, -)] -#[serde(rename_all = "lowercase")] -pub enum InstanceStateRequested { - Running, - Stopped, - // Issues a reset command to the instance, such that it should - // stop and then immediately become running. - Reboot, - Migrating, - Destroyed, -} - -impl Display for InstanceStateRequested { - fn fmt(&self, f: &mut Formatter) -> FormatResult { - write!(f, "{}", self.label()) - } -} - -impl InstanceStateRequested { - fn label(&self) -> &str { - match self { - InstanceStateRequested::Running => "running", - InstanceStateRequested::Stopped => "stopped", - InstanceStateRequested::Reboot => "reboot", - InstanceStateRequested::Migrating => "migrating", - InstanceStateRequested::Destroyed => "destroyed", - } - } - - /// Returns true if the state represents a stopped Instance. - pub fn is_stopped(&self) -> bool { - match self { - InstanceStateRequested::Running => false, - InstanceStateRequested::Stopped => true, - InstanceStateRequested::Reboot => false, - InstanceStateRequested::Migrating => false, - InstanceStateRequested::Destroyed => true, - } - } -} - -/// Instance runtime state to update for a migration. -#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct InstanceRuntimeStateMigrateParams { - pub migration_id: Uuid, - pub dst_propolis_id: Uuid, -} - -/// Used to request an Instance state change from a sled agent -/// -/// Right now, it's only the run state and migration id that can -/// be changed, though we might want to support changing properties -/// like "ncpus" here. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] -pub struct InstanceRuntimeStateRequested { - pub run_state: InstanceStateRequested, - pub migration_params: Option, -} - -/// The type of a dataset, and an auxiliary information necessary -/// to successfully launch a zone managing the associated data. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum DatasetKind { - CockroachDb { - /// The addresses of all nodes within the cluster. - all_addresses: Vec, - }, - Crucible, - Clickhouse, -} - -impl std::fmt::Display for DatasetKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use DatasetKind::*; - let s = match self { - Crucible => "crucible", - CockroachDb { .. } => "cockroach", - Clickhouse => "clickhouse", - }; - write!(f, "{}", s) - } -} - -/// Used to request a new partition kind exists within a zpool. -/// -/// Many partition types are associated with services that will be -/// instantiated when the partition is detected. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct DatasetEnsureBody { - // The name (and UUID) of the Zpool which we are inserting into. - pub zpool_uuid: Uuid, - // The type of the filesystem. - pub partition_kind: DatasetKind, - // The address on which the zone will listen for requests. - pub address: SocketAddr, - // NOTE: We could insert a UUID here, if we want that to be set by the - // caller explicitly? Currently, the lack of a UUID implies that - // "at most one partition type" exists within a zpool. - // - // It's unclear if this is actually necessary - making this change - // would also require the RSS to query existing datasets before - // requesting new ones (after all, we generally wouldn't want to - // create two CRDB datasets with different UUIDs on the same zpool). -} - -#[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, -)] -pub struct ServiceRequest { - // The name of the service to be created. - pub name: String, - // The addresses on which the service should listen for requests. - pub addresses: Vec, -} - -/// Used to request that the Sled initialize certain services on initialization. -/// -/// This may be used to record that certain sleds are responsible for -/// launching services which may not be associated with a partition, such -/// as Nexus. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] -pub struct ServiceEnsureBody { - pub services: Vec, -} diff --git a/nexus-client/src/lib.rs b/nexus-client/src/lib.rs index e8ce34da7e..35ec58288c 100644 --- a/nexus-client/src/lib.rs +++ b/nexus-client/src/lib.rs @@ -7,8 +7,6 @@ * from within the control plane */ -use std::convert::TryFrom; - use omicron_common::generate_logging_api; generate_logging_api!("../openapi/nexus-internal.json"); @@ -19,12 +17,6 @@ impl omicron_common::api::external::ClientError for types::Error { } } -impl From for omicron_common::api::external::Generation { - fn from(s: types::Generation) -> Self { - Self::try_from(s.0 as i64).unwrap() - } -} - impl From for types::ByteCount { fn from(s: omicron_common::api::external::ByteCount) -> Self { Self(s.to_bytes()) @@ -64,19 +56,6 @@ impl From } } -impl From - for types::DatasetKind -{ - fn from(d: omicron_common::api::internal::sled_agent::DatasetKind) -> Self { - use omicron_common::api::internal::sled_agent::DatasetKind::*; - match d { - CockroachDb { .. } => types::DatasetKind::Cockroach, - Crucible { .. } => types::DatasetKind::Crucible, - Clickhouse { .. } => types::DatasetKind::Clickhouse, - } - } -} - impl From for types::InstanceRuntimeState { @@ -99,63 +78,22 @@ impl From } } -impl From<&omicron_common::api::internal::nexus::InstanceRuntimeState> - for types::InstanceRuntimeState -{ - fn from( - s: &omicron_common::api::internal::nexus::InstanceRuntimeState, - ) -> Self { - Self { - run_state: s.run_state.into(), - sled_uuid: s.sled_uuid, - propolis_uuid: s.propolis_uuid, - dst_propolis_uuid: s.dst_propolis_uuid, - propolis_addr: s.propolis_addr.map(|addr| addr.to_string()), - migration_uuid: s.migration_uuid, - ncpus: s.ncpus.into(), - memory: s.memory.into(), - hostname: s.hostname.clone(), - gen: s.gen.into(), - time_updated: s.time_updated, - } - } -} - impl From for types::InstanceState { fn from(s: omicron_common::api::external::InstanceState) -> Self { + use omicron_common::api::external::InstanceState; match s { - omicron_common::api::external::InstanceState::Creating => { - Self::Creating - } - omicron_common::api::external::InstanceState::Starting => { - Self::Starting - } - omicron_common::api::external::InstanceState::Running => { - Self::Running - } - omicron_common::api::external::InstanceState::Stopping => { - Self::Stopping - } - omicron_common::api::external::InstanceState::Stopped => { - Self::Stopped - } - omicron_common::api::external::InstanceState::Rebooting => { - Self::Rebooting - } - omicron_common::api::external::InstanceState::Migrating => { - Self::Migrating - } - omicron_common::api::external::InstanceState::Repairing => { - Self::Repairing - } - omicron_common::api::external::InstanceState::Failed => { - Self::Failed - } - omicron_common::api::external::InstanceState::Destroyed => { - Self::Destroyed - } + InstanceState::Creating => Self::Creating, + InstanceState::Starting => Self::Starting, + InstanceState::Running => Self::Running, + InstanceState::Stopping => Self::Stopping, + InstanceState::Stopped => Self::Stopped, + InstanceState::Rebooting => Self::Rebooting, + InstanceState::Migrating => Self::Migrating, + InstanceState::Repairing => Self::Repairing, + InstanceState::Failed => Self::Failed, + InstanceState::Destroyed => Self::Destroyed, } } } @@ -188,26 +126,15 @@ impl From impl From for types::DiskState { fn from(s: omicron_common::api::external::DiskState) -> Self { + use omicron_common::api::external::DiskState; match s { - omicron_common::api::external::DiskState::Creating => { - Self::Creating - } - omicron_common::api::external::DiskState::Detached => { - Self::Detached - } - omicron_common::api::external::DiskState::Attaching(u) => { - Self::Attaching(u) - } - omicron_common::api::external::DiskState::Attached(u) => { - Self::Attached(u) - } - omicron_common::api::external::DiskState::Detaching(u) => { - Self::Detaching(u) - } - omicron_common::api::external::DiskState::Destroyed => { - Self::Destroyed - } - omicron_common::api::external::DiskState::Faulted => Self::Faulted, + DiskState::Creating => Self::Creating, + DiskState::Detached => Self::Detached, + DiskState::Attaching(u) => Self::Attaching(u), + DiskState::Attached(u) => Self::Attached(u), + DiskState::Detaching(u) => Self::Detaching(u), + DiskState::Destroyed => Self::Destroyed, + DiskState::Faulted => Self::Faulted, } } } diff --git a/nexus/src/db/model.rs b/nexus/src/db/model.rs index afea062982..5b5352c7f4 100644 --- a/nexus/src/db/model.rs +++ b/nexus/src/db/model.rs @@ -191,6 +191,12 @@ where } } +impl From for sled_agent_client::types::ByteCount { + fn from(b: ByteCount) -> Self { + Self(b.to_bytes()) + } +} + #[derive( Copy, Clone, @@ -242,6 +248,12 @@ where } } +impl From for sled_agent_client::types::Generation { + fn from(g: Generation) -> Self { + Self(i64::from(&g.0) as u64) + } +} + /// Representation of a [`u16`] in the database. /// We need this because the database does not support unsigned types. /// This handles converting from the database's INT4 to the actual u16. @@ -316,6 +328,12 @@ where } } +impl From for sled_agent_client::types::InstanceCpuCount { + fn from(i: InstanceCpuCount) -> Self { + Self(i.0 .0) + } +} + #[derive(Clone, Copy, Debug, PartialEq, AsExpression, FromSqlRow)] #[sql_type = "sql_types::Inet"] pub struct Ipv4Net(pub external::Ipv4Net); @@ -979,6 +997,28 @@ pub struct InstanceRuntimeState { pub hostname: String, } +impl From + for sled_agent_client::types::InstanceRuntimeState +{ + fn from(s: InstanceRuntimeState) -> Self { + Self { + run_state: s.state.into(), + sled_uuid: s.sled_uuid, + propolis_uuid: s.propolis_uuid, + dst_propolis_uuid: s.dst_propolis_uuid, + propolis_addr: s + .propolis_ip + .map(|ip| SocketAddr::new(ip.ip(), PROPOLIS_PORT).to_string()), + migration_uuid: s.migration_uuid, + ncpus: s.ncpus.into(), + memory: s.memory.into(), + hostname: s.hostname, + gen: s.gen.into(), + time_updated: s.time_updated, + } + } +} + /// Conversion to the external API type. impl Into for InstanceRuntimeState { fn into(self) -> external::InstanceRuntimeState { @@ -1061,6 +1101,25 @@ impl InstanceState { } } +impl From for sled_agent_client::types::InstanceState { + fn from(s: InstanceState) -> Self { + use external::InstanceState::*; + use sled_agent_client::types::InstanceState as Output; + match s.0 { + Creating => Output::Creating, + Starting => Output::Starting, + Running => Output::Running, + Stopping => Output::Stopping, + Stopped => Output::Stopped, + Rebooting => Output::Rebooting, + Migrating => Output::Migrating, + Repairing => Output::Repairing, + Failed => Output::Failed, + Destroyed => Output::Destroyed, + } + } +} + /// A Disk (network block device). #[derive( Queryable, diff --git a/nexus/src/nexus.rs b/nexus/src/nexus.rs index 2a185e147c..c9889a8589 100644 --- a/nexus/src/nexus.rs +++ b/nexus/src/nexus.rs @@ -54,9 +54,6 @@ use omicron_common::api::external::VpcRouterKind; use omicron_common::api::internal::nexus; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::UpdateArtifact; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateMigrateParams; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; -use omicron_common::api::internal::sled_agent::InstanceStateRequested; use omicron_common::backoff; use omicron_common::bail_unless; use oximeter_client::Client as OximeterClient; @@ -65,6 +62,9 @@ use oximeter_db::TimeseriesSchemaPaginationParams; use oximeter_producer::register; use rand::{rngs::StdRng, Rng, RngCore, SeedableRng}; use ring::digest; +use sled_agent_client::types::InstanceRuntimeStateMigrateParams; +use sled_agent_client::types::InstanceRuntimeStateRequested; +use sled_agent_client::types::InstanceStateRequested; use sled_agent_client::Client as SledAgentClient; use slog::Logger; use std::convert::{TryFrom, TryInto}; @@ -1291,15 +1291,12 @@ impl Nexus { * beat us to it. */ - let runtime: nexus::InstanceRuntimeState = - db_instance.runtime().clone().into(); - // TODO: Populate this with an appropriate NIC. // See also: sic_create_instance_record in sagas.rs for a similar // construction. let instance_hardware = sled_agent_client::types::InstanceHardware { runtime: sled_agent_client::types::InstanceRuntimeState::from( - runtime, + db_instance.runtime().clone(), ), nics: vec![], }; @@ -1309,7 +1306,7 @@ impl Nexus { &db_instance.id(), &sled_agent_client::types::InstanceEnsureBody { initial: instance_hardware, - target: requested.into(), + target: requested, migrate: None, }, ) diff --git a/nexus/src/sagas.rs b/nexus/src/sagas.rs index bf2a8d94e4..9838846efa 100644 --- a/nexus/src/sagas.rs +++ b/nexus/src/sagas.rs @@ -33,10 +33,15 @@ use omicron_common::api::external::InstanceState; use omicron_common::api::external::Name; use omicron_common::api::external::NetworkInterface; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceHardware; use omicron_common::backoff::{self, BackoffError}; use serde::Deserialize; use serde::Serialize; +use sled_agent_client::types::InstanceEnsureBody; +use sled_agent_client::types::InstanceHardware; +use sled_agent_client::types::InstanceMigrateParams; +use sled_agent_client::types::InstanceRuntimeStateMigrateParams; +use sled_agent_client::types::InstanceRuntimeStateRequested; +use sled_agent_client::types::InstanceStateRequested; use slog::warn; use slog::Logger; use std::collections::BTreeMap; @@ -494,7 +499,10 @@ async fn sic_create_instance_record( .map_err(ActionError::action_failed)?; // See also: instance_set_runtime in nexus.rs for a similar construction. - Ok(InstanceHardware { runtime: instance.runtime().clone().into(), nics }) + Ok(InstanceHardware { + runtime: instance.runtime().clone().into(), + nics: nics.into_iter().map(|nic| nic.into()).collect(), + }) } async fn sic_instance_ensure( @@ -504,12 +512,10 @@ async fn sic_instance_ensure( * TODO-correctness is this idempotent? */ let osagactx = sagactx.user_data(); - let runtime_params = - sled_agent_client::types::InstanceRuntimeStateRequested { - run_state: - sled_agent_client::types::InstanceStateRequested::Running, - migration_params: None, - }; + let runtime_params = InstanceRuntimeStateRequested { + run_state: InstanceStateRequested::Running, + migration_params: None, + }; let instance_id = sagactx.lookup::("instance_id")?; let sled_uuid = sagactx.lookup::("server_id")?; let initial_runtime = @@ -527,10 +533,8 @@ async fn sic_instance_ensure( let new_runtime_state = sa .instance_put( &instance_id, - &sled_agent_client::types::InstanceEnsureBody { - initial: sled_agent_client::types::InstanceHardware::from( - initial_runtime, - ), + &InstanceEnsureBody { + initial: initial_runtime, target: runtime_params, migrate: None, }, @@ -653,19 +657,17 @@ async fn sim_instance_migrate( propolis_addr: None, ..old_runtime }; - let instance_hardware = sled_agent_client::types::InstanceHardware { + let instance_hardware = InstanceHardware { runtime: runtime.into(), // TODO: populate NICs nics: vec![], }; - let target = sled_agent_client::types::InstanceRuntimeStateRequested { - run_state: sled_agent_client::types::InstanceStateRequested::Migrating, - migration_params: Some( - sled_agent_client::types::InstanceRuntimeStateMigrateParams { - migration_id, - dst_propolis_id: dst_propolis_uuid, - }, - ), + let target = InstanceRuntimeStateRequested { + run_state: InstanceStateRequested::Migrating, + migration_params: Some(InstanceRuntimeStateMigrateParams { + migration_id, + dst_propolis_id: dst_propolis_uuid, + }), }; let src_propolis_uuid = old_runtime.propolis_uuid; @@ -683,13 +685,13 @@ async fn sim_instance_migrate( let new_runtime_state: InstanceRuntimeState = dst_sa .instance_put( &instance_id, - &sled_agent_client::types::InstanceEnsureBody { + &InstanceEnsureBody { initial: instance_hardware, target, - migrate: Some(omicron_common::api::internal::sled_agent::InstanceMigrateParams { - src_propolis_addr, + migrate: Some(InstanceMigrateParams { + src_propolis_addr: src_propolis_addr.to_string(), src_propolis_uuid, - }.into()), + }), }, ) .await diff --git a/sled-agent-client/src/lib.rs b/sled-agent-client/src/lib.rs index a2c18495a6..6a5517b935 100644 --- a/sled-agent-client/src/lib.rs +++ b/sled-agent-client/src/lib.rs @@ -45,37 +45,18 @@ impl From for types::InstanceState { fn from(s: omicron_common::api::external::InstanceState) -> Self { + use omicron_common::api::external::InstanceState::*; match s { - omicron_common::api::external::InstanceState::Creating => { - Self::Creating - } - omicron_common::api::external::InstanceState::Starting => { - Self::Starting - } - omicron_common::api::external::InstanceState::Running => { - Self::Running - } - omicron_common::api::external::InstanceState::Stopping => { - Self::Stopping - } - omicron_common::api::external::InstanceState::Stopped => { - Self::Stopped - } - omicron_common::api::external::InstanceState::Rebooting => { - Self::Rebooting - } - omicron_common::api::external::InstanceState::Migrating => { - Self::Migrating - } - omicron_common::api::external::InstanceState::Repairing => { - Self::Repairing - } - omicron_common::api::external::InstanceState::Failed => { - Self::Failed - } - omicron_common::api::external::InstanceState::Destroyed => { - Self::Destroyed - } + Creating => Self::Creating, + Starting => Self::Starting, + Running => Self::Running, + Stopping => Self::Stopping, + Stopped => Self::Stopped, + Rebooting => Self::Rebooting, + Migrating => Self::Migrating, + Repairing => Self::Repairing, + Failed => Self::Failed, + Destroyed => Self::Destroyed, } } } @@ -100,42 +81,6 @@ impl From for types::Generation { } } -impl From - for types::InstanceRuntimeStateMigrateParams -{ - fn from( - s: omicron_common::api::internal::sled_agent::InstanceRuntimeStateMigrateParams, - ) -> Self { - Self { migration_id: s.migration_id, dst_propolis_id: s.dst_propolis_id } - } -} - -impl From - for types::InstanceRuntimeStateRequested -{ - fn from( - s: omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested, - ) -> Self { - Self { run_state: s.run_state.into(), migration_params: s.migration_params.map(|p| p.into()) } - } -} - -impl From - for types::InstanceStateRequested -{ - fn from( - s: omicron_common::api::internal::sled_agent::InstanceStateRequested, - ) -> Self { - match s { - omicron_common::api::internal::sled_agent::InstanceStateRequested::Running => Self::Running, - omicron_common::api::internal::sled_agent::InstanceStateRequested::Stopped => Self::Stopped, - omicron_common::api::internal::sled_agent::InstanceStateRequested::Reboot => Self::Reboot, - omicron_common::api::internal::sled_agent::InstanceStateRequested::Migrating => Self::Migrating, - omicron_common::api::internal::sled_agent::InstanceStateRequested::Destroyed => Self::Destroyed, - } - } -} - impl From for omicron_common::api::internal::nexus::InstanceRuntimeState { @@ -160,17 +105,18 @@ impl From for omicron_common::api::external::InstanceState { fn from(s: types::InstanceState) -> Self { + use types::InstanceState::*; match s { - types::InstanceState::Creating => Self::Creating, - types::InstanceState::Starting => Self::Starting, - types::InstanceState::Running => Self::Running, - types::InstanceState::Stopping => Self::Stopping, - types::InstanceState::Stopped => Self::Stopped, - types::InstanceState::Rebooting => Self::Rebooting, - types::InstanceState::Migrating => Self::Migrating, - types::InstanceState::Repairing => Self::Repairing, - types::InstanceState::Failed => Self::Failed, - types::InstanceState::Destroyed => Self::Destroyed, + Creating => Self::Creating, + Starting => Self::Starting, + Running => Self::Running, + Stopping => Self::Stopping, + Stopped => Self::Stopped, + Rebooting => Self::Rebooting, + Migrating => Self::Migrating, + Repairing => Self::Repairing, + Failed => Self::Failed, + Destroyed => Self::Destroyed, } } } @@ -209,26 +155,15 @@ impl From impl From for types::DiskState { fn from(s: omicron_common::api::external::DiskState) -> Self { + use omicron_common::api::external::DiskState::*; match s { - omicron_common::api::external::DiskState::Creating => { - Self::Creating - } - omicron_common::api::external::DiskState::Detached => { - Self::Detached - } - omicron_common::api::external::DiskState::Attaching(u) => { - Self::Attaching(u) - } - omicron_common::api::external::DiskState::Attached(u) => { - Self::Attached(u) - } - omicron_common::api::external::DiskState::Detaching(u) => { - Self::Detaching(u) - } - omicron_common::api::external::DiskState::Destroyed => { - Self::Destroyed - } - omicron_common::api::external::DiskState::Faulted => Self::Faulted, + Creating => Self::Creating, + Detached => Self::Detached, + Attaching(u) => Self::Attaching(u), + Attached(u) => Self::Attached(u), + Detaching(u) => Self::Detaching(u), + Destroyed => Self::Destroyed, + Faulted => Self::Faulted, } } } @@ -247,48 +182,23 @@ impl From impl From for omicron_common::api::external::DiskState { fn from(s: types::DiskState) -> Self { + use types::DiskState::*; match s { - types::DiskState::Creating => Self::Creating, - types::DiskState::Detached => Self::Detached, - types::DiskState::Attaching(u) => Self::Attaching(u), - types::DiskState::Attached(u) => Self::Attached(u), - types::DiskState::Detaching(u) => Self::Detaching(u), - types::DiskState::Destroyed => Self::Destroyed, - types::DiskState::Faulted => Self::Faulted, - } - } -} - -impl From - for types::InstanceHardware -{ - fn from( - s: omicron_common::api::internal::sled_agent::InstanceHardware, - ) -> Self { - Self { - nics: s.nics.iter().map(Into::into).collect(), - runtime: s.runtime.into(), - } - } -} - -impl From - for types::InstanceMigrateParams -{ - fn from( - s: omicron_common::api::internal::sled_agent::InstanceMigrateParams, - ) -> Self { - Self { - src_propolis_addr: s.src_propolis_addr.to_string(), - src_propolis_uuid: s.src_propolis_uuid, + Creating => Self::Creating, + Detached => Self::Detached, + Attaching(u) => Self::Attaching(u), + Attached(u) => Self::Attached(u), + Detaching(u) => Self::Detaching(u), + Destroyed => Self::Destroyed, + Faulted => Self::Faulted, } } } -impl From<&omicron_common::api::external::NetworkInterface> +impl From for types::NetworkInterface { - fn from(s: &omicron_common::api::external::NetworkInterface) -> Self { + fn from(s: omicron_common::api::external::NetworkInterface) -> Self { Self { description: s.identity.description.clone(), id: s.identity.id, @@ -316,48 +226,6 @@ impl From for types::MacAddr { } } -impl From - for types::DatasetKind -{ - fn from(k: omicron_common::api::internal::sled_agent::DatasetKind) -> Self { - use omicron_common::api::internal::sled_agent::DatasetKind::*; - match k { - CockroachDb { all_addresses } => Self::CockroachDb( - all_addresses.iter().map(|a| a.to_string()).collect(), - ), - Crucible => Self::Crucible, - Clickhouse => Self::Clickhouse, - } - } -} - -impl From - for types::DatasetEnsureBody -{ - fn from( - p: omicron_common::api::internal::sled_agent::DatasetEnsureBody, - ) -> Self { - Self { - zpool_uuid: p.zpool_uuid, - partition_kind: p.partition_kind.into(), - address: p.address.to_string(), - } - } -} - -impl From - for types::ServiceRequest -{ - fn from( - s: omicron_common::api::internal::sled_agent::ServiceRequest, - ) -> Self { - Self { - name: s.name, - addresses: s.addresses.into_iter().map(|s| s.to_string()).collect(), - } - } -} - impl From for types::UpdateArtifact { diff --git a/sled-agent/src/bootstrap/config.rs b/sled-agent/src/bootstrap/config.rs index 0ea57aa3b6..339ecb3613 100644 --- a/sled-agent/src/bootstrap/config.rs +++ b/sled-agent/src/bootstrap/config.rs @@ -7,11 +7,9 @@ */ use crate::config::ConfigError; +use crate::params::{DatasetEnsureBody, ServiceRequest}; use dropshot::ConfigDropshot; use dropshot::ConfigLogging; -use omicron_common::api::internal::sled_agent::{ - DatasetEnsureBody, ServiceRequest, -}; use serde::Deserialize; use serde::Serialize; use std::net::SocketAddr; diff --git a/sled-agent/src/common/instance.rs b/sled-agent/src/common/instance.rs index 8022fe7797..8481c3c7b1 100644 --- a/sled-agent/src/common/instance.rs +++ b/sled-agent/src/common/instance.rs @@ -4,13 +4,14 @@ //! Describes the states of VM instances. +use crate::params::{ + InstanceRuntimeStateMigrateParams, InstanceRuntimeStateRequested, + InstanceStateRequested, +}; use chrono::Utc; use omicron_common::api::external::Error; use omicron_common::api::external::InstanceState; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateMigrateParams; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; -use omicron_common::api::internal::sled_agent::InstanceStateRequested; use propolis_client::api::InstanceState as PropolisInstanceState; /// The port propolis-server listens on inside the propolis zone. @@ -353,19 +354,17 @@ impl InstanceStates { mod test { use super::{Action, InstanceStates}; - use std::assert_matches::assert_matches; - + use crate::params::{ + InstanceRuntimeStateMigrateParams, InstanceRuntimeStateRequested, + InstanceStateRequested as Requested, + }; use chrono::Utc; use omicron_common::api::external::{ ByteCount, Error, Generation, InstanceCpuCount, InstanceState as State, }; - use omicron_common::api::internal::{ - nexus::InstanceRuntimeState, - sled_agent::InstanceRuntimeStateMigrateParams, - sled_agent::InstanceRuntimeStateRequested, - sled_agent::InstanceStateRequested as Requested, - }; + use omicron_common::api::internal::nexus::InstanceRuntimeState; use propolis_client::api::InstanceState as Observed; + use std::assert_matches::assert_matches; use uuid::Uuid; fn make_instance() -> InstanceStates { diff --git a/sled-agent/src/http_entrypoints.rs b/sled-agent/src/http_entrypoints.rs index 6575ce70d3..11f6d9d2eb 100644 --- a/sled-agent/src/http_entrypoints.rs +++ b/sled-agent/src/http_entrypoints.rs @@ -4,7 +4,9 @@ //! HTTP entrypoint functions for the sled agent's exposed API -use super::params::DiskEnsureBody; +use crate::params::{ + DatasetEnsureBody, DiskEnsureBody, InstanceEnsureBody, ServiceEnsureBody, +}; use dropshot::{ endpoint, ApiDescription, HttpError, HttpResponseOk, HttpResponseUpdatedNoContent, Path, RequestContext, TypedBody, @@ -13,9 +15,6 @@ use omicron_common::api::external::Error; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::InstanceRuntimeState; use omicron_common::api::internal::nexus::UpdateArtifact; -use omicron_common::api::internal::sled_agent::DatasetEnsureBody; -use omicron_common::api::internal::sled_agent::InstanceEnsureBody; -use omicron_common::api::internal::sled_agent::ServiceEnsureBody; use schemars::JsonSchema; use serde::Deserialize; use std::sync::Arc; diff --git a/sled-agent/src/instance.rs b/sled-agent/src/instance.rs index 62375f8cbc..4bafe69f80 100644 --- a/sled-agent/src/instance.rs +++ b/sled-agent/src/instance.rs @@ -14,13 +14,13 @@ use crate::illumos::vnic::VnicAllocator; use crate::illumos::zone::{AddressRequest, PROPOLIS_ZONE_PREFIX}; use crate::instance_manager::InstanceTicket; use crate::nexus::NexusClient; +use crate::params::{ + InstanceHardware, InstanceMigrateParams, InstanceRuntimeStateRequested, +}; use anyhow::anyhow; use futures::lock::{Mutex, MutexGuard}; use omicron_common::api::external::NetworkInterface; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceHardware; -use omicron_common::api::internal::sled_agent::InstanceMigrateParams; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; use omicron_common::backoff; use propolis_client::Client as PropolisClient; use slog::Logger; @@ -219,7 +219,7 @@ impl InstanceInner { .cpapi_instances_put( self.id(), &nexus_client::types::InstanceRuntimeState::from( - self.state.current(), + self.state.current().clone(), ), ) .await @@ -635,13 +635,13 @@ impl Instance { mod test { use super::*; use crate::mocks::MockNexusClient; + use crate::params::InstanceStateRequested; use chrono::Utc; use omicron_common::api::external::{ ByteCount, Generation, InstanceCpuCount, InstanceState, }; - use omicron_common::api::internal::{ - nexus::InstanceRuntimeState, sled_agent::InstanceStateRequested, - }; + use omicron_common::api::internal::nexus::InstanceRuntimeState; + static INST_UUID_STR: &str = "e398c5d5-5059-4e55-beac-3a1071083aaa"; static PROPOLIS_UUID_STR: &str = "ed895b13-55d5-4e0b-88e9-3f4e74d0d936"; diff --git a/sled-agent/src/instance_manager.rs b/sled-agent/src/instance_manager.rs index d54c7f5d2e..d8b7e946c8 100644 --- a/sled-agent/src/instance_manager.rs +++ b/sled-agent/src/instance_manager.rs @@ -7,10 +7,10 @@ use crate::common::vlan::VlanID; use crate::illumos::vnic::VnicAllocator; use crate::nexus::NexusClient; +use crate::params::{ + InstanceHardware, InstanceMigrateParams, InstanceRuntimeStateRequested, +}; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceHardware; -use omicron_common::api::internal::sled_agent::InstanceMigrateParams; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; use slog::Logger; use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; @@ -199,13 +199,12 @@ mod test { use crate::illumos::{dladm::MockDladm, zone::MockZones}; use crate::instance::MockInstance; use crate::mocks::MockNexusClient; + use crate::params::InstanceStateRequested; use chrono::Utc; use omicron_common::api::external::{ ByteCount, Generation, InstanceCpuCount, InstanceState, }; - use omicron_common::api::internal::{ - nexus::InstanceRuntimeState, sled_agent::InstanceStateRequested, - }; + use omicron_common::api::internal::nexus::InstanceRuntimeState; static INST_UUID_STR: &str = "e398c5d5-5059-4e55-beac-3a1071083aaa"; diff --git a/sled-agent/src/params.rs b/sled-agent/src/params.rs index 993b31b632..0b7bb347ef 100644 --- a/sled-agent/src/params.rs +++ b/sled-agent/src/params.rs @@ -2,9 +2,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use omicron_common::api::internal::nexus::DiskRuntimeState; +use omicron_common::api::external::NetworkInterface; +use omicron_common::api::internal::nexus::{ + DiskRuntimeState, InstanceRuntimeState, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::fmt::{Debug, Display, Formatter, Result as FormatResult}; +use std::net::SocketAddr; use uuid::Uuid; ///Used to request a Disk state change @@ -39,3 +44,211 @@ pub struct DiskEnsureBody { /// requested runtime state of the Disk pub target: DiskStateRequested, } + +/// Describes the instance hardware. +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +pub struct InstanceHardware { + pub runtime: InstanceRuntimeState, + pub nics: Vec, +} + +/// Sent to a sled agent to establish the runtime state of an Instance +#[derive(Serialize, Deserialize, JsonSchema)] +pub struct InstanceEnsureBody { + /// Last runtime state of the Instance known to Nexus (used if the agent + /// has never seen this Instance before). + pub initial: InstanceHardware, + /// requested runtime state of the Instance + pub target: InstanceRuntimeStateRequested, + /// If we're migrating this instance, the details needed to drive the migration + pub migrate: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +pub struct InstanceMigrateParams { + pub src_propolis_uuid: Uuid, + pub src_propolis_addr: SocketAddr, +} + +/// Requestable running state of an Instance. +/// +/// A subset of [`external::InstanceState`]. +#[derive( + Copy, + Clone, + Debug, + Deserialize, + Eq, + Ord, + PartialEq, + PartialOrd, + Serialize, + JsonSchema, +)] +#[serde(rename_all = "lowercase")] +pub enum InstanceStateRequested { + Running, + Stopped, + // Issues a reset command to the instance, such that it should + // stop and then immediately become running. + Reboot, + Migrating, + Destroyed, +} + +impl Display for InstanceStateRequested { + fn fmt(&self, f: &mut Formatter) -> FormatResult { + write!(f, "{}", self.label()) + } +} + +impl InstanceStateRequested { + fn label(&self) -> &str { + match self { + InstanceStateRequested::Running => "running", + InstanceStateRequested::Stopped => "stopped", + InstanceStateRequested::Reboot => "reboot", + InstanceStateRequested::Migrating => "migrating", + InstanceStateRequested::Destroyed => "destroyed", + } + } + + /// Returns true if the state represents a stopped Instance. + pub fn is_stopped(&self) -> bool { + match self { + InstanceStateRequested::Running => false, + InstanceStateRequested::Stopped => true, + InstanceStateRequested::Reboot => false, + InstanceStateRequested::Migrating => false, + InstanceStateRequested::Destroyed => true, + } + } +} + +/// Instance runtime state to update for a migration. +#[derive(Copy, Clone, Debug, Deserialize, Serialize, JsonSchema)] +pub struct InstanceRuntimeStateMigrateParams { + pub migration_id: Uuid, + pub dst_propolis_id: Uuid, +} + +/// Used to request an Instance state change from a sled agent +/// +/// Right now, it's only the run state and migration id that can +/// be changed, though we might want to support changing properties +/// like "ncpus" here. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] +pub struct InstanceRuntimeStateRequested { + pub run_state: InstanceStateRequested, + pub migration_params: Option, +} + +/// The type of a dataset, and an auxiliary information necessary +/// to successfully launch a zone managing the associated data. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum DatasetKind { + CockroachDb { + /// The addresses of all nodes within the cluster. + all_addresses: Vec, + }, + Crucible, + Clickhouse, +} + +impl From for sled_agent_client::types::DatasetKind { + fn from(k: DatasetKind) -> Self { + use DatasetKind::*; + match k { + CockroachDb { all_addresses } => Self::CockroachDb( + all_addresses.iter().map(|a| a.to_string()).collect(), + ), + Crucible => Self::Crucible, + Clickhouse => Self::Clickhouse, + } + } +} + +impl From for nexus_client::types::DatasetKind { + fn from(k: DatasetKind) -> Self { + use DatasetKind::*; + match k { + CockroachDb { .. } => Self::Cockroach, + Crucible => Self::Crucible, + Clickhouse => Self::Clickhouse, + } + } +} + +impl std::fmt::Display for DatasetKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use DatasetKind::*; + let s = match self { + Crucible => "crucible", + CockroachDb { .. } => "cockroach", + Clickhouse => "clickhouse", + }; + write!(f, "{}", s) + } +} + +/// Used to request a new partition kind exists within a zpool. +/// +/// Many partition types are associated with services that will be +/// instantiated when the partition is detected. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub struct DatasetEnsureBody { + // The name (and UUID) of the Zpool which we are inserting into. + pub zpool_uuid: Uuid, + // The type of the filesystem. + pub partition_kind: DatasetKind, + // The address on which the zone will listen for requests. + pub address: SocketAddr, + // NOTE: We could insert a UUID here, if we want that to be set by the + // caller explicitly? Currently, the lack of a UUID implies that + // "at most one partition type" exists within a zpool. + // + // It's unclear if this is actually necessary - making this change + // would also require the RSS to query existing datasets before + // requesting new ones (after all, we generally wouldn't want to + // create two CRDB datasets with different UUIDs on the same zpool). +} + +impl From for sled_agent_client::types::DatasetEnsureBody { + fn from(p: DatasetEnsureBody) -> Self { + Self { + zpool_uuid: p.zpool_uuid, + partition_kind: p.partition_kind.into(), + address: p.address.to_string(), + } + } +} + +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, +)] +pub struct ServiceRequest { + // The name of the service to be created. + pub name: String, + // The addresses on which the service should listen for requests. + pub addresses: Vec, +} + +impl From for sled_agent_client::types::ServiceRequest { + fn from(s: ServiceRequest) -> Self { + Self { + name: s.name, + addresses: s.addresses.into_iter().map(|s| s.to_string()).collect(), + } + } +} + +/// Used to request that the Sled initialize certain services on initialization. +/// +/// This may be used to record that certain sleds are responsible for +/// launching services which may not be associated with a partition, such +/// as Nexus. +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq)] +pub struct ServiceEnsureBody { + pub services: Vec, +} diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index 3217ac3009..0e2dd2c358 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -7,9 +7,7 @@ use crate::illumos::running_zone::{InstalledZone, RunningZone}; use crate::illumos::vnic::VnicAllocator; use crate::illumos::zone::AddressRequest; -use omicron_common::api::internal::sled_agent::{ - ServiceEnsureBody, ServiceRequest, -}; +use crate::params::{ServiceEnsureBody, ServiceRequest}; use slog::Logger; use std::collections::HashSet; use std::iter::FromIterator; diff --git a/sled-agent/src/sim/collection.rs b/sled-agent/src/sim/collection.rs index 886a7fecde..c156adb05d 100644 --- a/sled-agent/src/sim/collection.rs +++ b/sled-agent/src/sim/collection.rs @@ -333,7 +333,10 @@ impl SimCollection { #[cfg(test)] mod test { - use crate::params::DiskStateRequested; + use crate::params::{ + DiskStateRequested, InstanceRuntimeStateRequested, + InstanceStateRequested, + }; use crate::sim::collection::SimObject; use crate::sim::disk::SimDisk; use crate::sim::instance::SimInstance; @@ -349,8 +352,6 @@ mod test { use omicron_common::api::external::InstanceState; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::InstanceRuntimeState; - use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; - use omicron_common::api::internal::sled_agent::InstanceStateRequested; use omicron_test_utils::dev::test_setup_log; fn make_instance( diff --git a/sled-agent/src/sim/http_entrypoints.rs b/sled-agent/src/sim/http_entrypoints.rs index 28921d3167..d94836af62 100644 --- a/sled-agent/src/sim/http_entrypoints.rs +++ b/sled-agent/src/sim/http_entrypoints.rs @@ -6,7 +6,7 @@ * HTTP entrypoint functions for the sled agent's exposed API */ -use crate::params::DiskEnsureBody; +use crate::params::{DiskEnsureBody, InstanceEnsureBody}; use dropshot::endpoint; use dropshot::ApiDescription; use dropshot::HttpError; @@ -18,7 +18,6 @@ use dropshot::TypedBody; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::InstanceRuntimeState; use omicron_common::api::internal::nexus::UpdateArtifact; -use omicron_common::api::internal::sled_agent::InstanceEnsureBody; use schemars::JsonSchema; use serde::Deserialize; use std::sync::Arc; diff --git a/sled-agent/src/sim/instance.rs b/sled-agent/src/sim/instance.rs index 36122fc127..88392f1f97 100644 --- a/sled-agent/src/sim/instance.rs +++ b/sled-agent/src/sim/instance.rs @@ -9,14 +9,13 @@ use super::simulatable::Simulatable; use crate::nexus::NexusClient; +use crate::params::{InstanceRuntimeStateRequested, InstanceStateRequested}; use async_trait::async_trait; use nexus_client; use omicron_common::api::external::Error; use omicron_common::api::external::Generation; use omicron_common::api::external::InstanceState; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; -use omicron_common::api::internal::sled_agent::InstanceStateRequested; use propolis_client::api::InstanceState as PropolisInstanceState; use std::sync::Arc; use uuid::Uuid; diff --git a/sled-agent/src/sim/sled_agent.rs b/sled-agent/src/sim/sled_agent.rs index d9a65da3e6..8332cc4b6e 100644 --- a/sled-agent/src/sim/sled_agent.rs +++ b/sled-agent/src/sim/sled_agent.rs @@ -7,13 +7,13 @@ */ use crate::nexus::NexusClient; -use crate::params::DiskStateRequested; +use crate::params::{ + DiskStateRequested, InstanceHardware, InstanceRuntimeStateRequested, +}; use futures::lock::Mutex; use omicron_common::api::external::Error; use omicron_common::api::internal::nexus::DiskRuntimeState; use omicron_common::api::internal::nexus::InstanceRuntimeState; -use omicron_common::api::internal::sled_agent::InstanceHardware; -use omicron_common::api::internal::sled_agent::InstanceRuntimeStateRequested; use slog::Logger; use std::sync::Arc; use uuid::Uuid; diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index e61ea8a10c..1298afd212 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -10,16 +10,15 @@ use crate::illumos::zfs::{ }; use crate::instance_manager::InstanceManager; use crate::nexus::NexusClient; -use crate::params::DiskStateRequested; +use crate::params::{ + DatasetKind, DiskStateRequested, InstanceHardware, InstanceMigrateParams, + InstanceRuntimeStateRequested, ServiceEnsureBody, +}; use crate::services::ServiceManager; use crate::storage_manager::StorageManager; use omicron_common::api::{ internal::nexus::DiskRuntimeState, internal::nexus::InstanceRuntimeState, - internal::nexus::UpdateArtifact, internal::sled_agent::DatasetKind, - internal::sled_agent::InstanceHardware, - internal::sled_agent::InstanceMigrateParams, - internal::sled_agent::InstanceRuntimeStateRequested, - internal::sled_agent::ServiceEnsureBody, + internal::nexus::UpdateArtifact, }; use slog::Logger; use std::net::SocketAddr; diff --git a/sled-agent/src/storage_manager.rs b/sled-agent/src/storage_manager.rs index 9c6c42318f..4ebebf8916 100644 --- a/sled-agent/src/storage_manager.rs +++ b/sled-agent/src/storage_manager.rs @@ -12,12 +12,12 @@ use crate::illumos::zone::AddressRequest; use crate::illumos::zpool::ZpoolName; use crate::illumos::{zfs::Mountpoint, zone::ZONE_PREFIX, zpool::ZpoolInfo}; use crate::nexus::NexusClient; +use crate::params::DatasetKind; use futures::stream::FuturesOrdered; use futures::FutureExt; use futures::StreamExt; use nexus_client::types::{DatasetPutRequest, ZpoolPutRequest}; use omicron_common::api::external::{ByteCount, ByteCountRangeError}; -use omicron_common::api::internal::sled_agent::DatasetKind; use omicron_common::backoff; use schemars::JsonSchema; use serde::{Deserialize, Serialize};