More feature-complete dev/local docker-compose commands
By de-duplicating the code between dev.py and local.py, we are able to support more docker-compose run/up/stop options passed from tutor. To do so, we had to disable some features, such as automatically mounting the edx-platform repo when the TUTOR_EDX_PLATFORM_PATH environment variable was defined.
This commit is contained in:
parent
fcf2dd0d6f
commit
d17fdaa658
|
@ -2,6 +2,10 @@
|
|||
|
||||
Note: Breaking changes between versions are indicated by "💥".
|
||||
|
||||
## Unreleased
|
||||
|
||||
- 💥[Feature] `dev run/exec` commands now support generic options which are passed to docker-compose. Consequently, defining the `TUTOR_EDX_PLATFORM_PATH` environment variable no longer works. Instead, users are encouraged to explicitely pass the `-v` option or define a command alias.
|
||||
|
||||
## 3.9.1 (2020-01-08)
|
||||
|
||||
- [Improvement] Make it possible to override the project name in development mode
|
||||
|
|
47
docs/dev.rst
47
docs/dev.rst
|
@ -3,7 +3,7 @@
|
|||
Open edX development
|
||||
====================
|
||||
|
||||
In addition to running Open edX in production, Tutor can be used for local development of Open edX. This means it is possible to hack on Open edX without setting up a Virtual Machine. Essentially, this replaces the devstack provided by edX.
|
||||
In addition to running Open edX in production, Tutor can be used for local development of Open edX. This means that it is possible to hack on Open edX without setting up a Virtual Machine. Essentially, this replaces the devstack provided by edX.
|
||||
|
||||
The following commands assume you have previously launched a :ref:`local <local>` Open edX platform. If you have not done so already, you should run::
|
||||
|
||||
|
@ -58,15 +58,36 @@ To collect assets, you can use the standard ``update_assets`` Open edX command w
|
|||
Point to a local edx-platform
|
||||
-----------------------------
|
||||
|
||||
If you have one, you can point to a local version of `edx-platform <https://github.com/edx/edx-platform/>`_ on your host machine. To do so, pass a ``-P/--edx-platform-path`` option to the commands. For instance::
|
||||
If you have one, you can point to a local version of `edx-platform <https://github.com/edx/edx-platform/>`_ on your host machine. To do so, pass a ``-v/--volume`` option to the ``run`` and runserver commands. For instance::
|
||||
|
||||
tutor dev run --edx-platform-path=/path/to/edx-platform lms bash
|
||||
tutor dev run -v /path/to/edx-platform:/openedx/edx-platform lms bash
|
||||
|
||||
If you don't want to rewrite this option every time, you can instead define the environment variable::
|
||||
If you don't want to rewrite this option every time, you can define a command alias::
|
||||
|
||||
export TUTOR_EDX_PLATFORM_PATH=/path/to/edx-platform
|
||||
alias tutor-dev-run-lms="tutor dev run -v /path/to/edx-platform:/openedx/edx-platform lms"
|
||||
|
||||
All development commands will then automatically mount your local repo.
|
||||
For technical reasons, the ``-v`` option is only supported for the ``run`` and ``runserver`` commands. With these commands, only one service is started. But there are cases where you may want to launch and debug a complete Open edX platform with ``tutor dev start`` and mount a custom edx-platform fork. For instance, this might be needed when testing the interaction between multiple services. To do so, you should create a ``docker-compose.override.yml`` file that will specify a custom volume to be used with all ``dev`` commands::
|
||||
|
||||
vim "$(tutor config printroot)/env/dev/docker-compose.override.yml"
|
||||
|
||||
Then, add the following content::
|
||||
|
||||
version: "3.7"
|
||||
services:
|
||||
lms:
|
||||
volumes:
|
||||
- /path/to/edx-platform/:/openedx/edx-platform
|
||||
cms:
|
||||
volumes:
|
||||
- /path/to/edx-platform/:/openedx/edx-platform
|
||||
lms_worker:
|
||||
volumes:
|
||||
- /path/to/edx-platform/:/openedx/edx-platform
|
||||
cms_worker:
|
||||
volumes:
|
||||
- /path/to/edx-platform/:/openedx/edx-platform
|
||||
|
||||
This override file will be loaded when running any ``tutor dev ..`` command. The edx-platform repo mounted at the specified path will be automaticall mounted inside all LMS and CMS containers. With this file, you should no longer specify the ``-v`` option from the command line with the ``run`` or ``runserver`` commands.
|
||||
|
||||
**Note:** containers are built on the Ironwood release. If you are working on a different version of Open edX, you will have to rebuild the ``openedx`` docker images with the version. See the :ref:`fork edx-platform section <edx_platform_fork>`.
|
||||
|
||||
|
@ -75,17 +96,17 @@ Prepare the edx-platform repo
|
|||
|
||||
In order to run a fork of edx-platform, dependencies need to be properly installed and assets compiled in that repo. To do so, run::
|
||||
|
||||
export TUTOR_EDX_PLATFORM_PATH=/path/to/edx-platform
|
||||
tutor dev run lms pip install --requirement requirements/edx/development.txt
|
||||
tutor dev run lms python setup.py install
|
||||
tutor dev run lms paver update_assets --settings=tutor.development
|
||||
tutor dev run -v /path/to/edx-platform:/openedx/edx-platform lms bash
|
||||
pip install --requirement requirements/edx/development.txt
|
||||
python setup.py install
|
||||
paver update_assets --settings=tutor.development
|
||||
|
||||
Debug edx-platform
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To debug a local edx-platform repository, add a ``import ipdb; ipdb.set_trace()`` breakpoint anywhere in your code and run::
|
||||
|
||||
tutor dev runserver lms --edx-platform-path=/path/to/edx-platform
|
||||
tutor dev runserver -v /path/to/edx-platform:/openedx/edx-platform lms
|
||||
|
||||
Customised themes
|
||||
-----------------
|
||||
|
@ -115,7 +136,7 @@ Custom edx-platform settings
|
|||
|
||||
By default, tutor settings files are mounted inside the docker images at ``/openedx/edx-platform/lms/envs/tutor/`` and ``/openedx/edx-platform/cms/envs/tutor/``. In the various ``dev`` commands, the default ``edx-platform`` settings module is set to ``tutor.development`` and you don't have to do anything to set up these settings.
|
||||
|
||||
If, for some reason, you want to use different settings, you will need to pass the ``-S/--edx-platform-settings`` option to each command. Alternatively, you can define the ``TUTOR_EDX_PLATFORM_SETTINGS`` environment variable.
|
||||
If, for some reason, you want to use different settings, you will need to pass the ``-e SETTINGS=mycustomsettings`` option to each command. Alternatively, you can define the ``TUTOR_EDX_PLATFORM_SETTINGS`` environment variable.
|
||||
|
||||
For instance, let's assume you have created the ``/path/to/edx-platform/lms/envs/mysettings.py`` and ``/path/to/edx-platform/cms/envs/mysettings.py`` modules. These settings should be pretty similar to the following files::
|
||||
|
||||
|
@ -133,4 +154,4 @@ You should then specify the settings to use on the host::
|
|||
|
||||
From then on, all ``dev`` commands will use the ``mysettings`` module. For instance::
|
||||
|
||||
tutor dev runserver lms --edx-platform-path=/path/to/edx-platform
|
||||
tutor dev runserver -v /path/to/edx-platform:/openedx/edx-platform lms
|
||||
|
|
|
@ -7,6 +7,7 @@ import click_repl
|
|||
|
||||
from .android import android
|
||||
from .config import config_command
|
||||
from .context import Context
|
||||
from .dev import dev
|
||||
from .images import images_command
|
||||
from .k8s import k8s
|
||||
|
@ -19,12 +20,6 @@ from .. import exceptions
|
|||
from .. import fmt
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class Context:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
cli() # pylint: disable=no-value-for-parameter
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
import click
|
||||
|
||||
from .. import config as tutor_config
|
||||
from .. import fmt
|
||||
from .. import scripts
|
||||
|
||||
|
||||
class ScriptRunner(scripts.BaseRunner):
|
||||
def __init__(self, root, config, docker_compose_func):
|
||||
super().__init__(root, config)
|
||||
self.docker_compose_func = docker_compose_func
|
||||
|
||||
def exec(self, service, command):
|
||||
self.docker_compose_func(
|
||||
self.root, self.config, "exec", service, "sh", "-e", "-c", command
|
||||
)
|
||||
|
||||
|
||||
@click.command(help="Update docker images")
|
||||
@click.pass_obj
|
||||
def pullimages(context):
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, "pull")
|
||||
|
||||
|
||||
@click.command(help="Run all or a selection of configured Open edX services")
|
||||
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
|
||||
@click.argument("services", metavar="service", nargs=-1)
|
||||
@click.pass_obj
|
||||
def start(context, detach, services):
|
||||
command = ["up", "--remove-orphans"]
|
||||
if detach:
|
||||
command.append("-d")
|
||||
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, *command, *services)
|
||||
|
||||
|
||||
@click.command(help="Stop a running platform")
|
||||
@click.argument("services", metavar="service", nargs=-1)
|
||||
@click.pass_obj
|
||||
def stop(context, services):
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, "rm", "--stop", "--force", *services)
|
||||
|
||||
|
||||
@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)
|
||||
def reboot(detach, services):
|
||||
stop.callback(services)
|
||||
start.callback(detach, services)
|
||||
|
||||
|
||||
@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.""",
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.pass_obj
|
||||
def restart(context, service):
|
||||
config = tutor_config.load(context.root)
|
||||
command = ["restart"]
|
||||
if service == "openedx":
|
||||
if config["ACTIVATE_LMS"]:
|
||||
command += ["lms", "lms_worker"]
|
||||
if config["ACTIVATE_CMS"]:
|
||||
command += ["cms", "cms_worker"]
|
||||
elif service != "all":
|
||||
command += [service]
|
||||
context.docker_compose(context.root, config, *command)
|
||||
|
||||
|
||||
@click.command(
|
||||
short_help="Run a command in a new container",
|
||||
help="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)
|
||||
@click.pass_obj
|
||||
def run(context, args):
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, "run", "--rm", *args)
|
||||
|
||||
|
||||
@click.command(
|
||||
short_help="Run a command in a running container",
|
||||
help="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)
|
||||
@click.pass_obj
|
||||
def execute(context, args):
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, "exec", *args)
|
||||
|
||||
|
||||
@click.command(help="Initialise all applications")
|
||||
@click.pass_obj
|
||||
def init(context):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config, context.docker_compose)
|
||||
scripts.initialise(runner)
|
||||
|
||||
|
||||
@click.command(
|
||||
short_help="Manually trigger hook (advanced users only)",
|
||||
help="""
|
||||
Manually trigger a hook for a given plugin/service. This is a low-level command
|
||||
that is convenient when developing new plugins. Ex:
|
||||
|
||||
tutor local hook mysql hooks mysql init
|
||||
tutor local hook discovery discovery hooks discovery init""",
|
||||
name="hook",
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.argument("path", nargs=-1)
|
||||
@click.pass_obj
|
||||
def run_hook(context, service, path):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config, context.docker_compose)
|
||||
fmt.echo_info(
|
||||
"Running '{}' hook in '{}' container...".format(".".join(path), service)
|
||||
)
|
||||
runner.run(service, *path)
|
||||
|
||||
|
||||
@click.command(help="View output from containers")
|
||||
@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)
|
||||
@click.pass_obj
|
||||
def logs(context, follow, tail, service):
|
||||
command = ["logs"]
|
||||
if follow:
|
||||
command += ["--follow"]
|
||||
if tail is not None:
|
||||
command += ["--tail", str(tail)]
|
||||
command += service
|
||||
config = tutor_config.load(context.root)
|
||||
context.docker_compose(context.root, config, *command)
|
||||
|
||||
|
||||
@click.command(help="Create an Open edX user and interactively set their password")
|
||||
@click.option("--superuser", is_flag=True, help="Make superuser")
|
||||
@click.option("--staff", is_flag=True, help="Make staff user")
|
||||
@click.option(
|
||||
"-p",
|
||||
"--password",
|
||||
help="Specify password from the command line. If undefined, you will be prompted to input a password",
|
||||
)
|
||||
@click.argument("name")
|
||||
@click.argument("email")
|
||||
@click.pass_obj
|
||||
def createuser(context, superuser, staff, password, name, email):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config, context.docker_compose)
|
||||
runner.check_service_is_activated("lms")
|
||||
command = scripts.create_user_command(
|
||||
superuser, staff, name, email, password=password
|
||||
)
|
||||
runner.exec("lms", command)
|
||||
|
||||
|
||||
@click.command(help="Import the demo course")
|
||||
@click.pass_obj
|
||||
def importdemocourse(context):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config, context.docker_compose)
|
||||
fmt.echo_info("Importing demo course")
|
||||
scripts.import_demo_course(runner)
|
||||
|
||||
|
||||
def add_commands(command_group):
|
||||
command_group.add_command(pullimages)
|
||||
command_group.add_command(start)
|
||||
command_group.add_command(stop)
|
||||
command_group.add_command(restart)
|
||||
command_group.add_command(reboot)
|
||||
command_group.add_command(run)
|
||||
command_group.add_command(execute)
|
||||
command_group.add_command(init)
|
||||
command_group.add_command(logs)
|
||||
command_group.add_command(createuser)
|
||||
command_group.add_command(importdemocourse)
|
||||
# command_group.add_command(run_hook) # Disabled for now
|
|
@ -0,0 +1,4 @@
|
|||
# pylint: disable=too-few-public-methods
|
||||
class Context:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
|
@ -1,150 +1,55 @@
|
|||
import click
|
||||
|
||||
from .. import config as tutor_config
|
||||
from . import compose
|
||||
from .context import Context
|
||||
from .. import env as tutor_env
|
||||
from .. import fmt
|
||||
from .. import utils
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class DevContext(Context):
|
||||
@staticmethod
|
||||
def docker_compose(root, config, *command):
|
||||
return utils.docker_compose(
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "local", "docker-compose.yml"),
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "dev", "docker-compose.yml"),
|
||||
"--project-name",
|
||||
config["DEV_PROJECT_NAME"],
|
||||
*command,
|
||||
)
|
||||
|
||||
|
||||
@click.group(help="Run Open edX platform with development settings")
|
||||
def dev():
|
||||
pass
|
||||
|
||||
|
||||
edx_platform_path_option = click.option(
|
||||
"-P",
|
||||
"--edx-platform-path",
|
||||
envvar="TUTOR_EDX_PLATFORM_PATH",
|
||||
type=click.Path(exists=True, dir_okay=True, resolve_path=True),
|
||||
help="Mount a local edx-platform from the host (environment variable: TUTOR_EDX_PLATFORM_PATH)",
|
||||
)
|
||||
|
||||
edx_platform_development_settings_option = click.option(
|
||||
"-S",
|
||||
"--edx-platform-settings",
|
||||
envvar="TUTOR_EDX_PLATFORM_SETTINGS",
|
||||
default="tutor.development",
|
||||
help="Load custom development settings (environment variable: TUTOR_EDX_PLATFORM_SETTINGS)",
|
||||
)
|
||||
@click.pass_context
|
||||
def dev(context):
|
||||
context.obj = DevContext(context.obj.root)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="Run all or a selection of configured Open edX services in development mode"
|
||||
help="Run a development server", context_settings={"ignore_unknown_options": True},
|
||||
)
|
||||
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
|
||||
@click.argument("services", metavar="service", nargs=-1)
|
||||
@click.pass_obj
|
||||
def start(context, detach, services):
|
||||
"""
|
||||
TODO document this
|
||||
"""
|
||||
command = ["up", "--remove-orphans"]
|
||||
if detach:
|
||||
command.append("-d")
|
||||
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *command, *services)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="Run a command in one of the containers",
|
||||
context_settings={"ignore_unknown_options": True},
|
||||
)
|
||||
@edx_platform_path_option
|
||||
@edx_platform_development_settings_option
|
||||
@click.argument("service")
|
||||
@click.argument("command", default=None, required=False)
|
||||
@click.argument("args", nargs=-1)
|
||||
@click.pass_obj
|
||||
def run(context, edx_platform_path, edx_platform_settings, service, command, args):
|
||||
run_command = [service]
|
||||
if command:
|
||||
run_command.append(command)
|
||||
if args:
|
||||
run_command += args
|
||||
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose_run(
|
||||
context.root, config, edx_platform_path, edx_platform_settings, *run_command
|
||||
)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="Exec a command in a running container",
|
||||
context_settings={"ignore_unknown_options": True},
|
||||
name="exec",
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.argument("command")
|
||||
@click.argument("args", nargs=-1)
|
||||
@click.pass_obj
|
||||
def execute(context, service, command, args):
|
||||
exec_command = ["exec", service, command]
|
||||
if args:
|
||||
exec_command += args
|
||||
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *exec_command)
|
||||
|
||||
|
||||
@click.command(help="Run a development server")
|
||||
@edx_platform_path_option
|
||||
@edx_platform_development_settings_option
|
||||
@click.argument("options", nargs=-1, required=False)
|
||||
@click.argument("service", type=click.Choice(["lms", "cms"]))
|
||||
@click.pass_obj
|
||||
def runserver(context, edx_platform_path, edx_platform_settings, service):
|
||||
def runserver(options, service):
|
||||
port = 8000 if service == "lms" else 8001
|
||||
|
||||
fmt.echo_info(
|
||||
"The {} service will be available at http://localhost:{}".format(service, port)
|
||||
)
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose_run(
|
||||
context.root,
|
||||
config,
|
||||
edx_platform_path,
|
||||
edx_platform_settings,
|
||||
args = [
|
||||
"-p",
|
||||
"{port}:{port}".format(port=port),
|
||||
*options,
|
||||
service,
|
||||
"./manage.py",
|
||||
service,
|
||||
"runserver",
|
||||
"0.0.0.0:{}".format(port),
|
||||
)
|
||||
]
|
||||
compose.run.callback(args)
|
||||
|
||||
|
||||
@click.command(help="Stop a running development platform")
|
||||
@click.pass_obj
|
||||
def stop(context):
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, "rm", "--stop", "--force")
|
||||
|
||||
|
||||
def docker_compose_run(
|
||||
root, config, edx_platform_path, edx_platform_settings, *command
|
||||
):
|
||||
run_command = ["run", "--rm", "-e", "SETTINGS={}".format(edx_platform_settings)]
|
||||
if edx_platform_path:
|
||||
run_command += ["--volume={}:/openedx/edx-platform".format(edx_platform_path)]
|
||||
run_command += command
|
||||
docker_compose(root, config, *run_command)
|
||||
|
||||
|
||||
def docker_compose(root, config, *command):
|
||||
return utils.docker_compose(
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "local", "docker-compose.yml"),
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "dev", "docker-compose.yml"),
|
||||
"--project-name",
|
||||
config["DEV_PROJECT_NAME"],
|
||||
*command
|
||||
)
|
||||
|
||||
|
||||
dev.add_command(start)
|
||||
dev.add_command(run)
|
||||
dev.add_command(execute)
|
||||
dev.add_command(runserver)
|
||||
dev.add_command(stop)
|
||||
compose.add_commands(dev)
|
||||
|
|
|
@ -2,20 +2,35 @@ from textwrap import indent
|
|||
|
||||
import click
|
||||
|
||||
from . import compose
|
||||
from .context import Context
|
||||
from .. import config as tutor_config
|
||||
from .. import env as tutor_env
|
||||
from .. import fmt
|
||||
from .. import interactive as interactive_config
|
||||
from .. import scripts
|
||||
from .. import utils
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
class LocalContext(Context):
|
||||
@staticmethod
|
||||
def docker_compose(root, config, *command):
|
||||
return utils.docker_compose(
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "local", "docker-compose.yml"),
|
||||
"--project-name",
|
||||
config["LOCAL_PROJECT_NAME"],
|
||||
*command
|
||||
)
|
||||
|
||||
|
||||
@click.group(
|
||||
short_help="Run Open edX locally",
|
||||
help="Run Open edX platform locally, with docker-compose.",
|
||||
)
|
||||
def local():
|
||||
pass
|
||||
@click.pass_context
|
||||
def local(context):
|
||||
context.obj = LocalContext(context.obj.root)
|
||||
|
||||
|
||||
@click.command(help="Configure and run Open edX from scratch")
|
||||
|
@ -30,39 +45,19 @@ def quickstart(context, non_interactive, pullimages_):
|
|||
click.echo(fmt.title("Updating the current environment"))
|
||||
tutor_env.save(context.root, config)
|
||||
click.echo(fmt.title("Stopping any existing platform"))
|
||||
stop.callback([])
|
||||
compose.stop.callback([])
|
||||
click.echo(fmt.title("HTTPS certificates generation"))
|
||||
https_create.callback()
|
||||
if pullimages_:
|
||||
click.echo(fmt.title("Docker image updates"))
|
||||
pullimages.callback()
|
||||
compose.pullimages.callback()
|
||||
click.echo(fmt.title("Starting the platform in detached mode"))
|
||||
start.callback(True, [])
|
||||
compose.start.callback(True, [])
|
||||
click.echo(fmt.title("Database creation and migrations"))
|
||||
init.callback()
|
||||
compose.init.callback()
|
||||
echo_platform_info(config)
|
||||
|
||||
|
||||
@click.command(help="Update docker images")
|
||||
@click.pass_obj
|
||||
def pullimages(context):
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, "pull")
|
||||
|
||||
|
||||
@click.command(help="Run all or a selection of configured Open edX services")
|
||||
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
|
||||
@click.argument("services", metavar="service", nargs=-1)
|
||||
@click.pass_obj
|
||||
def start(context, detach, services):
|
||||
command = ["up", "--remove-orphans"]
|
||||
if detach:
|
||||
command.append("-d")
|
||||
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *command, *services)
|
||||
|
||||
|
||||
def echo_platform_info(config):
|
||||
fmt.echo_info("The Open edX platform is now running in detached mode")
|
||||
http = "https" if config["ACTIVATE_HTTPS"] else "http"
|
||||
|
@ -80,115 +75,6 @@ def echo_platform_info(config):
|
|||
)
|
||||
|
||||
|
||||
@click.command(help="Stop a running platform")
|
||||
@click.argument("services", metavar="service", nargs=-1)
|
||||
@click.pass_obj
|
||||
def stop(context, services):
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, "rm", "--stop", "--force", *services)
|
||||
|
||||
|
||||
@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)
|
||||
def reboot(detach, services):
|
||||
stop.callback(services)
|
||||
start.callback(detach, services)
|
||||
|
||||
|
||||
@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.""",
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.pass_obj
|
||||
def restart(context, service):
|
||||
config = tutor_config.load(context.root)
|
||||
command = ["restart"]
|
||||
if service == "openedx":
|
||||
if config["ACTIVATE_LMS"]:
|
||||
command += ["lms", "lms_worker"]
|
||||
if config["ACTIVATE_CMS"]:
|
||||
command += ["cms", "cms_worker"]
|
||||
elif service != "all":
|
||||
command += [service]
|
||||
docker_compose(context.root, config, *command)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="Run a command in one of the containers",
|
||||
context_settings={"ignore_unknown_options": True},
|
||||
)
|
||||
@click.option("--entrypoint", help="Override the entrypoint of the image")
|
||||
@click.argument("service")
|
||||
@click.argument("command", default=None, required=False)
|
||||
@click.argument("args", nargs=-1)
|
||||
@click.pass_obj
|
||||
def run(context, entrypoint, service, command, args):
|
||||
run_command = ["run", "--rm"]
|
||||
if entrypoint:
|
||||
run_command += ["--entrypoint", entrypoint]
|
||||
run_command.append(service)
|
||||
if command:
|
||||
run_command.append(command)
|
||||
if args:
|
||||
run_command += args
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *run_command)
|
||||
|
||||
|
||||
@click.command(
|
||||
help="Exec a command in a running container",
|
||||
context_settings={"ignore_unknown_options": True},
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.argument("command")
|
||||
@click.argument("args", nargs=-1)
|
||||
@click.pass_obj
|
||||
def execute(context, service, command, args):
|
||||
exec_command = ["exec", service, command]
|
||||
if args:
|
||||
exec_command += args
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *exec_command)
|
||||
|
||||
|
||||
@click.command(help="Initialise all applications")
|
||||
@click.pass_obj
|
||||
def init(context):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config)
|
||||
scripts.initialise(runner)
|
||||
|
||||
|
||||
@click.command(
|
||||
short_help="Manually trigger hook (advanced users only)",
|
||||
help="""
|
||||
Manually trigger a hook for a given plugin/service. This is a low-level command
|
||||
that is convenient when developing new plugins. Ex:
|
||||
|
||||
tutor local hook mysql hooks mysql init
|
||||
tutor local hook discovery discovery hooks discovery init""",
|
||||
name="hook",
|
||||
)
|
||||
@click.argument("service")
|
||||
@click.argument("path", nargs=-1)
|
||||
@click.pass_obj
|
||||
def run_hook(context, service, path):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config)
|
||||
fmt.echo_info(
|
||||
"Running '{}' hook in '{}' container...".format(".".join(path), service)
|
||||
)
|
||||
runner.run(service, *path)
|
||||
|
||||
|
||||
@click.group(help="Manage https certificates")
|
||||
def https():
|
||||
pass
|
||||
|
@ -205,7 +91,7 @@ def https_create(context):
|
|||
2. On certificate renewal, nginx is not reloaded
|
||||
"""
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config)
|
||||
runner = compose.ScriptRunner(context.root, config, context.docker_compose)
|
||||
if not config["ACTIVATE_HTTPS"]:
|
||||
fmt.echo_info("HTTPS is not activated: certificate generation skipped")
|
||||
return
|
||||
|
@ -268,83 +154,8 @@ See the official certbot documentation for your platform: https://certbot.eff.or
|
|||
utils.docker_run(*docker_run)
|
||||
|
||||
|
||||
@click.command(help="View output from containers")
|
||||
@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)
|
||||
@click.pass_obj
|
||||
def logs(context, follow, tail, service):
|
||||
command = ["logs"]
|
||||
if follow:
|
||||
command += ["--follow"]
|
||||
if tail is not None:
|
||||
command += ["--tail", str(tail)]
|
||||
command += service
|
||||
config = tutor_config.load(context.root)
|
||||
docker_compose(context.root, config, *command)
|
||||
|
||||
|
||||
@click.command(help="Create an Open edX user and interactively set their password")
|
||||
@click.option("--superuser", is_flag=True, help="Make superuser")
|
||||
@click.option("--staff", is_flag=True, help="Make staff user")
|
||||
@click.option(
|
||||
"-p",
|
||||
"--password",
|
||||
help="Specify password from the command line. If undefined, you will be prompted to input a password",
|
||||
)
|
||||
@click.argument("name")
|
||||
@click.argument("email")
|
||||
@click.pass_obj
|
||||
def createuser(context, superuser, staff, password, name, email):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config)
|
||||
runner.check_service_is_activated("lms")
|
||||
command = scripts.create_user_command(
|
||||
superuser, staff, name, email, password=password
|
||||
)
|
||||
runner.exec("lms", command)
|
||||
|
||||
|
||||
@click.command(help="Import the demo course")
|
||||
@click.pass_obj
|
||||
def importdemocourse(context):
|
||||
config = tutor_config.load(context.root)
|
||||
runner = ScriptRunner(context.root, config)
|
||||
fmt.echo_info("Importing demo course")
|
||||
scripts.import_demo_course(runner)
|
||||
|
||||
|
||||
class ScriptRunner(scripts.BaseRunner):
|
||||
def exec(self, service, command):
|
||||
docker_compose(
|
||||
self.root, self.config, "exec", service, "sh", "-e", "-c", command
|
||||
)
|
||||
|
||||
|
||||
def docker_compose(root, config, *command):
|
||||
return utils.docker_compose(
|
||||
"-f",
|
||||
tutor_env.pathjoin(root, "local", "docker-compose.yml"),
|
||||
"--project-name",
|
||||
config["LOCAL_PROJECT_NAME"],
|
||||
*command
|
||||
)
|
||||
|
||||
|
||||
https.add_command(https_create)
|
||||
https.add_command(https_renew)
|
||||
|
||||
local.add_command(quickstart)
|
||||
local.add_command(pullimages)
|
||||
local.add_command(start)
|
||||
local.add_command(stop)
|
||||
local.add_command(restart)
|
||||
local.add_command(reboot)
|
||||
local.add_command(run)
|
||||
local.add_command(execute, name="exec")
|
||||
local.add_command(init)
|
||||
local.add_command(run_hook)
|
||||
local.add_command(https)
|
||||
local.add_command(logs)
|
||||
local.add_command(createuser)
|
||||
local.add_command(importdemocourse)
|
||||
local.add_command(quickstart)
|
||||
compose.add_commands(local)
|
||||
|
|
|
@ -4,6 +4,8 @@ services:
|
|||
x-openedx-service:
|
||||
&openedx-service
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX_DEV }}
|
||||
environment:
|
||||
SETTINGS: ${TUTOR_EDX_PLATFORM_SETTINGS:-tutor.development}
|
||||
volumes:
|
||||
# theme files
|
||||
- ../build/openedx/themes:/openedx/themes
|
||||
|
|
Loading…
Reference in New Issue