2020-01-17 08:41:54 +00:00
|
|
|
import os
|
2019-01-22 20:25:04 +00:00
|
|
|
|
|
|
|
import click
|
|
|
|
|
2019-06-03 22:44:12 +00:00
|
|
|
from .. import config as tutor_config
|
2019-05-11 19:20:09 +00:00
|
|
|
from .. import env as tutor_env
|
2021-02-25 08:09:14 +00:00
|
|
|
from .. import fmt
|
2021-04-06 10:09:00 +00:00
|
|
|
from ..types import get_typed, Config
|
2021-02-25 08:09:14 +00:00
|
|
|
from .. import utils
|
2020-11-12 14:31:13 +00:00
|
|
|
from . import compose
|
|
|
|
from .config import save as config_save_command
|
2021-02-25 08:09:14 +00:00
|
|
|
from .context import Context
|
2021-03-13 18:46:44 +00:00
|
|
|
|
|
|
|
|
2021-04-06 10:09:00 +00:00
|
|
|
def docker_compose(root: str, config: Config, *command: str) -> int:
|
2021-03-13 18:46:44 +00:00
|
|
|
"""
|
|
|
|
Run docker-compose with local and production yml files.
|
|
|
|
"""
|
|
|
|
args = []
|
|
|
|
override_path = tutor_env.pathjoin(root, "local", "docker-compose.override.yml")
|
|
|
|
if os.path.exists(override_path):
|
|
|
|
args += ["-f", override_path]
|
|
|
|
return utils.docker_compose(
|
|
|
|
"-f",
|
|
|
|
tutor_env.pathjoin(root, "local", "docker-compose.yml"),
|
|
|
|
"-f",
|
|
|
|
tutor_env.pathjoin(root, "local", "docker-compose.prod.yml"),
|
|
|
|
*args,
|
|
|
|
"--project-name",
|
2021-04-06 10:09:00 +00:00
|
|
|
get_typed(config, "LOCAL_PROJECT_NAME", str),
|
2021-03-13 18:46:44 +00:00
|
|
|
*command
|
|
|
|
)
|
2020-01-08 18:38:13 +00:00
|
|
|
|
|
|
|
|
2020-10-15 15:33:28 +00:00
|
|
|
@click.group(help="Run Open edX locally with docker-compose")
|
2021-03-13 18:46:44 +00:00
|
|
|
@click.pass_obj
|
2021-02-25 08:09:14 +00:00
|
|
|
def local(context: Context) -> None:
|
|
|
|
context.docker_compose_func = docker_compose
|
2019-01-22 20:25:04 +00:00
|
|
|
|
2019-04-23 07:57:55 +00:00
|
|
|
|
2019-03-21 18:06:08 +00:00
|
|
|
@click.command(help="Configure and run Open edX from scratch")
|
2019-06-05 17:45:22 +00:00
|
|
|
@click.option("-I", "--non-interactive", is_flag=True, help="Run non-interactively")
|
2021-02-25 08:09:14 +00:00
|
|
|
@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:
|
|
|
|
if tutor_env.needs_major_upgrade(context.obj.root):
|
2019-12-24 16:22:12 +00:00
|
|
|
click.echo(fmt.title("Upgrading from an older release"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(
|
|
|
|
upgrade,
|
|
|
|
from_version=tutor_env.current_release(context.obj.root),
|
2019-12-24 16:22:12 +00:00
|
|
|
non_interactive=non_interactive,
|
|
|
|
)
|
|
|
|
|
2019-01-22 20:25:04 +00:00
|
|
|
click.echo(fmt.title("Interactive platform configuration"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(
|
|
|
|
config_save_command,
|
|
|
|
interactive=(not non_interactive),
|
|
|
|
set_vars=[],
|
|
|
|
unset_vars=[],
|
2020-11-13 16:44:24 +00:00
|
|
|
)
|
2019-01-22 20:25:04 +00:00
|
|
|
click.echo(fmt.title("Stopping any existing platform"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
|
|
|
if pullimages:
|
2019-03-06 15:32:23 +00:00
|
|
|
click.echo(fmt.title("Docker image updates"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.dc_command, command="pull")
|
2019-01-22 20:25:04 +00:00
|
|
|
click.echo(fmt.title("Starting the platform in detached mode"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.start, detach=True)
|
2019-09-03 07:29:38 +00:00
|
|
|
click.echo(fmt.title("Database creation and migrations"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.init)
|
2019-01-22 20:25:04 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
config = tutor_config.load(context.obj.root)
|
2019-09-03 08:36:10 +00:00
|
|
|
fmt.echo_info(
|
2019-12-24 16:22:12 +00:00
|
|
|
"""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(
|
2020-09-17 10:53:14 +00:00
|
|
|
http="https" if config["ENABLE_HTTPS"] else "http",
|
2019-12-24 16:22:12 +00:00
|
|
|
lms_host=config["LMS_HOST"],
|
|
|
|
cms_host=config["CMS_HOST"],
|
2019-05-05 09:45:24 +00:00
|
|
|
)
|
2019-09-03 08:36:10 +00:00
|
|
|
)
|
2019-05-05 09:45:24 +00:00
|
|
|
|
|
|
|
|
2019-12-24 16:22:12 +00:00
|
|
|
@click.command(help="Upgrade from a previous Open edX named release")
|
|
|
|
@click.option(
|
2020-09-17 10:53:14 +00:00
|
|
|
"--from",
|
|
|
|
"from_version",
|
|
|
|
default="juniper",
|
|
|
|
type=click.Choice(["ironwood", "juniper"]),
|
2019-12-24 16:22:12 +00:00
|
|
|
)
|
|
|
|
@click.option("-I", "--non-interactive", is_flag=True, help="Run non-interactively")
|
2021-02-25 08:09:14 +00:00
|
|
|
@click.pass_context
|
|
|
|
def upgrade(context: click.Context, from_version: str, non_interactive: bool) -> None:
|
|
|
|
config = tutor_config.load_no_check(context.obj.root)
|
2019-12-24 16:22:12 +00:00
|
|
|
|
|
|
|
if not non_interactive:
|
|
|
|
question = """You are about to upgrade your Open edX platform. It is strongly recommended to make a backup before upgrading. To do so, run:
|
|
|
|
|
|
|
|
tutor local stop
|
|
|
|
sudo rsync -avr "$(tutor config printroot)"/ /tmp/tutor-backup/
|
|
|
|
|
|
|
|
In case of problem, to restore your backup you will then have to run: sudo rsync -avr /tmp/tutor-backup/ "$(tutor config printroot)"/
|
|
|
|
|
|
|
|
Are you sure you want to continue?"""
|
|
|
|
click.confirm(
|
|
|
|
fmt.question(question), default=True, abort=True, prompt_suffix=" "
|
|
|
|
)
|
|
|
|
|
2020-09-17 10:53:14 +00:00
|
|
|
running_version = from_version
|
|
|
|
if running_version == "ironwood":
|
2019-12-24 16:22:12 +00:00
|
|
|
upgrade_from_ironwood(context, config)
|
2020-09-17 10:53:14 +00:00
|
|
|
running_version = "juniper"
|
|
|
|
|
|
|
|
if running_version == "juniper":
|
|
|
|
upgrade_from_juniper(context, config)
|
|
|
|
running_version = "koa"
|
2019-12-24 16:22:12 +00:00
|
|
|
|
|
|
|
|
2021-04-06 10:09:00 +00:00
|
|
|
def upgrade_from_ironwood(context: click.Context, config: Config) -> None:
|
2019-12-24 16:22:12 +00:00
|
|
|
click.echo(fmt.title("Upgrading from Ironwood"))
|
2021-02-25 08:09:14 +00:00
|
|
|
tutor_env.save(context.obj.root, config)
|
2019-12-24 16:22:12 +00:00
|
|
|
|
|
|
|
click.echo(fmt.title("Stopping any existing platform"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
2019-12-24 16:22:12 +00:00
|
|
|
|
2020-09-17 10:53:14 +00:00
|
|
|
if not config["RUN_MONGODB"]:
|
2019-12-24 16:22:12 +00:00
|
|
|
fmt.echo_info(
|
2020-09-17 10:53:14 +00:00
|
|
|
"You are not running MongDB (RUN_MONGODB=false). It is your "
|
2019-12-24 16:22:12 +00:00
|
|
|
"responsibility to upgrade your MongoDb instance to v3.6. There is "
|
2020-09-17 10:53:14 +00:00
|
|
|
"nothing left to do to upgrade from Ironwood."
|
2019-12-24 16:22:12 +00:00
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
# Note that the DOCKER_IMAGE_MONGODB value is never saved, because we only save the
|
|
|
|
# environment, not the configuration.
|
|
|
|
click.echo(fmt.title("Upgrading MongoDb from v3.2 to v3.4"))
|
|
|
|
config["DOCKER_IMAGE_MONGODB"] = "mongo:3.4.24"
|
2021-02-25 08:09:14 +00:00
|
|
|
tutor_env.save(context.obj.root, config)
|
|
|
|
context.invoke(compose.start, detach=True, services=["mongodb"])
|
|
|
|
context.invoke(
|
|
|
|
compose.execute,
|
|
|
|
args=[
|
2019-12-24 16:22:12 +00:00
|
|
|
"mongodb",
|
|
|
|
"mongo",
|
|
|
|
"--eval",
|
|
|
|
'db.adminCommand({ setFeatureCompatibilityVersion: "3.4" })',
|
2021-02-25 08:09:14 +00:00
|
|
|
],
|
2019-12-24 16:22:12 +00:00
|
|
|
)
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
2019-12-24 16:22:12 +00:00
|
|
|
|
|
|
|
click.echo(fmt.title("Upgrading MongoDb from v3.4 to v3.6"))
|
|
|
|
config["DOCKER_IMAGE_MONGODB"] = "mongo:3.6.18"
|
2021-02-25 08:09:14 +00:00
|
|
|
tutor_env.save(context.obj.root, config)
|
|
|
|
context.invoke(compose.start, detach=True, services=["mongodb"])
|
|
|
|
context.invoke(
|
|
|
|
compose.execute,
|
|
|
|
args=[
|
2019-12-24 16:22:12 +00:00
|
|
|
"mongodb",
|
|
|
|
"mongo",
|
|
|
|
"--eval",
|
|
|
|
'db.adminCommand({ setFeatureCompatibilityVersion: "3.6" })',
|
2021-02-25 08:09:14 +00:00
|
|
|
],
|
2019-12-24 16:22:12 +00:00
|
|
|
)
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
2019-12-24 16:22:12 +00:00
|
|
|
|
|
|
|
|
2021-04-06 10:09:00 +00:00
|
|
|
def upgrade_from_juniper(context: click.Context, config: Config) -> None:
|
2020-09-17 10:53:14 +00:00
|
|
|
click.echo(fmt.title("Upgrading from Juniper"))
|
2021-02-25 08:09:14 +00:00
|
|
|
tutor_env.save(context.obj.root, config)
|
2020-09-17 10:53:14 +00:00
|
|
|
|
|
|
|
click.echo(fmt.title("Stopping any existing platform"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
2020-09-17 10:53:14 +00:00
|
|
|
|
|
|
|
if not config["RUN_MYSQL"]:
|
|
|
|
fmt.echo_info(
|
|
|
|
"You are not running MySQL (RUN_MYSQL=false). It is your "
|
|
|
|
"responsibility to upgrade your MySQL instance to v5.7. There is "
|
|
|
|
"nothing left to do to upgrade from Juniper."
|
|
|
|
)
|
|
|
|
return
|
|
|
|
|
|
|
|
click.echo(fmt.title("Upgrading MySQL from v5.6 to v5.7"))
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.start, detach=True, services=["mysql"])
|
|
|
|
context.invoke(
|
|
|
|
compose.execute,
|
|
|
|
args=[
|
2020-09-17 10:53:14 +00:00
|
|
|
"mysql",
|
|
|
|
"bash",
|
|
|
|
"-e",
|
|
|
|
"-c",
|
|
|
|
"mysql_upgrade -u {} --password='{}'".format(
|
|
|
|
config["MYSQL_ROOT_USERNAME"], config["MYSQL_ROOT_PASSWORD"]
|
|
|
|
),
|
2021-02-25 08:09:14 +00:00
|
|
|
],
|
2020-09-17 10:53:14 +00:00
|
|
|
)
|
2021-02-25 08:09:14 +00:00
|
|
|
context.invoke(compose.stop)
|
2020-09-17 10:53:14 +00:00
|
|
|
|
|
|
|
|
2020-01-08 18:38:13 +00:00
|
|
|
local.add_command(quickstart)
|
2019-12-24 16:22:12 +00:00
|
|
|
local.add_command(upgrade)
|
2020-01-08 18:38:13 +00:00
|
|
|
compose.add_commands(local)
|