Skip to content

Commit 4960fbf

Browse files
committed
fix integration test
1 parent 6140a20 commit 4960fbf

8 files changed

Lines changed: 142 additions & 38 deletions

File tree

Cargo.nix

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crate-hashes.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/modules/trino/pages/usage-guide/openlineage.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ When configured, the operator:
1515
1616
The event listener runs on the coordinator only; workers are not affected.
1717

18+
NOTE: The Trino OpenLineage plugin only emits events for data-modifying query types (`INSERT`, `DELETE`, `MERGE`, `UPDATE`, `ALTER_TABLE_EXECUTE` and `DATA_DEFINITION`) by default; plain `SELECT` queries are filtered out. Adjust `openlineage-event-listener.trino.include-query-types` via config overrides (see below) to change this.
19+
1820
== Enabling OpenLineage
1921

2022
OpenLineage is configured through `clusterConfig.openLineage.connection`, which either inlines an OpenLineage connection or references a standalone `OpenLineageConnection` resource by name:
@@ -63,6 +65,8 @@ spec:
6365
The transport scheme is `https` when `tls.verification.server` is configured, otherwise `http`.
6466
When the connection verifies the server against a `secretClass` CA (as in the commented `tls` block above), the operator mounts that SecretClass certificate into the coordinator and adds it to the trust store, so the OpenLineage listener trusts the backend's certificate.
6567

68+
IMPORTANT: With TLS server verification, the `host` must match a Subject Alternative Name in the backend's certificate. Use the exact hostname the certificate was issued for (for an in-cluster backend, typically its full service FQDN such as `marquez.<namespace>.svc.cluster.local`), otherwise the TLS handshake fails and no events are delivered.
69+
6670
[#authentication]
6771
== Authentication
6872

rust/operator-binary/src/controller/build/properties/config_properties.rs

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use snafu::Snafu;
66
use stackable_operator::{memory::BinaryMultiple, utils::cluster_info::KubernetesClusterInfo};
77

88
use crate::{
9-
controller::{TrinoRoleGroupConfig, ValidatedCluster},
9+
controller::{TrinoRoleGroupConfig, ValidatedCluster, build::properties::ConfigFileName},
1010
crd::{
1111
Container, ENV_INTERNAL_SECRET, HTTP_PORT, HTTPS_PORT, MAX_TRINO_LOG_FILES_SIZE,
12-
STACKABLE_INTERNAL_TLS_DIR, STACKABLE_LOG_DIR, STACKABLE_SERVER_TLS_DIR,
13-
STACKABLE_TLS_STORE_PASSWORD, TrinoRole,
12+
RW_CONFIG_DIR_NAME, STACKABLE_INTERNAL_TLS_DIR, STACKABLE_LOG_DIR,
13+
STACKABLE_SERVER_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD, TrinoRole,
1414
discovery::{TrinoDiscovery, TrinoDiscoveryProtocol},
1515
},
1616
};
@@ -21,6 +21,9 @@ const HTTP_SERVER_LOG_ENABLED: &str = "http-server.log.enabled";
2121
// config.properties
2222
const COORDINATOR: &str = "coordinator";
2323
const DISCOVERY_URI: &str = "discovery.uri";
24+
// Registers event listener config files. Trino does not load `event-listener.properties` from
25+
// `--etc-dir`; the file must be listed here explicitly (see trinodb/trino `EventListenerManager`).
26+
const EVENT_LISTENER_CONFIG_FILES: &str = "event-listener.config-files";
2427
const HTTP_SERVER_HTTP_PORT: &str = "http-server.http.port";
2528
const QUERY_MAX_MEMORY: &str = "query.max-memory";
2629
const QUERY_MAX_MEMORY_PER_NODE: &str = "query.max-memory-per-node";
@@ -96,6 +99,19 @@ pub fn build(
9699
(role == TrinoRole::Coordinator).to_string(),
97100
);
98101

102+
// Register the OpenLineage event listener (coordinator only). The `event-listener.properties`
103+
// file itself is built by `event_listener_properties` and lands in the read-write config dir;
104+
// without this registration Trino would never load it (it does not scan `--etc-dir`).
105+
if role == TrinoRole::Coordinator && cluster.cluster_config.open_lineage.is_some() {
106+
props.insert(
107+
EVENT_LISTENER_CONFIG_FILES.to_string(),
108+
format!(
109+
"{RW_CONFIG_DIR_NAME}/{event_listener}",
110+
event_listener = ConfigFileName::EventListener
111+
),
112+
);
113+
}
114+
99115
// Trino's own JSON logging output.
100116
props.insert(LOG_FORMAT.to_string(), "json".to_string());
101117
props.insert(
@@ -249,9 +265,12 @@ pub fn build(
249265
#[cfg(test)]
250266
mod tests {
251267
use super::*;
252-
use crate::controller::build::properties::test_support::{
253-
MINIMAL_TRINO_YAML, file_auth_class, validated_cluster_from_yaml,
254-
validated_cluster_from_yaml_with_auth,
268+
use crate::{
269+
config::open_lineage::ResolvedOpenLineageConfig,
270+
controller::build::properties::test_support::{
271+
MINIMAL_TRINO_YAML, empty_derefs, file_auth_class, validated_cluster_from_yaml,
272+
validated_cluster_from_yaml_with_auth, validated_cluster_from_yaml_with_derefs,
273+
},
255274
};
256275

257276
const SERVER_TLS_ONLY_YAML: &str = r#"
@@ -347,6 +366,60 @@ mod tests {
347366
);
348367
}
349368

369+
fn cluster_with_open_lineage() -> ValidatedCluster {
370+
let mut derefs = empty_derefs();
371+
derefs.resolved_open_lineage_config = Some(ResolvedOpenLineageConfig {
372+
properties: BTreeMap::new(),
373+
volumes: Vec::new(),
374+
volume_mounts: Vec::new(),
375+
init_container_extra_start_commands: Vec::new(),
376+
});
377+
validated_cluster_from_yaml_with_derefs(MINIMAL_TRINO_YAML, derefs)
378+
}
379+
380+
#[test]
381+
fn coordinator_registers_openlineage_event_listener_config_file() {
382+
let cluster = cluster_with_open_lineage();
383+
let props = build(
384+
&cluster,
385+
TrinoRole::Coordinator,
386+
&rg(&cluster, &TrinoRole::Coordinator),
387+
&cluster_info(),
388+
)
389+
.unwrap();
390+
// Trino only loads the event listener when it is registered here.
391+
assert_eq!(
392+
props.get(EVENT_LISTENER_CONFIG_FILES).map(String::as_str),
393+
Some("/stackable/rwconfig/event-listener.properties")
394+
);
395+
}
396+
397+
#[test]
398+
fn worker_does_not_register_event_listener_config_file() {
399+
let cluster = cluster_with_open_lineage();
400+
let props = build(
401+
&cluster,
402+
TrinoRole::Worker,
403+
&rg(&cluster, &TrinoRole::Worker),
404+
&cluster_info(),
405+
)
406+
.unwrap();
407+
assert!(!props.contains_key(EVENT_LISTENER_CONFIG_FILES));
408+
}
409+
410+
#[test]
411+
fn no_event_listener_config_file_without_open_lineage() {
412+
let cluster = validated_cluster_from_yaml(MINIMAL_TRINO_YAML);
413+
let props = build(
414+
&cluster,
415+
TrinoRole::Coordinator,
416+
&rg(&cluster, &TrinoRole::Coordinator),
417+
&cluster_info(),
418+
)
419+
.unwrap();
420+
assert!(!props.contains_key(EVENT_LISTENER_CONFIG_FILES));
421+
}
422+
350423
#[test]
351424
fn server_tls_only_uses_server_keystore_dir_and_http_discovery() {
352425
let cluster = validated_cluster_from_yaml(SERVER_TLS_ONLY_YAML);

tests/templates/kuttl/openlineage/02_trino.yaml.j2

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ metadata:
2727
name: trino-openlineage
2828
spec:
2929
image:
30-
{% if test_scenario['values']['trino'].find(",") > 0 %}
31-
custom: "{{ test_scenario['values']['trino'].split(',')[1] }}"
32-
productVersion: "{{ test_scenario['values']['trino'].split(',')[0] }}"
30+
{% if test_scenario['values']['trino-latest'].find(",") > 0 %}
31+
custom: "{{ test_scenario['values']['trino-latest'].split(',')[1] }}"
32+
productVersion: "{{ test_scenario['values']['trino-latest'].split(',')[0] }}"
3333
{% else %}
34-
productVersion: "{{ test_scenario['values']['trino'] }}"
34+
productVersion: "{{ test_scenario['values']['trino-latest'] }}"
3535
{% endif %}
3636
pullPolicy: IfNotPresent
3737
clusterConfig:
@@ -41,7 +41,9 @@ spec:
4141
openLineage:
4242
connection:
4343
inline:
44-
host: openlineage-receiver
44+
# Use the full service FQDN: with TLS the backend's secret-operator cert only carries the
45+
# `openlineage-receiver.<ns>.svc.cluster.local` SAN, so a shorter host fails verification.
46+
host: openlineage-receiver.$NAMESPACE.svc.cluster.local
4547
port: 5000
4648
{% if test_scenario['values']['openlineage-use-tls'] == 'true' %}
4749
tls:
@@ -83,3 +85,16 @@ metadata:
8385
spec:
8486
connector:
8587
tpch: {}
88+
---
89+
# A writable target so the test can run a CREATE TABLE AS SELECT. The OpenLineage event listener
90+
# only emits for data-modifying query types (INSERT/DATA_DEFINITION/...); a plain SELECT is filtered
91+
# out by the plugin's default `include-query-types`.
92+
apiVersion: trino.stackable.tech/v1alpha1
93+
kind: TrinoCatalog
94+
metadata:
95+
name: blackhole
96+
labels:
97+
trino: trino-openlineage
98+
spec:
99+
connector:
100+
blackHole: {}

tests/templates/kuttl/openlineage/03-assert.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ kind: TestAssert
44
timeout: 300
55
commands:
66
# The coordinator ConfigMap must carry a generated event-listener.properties selecting the
7-
# OpenLineage plugin and pointing at the receiver.
7+
# OpenLineage plugin and pointing at the receiver, and config.properties must register that file
8+
# (Trino does not load it from --etc-dir otherwise).
89
- script: |
910
CM=$(kubectl get -n "$NAMESPACE" configmap trino-openlineage-coordinator-default -o yaml)
1011
echo "$CM" | grep -q "event-listener.properties"
1112
echo "$CM" | grep -q "event-listener.name=openlineage"
1213
echo "$CM" | grep -q "openlineage-event-listener.transport.url"
14+
echo "$CM" | grep -q "event-listener.config-files=/stackable/rwconfig/event-listener.properties"
1315
# Workers must NOT get an event listener configured.
1416
- script: |
1517
! kubectl get -n "$NAMESPACE" configmap trino-openlineage-worker-default -o yaml | grep -q "event-listener.properties"

tests/templates/kuttl/openlineage/04_emit_lineage.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#!/usr/bin/env python
2-
"""Run a query against Trino to make the OpenLineage event listener emit lineage events."""
2+
"""Run a data-modifying query against Trino so the OpenLineage event listener emits lineage events.
3+
4+
A plain SELECT is filtered out by the plugin's default `include-query-types`; a CREATE TABLE AS
5+
SELECT (INSERT / DATA_DEFINITION) is emitted, with `tpch.tiny.nation` as the input dataset and the
6+
blackhole table as the output dataset.
7+
"""
38

49
import argparse
510

@@ -29,9 +34,14 @@ def get_connection(coordinator):
2934

3035
conn = get_connection(args["coordinator"])
3136
cursor = conn.cursor()
32-
# Reads the built-in tpch dataset; the OpenLineage listener reports `tpch.tiny.nation` as an
33-
# input dataset in the emitted (START + COMPLETE) query events.
34-
cursor.execute("SELECT COUNT(*) FROM tpch.tiny.nation")
37+
38+
cursor.execute("CREATE SCHEMA IF NOT EXISTS blackhole.lineage_test")
39+
cursor.fetchall()
40+
cursor.execute("DROP TABLE IF EXISTS blackhole.lineage_test.nation_copy")
41+
cursor.fetchall()
42+
cursor.execute(
43+
"CREATE TABLE blackhole.lineage_test.nation_copy AS SELECT * FROM tpch.tiny.nation"
44+
)
3545
result = cursor.fetchone()
36-
assert result[0] == 25, f"unexpected tpch.tiny.nation row count: {result[0]}"
37-
print("query executed, OpenLineage events should have been emitted")
46+
assert result[0] == 25, f"unexpected CTAS row count: {result[0]}"
47+
print("CTAS executed, OpenLineage events should have been emitted")

tests/templates/kuttl/openlineage/05-assert.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ timeout: 180
99
commands:
1010
- script: |
1111
POD=$(kubectl get -n "$NAMESPACE" pod -l app=openlineage-receiver -o jsonpath='{.items[0].metadata.name}')
12-
# At least one lineage event body was persisted, referencing the queried tpch dataset ...
13-
kubectl exec -n "$NAMESPACE" "$POD" -- sh -c 'cat /tmp/lineage/* 2>/dev/null | grep -qi "nation"'
12+
# At least one lineage event body was persisted, referencing the CTAS output dataset ...
13+
kubectl exec -n "$NAMESPACE" "$POD" -- sh -c 'cat /tmp/lineage/* 2>/dev/null | grep -q "nation_copy"'
1414
# ... and a COMPLETE run event was received (the query finished and reported lineage).
1515
kubectl exec -n "$NAMESPACE" "$POD" -- sh -c 'cat /tmp/lineage/* 2>/dev/null | grep -q "COMPLETE"'

0 commit comments

Comments
 (0)