### Example Usage of `#[versioned]` Macro Source: https://github.com/stackabletech/operator-rs/blob/main/crates/stackable-versioned-macros/tests/README.md Demonstrates the structure of an input file for the `#[versioned]` macro, including imports, the macro attribute, the item it's applied to, and the rest of the code. Requires `rust-src` to be installed. ```rust use stackable_versioned::versioned; // --- <- See here! #[versioned( version(name = "v1alpha1"), version(name = "v1beta1"), version(name = "v1") )] // --- <- See here! pub(crate) struct Foo { #[versioned( changed(since = "v1beta1", from_name = "jjj", from_type = "u8"), changed(since = "v1", from_type = "u16"), )] bar: usize, baz: bool, } // --- <- See here! fn main() {} // Rest of code ... ``` -------------------------------- ### Build Kubernetes Container with Probes and Resources Source: https://context7.com/stackabletech/operator-rs/llms.txt Use `ContainerBuilder` to create a Kubernetes `Container` object. This example demonstrates setting environment variables, ports, volume mounts, readiness and liveness probes, lifecycle hooks, and resource requirements. ```rust use k8s_openapi::api::core::v1::{Container, ExecAction, HTTPGetAction, Lifecycle, LifecycleHandler, Probe}; use stackable_operator::builder::pod::{ container::{ContainerBuilder, FieldPathEnvVar}, resources::ResourceRequirementsBuilder, security::ContainerSecurityContextBuilder, }; fn build_container_with_probes() -> Result> { let readiness_probe = Probe { http_get: Some(HTTPGetAction { path: Some("/health".to_string()), port: k8s_openapi::apimachinery::pkg::util::intstr::IntOrString::Int(8080), ..Default::default() }), initial_delay_seconds: Some(10), period_seconds: Some(5), ..Default::default() }; let liveness_probe = Probe { exec: Some(ExecAction { command: Some(vec!["cat".to_string(), "/tmp/healthy".to_string()]) }), initial_delay_seconds: Some(30), period_seconds: Some(10), ..Default::default() }; let pre_stop = LifecycleHandler { exec: Some(ExecAction { command: Some(vec!["sh".to_string(), "-c".to_string(), "sleep 10".to_string()]) }), ..Default::default() }; let container = ContainerBuilder::new("webserver")? .image("nginx:1.25") .add_env_var("NGINX_PORT", "8080") .add_env_var_from_field_path("POD_NAME", &FieldPathEnvVar::Name) .add_env_var_from_field_path("POD_NAMESPACE", &FieldPathEnvVar::Namespace) .add_env_var_from_field_path("POD_UID", &FieldPathEnvVar::UID) .add_container_port("http", 8080) .add_volume_mount("www", "/usr/share/nginx/html")? .readiness_probe(readiness_probe) .liveness_probe(liveness_probe) .lifecycle_pre_stop(pre_stop) .resources( ResourceRequirementsBuilder::new() .with_cpu_request("100m") .with_cpu_limit("500m") .with_memory_request("128Mi") .with_memory_limit("256Mi") .build() ) .build(); Ok(container) } ``` -------------------------------- ### Build Kubernetes ObjectMeta with Labels and Annotations Source: https://context7.com/stackabletech/operator-rs/llms.txt Use `ObjectMetaBuilder` to construct Kubernetes `ObjectMeta`. This example shows how to set name, namespace, owner references, recommended labels, custom labels, annotations, and finalizers. ```rust use k8s_openapi::api::core::v1::Pod; use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta; use stackable_operator::{ builder::meta::ObjectMetaBuilder, kvp::{Annotation, Annotations, Label, Labels, ObjectLabels}, }; fn build_metadata(owner: &Pod) -> Result> { let labels = ObjectLabels { owner, app_name: "zookeeper", app_version: "3.8.1", operator_name: "zookeeper.stackable.tech", controller_name: "zookeepercluster", role: "server", role_group: "default", }; let metadata = ObjectMetaBuilder::new() .name("zookeeper-server-default-0") .namespace("zk-namespace") .ownerreference_from_resource(owner, Some(true), Some(true))? .with_recommended_labels(&labels)? .with_label(Label::try_from(("custom-label", "custom-value"))?) .with_annotation(Annotation::try_from(("prometheus.io/scrape", "true"))?) .with_annotation(Annotation::try_from(("prometheus.io/port", "9090"))?) .with_finalizer("zookeeper.stackable.tech/cleanup") .build(); Ok(metadata) } ``` -------------------------------- ### Kubernetes Client Operations Source: https://context7.com/stackabletech/operator-rs/llms.txt Demonstrates common Kubernetes API interactions using the Stackable Operator client, including getting, creating, patching, and deleting resources. Supports server-side apply for updates. ```rust use clap::Parser; use k8s_openapi::api::core::v1::{ConfigMap, Pod}; use stackable_operator::{ client::{Client, initialize_operator}, utils::cluster_info::KubernetesClusterInfoOptions, }; #[tokio::main] async fn main() -> Result<(), Box> { let cluster_info_opts = KubernetesClusterInfoOptions::parse(); let client = initialize_operator(Some("my-operator".to_string()), &cluster_info_opts).await?; // Get a resource let pod: Pod = client.get("my-pod", "default").await?; // Get optional (returns None if not found) let maybe_cm: Option = client.get_opt("my-config", "default").await?; // Create a resource let new_cm = ConfigMap::default(); let created = client.create(&new_cm).await?; // Server-side apply patch (creates or updates) let patched = client.apply_patch("my-field-manager", &new_cm, &new_cm).await?; // Apply status patch client.apply_patch_status("status-manager", &pod, &serde_json::json!({{"phase": "Running"}})).await?; // Delete a resource client.delete(&pod).await?; // Ensure resource is fully deleted (waits for removal) client.ensure_deleted(pod).await?; Ok(()) } ``` -------------------------------- ### Define and Configure Roles with Role Groups Source: https://context7.com/stackabletech/operator-rs/llms.txt Demonstrates defining roles with specific configurations and role groups, where role group settings override role-level settings. Requires implementing the `Configuration` trait for custom configuration structs. ```rust use std::collections::HashMap; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use stackable_operator::{ role_utils::{CommonConfiguration, GenericCommonConfig, Role, RoleGroup}, product_config_utils::{Configuration, transform_all_roles_to_config}, }; use product_config::types::PropertyNameKind; #[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize)] struct MyConfig { pub memory: Option, pub cpu_cores: Option, } // Implement Configuration trait for config validation impl Configuration for MyConfig { type Configurable = MyCluster; fn compute_env(&self, _resource: &Self::Configurable, _role_name: &str) -> Result>, stackable_operator::product_config_utils::Error> { let mut env = std::collections::BTreeMap::new(); if let Some(mem) = &self.memory { env.insert("MEMORY".to_string(), Some(mem.clone())); } Ok(env) } fn compute_cli(&self, _resource: &Self::Configurable, _role_name: &str) -> Result>, stackable_operator::product_config_utils::Error> { Ok(std::collections::BTreeMap::new()) } fn compute_files(&self, _resource: &Self::Configurable, _role_name: &str, _file: &str) -> Result>, stackable_operator::product_config_utils::Error> { Ok(std::collections::BTreeMap::new()) } } struct MyCluster; type MyRole = Role>, (), GenericCommonConfig>; fn example_role_config() { // Define roles with role groups let roles: HashMap, MyRole)> = HashMap::from([ ("worker".to_string(), ( vec![PropertyNameKind::Env], Role { config: CommonConfiguration { config: MyConfig { memory: Some("2Gi".to_string()), cpu_cores: Some(2) }, ..Default::default() }, role_config: (), role_groups: HashMap::from([ ("default".to_string(), RoleGroup { replicas: Some(3), config: CommonConfiguration { config: MyConfig { memory: Some("4Gi".to_string()), cpu_cores: None }, ..Default::default() }, ..Default::default() }), ]).into_iter().collect(), } )), ]); let cluster = MyCluster; let config = transform_all_roles_to_config(&cluster, &roles); // Config is merged: role_group overrides role settings } ``` -------------------------------- ### Create TLS Certificates with stackable-certs Source: https://context7.com/stackabletech/operator-rs/llms.txt Demonstrates creating a Certificate Authority and signing a leaf certificate for a webhook server using the `stackable-certs` crate. Requires the `rustls` feature for DER format output. ```rust use stackable_certs::{ ca::CertificateAuthority, keys::ecdsa::{EcdsaKeypair, EcdsaSigningKey}, CertificatePair, }; use std::time::Duration; async fn create_certificates() -> Result<(), Box> { // Create a Certificate Authority let ca = CertificateAuthority::::builder() .validity(Duration::from_secs(365 * 24 * 60 * 60)) // 1 year .common_name("My CA") .build()?; // Sign a leaf certificate for a webhook server let leaf_cert = ca.sign_leaf_certificate( "webhook-server", &["webhook.default.svc", "webhook.default.svc.cluster.local"], Duration::from_secs(90 * 24 * 60 * 60), // 90 days )?; // Get certificate and key in DER format for rustls #[cfg(feature = "rustls")] { let cert_der = leaf_cert.certificate_der()?; let key_der = leaf_cert.private_key_der()?; } Ok(()) } ``` -------------------------------- ### Build Type-Safe Labels and Annotations Source: https://context7.com/stackabletech/operator-rs/llms.txt Shows how to create Kubernetes Labels and Annotations using type-safe builders from `stackable-operator::kvp`. Supports creation from BTreeMap, individual labels, and common label helpers. ```rust use std::collections::BTreeMap; use stackable_operator::kvp::{ Annotation, Annotations, Label, Labels, ObjectLabels, consts::{K8S_APP_COMPONENT_KEY, K8S_APP_INSTANCE_KEY, K8S_APP_NAME_KEY}, }; fn create_labels_and_annotations() -> Result<(Labels, Annotations), Box> { // Create labels from a BTreeMap let labels = Labels::try_from(BTreeMap::from([ ("app.kubernetes.io/name", "kafka"), ("app.kubernetes.io/instance", "kafka-cluster"), ("app.kubernetes.io/component", "broker"), ("app.kubernetes.io/managed-by", "kafka.stackable.tech/kafkacluster"), ]))?; // Create individual labels let mut custom_labels = Labels::new(); custom_labels.insert(Label::try_from(("environment", "production"))?); custom_labels.insert(Label::try_from(("team", "platform"))?); // Create annotations let mut annotations = Annotations::new(); annotations.insert(Annotation::try_from(("prometheus.io/scrape", "true"))?); annotations.insert(Annotation::try_from(("prometheus.io/port", "9404"))?); annotations.insert(Annotation::try_from(( "kubectl.kubernetes.io/last-applied-configuration", "{...}" ))?); // Common labels helper let common = Labels::common("kafka", "kafka-cluster")?; Ok((labels, annotations)) } ``` -------------------------------- ### Running Snapshot Tests with `cargo-insta` Source: https://github.com/stackabletech/operator-rs/blob/main/crates/stackable-versioned-macros/tests/README.md Command to run snapshot tests for the `stackable-versioned-macros` crate with all features enabled. This command generates new snapshot files with a `.new` extension. ```shell cargo insta test -p stackable-versioned-macros --all-features ``` -------------------------------- ### Create Kubernetes Volumes with VolumeBuilder Source: https://context7.com/stackabletech/operator-rs/llms.txt Illustrates creating various Kubernetes Volume objects using `VolumeBuilder` and `SecretOperatorVolumeSourceBuilder`. Supports ConfigMap, Secret, EmptyDir, PVC, and Stackable secret management volumes. ```rust use k8s_openapi::api::core::v1::Volume; use k8s_openapi::apimachinery::pkg::api::resource::Quantity; use stackable_operator::builder::pod::volume::{ SecretOperatorVolumeSourceBuilder, VolumeBuilder, }; fn create_volumes() -> Result, Box> { let volumes = vec![ // ConfigMap volume VolumeBuilder::new("config") .with_config_map("app-config") .build(), // Secret volume VolumeBuilder::new("credentials") .with_secret("db-credentials", None) .build(), // EmptyDir volume with size limit VolumeBuilder::new("cache") .with_empty_dir( Some("Memory"), Some(Quantity("1Gi".to_string())) ) .build(), // PVC volume VolumeBuilder::new("data") .with_pvc("data-pvc") .build(), // Secret Operator volume (for Stackable secret management) { let secret_volume = SecretOperatorVolumeSourceBuilder::new("tls") .with_pod_scope() .build_ephemeral()?; Volume { name: "tls-certs".to_string(), ephemeral: Some(secret_volume), ..Default::default() } }, ]; Ok(volumes) } ``` -------------------------------- ### Parse Kubernetes API Version Source: https://github.com/stackabletech/operator-rs/blob/main/crates/k8s-version/README.md Use `ApiVersion::from_str` to parse a string into an `ApiVersion` object. Ensure the input string is a valid API version format. ```rust use k8s_version::ApiVersion; let api_version = ApiVersion::from_str("extensions/v1beta1")?; ``` -------------------------------- ### PodBuilder for Kubernetes Pods Source: https://context7.com/stackabletech/operator-rs/llms.txt Constructs Kubernetes Pod objects using a fluent API. Allows configuration of containers, volumes, resource requirements, environment variables, and metadata. ```rust use k8s_openapi::api::core::v1::Pod; use stackable_operator::{ builder::{ meta::ObjectMetaBuilder, pod::{PodBuilder, container::ContainerBuilder, resources::ResourceRequirementsBuilder, volume::VolumeBuilder}, }, kvp::Labels, }; use std::collections::BTreeMap; fn build_application_pod() -> Result> { let resources = ResourceRequirementsBuilder::new() .with_cpu_request("500m") .with_cpu_limit("2000m") .with_memory_request("512Mi") .with_memory_limit("2Gi") .build(); let main_container = ContainerBuilder::new("app")? .image("myregistry/myapp:1.0.0") .image_pull_policy("IfNotPresent") .command(vec!["./start.sh".to_string()]) .args(vec!["--config".to_string(), "/config/app.yaml".to_string()]) .add_env_var("LOG_LEVEL", "INFO") .add_env_var_from_secret("DB_PASSWORD", "db-credentials", "password") .add_env_var_from_config_map("APP_CONFIG", "app-settings", "mode") .add_container_port("http", 8080) .add_container_port("metrics", 9090) .add_volume_mount("config", "/config")? .add_volume_mount("data", "/data")? .resources(resources) .build(); let init_container = ContainerBuilder::new("init-config")? .image("busybox:latest") .command(vec!["sh".to_string(), "-c".to_string()]) .args(vec!["cp /defaults/* /config/".to_string()]) .add_volume_mount("config", "/config")? .build(); let labels = Labels::try_from(BTreeMap::from([ ("app.kubernetes.io/name", "myapp"), ("app.kubernetes.io/instance", "myapp-cluster"), ("app.kubernetes.io/component", "worker"), ]))?; let pod = PodBuilder::new() .metadata( ObjectMetaBuilder::new() .name("myapp-worker-0") .namespace("production") .build() ) .add_init_container(init_container) .add_container(main_container) .add_volume(VolumeBuilder::new("config").with_empty_dir(None::, None).build())? .add_volume(VolumeBuilder::new("data").with_empty_dir(None::, None).build())? .add_listener_volume_by_listener_class("listener", "nodeport", &labels)? .service_account_name("myapp-sa") .restart_policy("Always") .build()?; Ok(pod) } ``` -------------------------------- ### Build Kubernetes Resource Requirements Source: https://context7.com/stackabletech/operator-rs/llms.txt Utilizes `ResourceRequirementsBuilder` for type-safe construction of Kubernetes CPU and memory limits/requests, including custom resources like GPUs. ```rust use k8s_openapi::api::core::v1::ResourceRequirements; use stackable_operator::{ builder::pod::resources::ResourceRequirementsBuilder, commons::resources::ResourceRequirementsType, }; fn build_resources() -> ResourceRequirements { ResourceRequirementsBuilder::new() .with_cpu_request("250m") .with_cpu_limit("2") .with_memory_request("512Mi") .with_memory_limit("4Gi") // Custom resources like GPUs .with_resource(ResourceRequirementsType::Limits, "nvidia.com/gpu", "1") .with_resource(ResourceRequirementsType::Requests, "nvidia.com/gpu", "1") .build() } ``` -------------------------------- ### Reconcile Function with ClusterResources Source: https://context7.com/stackabletech/operator-rs/llms.txt This function demonstrates how to use the ClusterResources struct to manage Kubernetes resources like Services, ConfigMaps, and StatefulSets. It ensures that only resources added during the current reconciliation cycle are kept, and orphaned resources are deleted. ```rust use std::sync::Arc; use k8s_openapi::api::{apps::v1::StatefulSet, core::v1::{ConfigMap, Service}}; use kube::{CustomResource, runtime::controller::Action}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use stackable_operator::{ client::Client, cluster_resources::{ClusterResourceApplyStrategy, ClusterResources}, deep_merger::ObjectOverrides, }; #[derive(Clone, CustomResource, Debug, Deserialize, JsonSchema, Serialize)] #[kube(group = "example.stackable.tech", version = "v1", kind = "ExampleCluster", namespaced)] struct ExampleClusterSpec { #[serde(default)] pub object_overrides: ObjectOverrides, } async fn reconcile( cluster: Arc, client: Arc, ) -> Result> { let mut cluster_resources = ClusterResources::new( "example", // app_name "example.stackable.tech", // operator_name "examplecluster", // controller_name &cluster.object_ref(&()), // cluster reference ClusterResourceApplyStrategy::Default, // apply strategy &cluster.spec.object_overrides, // user overrides )?; // Create and track a Service let service = Service::default(); let patched_service = cluster_resources.add(&client, service).await?; // Create and track a ConfigMap let configmap = ConfigMap::default(); cluster_resources.add(&client, configmap).await?; // Create and track a StatefulSet let statefulset = StatefulSet::default(); cluster_resources.add(&client, statefulset).await?; // Delete any resources that were previously created but not added this reconciliation cluster_resources.delete_orphaned_resources(&client).await?; Ok(Action::requeue(std::time::Duration::from_secs(300))) } ``` -------------------------------- ### Automatic CRD Versioning with `versioned` Macro Source: https://context7.com/stackabletech/operator-rs/llms.txt The `versioned` macro automates CRD versioning and conversion between API versions. It allows defining fields with version-specific availability, renames, and deprecation notes. ```rust use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use stackable_versioned::versioned; #[versioned(version(name = "v1alpha1"), version(name = "v1beta1"), version(name = "v1"))] #[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct DatabaseClusterSpec { // Field available in all versions pub replicas: i32, // Field added in v1beta1 #[versioned(added(since = "v1beta1"))] pub storage_class: Option, // Field renamed in v1 #[versioned(renamed(since = "v1", from = "dbVersion"))] pub database_version: String, // Field deprecated in v1 #[versioned(deprecated(since = "v1", note = "Use storageClass instead"))] pub legacy_storage: Option, } // The macro generates: // - v1alpha1::DatabaseClusterSpec // - v1beta1::DatabaseClusterSpec // - v1::DatabaseClusterSpec // - Conversion implementations between versions ``` -------------------------------- ### Struct Versioning with stackable-versioned Source: https://github.com/stackabletech/operator-rs/blob/main/crates/stackable-versioned/README.md Use the `versioned` derive macro to declare multiple versions for a struct. Field-level attributes like `added`, `changed`, and `deprecated` can specify versioning details. ```rust use stackable_versioned::versioned; #[versioned( version(name = "v1alpha1"), version(name = "v1beta1"), version(name = "v1"), version(name = "v2"), version(name = "v3") )] struct Foo { /// My docs #[versioned( added(since = "v1alpha1"), changed(since = "v1beta1", from_name = "gau"), deprecated(since = "v2", note = "not required anymore") )] deprecated_bar: usize, baz: bool, } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.