odctl 0.1.0__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {odctl-0.1.0 → odctl-0.2.0}/PKG-INFO +1 -1
- {odctl-0.1.0 → odctl-0.2.0}/pyproject.toml +1 -1
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/config.py +14 -1
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/main.py +14 -5
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/config.xml +7 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/keeper_config.xml +7 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-analytics.yml +6 -64
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-flink.yml +6 -6
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-kafka.yml +8 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-spark.yml +6 -8
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/fetch_flink_dependencies.sh +7 -1
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/fetch_spark_dependencies.sh +1 -1
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/fetch_standalone_plugins.sh +1 -1
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/docker/spark/Dockerfile +4 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/registry.yml +2 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/spark/spark-defaults.conf +6 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/trino/catalog/clickhouse.properties +1 -1
- odctl-0.2.0/src/odctl/resources/trino/catalog/kafka.properties +7 -0
- odctl-0.2.0/src/odctl/resources/trino/catalog/kafka_avro.properties +10 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/workspace.py +2 -3
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_workspace.py +0 -1
- {odctl-0.1.0 → odctl-0.2.0}/uv.lock +1 -1
- {odctl-0.1.0 → odctl-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/renovate.json +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/build-deps.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/build-platform-images.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/ci.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/e2e-test.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/pipeline.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.github/workflows/publish.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.gitignore +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.pre-commit-config.yaml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/.vscode/settings.json +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/LICENSE +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/README.md +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/image/diagram.png +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/image/diagram1.drawio +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/image/diagram2.drawio +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/__init__.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/docker.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/planner.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/registry.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/init.sql +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/macros-11.xml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/macros-12.xml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/macros-21.xml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/macros-22.xml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/clickhouse/users.xml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-deps.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-infra.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-metadata.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-mlops.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-obsv.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-orch.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/compose-store.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/Dockerfile +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/build.gradle +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/deps/build_connectors.sh +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/docker/airflow/Dockerfile +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/docker/ray-mlops/Dockerfile +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/flink/flink1-conf.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/grafana/prometheus.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/marquez/marquez.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/mlops/serving/lightgbm_inference.py.example +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/mlops/serving/vector_search.py.example +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/postgres/01-init-databases.sh +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/prometheus/alertmanager.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/prometheus/prometheus.yml +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/seaweed/s3.json +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/spark/log4j2.properties +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/trino/catalog/iceberg.properties +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/trino/catalog/postgres.properties +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/resources/trino/catalog/valkey.properties +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/src/odctl/ui.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/conftest.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_cli.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_cli_extended.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_config.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_docker.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_planner.py +0 -0
- {odctl-0.1.0 → odctl-0.2.0}/tests/test_registry.py +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
# Workspace directory requested via the global `--workspace` flag (set in main.py).
|
|
6
|
+
_workspace_override: Optional[Path] = None
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def set_workspace_override(path: Optional[Path]) -> None:
|
|
10
|
+
"""Record the workspace directory requested via the global `--workspace` flag."""
|
|
11
|
+
global _workspace_override
|
|
12
|
+
_workspace_override = path.resolve() if path is not None else None
|
|
3
13
|
|
|
4
14
|
|
|
5
15
|
def get_internal_resources_dir() -> Path:
|
|
@@ -25,8 +35,11 @@ def get_workspace_dir() -> Path:
|
|
|
25
35
|
Get the path to the local mutable workspace.
|
|
26
36
|
|
|
27
37
|
Returns:
|
|
28
|
-
Path: The
|
|
38
|
+
Path: The directory supplied via `--workspace`, or the `.odctl` directory in
|
|
39
|
+
the current working directory when no override is set.
|
|
29
40
|
"""
|
|
41
|
+
if _workspace_override is not None:
|
|
42
|
+
return _workspace_override
|
|
30
43
|
return Path.cwd() / ".odctl"
|
|
31
44
|
|
|
32
45
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
from typing import List, Optional
|
|
3
4
|
|
|
4
5
|
import typer
|
|
5
6
|
|
|
6
|
-
from odctl import ui
|
|
7
|
+
from odctl import config, ui
|
|
7
8
|
from odctl.docker import (
|
|
8
9
|
get_managed_containers,
|
|
9
10
|
get_managed_logs,
|
|
@@ -51,14 +52,20 @@ def main(
|
|
|
51
52
|
help="Enable debug-level logging across all commands.",
|
|
52
53
|
rich_help_panel="Global Options",
|
|
53
54
|
),
|
|
54
|
-
workspace: Path = typer.Option(
|
|
55
|
-
|
|
55
|
+
workspace: Optional[Path] = typer.Option(
|
|
56
|
+
None,
|
|
56
57
|
"--workspace",
|
|
57
58
|
"-w",
|
|
58
|
-
help="Path to the ODCTL workspace directory.",
|
|
59
|
+
help="Path to the ODCTL workspace directory (default: ./.odctl).",
|
|
59
60
|
rich_help_panel="Global Options",
|
|
60
61
|
),
|
|
61
62
|
):
|
|
63
|
+
logging.basicConfig(
|
|
64
|
+
level=logging.DEBUG if verbose else logging.WARNING,
|
|
65
|
+
format="%(levelname)s %(name)s: %(message)s",
|
|
66
|
+
force=True,
|
|
67
|
+
)
|
|
68
|
+
config.set_workspace_override(workspace)
|
|
62
69
|
ctx.obj = {"verbose": verbose, "workspace": workspace}
|
|
63
70
|
|
|
64
71
|
|
|
@@ -183,7 +190,9 @@ def init(
|
|
|
183
190
|
"⚠️ This will wipe out local modifications. Are you sure?", abort=True
|
|
184
191
|
)
|
|
185
192
|
init_workspace(force=force)
|
|
186
|
-
ui.print_success(
|
|
193
|
+
ui.print_success(
|
|
194
|
+
f"Workspace initialized! You can now edit any file in {get_workspace_dir()}/"
|
|
195
|
+
)
|
|
187
196
|
|
|
188
197
|
|
|
189
198
|
@app.command(
|
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
<background_pool_size>16</background_pool_size>
|
|
10
10
|
<background_schedule_pool_size>8</background_schedule_pool_size>
|
|
11
11
|
|
|
12
|
+
<!-- Docker networks hand out IPv6 addresses, and container names can resolve
|
|
13
|
+
to the AAAA record only, so listening on IPv4 alone leaves peers with
|
|
14
|
+
connection refused. :: is dual-stack and covers IPv4 too, so it comes
|
|
15
|
+
first; the 0.0.0.0 entry is a fallback for hosts without IPv6, where
|
|
16
|
+
the :: bind fails harmlessly thanks to listen_try. -->
|
|
17
|
+
<listen_try>1</listen_try>
|
|
18
|
+
<listen_host>::</listen_host>
|
|
12
19
|
<listen_host>0.0.0.0</listen_host>
|
|
13
20
|
|
|
14
21
|
<zookeeper>
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
<level>information</level>
|
|
5
5
|
<console>1</console>
|
|
6
6
|
</logger>
|
|
7
|
+
<!-- Docker networks hand out IPv6 addresses, and container names can resolve
|
|
8
|
+
to the AAAA record only, so listening on IPv4 alone leaves peers with
|
|
9
|
+
connection refused. :: is dual-stack and covers IPv4 too, so it comes
|
|
10
|
+
first; the 0.0.0.0 entry is a fallback for hosts without IPv6, where
|
|
11
|
+
the :: bind fails harmlessly thanks to listen_try. -->
|
|
12
|
+
<listen_try>1</listen_try>
|
|
13
|
+
<listen_host>::</listen_host>
|
|
7
14
|
<listen_host>0.0.0.0</listen_host>
|
|
8
15
|
<keeper_server>
|
|
9
16
|
<tcp_port>9181</tcp_port>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
name: odctl-analytics
|
|
2
2
|
|
|
3
3
|
x-clickhouse-base: &clickhouse-base
|
|
4
|
-
image: clickhouse/clickhouse-server:
|
|
4
|
+
image: clickhouse/clickhouse-server:25.8-alpine
|
|
5
5
|
networks:
|
|
6
6
|
- odctl
|
|
7
7
|
mem_limit: 4g
|
|
@@ -32,7 +32,7 @@ services:
|
|
|
32
32
|
# [SHARED] Consensus Node
|
|
33
33
|
# ==========================================
|
|
34
34
|
ch-keeper:
|
|
35
|
-
image: clickhouse/clickhouse-keeper:
|
|
35
|
+
image: clickhouse/clickhouse-keeper:25.8-alpine
|
|
36
36
|
container_name: ch-keeper
|
|
37
37
|
# Keeper must run in BOTH profiles
|
|
38
38
|
profiles:
|
|
@@ -83,6 +83,7 @@ services:
|
|
|
83
83
|
- ./clickhouse/config.xml:/etc/clickhouse-server/config.d/cluster-config.xml
|
|
84
84
|
- ./clickhouse/users.xml:/etc/clickhouse-server/users.d/custom-users.xml
|
|
85
85
|
- ./clickhouse/macros-11.xml:/etc/clickhouse-server/config.d/macros.xml
|
|
86
|
+
- ./clickhouse/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
|
86
87
|
|
|
87
88
|
ch-12:
|
|
88
89
|
<<: *clickhouse-base
|
|
@@ -95,6 +96,7 @@ services:
|
|
|
95
96
|
- ./clickhouse/config.xml:/etc/clickhouse-server/config.d/cluster-config.xml
|
|
96
97
|
- ./clickhouse/users.xml:/etc/clickhouse-server/users.d/custom-users.xml
|
|
97
98
|
- ./clickhouse/macros-12.xml:/etc/clickhouse-server/config.d/macros.xml
|
|
99
|
+
- ./clickhouse/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
|
98
100
|
|
|
99
101
|
# ==========================================
|
|
100
102
|
# Shard 2 (Active ONLY in multi profile)
|
|
@@ -110,6 +112,7 @@ services:
|
|
|
110
112
|
- ./clickhouse/config.xml:/etc/clickhouse-server/config.d/cluster-config.xml
|
|
111
113
|
- ./clickhouse/users.xml:/etc/clickhouse-server/users.d/custom-users.xml
|
|
112
114
|
- ./clickhouse/macros-21.xml:/etc/clickhouse-server/config.d/macros.xml
|
|
115
|
+
- ./clickhouse/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
|
113
116
|
|
|
114
117
|
ch-22:
|
|
115
118
|
<<: *clickhouse-base
|
|
@@ -122,68 +125,7 @@ services:
|
|
|
122
125
|
- ./clickhouse/config.xml:/etc/clickhouse-server/config.d/cluster-config.xml
|
|
123
126
|
- ./clickhouse/users.xml:/etc/clickhouse-server/users.d/custom-users.xml
|
|
124
127
|
- ./clickhouse/macros-22.xml:/etc/clickhouse-server/config.d/macros.xml
|
|
125
|
-
|
|
126
|
-
# ==========================================
|
|
127
|
-
# [INIT: ch-lite] Database Initialization
|
|
128
|
-
# ==========================================
|
|
129
|
-
ch-init-lite:
|
|
130
|
-
image: clickhouse/clickhouse-server:24.3-alpine
|
|
131
|
-
container_name: ch-init-lite
|
|
132
|
-
profiles: ["ch-lite"]
|
|
133
|
-
networks:
|
|
134
|
-
- odctl
|
|
135
|
-
depends_on:
|
|
136
|
-
ch-11:
|
|
137
|
-
condition: service_healthy
|
|
138
|
-
ch-12:
|
|
139
|
-
condition: service_healthy
|
|
140
|
-
entrypoint: >
|
|
141
|
-
/bin/sh -c "
|
|
142
|
-
echo '[ch-lite] Creating databases on Shard 1...' &&
|
|
143
|
-
clickhouse-client --host ch-11 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
144
|
-
clickhouse-client --host ch-11 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
145
|
-
clickhouse-client --host ch-12 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
146
|
-
clickhouse-client --host ch-12 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
147
|
-
echo '✅ [ch-lite] Databases created successfully!' &&
|
|
148
|
-
sleep infinity
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
# ==========================================
|
|
152
|
-
# [INIT: ch-full] Database Initialization
|
|
153
|
-
# ==========================================
|
|
154
|
-
ch-init-full:
|
|
155
|
-
image: clickhouse/clickhouse-server:24.3-alpine
|
|
156
|
-
container_name: ch-init-full
|
|
157
|
-
profiles: ["ch-full"]
|
|
158
|
-
networks:
|
|
159
|
-
- odctl
|
|
160
|
-
depends_on:
|
|
161
|
-
ch-11:
|
|
162
|
-
condition: service_healthy
|
|
163
|
-
ch-12:
|
|
164
|
-
condition: service_healthy
|
|
165
|
-
ch-21:
|
|
166
|
-
condition: service_healthy
|
|
167
|
-
ch-22:
|
|
168
|
-
condition: service_healthy
|
|
169
|
-
entrypoint: >
|
|
170
|
-
/bin/sh -c "
|
|
171
|
-
echo '[ch-full] Creating databases on Shard 1...' &&
|
|
172
|
-
clickhouse-client --host ch-11 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
173
|
-
clickhouse-client --host ch-11 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
174
|
-
clickhouse-client --host ch-12 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
175
|
-
clickhouse-client --host ch-12 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
176
|
-
|
|
177
|
-
echo '[ch-full] Creating databases on Shard 2...' &&
|
|
178
|
-
clickhouse-client --host ch-21 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
179
|
-
clickhouse-client --host ch-21 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
180
|
-
clickhouse-client --host ch-22 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS feature_store;' &&
|
|
181
|
-
clickhouse-client --host ch-22 --user default --password password --query 'CREATE DATABASE IF NOT EXISTS odctl;' &&
|
|
182
|
-
|
|
183
|
-
echo '✅ [ch-full] All databases created across the cluster!' &&
|
|
184
|
-
sleep infinity
|
|
185
|
-
"
|
|
186
|
-
|
|
128
|
+
- ./clickhouse/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
|
187
129
|
|
|
188
130
|
# ==========================================
|
|
189
131
|
# [PROFILE: trino] Federated SQL Engine
|
|
@@ -9,18 +9,18 @@ x-flink-common: &flink-common
|
|
|
9
9
|
|
|
10
10
|
x-flink1-base: &flink1-base
|
|
11
11
|
<<: *flink-common
|
|
12
|
-
image: flink:1.20.
|
|
12
|
+
image: flink:1.20.5-java17
|
|
13
13
|
environment:
|
|
14
14
|
TZ: ${TZ:-UTC}
|
|
15
15
|
entrypoint:
|
|
16
16
|
- /bin/bash
|
|
17
17
|
- -c
|
|
18
18
|
- |
|
|
19
|
-
# Load dependencies
|
|
20
|
-
|
|
21
|
-
cp /mnt/shared-deps/shared/*.jar /opt/flink/
|
|
22
|
-
cp /mnt/shared-deps/flink/1.x/*.jar /opt/flink/
|
|
23
|
-
cp /mnt/shared-deps/connect/confluent-converters/*.jar /opt/flink/
|
|
19
|
+
# Load dependencies into lib/, not usrlib/. Only lib/ reaches the system
|
|
20
|
+
# classloader, which is where SQL connector factories are looked up.
|
|
21
|
+
cp /mnt/shared-deps/shared/*.jar /opt/flink/lib/ 2>/dev/null || true
|
|
22
|
+
cp /mnt/shared-deps/flink/1.x/*.jar /opt/flink/lib/ 2>/dev/null || true
|
|
23
|
+
cp /mnt/shared-deps/connect/confluent-converters/*.jar /opt/flink/lib/ 2>/dev/null || true
|
|
24
24
|
|
|
25
25
|
# S3 Plugin Linking
|
|
26
26
|
echo "Linking S3 FileSystem Plugin..."
|
|
@@ -39,6 +39,14 @@ services:
|
|
|
39
39
|
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:19091"
|
|
40
40
|
KAFKA_NUM_PARTITIONS: "3"
|
|
41
41
|
KAFKA_DEFAULT_REPLICATION_FACTOR: "1"
|
|
42
|
+
# Internal topics default to a replication factor of 3, which a single
|
|
43
|
+
# broker can never satisfy. Without these, __consumer_offsets is never
|
|
44
|
+
# created and every consumer group waits on the coordinator forever.
|
|
45
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
|
|
46
|
+
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: "1"
|
|
47
|
+
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: "1"
|
|
48
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR: "1"
|
|
49
|
+
KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR: "1"
|
|
42
50
|
<<: *kafka_broker_common_env_vars
|
|
43
51
|
mem_limit: 1500m
|
|
44
52
|
|
|
@@ -12,6 +12,12 @@ x-spark-base: &spark-base
|
|
|
12
12
|
environment:
|
|
13
13
|
TZ: ${TZ:-UTC}
|
|
14
14
|
SPARK_DIST_CLASSPATH: "/mnt/shared-deps/shared/*:/mnt/shared-deps/spark/*"
|
|
15
|
+
# Picked up by boto3 and by any AWS SDK client that falls back to the
|
|
16
|
+
# default credential chain
|
|
17
|
+
AWS_REGION: us-east-1
|
|
18
|
+
AWS_ACCESS_KEY_ID: user
|
|
19
|
+
AWS_SECRET_ACCESS_KEY: password
|
|
20
|
+
SPARK_WORKER_MEMORY: "1500m"
|
|
15
21
|
|
|
16
22
|
services:
|
|
17
23
|
spark-master:
|
|
@@ -23,8 +29,6 @@ services:
|
|
|
23
29
|
- "9080:8080"
|
|
24
30
|
- "7077:7077"
|
|
25
31
|
mem_limit: 1g
|
|
26
|
-
environment:
|
|
27
|
-
SPARK_WORKER_MEMORY: "1500m"
|
|
28
32
|
healthcheck:
|
|
29
33
|
test: ["CMD", "curl", "-f", "http://localhost:8080"]
|
|
30
34
|
interval: 10s
|
|
@@ -39,8 +43,6 @@ services:
|
|
|
39
43
|
ports:
|
|
40
44
|
- "9081:8081"
|
|
41
45
|
mem_limit: 2g
|
|
42
|
-
environment:
|
|
43
|
-
SPARK_WORKER_MEMORY: "1500m"
|
|
44
46
|
depends_on:
|
|
45
47
|
spark-master:
|
|
46
48
|
condition: service_healthy
|
|
@@ -53,8 +55,6 @@ services:
|
|
|
53
55
|
ports:
|
|
54
56
|
- "9082:8081"
|
|
55
57
|
mem_limit: 2g
|
|
56
|
-
environment:
|
|
57
|
-
SPARK_WORKER_MEMORY: "1500m"
|
|
58
58
|
depends_on:
|
|
59
59
|
spark-master:
|
|
60
60
|
condition: service_healthy
|
|
@@ -67,8 +67,6 @@ services:
|
|
|
67
67
|
ports:
|
|
68
68
|
- "9083:8081"
|
|
69
69
|
mem_limit: 2g
|
|
70
|
-
environment:
|
|
71
|
-
SPARK_WORKER_MEMORY: "1500m"
|
|
72
70
|
depends_on:
|
|
73
71
|
spark-master:
|
|
74
72
|
condition: service_healthy
|
|
@@ -10,7 +10,7 @@ fetch_artifact() {
|
|
|
10
10
|
else echo " ⬇️ Downloading: $2"; curl -sL -f -o "$1" "$2"; fi
|
|
11
11
|
}
|
|
12
12
|
get_maven_version() {
|
|
13
|
-
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed 's
|
|
13
|
+
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed -E 's#</?version>##g' || true
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
echo "▶️ Resolving Flink Versions..."
|
|
@@ -34,6 +34,12 @@ K_V=$(get_maven_version "org/apache/flink/flink-sql-connector-kafka" "[0-9]+\.[0
|
|
|
34
34
|
if [ -z "$K_V" ]; then echo "❌ Error: Kafka connector for Flink ${FLINK_MINOR} is not published yet!"; exit 1; fi
|
|
35
35
|
fetch_artifact "flink/1.x/kafka.jar" "https://repo1.maven.org/maven2/org/apache/flink/flink-sql-connector-kafka/${K_V}/flink-sql-connector-kafka-${K_V}.jar"
|
|
36
36
|
|
|
37
|
+
# Avro with Confluent Schema Registry. This uber JAR is a superset of
|
|
38
|
+
# flink-sql-avro: it registers the plain 'avro' format factory as well as
|
|
39
|
+
# 'avro-confluent' and 'debezium-avro-confluent', so adding both would duplicate
|
|
40
|
+
# the Avro classes and register the same factory twice.
|
|
41
|
+
fetch_artifact "flink/1.x/avro-confluent-registry.jar" "https://repo1.maven.org/maven2/org/apache/flink/flink-sql-avro-confluent-registry/${FLINK_V}/flink-sql-avro-confluent-registry-${FLINK_V}.jar"
|
|
42
|
+
|
|
37
43
|
# JDBC
|
|
38
44
|
J_V=$(get_maven_version "org/apache/flink/flink-connector-jdbc" "[0-9]+\.[0-9]+\.[0-9]+-${FLINK_MINOR}")
|
|
39
45
|
if [ -z "$J_V" ]; then echo "❌ Error: JDBC connector for Flink ${FLINK_MINOR} is not published yet!"; exit 1; fi
|
|
@@ -10,7 +10,7 @@ fetch_artifact() {
|
|
|
10
10
|
else echo " ⬇️ Downloading: $2"; curl -sL -f -o "$1" "$2"; fi
|
|
11
11
|
}
|
|
12
12
|
get_maven_version() {
|
|
13
|
-
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed 's
|
|
13
|
+
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed -E 's#</?version>##g' || true
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
echo "▶️ Resolving Spark Versions..."
|
|
@@ -10,7 +10,7 @@ fetch_artifact() {
|
|
|
10
10
|
else echo " ⬇️ Downloading: $2"; curl -sL -f -o "$1" "$2"; fi
|
|
11
11
|
}
|
|
12
12
|
get_maven_version() {
|
|
13
|
-
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed 's
|
|
13
|
+
curl -sL "https://repo1.maven.org/maven2/${1}/maven-metadata.xml" | grep -Eo "<version>${2}</version>" | sort -V | tail -1 | sed -E 's#</?version>##g' || true
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
echo "▶️ Resolving Shared & Connector Versions..."
|
|
@@ -12,5 +12,9 @@ RUN --mount=type=cache,target=/root/.cache/pip \
|
|
|
12
12
|
'mlflow~=3.12.0' \
|
|
13
13
|
'boto3'
|
|
14
14
|
|
|
15
|
+
# Pre-create the event log directory owned by the spark user. A named volume
|
|
16
|
+
# mounted here inherits this ownership, so spark-submit can write its logs.
|
|
17
|
+
RUN mkdir -p /tmp/spark-events && chown 185:185 /tmp/spark-events
|
|
18
|
+
|
|
15
19
|
# Revert to the official Apache Spark non-root user ID
|
|
16
20
|
USER 185
|
|
@@ -202,6 +202,8 @@ stacks:
|
|
|
202
202
|
• Trino UI & JDBC connection (user: user, password: none):
|
|
203
203
|
* External (Localhost): http://localhost:8080
|
|
204
204
|
* Internal (Docker): http://trino:8080
|
|
205
|
+
• Catalogs: iceberg, kafka (JSON topics), kafka_avro (Avro via
|
|
206
|
+
the schema registry), clickhouse, postgres, valkey
|
|
205
207
|
metabase: |
|
|
206
208
|
• Metabase Dashboard Engine:
|
|
207
209
|
* External (Localhost): http://localhost:3000
|
|
@@ -17,6 +17,12 @@ spark.sql.catalog.iceberg.s3.endpoint http://seaweed:8333
|
|
|
17
17
|
spark.sql.catalog.iceberg.s3.path-style-access true
|
|
18
18
|
spark.sql.defaultCatalog iceberg
|
|
19
19
|
|
|
20
|
+
# SeaweedFS ignores the region, but the AWS SDK refuses to build a client
|
|
21
|
+
# without one, and the default credential chain finds nothing in a container.
|
|
22
|
+
spark.sql.catalog.iceberg.s3.access-key-id user
|
|
23
|
+
spark.sql.catalog.iceberg.s3.secret-access-key password
|
|
24
|
+
spark.sql.catalog.iceberg.client.region us-east-1
|
|
25
|
+
|
|
20
26
|
# ========================================
|
|
21
27
|
# History Server & Event Logging (Local Volume)
|
|
22
28
|
# ========================================
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
connector.name=kafka
|
|
2
|
+
kafka.nodes=broker-1:19092
|
|
3
|
+
kafka.default-schema=default
|
|
4
|
+
kafka.table-names=web_events,logs
|
|
5
|
+
# Expose _message, _key and the other underscore columns so raw JSON topics can
|
|
6
|
+
# be read without a table description file
|
|
7
|
+
kafka.hide-internal-columns=false
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
connector.name=kafka
|
|
2
|
+
kafka.nodes=broker-1:19092
|
|
3
|
+
kafka.default-schema=default
|
|
4
|
+
# Tables are discovered from the schema registry, so topics carrying Confluent
|
|
5
|
+
# Avro appear without being listed and their fields arrive typed. This supplier
|
|
6
|
+
# replaces file-based discovery rather than extending it, which is why plain JSON
|
|
7
|
+
# topics live in the separate 'kafka' catalog.
|
|
8
|
+
kafka.table-description-supplier=CONFLUENT
|
|
9
|
+
kafka.confluent-schema-registry-url=http://karapace:8081
|
|
10
|
+
kafka.hide-internal-columns=false
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import shutil
|
|
2
2
|
from importlib.metadata import PackageNotFoundError, version
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from odctl.config import INTERNAL_RESOURCES_DIR, get_workspace_dir
|
|
6
5
|
|
|
@@ -34,11 +33,11 @@ def init_workspace(force: bool = False):
|
|
|
34
33
|
# Nuke the existing workspace if force is True
|
|
35
34
|
if force and workspace.exists():
|
|
36
35
|
shutil.rmtree(workspace)
|
|
37
|
-
print(f"🗑️ Removed existing workspace at {workspace
|
|
36
|
+
print(f"🗑️ Removed existing workspace at {workspace}/")
|
|
38
37
|
|
|
39
38
|
if not workspace.exists():
|
|
40
39
|
workspace.mkdir(parents=True)
|
|
41
|
-
print(f"📁 Created workspace at {workspace
|
|
40
|
+
print(f"📁 Created workspace at {workspace}/")
|
|
42
41
|
|
|
43
42
|
# Iterate over everything in the internal resources
|
|
44
43
|
for item in INTERNAL_RESOURCES_DIR.iterdir():
|
|
@@ -10,7 +10,6 @@ def test_init_workspace(tmp_path, monkeypatch):
|
|
|
10
10
|
monkeypatch.setattr(
|
|
11
11
|
"odctl.workspace.get_workspace_dir", lambda: tmp_path / ".odctl"
|
|
12
12
|
)
|
|
13
|
-
monkeypatch.setattr("odctl.workspace.Path.cwd", lambda: tmp_path)
|
|
14
13
|
|
|
15
14
|
# Mock INTERNAL_RESOURCES_DIR to point to a temporary internal dir
|
|
16
15
|
internal_dir = tmp_path / "internal"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|