pub mod bootstrap;
pub mod cluster;
pub mod credentials;
pub mod deployer;
pub mod manifests;
pub mod render;
use std::sync::Arc;
use greentic_deploy_spec::CapabilitySlot;
use semver::VersionReq;
use super::slot::EnvPackHandler;
use crate::tool_check::ToolCheck;
pub use cluster::{K8sCluster, K8sClusterError, ObjectRef, UnconfiguredCluster};
pub use credentials::{K8sDeployerCredentials, K8sValidatorClient};
#[derive(Debug)]
pub struct K8sDeployerHandler {
creds: K8sDeployerCredentials,
pub(crate) cluster: Arc<dyn K8sCluster>,
}
impl Default for K8sDeployerHandler {
fn default() -> Self {
Self {
creds: K8sDeployerCredentials::default(),
cluster: Arc::new(UnconfiguredCluster),
}
}
}
impl K8sDeployerHandler {
pub const DESCRIPTOR_PATH: &'static str = "greentic.deployer.k8s";
pub const VERSION_REQ: &'static str = ">=1.0.0-dev, <2.0.0";
pub fn with_cluster(cluster: Arc<dyn K8sCluster>) -> Self {
Self {
creds: K8sDeployerCredentials::default(),
cluster,
}
}
}
impl EnvPackHandler for K8sDeployerHandler {
fn slot(&self) -> CapabilitySlot {
CapabilitySlot::Deployer
}
fn descriptor_path(&self) -> &str {
Self::DESCRIPTOR_PATH
}
fn supported_versions(&self) -> VersionReq {
Self::VERSION_REQ
.parse()
.expect("k8s version-req is valid (guarded by tests)")
}
fn preflight(&self) -> Vec<ToolCheck> {
Vec::new()
}
fn deployer_credentials(&self) -> Option<&dyn crate::credentials::DeployerCredentials> {
Some(&self.creds)
}
fn wizard_qaspec_yaml(&self) -> Option<&'static str> {
Some(include_str!("wizard.qaspec.yaml"))
}
fn as_deployer(&self) -> Option<&dyn crate::env_packs::deployer::Deployer> {
Some(self)
}
fn as_manifest_renderer(&self) -> Option<&dyn crate::env_packs::render::ManifestRenderer> {
Some(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use greentic_deploy_spec::PackDescriptor;
#[test]
fn handler_serves_deployer_slot_with_k8s_path() {
let h = K8sDeployerHandler::default();
assert_eq!(h.slot(), CapabilitySlot::Deployer);
assert_eq!(h.descriptor_path(), "greentic.deployer.k8s");
let _ = h.supported_versions();
}
#[test]
fn version_req_accepts_ga_and_dev_releases() {
let h = K8sDeployerHandler::default();
let req = h.supported_versions();
let ga = PackDescriptor::try_new("greentic.deployer.k8s@1.0.0").unwrap();
assert!(req.matches(&ga.version().0), "{req} must accept 1.0.0");
let dev = PackDescriptor::try_new("greentic.deployer.k8s@1.0.0-dev.1").unwrap();
assert!(
req.matches(&dev.version().0),
"{req} must accept dev pre-release"
);
let next_major = PackDescriptor::try_new("greentic.deployer.k8s@2.0.0").unwrap();
assert!(
!req.matches(&next_major.version().0),
"{req} must reject 2.0.0 (breaking bump)"
);
}
#[test]
fn exposes_credentials_contract_and_deployer_impl() {
let h = K8sDeployerHandler::default();
let creds = h
.deployer_credentials()
.expect("k8s handler must expose credentials");
assert!(creds.requires_credentials_material());
assert!(
(&h as &dyn EnvPackHandler).as_deployer().is_some(),
"EnvPackHandler::as_deployer must surface the K8s Deployer impl"
);
}
#[test]
fn wizard_qaspec_yaml_id_matches_canonical() {
let yaml = K8sDeployerHandler::default()
.wizard_qaspec_yaml()
.expect("k8s handler ships a wizard QASpec");
let spec: qa_spec::FormSpec =
serde_yaml_bw::from_str(yaml).expect("wizard.qaspec.yaml parses as FormSpec");
assert_eq!(spec.id, "greentic.deployer.k8s.wizard");
}
}