diff --git a/.github/buildomat/jobs/deploy.sh b/.github/buildomat/jobs/deploy.sh index 1fa0caf38e0..2e90ef0c675 100755 --- a/.github/buildomat/jobs/deploy.sh +++ b/.github/buildomat/jobs/deploy.sh @@ -429,18 +429,6 @@ do ACTUAL_ZPOOL_COUNT=$(pfexec zlogin oxz_switch /opt/oxide/omdb/bin/omdb db zpool list -i | wc -l) done -# The bootstrap command creates a disk, so before that: adjust the control plane -# storage buffer to 0 as the virtual hardware only creates 20G pools - -pfexec zlogin oxz_switch /opt/oxide/omdb/bin/omdb db zpool list - -for ZPOOL in $(pfexec zlogin oxz_switch /opt/oxide/omdb/bin/omdb db zpool list -i); -do - pfexec zlogin oxz_switch /opt/oxide/omdb/bin/omdb -w db zpool set-storage-buffer "${ZPOOL}" 0 -done - -pfexec zlogin oxz_switch /opt/oxide/omdb/bin/omdb db zpool list - export RUST_BACKTRACE=1 export E2E_TLS_CERT IPPOOL_START IPPOOL_END eval "$(./target/debug/bootstrap)" diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index 3627e8c395c..0467610f2cb 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -95,6 +95,7 @@ mod role_builtin; pub mod saga_types; mod schema_versions; mod service_kind; +mod setting; mod silo; mod silo_group; mod silo_user; @@ -207,6 +208,7 @@ pub use saga_types::*; pub use schema_versions::*; pub use semver_version::*; pub use service_kind::*; +pub use setting::*; pub use silo::*; pub use silo_group::*; pub use silo_user::*; diff --git a/nexus/db-model/src/schema_versions.rs b/nexus/db-model/src/schema_versions.rs index d98bd3482f0..8b1bf80d5ac 100644 --- a/nexus/db-model/src/schema_versions.rs +++ b/nexus/db-model/src/schema_versions.rs @@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock}; /// /// This must be updated when you change the database schema. Refer to /// schema/crdb/README.adoc in the root of this repository for details. -pub const SCHEMA_VERSION: Version = Version::new(140, 0, 0); +pub const SCHEMA_VERSION: Version = Version::new(141, 0, 0); /// List of all past database schema versions, in *reverse* order /// @@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock> = LazyLock::new(|| { // | leaving the first copy as an example for the next person. // v // KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"), + KnownVersion::new(141, "nexus-settings"), KnownVersion::new(140, "instance-intended-state"), KnownVersion::new(139, "webhooks"), KnownVersion::new(138, "saga-abandoned-state"), diff --git a/nexus/db-model/src/setting.rs b/nexus/db-model/src/setting.rs new file mode 100644 index 00000000000..412ea3568d3 --- /dev/null +++ b/nexus/db-model/src/setting.rs @@ -0,0 +1,23 @@ +// 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/. + +use super::impl_enum_type; +use nexus_db_schema::schema::setting; + +impl_enum_type!( + SettingNameEnum: + + #[derive(Copy, Clone, Debug, AsExpression, FromSqlRow, PartialEq)] + pub enum SettingName; + + // Enum values + ControlPlaneStorageBuffer => b"control_plane_storage_buffer" +); + +#[derive(Queryable, Insertable, Debug, Selectable, Clone)] +#[diesel(table_name = setting)] +pub struct Setting { + pub name: SettingName, + pub int_value: Option, +} diff --git a/nexus/db-queries/src/db/datastore/mod.rs b/nexus/db-queries/src/db/datastore/mod.rs index 5a2acb6aff5..e6dff4b7cf7 100644 --- a/nexus/db-queries/src/db/datastore/mod.rs +++ b/nexus/db-queries/src/db/datastore/mod.rs @@ -87,6 +87,7 @@ pub mod region_snapshot_replacement; mod rendezvous_debug_dataset; mod role; mod saga; +mod setting; mod silo; mod silo_group; mod silo_user; diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index 3236abc857b..24ad4e3d068 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -90,6 +90,7 @@ pub struct RackInit { pub recovery_user_password_hash: omicron_passwords::PasswordHashString, pub dns_update: DnsVersionUpdateBuilder, pub allowed_source_ips: AllowedSourceIps, + pub control_plane_storage_buffer_gib: u32, } /// Possible errors while trying to initialize rack @@ -112,6 +113,8 @@ enum RackInitError { Database(DieselError), // Error adding initial allowed source IP list AllowedSourceIpError(Error), + // Error changing a Nexus setting + ChangeSetting(Error), } // Catch-all for Diesel error conversion into RackInitError, which @@ -175,6 +178,7 @@ impl From for Error { err )), RackInitError::AllowedSourceIpError(err) => err, + RackInitError::ChangeSetting(err) => err, } } } @@ -911,6 +915,17 @@ impl DataStore { DieselError::RollbackTransaction })?; + Self::set_control_plane_storage_buffer_gib_impl( + opctx, + &conn, + rack_init.control_plane_storage_buffer_gib, + ) + .await + .map_err(|e| { + err.set(RackInitError::ChangeSetting(e)).unwrap(); + DieselError::RollbackTransaction + })?; + let rack = diesel::update(rack_dsl::rack) .filter(rack_dsl::id.eq(rack_id)) .set(( @@ -1117,6 +1132,7 @@ mod test { "test suite".to_string(), ), allowed_source_ips: AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, } } } diff --git a/nexus/db-queries/src/db/datastore/setting.rs b/nexus/db-queries/src/db/datastore/setting.rs new file mode 100644 index 00000000000..e9ac846ddac --- /dev/null +++ b/nexus/db-queries/src/db/datastore/setting.rs @@ -0,0 +1,97 @@ +// 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/. + +//! [`DataStore`] methods on [`Setting`]s. + +// Settings are dynamically controlled values for Nexus + +use super::DataStore; +use crate::authz; +use crate::context::OpContext; +use crate::db::datastore::ErrorHandler; +use crate::db::datastore::public_error_from_diesel; +use async_bb8_diesel::AsyncRunQueryDsl; +use diesel::prelude::*; +use nexus_db_lookup::DbConnection; +use nexus_db_model::Setting; +use nexus_db_model::SettingName; +use omicron_common::api::external::ByteCount; +use omicron_common::api::external::Error; + +impl DataStore { + pub(crate) async fn set_control_plane_storage_buffer_gib_impl( + opctx: &OpContext, + conn: &async_bb8_diesel::Connection, + gibibytes: u32, + ) -> Result<(), Error> { + opctx.authorize(authz::Action::Modify, &authz::FLEET).await?; + + use nexus_db_schema::schema::setting::dsl; + + let name = SettingName::ControlPlaneStorageBuffer; + let value: i64 = ByteCount::from_gibibytes_u32(gibibytes).into(); + + let maybe_existing = + Self::get_control_plane_storage_buffer_impl(opctx, conn).await?; + + if maybe_existing.is_some() { + diesel::update(dsl::setting) + .filter(dsl::name.eq(name)) + .set(dsl::int_value.eq(value)) + .execute_async(conn) + .await + .map(|_| ()) + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server)) + } else { + let setting = Setting { name, int_value: Some(value) }; + + diesel::insert_into(dsl::setting) + .values(setting) + .execute_async(conn) + .await + .map(|_| ()) + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server)) + } + } + + pub(crate) async fn get_control_plane_storage_buffer_impl( + opctx: &OpContext, + conn: &async_bb8_diesel::Connection, + ) -> Result, Error> { + opctx.authorize(authz::Action::Modify, &authz::FLEET).await?; + + use nexus_db_schema::schema::setting::dsl; + + let name = SettingName::ControlPlaneStorageBuffer; + + let result = dsl::setting + .filter(dsl::name.eq(name)) + .select(Setting::as_select()) + .first_async(conn) + .await + .optional() + .map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?; + + Ok(match result { + Some(setting) => { + // A row exists with this setting's name + match setting.int_value { + Some(value) => Some(ByteCount::try_from(value).unwrap()), + + None => None, + } + } + + None => None, + }) + } + + pub async fn get_control_plane_storage_buffer( + &self, + opctx: &OpContext, + ) -> Result, Error> { + let conn = self.pool_connection_authorized(opctx).await?; + Self::get_control_plane_storage_buffer_impl(opctx, &conn).await + } +} diff --git a/nexus/db-schema/src/enums.rs b/nexus/db-schema/src/enums.rs index 79d312c8b64..b4d59582461 100644 --- a/nexus/db-schema/src/enums.rs +++ b/nexus/db-schema/src/enums.rs @@ -41,8 +41,8 @@ define_enums! { IdentityProviderTypeEnum => "provider_type", IdentityTypeEnum => "identity_type", InstanceAutoRestartPolicyEnum => "instance_auto_restart", - InstanceStateEnum => "instance_state_v2", InstanceIntendedStateEnum => "instance_intended_state", + InstanceStateEnum => "instance_state_v2", IpAttachStateEnum => "ip_attach_state", IpKindEnum => "ip_kind", IpPoolResourceTypeEnum => "ip_pool_resource_type", @@ -64,6 +64,7 @@ define_enums! { RouterRouteKindEnum => "router_route_kind", SagaStateEnum => "saga_state", ServiceKindEnum => "service_kind", + SettingNameEnum => "setting_name", SledPolicyEnum => "sled_policy", SledRoleEnum => "sled_role", SledStateEnum => "sled_state", @@ -85,9 +86,9 @@ define_enums! { VpcFirewallRuleProtocolEnum => "vpc_firewall_rule_protocol", VpcFirewallRuleStatusEnum => "vpc_firewall_rule_status", VpcRouterKindEnum => "vpc_router_kind", - WebhookEventClassEnum => "webhook_event_class", WebhookDeliveryAttemptResultEnum => "webhook_delivery_attempt_result", - WebhookDeliveryTriggerEnum => "webhook_delivery_trigger", WebhookDeliveryStateEnum => "webhook_delivery_state", + WebhookDeliveryTriggerEnum => "webhook_delivery_trigger", + WebhookEventClassEnum => "webhook_event_class", ZoneTypeEnum => "zone_type", } diff --git a/nexus/db-schema/src/schema.rs b/nexus/db-schema/src/schema.rs index ba699b579ac..5e2eeb07de4 100644 --- a/nexus/db-schema/src/schema.rs +++ b/nexus/db-schema/src/schema.rs @@ -2309,3 +2309,10 @@ allow_tables_to_appear_in_same_query!( webhook_delivery_attempt ); joinable!(webhook_delivery_attempt -> webhook_delivery (delivery_id)); + +table! { + setting (name) { + name -> crate::enums::SettingNameEnum, + int_value -> Nullable, + } +} diff --git a/nexus/src/app/background/tasks/physical_disk_adoption.rs b/nexus/src/app/background/tasks/physical_disk_adoption.rs index 35c72437ebc..d01da775a47 100644 --- a/nexus/src/app/background/tasks/physical_disk_adoption.rs +++ b/nexus/src/app/background/tasks/physical_disk_adoption.rs @@ -11,7 +11,6 @@ //! //! In the future, this may become more explicitly operator-controlled. -use crate::app::CONTROL_PLANE_STORAGE_BUFFER; use crate::app::background::BackgroundTask; use futures::FutureExt; use futures::future::BoxFuture; @@ -20,6 +19,7 @@ use nexus_db_model::Zpool; use nexus_db_queries::context::OpContext; use nexus_db_queries::db::DataStore; use nexus_types::identity::Asset; +use omicron_common::api::external::ByteCount; use omicron_common::api::external::DataPageParams; use omicron_uuid_kinds::CollectionUuid; use omicron_uuid_kinds::GenericUuid; @@ -62,6 +62,25 @@ impl BackgroundTask for PhysicalDiskAdoption { return json!({ "error": "task disabled" }); } + let control_plane_storage_buffer: ByteCount = match self + .datastore + .get_control_plane_storage_buffer(opctx) + .await { + Ok(value) => match value { + Some(value) => value, + None => { + // If no setting is in the database, use 0 + ByteCount::from(0) + } + }, + + Err(e) => { + return json!({ "error": format!( + "error getting control plane storage buffer: {e}" + )}); + } + }; + // Only adopt physical disks after rack handoff has completed. // // This prevents a race condition where the same physical disks @@ -140,7 +159,7 @@ impl BackgroundTask for PhysicalDiskAdoption { Uuid::new_v4(), inv_disk.sled_id.into_untyped_uuid(), disk.id(), - CONTROL_PLANE_STORAGE_BUFFER.into(), + control_plane_storage_buffer.into(), ); let result = self.datastore.physical_disk_and_zpool_insert( diff --git a/nexus/src/app/mod.rs b/nexus/src/app/mod.rs index 1291f369c73..0f6609a5c89 100644 --- a/nexus/src/app/mod.rs +++ b/nexus/src/app/mod.rs @@ -31,7 +31,6 @@ use nexus_types::deployment::PendingMgsUpdates; use omicron_common::address::DENDRITE_PORT; use omicron_common::address::MGD_PORT; use omicron_common::address::MGS_PORT; -use omicron_common::api::external::ByteCount; use omicron_common::api::external::Error; use omicron_common::api::internal::shared::SwitchLocation; use omicron_uuid_kinds::OmicronZoneUuid; @@ -135,14 +134,6 @@ pub const MAX_DISK_SIZE_BYTES: u64 = 1023 * (1 << 30); // 1023 GiB /// This value is aribtrary pub const MAX_SSH_KEYS_PER_INSTANCE: u32 = 100; -/// The amount of disk space to reserve for non-Crucible / control plane -/// storage. This amount represents a buffer that the region allocation query -/// will not use for each U2. -/// -/// See oxidecomputer/omicron#7875 for the 250G determination. -pub const CONTROL_PLANE_STORAGE_BUFFER: ByteCount = - ByteCount::from_gibibytes_u32(250); - /// Manages an Oxide fleet -- the heart of the control plane pub struct Nexus { /// uuid for this nexus instance. diff --git a/nexus/src/app/rack.rs b/nexus/src/app/rack.rs index 3db5e46f967..910028dfdb1 100644 --- a/nexus/src/app/rack.rs +++ b/nexus/src/app/rack.rs @@ -4,7 +4,6 @@ //! Rack management -use crate::app::CONTROL_PLANE_STORAGE_BUFFER; use crate::external_api::params; use crate::external_api::params::CertificateCreate; use crate::external_api::shared::ServiceUsingCertificate; @@ -53,6 +52,7 @@ use nexus_types::silo::silo_dns_name; use omicron_common::address::{Ipv6Subnet, RACK_PREFIX, get_64_subnet}; use omicron_common::api::external::AddressLotKind; use omicron_common::api::external::BgpPeer; +use omicron_common::api::external::ByteCount; use omicron_common::api::external::DataPageParams; use omicron_common::api::external::Error; use omicron_common::api::external::IdentityMetadataCreateParams; @@ -137,7 +137,10 @@ impl super::Nexus { pool.id, pool.sled_id, pool.physical_disk_id, - CONTROL_PLANE_STORAGE_BUFFER.into(), + ByteCount::from_gibibytes_u32( + request.control_plane_storage_buffer_gib, + ) + .into(), ) }) .collect(); @@ -728,6 +731,8 @@ impl super::Nexus { .into(), dns_update, allowed_source_ips: request.allowed_source_ips, + control_plane_storage_buffer_gib: request + .control_plane_storage_buffer_gib, }, ) .await?; diff --git a/nexus/src/lib.rs b/nexus/src/lib.rs index a2ee375726a..011b85a23f7 100644 --- a/nexus/src/lib.rs +++ b/nexus/src/lib.rs @@ -330,6 +330,7 @@ impl nexus_test_interface::NexusServer for Server { bfd: Vec::new(), }, allowed_source_ips: AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, }, ) .await diff --git a/nexus/types/src/internal_api/params.rs b/nexus/types/src/internal_api/params.rs index a1a707d12a9..70823656ea5 100644 --- a/nexus/types/src/internal_api/params.rs +++ b/nexus/types/src/internal_api/params.rs @@ -189,6 +189,10 @@ pub struct RackInitializationRequest { pub rack_network_config: RackNetworkConfig, /// IPs or subnets allowed to make requests to user-facing services pub allowed_source_ips: AllowedSourceIps, + /// The amount of space to reserve per-disk for non-Crucible storage (i.e. + /// control plane storage) in gibibytes. This amount represents a buffer + /// that the region allocation query will not use for each U2. + pub control_plane_storage_buffer_gib: u32, } pub type DnsConfigParams = internal_dns_types::config::DnsConfigParams; diff --git a/openapi/bootstrap-agent.json b/openapi/bootstrap-agent.json index ce16f185800..49bfa887532 100644 --- a/openapi/bootstrap-agent.json +++ b/openapi/bootstrap-agent.json @@ -944,6 +944,13 @@ } ] }, + "control_plane_storage_buffer_gib": { + "description": "The amount of space to reserve per-disk for non-Crucible storage (i.e. control plane storage) in gibibytes. This amount represents a buffer that the region allocation query will not use for each U2.", + "default": 0, + "type": "integer", + "format": "uint32", + "minimum": 0 + }, "dns_servers": { "description": "The external DNS server addresses.", "type": "array", diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index a9c6d4fa074..a42851569a1 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -5778,6 +5778,12 @@ "$ref": "#/components/schemas/Certificate" } }, + "control_plane_storage_buffer_gib": { + "description": "The amount of space to reserve per-disk for non-Crucible storage (i.e. control plane storage) in gibibytes. This amount represents a buffer that the region allocation query will not use for each U2.", + "type": "integer", + "format": "uint32", + "minimum": 0 + }, "crucible_datasets": { "description": "Crucible datasets on the rack which have been provisioned by RSS.", "type": "array", @@ -5847,6 +5853,7 @@ "allowed_source_ips", "blueprint", "certs", + "control_plane_storage_buffer_gib", "crucible_datasets", "external_dns_zone_name", "external_port_count", diff --git a/schema/crdb/dbinit.sql b/schema/crdb/dbinit.sql index d0b0e28004f..c58133f1743 100644 --- a/schema/crdb/dbinit.sql +++ b/schema/crdb/dbinit.sql @@ -5493,6 +5493,16 @@ ON omicron.public.webhook_delivery_attempt ( rx_id ); +CREATE TYPE IF NOT EXISTS omicron.public.setting_name AS ENUM ( + 'control_plane_storage_buffer' +); + +/* A table of Nexus' dynamic settings */ +CREATE TABLE IF NOT EXISTS omicron.public.setting ( + name omicron.public.setting_name PRIMARY KEY, + int_value INT +); + /* * Keep this at the end of file so that the database does not contain a version * until it is fully populated. @@ -5504,7 +5514,7 @@ INSERT INTO omicron.public.db_metadata ( version, target_version ) VALUES - (TRUE, NOW(), NOW(), '140.0.0', NULL) + (TRUE, NOW(), NOW(), '141.0.0', NULL) ON CONFLICT DO NOTHING; COMMIT; diff --git a/schema/crdb/nexus-settings/up01.sql b/schema/crdb/nexus-settings/up01.sql new file mode 100644 index 00000000000..1821e337b30 --- /dev/null +++ b/schema/crdb/nexus-settings/up01.sql @@ -0,0 +1,3 @@ +CREATE TYPE IF NOT EXISTS omicron.public.setting_name AS ENUM ( + 'control_plane_storage_buffer' +); diff --git a/schema/crdb/nexus-settings/up02.sql b/schema/crdb/nexus-settings/up02.sql new file mode 100644 index 00000000000..9251b1d9f73 --- /dev/null +++ b/schema/crdb/nexus-settings/up02.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS omicron.public.setting ( + name omicron.public.setting_name PRIMARY KEY, + int_value INT +); diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index 3a58e9583a8..a05b70bb332 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -1253,6 +1253,7 @@ mod tests { bfd: Vec::new(), }, allowed_source_ips: AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, } } diff --git a/sled-agent/src/rack_setup/service.rs b/sled-agent/src/rack_setup/service.rs index 85bef7032c6..b1da9e41dbd 100644 --- a/sled-agent/src/rack_setup/service.rs +++ b/sled-agent/src/rack_setup/service.rs @@ -988,6 +988,8 @@ impl ServiceInner { rack_network_config, external_port_count: port_discovery_mode.into(), allowed_source_ips, + control_plane_storage_buffer_gib: config + .control_plane_storage_buffer_gib, }; let notify_nexus = || async { diff --git a/sled-agent/src/sim/server.rs b/sled-agent/src/sim/server.rs index 05c75e18c0e..8d0bbce9ef2 100644 --- a/sled-agent/src/sim/server.rs +++ b/sled-agent/src/sim/server.rs @@ -595,6 +595,7 @@ pub async fn run_standalone_server( bfd: Vec::new(), }, allowed_source_ips: NexusTypes::AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, }; handoff_to_nexus(&log, &config, &rack_init_request).await?; diff --git a/sled-agent/types/src/rack_init.rs b/sled-agent/types/src/rack_init.rs index 0f047734c10..54a83cc610d 100644 --- a/sled-agent/types/src/rack_init.rs +++ b/sled-agent/types/src/rack_init.rs @@ -110,6 +110,7 @@ pub mod back_compat { recovery_silo: v1.recovery_silo, rack_network_config: v1.rack_network_config.into(), allowed_source_ips: v1.allowed_source_ips, + control_plane_storage_buffer_gib: 0, } } } @@ -131,6 +132,8 @@ struct UnvalidatedRackInitializeRequest { rack_network_config: RackNetworkConfig, #[serde(default = "default_allowed_source_ips")] allowed_source_ips: AllowedSourceIps, + #[serde(default)] + control_plane_storage_buffer_gib: u32, } fn validate_external_dns( @@ -177,6 +180,8 @@ impl TryFrom for RackInitializeRequest { recovery_silo: value.recovery_silo, rack_network_config: value.rack_network_config, allowed_source_ips: value.allowed_source_ips, + control_plane_storage_buffer_gib: value + .control_plane_storage_buffer_gib, }) } } @@ -229,6 +234,12 @@ pub struct RackInitializeRequest { /// IPs or subnets allowed to make requests to user-facing services #[serde(default = "default_allowed_source_ips")] pub allowed_source_ips: AllowedSourceIps, + + /// The amount of space to reserve per-disk for non-Crucible storage (i.e. + /// control plane storage) in gibibytes. This amount represents a buffer + /// that the region allocation query will not use for each U2. + #[serde(default)] + pub control_plane_storage_buffer_gib: u32, } impl RackInitializeRequest { @@ -386,6 +397,7 @@ impl std::fmt::Debug for RackInitializeRequest { recovery_silo, rack_network_config, allowed_source_ips, + control_plane_storage_buffer_gib, } = &self; f.debug_struct("RackInitializeRequest") @@ -403,6 +415,10 @@ impl std::fmt::Debug for RackInitializeRequest { .field("recovery_silo", recovery_silo) .field("rack_network_config", rack_network_config) .field("allowed_source_ips", allowed_source_ips) + .field( + "control_plane_storage_buffer_gib", + control_plane_storage_buffer_gib, + ) .finish() } } @@ -502,6 +518,7 @@ mod tests { bfd: Vec::new(), }, allowed_source_ips: AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, }; // Valid configs: all external DNS IPs are contained in the IP pool @@ -631,6 +648,7 @@ mod tests { bfd: Vec::new(), }, allowed_source_ips: AllowedSourceIps::Any, + control_plane_storage_buffer_gib: 0, }; assert_eq!( diff --git a/wicketd/src/rss_config.rs b/wicketd/src/rss_config.rs index 0223a565dfa..30d21228e86 100644 --- a/wicketd/src/rss_config.rs +++ b/wicketd/src/rss_config.rs @@ -314,6 +314,10 @@ impl CurrentRssConfig { .allowed_source_ips .clone() .unwrap_or(AllowedSourceIps::Any), + // Reserve a set amount of space for non-Crucible (i.e. control + // plane) storage. See oxidecomputer/omicron#7875 for the size + // determination. + control_plane_storage_buffer_gib: 250, }; Ok(request)