97 lines
2.6 KiB
Rust
Raw Normal View History

use async_trait::async_trait;
use reqwest::Url;
use super::DynError;
2026-01-26 08:26:15 +01:00
use crate::{nodes::ApiClient, topology::generation::NodeKind};
/// Marker type used by scenario builders to request node control support.
#[derive(Clone, Copy, Debug, Default)]
pub struct NodeControlCapability;
/// Optional observability settings attached to a scenario.
#[derive(Clone, Debug, Default)]
pub struct ObservabilityCapability {
2025-12-17 17:04:41 +01:00
/// Prometheus-compatible base URL used by the *runner process* to query
/// metrics (commonly a localhost port-forward, but can be any reachable
/// endpoint).
pub metrics_query_url: Option<Url>,
/// Full OTLP HTTP metrics ingest endpoint used by *nodes* to export metrics
/// (backend-specific host and path).
pub metrics_otlp_ingest_url: Option<Url>,
/// Optional Grafana base URL for printing/logging (human access).
pub grafana_url: Option<Url>,
}
2026-01-19 08:34:17 +01:00
/// Peer selection strategy for dynamically started nodes.
#[derive(Clone, Debug)]
pub enum PeerSelection {
/// Use the topology default (star/chain/full).
DefaultLayout,
/// Start without any initial peers.
None,
/// Connect to the named peers.
Named(Vec<String>),
}
/// Options for dynamically starting a node.
2026-01-19 08:34:17 +01:00
#[derive(Clone, Debug)]
pub struct StartNodeOptions {
2026-01-19 08:34:17 +01:00
/// How to select initial peers on startup.
pub peers: PeerSelection,
}
impl Default for StartNodeOptions {
fn default() -> Self {
Self {
peers: PeerSelection::DefaultLayout,
}
}
}
/// Trait implemented by scenario capability markers to signal whether node
/// control is required.
pub trait RequiresNodeControl {
const REQUIRED: bool;
}
impl RequiresNodeControl for () {
const REQUIRED: bool = false;
}
impl RequiresNodeControl for NodeControlCapability {
const REQUIRED: bool = true;
}
impl RequiresNodeControl for ObservabilityCapability {
const REQUIRED: bool = false;
}
/// Interface exposed by runners that can restart nodes at runtime.
#[async_trait]
pub trait NodeControlHandle: Send + Sync {
2026-01-26 08:26:15 +01:00
async fn restart_node(&self, index: usize) -> Result<(), DynError>;
2026-01-26 08:26:15 +01:00
async fn start_node(&self, _name: &str) -> Result<StartedNode, DynError> {
Err("start_node not supported by this deployer".into())
}
2026-01-26 08:26:15 +01:00
async fn start_node_with(
&self,
_name: &str,
_options: StartNodeOptions,
) -> Result<StartedNode, DynError> {
2026-01-26 08:26:15 +01:00
Err("start_node_with not supported by this deployer".into())
}
2026-01-19 08:34:17 +01:00
fn node_client(&self, _name: &str) -> Option<ApiClient> {
None
}
}
#[derive(Clone)]
pub struct StartedNode {
pub name: String,
2026-01-26 08:26:15 +01:00
pub kind: NodeKind,
pub api: ApiClient,
}