Skip to content

Commit ef871e2

Browse files
committed
okay i really hopep the CTE works
1 parent 05945f2 commit ef871e2

File tree

6 files changed

+314
-12
lines changed

6 files changed

+314
-12
lines changed

clients/nexus-client/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ impl From<omicron_common::api::internal::nexus::SledInstanceState>
136136
instance_state: s.instance_state.into(),
137137
propolis_id: s.propolis_id,
138138
vmm_state: s.vmm_state.into(),
139+
migration_state: None,
139140
}
140141
}
141142
}

common/src/api/internal/nexus.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ pub struct SledInstanceState {
9090
pub migration_state: Option<MigrationRuntimeState>,
9191
}
9292

93+
/// An update from a sled regarding the state of a migration, indicating the
94+
/// role of the VMM whose migration state was updated.
9395
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
9496
pub struct MigrationRuntimeState {
9597
pub migration_id: Uuid,
96-
9798
pub state: MigrationState,
99+
pub role: MigrationRole,
98100
}
99101

100102
/// The state of an instance's live migration.
@@ -127,6 +129,32 @@ impl fmt::Display for MigrationState {
127129
}
128130
}
129131

132+
#[derive(
133+
Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema,
134+
)]
135+
#[serde(rename_all = "snake_case")]
136+
pub enum MigrationRole {
137+
/// This update concerns the source VMM of a migration.
138+
Source,
139+
/// This update concerns the target VMM of a migration.
140+
Target,
141+
}
142+
143+
impl MigrationRole {
144+
pub fn label(&self) -> &'static str {
145+
match self {
146+
Self::Source => "source",
147+
Self::Target => "target",
148+
}
149+
}
150+
}
151+
152+
impl fmt::Display for MigrationRole {
153+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154+
f.write_str(self.label())
155+
}
156+
}
157+
130158
// Oximeter producer/collector objects.
131159

132160
/// The kind of metric producer this is.

nexus/db-queries/src/db/datastore/instance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ impl DataStore {
389389
new_instance.clone(),
390390
*vmm_id,
391391
new_vmm.clone(),
392+
None, // TODO: ELIZA ADD THIS
392393
);
393394

394395
// The InstanceAndVmmUpdate query handles and indicates failure to find

nexus/db-queries/src/db/queries/instance.rs

Lines changed: 135 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ use diesel::sql_types::{Nullable, Uuid as SqlUuid};
1212
use diesel::{pg::Pg, query_builder::AstPass};
1313
use diesel::{Column, ExpressionMethods, QueryDsl, RunQueryDsl};
1414
use nexus_db_model::{
15-
schema::{instance::dsl as instance_dsl, vmm::dsl as vmm_dsl},
16-
InstanceRuntimeState, VmmRuntimeState,
15+
schema::{
16+
instance::dsl as instance_dsl, migration::dsl as migration_dsl,
17+
vmm::dsl as vmm_dsl,
18+
},
19+
InstanceRuntimeState, MigrationState, VmmRuntimeState,
20+
};
21+
use omicron_common::api::internal::nexus::{
22+
MigrationRole, MigrationRuntimeState,
1723
};
1824
use uuid::Uuid;
1925

@@ -76,6 +82,12 @@ pub struct InstanceAndVmmUpdate {
7682
vmm_find: Box<dyn QueryFragment<Pg> + Send>,
7783
instance_update: Box<dyn QueryFragment<Pg> + Send>,
7884
vmm_update: Box<dyn QueryFragment<Pg> + Send>,
85+
migration: Option<MigrationUpdate>,
86+
}
87+
88+
struct MigrationUpdate {
89+
find: Box<dyn QueryFragment<Pg> + Send>,
90+
update: Box<dyn QueryFragment<Pg> + Send>,
7991
}
8092

8193
/// Contains the result of a combined instance-and-VMM update operation.
@@ -89,6 +101,11 @@ pub struct InstanceAndVmmUpdateResult {
89101
/// `Some(status)` if the target VMM was found; the wrapped `UpdateStatus`
90102
/// indicates whether the row was updated. `None` if the VMM was not found.
91103
pub vmm_status: Option<UpdateStatus>,
104+
105+
/// `Some(status)` if the target migration was found; the wrapped `UpdateStatus`
106+
/// indicates whether the row was updated. `None` if the migration was not
107+
/// found, or no migration update was performed.
108+
pub migration_status: Option<UpdateStatus>,
92109
}
93110

94111
/// Computes the update status to return from the results of queries that find
@@ -135,6 +152,7 @@ impl InstanceAndVmmUpdate {
135152
new_instance_runtime_state: InstanceRuntimeState,
136153
vmm_id: Uuid,
137154
new_vmm_runtime_state: VmmRuntimeState,
155+
migration: Option<MigrationRuntimeState>,
138156
) -> Self {
139157
let instance_find = Box::new(
140158
instance_dsl::instance
@@ -165,24 +183,92 @@ impl InstanceAndVmmUpdate {
165183
.set(new_vmm_runtime_state),
166184
);
167185

168-
Self { instance_find, vmm_find, instance_update, vmm_update }
186+
let migration = migration.map(
187+
|MigrationRuntimeState { role, migration_id, state }| {
188+
let state = MigrationState::from(state);
189+
match role {
190+
MigrationRole::Target => {
191+
let find = Box::new(
192+
migration_dsl::migration
193+
.filter(migration_dsl::id.eq(migration_id))
194+
.filter(
195+
migration_dsl::target_propolis_id
196+
.eq(vmm_id),
197+
)
198+
.select(migration_dsl::id),
199+
);
200+
let update = Box::new(
201+
diesel::update(migration_dsl::migration)
202+
.filter(migration_dsl::id.eq(migration_id))
203+
.filter(
204+
migration_dsl::target_propolis_id
205+
.eq(vmm_id),
206+
)
207+
.set(migration_dsl::target_state.eq(state)),
208+
);
209+
MigrationUpdate { find, update }
210+
}
211+
MigrationRole::Source => {
212+
let find = Box::new(
213+
migration_dsl::migration
214+
.filter(migration_dsl::id.eq(migration_id))
215+
.filter(
216+
migration_dsl::source_propolis_id
217+
.eq(vmm_id),
218+
)
219+
.select(migration_dsl::id),
220+
);
221+
let update = Box::new(
222+
diesel::update(migration_dsl::migration)
223+
.filter(migration_dsl::id.eq(migration_id))
224+
.filter(
225+
migration_dsl::source_propolis_id
226+
.eq(vmm_id),
227+
)
228+
.set(migration_dsl::source_state.eq(state)),
229+
);
230+
MigrationUpdate { find, update }
231+
}
232+
}
233+
},
234+
);
235+
236+
Self { instance_find, vmm_find, instance_update, vmm_update, migration }
169237
}
170238

171239
pub async fn execute_and_check(
172240
self,
173241
conn: &(impl async_bb8_diesel::AsyncConnection<DbConnection> + Sync),
174242
) -> Result<InstanceAndVmmUpdateResult, DieselError> {
175-
let (vmm_found, vmm_updated, instance_found, instance_updated) =
176-
self.get_result_async::<(Option<Uuid>,
177-
Option<Uuid>,
178-
Option<Uuid>,
179-
Option<Uuid>)>(conn).await?;
243+
let (
244+
vmm_found,
245+
vmm_updated,
246+
instance_found,
247+
instance_updated,
248+
migration_found,
249+
migration_updated,
250+
) = self
251+
.get_result_async::<(
252+
Option<Uuid>,
253+
Option<Uuid>,
254+
Option<Uuid>,
255+
Option<Uuid>,
256+
Option<Uuid>,
257+
Option<Uuid>,
258+
)>(conn)
259+
.await?;
180260

181261
let instance_status =
182262
compute_update_status(instance_found, instance_updated);
183263
let vmm_status = compute_update_status(vmm_found, vmm_updated);
264+
let migration_status =
265+
compute_update_status(migration_found, migration_updated);
184266

185-
Ok(InstanceAndVmmUpdateResult { instance_status, vmm_status })
267+
Ok(InstanceAndVmmUpdateResult {
268+
instance_status,
269+
vmm_status,
270+
migration_status,
271+
})
186272
}
187273
}
188274

@@ -197,6 +283,8 @@ impl Query for InstanceAndVmmUpdate {
197283
Nullable<SqlUuid>,
198284
Nullable<SqlUuid>,
199285
Nullable<SqlUuid>,
286+
Nullable<SqlUuid>,
287+
Nullable<SqlUuid>,
200288
);
201289
}
202290

@@ -212,6 +300,12 @@ impl QueryFragment<Pg> for InstanceAndVmmUpdate {
212300
self.vmm_find.walk_ast(out.reborrow())?;
213301
out.push_sql(") AS id), ");
214302

303+
if let Some(MigrationUpdate { ref find, .. }) = self.migration {
304+
out.push_sql("migration_found AS (SELECT (");
305+
find.walk_ast(out.reborrow())?;
306+
out.push_sql(") AS id), ");
307+
}
308+
215309
out.push_sql("instance_updated AS (");
216310
self.instance_update.walk_ast(out.reborrow())?;
217311
out.push_sql(" RETURNING id), ");
@@ -220,6 +314,12 @@ impl QueryFragment<Pg> for InstanceAndVmmUpdate {
220314
self.vmm_update.walk_ast(out.reborrow())?;
221315
out.push_sql(" RETURNING id), ");
222316

317+
if let Some(MigrationUpdate { ref update, .. }) = self.migration {
318+
out.push_sql("migration_updated AS (");
319+
update.walk_ast(out.reborrow())?;
320+
out.push_sql(" RETURNING id), ");
321+
}
322+
223323
out.push_sql("vmm_result AS (");
224324
out.push_sql("SELECT vmm_found.");
225325
out.push_identifier(vmm_dsl::id::NAME)?;
@@ -246,9 +346,33 @@ impl QueryFragment<Pg> for InstanceAndVmmUpdate {
246346
out.push_identifier(instance_dsl::id::NAME)?;
247347
out.push_sql(") ");
248348

349+
if self.migration.is_some() {
350+
out.push_sql("migration_result AS (");
351+
out.push_sql("SELECT migration_found.");
352+
out.push_identifier(migration_dsl::id::NAME)?;
353+
out.push_sql(" AS found, migration_updated.");
354+
out.push_identifier(migration_dsl::id::NAME)?;
355+
out.push_sql(" AS updated");
356+
out.push_sql(
357+
" FROM migration_found LEFT JOIN migration_updated ON migration_found.",
358+
);
359+
out.push_identifier(migration_dsl::id::NAME)?;
360+
out.push_sql(" = migration_updated.");
361+
out.push_identifier(migration_dsl::id::NAME)?;
362+
out.push_sql(") ");
363+
}
364+
249365
out.push_sql("SELECT vmm_result.found, vmm_result.updated, ");
250-
out.push_sql("instance_result.found, instance_result.updated ");
251-
out.push_sql("FROM vmm_result, instance_result;");
366+
out.push_sql("instance_result.found, instance_result.updated, ");
367+
if self.migration.is_some() {
368+
out.push_sql("migration_result.found, migration_result.updated");
369+
} else {
370+
out.push_sql("NULL, NULL");
371+
}
372+
out.push_sql("FROM vmm_result, instance_result");
373+
if self.migration.is_some() {
374+
out.push_sql(", migration_result");
375+
}
252376

253377
Ok(())
254378
}

openapi/nexus-internal.json

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,6 +3503,71 @@
35033503
"minLength": 5,
35043504
"maxLength": 17
35053505
},
3506+
"MigrationRole": {
3507+
"oneOf": [
3508+
{
3509+
"description": "This update concerns the source VMM of a migration.",
3510+
"type": "string",
3511+
"enum": [
3512+
"source"
3513+
]
3514+
},
3515+
{
3516+
"description": "This update concerns the target VMM of a migration.",
3517+
"type": "string",
3518+
"enum": [
3519+
"target"
3520+
]
3521+
}
3522+
]
3523+
},
3524+
"MigrationRuntimeState": {
3525+
"description": "An update from a sled regarding the state of a migration, indicating the role of the VMM whose migration state was updated.",
3526+
"type": "object",
3527+
"properties": {
3528+
"migration_id": {
3529+
"type": "string",
3530+
"format": "uuid"
3531+
},
3532+
"role": {
3533+
"$ref": "#/components/schemas/MigrationRole"
3534+
},
3535+
"state": {
3536+
"$ref": "#/components/schemas/MigrationState"
3537+
}
3538+
},
3539+
"required": [
3540+
"migration_id",
3541+
"role",
3542+
"state"
3543+
]
3544+
},
3545+
"MigrationState": {
3546+
"description": "The state of an instance's live migration.",
3547+
"oneOf": [
3548+
{
3549+
"description": "The migration is in progress.",
3550+
"type": "string",
3551+
"enum": [
3552+
"in_progress"
3553+
]
3554+
},
3555+
{
3556+
"description": "The migration has failed.",
3557+
"type": "string",
3558+
"enum": [
3559+
"failed"
3560+
]
3561+
},
3562+
{
3563+
"description": "The migration has completed.",
3564+
"type": "string",
3565+
"enum": [
3566+
"completed"
3567+
]
3568+
}
3569+
]
3570+
},
35063571
"Name": {
35073572
"title": "A name unique within the parent collection",
35083573
"description": "Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.",
@@ -4647,6 +4712,15 @@
46474712
}
46484713
]
46494714
},
4715+
"migration_state": {
4716+
"nullable": true,
4717+
"description": "The current state of any in-progress migration for this instance, as understood by this sled.",
4718+
"allOf": [
4719+
{
4720+
"$ref": "#/components/schemas/MigrationRuntimeState"
4721+
}
4722+
]
4723+
},
46504724
"propolis_id": {
46514725
"description": "The ID of the VMM whose state is being reported.",
46524726
"type": "string",

0 commit comments

Comments
 (0)