Skip to main content

mz_cloud_resources/crd/
console.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::collections::BTreeMap;
11
12use k8s_openapi::{
13    api::core::v1::ResourceRequirements, apimachinery::pkg::apis::meta::v1::Condition,
14};
15use kube::{CustomResource, Resource, ResourceExt};
16use schemars::JsonSchema;
17use serde::{Deserialize, Serialize};
18
19use crate::crd::{ManagedResource, MaterializeCertSpec, new_resource_id};
20use mz_server_core::listeners::AuthenticatorKind;
21
22pub mod v1alpha1 {
23    use super::*;
24
25    #[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize, JsonSchema)]
26    #[serde(rename_all = "camelCase")]
27    pub enum HttpConnectionScheme {
28        #[default]
29        Http,
30        Https,
31    }
32
33    #[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize, JsonSchema)]
34    #[serde(rename_all = "camelCase")]
35    pub struct BalancerdRef {
36        /// The service name for the balancerd service to connect to
37        pub service_name: String,
38        /// The namespace the balancerd service runs in
39        pub namespace: String,
40        /// Whether to use HTTP or HTTPS to communicate with Materialize.
41        pub scheme: HttpConnectionScheme,
42        /// External DNS names balancerd serves traffic for
43        #[serde(default, skip_serializing_if = "Option::is_none")]
44        pub dns_names: Option<Vec<String>>,
45    }
46
47    #[derive(
48        CustomResource,
49        Clone,
50        Debug,
51        Default,
52        PartialEq,
53        Deserialize,
54        Serialize,
55        JsonSchema
56    )]
57    #[serde(rename_all = "camelCase")]
58    #[kube(
59        namespaced,
60        group = "materialize.cloud",
61        version = "v1alpha1",
62        kind = "Console",
63        singular = "console",
64        plural = "consoles",
65        status = "ConsoleStatus",
66        printcolumn = r#"{"name": "ImageRef", "type": "string", "description": "Reference to the Docker image.", "jsonPath": ".spec.consoleImageRef", "priority": 1}"#,
67        printcolumn = r#"{"name": "Ready", "type": "string", "description": "Whether the deployment is ready", "jsonPath": ".status.conditions[?(@.type==\"Ready\")].status", "priority": 1}"#
68    )]
69    pub struct ConsoleSpec {
70        /// The console image to run.
71        pub console_image_ref: String,
72        // Resource requirements for the console pod
73        pub resource_requirements: Option<ResourceRequirements>,
74        // Number of console pods to create
75        pub replicas: Option<i32>,
76        // The configuration for generating an x509 certificate using cert-manager for console
77        // to present to incoming connections.
78        // The dns_names and issuer_ref fields are required.
79        pub external_certificate_spec: Option<MaterializeCertSpec>,
80        // Annotations to apply to the pods
81        pub pod_annotations: Option<BTreeMap<String, String>>,
82        // Labels to apply to the pods
83        pub pod_labels: Option<BTreeMap<String, String>>,
84
85        // Connection information for the balancerd service to use
86        pub balancerd: BalancerdRef,
87        /// How to authenticate with Materialize.
88        #[serde(default)]
89        pub authenticator_kind: AuthenticatorKind,
90
91        // This can be set to override the randomly chosen resource id
92        pub resource_id: Option<String>,
93    }
94
95    impl Console {
96        pub fn name_prefixed(&self, suffix: &str) -> String {
97            format!("mz{}-{}", self.resource_id(), suffix)
98        }
99
100        pub fn resource_id(&self) -> &str {
101            &self.status.as_ref().unwrap().resource_id
102        }
103
104        pub fn namespace(&self) -> String {
105            self.meta().namespace.clone().unwrap()
106        }
107
108        pub fn deployment_name(&self) -> String {
109            self.name_prefixed("console")
110        }
111
112        pub fn replicas(&self) -> i32 {
113            self.spec.replicas.unwrap_or(2)
114        }
115
116        pub fn app_name(&self) -> String {
117            "console".to_owned()
118        }
119
120        pub fn service_name(&self) -> String {
121            self.name_prefixed("console")
122        }
123
124        pub fn configmap_name(&self) -> String {
125            self.name_prefixed("console")
126        }
127
128        pub fn external_certificate_name(&self) -> String {
129            self.name_prefixed("console-external")
130        }
131
132        pub fn external_certificate_secret_name(&self) -> String {
133            self.name_prefixed("console-external-tls")
134        }
135
136        pub fn status(&self) -> ConsoleStatus {
137            self.status.clone().unwrap_or_else(|| ConsoleStatus {
138                resource_id: self
139                    .spec
140                    .resource_id
141                    .clone()
142                    .unwrap_or_else(new_resource_id),
143                conditions: vec![],
144            })
145        }
146    }
147
148    #[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq)]
149    #[serde(rename_all = "camelCase")]
150    pub struct ConsoleStatus {
151        /// Resource identifier used as a name prefix to avoid pod name collisions.
152        pub resource_id: String,
153
154        pub conditions: Vec<Condition>,
155    }
156
157    impl ManagedResource for Console {
158        fn default_labels(&self) -> BTreeMap<String, String> {
159            BTreeMap::from_iter([
160                (
161                    "materialize.cloud/organization-name".to_owned(),
162                    self.name_unchecked(),
163                ),
164                (
165                    "materialize.cloud/organization-namespace".to_owned(),
166                    self.namespace(),
167                ),
168                (
169                    "materialize.cloud/mz-resource-id".to_owned(),
170                    self.resource_id().to_owned(),
171                ),
172                ("materialize.cloud/app".to_owned(), "console".to_owned()),
173            ])
174        }
175
176        fn app_name(&self) -> Option<&str> {
177            Some("console")
178        }
179    }
180}