2026-02-08 21:29:17 +01:00
|
|
|
use crate::error::Result;
|
|
|
|
|
use crate::types::{NetworkMode, ZoneConfig, ZoneInfo, ZoneState};
|
|
|
|
|
use async_trait::async_trait;
|
|
|
|
|
|
|
|
|
|
/// Trait for zone runtime implementations
|
|
|
|
|
///
|
2026-02-09 00:47:28 +01:00
|
|
|
/// This trait abstracts over the illumos zone lifecycle and networking
|
2026-02-08 21:29:17 +01:00
|
|
|
/// operations. It enables testing via `MockRuntime` on non-illumos platforms.
|
2026-02-09 00:47:28 +01:00
|
|
|
///
|
|
|
|
|
/// Storage operations (ZFS dataset create/destroy, snapshots, volumes) are
|
|
|
|
|
/// handled by the separate `StorageEngine` trait, which is injected into
|
|
|
|
|
/// runtime implementations.
|
2026-02-08 21:29:17 +01:00
|
|
|
#[async_trait]
|
|
|
|
|
pub trait ZoneRuntime: Send + Sync {
|
|
|
|
|
// --- Zone lifecycle ---
|
|
|
|
|
|
|
|
|
|
/// Create a zone configuration (zonecfg)
|
|
|
|
|
async fn create_zone(&self, config: &ZoneConfig) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Install a zone (zoneadm install)
|
|
|
|
|
async fn install_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Boot a zone (zoneadm boot)
|
|
|
|
|
async fn boot_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Gracefully shut down a zone (zoneadm shutdown)
|
|
|
|
|
async fn shutdown_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Forcefully halt a zone (zoneadm halt)
|
|
|
|
|
async fn halt_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Uninstall a zone (zoneadm uninstall -F)
|
|
|
|
|
async fn uninstall_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Delete a zone configuration (zonecfg delete -F)
|
|
|
|
|
async fn delete_zone(&self, zone_name: &str) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
// --- Zone query ---
|
|
|
|
|
|
|
|
|
|
/// Get the current state of a zone
|
|
|
|
|
async fn get_zone_state(&self, zone_name: &str) -> Result<ZoneState>;
|
|
|
|
|
|
|
|
|
|
/// Get full info about a zone
|
|
|
|
|
async fn get_zone_info(&self, zone_name: &str) -> Result<ZoneInfo>;
|
|
|
|
|
|
|
|
|
|
/// List all managed zones
|
|
|
|
|
async fn list_zones(&self) -> Result<Vec<ZoneInfo>>;
|
|
|
|
|
|
Add health probes (liveness/readiness/startup) with exec, HTTP, and TCP checks
Implement Kubernetes-style health probes that run during the reconcile loop
to detect unhealthy applications inside running zones. Previously the pod
controller only checked zone liveness via get_zone_state(), missing cases
where the zone is running but the application inside has crashed.
- Add exec_in_zone() to ZoneRuntime trait, implemented via zlogin on illumos
and with configurable mock results for testing
- Add probe type system (ProbeKind, ProbeAction, ContainerProbeConfig) that
decouples from k8s_openapi and extracts probes from pod container specs
with proper k8s defaults (period=10s, timeout=1s, failure=3, success=1)
- Add ProbeExecutor for exec/HTTP/TCP checks with tokio timeout support
(HTTPS falls back to TCP-only with warning)
- Add ProbeTracker state machine that tracks per-pod/container/probe-kind
state, respects initial delays and periods, gates liveness on startup
probes, and aggregates results into PodProbeStatus
- Integrate into PodController reconcile loop: on liveness failure set
phase=Failed with reason LivenessProbeFailure; on readiness failure set
Ready=False; on all-pass restore Ready=True
- Add ProbeFailed error variant with miette diagnostic
Known v1 limitation: probes execute at reconcile cadence (~30s), not at
their configured periodSeconds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 22:41:30 +01:00
|
|
|
// --- Exec ---
|
|
|
|
|
|
|
|
|
|
/// Execute a command inside a running zone
|
|
|
|
|
///
|
|
|
|
|
/// Returns the command output including exit code. A non-zero exit code
|
|
|
|
|
/// is NOT treated as an error — callers (e.g. probe executors) interpret
|
|
|
|
|
/// the exit code themselves.
|
|
|
|
|
async fn exec_in_zone(
|
|
|
|
|
&self,
|
|
|
|
|
zone_name: &str,
|
|
|
|
|
command: &[String],
|
|
|
|
|
) -> Result<crate::command::CommandOutput>;
|
|
|
|
|
|
2026-02-08 21:29:17 +01:00
|
|
|
// --- Networking ---
|
|
|
|
|
|
|
|
|
|
/// Set up network for a zone
|
|
|
|
|
async fn setup_network(&self, zone_name: &str, network: &NetworkMode) -> Result<()>;
|
|
|
|
|
|
2026-03-19 20:28:40 +00:00
|
|
|
/// Configure IP address inside a running zone via ipadm
|
|
|
|
|
///
|
|
|
|
|
/// Must be called after the zone is booted. Creates the IP interface,
|
|
|
|
|
/// assigns a static address, and configures the default route.
|
|
|
|
|
async fn configure_zone_ip(&self, zone_name: &str, network: &NetworkMode) -> Result<()>;
|
|
|
|
|
|
2026-02-08 21:29:17 +01:00
|
|
|
/// Tear down network for a zone
|
|
|
|
|
async fn teardown_network(&self, zone_name: &str, network: &NetworkMode) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
// --- High-level lifecycle ---
|
|
|
|
|
|
|
|
|
|
/// Full provisioning: create dataset -> setup network -> create zone -> install -> boot
|
|
|
|
|
async fn provision(&self, config: &ZoneConfig) -> Result<()>;
|
|
|
|
|
|
|
|
|
|
/// Full deprovisioning: halt -> uninstall -> delete -> teardown network -> destroy dataset
|
|
|
|
|
async fn deprovision(&self, config: &ZoneConfig) -> Result<()>;
|
|
|
|
|
}
|