docker-stack 2.0.4__tar.gz → 2.0.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.
- {docker_stack-2.0.4 → docker_stack-2.0.6}/PKG-INFO +1 -1
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/cli.py +12 -5
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/PKG-INFO +1 -1
- {docker_stack-2.0.4 → docker_stack-2.0.6}/setup.py +1 -1
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_docker_stack.py +31 -4
- {docker_stack-2.0.4 → docker_stack-2.0.6}/README.md +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/__init__.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/command_runner.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/compose.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/docker_objects.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/envsubst.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/envsubst_merge.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/helpers.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/login.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/manager_api.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/markers.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/merge_conf.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/registry.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack/url_parser.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/SOURCES.txt +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/dependency_links.txt +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/entry_points.txt +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/requires.txt +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/docker_stack.egg-info/top_level.txt +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/pyproject.toml +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/setup.cfg +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_docker_objects.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_load_env.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_login.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_manager_api.py +0 -0
- {docker_stack-2.0.4 → docker_stack-2.0.6}/tests/test_node_ls.py +0 -0
|
@@ -329,12 +329,13 @@ class DockerStack:
|
|
|
329
329
|
docker_object_name = docker_object_name_for(name, explicit_name=explicit_name)
|
|
330
330
|
|
|
331
331
|
if manager_client and stack:
|
|
332
|
+
manager_object_name = explicit_name or name
|
|
332
333
|
label_map = normalize_labels(labels)
|
|
333
334
|
if manager.object_type == "config":
|
|
334
335
|
response = manager_client.resolve_config(
|
|
335
336
|
stack=stack,
|
|
336
337
|
namespace=namespace,
|
|
337
|
-
name=
|
|
338
|
+
name=manager_object_name,
|
|
338
339
|
content=data,
|
|
339
340
|
labels=label_map,
|
|
340
341
|
)
|
|
@@ -342,7 +343,7 @@ class DockerStack:
|
|
|
342
343
|
response = manager_client.resolve_secret(
|
|
343
344
|
stack=stack,
|
|
344
345
|
namespace=namespace,
|
|
345
|
-
name=
|
|
346
|
+
name=manager_object_name,
|
|
346
347
|
content=None if is_generated_secret else data,
|
|
347
348
|
generate=generate_options if is_generated_secret else None,
|
|
348
349
|
labels=label_map,
|
|
@@ -432,6 +433,12 @@ class DockerStack:
|
|
|
432
433
|
@staticmethod
|
|
433
434
|
def _version_sort_key(raw: str):
|
|
434
435
|
return int(raw) if raw.isdigit() else raw
|
|
436
|
+
@staticmethod
|
|
437
|
+
def _display_stack_name(raw: str) -> str:
|
|
438
|
+
value = raw.strip()
|
|
439
|
+
if value.startswith("default--"):
|
|
440
|
+
return value[len("default--"):]
|
|
441
|
+
return value
|
|
435
442
|
|
|
436
443
|
def _print_stack_listing(self, stack_versions: Dict[str, List[str]]) -> None:
|
|
437
444
|
max_stack_name_length = max(len(stack) for stack in stack_versions) if stack_versions else 10
|
|
@@ -461,7 +468,7 @@ class DockerStack:
|
|
|
461
468
|
try:
|
|
462
469
|
payload = client.list_stacks()
|
|
463
470
|
stack_versions = {
|
|
464
|
-
str(item.get("stack")): [
|
|
471
|
+
self._display_stack_name(str(item.get("stack"))): [
|
|
465
472
|
str(version)
|
|
466
473
|
for version in (
|
|
467
474
|
item.get("versions")
|
|
@@ -487,7 +494,7 @@ class DockerStack:
|
|
|
487
494
|
parts = line.split("\t")
|
|
488
495
|
if len(parts) == 3 and "mesudip.stack.name" in parts[2]:
|
|
489
496
|
labels = {k: v for k, v in (label.split("=") for label in parts[2].split(",") if "=" in label)}
|
|
490
|
-
stack_name = labels.get("mesudip.stack.name")
|
|
497
|
+
stack_name = self._display_stack_name(labels.get("mesudip.stack.name", "")) or None
|
|
491
498
|
version = labels.get("mesudip.object.version", "unknown")
|
|
492
499
|
|
|
493
500
|
if stack_name:
|
|
@@ -558,7 +565,7 @@ class DockerStack:
|
|
|
558
565
|
parts = line.split("\t")
|
|
559
566
|
if len(parts) == 2 and "mesudip.stack.name" in parts[1]:
|
|
560
567
|
labels = {k: v for k, v in (label.split("=") for label in parts[1].split(",") if "=" in label)}
|
|
561
|
-
stack = labels.get("mesudip.stack.name")
|
|
568
|
+
stack = self._display_stack_name(labels.get("mesudip.stack.name", "")) or None
|
|
562
569
|
version = labels.get("mesudip.object.version", "unknown")
|
|
563
570
|
tag = labels.get("mesudip.stack.tag", "")
|
|
564
571
|
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="docker-stack",
|
|
5
|
-
version="2.0.
|
|
5
|
+
version="2.0.6",
|
|
6
6
|
description="CLI for deploying and managing Docker stacks.",
|
|
7
7
|
long_description=open("README.md").read(), # You can include a README file to describe your package
|
|
8
8
|
long_description_content_type="text/markdown",
|
|
@@ -229,7 +229,7 @@ def test_process_x_content_uses_manager_resolve_apis(monkeypatch):
|
|
|
229
229
|
{
|
|
230
230
|
"stack": "govtool",
|
|
231
231
|
"namespace": "default",
|
|
232
|
-
"name": "
|
|
232
|
+
"name": "app.conf",
|
|
233
233
|
"content": "hello",
|
|
234
234
|
"labels": {},
|
|
235
235
|
}
|
|
@@ -238,7 +238,7 @@ def test_process_x_content_uses_manager_resolve_apis(monkeypatch):
|
|
|
238
238
|
{
|
|
239
239
|
"stack": "govtool",
|
|
240
240
|
"namespace": "default",
|
|
241
|
-
"name": "
|
|
241
|
+
"name": "app-secret",
|
|
242
242
|
"content": None,
|
|
243
243
|
"generate": {
|
|
244
244
|
"length": 24,
|
|
@@ -250,8 +250,8 @@ def test_process_x_content_uses_manager_resolve_apis(monkeypatch):
|
|
|
250
250
|
"return_generated_value": True,
|
|
251
251
|
}
|
|
252
252
|
]
|
|
253
|
-
assert processed_configs == {"app.conf": {"name": "
|
|
254
|
-
assert processed_secrets == {"app-secret": {"name": "
|
|
253
|
+
assert processed_configs == {"app.conf": {"name": "app.conf_v2", "external": True}}
|
|
254
|
+
assert processed_secrets == {"app-secret": {"name": "app-secret", "external": True}}
|
|
255
255
|
assert docker.stack.generated_secrets == {"app-secret": "generated-from-manager"}
|
|
256
256
|
|
|
257
257
|
|
|
@@ -295,6 +295,33 @@ def test_rm_enqueues_stack_remove_command():
|
|
|
295
295
|
assert docker.stack.commands[-1].command == ["docker", "stack", "rm", "govtool"]
|
|
296
296
|
|
|
297
297
|
|
|
298
|
+
def test_default_namespace_stack_names_are_normalized_in_output(monkeypatch, capsys):
|
|
299
|
+
inspect_payloads = {
|
|
300
|
+
("docker", "config", "ls", "--format", "{{.ID}} {{.Name}} {{.Labels}}"):
|
|
301
|
+
"cfg1 default--team-a mesudip.stack.name=default--team-a,mesudip.object.version=1",
|
|
302
|
+
("docker", "config", "ls", "--format", "{{.Name}} {{.Labels}}"):
|
|
303
|
+
"default--team-a mesudip.stack.name=default--team-a,mesudip.object.version=1,mesudip.stack.tag=stable",
|
|
304
|
+
("docker", "config", "inspect", "team-a"):
|
|
305
|
+
json.dumps([{"Spec": {"Data": base64.b64encode(b"services:\n api:\n image: busybox\n").decode("utf-8")}}]),
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
def fake_run_cli_command(command, **kwargs):
|
|
309
|
+
key = tuple(command)
|
|
310
|
+
if key not in inspect_payloads:
|
|
311
|
+
raise AssertionError(f"Unexpected command: {command}")
|
|
312
|
+
return inspect_payloads[key]
|
|
313
|
+
|
|
314
|
+
monkeypatch.setattr("docker_stack.cli.run_cli_command", fake_run_cli_command)
|
|
315
|
+
monkeypatch.setattr("docker_stack.cli.discover_manager_client", lambda *_args, **_kwargs: None)
|
|
316
|
+
|
|
317
|
+
docker = Docker()
|
|
318
|
+
assert docker.stack.ls() == {"team-a": ["1"]}
|
|
319
|
+
assert docker.stack.versions("team-a") == [("1", "stable")]
|
|
320
|
+
output = capsys.readouterr().out
|
|
321
|
+
assert "default--team-a" not in output
|
|
322
|
+
assert "team-a" in output
|
|
323
|
+
|
|
324
|
+
|
|
298
325
|
def test_filtered_agent_outputs_still_render(monkeypatch, capsys):
|
|
299
326
|
inspect_payloads = {
|
|
300
327
|
("docker", "config", "ls", "--format", "{{.ID}}\t{{.Name}}\t{{.Labels}}"): "\n".join(
|
|
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
|