Skip to content

Commit 28ffeef

Browse files
authored
Distinguish between Scrimlets and Gimlets (#1510)
* Distinguish between Scrimlets and Gimlets * Update scrimlet status on upsert
1 parent 2328063 commit 28ffeef

File tree

13 files changed

+103
-22
lines changed

13 files changed

+103
-22
lines changed

common/src/sql/dbinit.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ CREATE TABLE omicron.public.sled (
7878
/* FK into the Rack table */
7979
rack_id UUID NOT NULL,
8080

81+
/* Idenfities if this Sled is a Scrimlet */
82+
is_scrimlet BOOL NOT NULL,
83+
8184
/* The IP address and bound port of the sled agent server. */
8285
ip INET NOT NULL,
8386
port INT4 CHECK (port BETWEEN 0 AND 65535) NOT NULL,

nexus/db-model/src/schema.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ table! {
346346
rcgen -> Int8,
347347

348348
rack_id -> Uuid,
349+
is_scrimlet -> Bool,
349350
ip -> Inet,
350351
port -> Int4,
351352
last_used_address -> Inet,

nexus/db-model/src/sled.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub struct Sled {
2424

2525
pub rack_id: Uuid,
2626

27+
is_scrimlet: bool,
28+
2729
// ServiceAddress (Sled Agent).
2830
pub ip: ipv6::Ipv6Addr,
2931
pub port: SqlU16,
@@ -33,7 +35,12 @@ pub struct Sled {
3335
}
3436

3537
impl Sled {
36-
pub fn new(id: Uuid, addr: SocketAddrV6, rack_id: Uuid) -> Self {
38+
pub fn new(
39+
id: Uuid,
40+
addr: SocketAddrV6,
41+
is_scrimlet: bool,
42+
rack_id: Uuid,
43+
) -> Self {
3744
let last_used_address = {
3845
let mut segments = addr.ip().segments();
3946
segments[7] += omicron_common::address::RSS_RESERVED_ADDRESSES;
@@ -44,12 +51,17 @@ impl Sled {
4451
time_deleted: None,
4552
rcgen: Generation::new(),
4653
rack_id,
54+
is_scrimlet,
4755
ip: ipv6::Ipv6Addr::from(addr.ip()),
4856
port: addr.port().into(),
4957
last_used_address,
5058
}
5159
}
5260

61+
pub fn is_scrimlet(&self) -> bool {
62+
self.is_scrimlet
63+
}
64+
5365
pub fn ip(&self) -> Ipv6Addr {
5466
self.ip.into()
5567
}

nexus/src/app/sled.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ use crate::db::identity::Asset;
1010
use crate::db::lookup::LookupPath;
1111
use crate::db::model::DatasetKind;
1212
use crate::db::model::ServiceKind;
13-
use crate::internal_api::params::ZpoolPutRequest;
13+
use crate::internal_api::params::{
14+
SledAgentStartupInfo, SledRole, ZpoolPutRequest,
15+
};
1416
use omicron_common::api::external::DataPageParams;
1517
use omicron_common::api::external::Error;
1618
use omicron_common::api::external::ListResultVec;
1719
use omicron_common::api::external::LookupResult;
1820
use sled_agent_client::Client as SledAgentClient;
19-
use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
21+
use std::net::{Ipv6Addr, SocketAddr};
2022
use std::sync::Arc;
2123
use uuid::Uuid;
2224

@@ -28,10 +30,21 @@ impl super::Nexus {
2830
pub async fn upsert_sled(
2931
&self,
3032
id: Uuid,
31-
address: SocketAddrV6,
33+
info: SledAgentStartupInfo,
3234
) -> Result<(), Error> {
3335
info!(self.log, "registered sled agent"; "sled_uuid" => id.to_string());
34-
let sled = db::model::Sled::new(id, address, self.rack_id);
36+
37+
let is_scrimlet = match info.role {
38+
SledRole::Gimlet => false,
39+
SledRole::Scrimlet => true,
40+
};
41+
42+
let sled = db::model::Sled::new(
43+
id,
44+
info.sa_address,
45+
is_scrimlet,
46+
self.rack_id,
47+
);
3548
self.db_datastore.sled_upsert(sled).await?;
3649
Ok(())
3750
}

nexus/src/db/datastore/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,8 @@ mod test {
431431
);
432432
let rack_id = Uuid::new_v4();
433433
let sled_id = Uuid::new_v4();
434-
let sled = Sled::new(sled_id, bogus_addr.clone(), rack_id);
434+
let is_scrimlet = false;
435+
let sled = Sled::new(sled_id, bogus_addr.clone(), is_scrimlet, rack_id);
435436
datastore.sled_upsert(sled).await.unwrap();
436437
sled_id
437438
}
@@ -790,12 +791,13 @@ mod test {
790791
let rack_id = Uuid::new_v4();
791792
let addr1 = "[fd00:1de::1]:12345".parse().unwrap();
792793
let sled1_id = "0de4b299-e0b4-46f0-d528-85de81a7095f".parse().unwrap();
793-
let sled1 = db::model::Sled::new(sled1_id, addr1, rack_id);
794+
let is_scrimlet = false;
795+
let sled1 = db::model::Sled::new(sled1_id, addr1, is_scrimlet, rack_id);
794796
datastore.sled_upsert(sled1).await.unwrap();
795797

796798
let addr2 = "[fd00:1df::1]:12345".parse().unwrap();
797799
let sled2_id = "66285c18-0c79-43e0-e54f-95271f271314".parse().unwrap();
798-
let sled2 = db::model::Sled::new(sled2_id, addr2, rack_id);
800+
let sled2 = db::model::Sled::new(sled2_id, addr2, is_scrimlet, rack_id);
799801
datastore.sled_upsert(sled2).await.unwrap();
800802

801803
let ip = datastore.next_ipv6_address(&opctx, sled1_id).await.unwrap();

nexus/src/db/datastore/sled.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ impl DataStore {
3434
dsl::time_modified.eq(Utc::now()),
3535
dsl::ip.eq(sled.ip),
3636
dsl::port.eq(sled.port),
37+
dsl::rack_id.eq(sled.rack_id),
38+
dsl::is_scrimlet.eq(sled.is_scrimlet()),
3739
))
3840
.returning(Sled::as_returning())
3941
.get_result_async(self.pool())

nexus/src/internal_api/http_entrypoints.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type NexusApiDescription = ApiDescription<Arc<ServerContext>>;
3636
/// Returns a description of the internal nexus API
3737
pub fn internal_api() -> NexusApiDescription {
3838
fn register_endpoints(api: &mut NexusApiDescription) -> Result<(), String> {
39-
api.register(cpapi_sled_agents_post)?;
39+
api.register(sled_agent_put)?;
4040
api.register(rack_initialization_complete)?;
4141
api.register(zpool_put)?;
4242
api.register(dataset_put)?;
@@ -63,26 +63,22 @@ struct SledAgentPathParam {
6363
}
6464

6565
/// Report that the sled agent for the specified sled has come online.
66-
// TODO: Should probably be "PUT", since:
67-
// 1. We're upserting the value
68-
// 2. The client supplies the UUID
69-
// 3. This call is idempotent (mod "time_modified").
7066
#[endpoint {
7167
method = POST,
7268
path = "/sled-agents/{sled_id}",
7369
}]
74-
async fn cpapi_sled_agents_post(
70+
async fn sled_agent_put(
7571
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
7672
path_params: Path<SledAgentPathParam>,
7773
sled_info: TypedBody<SledAgentStartupInfo>,
7874
) -> Result<HttpResponseUpdatedNoContent, HttpError> {
7975
let apictx = rqctx.context();
8076
let nexus = &apictx.nexus;
8177
let path = path_params.into_inner();
82-
let si = sled_info.into_inner();
78+
let info = sled_info.into_inner();
8379
let sled_id = &path.sled_id;
8480
let handler = async {
85-
nexus.upsert_sled(*sled_id, si.sa_address).await?;
81+
nexus.upsert_sled(*sled_id, info).await?;
8682
Ok(HttpResponseUpdatedNoContent())
8783
};
8884
apictx.internal_latencies.instrument_dropshot_handler(&rqctx, handler).await

nexus/types/src/internal_api/params.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,28 @@ use std::net::SocketAddrV6;
1313
use std::str::FromStr;
1414
use uuid::Uuid;
1515

16+
/// Describes the role of the sled within the rack.
17+
///
18+
/// Note that this may change if the sled is physically moved
19+
/// within the rack.
20+
#[derive(Serialize, Deserialize, JsonSchema)]
21+
#[serde(rename_all = "snake_case")]
22+
pub enum SledRole {
23+
/// The sled is a general compute sled.
24+
Gimlet,
25+
/// The sled is attached to the network switch, and has additional
26+
/// responsibilities.
27+
Scrimlet,
28+
}
29+
1630
/// Sent by a sled agent on startup to Nexus to request further instruction
1731
#[derive(Serialize, Deserialize, JsonSchema)]
1832
pub struct SledAgentStartupInfo {
19-
/// the address of the sled agent's API endpoint
33+
/// The address of the sled agent's API endpoint
2034
pub sa_address: SocketAddrV6,
35+
36+
/// Describes the responsibilities of the sled
37+
pub role: SledRole,
2138
}
2239

2340
/// Sent by a sled agent on startup to Nexus to request further instruction

openapi/nexus-internal.json

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@
281281
"/sled-agents/{sled_id}": {
282282
"post": {
283283
"summary": "Report that the sled agent for the specified sled has come online.",
284-
"operationId": "cpapi_sled_agents_post",
284+
"operationId": "sled_agent_put",
285285
"parameters": [
286286
{
287287
"in": "path",
@@ -1788,15 +1788,32 @@
17881788
"description": "Sent by a sled agent on startup to Nexus to request further instruction",
17891789
"type": "object",
17901790
"properties": {
1791+
"role": {
1792+
"description": "Describes the responsibilities of the sled",
1793+
"allOf": [
1794+
{
1795+
"$ref": "#/components/schemas/SledRole"
1796+
}
1797+
]
1798+
},
17911799
"sa_address": {
1792-
"description": "the address of the sled agent's API endpoint",
1800+
"description": "The address of the sled agent's API endpoint",
17931801
"type": "string"
17941802
}
17951803
},
17961804
"required": [
1805+
"role",
17971806
"sa_address"
17981807
]
17991808
},
1809+
"SledRole": {
1810+
"description": "Describes the role of the sled within the rack.\n\nNote that this may change if the sled is physically moved within the rack.",
1811+
"type": "string",
1812+
"enum": [
1813+
"gimlet",
1814+
"scrimlet"
1815+
]
1816+
},
18001817
"ZpoolPutRequest": {
18011818
"description": "Sent by a sled agent on startup to Nexus to request further instruction",
18021819
"type": "object",

sled-agent/src/bootstrap/agent.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,20 @@ impl Agent {
263263

264264
return Ok(SledAgentResponse { id: server.id() });
265265
}
266+
267+
// TODO(https://github.com/oxidecomputer/omicron/issues/823):
268+
// Currently, the prescence or abscence of RSS is our signal
269+
// for "is this a scrimlet or not".
270+
// Longer-term, we should make this call based on the underlying
271+
// hardware.
272+
let is_scrimlet = self.rss.lock().await.is_some();
273+
266274
// Server does not exist, initialize it.
267275
let server = SledServer::start(
268276
&self.sled_config,
269277
self.parent_log.clone(),
270278
sled_address,
279+
is_scrimlet,
271280
request.rack_id,
272281
)
273282
.await

0 commit comments

Comments
 (0)