Skip to content

Commit 3690806

Browse files
authored
[nexus] Add service to DB, add rack initialization API (#1169)
This PR implements the "internal API" from RFD 278 which will be invoked by RSS to initialize the rack. Currently, this API has no callers, and nothing is blocked on the value of rack.initialized being set. Fixes #1149
1 parent 4a3815b commit 3690806

File tree

17 files changed

+654
-34
lines changed

17 files changed

+654
-34
lines changed

common/src/address.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const _ANYCAST_ADDRESS_INDEX: usize = 0;
4646
const DNS_ADDRESS_INDEX: usize = 1;
4747
const GZ_ADDRESS_INDEX: usize = 2;
4848

49+
/// The maximum number of addresses per sled reserved for RSS.
50+
pub const RSS_RESERVED_ADDRESSES: u16 = 10;
51+
4952
/// Wraps an [`Ipv6Network`] with a compile-time prefix length.
5053
#[derive(Debug, Clone, Copy, JsonSchema, Serialize, Deserialize, PartialEq)]
5154
pub struct Ipv6Subnet<const N: u8> {

common/src/api/external/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ pub enum ResourceType {
527527
Instance,
528528
NetworkInterface,
529529
Rack,
530+
Service,
530531
Sled,
531532
SagaDbg,
532533
Snapshot,

common/src/sql/dbinit.sql

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ CREATE TABLE omicron.public.rack (
4848
time_created TIMESTAMPTZ NOT NULL,
4949
time_modified TIMESTAMPTZ NOT NULL,
5050

51+
/*
52+
* Identifies if rack management has been transferred from RSS -> Nexus.
53+
* If "false", RSS is still managing sleds, services, and DNS records.
54+
*
55+
* This value is set to "true" when RSS calls the
56+
* "rack_initialization_complete" endpoint on Nexus' internal interface.
57+
*
58+
* See RFD 278 for more detail.
59+
*/
60+
initialized BOOL NOT NULL,
61+
5162
/* Used to configure the updates service URL */
5263
tuf_base_url STRING(512)
5364
);
@@ -72,6 +83,35 @@ CREATE TABLE omicron.public.sled (
7283
last_used_address INET NOT NULL
7384
);
7485

86+
/*
87+
* Services
88+
*/
89+
90+
CREATE TYPE omicron.public.service_kind AS ENUM (
91+
'internal_dns',
92+
'nexus',
93+
'oximeter'
94+
);
95+
96+
CREATE TABLE omicron.public.service (
97+
/* Identity metadata (asset) */
98+
id UUID PRIMARY KEY,
99+
time_created TIMESTAMPTZ NOT NULL,
100+
time_modified TIMESTAMPTZ NOT NULL,
101+
102+
/* FK into the Sled table */
103+
sled_id UUID NOT NULL,
104+
/* The IP address of the service. */
105+
ip INET NOT NULL,
106+
/* Indicates the type of service. */
107+
kind omicron.public.service_kind NOT NULL
108+
);
109+
110+
/* Add an index which lets us look up the services on a sled */
111+
CREATE INDEX ON omicron.public.service (
112+
sled_id
113+
);
114+
75115
/*
76116
* ZPools of Storage, attached to Sleds.
77117
* Typically these are backed by a single physical disk.

nexus/src/app/rack.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use crate::authz;
88
use crate::context::OpContext;
99
use crate::db;
10+
use crate::internal_api::params::ServicePutRequest;
1011
use futures::future::ready;
1112
use futures::StreamExt;
1213
use omicron_common::api::external::DataPageParams;
@@ -21,6 +22,7 @@ impl super::Nexus {
2122
pub(crate) fn as_rack(&self) -> db::model::Rack {
2223
db::model::Rack {
2324
identity: self.api_rack_identity.clone(),
25+
initialized: true,
2426
tuf_base_url: None,
2527
}
2628
}
@@ -59,4 +61,35 @@ impl super::Nexus {
5961
Err(Error::not_found_by_id(ResourceType::Rack, rack_id))
6062
}
6163
}
64+
65+
/// Marks the rack as initialized with a set of services.
66+
///
67+
/// This function is a no-op if the rack has already been initialized.
68+
pub async fn rack_initialize(
69+
&self,
70+
opctx: &OpContext,
71+
rack_id: Uuid,
72+
services: Vec<ServicePutRequest>,
73+
) -> Result<(), Error> {
74+
opctx.authorize(authz::Action::Modify, &authz::FLEET).await?;
75+
76+
// Convert from parameter -> DB type.
77+
let services: Vec<_> = services
78+
.into_iter()
79+
.map(|svc| {
80+
db::model::Service::new(
81+
svc.service_id,
82+
svc.sled_id,
83+
svc.address,
84+
svc.kind.into(),
85+
)
86+
})
87+
.collect();
88+
89+
self.db_datastore
90+
.rack_set_initialized(opctx, rack_id, services)
91+
.await?;
92+
93+
Ok(())
94+
}
6295
}

nexus/src/app/sled.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ use crate::db;
99
use crate::db::identity::Asset;
1010
use crate::db::lookup::LookupPath;
1111
use crate::db::model::DatasetKind;
12+
use crate::db::model::ServiceKind;
1213
use crate::internal_api::params::ZpoolPutRequest;
1314
use omicron_common::api::external::DataPageParams;
1415
use omicron_common::api::external::Error;
1516
use omicron_common::api::external::ListResultVec;
1617
use omicron_common::api::external::LookupResult;
1718
use sled_agent_client::Client as SledAgentClient;
18-
use std::net::{SocketAddr, SocketAddrV6};
19+
use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
1920
use std::sync::Arc;
2021
use uuid::Uuid;
2122

@@ -142,4 +143,27 @@ impl super::Nexus {
142143
self.db_datastore.dataset_upsert(dataset).await?;
143144
Ok(())
144145
}
146+
147+
// Services
148+
149+
/// Upserts a Service into the database, updating it if it already exists.
150+
pub async fn upsert_service(
151+
&self,
152+
opctx: &OpContext,
153+
id: Uuid,
154+
sled_id: Uuid,
155+
address: Ipv6Addr,
156+
kind: ServiceKind,
157+
) -> Result<(), Error> {
158+
info!(
159+
self.log,
160+
"upserting service";
161+
"sled_id" => sled_id.to_string(),
162+
"service_id" => id.to_string(),
163+
"address" => address.to_string(),
164+
);
165+
let service = db::model::Service::new(id, sled_id, address, kind);
166+
self.db_datastore.service_upsert(opctx, service).await?;
167+
Ok(())
168+
}
145169
}

0 commit comments

Comments
 (0)