use std::net::SocketAddr;
use std::path::PathBuf;
use std::time::Duration as StdDuration;
use clap::{ArgAction, Args, Subcommand, ValueEnum};
use super::util::parse_duration_arg;
#[derive(Debug, Args)]
pub(crate) struct OrchestratorArgs {
#[command(subcommand)]
pub command: OrchestratorCommand,
}
#[derive(Debug, Args, Clone)]
pub(crate) struct OrchestratorLocalArgs {
#[arg(
long,
visible_alias = "manifest",
env = "HARN_ORCHESTRATOR_MANIFEST",
default_value = "harn.toml",
value_name = "PATH"
)]
pub config: PathBuf,
#[arg(
long = "state-dir",
env = "HARN_ORCHESTRATOR_STATE_DIR",
default_value = ".harn/orchestrator",
value_name = "PATH"
)]
pub state_dir: PathBuf,
}
#[derive(Debug, Subcommand)]
pub(crate) enum OrchestratorCommand {
Serve(OrchestratorServeArgs),
Deploy(Box<OrchestratorDeployArgs>),
Reload(OrchestratorReloadArgs),
Inspect(OrchestratorInspectArgs),
Stats(OrchestratorStatsArgs),
Fire(OrchestratorFireArgs),
Replay(OrchestratorReplayArgs),
ReplayOracle(OrchestratorReplayOracleArgs),
Resume(OrchestratorResumeArgs),
Dlq(OrchestratorDlqArgs),
Queue(OrchestratorQueueArgs),
Recover(OrchestratorRecoverArgs),
Tenant(OrchestratorTenantArgs),
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorTenantArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[command(subcommand)]
pub command: OrchestratorTenantCommand,
}
#[derive(Debug, Subcommand)]
pub(crate) enum OrchestratorTenantCommand {
Create(OrchestratorTenantCreateArgs),
Ls(OrchestratorTenantLsArgs),
Suspend(OrchestratorTenantSuspendArgs),
Delete(OrchestratorTenantDeleteArgs),
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorTenantCreateArgs {
pub id: String,
#[arg(long = "daily-cost-usd", value_name = "USD")]
pub daily_cost_usd: Option<f64>,
#[arg(long = "hourly-cost-usd", value_name = "USD")]
pub hourly_cost_usd: Option<f64>,
#[arg(long = "ingest-per-minute", value_name = "N")]
pub ingest_per_minute: Option<u32>,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args, Default)]
pub(crate) struct OrchestratorTenantLsArgs {
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorTenantSuspendArgs {
pub id: String,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorTenantDeleteArgs {
pub id: String,
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
pub confirm: bool,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorServeArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(
long,
visible_alias = "listen",
env = "HARN_ORCHESTRATOR_LISTEN",
default_value = "127.0.0.1:8080",
value_name = "ADDR"
)]
pub bind: SocketAddr,
#[arg(long, env = "HARN_ORCHESTRATOR_CERT", value_name = "PATH")]
pub cert: Option<PathBuf>,
#[arg(long, env = "HARN_ORCHESTRATOR_KEY", value_name = "PATH")]
pub key: Option<PathBuf>,
#[arg(long = "shutdown-timeout", default_value_t = 30, value_name = "SECS")]
pub shutdown_timeout: u64,
#[arg(long = "drain-max-items", value_name = "COUNT")]
pub drain_max_items: Option<usize>,
#[arg(long = "drain-deadline", value_name = "SECS")]
pub drain_deadline: Option<u64>,
#[arg(
long = "pump-max-outstanding",
env = "HARN_ORCHESTRATOR_PUMP_MAX_OUTSTANDING",
value_name = "COUNT"
)]
pub pump_max_outstanding: Option<usize>,
#[arg(long = "mcp", default_value_t = false, action = ArgAction::SetTrue)]
pub mcp: bool,
#[arg(long = "mcp-path", default_value = "/mcp", value_name = "PATH")]
pub mcp_path: String,
#[arg(long = "mcp-sse-path", default_value = "/sse", value_name = "PATH")]
pub mcp_sse_path: String,
#[arg(
long = "mcp-messages-path",
default_value = "/messages",
value_name = "PATH"
)]
pub mcp_messages_path: String,
#[arg(long)]
pub watch: bool,
#[arg(
long = "log-format",
env = "HARN_ORCHESTRATOR_LOG_FORMAT",
value_enum,
default_value_t = OrchestratorLogFormat::Text
)]
pub log_format: OrchestratorLogFormat,
#[arg(
long,
env = "HARN_ORCHESTRATOR_ROLE",
value_enum,
default_value_t = crate::commands::orchestrator::role::OrchestratorRole::SingleTenant
)]
pub role: crate::commands::orchestrator::role::OrchestratorRole,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum OrchestratorLogFormat {
Text,
Pretty,
Json,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorDeployArgs {
#[arg(long, value_enum)]
pub provider: OrchestratorDeployProvider,
#[arg(
long,
visible_alias = "config",
env = "HARN_ORCHESTRATOR_MANIFEST",
default_value = "harn.toml",
value_name = "PATH"
)]
pub manifest: PathBuf,
#[arg(long, default_value = "harn-orchestrator", value_name = "NAME")]
pub name: String,
#[arg(
long,
default_value = "ghcr.io/burin-labs/harn:latest",
value_name = "IMAGE"
)]
pub image: String,
#[arg(long = "deploy-dir", default_value = "deploy", value_name = "DIR")]
pub deploy_dir: PathBuf,
#[arg(long, default_value_t = 8080, value_name = "PORT")]
pub port: u16,
#[arg(long = "data-dir", default_value = "/data", value_name = "PATH")]
pub data_dir: String,
#[arg(long = "disk-size-gb", default_value_t = 10, value_name = "GB")]
pub disk_size_gb: u16,
#[arg(long = "shutdown-timeout", default_value_t = 30, value_name = "SECS")]
pub shutdown_timeout: u64,
#[arg(long, value_name = "REGION")]
pub region: Option<String>,
#[arg(long = "render-service", value_name = "SERVICE")]
pub render_service: Option<String>,
#[arg(long = "railway-service", value_name = "SERVICE")]
pub railway_service: Option<String>,
#[arg(long = "railway-environment", value_name = "ENV")]
pub railway_environment: Option<String>,
#[arg(
long = "railway-project",
env = "RAILWAY_PROJECT_ID",
value_name = "PROJECT_ID"
)]
pub railway_project: Option<String>,
#[arg(long = "render-api-key", env = "RENDER_API_KEY", value_name = "TOKEN")]
pub render_api_key: Option<String>,
#[arg(long = "fly-api-token", env = "FLY_API_TOKEN", value_name = "TOKEN")]
pub fly_api_token: Option<String>,
#[arg(long = "railway-token", env = "RAILWAY_TOKEN", value_name = "TOKEN")]
pub railway_token: Option<String>,
#[arg(long)]
pub build: bool,
#[arg(long = "no-push")]
pub no_push: bool,
#[arg(long = "env", value_name = "KEY=VALUE")]
pub env: Vec<String>,
#[arg(long = "secret", value_name = "KEY=VALUE")]
pub secret: Vec<String>,
#[arg(long = "no-secret-sync")]
pub no_secret_sync: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub print: bool,
#[arg(long = "health-url", value_name = "URL")]
pub health_url: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub(crate) enum OrchestratorDeployProvider {
Render,
Fly,
Railway,
}
impl OrchestratorDeployProvider {
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Render => "render",
Self::Fly => "fly",
Self::Railway => "railway",
}
}
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorReloadArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(long = "admin-url", value_name = "URL")]
pub admin_url: Option<String>,
#[arg(long, default_value_t = 10, value_name = "SECS")]
pub timeout: u64,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorInspectArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorStatsArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(long = "window", value_name = "DURATION", value_parser = parse_duration_arg, default_value = "24h")]
pub window: StdDuration,
#[arg(long = "top", default_value_t = 10, value_name = "N")]
pub top: usize,
#[arg(long = "tenant", value_name = "TENANT")]
pub tenant: Option<String>,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorFireArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
pub binding_id: String,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorReplayArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
pub event_id: String,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorReplayOracleArgs {
#[arg(value_name = "PATH")]
pub selection: Option<PathBuf>,
#[arg(long, value_name = "TEXT")]
pub filter: Option<String>,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorResumeArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
pub event_id: String,
#[arg(long, default_value = "manual")]
pub reviewer: String,
#[arg(long)]
pub reason: Option<String>,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorDlqArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(long)]
pub json: bool,
#[arg(
long,
default_value_t = false,
action = ArgAction::SetTrue,
conflicts_with_all = ["replay", "discard"]
)]
pub list: bool,
#[arg(long, value_name = "ID", conflicts_with = "discard")]
pub replay: Option<String>,
#[arg(long, value_name = "ID", conflicts_with = "replay")]
pub discard: Option<String>,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorQueueArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[command(subcommand)]
pub command: Option<OrchestratorQueueCommand>,
}
#[derive(Debug, Subcommand)]
pub(crate) enum OrchestratorQueueCommand {
Ls(OrchestratorQueueLsArgs),
Drain(OrchestratorQueueDrainArgs),
Purge(OrchestratorQueuePurgeArgs),
}
#[derive(Debug, Args, Default)]
pub(crate) struct OrchestratorQueueLsArgs {
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorQueueDrainArgs {
pub queue: String,
#[arg(long, value_name = "ID")]
pub consumer_id: Option<String>,
#[arg(long = "claim-ttl", value_name = "DURATION", value_parser = parse_duration_arg, default_value = "5m")]
pub claim_ttl: StdDuration,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorQueuePurgeArgs {
pub queue: String,
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
pub confirm: bool,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Args)]
pub(crate) struct OrchestratorRecoverArgs {
#[command(flatten)]
pub local: OrchestratorLocalArgs,
#[arg(long = "envelope-age", value_name = "DURATION", value_parser = parse_duration_arg)]
pub envelope_age: StdDuration,
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
pub dry_run: bool,
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
pub yes: bool,
}