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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased] - yyyy-mm-dd

### Changed

- Internally refactor how nodes are "executed", split into two distinct
stages. "Planning" and "Executing". Previously, these two were intertwined and
difficult to maintain.
- Now zeroizes the key data in memory when dropped.

### Fixed

- Fix a bug where key permissions where being printed in decimal format instead
Expand Down
57 changes: 55 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
[workspace]
members = ["crates/key_agent", "crates/core", "crates/cli"]
members = [
"crates/key_agent",
"crates/core",
"crates/cli",
"crates/plan",
"crates/keys",
"crates/execute",
]
resolver = "2"
package.edition = "2024"
package.version = "1.1.1"
Expand All @@ -26,6 +33,7 @@ tracing-log = "0.2.0"
tracing-subscriber = "0.3.20"
im = { version = "15.1.0", features = ["serde"] }
anyhow = "1.0.100"
secrecy = "0.10.3"
prost = "0.14.1"
nix = { version = "0.30.1", features = ["user", "poll", "term"] }
miette = { version = "7.6.0", features = ["fancy"] }
Expand All @@ -47,6 +55,5 @@ nix-compat = { git = "https://git.snix.dev/snix/snix.git", features = [
# ] }
serde_json = { version = "1.0.145" }
owo-colors = { version = "4.2.3", features = ["supports-colors"] }

[profile.dev.package.sqlx-macros]
opt-level = 3
enum_dispatch = { version = "0.3.13" }
itertools = "0.14.0"
5 changes: 3 additions & 2 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,22 @@ workspace = true
dhat-heap = []

[dependencies]
wire-core = { path = "../core" }
wire-plan = { path = "../plan" }
clap = { workspace = true }
clap-verbosity-flag = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
tracing-log = { workspace = true }
tracing-subscriber = { workspace = true }
wire-core = { path = "../core" }
serde_json = { workspace = true }
miette = { workspace = true }
thiserror = { workspace = true }
enum-display-derive = "0.1.1"
futures = "0.3.31"
clap-num = "1.2.0"
clap-markdown = "0.1.5"
itertools = "0.14.0"
itertools.workspace = true
dhat = "0.3.2"
clap_complete = { version = "4.5.60", features = ["unstable-dynamic"] }
owo-colors = { workspace = true }
Expand Down
114 changes: 59 additions & 55 deletions crates/cli/src/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
// Copyright 2024-2025 wire Contributors

use futures::{FutureExt, StreamExt};
use itertools::{Either, Itertools};
use itertools::Itertools;
use miette::{Diagnostic, IntoDiagnostic, Result};
use wire_plan::{Goal, plan_for_node};
use std::any::Any;
use std::collections::HashSet;
use std::io::{Read, stderr};
use std::collections::{HashMap, HashSet};
use std::io::Read;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use thiserror::Error;
use tracing::{error, info};
use wire_core::hive::node::{Context, GoalExecutor, Name, Node, Objective, StepState};
use wire_core::hive::node::{Name, Node};
use wire_core::hive::{Hive, HiveLocation};
use wire_core::status::STATUS;
use wire_core::{SubCommandModifiers, errors::HiveLibError};
Expand Down Expand Up @@ -96,17 +97,17 @@ where

pub async fn apply<F>(
hive: &mut Hive,
should_shutdown: Arc<AtomicBool>,
_should_shutdown: Arc<AtomicBool>,
location: HiveLocation,
args: CommonVerbArgs,
partition: Partitions,
make_objective: F,
mut modifiers: SubCommandModifiers,
) -> Result<()>
where
F: Fn(&Name, &Node) -> Objective,
F: Fn(&Name, &Node) -> Goal,
{
let location = Arc::new(location);
let _location = Arc::new(location);

let (tags, names) = resolve_targets(&args.on, &mut modifiers);

Expand Down Expand Up @@ -137,65 +138,68 @@ where
.lock()
.add_many(&partitioned_names.iter().collect::<Vec<_>>());

let mut set = hive
let mut nodes: HashMap<_, _> = hive
.nodes
.iter_mut()
.filter(|(name, _)| partitioned_names.contains(name))
.map(|(name, node)| {
info!("Resolved {:?} to include {}", args.on, name);

let objective = make_objective(name, node);

let context = Context {
node,
let plan = plan_for_node(
Node {
target: Arc::new(node.target),
build_remotely: node.build_remotely,
allow_local_deployment: node.allow_local_deployment,
tags: node.tags,
host_platform: node.host_platform,
privilege_escalation_command: Arc::new(node.privilege_escalation_command),
keys,
},
name,
objective,
state: StepState::default(),
hive_location: location.clone(),
goal,
hive_location.clone(),
modifiers,
should_quit: should_shutdown.clone(),
};

GoalExecutor::new(context)
.execute()
.map(move |result| (name, result))
should_quit.clone()
);
})
.peekable();
.collect();

// let plans = wire_plan::create_plans(nodes, goal);

if set.peek().is_none() {
error!("There are no nodes selected for deployment");
}
// let plan = nodes.inter

let futures = futures::stream::iter(set).buffer_unordered(args.parallel);
let result = futures.collect::<Vec<_>>().await;
let (successful, errors): (Vec<_>, Vec<_>) =
result
.into_iter()
.partition_map(|(name, result)| match result {
Ok(..) => Either::Left(name),
Err(err) => Either::Right((name, err)),
});

if !successful.is_empty() {
info!(
"Successfully applied goal to {} node(s): {:?}",
successful.len(),
successful
);
if nodes.peek().is_none() {
error!("There are no nodes selected for deployment");
}

if !errors.is_empty() {
// clear the status bar if we are about to print error messages
STATUS.lock().clear(&mut stderr());

return Err(NodeErrors(
errors
.into_iter()
.map(|(name, error)| NodeError(name.clone(), error))
.collect(),
)
.into());
}
// let futures = futures::stream::iter(set).buffer_unordered(args.parallel);
// let result = futures.collect::<Vec<_>>().await;
// let (successful, errors): (Vec<_>, Vec<_>) =
// result
// .into_iter()
// .partition_map(|(name, result)| match result {
// Ok(..) => Either::Left(name),
// Err(err) => Either::Right((name, err)),
// });
//
// if !successful.is_empty() {
// info!(
// "Successfully applied goal to {} node(s): {:?}",
// successful.len(),
// successful
// );
// }
//
// if !errors.is_empty() {
// // clear the status bar if we are about to print error messages
// STATUS.lock().clear(&mut stderr());
//
// return Err(NodeErrors(
// errors
// .into_iter()
// .map(|(name, error)| NodeError(name.clone(), error))
// .collect(),
// )
// .into());
// }

Ok(())
}
Expand Down
23 changes: 12 additions & 11 deletions crates/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use wire_core::SubCommandModifiers;
use wire_core::commands::common::get_hive_node_names;
use wire_core::hive::node::{Goal as HiveGoal, HandleUnreachable, Name, SwitchToConfigurationGoal};
use wire_core::hive::{Hive, get_hive_location};
use wire_plan::ApplyGoal;

use std::io::IsTerminal;
use std::{
Expand Down Expand Up @@ -174,7 +175,7 @@ pub struct ApplyArgs {
pub common: CommonVerbArgs,

#[arg(value_enum, default_value_t)]
pub goal: Goal,
pub goal: CliApplyGoal,

/// Skip key uploads. noop when [GOAL] = Keys
#[arg(short, long, default_value_t = false)]
Expand Down Expand Up @@ -267,7 +268,7 @@ pub enum Inspection {
}

#[derive(Clone, Debug, Default, ValueEnum, Display)]
pub enum Goal {
pub enum CliApplyGoal {
/// Make the configuration the boot default and activate now
#[default]
Switch,
Expand All @@ -285,26 +286,26 @@ pub enum Goal {
DryActivate,
}

impl TryFrom<Goal> for HiveGoal {
impl TryFrom<CliApplyGoal> for ApplyGoal {
type Error = miette::Error;

fn try_from(value: Goal) -> Result<Self, Self::Error> {
fn try_from(value: CliApplyGoal) -> Result<Self, Self::Error> {
match value {
Goal::Build => Ok(HiveGoal::Build),
Goal::Push => Ok(HiveGoal::Push),
Goal::Boot => Ok(HiveGoal::SwitchToConfiguration(
CliApplyGoal::Build => Ok(ApplyGoal::Build),
CliApplyGoal::Push => Ok(ApplyGoal::Push),
CliApplyGoal::Boot => Ok(ApplyGoal::SwitchToConfiguration(
SwitchToConfigurationGoal::Boot,
)),
Goal::Switch => Ok(HiveGoal::SwitchToConfiguration(
CliApplyGoal::Switch => Ok(ApplyGoal::SwitchToConfiguration(
SwitchToConfigurationGoal::Switch,
)),
Goal::Test => Ok(HiveGoal::SwitchToConfiguration(
CliApplyGoal::Test => Ok(ApplyGoal::SwitchToConfiguration(
SwitchToConfigurationGoal::Test,
)),
Goal::DryActivate => Ok(HiveGoal::SwitchToConfiguration(
CliApplyGoal::DryActivate => Ok(ApplyGoal::SwitchToConfiguration(
SwitchToConfigurationGoal::DryActivate,
)),
Goal::Keys => Ok(HiveGoal::Keys),
CliApplyGoal::Keys => Ok(ApplyGoal::Keys),
}
}
}
Expand Down
Loading
Loading