@@ -17,13 +17,16 @@ use sled_agent_config_reconciler::{ConfigReconcilerHandle, InventoryError};
1717use sled_agent_resolvable_files:: ZoneImageSourceResolver ;
1818use sled_agent_types:: inventory:: {
1919 ConfigReconcilerInventoryResult , OmicronSledConfig ,
20- SingleMeasurementInventory ,
20+ SingleMeasurementInventory , OmicronSingleMeasurement ,
21+ } ;
22+ use sled_agent_types:: resolvable_files:: {
23+ ManifestHashError , MupdateOverrideReadError ,
2124} ;
22- use sled_agent_types:: resolvable_files:: ManifestHashError ;
2325use slog:: Logger ;
24- use slog:: error;
26+ use slog:: { error, info , warn } ;
2527use slog_error_chain:: InlineErrorChain ;
2628use slog_error_chain:: SlogInlineError ;
29+ use std:: collections:: BTreeSet ;
2730use std:: sync:: Arc ;
2831use thiserror:: Error ;
2932use tokio:: sync:: oneshot;
@@ -42,6 +45,8 @@ pub enum MeasurementError {
4245 ManifestHashError ( #[ source] ManifestHashError ) ,
4346 #[ error( "Error notification from ledger start" ) ]
4447 LedgerStartFailure ,
48+ #[ error( "mupdate override error" ) ]
49+ MupdateOverrideError ( #[ source] MupdateOverrideReadError ) ,
4550}
4651
4752#[ derive( Clone ) ]
@@ -191,10 +196,114 @@ impl MeasurementsHandle {
191196 }
192197}
193198
194- // Right now we only take into account the install dataset/MUPdate case.
195- // Future work will also give artifact hashes.
196199fn measurements_from_sled_config (
197- _config : & OmicronSledConfig ,
200+ config : & OmicronSledConfig ,
201+ log : & Logger ,
202+ config_reconciler : & Arc < ConfigReconcilerHandle > ,
203+ zone_image_resolver : & ZoneImageSourceResolver ,
204+ ) -> Result < Vec < Utf8PathBuf > , MeasurementError > {
205+ let status = zone_image_resolver. status ( ) ;
206+ let use_install = config. measurements . is_empty ( ) ;
207+
208+ match ( & status. mupdate_override . boot_disk_override , use_install) {
209+ // We are set to use the install dataset and there is a MUPdate override
210+ ( Ok ( Some ( override_info) ) , true ) => {
211+ info ! ( log, "mupdate override active, already using install dataset" ;
212+ "mupdate_override_id" => %override_info. mupdate_uuid) ;
213+ measurements_from_install_dataset (
214+ log,
215+ config_reconciler,
216+ zone_image_resolver,
217+ )
218+ }
219+ // Actual override case! Use the install dataset
220+ ( Ok ( Some ( override_info) ) , false ) => {
221+ info ! ( log, "mupdate override active, redirecting to install \
222+ dataset from artifacts";
223+ "mupdate_override_id" => %override_info. mupdate_uuid) ;
224+ measurements_from_install_dataset (
225+ log,
226+ config_reconciler,
227+ zone_image_resolver,
228+ )
229+ }
230+ // No override is active but we're still using the install dataset
231+ ( Ok ( None ) , true ) => measurements_from_install_dataset (
232+ log,
233+ config_reconciler,
234+ zone_image_resolver,
235+ ) ,
236+ // No override and we're not using the install dataset
237+ ( Ok ( None ) , false ) => measurements_from_artifact_dataset (
238+ config_reconciler,
239+ & config. measurements ,
240+ ) ,
241+ // Error getting the mupdate override but we're still set to use
242+ // the install dataset
243+ ( Err ( error) , true ) => {
244+ warn ! ( log, "error obtaining mupdate override but we're still \
245+ using install dataset, proceeding with caution";
246+ "error" => InlineErrorChain :: new( error) ) ;
247+ measurements_from_install_dataset (
248+ log,
249+ config_reconciler,
250+ zone_image_resolver,
251+ )
252+ }
253+ // Error getting the mupdate override but we're supposed to
254+ // use the artifacts
255+ ( Err ( error) , false ) => {
256+ error ! ( log, "error obtaining mupdate override, can't use the \
257+ artifacts, returning an error";
258+ "error" => InlineErrorChain :: new( error) ) ;
259+
260+ Err ( MeasurementError :: MupdateOverrideError ( error. clone ( ) ) )
261+ }
262+ }
263+ }
264+
265+ fn measurements_from_artifact_dataset (
266+ config_reconciler : & Arc < ConfigReconcilerHandle > ,
267+ measurements : & BTreeSet < OmicronSingleMeasurement > ,
268+ ) -> Result < Vec < Utf8PathBuf > , MeasurementError > {
269+ let mut valid = Vec :: new ( ) ;
270+ let mut errors = Vec :: new ( ) ;
271+
272+ for m in measurements {
273+ // We have mulitple possible artifact paths. We only need one per hash
274+ let mut found = false ;
275+ for dataset in config_reconciler
276+ . internal_disks_rx ( )
277+ . current ( )
278+ . all_artifact_datasets ( )
279+ {
280+ let potential_path = dataset. join ( m. hash . to_string ( ) ) ;
281+
282+ // This could technically be a TOCTOU issue but arguably all the paths we
283+ // return have the same potential issue and hopefully the callers handle
284+ // the failure gracefully
285+ if potential_path. is_file ( ) {
286+ found = true ;
287+ valid. push ( potential_path) ;
288+ break ;
289+ }
290+ }
291+ if !found {
292+ errors. push ( format ! (
293+ "artifact {} missing from all artifact datasets" ,
294+ m. hash
295+ ) ) ;
296+ }
297+ }
298+
299+ if errors. is_empty ( ) {
300+ Ok ( valid)
301+ } else {
302+ Err ( MeasurementError :: Paths { valid, errors } )
303+ }
304+ }
305+
306+ fn measurements_from_install_dataset (
198307 log : & Logger ,
199308 config_reconciler : & Arc < ConfigReconcilerHandle > ,
200309 zone_image_resolver : & ZoneImageSourceResolver ,
0 commit comments