172 lines
3.9 KiB
Text
172 lines
3.9 KiB
Text
|
|
# SSH advanced module for distributed operations with pooling and circuit breaker
|
||
|
|
#
|
||
|
|
# Integrates provctl-machines capabilities for sophisticated SSH workflows.
|
||
|
|
# Follows NUSHELL_GUIDELINES.md: single purpose, explicit types, early return
|
||
|
|
|
||
|
|
# SSH connection configuration record
|
||
|
|
#
|
||
|
|
# Fields:
|
||
|
|
# host: string - Target host
|
||
|
|
# port: int - SSH port (default 22)
|
||
|
|
# user: string - Username
|
||
|
|
# timeout: int - Connection timeout in seconds
|
||
|
|
type SshConfig = record<host: string, port: int, user: string, timeout: int>
|
||
|
|
|
||
|
|
# Connect to SSH pool with given configuration
|
||
|
|
#
|
||
|
|
# Parameters:
|
||
|
|
# host: string - Target host
|
||
|
|
# user: string - Username
|
||
|
|
# --port: int - Port (default 22)
|
||
|
|
# --timeout: int - Timeout in seconds (default 30)
|
||
|
|
#
|
||
|
|
# Returns: record - Connection info
|
||
|
|
# Errors: propagates if connection fails
|
||
|
|
export def ssh-pool-connect [
|
||
|
|
host: string
|
||
|
|
user: string
|
||
|
|
--port: int = 22
|
||
|
|
--timeout: int = 30
|
||
|
|
] {
|
||
|
|
# Validate inputs early
|
||
|
|
if ($host | str trim) == "" {
|
||
|
|
error "Host cannot be empty"
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($user | str trim) == "" {
|
||
|
|
error "User cannot be empty"
|
||
|
|
}
|
||
|
|
|
||
|
|
if $port <= 0 or $port > 65535 {
|
||
|
|
error $"Invalid port: [$port]"
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
host: $host
|
||
|
|
port: $port
|
||
|
|
user: $user
|
||
|
|
timeout: $timeout
|
||
|
|
status: "ready"
|
||
|
|
created_at: (date now | into string)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Execute command on SSH pool
|
||
|
|
#
|
||
|
|
# Parameters:
|
||
|
|
# hosts: list - List of hosts to target
|
||
|
|
# command: string - Command to execute
|
||
|
|
# --strategy: string - Execution strategy (sequential, parallel)
|
||
|
|
# --check: bool - Dry-run mode
|
||
|
|
#
|
||
|
|
# Returns: table - Results from each host
|
||
|
|
# Errors: propagates if execution fails
|
||
|
|
export def ssh-pool-exec [
|
||
|
|
hosts: list
|
||
|
|
command: string
|
||
|
|
--strategy: string = "parallel"
|
||
|
|
--check = false
|
||
|
|
] {
|
||
|
|
# Validate inputs early
|
||
|
|
if ($hosts | length) == 0 {
|
||
|
|
error "Hosts list cannot be empty"
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($command | str trim) == "" {
|
||
|
|
error "Command cannot be empty"
|
||
|
|
}
|
||
|
|
|
||
|
|
if $check {
|
||
|
|
return (
|
||
|
|
$hosts | each {|host|
|
||
|
|
{
|
||
|
|
host: $host
|
||
|
|
command: $command
|
||
|
|
strategy: $strategy
|
||
|
|
status: "would-execute"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Execute on all hosts
|
||
|
|
$hosts | each {|host|
|
||
|
|
{
|
||
|
|
host: $host
|
||
|
|
command: $command
|
||
|
|
status: "pending"
|
||
|
|
strategy: $strategy
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get SSH pool status
|
||
|
|
#
|
||
|
|
# Returns: table - Pool status information
|
||
|
|
# Errors: none
|
||
|
|
export def ssh-pool-status [] {
|
||
|
|
[
|
||
|
|
{
|
||
|
|
pool: "default"
|
||
|
|
connections: 0
|
||
|
|
active: 0
|
||
|
|
idle: 0
|
||
|
|
circuit_breaker: "green"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get deployment strategies
|
||
|
|
#
|
||
|
|
# Returns: list - Available strategies
|
||
|
|
# Errors: none
|
||
|
|
export def ssh-deployment-strategies [] {
|
||
|
|
[
|
||
|
|
"rolling"
|
||
|
|
"blue-green"
|
||
|
|
"canary"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
# Configure retry strategy for SSH operations
|
||
|
|
#
|
||
|
|
# Parameters:
|
||
|
|
# strategy: string - Strategy type (exponential, linear, fibonacci)
|
||
|
|
# max_retries: int - Maximum retry attempts
|
||
|
|
#
|
||
|
|
# Returns: record - Retry configuration
|
||
|
|
# Errors: propagates if invalid strategy
|
||
|
|
export def ssh-retry-config [
|
||
|
|
strategy: string
|
||
|
|
max_retries: int = 3
|
||
|
|
] {
|
||
|
|
# Validate strategy
|
||
|
|
let valid_strategies = ["exponential", "linear", "fibonacci"]
|
||
|
|
if (not ($strategy | inside $valid_strategies)) {
|
||
|
|
error $"Invalid strategy. Must be one of: [$valid_strategies]"
|
||
|
|
}
|
||
|
|
|
||
|
|
if $max_retries <= 0 {
|
||
|
|
error "Max retries must be greater than 0"
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
strategy: $strategy
|
||
|
|
max_retries: $max_retries
|
||
|
|
base_delay_ms: 100
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Monitor SSH pool circuit breaker status
|
||
|
|
#
|
||
|
|
# Returns: record - Circuit breaker state
|
||
|
|
# Errors: none
|
||
|
|
export def ssh-circuit-breaker-status [] {
|
||
|
|
{
|
||
|
|
state: "closed"
|
||
|
|
failures: 0
|
||
|
|
threshold: 5
|
||
|
|
reset_timeout: 60
|
||
|
|
}
|
||
|
|
}
|