6
6
7
7
use super :: MgsUpdateStatus ;
8
8
use super :: MgsUpdateStatusError ;
9
+ use crate :: mgs_updates:: MgsUpdateOutcome ;
9
10
use nexus_types:: deployment:: BlueprintArtifactVersion ;
10
11
use nexus_types:: deployment:: BlueprintHostPhase2DesiredContents ;
11
12
use nexus_types:: deployment:: PendingMgsUpdate ;
12
13
use nexus_types:: deployment:: PendingMgsUpdateDetails ;
13
14
use nexus_types:: deployment:: PendingMgsUpdateHostPhase1Details ;
14
- use nexus_types:: deployment:: planning_report:: FailedMgsUpdateReason ;
15
+ use nexus_types:: deployment:: planning_report:: FailedHostOsUpdateReason ;
15
16
use nexus_types:: inventory:: BaseboardId ;
16
17
use nexus_types:: inventory:: Collection ;
17
18
use nexus_types:: inventory:: SpType ;
@@ -22,7 +23,6 @@ use omicron_uuid_kinds::SledUuid;
22
23
use slog:: Logger ;
23
24
use slog:: debug;
24
25
use slog:: error;
25
- use slog:: warn;
26
26
use std:: collections:: BTreeMap ;
27
27
use std:: sync:: Arc ;
28
28
use tufaceous_artifact:: ArtifactHash ;
@@ -273,39 +273,36 @@ pub(super) fn try_make_update(
273
273
baseboard_id : & Arc < BaseboardId > ,
274
274
inventory : & Collection ,
275
275
current_artifacts : & TufRepoDescription ,
276
- // TODO-K: Instead of this convoluted return type use an enum as suggested in
277
- // https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372837627
278
- ) -> Result <
279
- Option < ( PendingMgsUpdate , PendingHostPhase2Changes ) > ,
280
- FailedMgsUpdateReason ,
281
- > {
276
+ ) -> Result < MgsUpdateOutcome , FailedHostOsUpdateReason > {
282
277
let Some ( sp_info) = inventory. sps . get ( baseboard_id) else {
283
- return Err ( FailedMgsUpdateReason :: SpNotInInventory ) ;
278
+ return Err ( FailedHostOsUpdateReason :: SpNotInInventory ) ;
284
279
} ;
285
280
286
281
// Only configure host OS updates for sleds.
287
282
//
288
- // We don't bother logging a return value of `None ` for non-sleds, because
289
- // we will never attempt to configure an update for them (nor should we).
290
- // For the same reason, we do not return an error.
283
+ // We don't bother logging a return value of `NoUpdateNeeded ` for non-sleds,
284
+ // because we will never attempt to configure an update for them (nor should
285
+ // we). For the same reason, we do not return an error.
291
286
match sp_info. sp_type {
292
287
SpType :: Sled => ( ) ,
293
- SpType :: Power | SpType :: Switch => return Ok ( None ) ,
288
+ SpType :: Power | SpType :: Switch => {
289
+ return Ok ( MgsUpdateOutcome :: NoUpdateNeeded ) ;
290
+ }
294
291
}
295
292
296
293
let Some ( sled_agent) = inventory. sled_agents . iter ( ) . find ( |sled_agent| {
297
294
sled_agent. baseboard_id . as_ref ( ) == Some ( baseboard_id)
298
295
} ) else {
299
- return Err ( FailedMgsUpdateReason :: SledAgentInfoNotInInventory ) ;
296
+ return Err ( FailedHostOsUpdateReason :: SledAgentInfoNotInInventory ) ;
300
297
} ;
301
298
let Some ( last_reconciliation) = sled_agent. last_reconciliation . as_ref ( )
302
299
else {
303
- return Err ( FailedMgsUpdateReason :: LastReconciliationNotInInventory ) ;
300
+ return Err ( FailedHostOsUpdateReason :: LastReconciliationNotInInventory ) ;
304
301
} ;
305
302
let boot_disk = match & last_reconciliation. boot_partitions . boot_disk {
306
303
Ok ( boot_disk) => * boot_disk,
307
304
Err ( err) => {
308
- return Err ( FailedMgsUpdateReason :: UnableToDetermineBootDisk (
305
+ return Err ( FailedHostOsUpdateReason :: UnableToDetermineBootDisk (
309
306
err. to_string ( ) ,
310
307
) ) ;
311
308
}
@@ -315,17 +312,19 @@ pub(super) fn try_make_update(
315
312
Ok ( details) => details. artifact_hash ,
316
313
Err ( err) => {
317
314
return Err (
318
- FailedMgsUpdateReason :: UnableToRetrieveBootDiskPhase2Image (
319
- err. to_string ( ) ,
320
- ) ,
321
- ) ;
315
+ FailedHostOsUpdateReason :: UnableToRetrieveBootDiskPhase2Image (
316
+ err. to_string ( ) ,
317
+ ) ,
318
+ ) ;
322
319
}
323
320
} ;
324
321
325
322
let Some ( active_phase_1_slot) =
326
323
inventory. host_phase_1_active_slot_for ( baseboard_id) . map ( |s| s. slot )
327
324
else {
328
- return Err ( FailedMgsUpdateReason :: ActiveHostPhase1SlotNotInInventory ) ;
325
+ return Err (
326
+ FailedHostOsUpdateReason :: ActiveHostPhase1SlotNotInInventory ,
327
+ ) ;
329
328
} ;
330
329
331
330
// TODO-correctness What should we do if the active phase 1 slot doesn't
@@ -341,7 +340,7 @@ pub(super) fn try_make_update(
341
340
// this current implementation. As far as we know they shouldn't happen.
342
341
if active_phase_1_slot != boot_disk {
343
342
return Err (
344
- FailedMgsUpdateReason :: ActiveHostPhase1SlotBootDiskMismatch (
343
+ FailedHostOsUpdateReason :: ActiveHostPhase1SlotBootDiskMismatch (
345
344
active_phase_1_slot,
346
345
) ,
347
346
) ;
@@ -351,9 +350,11 @@ pub(super) fn try_make_update(
351
350
. host_phase_1_flash_hash_for ( active_phase_1_slot, baseboard_id)
352
351
. map ( |h| h. hash )
353
352
else {
354
- return Err ( FailedMgsUpdateReason :: ActiveHostPhase1HashNotInInventory (
355
- active_phase_1_slot,
356
- ) ) ;
353
+ return Err (
354
+ FailedHostOsUpdateReason :: ActiveHostPhase1HashNotInInventory (
355
+ active_phase_1_slot,
356
+ ) ,
357
+ ) ;
357
358
} ;
358
359
359
360
let Some ( inactive_phase_1_hash) = inventory
@@ -363,15 +364,8 @@ pub(super) fn try_make_update(
363
364
)
364
365
. map ( |h| h. hash )
365
366
else {
366
- warn ! (
367
- log,
368
- "cannot configure host OS update for board \
369
- (missing inactive phase 1 hash from inventory)";
370
- baseboard_id,
371
- "slot" => ?active_phase_1_slot. toggled( ) ,
372
- ) ;
373
367
return Err (
374
- FailedMgsUpdateReason :: InactiveHostPhase1HashNotInInventory (
368
+ FailedHostOsUpdateReason :: InactiveHostPhase1HashNotInInventory (
375
369
active_phase_1_slot. toggled ( ) ,
376
370
) ,
377
371
) ;
@@ -392,19 +386,26 @@ pub(super) fn try_make_update(
392
386
match ( phase_1_artifacts. as_slice ( ) , phase_2_artifacts. as_slice ( ) ) {
393
387
// Common case: Exactly 1 of each artifact.
394
388
( [ p1] , [ p2] ) => ( p1, p2) ,
395
- // "TUF is broken" cases: missing one or the other.
389
+ // "TUF is broken" cases: missing both, one or the other.
390
+ ( [ ] , [ ] ) => {
391
+ return Err ( FailedHostOsUpdateReason :: NoMatchingArtifactsFound ) ;
392
+ }
396
393
( [ ] , _) => {
397
- return Err ( FailedMgsUpdateReason :: NoMatchingArtifactFound ) ;
394
+ return Err (
395
+ FailedHostOsUpdateReason :: NoMatchingPhase1ArtifactFound ,
396
+ ) ;
398
397
}
399
398
( _, [ ] ) => {
400
- return Err ( FailedMgsUpdateReason :: NoMatchingArtifactFound ) ;
399
+ return Err (
400
+ FailedHostOsUpdateReason :: NoMatchingPhase2ArtifactFound ,
401
+ ) ;
401
402
}
402
403
// "TUF is broken" cases: have multiple of one or the other. This
403
404
// should be impossible unless we shipped a TUF repo with multiple
404
405
// host OS images. We can't proceed, because we don't know how to
405
406
// pair up which phase 1 matches which phase 2.
406
407
( _, _) => {
407
- return Err ( FailedMgsUpdateReason :: TooManyMatchingArtifacts ) ;
408
+ return Err ( FailedHostOsUpdateReason :: TooManyMatchingArtifacts ) ;
408
409
}
409
410
} ;
410
411
@@ -416,7 +417,7 @@ pub(super) fn try_make_update(
416
417
// this sled will fail to boot if it were rebooted now.)
417
418
if active_phase_2_hash == phase_2_artifact. hash {
418
419
debug ! ( log, "no host OS update needed for board" ; baseboard_id) ;
419
- return Ok ( None ) ;
420
+ return Ok ( MgsUpdateOutcome :: NoUpdateNeeded ) ;
420
421
}
421
422
422
423
// Before we can proceed with the phase 1 update, we need sled-agent to
@@ -432,7 +433,7 @@ pub(super) fn try_make_update(
432
433
phase_2_artifact,
433
434
) ;
434
435
435
- Ok ( Some ( (
436
+ Ok ( MgsUpdateOutcome :: Pending (
436
437
PendingMgsUpdate {
437
438
baseboard_id : baseboard_id. clone ( ) ,
438
439
sp_type : sp_info. sp_type ,
@@ -452,7 +453,7 @@ pub(super) fn try_make_update(
452
453
artifact_version : phase_1_artifact. id . version . clone ( ) ,
453
454
} ,
454
455
pending_host_phase_2_changes,
455
- ) ) )
456
+ ) )
456
457
}
457
458
458
459
#[ cfg( test) ]
0 commit comments