odctl 0.4.4__tar.gz → 0.4.6__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.4.4 → odctl-0.4.6}/PKG-INFO +2 -2
- {odctl-0.4.4 → odctl-0.4.6}/pyproject.toml +1 -1
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/main.py +39 -0
- odctl-0.4.6/src/odctl/resources/trino/catalog/clickhouse.properties +17 -0
- odctl-0.4.6/tests/test_cli_extended.py +146 -0
- odctl-0.4.4/src/odctl/resources/trino/catalog/clickhouse.properties +0 -4
- odctl-0.4.4/tests/test_cli_extended.py +0 -70
- {odctl-0.4.4 → odctl-0.4.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/renovate.json +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/scripts/smoke.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/build-deps.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/build-platform-images.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/ci.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/e2e-test.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/pipeline.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.github/workflows/publish.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.gitignore +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.pre-commit-config.yaml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/.vscode/settings.json +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/LICENSE +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/README.md +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/image/diagram.png +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/image/diagram1.drawio +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/image/diagram2.drawio +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/__init__.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/config.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/docker.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/planner.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/registry.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/config.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/init.sql +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/keeper_config.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/macros-11.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/macros-12.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/macros-21.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/macros-22.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/clickhouse/users.xml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-analytics.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-deps.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-flink.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-infra.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-kafka.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-metadata.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-mlops.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-obsv.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-orch.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-spark.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/compose-store.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/Dockerfile +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/build.gradle +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/build_connectors.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/fetch_flink_dependencies.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/fetch_spark_dependencies.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/fetch_standalone_plugins.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/deps/versions.env +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/docker/airflow/Dockerfile +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/docker/ray-mlops/Dockerfile +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/docker/spark/Dockerfile +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/flink/flink-conf.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/grafana/prometheus.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/marquez/marquez.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/mlops/serving/lightgbm_inference.py.example +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/mlops/serving/vector_search.py.example +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/postgres/01-init-databases.sh +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/prometheus/alertmanager.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/prometheus/prometheus.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/registry.yml +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/seaweed/s3.json +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/spark/log4j2.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/spark/spark-defaults.conf +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/access-control.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/catalog/iceberg.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/catalog/kafka.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/catalog/postgres.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/catalog/valkey.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/group-provider.properties +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/groups.txt +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/resources/trino/rules.json +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/ui.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/src/odctl/workspace.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/conftest.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_cli.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_compose_profiles.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_config.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_docker.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_planner.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_registry.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/tests/test_workspace.py +0 -0
- {odctl-0.4.4 → odctl-0.4.6}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: odctl
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.6
|
|
4
4
|
Summary: Orchestrator for the Open Data Stack
|
|
5
5
|
Project-URL: Homepage, https://github.com/jaehyeon-kim/odctl
|
|
6
6
|
Project-URL: Repository, https://github.com/jaehyeon-kim/odctl
|
|
@@ -305,6 +305,31 @@ def up(
|
|
|
305
305
|
ui.print_success("All requested profiles successfully started!")
|
|
306
306
|
|
|
307
307
|
|
|
308
|
+
_DEPS_FILE = "compose-deps.yml"
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _shared_deps_are_idle(torn_down: dict) -> bool:
|
|
312
|
+
"""Report whether the shared deps project is safe to remove.
|
|
313
|
+
|
|
314
|
+
The deps project owns the ``odctl`` network and the shared JAR volume, so it
|
|
315
|
+
may only go once no other profile has a container left. Containers are listed
|
|
316
|
+
including exited ones, so a stopped-but-present service still counts as in
|
|
317
|
+
use, and deps itself is excluded because its init container always exits.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
torn_down (dict): The plan just stopped, so its files are not consulted.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
bool: True when nothing outside deps remains.
|
|
324
|
+
"""
|
|
325
|
+
if _DEPS_FILE in torn_down:
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
declared = build_execution_plan(None, True, resolve_deps=False)
|
|
329
|
+
others = {file: profs for file, profs in declared.items() if file != _DEPS_FILE}
|
|
330
|
+
return not get_managed_containers(others)
|
|
331
|
+
|
|
332
|
+
|
|
308
333
|
@app.command(
|
|
309
334
|
rich_help_panel="Cluster Lifecycle",
|
|
310
335
|
epilog="""
|
|
@@ -395,6 +420,20 @@ def down(
|
|
|
395
420
|
except Exception as e:
|
|
396
421
|
ui.print_error(f"Failed to stop {file}", details=str(e))
|
|
397
422
|
raise typer.Exit(1)
|
|
423
|
+
|
|
424
|
+
# `--all` already carries deps in its plan. A named teardown does not, so
|
|
425
|
+
# `odctl down kafka-lite -v` used to leave the init container, the odctl
|
|
426
|
+
# network and the shared JAR volume behind: a wipe that did not wipe. Remove
|
|
427
|
+
# them here, but only once nothing else is running, since every other profile
|
|
428
|
+
# attaches to that network and mounts that volume.
|
|
429
|
+
if volumes and not all and _shared_deps_are_idle(plan):
|
|
430
|
+
ui.print_info("🛑 Stopping [cyan]deps[/cyan]...")
|
|
431
|
+
try:
|
|
432
|
+
stop_stack(_DEPS_FILE, ["deps"], remove_volumes=True)
|
|
433
|
+
except Exception as e:
|
|
434
|
+
ui.print_error("Failed to stop deps", details=str(e))
|
|
435
|
+
raise typer.Exit(1)
|
|
436
|
+
|
|
398
437
|
ui.print_success("Teardown complete.")
|
|
399
438
|
|
|
400
439
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
connector.name=clickhouse
|
|
2
|
+
# compress=false is what keeps this catalog usable, not a tuning knob. The
|
|
3
|
+
# clickhouse-jdbc 0.7.1 driver shaded into Trino 480 asks for a compressed
|
|
4
|
+
# response two ways at once: the compress=1 URL parameter, which selects
|
|
5
|
+
# ClickHouse's native compressed-block framing, and an Accept-Encoding: lz4
|
|
6
|
+
# header. ClickHouse only honoured the header when enable_http_compression was
|
|
7
|
+
# turned on, and that setting now defaults to 1, so the server wraps the native
|
|
8
|
+
# blocks in an LZ4 frame and answers Content-Encoding: lz4. The driver never
|
|
9
|
+
# unwraps that frame: it reads the frame's bytes as a block header and dies with
|
|
10
|
+
# "Magic is not correct - expect [-126] but got [123]", which is 0x82 expected
|
|
11
|
+
# against the '{' it found inside the frame. Every query through the catalog
|
|
12
|
+
# fails, listing schemas included. Setting compress=false drops both the
|
|
13
|
+
# parameter and the header, so the body arrives as plain RowBinary. The response
|
|
14
|
+
# is uncompressed over the container network, which costs nothing here.
|
|
15
|
+
connection-url=jdbc:clickhouse://ch-11:8123/feature_store?compress=false
|
|
16
|
+
connection-user=user
|
|
17
|
+
connection-password=password
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from unittest.mock import MagicMock
|
|
2
|
+
from typer.testing import CliRunner
|
|
3
|
+
from odctl.main import app
|
|
4
|
+
|
|
5
|
+
runner = CliRunner()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_down_command(monkeypatch):
|
|
9
|
+
mock_stop = MagicMock()
|
|
10
|
+
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
11
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
12
|
+
|
|
13
|
+
# Mock get_managed_containers to return a fake container so down --all proceeds
|
|
14
|
+
mock_container = MagicMock()
|
|
15
|
+
mock_container.config.labels = {"com.docker.compose.service": "kafka"}
|
|
16
|
+
monkeypatch.setattr(
|
|
17
|
+
"odctl.docker.get_managed_containers", lambda x: [mock_container]
|
|
18
|
+
)
|
|
19
|
+
monkeypatch.setattr(
|
|
20
|
+
"odctl.docker.get_stack_details",
|
|
21
|
+
lambda x, y: (["kafka"], [], [], []),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
result = runner.invoke(app, ["down", "--all"])
|
|
25
|
+
assert result.exit_code == 0
|
|
26
|
+
mock_stop.assert_called()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_restart_command(monkeypatch):
|
|
30
|
+
mock_restart = MagicMock()
|
|
31
|
+
monkeypatch.setattr("odctl.main.restart_managed_containers", mock_restart)
|
|
32
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
33
|
+
|
|
34
|
+
result = runner.invoke(app, ["restart", "kafka-lite"])
|
|
35
|
+
assert result.exit_code == 0
|
|
36
|
+
mock_restart.assert_called()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_logs_command(monkeypatch):
|
|
40
|
+
mock_logs = MagicMock()
|
|
41
|
+
monkeypatch.setattr("odctl.main.get_managed_logs", mock_logs)
|
|
42
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
43
|
+
|
|
44
|
+
result = runner.invoke(app, ["logs", "kafka-lite"])
|
|
45
|
+
assert result.exit_code == 0
|
|
46
|
+
mock_logs.assert_called()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_list_command(monkeypatch):
|
|
50
|
+
result = runner.invoke(app, ["list"])
|
|
51
|
+
assert result.exit_code == 0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_explain_command(monkeypatch):
|
|
55
|
+
result = runner.invoke(app, ["explain", "kafka-lite"])
|
|
56
|
+
assert result.exit_code == 0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_docker_not_running(monkeypatch):
|
|
60
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: False)
|
|
61
|
+
result = runner.invoke(app, ["up", "kafka-lite"])
|
|
62
|
+
assert result.exit_code != 0
|
|
63
|
+
assert "Docker is not reachable" in result.stdout
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_invalid_profile(monkeypatch):
|
|
67
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
68
|
+
result = runner.invoke(app, ["up", "invalid_profile"])
|
|
69
|
+
assert result.exit_code != 0
|
|
70
|
+
assert "Unknown profile" in result.stdout
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _stopped_files(mock_stop):
|
|
74
|
+
"""The compose files a mocked stop_stack was asked to tear down, in order."""
|
|
75
|
+
return [call.args[0] for call in mock_stop.call_args_list]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_down_named_profile_with_volumes_also_removes_shared_deps(monkeypatch):
|
|
79
|
+
"""`odctl down kafka-lite -v` must not leave the deps init container, the
|
|
80
|
+
odctl network and the shared JAR volume behind."""
|
|
81
|
+
mock_stop = MagicMock()
|
|
82
|
+
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
83
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
84
|
+
# Nothing else is left running, so deps is safe to remove.
|
|
85
|
+
monkeypatch.setattr("odctl.main.get_managed_containers", lambda plan: [])
|
|
86
|
+
|
|
87
|
+
result = runner.invoke(app, ["down", "kafka-lite", "-v"])
|
|
88
|
+
|
|
89
|
+
assert result.exit_code == 0
|
|
90
|
+
files = _stopped_files(mock_stop)
|
|
91
|
+
assert "compose-deps.yml" in files, files
|
|
92
|
+
deps_call = mock_stop.call_args_list[-1]
|
|
93
|
+
assert deps_call.args[0] == "compose-deps.yml"
|
|
94
|
+
assert deps_call.args[1] == ["deps"]
|
|
95
|
+
assert deps_call.kwargs["remove_volumes"] is True
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_down_named_profile_keeps_shared_deps_while_others_run(monkeypatch):
|
|
99
|
+
"""Another profile still holding containers needs the network and the volume,
|
|
100
|
+
so deps must survive."""
|
|
101
|
+
mock_stop = MagicMock()
|
|
102
|
+
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
103
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
104
|
+
monkeypatch.setattr("odctl.main.get_managed_containers", lambda plan: [MagicMock()])
|
|
105
|
+
|
|
106
|
+
result = runner.invoke(app, ["down", "kafka-lite", "-v"])
|
|
107
|
+
|
|
108
|
+
assert result.exit_code == 0
|
|
109
|
+
assert "compose-deps.yml" not in _stopped_files(mock_stop)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_down_named_profile_without_volumes_keeps_shared_deps(monkeypatch):
|
|
113
|
+
"""Without -v the data is meant to survive, and so is the shared volume."""
|
|
114
|
+
mock_stop = MagicMock()
|
|
115
|
+
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
116
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
117
|
+
monkeypatch.setattr("odctl.main.get_managed_containers", lambda plan: [])
|
|
118
|
+
|
|
119
|
+
result = runner.invoke(app, ["down", "kafka-lite"])
|
|
120
|
+
|
|
121
|
+
assert result.exit_code == 0
|
|
122
|
+
assert "compose-deps.yml" not in _stopped_files(mock_stop)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_down_all_with_volumes_removes_deps_exactly_once(monkeypatch):
|
|
126
|
+
"""`--all` already carries deps in its plan, so the idle check must not add a
|
|
127
|
+
second teardown of the same project."""
|
|
128
|
+
mock_stop = MagicMock()
|
|
129
|
+
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
130
|
+
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
131
|
+
monkeypatch.setattr("odctl.main.typer.confirm", lambda *a, **k: True)
|
|
132
|
+
|
|
133
|
+
mock_container = MagicMock()
|
|
134
|
+
mock_container.config.labels = {"com.docker.compose.service": "init-deps"}
|
|
135
|
+
monkeypatch.setattr(
|
|
136
|
+
"odctl.docker.get_managed_containers", lambda plan: [mock_container]
|
|
137
|
+
)
|
|
138
|
+
monkeypatch.setattr(
|
|
139
|
+
"odctl.docker.get_stack_details",
|
|
140
|
+
lambda f, p: (["init-deps"], [], [], ["odctl-shared-deps"]),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
result = runner.invoke(app, ["down", "--all", "-v"])
|
|
144
|
+
|
|
145
|
+
assert result.exit_code == 0
|
|
146
|
+
assert _stopped_files(mock_stop).count("compose-deps.yml") == 1
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
from unittest.mock import MagicMock
|
|
2
|
-
from typer.testing import CliRunner
|
|
3
|
-
from odctl.main import app
|
|
4
|
-
|
|
5
|
-
runner = CliRunner()
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_down_command(monkeypatch):
|
|
9
|
-
mock_stop = MagicMock()
|
|
10
|
-
monkeypatch.setattr("odctl.main.stop_stack", mock_stop)
|
|
11
|
-
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
12
|
-
|
|
13
|
-
# Mock get_managed_containers to return a fake container so down --all proceeds
|
|
14
|
-
mock_container = MagicMock()
|
|
15
|
-
mock_container.config.labels = {"com.docker.compose.service": "kafka"}
|
|
16
|
-
monkeypatch.setattr(
|
|
17
|
-
"odctl.docker.get_managed_containers", lambda x: [mock_container]
|
|
18
|
-
)
|
|
19
|
-
monkeypatch.setattr(
|
|
20
|
-
"odctl.docker.get_stack_details",
|
|
21
|
-
lambda x, y: (["kafka"], [], [], []),
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
result = runner.invoke(app, ["down", "--all"])
|
|
25
|
-
assert result.exit_code == 0
|
|
26
|
-
mock_stop.assert_called()
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def test_restart_command(monkeypatch):
|
|
30
|
-
mock_restart = MagicMock()
|
|
31
|
-
monkeypatch.setattr("odctl.main.restart_managed_containers", mock_restart)
|
|
32
|
-
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
33
|
-
|
|
34
|
-
result = runner.invoke(app, ["restart", "kafka-lite"])
|
|
35
|
-
assert result.exit_code == 0
|
|
36
|
-
mock_restart.assert_called()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def test_logs_command(monkeypatch):
|
|
40
|
-
mock_logs = MagicMock()
|
|
41
|
-
monkeypatch.setattr("odctl.main.get_managed_logs", mock_logs)
|
|
42
|
-
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
43
|
-
|
|
44
|
-
result = runner.invoke(app, ["logs", "kafka-lite"])
|
|
45
|
-
assert result.exit_code == 0
|
|
46
|
-
mock_logs.assert_called()
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def test_list_command(monkeypatch):
|
|
50
|
-
result = runner.invoke(app, ["list"])
|
|
51
|
-
assert result.exit_code == 0
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_explain_command(monkeypatch):
|
|
55
|
-
result = runner.invoke(app, ["explain", "kafka-lite"])
|
|
56
|
-
assert result.exit_code == 0
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def test_docker_not_running(monkeypatch):
|
|
60
|
-
monkeypatch.setattr("odctl.main.is_docker_running", lambda: False)
|
|
61
|
-
result = runner.invoke(app, ["up", "kafka-lite"])
|
|
62
|
-
assert result.exit_code != 0
|
|
63
|
-
assert "Docker is not reachable" in result.stdout
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_invalid_profile(monkeypatch):
|
|
67
|
-
monkeypatch.setattr("odctl.main.is_docker_running", lambda: True)
|
|
68
|
-
result = runner.invoke(app, ["up", "invalid_profile"])
|
|
69
|
-
assert result.exit_code != 0
|
|
70
|
-
assert "Unknown profile" in result.stdout
|
|
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
|
|
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
|