diff --git a/Cargo.toml b/Cargo.toml index 336b2c1..d55c921 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ wfe-yaml = { version = "1.7.0", path = "wfe-yaml", registry = "sunbeam" } wfe-buildkit = { version = "1.7.0", path = "wfe-buildkit", registry = "sunbeam" } wfe-containerd = { version = "1.7.0", path = "wfe-containerd", registry = "sunbeam" } wfe-rustlang = { version = "1.7.0", path = "wfe-rustlang", registry = "sunbeam" } +wfe-kubernetes = { version = "1.7.0", path = "wfe-kubernetes", registry = "sunbeam" } # YAML serde_yaml = "0.9" diff --git a/wfe-yaml/Cargo.toml b/wfe-yaml/Cargo.toml index aba7893..b271bd6 100644 --- a/wfe-yaml/Cargo.toml +++ b/wfe-yaml/Cargo.toml @@ -10,6 +10,7 @@ deno = ["deno_core", "deno_error", "url", "reqwest"] buildkit = ["wfe-buildkit"] containerd = ["wfe-containerd"] rustlang = ["wfe-rustlang"] +kubernetes = ["wfe-kubernetes"] [dependencies] wfe-core = { workspace = true } @@ -30,6 +31,7 @@ reqwest = { workspace = true, optional = true } wfe-buildkit = { workspace = true, optional = true } wfe-containerd = { workspace = true, optional = true } wfe-rustlang = { workspace = true, optional = true } +wfe-kubernetes = { workspace = true, optional = true } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/wfe-yaml/src/compiler.rs b/wfe-yaml/src/compiler.rs index 3b4e32b..5733204 100644 --- a/wfe-yaml/src/compiler.rs +++ b/wfe-yaml/src/compiler.rs @@ -15,6 +15,8 @@ use wfe_buildkit::{BuildkitConfig, BuildkitStep}; use wfe_containerd::{ContainerdConfig, ContainerdStep}; #[cfg(feature = "rustlang")] use wfe_rustlang::{CargoCommand, CargoConfig, CargoStep, RustupCommand, RustupConfig, RustupStep}; +#[cfg(feature = "kubernetes")] +use wfe_kubernetes::{ClusterConfig, KubernetesStepConfig, KubernetesStep}; use wfe_core::primitives::sub_workflow::SubWorkflowStep; use wfe_core::models::condition::{ComparisonOp, FieldComparison, StepCondition}; @@ -456,6 +458,23 @@ fn build_step_config_and_factory( }); Ok((key, value, factory)) } + #[cfg(feature = "kubernetes")] + "kubernetes" | "k8s" => { + let config = build_kubernetes_config(step)?; + let key = format!("wfe_yaml::kubernetes::{}", step.name); + let value = serde_json::to_value(&config.0).map_err(|e| { + YamlWorkflowError::Compilation(format!( + "Failed to serialize kubernetes config: {e}" + )) + })?; + let step_config = config.0; + let cluster_config = config.1; + let factory: StepFactory = Box::new(move || { + Box::new(KubernetesStep::lazy(step_config.clone(), cluster_config.clone())) + as Box + }); + Ok((key, value, factory)) + } #[cfg(feature = "rustlang")] "cargo-build" | "cargo-test" | "cargo-check" | "cargo-clippy" | "cargo-fmt" | "cargo-doc" | "cargo-publish" | "cargo-audit" | "cargo-deny" | "cargo-nextest" @@ -862,6 +881,47 @@ fn build_containerd_config( }) } +#[cfg(feature = "kubernetes")] +fn build_kubernetes_config( + step: &YamlStep, +) -> Result<(KubernetesStepConfig, ClusterConfig), YamlWorkflowError> { + let config = step.config.as_ref().ok_or_else(|| { + YamlWorkflowError::Compilation(format!( + "Kubernetes step '{}' is missing 'config' section", + step.name + )) + })?; + + let image = config.image.clone().ok_or_else(|| { + YamlWorkflowError::Compilation(format!( + "Kubernetes step '{}' must have 'config.image'", + step.name + )) + })?; + + let timeout_ms = config.timeout.as_ref().and_then(|t| parse_duration_ms(t)); + + let step_config = KubernetesStepConfig { + image, + command: config.command.clone(), + run: config.run.clone(), + env: config.env.clone(), + working_dir: config.working_dir.clone(), + memory: config.memory.clone(), + cpu: config.cpu.clone(), + timeout_ms, + pull_policy: config.pull_policy.clone(), + namespace: config.namespace.clone(), + }; + + let cluster_config = ClusterConfig { + kubeconfig: config.kubeconfig.clone(), + ..Default::default() + }; + + Ok((step_config, cluster_config)) +} + fn map_error_behavior(eb: &YamlErrorBehavior) -> Result { match eb.behavior_type.as_str() { "retry" => { diff --git a/wfe-yaml/src/schema.rs b/wfe-yaml/src/schema.rs index 74c903b..2adf98b 100644 --- a/wfe-yaml/src/schema.rs +++ b/wfe-yaml/src/schema.rs @@ -164,6 +164,13 @@ pub struct StepConfig { pub containerd_addr: Option, /// CLI binary name for containerd steps: "nerdctl" (default) or "docker". pub cli: Option, + // Kubernetes fields + /// Kubeconfig path for kubernetes steps. + pub kubeconfig: Option, + /// Namespace override for kubernetes steps. + pub namespace: Option, + /// Image pull policy for kubernetes steps: Always, IfNotPresent, Never. + pub pull_policy: Option, // Cargo fields /// Target package for cargo steps (`-p`). pub package: Option,