docker-stack 2__py3-none-any.whl → 2.0.2__py3-none-any.whl
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/cli.py +7 -4
- docker_stack/manager_api.py +30 -69
- {docker_stack-2.0.0.dist-info → docker_stack-2.0.2.dist-info}/METADATA +1 -1
- {docker_stack-2.0.0.dist-info → docker_stack-2.0.2.dist-info}/RECORD +7 -7
- {docker_stack-2.0.0.dist-info → docker_stack-2.0.2.dist-info}/WHEEL +0 -0
- {docker_stack-2.0.0.dist-info → docker_stack-2.0.2.dist-info}/entry_points.txt +0 -0
- {docker_stack-2.0.0.dist-info → docker_stack-2.0.2.dist-info}/top_level.txt +0 -0
docker_stack/cli.py
CHANGED
|
@@ -639,10 +639,9 @@ class DockerStack:
|
|
|
639
639
|
)
|
|
640
640
|
return
|
|
641
641
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
642
|
+
# Manager-backed deploys must stay on the manager stack APIs. Hitting
|
|
643
|
+
# direct daemon config endpoints here breaks GitHub OIDC workflows,
|
|
644
|
+
# which are intentionally restricted away from generic daemon access.
|
|
646
645
|
if manager_deploy and not with_registry_auth:
|
|
647
646
|
self.commands.append(
|
|
648
647
|
CallbackCommand(
|
|
@@ -657,6 +656,10 @@ class DockerStack:
|
|
|
657
656
|
)
|
|
658
657
|
return
|
|
659
658
|
|
|
659
|
+
_, cmd = self.docker.config.increment(stack_name, rendered_content, labels=labels, stack=stack_name)
|
|
660
|
+
if not cmd.isNop():
|
|
661
|
+
self.commands.append(cmd)
|
|
662
|
+
|
|
660
663
|
cmd = ["docker", "stack", "deploy", "-c", str(rendered_filename), stack_name]
|
|
661
664
|
if with_registry_auth:
|
|
662
665
|
cmd.insert(3, "--with-registry-auth")
|
docker_stack/manager_api.py
CHANGED
|
@@ -48,6 +48,28 @@ def _manager_target_from_env() -> Optional[str]:
|
|
|
48
48
|
return None
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
def _format_control_plane_endpoints(endpoints: Any) -> str:
|
|
52
|
+
if not isinstance(endpoints, list) or not endpoints:
|
|
53
|
+
return "none"
|
|
54
|
+
values = []
|
|
55
|
+
for item in endpoints:
|
|
56
|
+
if not isinstance(item, dict):
|
|
57
|
+
continue
|
|
58
|
+
endpoint_id = item.get("id")
|
|
59
|
+
name = str(item.get("name") or "").strip()
|
|
60
|
+
slug = str(item.get("slug") or "").strip()
|
|
61
|
+
parts = []
|
|
62
|
+
if endpoint_id is not None:
|
|
63
|
+
parts.append(f"id={endpoint_id}")
|
|
64
|
+
if name:
|
|
65
|
+
parts.append(f"name={name}")
|
|
66
|
+
if slug:
|
|
67
|
+
parts.append(f"slug={slug}")
|
|
68
|
+
if parts:
|
|
69
|
+
values.append(", ".join(parts))
|
|
70
|
+
return "; ".join(values) if values else "none"
|
|
71
|
+
|
|
72
|
+
|
|
51
73
|
class ManagerApiClient:
|
|
52
74
|
def __init__(
|
|
53
75
|
self,
|
|
@@ -134,70 +156,13 @@ class ManagerApiClient:
|
|
|
134
156
|
|
|
135
157
|
self._endpoint_id_checked = True
|
|
136
158
|
|
|
137
|
-
env_endpoint_id = os.getenv("DOCKER_MANAGER_ENDPOINT_ID", "").strip()
|
|
138
|
-
if env_endpoint_id:
|
|
139
|
-
try:
|
|
140
|
-
parsed_id = int(env_endpoint_id)
|
|
141
|
-
except ValueError as exc:
|
|
142
|
-
raise RuntimeError("DOCKER_MANAGER_ENDPOINT_ID must be a positive integer") from exc
|
|
143
|
-
if parsed_id <= 0:
|
|
144
|
-
raise RuntimeError("DOCKER_MANAGER_ENDPOINT_ID must be a positive integer")
|
|
145
|
-
self._endpoint_id = parsed_id
|
|
146
|
-
return parsed_id
|
|
147
|
-
|
|
148
159
|
payload = self._request_json("/api/endpoints")
|
|
149
160
|
endpoints = payload.get("endpoints")
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
selected = None
|
|
156
|
-
|
|
157
|
-
if endpoint_slug:
|
|
158
|
-
selected = next(
|
|
159
|
-
(
|
|
160
|
-
item
|
|
161
|
-
for item in endpoints
|
|
162
|
-
if isinstance(item, dict) and str(item.get("slug", "")).strip() == endpoint_slug
|
|
163
|
-
),
|
|
164
|
-
None,
|
|
165
|
-
)
|
|
166
|
-
if selected is None:
|
|
167
|
-
raise RuntimeError(
|
|
168
|
-
f"Could not find endpoint with slug '{endpoint_slug}'. "
|
|
169
|
-
"Set DOCKER_MANAGER_ENDPOINT_ID to select explicitly."
|
|
170
|
-
)
|
|
171
|
-
elif endpoint_name:
|
|
172
|
-
selected = next(
|
|
173
|
-
(
|
|
174
|
-
item
|
|
175
|
-
for item in endpoints
|
|
176
|
-
if isinstance(item, dict) and str(item.get("name", "")).strip() == endpoint_name
|
|
177
|
-
),
|
|
178
|
-
None,
|
|
179
|
-
)
|
|
180
|
-
if selected is None:
|
|
181
|
-
raise RuntimeError(
|
|
182
|
-
f"Could not find endpoint with name '{endpoint_name}'. "
|
|
183
|
-
"Set DOCKER_MANAGER_ENDPOINT_ID to select explicitly."
|
|
184
|
-
)
|
|
185
|
-
else:
|
|
186
|
-
selected = next((item for item in endpoints if isinstance(item, dict)), None)
|
|
187
|
-
|
|
188
|
-
if not isinstance(selected, dict):
|
|
189
|
-
raise RuntimeError("Docker-Manager endpoint payload is invalid")
|
|
190
|
-
|
|
191
|
-
try:
|
|
192
|
-
endpoint_id = int(selected.get("id"))
|
|
193
|
-
except (TypeError, ValueError) as exc:
|
|
194
|
-
raise RuntimeError("Docker-Manager endpoint payload is missing a valid id") from exc
|
|
195
|
-
|
|
196
|
-
if endpoint_id <= 0:
|
|
197
|
-
raise RuntimeError("Docker-Manager endpoint id must be positive")
|
|
198
|
-
|
|
199
|
-
self._endpoint_id = endpoint_id
|
|
200
|
-
return endpoint_id
|
|
161
|
+
raise RuntimeError(
|
|
162
|
+
"docker-stack does not support Docker-Manager control-plane targets. "
|
|
163
|
+
"Point DOCKER_MANAGER_URL at a direct manager stack API instead. "
|
|
164
|
+
f"Visible endpoints: {_format_control_plane_endpoints(endpoints)}"
|
|
165
|
+
)
|
|
201
166
|
|
|
202
167
|
def _endpoint_path(self, suffix: str) -> str:
|
|
203
168
|
normalized = suffix if suffix.startswith("/") else f"/{suffix}"
|
|
@@ -208,13 +173,9 @@ class ManagerApiClient:
|
|
|
208
173
|
features = self.detect_features()
|
|
209
174
|
if feature_name not in features:
|
|
210
175
|
return False
|
|
211
|
-
if feature_name
|
|
176
|
+
if feature_name == FEATURE_STACK_DEPLOY:
|
|
212
177
|
if not self._detect_manager_backend():
|
|
213
178
|
return False
|
|
214
|
-
try:
|
|
215
|
-
self._resolve_endpoint_id()
|
|
216
|
-
except RuntimeError:
|
|
217
|
-
return False
|
|
218
179
|
return True
|
|
219
180
|
|
|
220
181
|
def list_stacks(self) -> Dict[str, Any]:
|
|
@@ -300,7 +261,7 @@ class ManagerApiClient:
|
|
|
300
261
|
if options:
|
|
301
262
|
payload["options"] = options
|
|
302
263
|
return self._request_json(
|
|
303
|
-
|
|
264
|
+
"/api/stacks/validate",
|
|
304
265
|
method="POST",
|
|
305
266
|
payload=payload,
|
|
306
267
|
)
|
|
@@ -317,7 +278,7 @@ class ManagerApiClient:
|
|
|
317
278
|
if options:
|
|
318
279
|
payload["options"] = options
|
|
319
280
|
return self._request_json(
|
|
320
|
-
|
|
281
|
+
"/api/stacks/deploy",
|
|
321
282
|
method="POST",
|
|
322
283
|
payload=payload,
|
|
323
284
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
docker_stack/__init__.py,sha256=22W2926fX4sMA1POE1EligVb05cbmP8I6rnacEUmaFs,879
|
|
2
|
-
docker_stack/cli.py,sha256=
|
|
2
|
+
docker_stack/cli.py,sha256=fsjXjaGFBXi-uYtAm5jcYSPg-yafaVsENsjKK9o_55g,50570
|
|
3
3
|
docker_stack/command_runner.py,sha256=mNaUAVKtrJbji_5ARVPLKhc92avqllNKrVQj1A6S0dA,1252
|
|
4
4
|
docker_stack/compose.py,sha256=_fAVesjyW5ecid46sYYhcu02yF1vqknDSCFYflJPDOE,534
|
|
5
5
|
docker_stack/docker_objects.py,sha256=6FYi3Cq5qTkz2XgRrb_DGy2tgX8uoagib6bZD_Bs3W4,10922
|
|
@@ -7,13 +7,13 @@ docker_stack/envsubst.py,sha256=gdEUpsjWJeNbbahySk56vUdQh1nns85o3LbU6SUBo3I,8337
|
|
|
7
7
|
docker_stack/envsubst_merge.py,sha256=TwOu8BducG0rWnSreJGwesNi-VghCetljcf-aWceE8M,4971
|
|
8
8
|
docker_stack/helpers.py,sha256=7zQT_lYU6IcqjSOYjE0JlHRtbB8Sffz3XlJKyNvot6U,5580
|
|
9
9
|
docker_stack/login.py,sha256=_4sx0hltvKnwA81r_HyYkdQjXs5AEPlh_Qy87sUfcP0,30996
|
|
10
|
-
docker_stack/manager_api.py,sha256=
|
|
10
|
+
docker_stack/manager_api.py,sha256=MrPKfbykRHgGoEl-1qehJBdaxncXGvzN_ef5Q2QBPXk,11486
|
|
11
11
|
docker_stack/markers.py,sha256=gqStnr0tNWZ1kzqvREc2jVQVQrevheShgJtL5QzSx4g,2388
|
|
12
12
|
docker_stack/merge_conf.py,sha256=Pmsabcgf3SDyaWvf2OLsBPodzEqsvOIjj9xzn_qWXH0,1917
|
|
13
13
|
docker_stack/registry.py,sha256=sWC1J9JDIrcYyhei1POYCZHJ0xUCKC2pveisSHMgYsQ,9036
|
|
14
14
|
docker_stack/url_parser.py,sha256=Sk8GQE0nEiwCkijp1OltP2AfgtKEmM2hybcH_rBhfiI,6824
|
|
15
|
-
docker_stack-2.0.
|
|
16
|
-
docker_stack-2.0.
|
|
17
|
-
docker_stack-2.0.
|
|
18
|
-
docker_stack-2.0.
|
|
19
|
-
docker_stack-2.0.
|
|
15
|
+
docker_stack-2.0.2.dist-info/METADATA,sha256=GUpDIRMWkpz6IFjZUGhHU9qhaEMmU2WYfyEweLaLyVE,8753
|
|
16
|
+
docker_stack-2.0.2.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
17
|
+
docker_stack-2.0.2.dist-info/entry_points.txt,sha256=mpe2RwIguARsosXIUBQEN2pKU53URqZCh2S4ATwDFL4,55
|
|
18
|
+
docker_stack-2.0.2.dist-info/top_level.txt,sha256=zT6TPL54cLrt9LO_MNkhEpGGOmsoe2HV6Na5Ohy3_2c,13
|
|
19
|
+
docker_stack-2.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|