Skip to content

Commit

Permalink
feat: introduce 'tutor dev quickstart'
Browse files Browse the repository at this point in the history
Add `tutor dev quickstart` command, which is equivalent to
`tutor local quickstart`, but uses dev containers instead
of local production ones. This should remove some friction
from the Open edX development setup process, which previously
required that users provision using local producation
containers but then stop them and switch to dev containers:
 * tutor local quickstart
 * tutor local stop
 * tutor dev start -d

Fixes openedx-unsupported/wg-developer-experience#58
  • Loading branch information
kdmccormick committed Apr 5, 2022
1 parent 6d46955 commit 7a02d9e
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 64 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Note: Breaking changes between versions are indicated by "💥".

## Unreleased

- [Feature] Add `tutor dev quickstart` command, which is equivalent to `tutor local quickstart`, but uses dev containers instead of local production ones. This should remove some friction from the Open edX development setup process, which previously required that users provision using local producation containers (`tutor local quickstart`) but then stop them and switch to dev containers (`tutor local stop && tutor dev start -d`).

## v13.1.8 (2022-03-18)

- [Bugfix] Fix "evalsymlink failure" during `k8s quickstart` (#611).
Expand Down
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ Quickstart
----------

1. Install the `latest stable release <https://github.com/overhangio/tutor/releases>`_ of Tutor
2. Run ``tutor local quickstart``
2. Run one of these commands:
* ``tutor local quickstart`` (for production deployment)
* ``tutor dev quickstart`` (for development)
3. You're done!

Documentation
Expand Down
2 changes: 1 addition & 1 deletion docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This section does not cover :ref:`plugin development <plugins>`. For simple chan
Configuration
-------------

With Tutor, all Open edX deployment parameters are stored in a single ``config.yml`` file. This is the file that is generated when you run ``tutor local quickstart`` or ``tutor config save``. To view the content of this file, run::
With Tutor, all Open edX deployment parameters are stored in a single ``config.yml`` file. This is the file that is generated when you run ``tutor ... quickstart`` or ``tutor config save``. To view the content of this file, run::

cat "$(tutor config printroot)/config.yml"

Expand Down
54 changes: 37 additions & 17 deletions docs/dev.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,57 @@ Open edX development

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::
.. warning::

tutor local quickstart
Do not run ``tutor dev ...`` commands on a production system. They can modify your configuration and database in ways that are nonsensical or insecure for production use.

To run the platform in development mode, you **must** answer no ("n") to the question "Are you configuring a production platform".
Start by launching a development platform::

Note that the local.overhang.io `domain <https://dnschecker.org/#A/local.overhang.io>`__ and its `subdomains <https://dnschecker.org/#CNAME/studio.local.overhang.io>`__ all point to 127.0.0.1. This is just a domain name that was set up to conveniently access a locally running Open edX platform.
tutor dev quickstart

Once the local platform has been configured, you should stop it so that it does not interfere with the development environment::
This will perform several tasks:

tutor local stop
* Stop any existing locally-running Tutor containers.

Finally, you should build the ``openedx-dev`` docker image::
* Disable HTTPS and configure your ``LMS_HOST`` to local.overhang.io. This `domain <https://dnschecker.org/#A/local.overhang.io>`__ and its `subdomains <https://dnschecker.org/#CNAME/studio.local.overhang.io>`__ were set up to point to 127.0.0.1, allowing Tutor users to conveniently access a locally running Open edX platform.

tutor dev dc build lms
* Prompt for a platform name, contact email, and language. The provided defaults are sufficient for development.

This ``openedx-dev`` development image differs from the ``openedx`` production image:
* Offer to import the demo course and create a superuser.

- The user that runs inside the container has the same UID as the user on the host, to avoid permission problems inside mounted volumes (and in particular in the edx-platform repository).
- Additional python and system requirements are installed for convenient debugging: `ipython <https://ipython.org/>`__, `ipdb <https://pypi.org/project/ipdb/>`__, vim, telnet.
- The edx-platform `development requirements <https://github.com/openedx/edx-platform/blob/open-release/maple.master/requirements/edx/development.in>`__ are installed.
* Build an ``openedx-dev`` development image, which differs from the ``openedx`` production image:

Since the ``openedx-dev`` is based upon the ``openedx`` docker image, it should be re-built every time the ``openedx`` docker image is modified.
- The user that runs inside the container has the same UID as the user on the host, to avoid permission problems inside mounted volumes (and in particular in the edx-platform repository).
- Additional python and system requirements are installed for convenient debugging: `ipython <https://ipython.org/>`__, `ipdb <https://pypi.org/project/ipdb/>`__, vim, telnet.
- The edx-platform `development requirements <https://github.com/openedx/edx-platform/blob/open-release/maple.master/requirements/edx/development.in>`__ are installed.

Run a local development webserver
---------------------------------
- Note: Since the ``openedx-dev`` is based upon the ``openedx`` docker image, it should be re-built every time the ``openedx`` docker image is modified. To rebuild the image without running ``quickstart`` again, you can run ``tutor dev dc build lms``.

* Start your platform and ensure databases are provisioned.

Once setup is complete, the platform will be running in the background:

* LMS will be accessible at `http://local.overhang.io:8000 <http://local.overhang.io:8000>`_.
* CMS will be accessible at `http://studio.local.overhang.io:8001 <http://studio.local.overhang.io:8001>`_.

Stopping the platform
---------------------

::

tutor dev runserver lms # Access the lms at http://local.overhang.io:8000
tutor dev runserver cms # Access the cms at http://studio.local.overhang.io:8001
tutor dev stop


Starting the platform, again
----------------------------

In the same terminal ("attached")::

tutor dev start

Or, in the background ("detached")::

tutor dev start -d

Running arbitrary commands
--------------------------
Expand Down
3 changes: 2 additions & 1 deletion docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ To upgrade Open edX or benefit from the latest features and bug fixes, you shoul

pip install --upgrade tutor[full]

Then run the ``quickstart`` command again. Depending on your deployment target, run either::
Then run the ``quickstart`` command again. Depending on your deployment target, run one of::

tutor local quickstart # for local installations
tutor k8s quickstart # for Kubernetes installation
tutor dev quickstart # for development installations

Upgrading with custom Docker images
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 3 additions & 3 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ Tutor commands are structured in an easy-to-follow hierarchy. At the top level,

Within each mode, Tutor has subcommands for managing that type of Open edX instance. Many of them are common between modes, such as ``quickstart``, ``start``, ``stop``, ``exec``, and ``logs``. For example::

tutor local logs lms # View logs of a locally-deployed LMS.
tutor k8s logs lms # View logs of a Kubernetes-managed LMS.
tutor dev logs lms # View logs of a development-mode LMS.
tutor local logs # View logs of a local deployment.
tutor k8s logs # View logs of a Kubernetes-managed deployment.
tutor dev logs # View logs of a development platform.

Finally, the ``tutor config ...`` and ``tutor images ...`` commands contain subcommands for configuring your environment and managing Docker images, respectively. These commands are not specific to any mode of Tutor deployment. For example, to pull images suitable for any type of deployment, you would use::

Expand Down
5 changes: 4 additions & 1 deletion docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ Or `download <https://github.com/overhangio/tutor/releases>`_ the pre-compiled b

.. include:: download/binary.rst

2. Run ``tutor local quickstart``
2. Run one of these commands:
* ``tutor local quickstart`` (for production usage)
* ``tutor dev quickstart`` (for development usage)

3. You're done!

**That's it?**
Expand Down
8 changes: 7 additions & 1 deletion tests/commands/test_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from click.testing import CliRunner

from tutor.commands.compose import bindmount_command
from tutor.commands.dev import dev
from tutor.commands.dev import dev, quickstart


class DevTests(unittest.TestCase):
Expand All @@ -13,6 +13,12 @@ def test_dev_help(self) -> None:
self.assertEqual(0, result.exit_code)
self.assertIsNone(result.exception)

def test_local_quickstart_help(self) -> None:
runner = CliRunner()
result = runner.invoke(quickstart, ["--help"])
self.assertEqual(0, result.exit_code)
self.assertIsNone(result.exception)

def test_dev_bindmount(self) -> None:
runner = CliRunner()
result = runner.invoke(bindmount_command, ["--help"])
Expand Down
4 changes: 3 additions & 1 deletion tutor/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ def save(
unset_vars: List[str],
env_only: bool,
) -> None:
config = interactive_config.load_user_config(context.root, interactive=interactive)
config = interactive_config.load_user_config(
context.root, interactive=interactive, dev_context=context.is_dev()
)
if set_vars:
for key, value in dict(set_vars).items():
config[key] = env.render_unknown(config, value)
Expand Down
6 changes: 6 additions & 0 deletions tutor/commands/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ class Context:
def __init__(self, root: str) -> None:
self.root = root

def is_dev(self) -> bool:
"""
Are we running from a developer (`tutor dev ...`) context?
"""
return False


class BaseJobContext(Context):
"""
Expand Down
108 changes: 107 additions & 1 deletion tutor/commands/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

from .. import config as tutor_config
from .. import env as tutor_env
from .. import fmt
from .. import exceptions, fmt, utils
from ..types import Config, get_typed
from .config import save as config_save_command
from . import compose


Expand Down Expand Up @@ -34,6 +35,110 @@ class DevContext(compose.BaseComposeContext):
def job_runner(self, config: Config) -> DevJobRunner:
return DevJobRunner(self.root, config)

def is_dev(self) -> bool:
return True


@click.command(help="Configure and run Open edX from scratch, for development")
@click.option("-I", "--non-interactive", is_flag=True, help="Run non-interactively")
@click.option("-p", "--pullimages", is_flag=True, help="Update docker images")
@click.pass_context
def quickstart(context: click.Context, non_interactive: bool, pullimages: bool) -> None:
try:
utils.check_macos_docker_memory()
except exceptions.TutorError as e:
fmt.echo_alert(
f"""Could not verify sufficient RAM allocation in Docker:
{e}
Tutor may not work if Docker is configured with < 4 GB RAM. Please follow instructions from:
https://docs.tutor.overhang.io/install.html"""
)

click.echo(fmt.title("Interactive platform configuration"))
context.invoke(config_save_command, interactive=(not non_interactive))
config = tutor_config.load(context.obj.root)

if non_interactive:
import_demo = False
create_superuser = False
else:
import_demo = click.confirm(
fmt.question("Import the demo course?"),
prompt_suffix=" ",
default=True,
)
create_superuser = click.confirm(
fmt.question("Create/update a superuser?"),
prompt_suffix=" ",
default=True,
)
if create_superuser:
superuser_username = click.prompt(
fmt.question(" Username for superuser"),
prompt_suffix=" ",
show_default=True,
default="admin",
)
superuser_email = click.prompt(
fmt.question(" Email for superuser"),
prompt_suffix=" ",
show_default=True,
default=f"admin@{config['LMS_HOST']}",
)
superuser_password = click.prompt(
fmt.question(" Password for superuser"),
prompt_suffix=" ",
show_default=True,
default="password",
)

click.echo(fmt.title("Stopping any existing platform"))
context.invoke(compose.stop)

if pullimages:
click.echo(fmt.title("Docker image updates"))
context.invoke(compose.dc_command, command="pull")

click.echo(fmt.title("Building Docker image for LMS and CMS development"))
context.invoke(compose.dc_command, command="build", args=["lms"])

click.echo(fmt.title("Starting the platform in detached mode"))
context.invoke(compose.start, detach=True)

click.echo(fmt.title("Database creation and migrations"))
context.invoke(compose.init)

if import_demo:
click.echo(fmt.title("Importing the demo course"))
context.invoke(compose.importdemocourse)

if create_superuser:
click.echo(fmt.title("Creating or updating a superuser"))
context.invoke(
compose.createuser,
name=superuser_username,
password=superuser_password,
email=superuser_email,
staff=True,
superuser=True,
)

fmt.echo_info(
"""The Open edX platform is now running in detached mode
Your Open edX platform is ready and can be accessed at the following urls:
{http}://{lms_host}
{http}://{cms_host}
""".format(
http="https" if config["ENABLE_HTTPS"] else "http",
lms_host=config["LMS_HOST"],
cms_host=config["CMS_HOST"],
)
)


@click.group(help="Run Open edX locally with development settings")
@click.pass_context
Expand Down Expand Up @@ -62,5 +167,6 @@ def runserver(context: click.Context, options: List[str], service: str) -> None:
context.invoke(compose.run, args=args)


dev.add_command(quickstart)
dev.add_command(runserver)
compose.add_commands(dev)
Loading

0 comments on commit 7a02d9e

Please sign in to comment.