Skip to content

Commit

Permalink
Add PodListeners (#644)
Browse files Browse the repository at this point in the history
* Add PodListeners

* Add pod listener scope

* Add address type to ListenerIngress

* Add docs for PodListeners

* Mention who is responsible for creating the PodListeners

* Add list-op CRD summary docs

* Update src/commons/listener.rs

Co-authored-by: Felix Hennig <fhennig@users.noreply.github.com>

* Changelog

* Derive additional traits

* Explicitly pluralize `PodListeners` as `podlisteners`

* Fix changelog

---------

Co-authored-by: Felix Hennig <fhennig@users.noreply.github.com>
Co-authored-by: Siegfried Weber <mail@siegfriedweber.net>
  • Loading branch information
3 people authored Sep 15, 2023
1 parent d2b8b80 commit 63da978
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 8 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ All notable changes to this project will be documented in this file.

### Added

- `PodListeners` CRD ([#644]).
- Add support for tls pkcs12 password to secret operator volume builder ([#645]).

### Changed

- Derive `Eq` and `Copy` where applicable for listener CRDs ([#644]).
- Bump `kube` to `0.86.0` and Kubernetes version to `1.28` ([#648]).

[#644]: https://github.com/stackabletech/operator-rs/pull/644
[#645]: https://github.com/stackabletech/operator-rs/pull/645
[#648]: https://github.com/stackabletech/operator-rs/pull/648

Expand Down
101 changes: 93 additions & 8 deletions src/commons/listener.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
//! This modules provides resource types used to interact with [listener-operator](https://docs.stackable.tech/listener-operator/stable/index.html)
//!
//! # Custom Resources
//!
//! ## [`Listener`]
//!
//! Exposes a set of pods, either internally to the cluster or to the outside world. The mechanism for how it is exposed
//! is managed by the [`ListenerClass`].
//!
//! It can be either created manually by the application administrator (for applications that expose a single load-balanced endpoint),
//! or automatically when mounting a [listener volume](`ListenerOperatorVolumeSourceBuilder`) (for applications that expose a separate endpoint
//! per replica).
//!
//! All exposed pods *must* have a mounted [listener volume](`ListenerOperatorVolumeSourceBuilder`), regardless of whether the [`Listener`] is created automatically.
//!
//! ## [`ListenerClass`]
//!
//! Declares a policy for how [`Listener`]s are exposed to users.
//!
//! It is created by the cluster administrator.
//!
//! ## [`PodListeners`]
//!
//! Informs users and other operators about the state of all [`Listener`]s associated with a [`Pod`].
//!
//! It is created by the Stackable Secret Operator, and always named `pod-{pod.metadata.uid}`.
use std::collections::BTreeMap;

Expand All @@ -7,10 +32,15 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[cfg(doc)]
use k8s_openapi::api::core::v1::{Node, Pod, Service, Volume};
use k8s_openapi::api::core::v1::{
Node, PersistentVolume, PersistentVolumeClaim, Pod, Service, Volume,
};

#[cfg(doc)]
use crate::builder::ListenerOperatorVolumeSourceBuilder;

/// Defines a policy for how [`Listener`]s should be exposed.
#[derive(CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[derive(CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[kube(
group = "listeners.stackable.tech",
version = "v1alpha1",
Expand All @@ -25,7 +55,7 @@ pub struct ListenerClassSpec {
}

/// The method used to access the services.
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, JsonSchema, PartialEq, Eq)]
pub enum ServiceType {
/// Reserve a port on each node.
NodePort,
Expand All @@ -37,11 +67,13 @@ pub enum ServiceType {

/// Exposes a set of pods to the outside world.
///
/// Essentially a Stackable extension of a Kubernetes [`Service`]. Compared to [`Service`], [`Listener`] changes two things:
/// Essentially a Stackable extension of a Kubernetes [`Service`]. Compared to [`Service`], [`Listener`] changes three things:
/// 1. It uses a cluster-level policy object ([`ListenerClass`]) to define how exactly the exposure works
/// 2. It has a consistent API for reading back the exposed address(es) of the service
/// 3. The [`Pod`] must mount a [`Volume`] referring to the `Listener`, which also allows us to control stickiness
#[derive(CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, Default)]
#[derive(
CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq,
)]
#[kube(
group = "listeners.stackable.tech",
version = "v1alpha1",
Expand Down Expand Up @@ -69,7 +101,7 @@ impl ListenerSpec {
}
}

#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ListenerPort {
/// The name of the port.
Expand All @@ -83,7 +115,7 @@ pub struct ListenerPort {
}

/// Informs users about how to reach the [`Listener`].
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ListenerStatus {
/// The backing Kubernetes [`Service`].
Expand All @@ -98,11 +130,64 @@ pub struct ListenerStatus {
}

/// One address that a [`Listener`] is accessible from.
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)]
#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ListenerIngress {
/// The hostname or IP address to the [`Listener`].
pub address: String,
/// The type of address (`Hostname` or `IP`).
pub address_type: AddressType,
/// Port mapping table.
pub ports: BTreeMap<String, i32>,
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub enum AddressType {
Hostname,
#[serde(rename = "IP")]
Ip,
}

/// Informs users about [`Listener`]s that are bound by a given [`Pod`].
///
/// This is not expected to be created or modified by users. It will be created by
/// the Stackable Listener Operator when mounting the listener volume, and is always
/// named `pod-{pod.metadata.uid}`.
#[derive(
CustomResource, Serialize, Deserialize, Clone, Debug, JsonSchema, Default, PartialEq, Eq,
)]
#[kube(
group = "listeners.stackable.tech",
version = "v1alpha1",
kind = "PodListeners",
namespaced,
plural = "podlisteners"
)]
#[serde(rename_all = "camelCase")]
pub struct PodListenersSpec {
/// All listeners currently bound by the [`Pod`].
///
/// Indexed by [`Volume`] name (not [`PersistentVolume`] or [`PersistentVolumeClaim`]).
pub listeners: BTreeMap<String, PodListener>,
}

#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PodListener {
/// `Node` if this address only allows access to [`Pod`]s hosted on a specific Kubernetes [`Node`], otherwise `Cluster`.
pub scope: PodListenerScope,
/// Addresses allowing access to this [`Pod`].
///
/// Compared to [`ListenerStatus::ingress_addresses`], this list is restricted to addresses that can access this [`Pod`].
///
/// This field is intended to be equivalent to the files mounted into the listener volume.
pub ingress_addresses: Option<Vec<ListenerIngress>>,
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "PascalCase")]
pub enum PodListenerScope {
Node,
Cluster,
}

0 comments on commit 63da978

Please sign in to comment.