///|
/// Errors raised while resolving a local deployment profile.
pub(all) suberror DeployError {
EmptyPath
InvalidResourceLimit
UnknownArgument(String)
MissingArgument(String)
InvalidProfile(String)
} derive(Debug, Eq)
///|
/// The two supported process roles.
pub(all) enum RunProfileKind {
Node
ControlPlane
} derive(Debug, Eq)
///|
/// The supported deployment target for this release.
pub(all) enum DeploymentTarget {
LinuxNative
} derive(Debug, Eq)
///|
/// Network behavior selected by a run profile.
pub(all) enum NetworkMode {
Reconnectable
OfflineOnly
} derive(Debug, Eq)
///|
/// Bounded local resource settings for a process role.
pub(all) struct ResourceLimits {
max_pending_events : Int32
max_log_entries : Int32
max_reconnect_attempts : Int32
} derive(Debug, Eq)
///|
/// Creates positive resource limits.
pub fn ResourceLimits::new(
max_pending_events~ : Int32,
max_log_entries~ : Int32,
max_reconnect_attempts~ : Int32,
) -> ResourceLimits raise DeployError {
if max_pending_events <= 0 ||
max_log_entries <= 0 ||
max_reconnect_attempts <= 0 {
raise DeployError::InvalidResourceLimit
}
{ max_pending_events, max_log_entries, max_reconnect_attempts, }
}
///|
/// A complete node or control-plane run profile.
pub(all) struct RunProfile {
name : String
kind : RunProfileKind
target : DeploymentTarget
network : NetworkMode
data_dir : String
config_path : String
journal_dir : String
diagnostics_dir : String
resources : ResourceLimits
} derive(Debug, Eq)
///|
/// Returns the default node profile for a standard Linux user process.
pub fn RunProfile::node_default() -> RunProfile {
{
name: "node",
kind: RunProfileKind::Node,
target: DeploymentTarget::LinuxNative,
network: NetworkMode::Reconnectable,
data_dir: "/var/lib/edgeweaver/node",
config_path: "/etc/edgeweaver/node.toml",
journal_dir: "/var/lib/edgeweaver/node/events",
diagnostics_dir: "/var/lib/edgeweaver/node/diagnostics",
resources: {
max_pending_events: 1024,
max_log_entries: 256,
max_reconnect_attempts: 8,
},
}
}
///|
/// Returns the default control-plane profile for a standard Linux user process.
pub fn RunProfile::control_plane_default() -> RunProfile {
{
name: "control-plane",
kind: RunProfileKind::ControlPlane,
target: DeploymentTarget::LinuxNative,
network: NetworkMode::Reconnectable,
data_dir: "/var/lib/edgeweaver/control-plane",
config_path: "/etc/edgeweaver/control-plane.toml",
journal_dir: "/var/lib/edgeweaver/control-plane/events",
diagnostics_dir: "/var/lib/edgeweaver/control-plane/diagnostics",
resources: {
max_pending_events: 4096,
max_log_entries: 512,
max_reconnect_attempts: 8,
},
}
}
///|
/// Selects a default profile by process role.
pub fn RunProfile::for_kind(kind~ : RunProfileKind) -> RunProfile {
match kind {
RunProfileKind::Node => RunProfile::node_default()
RunProfileKind::ControlPlane => RunProfile::control_plane_default()
}
}
///|
/// Validates paths and resource limits before process startup.
pub fn RunProfile::validate(self : RunProfile) -> Unit raise DeployError {
ensure_path(self.data_dir)
ensure_path(self.config_path)
ensure_path(self.journal_dir)
ensure_path(self.diagnostics_dir)
if self.resources.max_pending_events <= 0 ||
self.resources.max_log_entries <= 0 ||
self.resources.max_reconnect_attempts <= 0 {
raise DeployError::InvalidResourceLimit
}
}
///|
/// Startup overrides accepted by the command-line launcher.
pub(all) struct LaunchOptions {
mut kind : RunProfileKind
mut data_dir : String?
mut config_path : String?
} derive(Debug, Eq)
///|
/// Creates launcher options for a profile role.
pub fn LaunchOptions::new(kind~ : RunProfileKind) -> LaunchOptions {
{ kind, data_dir: None, config_path: None, }
}
///|
/// Parses profile, data directory, and config path startup arguments.
pub fn LaunchOptions::parse(
args~ : Array[String],
) -> LaunchOptions raise DeployError {
let options = LaunchOptions::new(kind=RunProfileKind::Node)
let mut index = 0
while index < args.length() {
match args[index] {
"--profile" => {
let value = next_argument(args, index, "--profile")
options.kind = parse_profile(value)
index = index + 2
}
"--data-dir" => {
let value = next_argument(args, index, "--data-dir")
options.data_dir = Some(value)
index = index + 2
}
"--config" => {
let value = next_argument(args, index, "--config")
options.config_path = Some(value)
index = index + 2
}
argument => raise DeployError::UnknownArgument(argument)
}
}
options
}
///|
/// Resolves startup overrides into a validated run profile.
pub fn LaunchOptions::resolve(
self : LaunchOptions,
) -> RunProfile raise DeployError {
let base = RunProfile::for_kind(kind=self.kind)
let data_dir = match self.data_dir {
Some(path) => path
None => base.data_dir
}
let config_path = match self.config_path {
Some(path) => path
None => base.config_path
}
let profile = {
name: base.name,
kind: base.kind,
target: base.target,
network: base.network,
data_dir,
config_path,
journal_dir: data_dir + "/events",
diagnostics_dir: data_dir + "/diagnostics",
resources: base.resources,
}
profile.validate()
profile
}
///|
fn next_argument(
args : Array[String],
index : Int32,
option : String,
) -> String raise DeployError {
if index + 1 >= args.length() {
raise DeployError::MissingArgument(option)
}
let value = args[index + 1]
if value == "" {
raise DeployError::EmptyPath
}
value
}
///|
fn parse_profile(value : String) -> RunProfileKind raise DeployError {
match value {
"node" => RunProfileKind::Node
"control-plane" => RunProfileKind::ControlPlane
_ => raise DeployError::InvalidProfile(value)
}
}
///|
fn ensure_path(path : String) -> Unit raise DeployError {
if path == "" {
raise DeployError::EmptyPath
}
}