Added ownerRefs

This commit is contained in:
Michael Francis 2024-05-26 15:02:43 -04:00
parent 39bab0cb3a
commit 1a7dfa7acd
3 changed files with 109 additions and 39 deletions

View File

@ -12,14 +12,16 @@ use kube::runtime::wait::await_condition;
use kube::runtime::watcher::Config;
use kube::Client;
use kube::CustomResourceExt;
use kube::Resource;
use kube::ResourceExt;
use kube::{runtime::controller::Action, runtime::Controller};
use tracing::error;
use tracing::info;
use tracing::instrument;
pub mod crd;
pub mod minio;
pub mod neon;
mod crd;
mod minio;
mod neon;
struct ContextData {
pub kube_client: Client,
@ -40,9 +42,11 @@ pub enum Error {
#[from]
source: kube::Error,
},
/// Error in user input or Echo resource definition, typically missing fields.
#[error("Invalid Neon CRD: {0}")]
/// Error in user input or NeonDatabase resource definition, typically missing fields.
#[error("Invalid NeonDatabase CRD: {0}")]
UserInputError(String),
#[error("General error: {0}")]
GeneralError(String),
}
#[tokio::main]
@ -55,7 +59,7 @@ async fn main() {
let crd_api: Api<NeonDatabase> = Api::all(kube_client.clone());
let context: Arc<ContextData> = Arc::new(ContextData::new(kube_client.clone()));
let ssapply = PatchParams::apply("crd_apply_example").force();
let ssapply = PatchParams::apply("neon_operator").force();
let crds: Api<CustomResourceDefinition> = Api::all(kube_client.clone());
info!(
"Creating crd: {}",
@ -77,7 +81,7 @@ async fn main() {
);
let _ = tokio::time::timeout(std::time::Duration::from_secs(10), establish)
.await
.expect("Waiting failed");
.expect("Timeout waiting for CRD to establish");
info!("CRD established, starting controller");
Controller::new(crd_api.clone(), Config::default())
@ -100,16 +104,44 @@ async fn reconcile(neon: Arc<NeonDatabase>, context: Arc<ContextData>) -> Result
let client = context.kube_client.clone();
let namespace: String = match neon.namespace() {
Some(ns) => ns.to_string(),
Some(ns) => ns,
None => return Err(Error::UserInputError("Missing namespace".to_string())),
};
minio::create_deployment(client.clone(), &namespace).await?;
minio::create_service(client.clone(), &namespace).await?;
neon::reconcile_storage_broker(client.clone(), &namespace).await?;
neon::reconcile_page_server(client.clone(), &namespace).await?;
neon::reconcile_safe_keepers(client.clone(), &namespace).await?;
neon::reconcile_compute(client.clone(), &namespace, &neon.spec.compute_image_ref).await?;
let owner_ref = neon
.controller_owner_ref(&())
.ok_or(Error::GeneralError("Missing owner ref".to_string()))?;
minio::create_deployment(client.clone(), &owner_ref, &namespace).await?;
minio::create_service(client.clone(), &owner_ref, &namespace).await?;
neon::reconcile_storage_broker(
client.clone(),
&owner_ref,
&namespace,
&neon.spec.neon_image_ref,
)
.await?;
neon::reconcile_page_server(
client.clone(),
&owner_ref,
&namespace,
&neon.spec.neon_image_ref,
)
.await?;
neon::reconcile_safe_keepers(
client.clone(),
&owner_ref,
&namespace,
&neon.spec.neon_image_ref,
)
.await?;
neon::reconcile_compute(
client.clone(),
&owner_ref,
&namespace,
&neon.spec.compute_image_ref,
)
.await?;
Ok(Action::requeue(Duration::from_secs(5)))
}

View File

@ -1,16 +1,33 @@
use k8s_openapi::api::apps::v1::{Deployment, DeploymentSpec};
use k8s_openapi::api::core::v1::{
Container, ContainerPort, EnvVar, PodSpec, PodTemplateSpec, Service, ServicePort, ServiceSpec,
Container, ContainerPort, EnvVar, HTTPGetAction, PodSpec, PodTemplateSpec, Probe, Service,
ServicePort, ServiceSpec,
};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::{LabelSelector, OwnerReference};
use k8s_openapi::apimachinery::pkg::util::intstr::IntOrString;
use kube::api::{ListParams, ObjectMeta, Patch, PatchParams};
use kube::{Api, Client, Error};
use std::collections::BTreeMap;
use tracing::{info, instrument};
const NAME: &str = "minio";
// Minio settings to lift out
const NAME: &str = "minio"; // In a real world scenario, we should support multiple minio instances
const MINIO_ROOT_USER: &str = "minio";
const MINIO_ROOT_PASSWORD: &str = "password";
const MINIO_IMAGE: &str = "quay.io/minio/minio:RELEASE.2022-10-20T00-55-09Z";
const MINIO_PORT: i32 = 9000;
const MINIO_CONSOLE_PORT: i32 = 9001;
pub async fn create_deployment(client: Client, namespace: &str) -> Result<(), Error> {
// Workflow:
// 1. Create minio deployment
// 2. Create minio service
// 3. Ensure bucket exists
pub async fn create_deployment(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
) -> Result<(), Error> {
let minio_container = Container {
name: NAME.to_string(),
env: Some(vec![
@ -49,20 +66,20 @@ pub async fn create_deployment(client: Client, namespace: &str) -> Result<(), Er
.map(|s| s.to_string())
.collect::<Vec<String>>(),
),
liveness_probe: Some(k8s_openapi::api::core::v1::Probe {
http_get: Some(k8s_openapi::api::core::v1::HTTPGetAction {
liveness_probe: Some(Probe {
http_get: Some(HTTPGetAction {
path: Some("/minio/health/live".to_string()),
port: k8s_openapi::apimachinery::pkg::util::intstr::IntOrString::Int(9000),
port: IntOrString::Int(9000),
..Default::default()
}),
initial_delay_seconds: Some(10),
period_seconds: Some(30),
..Default::default()
}),
readiness_probe: Some(k8s_openapi::api::core::v1::Probe {
http_get: Some(k8s_openapi::api::core::v1::HTTPGetAction {
readiness_probe: Some(Probe {
http_get: Some(HTTPGetAction {
path: Some("/minio/health/ready".to_string()),
port: k8s_openapi::apimachinery::pkg::util::intstr::IntOrString::Int(9000),
port: IntOrString::Int(9000),
..Default::default()
}),
initial_delay_seconds: Some(10),
@ -100,6 +117,7 @@ pub async fn create_deployment(client: Client, namespace: &str) -> Result<(), Er
metadata: ObjectMeta {
name: Some(NAME.to_string()),
namespace: Some(namespace.to_string()),
owner_references: Some(vec![owner_ref.clone()]),
labels: Some(BTreeMap::from([("app".to_string(), NAME.to_string())])),
..Default::default()
},
@ -131,7 +149,7 @@ pub async fn create_deployment(client: Client, namespace: &str) -> Result<(), Er
deployment_api
.patch(
NAME,
&PatchParams::apply("neon-operator"),
&PatchParams::apply("neon_operator"),
&Patch::Apply(deployment),
)
.await?;
@ -139,12 +157,17 @@ pub async fn create_deployment(client: Client, namespace: &str) -> Result<(), Er
Ok(())
}
pub async fn create_service(client: Client, namespace: &str) -> Result<(), Error> {
pub async fn create_service(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
) -> Result<(), Error> {
let service = Service {
metadata: ObjectMeta {
name: Some(NAME.to_string()),
namespace: Some(namespace.to_string()),
labels: Some(BTreeMap::from([("app".to_string(), NAME.to_string())])),
owner_references: Some(vec![owner_ref.clone()]),
..Default::default()
},
spec: Some(ServiceSpec {
@ -162,7 +185,7 @@ pub async fn create_service(client: Client, namespace: &str) -> Result<(), Error
Api::<Service>::namespaced(client, namespace)
.patch(
NAME,
&PatchParams::apply("neon-operator"),
&PatchParams::apply("neon_operator"),
&Patch::Apply(service),
)
.await?;

View File

@ -2,21 +2,22 @@ use k8s_openapi::api::apps::v1::{Deployment, DeploymentSpec, StatefulSet};
use k8s_openapi::api::core::v1::{
Container, ContainerPort, EnvVar, PodSpec, PodTemplateSpec, Service, ServicePort, ServiceSpec,
};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::LabelSelector;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::{LabelSelector, OwnerReference};
use kube::api::{ObjectMeta, Patch, PatchParams};
use kube::{Api, Client, Error};
use std::collections::BTreeMap;
// Workflow:
// 1. Create minio deployment
// 2. Create minio service
// 3. Ensure bucket exists
pub async fn reconcile_storage_broker(client: Client, namespace: &str) -> Result<(), Error> {
pub async fn reconcile_storage_broker(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
neon_image_ref: &str,
) -> Result<(), Error> {
let storage_broker = Deployment {
metadata: ObjectMeta {
name: Some("storage-broker".to_string()),
namespace: Some(namespace.to_string()),
owner_references: Some(vec![owner_ref.clone()]),
..Default::default()
},
spec: Some(DeploymentSpec {
@ -39,7 +40,7 @@ pub async fn reconcile_storage_broker(client: Client, namespace: &str) -> Result
spec: Some(PodSpec {
containers: vec![Container {
name: "storage-broker".to_string(),
image: Some("neondatabase/neon".to_string()),
image: Some(neon_image_ref.to_string()),
ports: Some(vec![ContainerPort {
container_port: 50051,
..Default::default()
@ -104,11 +105,17 @@ pub async fn reconcile_storage_broker(client: Client, namespace: &str) -> Result
Ok(())
}
pub async fn reconcile_page_server(client: Client, namespace: &str) -> Result<(), Error> {
pub async fn reconcile_page_server(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
neon_image_ref: &str,
) -> Result<(), Error> {
let deployment = Deployment {
metadata: ObjectMeta {
name: Some("pageserver".to_string()),
namespace: Some(namespace.to_string()),
owner_references: Some(vec![owner_ref.clone()]),
..Default::default()
},
spec: Some(DeploymentSpec {
@ -131,7 +138,7 @@ pub async fn reconcile_page_server(client: Client, namespace: &str) -> Result<()
spec: Some(PodSpec {
containers: vec![Container {
name: "pageserver".to_string(),
image: Some("neondatabase/neon".to_string()),
image: Some(neon_image_ref.to_string()),
ports: Some(vec![ContainerPort {
container_port: 9898,
name: Some("http".to_string()),
@ -235,11 +242,17 @@ pub async fn reconcile_page_server(client: Client, namespace: &str) -> Result<()
Ok(())
}
pub async fn reconcile_safe_keepers(client: Client, namespace: &str) -> Result<(), Error> {
pub async fn reconcile_safe_keepers(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
neon_image_ref: &str,
) -> Result<(), Error> {
let stateful_set = StatefulSet {
metadata: ObjectMeta {
name: Some("safe-keeper".to_string()),
namespace: Some(namespace.to_string()),
owner_references: Some(vec![owner_ref.clone()]),
..Default::default()
},
spec: Some(k8s_openapi::api::apps::v1::StatefulSetSpec {
@ -263,7 +276,7 @@ pub async fn reconcile_safe_keepers(client: Client, namespace: &str) -> Result<(
spec: Some(PodSpec {
containers: vec![Container {
name: "safe-keeper".to_string(),
image: Some("neondatabase/neon".to_string()),
image: Some(neon_image_ref.to_string()),
ports: Some(vec![ContainerPort {
container_port: 7676,
..Default::default()
@ -375,6 +388,7 @@ pub async fn reconcile_safe_keepers(client: Client, namespace: &str) -> Result<(
pub async fn reconcile_compute(
client: Client,
owner_ref: &OwnerReference,
namespace: &str,
compute_image: &str,
) -> Result<(), Error> {
@ -382,6 +396,7 @@ pub async fn reconcile_compute(
metadata: ObjectMeta {
name: Some("compute".to_string()),
namespace: Some(namespace.to_string()),
owner_references: Some(vec![owner_ref.clone()]),
..Default::default()
},
spec: Some(DeploymentSpec {