//! Example of using roperator to create an operator for an `TempNamespace` example Custom Resource. //! When an instance of the TempNamespace CRD is created, the operator will create an actual k8s //! namespace in response. It will automaticaly delete the namespace after the provided duration. //! //! This example uses the `DefaultFailableHandler` to wrap a `FailableHandler` impl. This //! provides a somewhat more opinionated and simpler interface that makes it easy to have proper //! error handling and visibility. This requires the "failable" feature to be enabled. #[macro_use] extern crate serde_derive; use chrono::offset::Utc; use k8s_openapi::apimachinery::pkg::apis::meta::v1::{ObjectMeta, Time}; use roperator::config::{ClientConfig, Credentials, KubeConfig}; use roperator::handler::failable::{DefaultFailableHandler, FailableHandler, HandlerResult}; use roperator::prelude::{k8s_types, ChildConfig, K8sType, OperatorConfig, SyncRequest}; use roperator::serde_json::{json, Value}; use serde::de::{self, Deserialize, Deserializer}; use std::time::Duration; /// Name of our operator, which is automatically added as a label value in all of the child resources we create const OPERATOR_NAME: &str = "temp-namespace-example"; /// a `K8sType` with basic info about our parent CRD static PARENT_TYPE: &K8sType = &K8sType { api_version: "example.roperator.com/v1alpha1", kind: "TempNamespace", plural_kind: "tempnamespaces", }; /// Represents an instance of the CRD that is in the kubernetes cluster. /// Note that this struct does not need to implement Serialize because the /// operator will only ever update the `status` subresource #[derive(Deserialize, Clone, Debug, PartialEq)] pub struct TempNamespace { pub metadata: ObjectMeta, pub spec: TempNamespaceSpec, pub status: Option, } impl TempNamespace { fn get_time_remaining(&self) -> Option { let created_at = self .status .as_ref() .and_then(|status| status.created_at.as_ref().map(|time| time.0)) .unwrap_or(Utc::now()); let elapsed = Utc::now() .signed_duration_since(created_at) .to_std() .unwrap_or_else(|_| Duration::from_secs(0)); if self.spec.delete_after > elapsed { Some(self.spec.delete_after - elapsed) } else { None } } } #[derive(Deserialize, Clone, Debug, PartialEq)] pub struct TempNamespaceSpec { #[serde(rename = "deleteAfter", deserialize_with = "deserialize_duration")] delete_after: Duration, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[serde(rename_all = "camelCase")] pub struct TempNamespaceStatus { #[serde(skip_serializing_if = "Option::is_none")] created_at: Option