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:
Régis Behmo 2020-01-08 19:38:13 +01:00
parent fcf2dd0d6f
commit d17fdaa658
8 changed files with 290 additions and 355 deletions

View File

@ -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

View File

@ -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

View File

@ -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

193
tutor/commands/compose.py Normal file
View File

@ -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

View File

@ -0,0 +1,4 @@
# pylint: disable=too-few-public-methods
class Context:
def __init__(self, root):
self.root = root

View File

@ -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)

View File

@ -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)

View File

@ -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