use anyhow::Result;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference;
use kube::{
Api, Client as KubeClient, CustomResource,
api::{Patch, PatchParams},
};
use serde::{Deserialize, Serialize};
use crate::discovery::DiscoveryMetadata;
const FIELD_MANAGER: &str = "dynamo-worker";
#[derive(CustomResource, Clone, Debug, Deserialize, Serialize)]
#[kube(
group = "nvidia.com",
version = "v1alpha1",
kind = "DynamoWorkerMetadata",
namespaced,
schema = "disabled"
)]
pub struct DynamoWorkerMetadataSpec {
pub data: serde_json::Value,
}
impl DynamoWorkerMetadataSpec {
pub fn new(data: serde_json::Value) -> Self {
Self { data }
}
}
pub fn build_cr(
pod_name: &str,
pod_uid: &str,
metadata: &DiscoveryMetadata,
) -> Result<DynamoWorkerMetadata> {
let data = serde_json::to_value(metadata)?;
let spec = DynamoWorkerMetadataSpec::new(data);
let mut cr = DynamoWorkerMetadata::new(pod_name, spec);
cr.metadata.owner_references = Some(vec![OwnerReference {
api_version: "v1".to_string(),
kind: "Pod".to_string(),
name: pod_name.to_string(),
uid: pod_uid.to_string(),
controller: Some(true),
block_owner_deletion: Some(false),
}]);
Ok(cr)
}
pub async fn apply_cr(
kube_client: &KubeClient,
namespace: &str,
cr: &DynamoWorkerMetadata,
) -> Result<()> {
let api: Api<DynamoWorkerMetadata> = Api::namespaced(kube_client.clone(), namespace);
let cr_name = cr
.metadata
.name
.as_ref()
.ok_or_else(|| anyhow::anyhow!("CR must have a name"))?;
let params = PatchParams::apply(FIELD_MANAGER).force();
api.patch(cr_name, ¶ms, &Patch::Apply(cr))
.await
.map_err(|e| anyhow::anyhow!("Failed to apply DynamoWorkerMetadata CR: {}", e))?;
tracing::debug!(
"Applied DynamoWorkerMetadata CR: name={}, namespace={}",
cr_name,
namespace
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use kube::Resource;
#[test]
fn test_crd_metadata() {
assert_eq!(DynamoWorkerMetadata::group(&()), "nvidia.com");
assert_eq!(DynamoWorkerMetadata::version(&()), "v1alpha1");
assert_eq!(DynamoWorkerMetadata::kind(&()), "DynamoWorkerMetadata");
assert_eq!(DynamoWorkerMetadata::plural(&()), "dynamoworkermetadatas");
}
#[test]
fn test_serialization_roundtrip() {
let data = serde_json::json!({
"endpoints": {
"ns/comp/ep": {
"type": "Endpoint",
"namespace": "ns",
"component": "comp",
"endpoint": "ep",
"instance_id": 12345,
"transport": { "Nats": "nats://localhost:4222" }
}
},
"model_cards": {}
});
let spec = DynamoWorkerMetadataSpec::new(data.clone());
let cr = DynamoWorkerMetadata::new("test-pod", spec);
let json = serde_json::to_string(&cr).expect("Failed to serialize CR");
let deserialized: DynamoWorkerMetadata =
serde_json::from_str(&json).expect("Failed to deserialize CR");
assert_eq!(deserialized.spec.data, data);
}
}