Skip to content

Commit 483e519

Browse files
committed
feat: Allow tweaking catalog name in Trino
1 parent b3787d4 commit 483e519

6 files changed

Lines changed: 142 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ All notable changes to this project will be documented in this file.
99
- BREAKING: Add required CLI argument and env var to set the image repository used to construct final product image names: `IMAGE_REPOSITORY` (`--image-repository`), eg. `oci.example.org/my/namespace` ([#884]).
1010
- Added support for the [PostgreSQL connector](https://trino.io/docs/current/connector/postgresql.html) using the new generic database connection mechanism.
1111
Previously, users had to use the `generic` connector ([#883]).
12-
- Added support for Trino 481 ([#900]).
12+
- Add support for Trino 481 ([#900]).
13+
- Add a new `.spec.name.inferred.replaceHyphensWithUnderscores` field on TrinoCatalog, which allows tweaking the catalog name in Trino ([#XXX]).
1314

1415
### Changed
1516

@@ -40,6 +41,7 @@ All notable changes to this project will be documented in this file.
4041
[#889]: https://github.com/stackabletech/trino-operator/pull/889
4142
[#895]: https://github.com/stackabletech/trino-operator/pull/895
4243
[#900]: https://github.com/stackabletech/trino-operator/pull/900
44+
[#XXX]: https://github.com/stackabletech/trino-operator/pull/XXX
4345

4446
## [26.3.0] - 2026-03-16
4547

docs/modules/trino/pages/usage-guide/catalogs/index.adoc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,28 @@ In this case the `hive` and `iceberg` catalogs will be used as they both match t
105105

106106
A `TrinoCluster` can, once created, detect and use new catalogs that have been subsequently created with a matching label. This also means that it is possible to reuse a `TrinoCatalog` within multiple `TrinoClusters`.
107107

108+
=== Catalog name tweaking
109+
110+
By default the name of the catalog in Trino is inferred from the `.metadata.name` of the TrinoCatalog object.
111+
This ensures that no catalog names clash, as their can only be one TrinoCatalog with a given name.
112+
113+
One inconvenience is that you need to quote catalogs (or schemas and tables for that matter) containing `-` in Trino, while `_` is fine.
114+
As Kubernetes doesn't allow `_` in the object names, we offer a feature to replace `-` with `_`, which allows you to use valid Kubernetes names, but keeps the convenience of `_` in catalog names.
115+
116+
You can enable it like this, the Trino catalog will be called `my_postgres`:
117+
118+
[source,yaml]
119+
----
120+
kind: TrinoCatalog
121+
metadata:
122+
name: my-postgres
123+
spec:
124+
name:
125+
inferred:
126+
replaceHyphensWithUnderscores: true
127+
# ...
128+
----
129+
108130
=== Generic fallback connector
109131

110132
Trino supports lots of different connectors and we can not cover all the available connectors.

extra/crds.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4279,6 +4279,34 @@ spec:
42794279
items:
42804280
type: string
42814281
type: array
4282+
name:
4283+
default:
4284+
inferred:
4285+
replaceHyphensWithUnderscores: false
4286+
description: The name of the catalog
4287+
oneOf:
4288+
- required:
4289+
- inferred
4290+
properties:
4291+
inferred:
4292+
description: |-
4293+
Infer the catalog name from the `.metadata.name` of the TrinoCatalog resource.
4294+
4295+
This ensures that no catalog names clash, as their can only be one TrinoCatalog with a
4296+
given name.
4297+
properties:
4298+
replaceHyphensWithUnderscores:
4299+
default: false
4300+
description: |-
4301+
Wether hyphens (`-`) in the name of the catalog should be replaced by underscores (`_`).
4302+
4303+
This is recommended because Kubernetes only allows `a-z` and `-`, while Trino
4304+
requires quoting for catalogs containing `-` characters, but not for `_`. This mechanism
4305+
allows you to use valid Kubernetes names, but keeps the convenience of `_` in catalog
4306+
names.
4307+
type: boolean
4308+
type: object
4309+
type: object
42824310
required:
42834311
- connector
42844312
type: object

rust/operator-binary/src/catalog/config.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use stackable_operator::{
55
k8s_openapi::api::core::v1::{
66
ConfigMapKeySelector, EnvVar, EnvVarSource, SecretKeySelector, Volume, VolumeMount,
77
},
8-
kube::{Resource, ResourceExt},
8+
kube::ResourceExt,
99
};
1010

1111
use super::{FromTrinoCatalogError, ToCatalogConfig};
@@ -103,15 +103,11 @@ impl CatalogConfig {
103103
}
104104

105105
pub async fn from_catalog(
106+
catalog_name: &str,
106107
catalog: &v1alpha1::TrinoCatalog,
107108
client: &Client,
108109
trino_version: u16,
109110
) -> Result<CatalogConfig, FromTrinoCatalogError> {
110-
let catalog_name = catalog
111-
.meta()
112-
.name
113-
.clone()
114-
.ok_or(FromTrinoCatalogError::InvalidCatalogSpec)?;
115111
let catalog_namespace = catalog.namespace();
116112

117113
let to_catalog_config: &dyn ToCatalogConfig = match &catalog.spec.connector {
@@ -126,7 +122,7 @@ impl CatalogConfig {
126122
TrinoCatalogConnector::Tpch(tpch_connector) => tpch_connector,
127123
};
128124
let mut catalog_config = to_catalog_config
129-
.to_catalog_config(&catalog_name, catalog_namespace, client, trino_version)
125+
.to_catalog_config(catalog_name, catalog_namespace, client, trino_version)
130126
.await?;
131127

132128
catalog_config

rust/operator-binary/src/controller/dereference.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
//! `ResolvedClientProtocolConfig::from_config`) currently mix fetching and validation; their
77
//! outputs are treated as "dereferenced" for now. Splitting those helpers is a follow-up.
88
9-
use std::{num::ParseIntError, str::FromStr};
9+
use std::{collections::HashSet, num::ParseIntError, str::FromStr};
1010

1111
use snafu::{OptionExt, ResultExt, Snafu};
12-
use stackable_operator::{client::Client, kube::runtime::reflector::ObjectRef};
12+
use stackable_operator::{
13+
client::Client,
14+
kube::{Resource, runtime::reflector::ObjectRef},
15+
};
1316

1417
use crate::{
1518
authorization::opa::TrinoOpaConfig,
@@ -29,6 +32,9 @@ pub enum Error {
2932
#[snafu(display("object defines no namespace"))]
3033
ObjectHasNoNamespace,
3134

35+
#[snafu(display("object defines no name"))]
36+
ObjectHasNoName,
37+
3238
#[snafu(display("failed to retrieve AuthenticationClass"))]
3339
AuthenticationClassRetrieval {
3440
source: crate::crd::authentication::Error,
@@ -63,6 +69,11 @@ pub enum Error {
6369
InvalidOpaConfig {
6470
source: stackable_operator::commons::opa::Error,
6571
},
72+
73+
#[snafu(display(
74+
"The catalog name {catalog_name:?} clashes (there are multiple catalogs with this name). Please make sure there is exactly one catalog for any given name"
75+
))]
76+
ClashingCatalogName { catalog_name: String },
6677
}
6778

6879
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -108,13 +119,32 @@ pub async fn dereference(
108119
})?;
109120

110121
let mut catalogs = Vec::with_capacity(catalog_definitions.len());
122+
let mut catalog_names: HashSet<String> = HashSet::new();
111123
for catalog in &catalog_definitions {
112124
let catalog_ref = ObjectRef::from_obj(catalog);
113-
let catalog_config = CatalogConfig::from_catalog(catalog, client, product_version)
114-
.await
115-
.context(ParseCatalogSnafu {
116-
catalog: catalog_ref,
117-
})?;
125+
// We are using a match here, as we might support other ways of naming (e.g. custom) later
126+
let catalog_name = match catalog.spec.name {
127+
catalog::v1alpha1::TrinoCatalogNameSpec::Inferred {
128+
replace_hyphens_with_underscores,
129+
} => {
130+
let mut catalog_name = catalog.meta().name.clone().context(ObjectHasNoNameSnafu)?;
131+
if replace_hyphens_with_underscores {
132+
catalog_name = catalog_name.replace('-', "_");
133+
}
134+
catalog_name
135+
}
136+
};
137+
138+
if catalog_names.insert(catalog_name.clone()) {
139+
return ClashingCatalogNameSnafu { catalog_name }.fail();
140+
}
141+
142+
let catalog_config =
143+
CatalogConfig::from_catalog(&catalog_name, catalog, client, product_version)
144+
.await
145+
.context(ParseCatalogSnafu {
146+
catalog: catalog_ref,
147+
})?;
118148
catalogs.push(catalog_config);
119149
}
120150

rust/operator-binary/src/crd/catalog/mod.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ pub mod versioned {
4848
#[derive(Clone, CustomResource, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
4949
#[serde(rename_all = "camelCase")]
5050
pub struct TrinoCatalogSpec {
51+
/// The name of the catalog
52+
#[serde(default)]
53+
pub name: TrinoCatalogNameSpec,
54+
5155
/// The `connector` defines which connector is used.
5256
pub connector: TrinoCatalogConnector,
5357

@@ -65,6 +69,47 @@ pub mod versioned {
6569
#[serde(default, rename = "experimentalConfigRemovals")]
6670
pub config_removals: Vec<String>,
6771
}
72+
73+
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
74+
#[serde(rename_all = "camelCase")]
75+
pub enum TrinoCatalogNameSpec {
76+
/// Infer the catalog name from the `.metadata.name` of the TrinoCatalog resource.
77+
///
78+
/// This ensures that no catalog names clash, as their can only be one TrinoCatalog with a
79+
/// given name.
80+
#[serde(rename_all = "camelCase")]
81+
Inferred {
82+
/// Wether hyphens (`-`) in the name of the catalog should be replaced by underscores (`_`).
83+
///
84+
/// This is recommended because Kubernetes only allows `a-z` and `-`, while Trino
85+
/// requires quoting for catalogs containing `-` characters, but not for `_`. This mechanism
86+
/// allows you to use valid Kubernetes names, but keeps the convenience of `_` in catalog
87+
/// names.
88+
//
89+
// /// In case you need complete flexibility over the catalog name, you can use
90+
// /// `name.custom`.
91+
#[serde(default)]
92+
replace_hyphens_with_underscores: bool,
93+
},
94+
// As requested in https://github.com/stackabletech/trino-operator/issues/891 we are not
95+
// implementing the custom variant yet. Please re-open or create a new decision before
96+
// implementing this.
97+
//
98+
// /// Specify the name of the catalog as it shows up in Trino.
99+
// ///
100+
// /// It is your responsibility to make sure that no catalog names clash, the operator will
101+
// /// raise an error in that case.
102+
// ///
103+
// /// TIP: If you only want to replace `-` with `_` use
104+
// /// `name.inferred.replaceHyphensWithUnderscores` instead.
105+
// Custom(String),
106+
}
107+
}
108+
109+
impl Default for v1alpha1::TrinoCatalogNameSpec {
110+
fn default() -> Self {
111+
Self::Inferred { replace_hyphens_with_underscores: false }
112+
}
68113
}
69114

70115
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
@@ -172,7 +217,10 @@ mod tests {
172217
secretClass: minio-credentials
173218
- connector:
174219
tpcds: {}
175-
- connector:
220+
- name:
221+
inferred:
222+
replaceHyphensWithUnderscores: true
223+
connector:
176224
tpch: {}
177225
"})
178226
.expect("Failed to parse TrinoCatalogSpec YAML")

0 commit comments

Comments
 (0)