Skip to content

Commit d846449

Browse files
feat: Allow tweaking catalog name in Trino (#903)
* feat: Allow tweaking catalog name in Trino * Apply suggestions from code review Co-authored-by: maltesander <malte.sander.it@gmail.com> * Apply suggestions from code review Co-authored-by: maltesander <malte.sander.it@gmail.com> * Regenerate charts * Remove custom variant code as commenRemove custom variant code comment * Use operator-rs macro * regenerate charts * Document why we have a limit of 40 chars * Add test --------- Co-authored-by: maltesander <malte.sander.it@gmail.com>
1 parent 34e9783 commit d846449

23 files changed

Lines changed: 319 additions & 102 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
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]).
1212
- Added support for Trino 481 ([#900]).
13+
- Add a new `.spec.name.inferred.replaceHyphensWithUnderscores` field on TrinoCatalog, which allows tweaking the catalog name in Trino ([#903]).
1314

1415
### Changed
1516

@@ -43,6 +44,7 @@ All notable changes to this project will be documented in this file.
4344
[#895]: https://github.com/stackabletech/trino-operator/pull/895
4445
[#897]: https://github.com/stackabletech/trino-operator/pull/897
4546
[#900]: https://github.com/stackabletech/trino-operator/pull/900
47+
[#903]: https://github.com/stackabletech/trino-operator/pull/903
4648

4749
## [26.3.0] - 2026-03-16
4850

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,29 @@ 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 there 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 using `_` in catalog names.
115+
116+
In order to replace `-` with `_`, use the setting `name.inferred.replaceHyphensWithUnderscores`.
117+
The Trino catalog will be called `my_postgres`:
118+
119+
[source,yaml]
120+
----
121+
kind: TrinoCatalog
122+
metadata:
123+
name: my-postgres
124+
spec:
125+
name:
126+
inferred:
127+
replaceHyphensWithUnderscores: true
128+
# ...
129+
----
130+
108131
=== Generic fallback connector
109132

110133
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
@@ -4227,6 +4227,34 @@ spec:
42274227
items:
42284228
type: string
42294229
type: array
4230+
name:
4231+
default:
4232+
inferred:
4233+
replaceHyphensWithUnderscores: false
4234+
description: The name of the catalog
4235+
oneOf:
4236+
- required:
4237+
- inferred
4238+
properties:
4239+
inferred:
4240+
description: |-
4241+
Infer the catalog name from the `.metadata.name` of the TrinoCatalog resource.
4242+
4243+
This ensures that no catalog names clash, as there can only be one TrinoCatalog with a
4244+
given name.
4245+
properties:
4246+
replaceHyphensWithUnderscores:
4247+
default: false
4248+
description: |-
4249+
Whether hyphens (`-`) in the name of the catalog should be replaced by underscores (`_`).
4250+
4251+
This is recommended because Kubernetes only allows `a-z` and `-`, while Trino
4252+
requires quoting for catalogs containing `-` characters. This mechanism allows
4253+
you to use valid Kubernetes names, but keeps the convenience of using `_` in
4254+
catalog names.
4255+
type: boolean
4256+
type: object
4257+
type: object
42304258
required:
42314259
- connector
42324260
type: object

rust/operator-binary/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ repository.workspace = true
99
publish = false
1010
build = "build.rs"
1111

12+
[features]
13+
# The macro attributed_string_type is used in this operator. It produces test
14+
# code if the feature "test-support" is set. This feature is defined here to
15+
# suppress a Clippy warning.
16+
test-support = []
17+
1218
[dependencies]
1319
stackable-operator = { workspace = true, features = ["test-support"] }
1420

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

4-
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::black_hole::BlackHoleConnector;
4+
use crate::{
5+
catalog::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig},
6+
crd::catalog::{TrinoCatalogName, black_hole::BlackHoleConnector},
7+
};
68

79
pub const CONNECTOR_NAME: &str = "blackhole";
810

911
#[async_trait]
1012
impl ToCatalogConfig for BlackHoleConnector {
1113
async fn to_catalog_config(
1214
&self,
13-
catalog_name: &str,
15+
catalog_name: &TrinoCatalogName,
1416
_catalog_namespace: &NamespaceName,
1517
_client: &Client,
1618
_trino_version: u16,
1719
) -> Result<CatalogConfig, FromTrinoCatalogError> {
1820
// No additional properties needed
19-
Ok(CatalogConfig::new(catalog_name.to_string(), CONNECTOR_NAME))
21+
Ok(CatalogConfig::new(catalog_name, CONNECTOR_NAME))
2022
}
2123
}

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ use stackable_operator::{
88
v2::types::kubernetes::NamespaceName,
99
};
1010

11-
use super::{
12-
ExtendCatalogConfig, FromTrinoCatalogError,
13-
config::CatalogConfig,
14-
from_trino_catalog_error::{
15-
ConfigureS3Snafu, FailedToGetDiscoveryConfigMapDataKeySnafu,
16-
FailedToGetDiscoveryConfigMapDataSnafu, FailedToGetDiscoveryConfigMapSnafu,
17-
S3TlsNoVerificationNotSupportedSnafu, S3TlsRequiredSnafu,
18-
},
19-
};
2011
use crate::{
12+
catalog::{
13+
ExtendCatalogConfig, FromTrinoCatalogError,
14+
config::CatalogConfig,
15+
from_trino_catalog_error::{
16+
ConfigureS3Snafu, FailedToGetDiscoveryConfigMapDataKeySnafu,
17+
FailedToGetDiscoveryConfigMapDataSnafu, FailedToGetDiscoveryConfigMapSnafu,
18+
S3TlsNoVerificationNotSupportedSnafu, S3TlsRequiredSnafu,
19+
},
20+
},
2121
config,
2222
crd::{
2323
CONFIG_DIR_NAME,
24-
catalog::commons::{HdfsConnection, MetastoreConnection},
24+
catalog::{
25+
TrinoCatalogName,
26+
commons::{HdfsConnection, MetastoreConnection},
27+
},
2528
},
2629
};
2730

@@ -30,7 +33,7 @@ impl ExtendCatalogConfig for MetastoreConnection {
3033
async fn extend_catalog_config(
3134
&self,
3235
catalog_config: &mut CatalogConfig,
33-
catalog_name: &str,
36+
catalog_name: &TrinoCatalogName,
3437
catalog_namespace: &NamespaceName,
3538
client: &Client,
3639
_trino_version: u16,
@@ -72,7 +75,7 @@ impl ExtendCatalogConfig for s3::v1alpha1::InlineConnectionOrReference {
7275
async fn extend_catalog_config(
7376
&self,
7477
catalog_config: &mut CatalogConfig,
75-
_catalog_name: &str,
78+
_catalog_name: &TrinoCatalogName,
7679
catalog_namespace: &NamespaceName,
7780
client: &Client,
7881
_trino_version: u16,
@@ -117,7 +120,7 @@ impl ExtendCatalogConfig for HdfsConnection {
117120
async fn extend_catalog_config(
118121
&self,
119122
catalog_config: &mut CatalogConfig,
120-
catalog_name: &str,
123+
catalog_name: &TrinoCatalogName,
121124
_catalog_namespace: &NamespaceName,
122125
_client: &Client,
123126
_trino_version: u16,

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

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ use stackable_operator::{
55
k8s_openapi::api::core::v1::{
66
ConfigMapKeySelector, EnvVar, EnvVarSource, SecretKeySelector, Volume, VolumeMount,
77
},
8-
kube::Resource,
98
v2::types::kubernetes::NamespaceName,
109
};
1110

12-
use super::{FromTrinoCatalogError, ToCatalogConfig};
13-
use crate::crd::catalog::{TrinoCatalogConnector, v1alpha1};
11+
use crate::{
12+
catalog::{FromTrinoCatalogError, ToCatalogConfig},
13+
crd::catalog::{TrinoCatalogConnector, TrinoCatalogName, v1alpha1},
14+
};
1415

1516
#[derive(Clone, Debug)]
1617
pub struct CatalogConfig {
1718
/// Name of the catalog
18-
pub name: String,
19+
pub name: TrinoCatalogName,
1920

2021
/// Properties of the catalog
2122
pub properties: BTreeMap<String, String>,
@@ -39,9 +40,9 @@ pub struct CatalogConfig {
3940
}
4041

4142
impl CatalogConfig {
42-
pub fn new(name: impl Into<String>, connector_name: impl Into<String>) -> Self {
43+
pub fn new(name: &TrinoCatalogName, connector_name: impl Into<String>) -> Self {
4344
let mut config = CatalogConfig {
44-
name: name.into(),
45+
name: name.clone(),
4546
properties: BTreeMap::new(),
4647
env_bindings: Vec::new(),
4748
load_env_from_files: BTreeMap::new(),
@@ -105,17 +106,12 @@ impl CatalogConfig {
105106
}
106107

107108
pub async fn from_catalog(
109+
catalog_name: &TrinoCatalogName,
108110
catalog: &v1alpha1::TrinoCatalog,
109111
client: &Client,
110112
catalog_namespace: &NamespaceName,
111113
trino_version: u16,
112114
) -> Result<CatalogConfig, FromTrinoCatalogError> {
113-
let catalog_name = catalog
114-
.meta()
115-
.name
116-
.clone()
117-
.ok_or(FromTrinoCatalogError::InvalidCatalogSpec)?;
118-
119115
let to_catalog_config: &dyn ToCatalogConfig = match &catalog.spec.connector {
120116
TrinoCatalogConnector::BlackHole(black_hole_connector) => black_hole_connector,
121117
TrinoCatalogConnector::DeltaLake(delta_lake_connector) => delta_lake_connector,
@@ -128,7 +124,7 @@ impl CatalogConfig {
128124
TrinoCatalogConnector::Tpch(tpch_connector) => tpch_connector,
129125
};
130126
let mut catalog_config = to_catalog_config
131-
.to_catalog_config(&catalog_name, catalog_namespace, client, trino_version)
127+
.to_catalog_config(catalog_name, catalog_namespace, client, trino_version)
132128
.await?;
133129

134130
catalog_config
@@ -138,7 +134,7 @@ impl CatalogConfig {
138134
for removal in &catalog.spec.config_removals {
139135
if catalog_config.properties.remove(removal).is_none() {
140136
tracing::warn!(
141-
catalog.name = catalog_name,
137+
catalog.name = %catalog_name,
142138
property = removal,
143139
"You asked to remove a non-existing config property from a catalog"
144140
);
@@ -149,8 +145,8 @@ impl CatalogConfig {
149145
}
150146
}
151147

152-
fn calculate_env_name(catalog: impl Into<String>, property: impl Into<String>) -> String {
153-
let catalog = catalog.into().replace(['.', '-'], "_");
148+
fn calculate_env_name(catalog_name: &TrinoCatalogName, property: impl Into<String>) -> String {
149+
let catalog = catalog_name.to_string().replace(['.', '-'], "_");
154150
let property = property.into().replace(['.', '-'], "_");
155151
format!("CATALOG_{catalog}_{property}").to_uppercase()
156152
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

4-
use super::{ExtendCatalogConfig, FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::delta_lake::DeltaLakeConnector;
4+
use crate::{
5+
catalog::{ExtendCatalogConfig, FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig},
6+
crd::catalog::{TrinoCatalogName, delta_lake::DeltaLakeConnector},
7+
};
68

79
pub const CONNECTOR_NAME: &str = "delta_lake";
810

911
#[async_trait]
1012
impl ToCatalogConfig for DeltaLakeConnector {
1113
async fn to_catalog_config(
1214
&self,
13-
catalog_name: &str,
15+
catalog_name: &TrinoCatalogName,
1416
catalog_namespace: &NamespaceName,
1517
client: &Client,
1618
trino_version: u16,
1719
) -> Result<CatalogConfig, FromTrinoCatalogError> {
18-
let mut config = CatalogConfig::new(catalog_name.to_string(), CONNECTOR_NAME);
20+
let mut config = CatalogConfig::new(catalog_name, CONNECTOR_NAME);
1921

2022
// No authorization checks are enforced at the catalog level.
2123
// We don't want the delta connector to prevent users from dropping tables.

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

4-
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::generic::{GenericConnector, Property};
4+
use crate::{
5+
catalog::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig},
6+
crd::catalog::{
7+
TrinoCatalogName,
8+
generic::{GenericConnector, Property},
9+
},
10+
};
611

712
#[async_trait]
813
impl ToCatalogConfig for GenericConnector {
914
async fn to_catalog_config(
1015
&self,
11-
catalog_name: &str,
16+
catalog_name: &TrinoCatalogName,
1217
_catalog_namespace: &NamespaceName,
1318
_client: &Client,
1419
_trino_version: u16,
1520
) -> Result<CatalogConfig, FromTrinoCatalogError> {
1621
let connector_name = &self.connector_name;
17-
let mut config = CatalogConfig::new(catalog_name.to_string(), connector_name);
22+
let mut config = CatalogConfig::new(catalog_name, connector_name);
1823

1924
for (property_name, property) in &self.properties {
2025
match property {

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,30 @@ use stackable_operator::{
55
v2::types::kubernetes::NamespaceName,
66
};
77

8-
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
9-
use crate::crd::{CONFIG_DIR_NAME, catalog::google_sheet::GoogleSheetConnector};
8+
use crate::{
9+
catalog::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig},
10+
crd::{
11+
CONFIG_DIR_NAME,
12+
catalog::{TrinoCatalogName, google_sheet::GoogleSheetConnector},
13+
},
14+
};
1015

1116
pub const CONNECTOR_NAME: &str = "gsheets";
1217

1318
#[async_trait]
1419
impl ToCatalogConfig for GoogleSheetConnector {
1520
async fn to_catalog_config(
1621
&self,
17-
catalog_name: &str,
22+
catalog_name: &TrinoCatalogName,
1823
_catalog_namespace: &NamespaceName,
1924
_client: &Client,
2025
_trino_version: u16,
2126
) -> Result<CatalogConfig, FromTrinoCatalogError> {
22-
let mut config = CatalogConfig::new(catalog_name.to_string(), CONNECTOR_NAME);
27+
let mut config = CatalogConfig::new(catalog_name, CONNECTOR_NAME);
2328

24-
let volume_name = format!("{catalog_name}-google-sheets-credentials");
29+
let volume_name = format!("{catalog_name}-sheets-credentials");
2530
let google_sheets_credentials_dir =
26-
format!("{CONFIG_DIR_NAME}/catalog/{catalog_name}/google-sheets-credentials/");
31+
format!("{CONFIG_DIR_NAME}/catalog/{catalog_name}/sheets-credentials/");
2732

2833
config.volumes.push(
2934
VolumeBuilder::new(&volume_name)

0 commit comments

Comments
 (0)