Skip to content

Commit e306fc1

Browse files
committed
feat: Allow tweaking catalog name in Trino
1 parent 34e9783 commit e306fc1

22 files changed

Lines changed: 244 additions & 72 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: 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
@@ -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 their can only be one TrinoCatalog with a
4244+
given name.
4245+
properties:
4246+
replaceHyphensWithUnderscores:
4247+
default: false
4248+
description: |-
4249+
Wether 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, but not for `_`. This mechanism
4253+
allows you to use valid Kubernetes names, but keeps the convenience of `_` in catalog
4254+
names.
4255+
type: boolean
4256+
type: object
4257+
type: object
42304258
required:
42314259
- connector
42324260
type: object

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@ use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

44
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::black_hole::BlackHoleConnector;
5+
use crate::{
6+
controller::dereference::TrinoCatalogName, crd::catalog::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: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use super::{
1919
};
2020
use crate::{
2121
config,
22+
controller::dereference::TrinoCatalogName,
2223
crd::{
2324
CONFIG_DIR_NAME,
2425
catalog::commons::{HdfsConnection, MetastoreConnection},
@@ -30,7 +31,7 @@ impl ExtendCatalogConfig for MetastoreConnection {
3031
async fn extend_catalog_config(
3132
&self,
3233
catalog_config: &mut CatalogConfig,
33-
catalog_name: &str,
34+
catalog_name: &TrinoCatalogName,
3435
catalog_namespace: &NamespaceName,
3536
client: &Client,
3637
_trino_version: u16,
@@ -72,7 +73,7 @@ impl ExtendCatalogConfig for s3::v1alpha1::InlineConnectionOrReference {
7273
async fn extend_catalog_config(
7374
&self,
7475
catalog_config: &mut CatalogConfig,
75-
_catalog_name: &str,
76+
_catalog_name: &TrinoCatalogName,
7677
catalog_namespace: &NamespaceName,
7778
client: &Client,
7879
_trino_version: u16,
@@ -117,15 +118,15 @@ impl ExtendCatalogConfig for HdfsConnection {
117118
async fn extend_catalog_config(
118119
&self,
119120
catalog_config: &mut CatalogConfig,
120-
catalog_name: &str,
121+
catalog_name: &TrinoCatalogName,
121122
_catalog_namespace: &NamespaceName,
122123
_client: &Client,
123124
_trino_version: u16,
124125
) -> Result<(), FromTrinoCatalogError> {
125126
// Since Trino 458, fs.hadoop.enabled defaults to false.
126127
catalog_config.add_property("fs.hadoop.enabled", "true");
127128

128-
let hdfs_site_dir = format!("{CONFIG_DIR_NAME}/catalog/{catalog_name}/hdfs-config");
129+
let hdfs_site_dir = format!("{CONFIG_DIR_NAME}/catalog/{catalog_name}/hdfs-config",);
129130
catalog_config.add_property(
130131
"hive.config.resources",
131132
format!("{hdfs_site_dir}/core-site.xml,{hdfs_site_dir}/hdfs-site.xml"),

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ 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

1211
use super::{FromTrinoCatalogError, ToCatalogConfig};
13-
use crate::crd::catalog::{TrinoCatalogConnector, v1alpha1};
12+
use crate::{
13+
controller::dereference::TrinoCatalogName,
14+
crd::catalog::{TrinoCatalogConnector, v1alpha1},
15+
};
1416

1517
#[derive(Clone, Debug)]
1618
pub struct CatalogConfig {
1719
/// Name of the catalog
18-
pub name: String,
20+
pub name: TrinoCatalogName,
1921

2022
/// Properties of the catalog
2123
pub properties: BTreeMap<String, String>,
@@ -39,9 +41,9 @@ pub struct CatalogConfig {
3941
}
4042

4143
impl CatalogConfig {
42-
pub fn new(name: impl Into<String>, connector_name: impl Into<String>) -> Self {
44+
pub fn new(name: &TrinoCatalogName, connector_name: impl Into<String>) -> Self {
4345
let mut config = CatalogConfig {
44-
name: name.into(),
46+
name: name.clone(),
4547
properties: BTreeMap::new(),
4648
env_bindings: Vec::new(),
4749
load_env_from_files: BTreeMap::new(),
@@ -105,17 +107,12 @@ impl CatalogConfig {
105107
}
106108

107109
pub async fn from_catalog(
110+
catalog_name: &TrinoCatalogName,
108111
catalog: &v1alpha1::TrinoCatalog,
109112
client: &Client,
110113
catalog_namespace: &NamespaceName,
111114
trino_version: u16,
112115
) -> Result<CatalogConfig, FromTrinoCatalogError> {
113-
let catalog_name = catalog
114-
.meta()
115-
.name
116-
.clone()
117-
.ok_or(FromTrinoCatalogError::InvalidCatalogSpec)?;
118-
119116
let to_catalog_config: &dyn ToCatalogConfig = match &catalog.spec.connector {
120117
TrinoCatalogConnector::BlackHole(black_hole_connector) => black_hole_connector,
121118
TrinoCatalogConnector::DeltaLake(delta_lake_connector) => delta_lake_connector,
@@ -128,7 +125,7 @@ impl CatalogConfig {
128125
TrinoCatalogConnector::Tpch(tpch_connector) => tpch_connector,
129126
};
130127
let mut catalog_config = to_catalog_config
131-
.to_catalog_config(&catalog_name, catalog_namespace, client, trino_version)
128+
.to_catalog_config(catalog_name, catalog_namespace, client, trino_version)
132129
.await?;
133130

134131
catalog_config
@@ -138,7 +135,7 @@ impl CatalogConfig {
138135
for removal in &catalog.spec.config_removals {
139136
if catalog_config.properties.remove(removal).is_none() {
140137
tracing::warn!(
141-
catalog.name = catalog_name,
138+
catalog.name = %catalog_name,
142139
property = removal,
143140
"You asked to remove a non-existing config property from a catalog"
144141
);
@@ -149,8 +146,8 @@ impl CatalogConfig {
149146
}
150147
}
151148

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

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@ use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

44
use super::{ExtendCatalogConfig, FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::delta_lake::DeltaLakeConnector;
5+
use crate::{
6+
controller::dereference::TrinoCatalogName, crd::catalog::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: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ use async_trait::async_trait;
22
use stackable_operator::{client::Client, v2::types::kubernetes::NamespaceName};
33

44
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::generic::{GenericConnector, Property};
5+
use crate::{
6+
controller::dereference::TrinoCatalogName,
7+
crd::catalog::generic::{GenericConnector, Property},
8+
};
69

710
#[async_trait]
811
impl ToCatalogConfig for GenericConnector {
912
async fn to_catalog_config(
1013
&self,
11-
catalog_name: &str,
14+
catalog_name: &TrinoCatalogName,
1215
_catalog_namespace: &NamespaceName,
1316
_client: &Client,
1417
_trino_version: u16,
1518
) -> Result<CatalogConfig, FromTrinoCatalogError> {
1619
let connector_name = &self.connector_name;
17-
let mut config = CatalogConfig::new(catalog_name.to_string(), connector_name);
20+
let mut config = CatalogConfig::new(catalog_name, connector_name);
1821

1922
for (property_name, property) in &self.properties {
2023
match property {

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@ use stackable_operator::{
66
};
77

88
use super::{FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
9-
use crate::crd::{CONFIG_DIR_NAME, catalog::google_sheet::GoogleSheetConnector};
9+
use crate::{
10+
controller::dereference::TrinoCatalogName,
11+
crd::{CONFIG_DIR_NAME, catalog::google_sheet::GoogleSheetConnector},
12+
};
1013

1114
pub const CONNECTOR_NAME: &str = "gsheets";
1215

1316
#[async_trait]
1417
impl ToCatalogConfig for GoogleSheetConnector {
1518
async fn to_catalog_config(
1619
&self,
17-
catalog_name: &str,
20+
catalog_name: &TrinoCatalogName,
1821
_catalog_namespace: &NamespaceName,
1922
_client: &Client,
2023
_trino_version: u16,
2124
) -> Result<CatalogConfig, FromTrinoCatalogError> {
22-
let mut config = CatalogConfig::new(catalog_name.to_string(), CONNECTOR_NAME);
25+
let mut config = CatalogConfig::new(catalog_name, CONNECTOR_NAME);
2326

2427
let volume_name = format!("{catalog_name}-google-sheets-credentials");
2528
let google_sheets_credentials_dir =

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

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

44
use super::{ExtendCatalogConfig, FromTrinoCatalogError, ToCatalogConfig, config::CatalogConfig};
5-
use crate::crd::catalog::hive::HiveConnector;
5+
use crate::{controller::dereference::TrinoCatalogName, crd::catalog::hive::HiveConnector};
66

77
pub const CONNECTOR_NAME: &str = "hive";
88

99
#[async_trait]
1010
impl ToCatalogConfig for HiveConnector {
1111
async fn to_catalog_config(
1212
&self,
13-
catalog_name: &str,
13+
catalog_name: &TrinoCatalogName,
1414
catalog_namespace: &NamespaceName,
1515
client: &Client,
1616
trino_version: u16,
1717
) -> Result<CatalogConfig, FromTrinoCatalogError> {
18-
let mut config = CatalogConfig::new(catalog_name.to_string(), CONNECTOR_NAME);
18+
let mut config = CatalogConfig::new(catalog_name, CONNECTOR_NAME);
1919

2020
// No authorization checks are enforced at the catalog level.
2121
// We don't want the hive connector to prevent users from dropping tables.

0 commit comments

Comments
 (0)