Skip to content

Commit 171fe2e

Browse files
committed
Make the planner watch for inventory collections
1 parent 3274431 commit 171fe2e

File tree

3 files changed

+101
-67
lines changed

3 files changed

+101
-67
lines changed

dev-tools/omdb/tests/successes.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ task: "bfd_manager"
528528
task: "blueprint_planner"
529529
configured period: every <REDACTED_DURATION>m
530530
currently executing: no
531-
last completed activation: <REDACTED ITERATIONS>, triggered by a periodic timer firing
531+
last completed activation: <REDACTED ITERATIONS>, triggered by a dependent task completing
532532
started at <REDACTED_TIMESTAMP> (<REDACTED DURATION>s ago) and ran for <REDACTED DURATION>ms
533533
last completion reported error: no target blueprint to use as parent for planning
534534

@@ -1054,7 +1054,7 @@ task: "bfd_manager"
10541054
task: "blueprint_planner"
10551055
configured period: every <REDACTED_DURATION>m
10561056
currently executing: no
1057-
last completed activation: <REDACTED ITERATIONS>, triggered by a periodic timer firing
1057+
last completed activation: <REDACTED ITERATIONS>, triggered by a dependent task completing
10581058
started at <REDACTED_TIMESTAMP> (<REDACTED DURATION>s ago) and ran for <REDACTED DURATION>ms
10591059
last completion reported error: no target blueprint to use as parent for planning
10601060

nexus/src/app/background/init.rs

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -418,38 +418,12 @@ impl BackgroundTasksInitializer {
418418
};
419419

420420
// Background task: blueprint loader
421+
//
422+
// Registration is below so that it can watch the planner.
421423
let blueprint_loader =
422424
blueprint_load::TargetBlueprintLoader::new(datastore.clone());
423425
let rx_blueprint = blueprint_loader.watcher();
424426

425-
// Background task: blueprint planner
426-
let blueprint_planner = blueprint_planner::BlueprintPlanner::new(
427-
datastore.clone(),
428-
false,
429-
rx_blueprint.clone(),
430-
);
431-
let rx_planner = blueprint_planner.watcher();
432-
driver.register(TaskDefinition {
433-
name: "blueprint_planner",
434-
description: "Updates the target blueprint",
435-
period: config.blueprints.period_secs_plan,
436-
task_impl: Box::new(blueprint_planner),
437-
opctx: opctx.child(BTreeMap::new()),
438-
watchers: vec![Box::new(rx_blueprint.clone())],
439-
activator: task_blueprint_planner,
440-
});
441-
442-
// The planner notifies the loader when it has generated a new target blueprint.
443-
driver.register(TaskDefinition {
444-
name: "blueprint_loader",
445-
description: "Loads the current target blueprint from the DB",
446-
period: config.blueprints.period_secs_load,
447-
task_impl: Box::new(blueprint_loader),
448-
opctx: opctx.child(BTreeMap::new()),
449-
watchers: vec![Box::new(rx_planner.clone())],
450-
activator: task_blueprint_loader,
451-
});
452-
453427
// Background task: blueprint executor
454428
let blueprint_executor = blueprint_execution::BlueprintExecutor::new(
455429
datastore.clone(),
@@ -470,22 +444,6 @@ impl BackgroundTasksInitializer {
470444
activator: task_blueprint_executor,
471445
});
472446

473-
// Background task: CockroachDB node ID collector
474-
let crdb_node_id_collector =
475-
crdb_node_id_collector::CockroachNodeIdCollector::new(
476-
datastore.clone(),
477-
rx_blueprint.clone(),
478-
);
479-
driver.register(TaskDefinition {
480-
name: "crdb_node_id_collector",
481-
description: "Collects node IDs of running CockroachDB zones",
482-
period: config.blueprints.period_secs_collect_crdb_node_ids,
483-
task_impl: Box::new(crdb_node_id_collector),
484-
opctx: opctx.child(BTreeMap::new()),
485-
watchers: vec![Box::new(rx_blueprint.clone())],
486-
activator: task_crdb_node_id_collector,
487-
});
488-
489447
// Background task: inventory collector
490448
//
491449
// This depends on the "output" of the blueprint executor in
@@ -515,6 +473,58 @@ impl BackgroundTasksInitializer {
515473
inventory_watcher
516474
};
517475

476+
// Background task: blueprint planner
477+
//
478+
// Replans on inventory collection and changes to the current
479+
// target blueprint.
480+
let blueprint_planner = blueprint_planner::BlueprintPlanner::new(
481+
datastore.clone(),
482+
false,
483+
inventory_watcher.clone(),
484+
rx_blueprint.clone(),
485+
);
486+
let rx_planner = blueprint_planner.watcher();
487+
driver.register(TaskDefinition {
488+
name: "blueprint_planner",
489+
description: "Updates the target blueprint",
490+
period: config.blueprints.period_secs_plan,
491+
task_impl: Box::new(blueprint_planner),
492+
opctx: opctx.child(BTreeMap::new()),
493+
watchers: vec![
494+
Box::new(inventory_watcher.clone()),
495+
Box::new(rx_blueprint.clone()),
496+
],
497+
activator: task_blueprint_planner,
498+
});
499+
500+
// The loader watches the planner so that it can immediately load
501+
// a new target blueprint.
502+
driver.register(TaskDefinition {
503+
name: "blueprint_loader",
504+
description: "Loads the current target blueprint from the DB",
505+
period: config.blueprints.period_secs_load,
506+
task_impl: Box::new(blueprint_loader),
507+
opctx: opctx.child(BTreeMap::new()),
508+
watchers: vec![Box::new(rx_planner.clone())],
509+
activator: task_blueprint_loader,
510+
});
511+
512+
// Background task: CockroachDB node ID collector
513+
let crdb_node_id_collector =
514+
crdb_node_id_collector::CockroachNodeIdCollector::new(
515+
datastore.clone(),
516+
rx_blueprint.clone(),
517+
);
518+
driver.register(TaskDefinition {
519+
name: "crdb_node_id_collector",
520+
description: "Collects node IDs of running CockroachDB zones",
521+
period: config.blueprints.period_secs_collect_crdb_node_ids,
522+
task_impl: Box::new(crdb_node_id_collector),
523+
opctx: opctx.child(BTreeMap::new()),
524+
watchers: vec![Box::new(rx_blueprint.clone())],
525+
activator: task_crdb_node_id_collector,
526+
});
527+
518528
// Cleans up and collects support bundles.
519529
//
520530
// This task is triggered by blueprint execution, since blueprint

nexus/src/app/background/tasks/blueprint_planner.rs

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use nexus_reconfigurator_planning::planner::Planner;
1313
use nexus_reconfigurator_preparation::PlanningInputFromDb;
1414
use nexus_types::deployment::{Blueprint, BlueprintTarget};
1515
use nexus_types::internal_api::background::BlueprintPlannerStatus;
16+
use omicron_uuid_kinds::CollectionUuid;
1617
use serde_json::json;
1718
use std::sync::Arc;
1819
use tokio::sync::watch::{self, Receiver, Sender};
@@ -21,6 +22,7 @@ use tokio::sync::watch::{self, Receiver, Sender};
2122
pub struct BlueprintPlanner {
2223
datastore: Arc<DataStore>,
2324
disabled: bool,
25+
rx_inventory: Receiver<Option<CollectionUuid>>,
2426
rx_blueprint: Receiver<Option<Arc<(BlueprintTarget, Blueprint)>>>,
2527
tx_blueprint: Sender<Option<Arc<(BlueprintTarget, Blueprint)>>>,
2628
}
@@ -29,10 +31,11 @@ impl BlueprintPlanner {
2931
pub fn new(
3032
datastore: Arc<DataStore>,
3133
disabled: bool,
34+
rx_inventory: Receiver<Option<CollectionUuid>>,
3235
rx_blueprint: Receiver<Option<Arc<(BlueprintTarget, Blueprint)>>>,
3336
) -> Self {
3437
let (tx_blueprint, _) = watch::channel(None);
35-
Self { datastore, disabled, rx_blueprint, tx_blueprint }
38+
Self { datastore, disabled, rx_inventory, rx_blueprint, tx_blueprint }
3639
}
3740

3841
pub fn watcher(
@@ -53,7 +56,8 @@ impl BlueprintPlanner {
5356
}
5457

5558
// Get the current target blueprint to use as a parent.
56-
let Some(rx) = self.rx_blueprint.borrow_and_update().clone() else {
59+
// Cloned so that we don't block the channel.
60+
let Some(loaded) = self.rx_blueprint.borrow_and_update().clone() else {
5761
warn!(
5862
&opctx.log,
5963
"blueprint planning skipped";
@@ -64,34 +68,54 @@ impl BlueprintPlanner {
6468
));
6569
return status;
6670
};
67-
let (target, parent) = &*rx;
71+
let (target, parent) = &*loaded;
6872

69-
// Assemble the planning context.
70-
let input = match PlanningInputFromDb::assemble(opctx, &self.datastore)
73+
// Get the inventory most recently seen by the collection
74+
// background task. The value is `Copy`, so with the deref
75+
// we don't block the channel.
76+
let Some(collection_id) = *self.rx_inventory.borrow_and_update() else {
77+
warn!(
78+
&opctx.log,
79+
"blueprint planning skipped";
80+
"reason" => "no inventory collection available"
81+
);
82+
status.error =
83+
Some(String::from("no inventory collection available"));
84+
return status;
85+
};
86+
let collection = match self
87+
.datastore
88+
.inventory_collection_read(opctx, collection_id)
7189
.await
7290
{
73-
Ok(input) => input,
91+
Ok(collection) => collection,
7492
Err(error) => {
75-
error!(&opctx.log, "can't assemble planning input: {error}");
76-
status.error = Some(error.to_string());
93+
error!(
94+
&opctx.log,
95+
"can't read inventory collection";
96+
"collection_id" => %collection_id,
97+
"error" => %error,
98+
);
99+
status.error = Some(format!(
100+
"can't read inventory collection {}: {}",
101+
collection_id, error
102+
));
77103
return status;
78104
}
79105
};
80-
let inventory =
81-
match self.datastore.inventory_get_latest_collection(opctx).await {
82-
Ok(Some(inventory)) => inventory,
83-
Ok(None) => {
84-
error!(&opctx.log, "no recent inventory collection");
85-
status.error =
86-
Some(String::from("no recent inventory collection"));
87-
return status;
88-
}
106+
107+
// Assemble the planning context.
108+
let input =
109+
match PlanningInputFromDb::assemble(opctx, &self.datastore).await {
110+
Ok(input) => input,
89111
Err(error) => {
90112
error!(
91113
&opctx.log,
92-
"can't get latest inventory collection: {error}"
114+
"can't assemble planning input";
115+
"error" => %error,
93116
);
94-
status.error = Some(error.to_string());
117+
status.error =
118+
Some(format!("can't assemble planning input: {error}"));
95119
return status;
96120
}
97121
};
@@ -102,7 +126,7 @@ impl BlueprintPlanner {
102126
&parent,
103127
&input,
104128
"blueprint_planner",
105-
&inventory,
129+
&collection,
106130
) {
107131
Ok(planner) => planner,
108132
Err(error) => {
@@ -169,7 +193,7 @@ impl BlueprintPlanner {
169193
{
170194
Ok(()) => (),
171195
Err(error) => {
172-
error!(
196+
warn!(
173197
&opctx.log,
174198
"can't make blueprint the current target";
175199
"error" => %error,

0 commit comments

Comments
 (0)