seto 3.2.0__tar.gz → 3.3.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.
- {seto-3.2.0 → seto-3.3.0}/PKG-INFO +1 -1
- {seto-3.2.0 → seto-3.3.0}/pyproject.toml +2 -1
- {seto-3.2.0 → seto-3.3.0}/seto/__main__.py +3 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/config.py +4 -3
- {seto-3.2.0 → seto-3.3.0}/seto/commands/deploy.py +25 -21
- {seto-3.2.0 → seto-3.3.0}/seto/core/command.py +2 -1
- {seto-3.2.0 → seto-3.3.0}/seto/core/parser.py +9 -7
- {seto-3.2.0 → seto-3.3.0}/LICENSE +0 -0
- {seto-3.2.0 → seto-3.3.0}/LICENSE_HEADER.txt +0 -0
- {seto-3.2.0 → seto-3.3.0}/README.md +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/__init__.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/down.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/mount.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/setup.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/umount.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/commands/volumes.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/dns.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/docker.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/driver.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/network.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/permissions.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/shell.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/swarm.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/traefik.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/core/volume.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/drivers/nfs.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/shells/local.py +0 -0
- {seto-3.2.0 → seto-3.3.0}/seto/shells/remote.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "seto"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.3.0"
|
|
8
8
|
description = "A Docker Swarm Deployment Manager"
|
|
9
9
|
keywords = ["docker", "swarm", "manager"]
|
|
10
10
|
authors = ["Sébastien Demanou <demsking@gmail.com>"]
|
|
@@ -33,6 +33,7 @@ pyyaml = "^6.0.1"
|
|
|
33
33
|
docker = "^7.1.0"
|
|
34
34
|
|
|
35
35
|
[tool.poetry.group.dev.dependencies]
|
|
36
|
+
classify-imports = "^4.2.0"
|
|
36
37
|
|
|
37
38
|
[tool.pytest.ini_options]
|
|
38
39
|
# Function starting with the following pattern are considered for test cases.
|
|
@@ -194,6 +194,9 @@ def main() -> None:
|
|
|
194
194
|
'deploy', description='Deploy a new stack or update an existing stack'
|
|
195
195
|
)
|
|
196
196
|
deploy_parser.set_defaults(func=execute_deploy_command)
|
|
197
|
+
deploy_parser.add_argument(
|
|
198
|
+
'--image-prefix', default='', help='Image namespace prefix to added to internal images'
|
|
199
|
+
)
|
|
197
200
|
|
|
198
201
|
#
|
|
199
202
|
# Down command
|
|
@@ -51,8 +51,8 @@ def resolve(
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
def parse(resolved_compose_data: dict, volumes: list[Volume]):
|
|
54
|
-
placement_hostname = resolved_compose_data.get('x-placement-hostname', None)
|
|
55
|
-
placement = resolved_compose_data.get('x-placement', None)
|
|
54
|
+
placement_hostname: str | None = resolved_compose_data.get('x-placement-hostname', None)
|
|
55
|
+
placement: str | None = resolved_compose_data.get('x-placement', None)
|
|
56
56
|
networks_ = resolved_compose_data.get('networks', {})
|
|
57
57
|
services = resolved_compose_data.get('services', {})
|
|
58
58
|
volumes = resolved_compose_data.get('volumes', {})
|
|
@@ -72,10 +72,11 @@ def resolve(
|
|
|
72
72
|
raise ValueError('Missing required x-placement or x-placement-hostname field')
|
|
73
73
|
|
|
74
74
|
if execute:
|
|
75
|
-
execute(resolved_compose_data, placement_hostname or placement)
|
|
75
|
+
execute(resolved_compose_data, placement_hostname or placement or '')
|
|
76
76
|
|
|
77
77
|
parse_services(
|
|
78
78
|
driver=driver,
|
|
79
|
+
image_prefix=args.image_prefix,
|
|
79
80
|
stack=args.stack or args.project,
|
|
80
81
|
execute=parse,
|
|
81
82
|
inject=inject,
|
|
@@ -110,7 +110,9 @@ def parse_compose_config(
|
|
|
110
110
|
published_port = random.randint(53100, 64200)
|
|
111
111
|
|
|
112
112
|
if not service_traefik_port:
|
|
113
|
-
print(
|
|
113
|
+
print(
|
|
114
|
+
f'WARN: Service "{service_name}" has no defined port. Skipped from Traefik HTTP Provider'
|
|
115
|
+
)
|
|
114
116
|
continue
|
|
115
117
|
|
|
116
118
|
service_ports.append(f'{published_port}:{service_traefik_port}')
|
|
@@ -184,6 +186,7 @@ def deploy_seto_stack(args, driver: Driver, replica: list[Setting]) -> None:
|
|
|
184
186
|
# Resolving compose local volumes
|
|
185
187
|
resolved_compose_data, volumes = resolve_compose_file(
|
|
186
188
|
driver=driver,
|
|
189
|
+
image_prefix=args.image_prefix,
|
|
187
190
|
compose_data=internal_stack,
|
|
188
191
|
inject=True,
|
|
189
192
|
)
|
|
@@ -239,30 +242,31 @@ def execute_deploy_command(args, driver: Driver) -> None:
|
|
|
239
242
|
},
|
|
240
243
|
}
|
|
241
244
|
|
|
242
|
-
register_command = ' && '.join(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
# Log the start of the initial endpoint call
|
|
249
|
-
'echo "Starting initial call to the provider endpoint..."',
|
|
250
|
-
|
|
251
|
-
# Call the POST endpoint at startup
|
|
252
|
-
register_command,
|
|
253
|
-
|
|
254
|
-
# Log the end of the initial endpoint call
|
|
255
|
-
'echo "Initial call to the provider endpoint completed. Running cron job..."',
|
|
256
|
-
|
|
257
|
-
# Set up the cron job
|
|
258
|
-
f'echo "*/1 * * * * {register_command}" | crontab -',
|
|
245
|
+
register_command = ' && '.join(
|
|
246
|
+
[
|
|
247
|
+
f'echo "Registering service {driver.stack_id}..."',
|
|
248
|
+
f'curl -s -X POST http://{HTTP_PROVIDER_SERVICENAME}:6116/api/config/{driver.stack_id} -H "Content-Type: application/json" -d @{traefik_http_provider_target} > /dev/nul',
|
|
249
|
+
]
|
|
250
|
+
)
|
|
259
251
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
252
|
+
entrypoint = ' && '.join(
|
|
253
|
+
[
|
|
254
|
+
# Log the start of the initial endpoint call
|
|
255
|
+
'echo "Starting initial call to the provider endpoint..."',
|
|
256
|
+
# Call the POST endpoint at startup
|
|
257
|
+
register_command,
|
|
258
|
+
# Log the end of the initial endpoint call
|
|
259
|
+
'echo "Initial call to the provider endpoint completed. Running cron job..."',
|
|
260
|
+
# Set up the cron job
|
|
261
|
+
f'echo "*/1 * * * * {register_command}" | crontab -',
|
|
262
|
+
# Start the cron service
|
|
263
|
+
'crond -f',
|
|
264
|
+
]
|
|
265
|
+
)
|
|
263
266
|
|
|
264
267
|
seto_agent_compose_data, _ = resolve_compose_file(
|
|
265
268
|
driver=driver,
|
|
269
|
+
image_prefix=args.image_prefix,
|
|
266
270
|
compose_data={
|
|
267
271
|
'services': {
|
|
268
272
|
'seto_agent': {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 Sébastien Demanou. All Rights Reserved.
|
|
1
|
+
# Copyright 2024-2025 Sébastien Demanou. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -24,6 +24,7 @@ def parse_volumes_args(args, driver: Driver) -> list[Volume]:
|
|
|
24
24
|
driver=driver,
|
|
25
25
|
stack=args.stack or args.project,
|
|
26
26
|
execute=lambda resolved_compose_data, volumes: all_volumes.extend(volumes),
|
|
27
|
+
image_prefix=args.image_prefix,
|
|
27
28
|
)
|
|
28
29
|
|
|
29
30
|
return all_volumes
|
|
@@ -56,10 +56,7 @@ def parse_volume_entry(entry: str, default_mode='rw') -> tuple[str, str, str]:
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def parse_local_volumes(
|
|
59
|
-
stack: str,
|
|
60
|
-
*,
|
|
61
|
-
service_name: str,
|
|
62
|
-
service: Service,
|
|
59
|
+
stack: str, *, service_name: str, service: Service, image_prefix: str
|
|
63
60
|
) -> None:
|
|
64
61
|
local_volumes = []
|
|
65
62
|
|
|
@@ -89,7 +86,7 @@ def parse_local_volumes(
|
|
|
89
86
|
service_dockerfile = '\n'.join(service_dockerfile_definition)
|
|
90
87
|
service_dockerfile = resolve_env_vars(service_dockerfile)
|
|
91
88
|
|
|
92
|
-
service['image'] = f'
|
|
89
|
+
service['image'] = f'{image_prefix}{image_name}:{image_version}'
|
|
93
90
|
service['build'] = {
|
|
94
91
|
'context': '.',
|
|
95
92
|
'dockerfile': service_dockerfile_file,
|
|
@@ -162,6 +159,7 @@ def resolve_compose_file(
|
|
|
162
159
|
compose_data: dict,
|
|
163
160
|
inject: bool = False,
|
|
164
161
|
mode: list[ResolveMode] | None = None,
|
|
162
|
+
image_prefix: str,
|
|
165
163
|
) -> tuple[dict, list]:
|
|
166
164
|
mode_value = mode or ['swarm']
|
|
167
165
|
updated_compose_data = compose_data.copy()
|
|
@@ -185,7 +183,9 @@ def resolve_compose_file(
|
|
|
185
183
|
|
|
186
184
|
service_deploy_labels.update(service_labels)
|
|
187
185
|
parse_stack_values(service_deploy_labels)
|
|
188
|
-
parse_local_volumes(
|
|
186
|
+
parse_local_volumes(
|
|
187
|
+
driver.stack_id, service_name=service_name, service=service, image_prefix=image_prefix
|
|
188
|
+
)
|
|
189
189
|
|
|
190
190
|
parse_volumes(
|
|
191
191
|
driver=driver,
|
|
@@ -242,7 +242,7 @@ def parse_service_configs(
|
|
|
242
242
|
config_name = re.sub(
|
|
243
243
|
r'_{2,}',
|
|
244
244
|
'_',
|
|
245
|
-
f
|
|
245
|
+
f'{service_name}_{source.replace("/", "_").replace(".", "_")}'.replace('-', '_'),
|
|
246
246
|
)
|
|
247
247
|
|
|
248
248
|
if inject:
|
|
@@ -305,6 +305,7 @@ def parse_services(
|
|
|
305
305
|
execute: Callable[[dict, list], None] | None = None,
|
|
306
306
|
mode: list[ResolveMode] | None = None,
|
|
307
307
|
inject: bool = False,
|
|
308
|
+
image_prefix: str,
|
|
308
309
|
) -> tuple[list, list]:
|
|
309
310
|
services_files = glob.glob(os.path.join(stack, '*.yaml'))
|
|
310
311
|
output_resolved_compose_data = []
|
|
@@ -332,6 +333,7 @@ def parse_services(
|
|
|
332
333
|
compose_data=compose_data,
|
|
333
334
|
inject=inject,
|
|
334
335
|
mode=[x_mode],
|
|
336
|
+
image_prefix=image_prefix,
|
|
335
337
|
)
|
|
336
338
|
|
|
337
339
|
output_resolved_compose_data.append(resolved_compose_data)
|
|
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
|