refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
from __future__ import annotations
|
2023-01-06 18:02:17 +00:00
|
|
|
|
2020-12-25 21:56:42 +00:00
|
|
|
import os
|
|
|
|
|
2020-01-08 18:38:13 +00:00
|
|
|
import click
|
|
|
|
|
2023-04-28 15:11:14 +00:00
|
|
|
from tutor import bindmount
|
2022-02-07 17:11:43 +00:00
|
|
|
from tutor import config as tutor_config
|
|
|
|
from tutor import env as tutor_env
|
2023-04-28 15:11:14 +00:00
|
|
|
from tutor import hooks, utils
|
2022-10-18 14:57:07 +00:00
|
|
|
from tutor.commands import jobs
|
2022-10-19 15:46:31 +00:00
|
|
|
from tutor.commands.context import BaseTaskContext
|
2023-01-06 18:02:17 +00:00
|
|
|
from tutor.core.hooks import Filter # pylint: disable=unused-import
|
2022-02-07 17:11:43 +00:00
|
|
|
from tutor.exceptions import TutorError
|
2022-10-19 15:46:31 +00:00
|
|
|
from tutor.tasks import BaseComposeTaskRunner
|
2022-02-07 17:11:43 +00:00
|
|
|
from tutor.types import Config
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
2022-10-19 15:46:31 +00:00
|
|
|
class ComposeTaskRunner(BaseComposeTaskRunner):
|
2021-09-27 10:32:28 +00:00
|
|
|
def __init__(self, root: str, config: Config):
|
|
|
|
super().__init__(root, config)
|
|
|
|
self.project_name = ""
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
self.docker_compose_files: list[str] = []
|
|
|
|
self.docker_compose_job_files: list[str] = []
|
2021-09-27 10:32:28 +00:00
|
|
|
|
|
|
|
def docker_compose(self, *command: str) -> int:
|
|
|
|
"""
|
|
|
|
Run docker-compose with the right yml files.
|
|
|
|
"""
|
2022-04-21 14:24:34 +00:00
|
|
|
if "start" in command or "up" in command or "restart" in command:
|
|
|
|
# Note that we don't trigger the action on "run". That's because we
|
|
|
|
# don't want to trigger the action for every initialization script.
|
|
|
|
hooks.Actions.COMPOSE_PROJECT_STARTED.do(
|
|
|
|
self.root, self.config, self.project_name
|
|
|
|
)
|
2021-09-27 10:32:28 +00:00
|
|
|
args = []
|
|
|
|
for docker_compose_path in self.docker_compose_files:
|
|
|
|
if os.path.exists(docker_compose_path):
|
|
|
|
args += ["-f", docker_compose_path]
|
|
|
|
return utils.docker_compose(
|
|
|
|
*args, "--project-name", self.project_name, *command
|
|
|
|
)
|
|
|
|
|
2022-10-19 15:46:31 +00:00
|
|
|
def run_task(self, service: str, command: str) -> int:
|
Improve job running in local and k8s
Running jobs was previously done with "exec". This was because it
allowed us to avoid copying too much container specification information
from the docker-compose/deployments files to the jobs files. However,
this was limiting:
- In order to run a job, the corresponding container had to be running.
This was particularly painful in Kubernetes, where containers are
crashing as long as migrations are not correctly run.
- Containers in which we need to run jobs needed to be present in the
docker-compose/deployments files. This is unnecessary, for example when
mysql is disabled, or in the case of the certbot container.
Now, we create dedicated jobs files, both for local and k8s deployment.
This introduces a little redundancy, but not too much. Note that
dependent containers are not listed in the docker-compose.jobs.yml file,
so an actual platform is still supposed to be running when we launch the
jobs.
This also introduces a subtle change: now, jobs go through the container
entrypoint prior to running. This is probably a good thing, as it will
avoid forgetting about incorrect environment variables.
In k8s, we find ourselves interacting way too much with the kubectl
utility. Parsing output from the CLI is a pain. So we need to switch to
the native kubernetes client library.
2020-03-25 17:47:36 +00:00
|
|
|
"""
|
|
|
|
Run the "{{ service }}-job" service from local/docker-compose.jobs.yml with the
|
2021-11-02 17:24:38 +00:00
|
|
|
specified command.
|
Improve job running in local and k8s
Running jobs was previously done with "exec". This was because it
allowed us to avoid copying too much container specification information
from the docker-compose/deployments files to the jobs files. However,
this was limiting:
- In order to run a job, the corresponding container had to be running.
This was particularly painful in Kubernetes, where containers are
crashing as long as migrations are not correctly run.
- Containers in which we need to run jobs needed to be present in the
docker-compose/deployments files. This is unnecessary, for example when
mysql is disabled, or in the case of the certbot container.
Now, we create dedicated jobs files, both for local and k8s deployment.
This introduces a little redundancy, but not too much. Note that
dependent containers are not listed in the docker-compose.jobs.yml file,
so an actual platform is still supposed to be running when we launch the
jobs.
This also introduces a subtle change: now, jobs go through the container
entrypoint prior to running. This is probably a good thing, as it will
avoid forgetting about incorrect environment variables.
In k8s, we find ourselves interacting way too much with the kubectl
utility. Parsing output from the CLI is a pain. So we need to switch to
the native kubernetes client library.
2020-03-25 17:47:36 +00:00
|
|
|
"""
|
2021-09-27 10:32:28 +00:00
|
|
|
run_command = []
|
|
|
|
for docker_compose_path in self.docker_compose_job_files:
|
|
|
|
path = tutor_env.pathjoin(self.root, docker_compose_path)
|
|
|
|
if os.path.exists(path):
|
|
|
|
run_command += ["-f", path]
|
2021-09-06 14:20:36 +00:00
|
|
|
run_command += ["run", "--rm"]
|
|
|
|
if not utils.is_a_tty():
|
|
|
|
run_command += ["-T"]
|
2022-02-21 10:52:46 +00:00
|
|
|
job_service_name = f"{service}-job"
|
2021-09-27 09:48:17 +00:00
|
|
|
return self.docker_compose(
|
2021-09-06 14:20:36 +00:00
|
|
|
*run_command,
|
|
|
|
job_service_name,
|
2021-02-25 08:09:14 +00:00
|
|
|
"sh",
|
|
|
|
"-e",
|
|
|
|
"-c",
|
|
|
|
command,
|
|
|
|
)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
2022-10-19 15:46:31 +00:00
|
|
|
class BaseComposeContext(BaseTaskContext):
|
|
|
|
def job_runner(self, config: Config) -> ComposeTaskRunner:
|
2021-09-27 09:48:17 +00:00
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
2021-04-13 20:14:43 +00:00
|
|
|
@click.command(
|
|
|
|
short_help="Run all or a selection of services.",
|
|
|
|
help="Run all or a selection of services. Docker images will be rebuilt where necessary.",
|
|
|
|
)
|
2021-10-18 09:43:40 +00:00
|
|
|
@click.option("--skip-build", is_flag=True, help="Skip image building")
|
2020-01-08 18:38:13 +00:00
|
|
|
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
|
|
|
|
@click.argument("services", metavar="service", nargs=-1)
|
|
|
|
@click.pass_obj
|
2021-10-18 09:43:40 +00:00
|
|
|
def start(
|
2022-04-15 08:51:19 +00:00
|
|
|
context: BaseComposeContext,
|
|
|
|
skip_build: bool,
|
|
|
|
detach: bool,
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
services: list[str],
|
2021-10-18 09:43:40 +00:00
|
|
|
) -> None:
|
|
|
|
command = ["up", "--remove-orphans"]
|
|
|
|
if not skip_build:
|
|
|
|
command.append("--build")
|
2020-01-08 18:38:13 +00:00
|
|
|
if detach:
|
|
|
|
command.append("-d")
|
|
|
|
|
2021-04-13 20:14:43 +00:00
|
|
|
# Start services
|
2021-09-27 09:48:17 +00:00
|
|
|
config = tutor_config.load(context.root)
|
|
|
|
context.job_runner(config).docker_compose(*command, *services)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@click.command(help="Stop a running platform")
|
|
|
|
@click.argument("services", metavar="service", nargs=-1)
|
|
|
|
@click.pass_obj
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
def stop(context: BaseComposeContext, services: list[str]) -> None:
|
2020-01-08 18:38:13 +00:00
|
|
|
config = tutor_config.load(context.root)
|
2021-09-27 09:48:17 +00:00
|
|
|
context.job_runner(config).docker_compose("stop", *services)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@click.command(
|
|
|
|
short_help="Reboot an existing platform",
|
|
|
|
help="This is more than just a restart: with reboot, the platform is fully stopped before being restarted again",
|
|
|
|
)
|
|
|
|
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
|
|
|
|
@click.argument("services", metavar="service", nargs=-1)
|
2021-02-25 08:09:14 +00:00
|
|
|
@click.pass_context
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
def reboot(context: click.Context, detach: bool, services: list[str]) -> None:
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(stop, services=services)
|
|
|
|
context.invoke(start, detach=detach, services=services)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@click.command(
|
|
|
|
short_help="Restart some components from a running platform.",
|
|
|
|
help="""Specify 'openedx' to restart the lms, cms and workers, or 'all' to
|
|
|
|
restart all services. Note that this performs a 'docker-compose restart', so new images
|
|
|
|
may not be taken into account. It is useful for reloading settings, for instance. To
|
|
|
|
fully stop the platform, use the 'reboot' command.""",
|
|
|
|
)
|
2020-03-12 08:52:22 +00:00
|
|
|
@click.argument("services", metavar="service", nargs=-1)
|
2020-01-08 18:38:13 +00:00
|
|
|
@click.pass_obj
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
def restart(context: BaseComposeContext, services: list[str]) -> None:
|
2020-01-08 18:38:13 +00:00
|
|
|
config = tutor_config.load(context.root)
|
|
|
|
command = ["restart"]
|
2020-03-12 08:52:22 +00:00
|
|
|
if "all" in services:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
for service in services:
|
Improve job running in local and k8s
Running jobs was previously done with "exec". This was because it
allowed us to avoid copying too much container specification information
from the docker-compose/deployments files to the jobs files. However,
this was limiting:
- In order to run a job, the corresponding container had to be running.
This was particularly painful in Kubernetes, where containers are
crashing as long as migrations are not correctly run.
- Containers in which we need to run jobs needed to be present in the
docker-compose/deployments files. This is unnecessary, for example when
mysql is disabled, or in the case of the certbot container.
Now, we create dedicated jobs files, both for local and k8s deployment.
This introduces a little redundancy, but not too much. Note that
dependent containers are not listed in the docker-compose.jobs.yml file,
so an actual platform is still supposed to be running when we launch the
jobs.
This also introduces a subtle change: now, jobs go through the container
entrypoint prior to running. This is probably a good thing, as it will
avoid forgetting about incorrect environment variables.
In k8s, we find ourselves interacting way too much with the kubectl
utility. Parsing output from the CLI is a pain. So we need to switch to
the native kubernetes client library.
2020-03-25 17:47:36 +00:00
|
|
|
if service == "openedx":
|
2023-03-26 00:07:37 +00:00
|
|
|
command += ["lms", "lms-worker", "cms", "cms-worker"]
|
2020-03-12 08:52:22 +00:00
|
|
|
else:
|
|
|
|
command.append(service)
|
2021-09-27 09:48:17 +00:00
|
|
|
context.job_runner(config).docker_compose(*command)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
2022-10-19 15:46:31 +00:00
|
|
|
@jobs.do_group
|
2023-04-27 18:25:20 +00:00
|
|
|
def do() -> None:
|
2022-10-19 15:46:31 +00:00
|
|
|
"""
|
|
|
|
Run a custom job in the right container(s).
|
|
|
|
"""
|
2022-11-11 13:13:36 +00:00
|
|
|
|
2020-01-08 18:38:13 +00:00
|
|
|
|
2020-11-16 11:46:01 +00:00
|
|
|
@click.command(
|
|
|
|
short_help="Run a command in a new container",
|
|
|
|
help=(
|
|
|
|
"Run a command in a new container. This is a wrapper around `docker-compose run`. Any option or argument passed"
|
|
|
|
" to this command will be forwarded to docker-compose. Thus, you may use `-v` or `-p` to mount volumes and"
|
|
|
|
" expose ports."
|
|
|
|
),
|
|
|
|
context_settings={"ignore_unknown_options": True},
|
|
|
|
)
|
|
|
|
@click.argument("args", nargs=-1, required=True)
|
2021-02-25 08:09:14 +00:00
|
|
|
@click.pass_context
|
2022-04-15 08:51:19 +00:00
|
|
|
def run(
|
|
|
|
context: click.Context,
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
args: list[str],
|
2022-04-15 08:51:19 +00:00
|
|
|
) -> None:
|
2020-12-25 21:56:42 +00:00
|
|
|
extra_args = ["--rm"]
|
2020-11-16 11:46:01 +00:00
|
|
|
if not utils.is_a_tty():
|
2020-12-25 21:56:42 +00:00
|
|
|
extra_args.append("-T")
|
2023-04-27 18:25:20 +00:00
|
|
|
context.invoke(dc_command, command="run", args=[*extra_args, *args])
|
2020-12-25 21:56:42 +00:00
|
|
|
|
|
|
|
|
2022-04-20 20:24:17 +00:00
|
|
|
@click.command(
|
|
|
|
name="copyfrom",
|
|
|
|
help="Copy files/folders from a container directory to the local filesystem.",
|
|
|
|
)
|
|
|
|
@click.argument("service")
|
|
|
|
@click.argument("container_path")
|
|
|
|
@click.argument(
|
|
|
|
"host_path",
|
|
|
|
type=click.Path(dir_okay=True, file_okay=False, resolve_path=True),
|
|
|
|
)
|
|
|
|
@click.pass_obj
|
|
|
|
def copyfrom(
|
|
|
|
context: BaseComposeContext, service: str, container_path: str, host_path: str
|
|
|
|
) -> None:
|
|
|
|
# Path management
|
|
|
|
container_root_path = "/tmp/mount"
|
|
|
|
container_dst_path = container_root_path
|
|
|
|
if not os.path.exists(host_path):
|
|
|
|
# Emulate cp semantics, where if the destination path does not exist
|
|
|
|
# then we copy to its parent and rename to the destination folder
|
|
|
|
container_dst_path += "/" + os.path.basename(host_path)
|
|
|
|
host_path = os.path.dirname(host_path)
|
|
|
|
if not os.path.exists(host_path):
|
|
|
|
raise TutorError(
|
|
|
|
f"Cannot create directory {host_path}. No such file or directory."
|
|
|
|
)
|
|
|
|
|
|
|
|
# cp/mv commands
|
|
|
|
command = f"cp --recursive --preserve {container_path} {container_dst_path}"
|
|
|
|
config = tutor_config.load(context.root)
|
|
|
|
runner = context.job_runner(config)
|
|
|
|
runner.docker_compose(
|
|
|
|
"run",
|
|
|
|
"--rm",
|
|
|
|
"--no-deps",
|
|
|
|
"--user=0",
|
|
|
|
f"--volume={host_path}:{container_root_path}",
|
|
|
|
service,
|
|
|
|
"sh",
|
|
|
|
"-e",
|
|
|
|
"-c",
|
|
|
|
command,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-11-16 11:46:01 +00:00
|
|
|
@click.command(
|
|
|
|
short_help="Run a command in a running container",
|
|
|
|
help=(
|
|
|
|
"Run a command in a running container. This is a wrapper around `docker-compose exec`. Any option or argument"
|
|
|
|
" passed to this command will be forwarded to docker-compose. Thus, you may use `-e` to manually define"
|
|
|
|
" environment variables."
|
|
|
|
),
|
|
|
|
context_settings={"ignore_unknown_options": True},
|
|
|
|
name="exec",
|
|
|
|
)
|
|
|
|
@click.argument("args", nargs=-1, required=True)
|
2021-02-25 08:09:14 +00:00
|
|
|
@click.pass_context
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
def execute(context: click.Context, args: list[str]) -> None:
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(dc_command, command="exec", args=args)
|
2020-11-16 11:46:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
@click.command(
|
|
|
|
short_help="View output from containers",
|
|
|
|
help="View output from containers. This is a wrapper around `docker-compose logs`.",
|
|
|
|
)
|
|
|
|
@click.option("-f", "--follow", is_flag=True, help="Follow log output")
|
|
|
|
@click.option("--tail", type=int, help="Number of lines to show from each container")
|
|
|
|
@click.argument("service", nargs=-1)
|
2021-02-25 08:09:14 +00:00
|
|
|
@click.pass_context
|
|
|
|
def logs(context: click.Context, follow: bool, tail: bool, service: str) -> None:
|
2020-12-25 21:56:42 +00:00
|
|
|
args = []
|
2020-11-16 11:46:01 +00:00
|
|
|
if follow:
|
2020-12-25 21:56:42 +00:00
|
|
|
args.append("--follow")
|
2020-11-16 11:46:01 +00:00
|
|
|
if tail is not None:
|
2020-12-25 21:56:42 +00:00
|
|
|
args += ["--tail", str(tail)]
|
|
|
|
args += service
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(dc_command, command="logs", args=args)
|
2020-12-25 21:56:42 +00:00
|
|
|
|
|
|
|
|
2022-04-08 16:02:21 +00:00
|
|
|
@click.command(help="Print status information for containers")
|
|
|
|
@click.pass_context
|
|
|
|
def status(context: click.Context) -> None:
|
|
|
|
context.invoke(dc_command, command="ps")
|
|
|
|
|
|
|
|
|
2020-12-25 21:56:42 +00:00
|
|
|
@click.command(
|
|
|
|
short_help="Direct interface to docker-compose.",
|
|
|
|
help=(
|
|
|
|
"Direct interface to docker-compose. This is a wrapper around `docker-compose`. Most commands, options and"
|
|
|
|
" arguments passed to this command will be forwarded as-is to docker-compose."
|
|
|
|
),
|
|
|
|
context_settings={"ignore_unknown_options": True},
|
|
|
|
name="dc",
|
|
|
|
)
|
|
|
|
@click.argument("command")
|
2021-05-04 15:57:47 +00:00
|
|
|
@click.argument("args", nargs=-1)
|
2020-12-25 21:56:42 +00:00
|
|
|
@click.pass_obj
|
2022-07-25 17:19:28 +00:00
|
|
|
def dc_command(
|
|
|
|
context: BaseComposeContext,
|
|
|
|
command: str,
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
args: list[str],
|
2022-07-25 17:19:28 +00:00
|
|
|
) -> None:
|
2020-12-25 21:56:42 +00:00
|
|
|
config = tutor_config.load(context.root)
|
2022-10-18 12:40:32 +00:00
|
|
|
context.job_runner(config).docker_compose(command, *args)
|
2020-11-16 11:46:01 +00:00
|
|
|
|
|
|
|
|
2022-04-15 08:51:19 +00:00
|
|
|
@hooks.Filters.COMPOSE_MOUNTS.add()
|
|
|
|
def _mount_edx_platform(
|
refactor: annotation with __future__.annotations
Adds `from __future__ import annotations` to the top of every module,
right below the module's docstring. Replaces any usages of t.List,
t.Dict, t.Set, t.Tuple, and t.Type with their built-in equivalents:
list, dict, set, tuple, and type. Ensures that make test still passes
under Python 3.7, 3.8 and 3.9.
2023-01-17 18:57:23 +00:00
|
|
|
volumes: list[tuple[str, str]], name: str
|
|
|
|
) -> list[tuple[str, str]]:
|
2022-04-15 08:51:19 +00:00
|
|
|
"""
|
2023-04-27 18:25:20 +00:00
|
|
|
When mounting edx-platform with `tutor config save --append MOUNTS=/path/to/edx-platform`,
|
|
|
|
bind-mount the host repo in the lms/cms containers.
|
2022-04-15 08:51:19 +00:00
|
|
|
"""
|
|
|
|
if name == "edx-platform":
|
|
|
|
path = "/openedx/edx-platform"
|
|
|
|
volumes += [
|
|
|
|
("lms", path),
|
|
|
|
("cms", path),
|
|
|
|
("lms-worker", path),
|
|
|
|
("cms-worker", path),
|
|
|
|
("lms-job", path),
|
|
|
|
("cms-job", path),
|
|
|
|
]
|
|
|
|
return volumes
|
|
|
|
|
|
|
|
|
2023-04-27 18:25:20 +00:00
|
|
|
hooks.Filters.ENV_TEMPLATE_VARIABLES.add_item(("iter_mounts", bindmount.iter_mounts))
|
|
|
|
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def add_commands(command_group: click.Group) -> None:
|
2020-01-08 18:38:13 +00:00
|
|
|
command_group.add_command(start)
|
|
|
|
command_group.add_command(stop)
|
|
|
|
command_group.add_command(restart)
|
|
|
|
command_group.add_command(reboot)
|
2020-11-16 11:46:01 +00:00
|
|
|
command_group.add_command(dc_command)
|
|
|
|
command_group.add_command(run)
|
2022-04-20 20:24:17 +00:00
|
|
|
command_group.add_command(copyfrom)
|
2020-11-16 11:46:01 +00:00
|
|
|
command_group.add_command(execute)
|
|
|
|
command_group.add_command(logs)
|
2022-04-08 16:02:21 +00:00
|
|
|
command_group.add_command(status)
|
2022-10-19 15:46:31 +00:00
|
|
|
|
|
|
|
@hooks.Actions.PLUGINS_LOADED.add()
|
|
|
|
def _add_do_commands() -> None:
|
|
|
|
jobs.add_job_commands(do)
|
|
|
|
command_group.add_command(do)
|