[][src]Crate roperator

Roperator lets you easily write Kubernetes Operators that manage a potentially complex set of child Kuberntes resources for each instance of a parent Custom Resource.

To get started, all you need is an OperatorConfig and a Handler implementation.

Busybox operator example:

use roperator::prelude::*;
use roperator::serde_json::json;

/// Name of our operator, which is automatically added as a label value in all of the child resources we create
const OPERATOR_NAME: &str = "echoserver-example";

// a `K8sType` with basic info about our parent CRD
static PARENT_TYPE: &K8sType = &K8sType {
   api_version: "example.roperator.com/v1alpha1",
   kind: "BusyBox",
   plural_kind: "busyboxes",
};

// In your main function create the OperatorConfig, which tells Roperator about
// the types of your parent and child resources, and about how to deal with
// each type of child resource when it needs updated
let operator_config = OperatorConfig::new(OPERATOR_NAME, PARENT_TYPE)
    .with_child(k8s_types::core::v1::Pod, ChildConfig::recreate());

// this function will block the current thread indifinitely while the operator runs
run_operator(operator_config, handle_sync);

fn handle_sync(request: &SyncRequest) -> Result<SyncResponse, Error> {
    // for this tiny example, we'll only create a single Pod. You can also use any of the types
    // defined in the k8s_openapi crate, which has serializable structs for all the usual resources
    let pod = json!({
        "metadata": {
            "namespace": request.parent.namespace(),
            "name": format!("{}-busybox", request.parent.name()),
        },
        "spec": {
            "containers": [
                {
                    "name": "busybox",
                    "image": "busybox:latest",
                    "command": [
                        "bash",
                        "-c",
                        format!("while true; do; echo 'Hello from {}'; sleep 10; done;", request.parent.name()),
                    ]
                }
            ]
        }
    });
    let status = json!({
        // normally, we'd derive the status by taking a look at the existing `children` in the request
        "message": "everything looks good here!",
    });
    Ok(SyncResponse {
        status,
        children: vec![pod],
        resync: None,
    })
}

The main function in most operators just needs to call roperator::runner::run_operator or roperator::runner::run_operator_with_client_config, passing the OperatorConfig and your Handler implementation.

Re-exports

pub use serde;
pub use serde_json;
pub use serde_yaml;

Modules

config

Types for creating OperatorConfig and ClientConfig. Most users will use OperatorConfig::new(). ClientConfig can be created automatically in most cases, but you can also create that manually.

error
handler

The handler module defines the Handler trait. Operators must implement their own Handler, which is where the majority of your code will live.

k8s_types

Since roperator doesn't use any swagger codegen or specialized kuberntes clients, it needs to have another way to encode and pass around information about the types of resources that it deals with. Instead, roperator uses the K8sType struct. The OperatorConfig api deals with the type &'static K8sType. The various submodules here have predefined &'static K8sTypes for all of the common v1 and v1beta1 (as of 1.15) resources. For any other types, you'd typically use the following:

prelude
resource
runner