Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/trident/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ pub enum Commands {
#[clap(long, value_delimiter = ',', num_args = 0.., default_value = "stage,finalize")]
allowed_operations: Vec<AllowedOperation>,

/// Boolean indicating that a runtime update is expected. If Trident
/// determines that an A/B update is required, it will issue a fatal
/// error to avoid an unexpected reboot
#[clap(long)]
runtime: bool,

/// Path to save the resulting Host Status
#[clap(short, long)]
status: Option<PathBuf>,
Expand Down
6 changes: 6 additions & 0 deletions crates/trident/src/engine/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) fn update(
host_config: &HostConfiguration,
state: &mut DataStore,
allowed_operations: &Operations,
expect_runtime: bool,
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter name expect_runtime is inconsistent with the CLI flag name runtime used elsewhere in the codebase. For clarity and consistency, consider renaming this parameter to runtime to match the CLI flag name used in cli.rs, main.rs, and lib.rs.

Suggested change
expect_runtime: bool,
runtime: bool,

Copilot uses AI. Check for mistakes.
image: OsImage,
#[cfg(feature = "grpc-dangerous")] sender: &mut Option<GrpcSender>,
) -> Result<ExitKind, TridentError> {
Expand Down Expand Up @@ -80,6 +81,11 @@ pub(crate) fn update(
}
ServicingType::RuntimeUpdate => {}
ServicingType::AbUpdate => {
if expect_runtime {
return Err(TridentError::new(
InvalidInputError::AbUpdateRuntimeFlagMismatch,
));
}
Comment on lines +84 to +88
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new AbUpdateRuntimeFlagMismatch error behavior lacks test coverage. Given that this repository has comprehensive test coverage for other error cases and the update function handles critical update logic, this new error path should be tested to ensure it correctly prevents A/B updates when the --runtime flag is set.

Copilot uses AI. Check for mistakes.
// Execute pre-servicing scripts
HooksSubsystem::new_for_local_scripts().execute_pre_servicing_scripts(&ctx)?;
}
Expand Down
7 changes: 4 additions & 3 deletions crates/trident/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ impl Trident {
if let Some((host_config, allowed_operations, sender)) = receiver.blocking_recv() {
self.host_config = Some(host_config);
if let ExitKind::NeedsReboot =
self.update(datastore, allowed_operations, &mut Some(sender))?
self.update(datastore, allowed_operations, false, &mut Some(sender))?
{
reboot().message("Failed to reboot after grpc update")?;
}
Expand Down Expand Up @@ -549,6 +549,7 @@ impl Trident {
&mut self,
datastore: &mut DataStore,
allowed_operations: Operations,
runtime: bool,
#[cfg(feature = "grpc-dangerous")] sender: &mut Option<GrpcSender>,
) -> Result<ExitKind, TridentError> {
let mut host_config = self
Expand Down Expand Up @@ -585,7 +586,7 @@ impl Trident {
debug!("Host Configuration has been updated");
// If allowed operations include 'stage', start update
if allowed_operations.has_stage() {
engine::update(&host_config, datastore, &allowed_operations, image, #[cfg(feature = "grpc-dangerous")] sender).message("Failed to execute an update")
engine::update(&host_config, datastore, &allowed_operations, runtime, image, #[cfg(feature = "grpc-dangerous")] sender).message("Failed to execute an update")
} else {
warn!("Host Configuration has been updated but allowed operations do not include 'stage'. Add 'stage' and re-run to stage the update");
Ok(ExitKind::Done)
Expand Down Expand Up @@ -631,7 +632,7 @@ impl Trident {
ServicingState::AbUpdateFinalized | ServicingState::Provisioned => {
// Need to either re-execute the failed update OR inform the user that no update
// is needed.
engine::update(&host_config, datastore, &allowed_operations, image, #[cfg(feature = "grpc-dangerous")] sender).message("Failed to update host")
engine::update(&host_config, datastore, &allowed_operations, runtime, image, #[cfg(feature = "grpc-dangerous")] sender).message("Failed to execute an update")
}
servicing_state => {
Err(TridentError::new(InternalError::UnexpectedServicingState {
Expand Down
2 changes: 2 additions & 0 deletions crates/trident/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,12 @@ fn run_trident(
),
Commands::Update {
ref allowed_operations,
runtime,
..
} => trident.update(
&mut datastore,
cli::to_operations(allowed_operations),
runtime,
#[cfg(feature = "grpc-dangerous")]
&mut None,
),
Expand Down
7 changes: 7 additions & 0 deletions crates/trident_api/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ pub enum InternalError {
#[derive(Debug, Eq, thiserror::Error, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum InvalidInputError {
#[error(
"Determined that an A/B update is required, but Trident was run with --runtime flag \
indicating runtime update was expected. Returning fatal error to avoid unexpected reboot. \
Edit Host Configuration or re-run without the --runtime flag."
)]
AbUpdateRuntimeFlagMismatch,

#[error("Allowed operations must be passed via command line, not in Host Configuration")]
AllowedOperationsInHostConfiguration,

Expand Down
9 changes: 9 additions & 0 deletions docs/Reference/Trident-CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ Options:
-v, --verbosity <VERBOSITY>
Logging verbosity [OFF, ERROR, WARN, INFO, DEBUG, TRACE]
[default: DEBUG]
--runtime
Boolean indicating that a runtime update is expected. If
Trident determines that an A/B update is required, it will
issue a fatal error to avoid an unexpected reboot
-s, --status <STATUS>
Path to save the resulting Host Status
-e, --error <ERROR>
Expand Down Expand Up @@ -183,6 +187,11 @@ Possible values:
Default: `stage,finalize`


#### <span>--runtime &lt;RUNTIME&gt;</span>
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation header incorrectly shows --runtime <RUNTIME> for a boolean flag. Since this is a boolean flag (defined with #[clap(long)] without a value parser), it should not show a parameter placeholder in the header. It should be --runtime instead of --runtime <RUNTIME>.

Suggested change
#### <span>--runtime &lt;RUNTIME&gt;</span>
#### <span>--runtime</span>

Copilot uses AI. Check for mistakes.

Boolean indicating that a runtime update is expected. If Trident determines that an A/B update is required, it will issue a fatal error to avoid an unexpected reboot


#### <span>--status &lt;STATUS&gt;</span>

Path to save the resulting Host Status
Expand Down