use chrono::{DateTime, Utc};
use kube::CustomResource;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use tatara_lisp_derive::TataraDomain as DeriveTataraDomain;
use crate::attestation::ProcessAttestation;
use crate::boundary::Boundary;
use crate::classification::Classification;
use crate::compliance::ComplianceSpec;
use crate::encapsulates::EncapsulatesSpec;
use crate::identity::Identity;
use crate::intent::Intent;
use crate::lifetime::Lifetime;
use crate::phase::ProcessPhase;
use crate::routing::RoutingSpec;
use crate::signal::ProcessSignal;
use crate::spec::{DependsOn, IdentitySpec, SignalPolicy};
use crate::status::{BoundaryStatus, ComplianceStatus, FluxResourceRef, ProcessCondition};
#[derive(CustomResource, DeriveTataraDomain, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[kube(
group = "tatara.pleme.io",
version = "v1alpha1",
kind = "Process",
plural = "processes",
shortname = "proc",
namespaced,
status = "ProcessStatus",
printcolumn = r#"{"name":"PID","type":"string","jsonPath":".status.pid"}"#,
printcolumn = r#"{"name":"Phase","type":"string","jsonPath":".status.phase"}"#,
printcolumn = r#"{"name":"Type","type":"string","jsonPath":".spec.classification.pointType"}"#,
printcolumn = r#"{"name":"Substrate","type":"string","jsonPath":".spec.classification.substrate"}"#,
printcolumn = r#"{"name":"Gen","type":"integer","jsonPath":".status.attestation.generation"}"#,
printcolumn = r#"{"name":"Age","type":"date","jsonPath":".metadata.creationTimestamp"}"#
)]
#[serde(rename_all = "camelCase")]
#[tatara(keyword = "defpoint")]
pub struct ProcessSpec {
#[serde(default)]
pub identity: IdentitySpec,
pub classification: Classification,
pub intent: Intent,
#[serde(default)]
pub boundary: Boundary,
#[serde(default)]
pub compliance: ComplianceSpec,
#[serde(default)]
pub depends_on: Vec<DependsOn>,
#[serde(default)]
pub signals: SignalPolicy,
#[serde(default, skip_serializing_if = "Lifetime::is_default")]
pub lifetime: Lifetime,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub routing: Option<RoutingSpec>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub encapsulates: Option<EncapsulatesSpec>,
#[serde(default)]
pub suspended: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct ProcessStatus {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pid: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(default)]
pub children: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub identity: Option<Identity>,
#[serde(default)]
pub phase: ProcessPhase,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub phase_since: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub attestation: Option<ProcessAttestation>,
#[serde(default)]
pub flux_resources: Vec<FluxResourceRef>,
#[serde(default)]
pub boundary: BoundaryStatus,
#[serde(default)]
pub compliance: ComplianceStatus,
#[serde(default)]
pub signal_queue: Vec<ProcessSignal>,
#[serde(default)]
pub conditions: Vec<ProcessCondition>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub exit_code: Option<i32>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::classification::{ConvergencePointType, SubstrateType};
use crate::intent::NixIntent;
#[test]
fn minimal_spec_serializes() {
let spec = ProcessSpec {
identity: IdentitySpec::default(),
classification: Classification {
point_type: ConvergencePointType::Gate,
substrate: SubstrateType::Observability,
horizon: Default::default(),
calm: Default::default(),
data_classification: Default::default(),
},
intent: Intent {
nix: Some(NixIntent {
flake_ref: "github:pleme-io/k8s".into(),
attribute: "obs".into(),
system: None,
attic_cache: None,
extra_args: vec![],
delegate_to_nix_build: false,
}),
..Intent::default()
},
boundary: Default::default(),
compliance: Default::default(),
depends_on: vec![],
signals: Default::default(),
lifetime: Default::default(),
routing: None,
encapsulates: None,
suspended: false,
};
let yaml = serde_yaml::to_string(&spec).unwrap();
assert!(yaml.contains("pointType: Gate"));
assert!(yaml.contains("substrate: Observability"));
assert!(yaml.contains("flakeRef: github:pleme-io/k8s"));
}
}