zrb 0.26.2__py3-none-any.whl → 0.28.0__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.
- zrb/__init__.py +0 -3
- zrb/action/runner.py +0 -2
- zrb/builtin/devtool/install/zsh/install.sh +1 -1
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/microservices/start.py +7 -2
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/monolith/start.py +7 -2
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/remove.py +8 -2
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/stop.py +8 -2
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/support/start.py +15 -3
- zrb/config/config.py +0 -9
- zrb/helper/asyncio_task.py +15 -5
- zrb/task/base_task/base_task.py +39 -9
- zrb/task/cmd_task.py +9 -10
- zrb/task/docker_compose_start_task.py +30 -27
- zrb/task/docker_compose_task.py +64 -33
- zrb/task/looper.py +1 -1
- zrb/task/remote_cmd_task.py +55 -18
- zrb/task/rsync_task.py +57 -23
- {zrb-0.26.2.dist-info → zrb-0.28.0.dist-info}/METADATA +2 -2
- {zrb-0.26.2.dist-info → zrb-0.28.0.dist-info}/RECORD +22 -31
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/_helper.py +0 -8
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/microservices/_helper.py +0 -24
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/monolith/_helper.py +0 -22
- zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/support/_helper.py +0 -30
- zrb/builtin/project/add/fastapp/app/template/src/kebab-zrb-app-name/.generator-version +0 -1
- zrb/shell-scripts/ensure-podman-is-installed.sh +0 -55
- zrb/shell-scripts/rsync-util.sh +0 -12
- zrb/shell-scripts/ssh-util.sh +0 -12
- zrb/task/base_remote_cmd_task.py +0 -354
- {zrb-0.26.2.dist-info → zrb-0.28.0.dist-info}/LICENSE +0 -0
- {zrb-0.26.2.dist-info → zrb-0.28.0.dist-info}/WHEEL +0 -0
- {zrb-0.26.2.dist-info → zrb-0.28.0.dist-info}/entry_points.txt +0 -0
zrb/__init__.py
CHANGED
@@ -10,7 +10,6 @@ from zrb.task.any_task_event_handler import (
|
|
10
10
|
OnTriggered,
|
11
11
|
OnWaiting,
|
12
12
|
)
|
13
|
-
from zrb.task.base_remote_cmd_task import BaseRemoteCmdTask, RemoteConfig
|
14
13
|
from zrb.task.checker import Checker
|
15
14
|
from zrb.task.cmd_task import CmdTask
|
16
15
|
from zrb.task.decorator import python_task
|
@@ -69,8 +68,6 @@ assert CmdTask
|
|
69
68
|
assert DockerComposeTask
|
70
69
|
assert DockerComposeStartTask
|
71
70
|
assert ServiceConfig
|
72
|
-
assert BaseRemoteCmdTask
|
73
|
-
assert RemoteConfig
|
74
71
|
assert RemoteCmdTask
|
75
72
|
assert RsyncTask
|
76
73
|
assert Notifier
|
zrb/action/runner.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import sys
|
2
1
|
from collections.abc import Callable, Mapping
|
3
2
|
from typing import Any, Union
|
4
3
|
|
@@ -122,7 +121,6 @@ class Runner:
|
|
122
121
|
function(*args, **kwargs)
|
123
122
|
except Exception:
|
124
123
|
stop_asyncio_sync()
|
125
|
-
sys.exit(1)
|
126
124
|
finally:
|
127
125
|
task.clear_xcom()
|
128
126
|
|
@@ -21,7 +21,6 @@ from .._input import enable_monitoring_input
|
|
21
21
|
from .._service_config import snake_zrb_app_name_service_configs
|
22
22
|
from ..remove import remove_snake_zrb_app_name_container
|
23
23
|
from ._group import snake_zrb_app_name_microservices_container_group
|
24
|
-
from ._helper import activate_microservices_compose_profile
|
25
24
|
|
26
25
|
start_snake_zrb_app_name_microservices_container = DockerComposeStartTask(
|
27
26
|
icon="🐳",
|
@@ -38,7 +37,13 @@ start_snake_zrb_app_name_microservices_container = DockerComposeStartTask(
|
|
38
37
|
should_execute="{{ input.local_snake_zrb_app_name}}",
|
39
38
|
upstreams=[build_snake_zrb_app_name_image, remove_snake_zrb_app_name_container],
|
40
39
|
cwd=RESOURCE_DIR,
|
41
|
-
|
40
|
+
compose_profiles=[
|
41
|
+
'{{"postgres" if env.APP_DB_CONNECTION.startswith("postgresql") else ""}}',
|
42
|
+
'{{"kafka" if env.APP_BROKER_TYPE == "kafka" else ""}}',
|
43
|
+
'{{"rabbitmq" if env.APP_BROKER_TYPE == "rabbitmq" else ""}}',
|
44
|
+
'{{"monitoring" if input.enable_snake_zrb_app_name_monitoring else ""}}',
|
45
|
+
"microservices",
|
46
|
+
],
|
42
47
|
compose_env_prefix="CONTAINER_ZRB_ENV_PREFIX",
|
43
48
|
compose_service_configs=snake_zrb_app_name_service_configs,
|
44
49
|
env_files=[compose_env_file],
|
@@ -21,7 +21,6 @@ from .._input import enable_monitoring_input
|
|
21
21
|
from .._service_config import snake_zrb_app_name_service_configs
|
22
22
|
from ..remove import remove_snake_zrb_app_name_container
|
23
23
|
from ._group import snake_zrb_app_name_monolith_container_group
|
24
|
-
from ._helper import activate_monolith_compose_profile
|
25
24
|
|
26
25
|
start_snake_zrb_app_name_monolith_container = DockerComposeStartTask(
|
27
26
|
icon="🐳",
|
@@ -38,7 +37,13 @@ start_snake_zrb_app_name_monolith_container = DockerComposeStartTask(
|
|
38
37
|
should_execute="{{ input.local_snake_zrb_app_name}}",
|
39
38
|
upstreams=[build_snake_zrb_app_name_image, remove_snake_zrb_app_name_container],
|
40
39
|
cwd=RESOURCE_DIR,
|
41
|
-
|
40
|
+
compose_profiles=[
|
41
|
+
'{{"postgres" if env.APP_DB_CONNECTION.startswith("postgresql") else ""}}',
|
42
|
+
'{{"kafka" if env.APP_BROKER_TYPE == "kafka" else ""}}',
|
43
|
+
'{{"rabbitmq" if env.APP_BROKER_TYPE == "rabbitmq" else ""}}',
|
44
|
+
'{{"monitoring" if input.enable_snake_zrb_app_name_monitoring else ""}}',
|
45
|
+
"monolith",
|
46
|
+
],
|
42
47
|
compose_env_prefix="CONTAINER_ZRB_ENV_PREFIX",
|
43
48
|
compose_service_configs=snake_zrb_app_name_service_configs,
|
44
49
|
env_files=[compose_env_file],
|
zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/remove.py
CHANGED
@@ -5,7 +5,6 @@ from .._constant import RESOURCE_DIR
|
|
5
5
|
from ..image._env import image_env
|
6
6
|
from ._env import compose_env_file
|
7
7
|
from ._group import snake_zrb_app_name_container_group
|
8
|
-
from ._helper import activate_all_compose_profile
|
9
8
|
from ._service_config import snake_zrb_app_name_service_configs
|
10
9
|
|
11
10
|
remove_snake_zrb_app_name_container = DockerComposeTask(
|
@@ -14,8 +13,15 @@ remove_snake_zrb_app_name_container = DockerComposeTask(
|
|
14
13
|
description="Remove human readable zrb app name container",
|
15
14
|
group=snake_zrb_app_name_container_group,
|
16
15
|
cwd=RESOURCE_DIR,
|
17
|
-
setup_cmd=activate_all_compose_profile,
|
18
16
|
compose_cmd="down",
|
17
|
+
compose_profiles=[
|
18
|
+
"postgres",
|
19
|
+
"kafka",
|
20
|
+
"rabbitmq",
|
21
|
+
"monitoring",
|
22
|
+
"monolith",
|
23
|
+
"microservices",
|
24
|
+
],
|
19
25
|
compose_env_prefix="CONTAINER_ZRB_ENV_PREFIX",
|
20
26
|
compose_service_configs=snake_zrb_app_name_service_configs,
|
21
27
|
env_files=[compose_env_file],
|
@@ -5,7 +5,6 @@ from .._constant import RESOURCE_DIR
|
|
5
5
|
from ..image._env import image_env
|
6
6
|
from ._env import compose_env_file, host_port_env
|
7
7
|
from ._group import snake_zrb_app_name_container_group
|
8
|
-
from ._helper import activate_all_compose_profile
|
9
8
|
from ._service_config import snake_zrb_app_name_service_configs
|
10
9
|
|
11
10
|
stop_snake_zrb_app_name_container = DockerComposeTask(
|
@@ -14,8 +13,15 @@ stop_snake_zrb_app_name_container = DockerComposeTask(
|
|
14
13
|
description="Stop human readable zrb app name container",
|
15
14
|
group=snake_zrb_app_name_container_group,
|
16
15
|
cwd=RESOURCE_DIR,
|
17
|
-
setup_cmd=activate_all_compose_profile,
|
18
16
|
compose_cmd="stop",
|
17
|
+
compose_profiles=[
|
18
|
+
"postgres",
|
19
|
+
"kafka",
|
20
|
+
"rabbitmq",
|
21
|
+
"monitoring",
|
22
|
+
"monolith",
|
23
|
+
"microservices",
|
24
|
+
],
|
19
25
|
compose_env_prefix="CONTAINER_ZRB_ENV_PREFIX",
|
20
26
|
compose_service_configs=snake_zrb_app_name_service_configs,
|
21
27
|
env_files=[compose_env_file],
|
zrb/builtin/project/add/fastapp/app/template/_automate/snake_zrb_app_name/container/support/start.py
CHANGED
@@ -17,7 +17,6 @@ from .._input import enable_monitoring_input
|
|
17
17
|
from .._service_config import snake_zrb_app_name_service_configs
|
18
18
|
from ..remove import remove_snake_zrb_app_name_container
|
19
19
|
from ._group import snake_zrb_app_name_support_container_group
|
20
|
-
from ._helper import activate_support_compose_profile, should_start_support_container
|
21
20
|
|
22
21
|
start_snake_zrb_app_name_support_container = DockerComposeStartTask(
|
23
22
|
icon="🐳",
|
@@ -31,10 +30,23 @@ start_snake_zrb_app_name_support_container = DockerComposeStartTask(
|
|
31
30
|
https_input,
|
32
31
|
image_input,
|
33
32
|
],
|
34
|
-
should_execute=should_start_support_container,
|
35
33
|
upstreams=[remove_snake_zrb_app_name_container],
|
36
34
|
cwd=RESOURCE_DIR,
|
37
|
-
|
35
|
+
should_execute=" ".join(
|
36
|
+
[
|
37
|
+
"{{",
|
38
|
+
'env.APP_DB_CONNECTION.startswith("postgresql")',
|
39
|
+
'or env.APP_BROKER_TYPE in ("kafka", "rabbitmq")',
|
40
|
+
"or input.enable_snake_zrb_app_name_monitoring",
|
41
|
+
"}}",
|
42
|
+
]
|
43
|
+
),
|
44
|
+
compose_profiles=[
|
45
|
+
'{{"postgres" if env.APP_DB_CONNECTION.startswith("postgresql") else ""}}',
|
46
|
+
'{{"kafka" if env.APP_BROKER_TYPE == "kafka" else ""}}',
|
47
|
+
'{{"rabbitmq" if env.APP_BROKER_TYPE == "rabbitmq" else ""}}',
|
48
|
+
'{{"monitoring" if input.enable_snake_zrb_app_name_monitoring else ""}}',
|
49
|
+
],
|
38
50
|
compose_env_prefix="CONTAINER_ZRB_ENV_PREFIX",
|
39
51
|
compose_service_configs=snake_zrb_app_name_service_configs,
|
40
52
|
env_files=[compose_env_file],
|
zrb/config/config.py
CHANGED
@@ -18,12 +18,6 @@ def _get_current_shell() -> str:
|
|
18
18
|
return "bash"
|
19
19
|
|
20
20
|
|
21
|
-
def _get_valid_container_backend(container_backend: str) -> str:
|
22
|
-
if container_backend.lower().strip() == "podman":
|
23
|
-
return "podman"
|
24
|
-
return "docker"
|
25
|
-
|
26
|
-
|
27
21
|
def _get_default_tmp_dir() -> str:
|
28
22
|
if os.path.isdir("/tmp"):
|
29
23
|
return "/tmp"
|
@@ -52,7 +46,4 @@ SHOW_ADVERTISEMENT = untyped_to_boolean(os.getenv("ZRB_SHOW_ADVERTISEMENT", "1")
|
|
52
46
|
SHOW_PROMPT = untyped_to_boolean(os.getenv("ZRB_SHOW_PROMPT", "1"))
|
53
47
|
SHOW_TIME = untyped_to_boolean(os.getenv("ZRB_SHOW_TIME", "1"))
|
54
48
|
VERSION = _get_version()
|
55
|
-
CONTAINER_BACKEND = _get_valid_container_backend(
|
56
|
-
os.getenv("ZRB_CONTAINER_BACKEND", "docker")
|
57
|
-
)
|
58
49
|
ENABLE_TYPE_CHECKING = untyped_to_boolean(os.getenv("ZRB_ENABLE_TYPE_CHECKING", "1"))
|
zrb/helper/asyncio_task.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import sys
|
2
3
|
|
3
4
|
from zrb.helper.accessories.color import colored
|
4
5
|
from zrb.helper.log import logger
|
@@ -6,11 +7,22 @@ from zrb.helper.log import logger
|
|
6
7
|
logger.debug(colored("Loading zrb.helper.asyncio_task", attrs=["dark"]))
|
7
8
|
|
8
9
|
|
10
|
+
def _surpress_event_loop_error(unraisable):
|
11
|
+
if not (
|
12
|
+
isinstance(unraisable.exc_value, RuntimeError)
|
13
|
+
and str(unraisable.exc_value) == "Event loop is closed"
|
14
|
+
):
|
15
|
+
# Raise exception for anything except "event loop is closed"
|
16
|
+
sys.__unraisablehook__(unraisable)
|
17
|
+
|
18
|
+
|
19
|
+
sys.unraisablehook = _surpress_event_loop_error
|
20
|
+
|
21
|
+
|
9
22
|
async def stop_asyncio():
|
10
23
|
tasks = [task for task in asyncio.all_tasks() if task is not asyncio.current_task()]
|
11
24
|
for task in tasks:
|
12
25
|
task.cancel()
|
13
|
-
|
14
26
|
# Wait until all tasks are cancelled
|
15
27
|
await asyncio.gather(*tasks, return_exceptions=True)
|
16
28
|
|
@@ -20,7 +32,5 @@ def stop_asyncio_sync():
|
|
20
32
|
loop = asyncio.get_event_loop()
|
21
33
|
if loop.is_running():
|
22
34
|
loop.create_task(stop_asyncio())
|
23
|
-
|
24
|
-
|
25
|
-
except Exception:
|
26
|
-
pass
|
35
|
+
except asyncio.CancelledError:
|
36
|
+
logger.warning("Task is cancelled")
|
zrb/task/base_task/base_task.py
CHANGED
@@ -159,16 +159,15 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
|
|
159
159
|
def copy(self) -> AnyTask:
|
160
160
|
return copy.deepcopy(self)
|
161
161
|
|
162
|
-
def
|
162
|
+
def __get_async_function(
|
163
163
|
self,
|
164
164
|
env_prefix: str = "",
|
165
165
|
raise_error: bool = True,
|
166
|
-
is_async: bool = False,
|
167
166
|
show_done_info: bool = True,
|
168
167
|
should_clear_xcom: bool = False,
|
169
168
|
should_stop_looper: bool = False,
|
170
169
|
) -> Callable[..., Any]:
|
171
|
-
async def
|
170
|
+
async def async_function(*args: Any, **kwargs: Any) -> Any:
|
172
171
|
self.log_info("Copy task")
|
173
172
|
self_cp: AnyTask = self.copy()
|
174
173
|
result = await self_cp._run_and_check_all(
|
@@ -184,9 +183,41 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
|
|
184
183
|
self_cp.clear_xcom()
|
185
184
|
return result
|
186
185
|
|
186
|
+
return async_function
|
187
|
+
|
188
|
+
def __to_sync_function(
|
189
|
+
self, async_function: Callable[..., Any]
|
190
|
+
) -> Callable[..., Any]:
|
191
|
+
def sync_function(*args: Any, **kwargs: Any) -> Any:
|
192
|
+
try:
|
193
|
+
return asyncio.run(async_function(*args, **kwargs))
|
194
|
+
except RuntimeError as e:
|
195
|
+
if "event loop is closed" not in str(e).lower():
|
196
|
+
raise e
|
197
|
+
except asyncio.CancelledError:
|
198
|
+
self.print_out_dark("Task is cancelled")
|
199
|
+
|
200
|
+
return sync_function
|
201
|
+
|
202
|
+
def to_function(
|
203
|
+
self,
|
204
|
+
env_prefix: str = "",
|
205
|
+
raise_error: bool = True,
|
206
|
+
is_async: bool = False,
|
207
|
+
show_done_info: bool = True,
|
208
|
+
should_clear_xcom: bool = False,
|
209
|
+
should_stop_looper: bool = False,
|
210
|
+
) -> Callable[..., Any]:
|
211
|
+
async_function = self.__get_async_function(
|
212
|
+
env_prefix=env_prefix,
|
213
|
+
raise_error=raise_error,
|
214
|
+
show_done_info=show_done_info,
|
215
|
+
should_clear_xcom=should_clear_xcom,
|
216
|
+
should_stop_looper=should_stop_looper,
|
217
|
+
)
|
187
218
|
if is_async:
|
188
|
-
return
|
189
|
-
return
|
219
|
+
return async_function
|
220
|
+
return self.__to_sync_function(async_function)
|
190
221
|
|
191
222
|
async def run(self, *args: Any, **kwargs: Any) -> Any:
|
192
223
|
if self._run_function is not None:
|
@@ -287,9 +318,6 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
|
|
287
318
|
result = results[-1]
|
288
319
|
self._print_result(result)
|
289
320
|
return result
|
290
|
-
except RuntimeError as e:
|
291
|
-
if raise_error and ("event loop is closed" not in str(e).lower()):
|
292
|
-
raise e
|
293
321
|
except Exception as e:
|
294
322
|
self.log_error(f"{e}")
|
295
323
|
if raise_error:
|
@@ -384,7 +412,9 @@ class BaseTask(FinishTracker, AttemptTracker, Renderer, BaseTaskModel, AnyTask):
|
|
384
412
|
is_failed: bool = False
|
385
413
|
while self._should_attempt():
|
386
414
|
try:
|
387
|
-
self.log_debug(
|
415
|
+
self.log_debug(
|
416
|
+
f"Started with args: {args} and kwargs: {local_kwargs}"
|
417
|
+
) # noqa
|
388
418
|
await self.on_started()
|
389
419
|
self.__running_tasks.append(self)
|
390
420
|
result = await run_async(self.run, *args, **local_kwargs)
|
zrb/task/cmd_task.py
CHANGED
@@ -291,8 +291,6 @@ class CmdTask(BaseTask):
|
|
291
291
|
for pid in self._pids:
|
292
292
|
self.__kill_by_pid(pid)
|
293
293
|
stop_asyncio_sync()
|
294
|
-
_print_out_dark(f"Exiting with signal {signum}")
|
295
|
-
sys.exit(signum)
|
296
294
|
|
297
295
|
def __on_exit(self):
|
298
296
|
self._global_state.no_more_attempt = True
|
@@ -351,14 +349,15 @@ class CmdTask(BaseTask):
|
|
351
349
|
)
|
352
350
|
)
|
353
351
|
# wait process
|
354
|
-
await
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
await
|
361
|
-
|
352
|
+
await asyncio.gather(
|
353
|
+
process.wait(),
|
354
|
+
stdout_process,
|
355
|
+
stderr_process,
|
356
|
+
)
|
357
|
+
# stop messages in queue
|
358
|
+
await asyncio.gather(stdout_queue.put(None), stderr_queue.put(None))
|
359
|
+
# end logging
|
360
|
+
await asyncio.gather(stdout_log_process, stderr_log_process)
|
362
361
|
|
363
362
|
def get_cmd_script(self, *args: Any, **kwargs: Any) -> str:
|
364
363
|
return self._create_cmd_script(self._cmd_path, self._cmd, *args, **kwargs)
|
@@ -45,6 +45,7 @@ class DockerComposeStartTask(DockerComposeTask):
|
|
45
45
|
compose_options: Mapping[JinjaTemplate, JinjaTemplate] = {},
|
46
46
|
compose_flags: Iterable[JinjaTemplate] = [],
|
47
47
|
compose_args: Iterable[JinjaTemplate] = [],
|
48
|
+
compose_profiles: Iterable[JinjaTemplate] = [],
|
48
49
|
compose_env_prefix: str = "",
|
49
50
|
setup_cmd: CmdVal = "",
|
50
51
|
setup_cmd_path: CmdVal = "",
|
@@ -85,9 +86,11 @@ class DockerComposeStartTask(DockerComposeTask):
|
|
85
86
|
executable=executable,
|
86
87
|
compose_service_configs=compose_service_configs,
|
87
88
|
compose_file=compose_file,
|
89
|
+
compose_cmd="up",
|
88
90
|
compose_options=compose_options,
|
89
91
|
compose_flags=compose_flags,
|
90
92
|
compose_args=compose_args,
|
93
|
+
compose_profiles=compose_profiles,
|
91
94
|
compose_env_prefix=compose_env_prefix,
|
92
95
|
setup_cmd=setup_cmd,
|
93
96
|
setup_cmd_path=setup_cmd_path,
|
@@ -116,31 +119,31 @@ class DockerComposeStartTask(DockerComposeTask):
|
|
116
119
|
should_show_working_directory=should_show_working_directory,
|
117
120
|
)
|
118
121
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
122
|
+
def _get_execute_docker_compose_script(
|
123
|
+
self,
|
124
|
+
compose_cmd: JinjaTemplate,
|
125
|
+
compose_options: Mapping[JinjaTemplate, JinjaTemplate],
|
126
|
+
compose_flags: Iterable[JinjaTemplate],
|
127
|
+
compose_args: Iterable[JinjaTemplate],
|
128
|
+
*args: Any
|
129
|
+
) -> JinjaTemplate:
|
130
|
+
return "\n".join(
|
131
|
+
[
|
132
|
+
# compose start
|
133
|
+
super()._get_execute_docker_compose_script(
|
134
|
+
compose_cmd=compose_cmd,
|
135
|
+
compose_options=compose_options,
|
136
|
+
compose_flags=list(compose_flags) + ["-d"],
|
137
|
+
compose_args=compose_args,
|
138
|
+
*args,
|
139
|
+
),
|
140
|
+
# compose log
|
141
|
+
super()._get_execute_docker_compose_script(
|
142
|
+
compose_cmd="logs",
|
143
|
+
compose_options={},
|
144
|
+
compose_flags=["-f"],
|
145
|
+
compose_args=[],
|
146
|
+
*args,
|
147
|
+
),
|
148
|
+
]
|
123
149
|
)
|
124
|
-
cmd_list = [setup_cmd] if setup_cmd.strip() != "" else []
|
125
|
-
# compose command
|
126
|
-
cmd_list = cmd_list + [
|
127
|
-
# compose start
|
128
|
-
self._get_docker_compose_cmd_script(
|
129
|
-
compose_cmd="up",
|
130
|
-
compose_options=self._compose_options,
|
131
|
-
compose_flags=list(self._compose_flags) + ["-d"],
|
132
|
-
compose_args=self._compose_args,
|
133
|
-
*args,
|
134
|
-
),
|
135
|
-
# compose log
|
136
|
-
self._get_docker_compose_cmd_script(
|
137
|
-
compose_cmd="logs",
|
138
|
-
compose_options={},
|
139
|
-
compose_flags=["-f"],
|
140
|
-
compose_args=[],
|
141
|
-
*args,
|
142
|
-
),
|
143
|
-
]
|
144
|
-
cmd_str = "\n".join(cmd_list)
|
145
|
-
self.log_info(f"Command: {cmd_str}")
|
146
|
-
return cmd_str
|
zrb/task/docker_compose_task.py
CHANGED
@@ -3,7 +3,6 @@ import pathlib
|
|
3
3
|
from collections.abc import Callable, Iterable, Mapping
|
4
4
|
from typing import Any, Optional, TypeVar, Union
|
5
5
|
|
6
|
-
from zrb.config.config import CONTAINER_BACKEND
|
7
6
|
from zrb.helper.accessories.color import colored
|
8
7
|
from zrb.helper.accessories.name import get_random_name
|
9
8
|
from zrb.helper.docker_compose.fetch_external_env import fetch_compose_file_env_map
|
@@ -33,32 +32,22 @@ from zrb.task_input.any_input import AnyInput
|
|
33
32
|
|
34
33
|
logger.debug(colored("Loading zrb.task.docker_compose_task", attrs=["dark"]))
|
35
34
|
|
35
|
+
TDockerComposeTask = TypeVar("TDockerComposeTask", bound="DockerComposeTask")
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
SHELL_SCRIPT_DIR = os.path.join(CURRENT_DIR, "..", "shell-scripts")
|
40
|
-
ensure_container_backend = CmdTask(
|
41
|
-
name="ensure-compose-backend",
|
42
|
-
cmd_path=[
|
43
|
-
os.path.join(SHELL_SCRIPT_DIR, "_common-util.sh"),
|
44
|
-
os.path.join(SHELL_SCRIPT_DIR, f"ensure-{backend}-is-installed.sh"),
|
45
|
-
],
|
46
|
-
preexec_fn=None,
|
47
|
-
should_print_cmd_result=False,
|
48
|
-
)
|
49
|
-
return CmdTask(
|
50
|
-
name="ensure-zrb-network",
|
51
|
-
cmd=[
|
52
|
-
f"{backend} network inspect zrb >/dev/null 2>&1 || \\",
|
53
|
-
f"{backend} network create -d bridge zrb",
|
54
|
-
],
|
55
|
-
upstreams=[ensure_container_backend],
|
56
|
-
should_print_cmd_result=False,
|
57
|
-
)
|
58
|
-
|
37
|
+
CURRENT_DIR = os.path.dirname(__file__)
|
38
|
+
SHELL_SCRIPT_DIR = os.path.join(CURRENT_DIR, "..", "shell-scripts")
|
59
39
|
|
60
|
-
|
61
|
-
|
40
|
+
ensure_container_backend = CmdTask(
|
41
|
+
name="ensure-compose-backend",
|
42
|
+
cmd_path=[
|
43
|
+
os.path.join(SHELL_SCRIPT_DIR, "_common-util.sh"),
|
44
|
+
os.path.join(SHELL_SCRIPT_DIR, "ensure-docker-is-installed.sh"),
|
45
|
+
],
|
46
|
+
preexec_fn=None,
|
47
|
+
should_print_cmd_result=False,
|
48
|
+
should_show_cmd=False,
|
49
|
+
should_show_working_directory=False,
|
50
|
+
)
|
62
51
|
|
63
52
|
|
64
53
|
@typechecked
|
@@ -93,6 +82,7 @@ class DockerComposeTask(CmdTask):
|
|
93
82
|
compose_options: Mapping[JinjaTemplate, JinjaTemplate] = {},
|
94
83
|
compose_flags: Iterable[JinjaTemplate] = [],
|
95
84
|
compose_args: Iterable[JinjaTemplate] = [],
|
85
|
+
compose_profiles: CmdVal = "",
|
96
86
|
compose_env_prefix: str = "",
|
97
87
|
setup_cmd: CmdVal = "",
|
98
88
|
setup_cmd_path: CmdVal = "",
|
@@ -120,21 +110,20 @@ class DockerComposeTask(CmdTask):
|
|
120
110
|
should_show_cmd: bool = True,
|
121
111
|
should_show_working_directory: bool = True,
|
122
112
|
):
|
123
|
-
combined_env_files = list(env_files)
|
124
113
|
CmdTask.__init__(
|
125
114
|
self,
|
126
115
|
name=name,
|
127
116
|
group=group,
|
128
117
|
inputs=inputs,
|
129
118
|
envs=envs,
|
130
|
-
env_files=
|
119
|
+
env_files=env_files,
|
131
120
|
icon=icon,
|
132
121
|
color=color,
|
133
122
|
description=description,
|
134
123
|
executable=executable,
|
135
124
|
cwd=cwd,
|
136
125
|
should_render_cwd=should_render_cwd,
|
137
|
-
upstreams=[
|
126
|
+
upstreams=[ensure_container_backend] + upstreams,
|
138
127
|
fallbacks=fallbacks,
|
139
128
|
on_triggered=on_triggered,
|
140
129
|
on_waiting=on_waiting,
|
@@ -168,6 +157,7 @@ class DockerComposeTask(CmdTask):
|
|
168
157
|
self._compose_flags = compose_flags
|
169
158
|
self._compose_args = compose_args
|
170
159
|
self._compose_env_prefix = compose_env_prefix
|
160
|
+
self._compose_profiles = compose_profiles
|
171
161
|
self._compose_template_file = self.__get_compose_template_file(compose_file)
|
172
162
|
self._compose_runtime_file = self.__get_compose_runtime_file(
|
173
163
|
self._compose_template_file
|
@@ -333,14 +323,24 @@ class DockerComposeTask(CmdTask):
|
|
333
323
|
raise Exception(f"Invalid compose file: {compose_file}")
|
334
324
|
|
335
325
|
def get_cmd_script(self, *args: Any, **kwargs: Any) -> str:
|
326
|
+
cmd_list = []
|
327
|
+
# create network
|
328
|
+
create_network_script = self._get_create_compose_network_script()
|
329
|
+
if create_network_script.strip() != "":
|
330
|
+
cmd_list.append(create_network_script)
|
331
|
+
# set compose profiles
|
332
|
+
compose_profile_script = self._get_compose_profile_script(*args, **kwargs)
|
333
|
+
if compose_profile_script.strip() != "":
|
334
|
+
cmd_list.append(compose_profile_script)
|
336
335
|
# setup
|
337
|
-
|
336
|
+
setup_script = self._create_cmd_script(
|
338
337
|
self._setup_cmd_path, self._setup_cmd, *args, **kwargs
|
339
338
|
)
|
340
|
-
|
339
|
+
if setup_script.strip() != "":
|
340
|
+
cmd_list.append(setup_script)
|
341
341
|
# compose command
|
342
342
|
cmd_list.append(
|
343
|
-
self.
|
343
|
+
self._get_execute_docker_compose_script(
|
344
344
|
compose_cmd=self._compose_cmd,
|
345
345
|
compose_options=self._compose_options,
|
346
346
|
compose_flags=self._compose_flags,
|
@@ -352,7 +352,38 @@ class DockerComposeTask(CmdTask):
|
|
352
352
|
self.log_info(f"Command: {cmd_str}")
|
353
353
|
return cmd_str
|
354
354
|
|
355
|
-
def
|
355
|
+
def _get_compose_profile_script(self, *args, **kwargs) -> str:
|
356
|
+
# Get list representation of self._compose_profiles
|
357
|
+
compose_profiles = self._compose_profiles
|
358
|
+
if callable(compose_profiles):
|
359
|
+
compose_profiles = self._compose_profiles(*args, **kwargs)
|
360
|
+
if isinstance(compose_profiles, str):
|
361
|
+
compose_profiles = compose_profiles.split(",")
|
362
|
+
# Get only non empty profiles
|
363
|
+
filtered_compose_profiles = [
|
364
|
+
self.render_str(profile)
|
365
|
+
for profile in compose_profiles
|
366
|
+
if self.render_str(profile).strip() != ""
|
367
|
+
]
|
368
|
+
if len(filtered_compose_profiles) == 0:
|
369
|
+
return ""
|
370
|
+
compose_profiles_str = ",".join(filtered_compose_profiles)
|
371
|
+
return f"export COMPOSE_PROFILES={compose_profiles_str}"
|
372
|
+
|
373
|
+
def _get_create_compose_network_script(self) -> str:
|
374
|
+
compose_data = read_compose_file(self._compose_runtime_file)
|
375
|
+
networks: Mapping[str, Mapping[str, Any]] = compose_data.get("networks", {})
|
376
|
+
scripts = []
|
377
|
+
for key, config in networks.items():
|
378
|
+
if not config.get("external", False):
|
379
|
+
continue
|
380
|
+
network_name = config.get("name", key)
|
381
|
+
scripts.append(
|
382
|
+
f"docker network inspect {network_name} > /dev/null 2>&1 || docker network create -d bridge{network_name}" # noqa
|
383
|
+
)
|
384
|
+
return "\n".join(scripts)
|
385
|
+
|
386
|
+
def _get_execute_docker_compose_script(
|
356
387
|
self,
|
357
388
|
compose_cmd: str,
|
358
389
|
compose_options: Mapping[JinjaTemplate, JinjaTemplate],
|
@@ -383,4 +414,4 @@ class DockerComposeTask(CmdTask):
|
|
383
414
|
if self.render_str(arg) != ""
|
384
415
|
]
|
385
416
|
)
|
386
|
-
return f"
|
417
|
+
return f"docker compose {options} {compose_cmd} {flags} {args}"
|
zrb/task/looper.py
CHANGED