6
0
mirror of https://github.com/ChristianLight/tutor.git synced 2025-01-23 05:38:23 +00:00

refactor: job running methods for clarity and extensibility

It made little sense to create dedicated context classes for local/dev.
Instead, we create local/dev compose methods which can be easily reused.
Also, we renamed the "scripts" module to better reflect its function.
This commit is contained in:
Régis Behmo 2021-03-13 19:46:44 +01:00
parent 6ca863e04c
commit 1d4ab79863
7 changed files with 70 additions and 75 deletions

View File

@ -1,11 +1,10 @@
import click import click
from .compose import ScriptRunner from .compose import ComposeJobRunner
from .local import LocalContext from .local import docker_compose as local_docker_compose
from .. import config as tutor_config from .. import config as tutor_config
from .. import env as tutor_env from .. import env as tutor_env
from .. import fmt from .. import fmt
from .. import utils
@click.group(help="Build an Android app for your Open edX platform [BETA FEATURE]") @click.group(help="Build an Android app for your Open edX platform [BETA FEATURE]")
@ -44,7 +43,7 @@ cp OpenEdXMobile/build/outputs/apk/prod/{apk_folder}/*.apk /openedx/data/"""
def docker_run(root, command): def docker_run(root, command):
config = tutor_config.load(root) config = tutor_config.load(root)
runner = ScriptRunner(root, config, LocalContext.docker_compose) runner = ComposeJobRunner(root, config, local_docker_compose)
runner.run_job("android", command) runner.run_job("android", command)

View File

@ -7,12 +7,12 @@ from .. import config as tutor_config
from .. import env as tutor_env from .. import env as tutor_env
from ..exceptions import TutorError from ..exceptions import TutorError
from .. import fmt from .. import fmt
from .. import scripts from .. import jobs
from .. import serialize from .. import serialize
from .. import utils from .. import utils
class ScriptRunner(scripts.BaseRunner): class ComposeJobRunner(jobs.BaseJobRunner):
def __init__(self, root, config, docker_compose_func): def __init__(self, root, config, docker_compose_func):
super().__init__(root, config) super().__init__(root, config)
self.docker_compose_func = docker_compose_func self.docker_compose_func = docker_compose_func
@ -138,8 +138,8 @@ def restart(context, services):
@click.pass_obj @click.pass_obj
def init(context, limit): def init(context, limit):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = ScriptRunner(context.root, config, context.docker_compose) runner = ComposeJobRunner(context.root, config, context.docker_compose)
scripts.initialise(runner, limit_to=limit) jobs.initialise(runner, limit_to=limit)
@click.command(help="Create an Open edX user and interactively set their password") @click.command(help="Create an Open edX user and interactively set their password")
@ -155,10 +155,8 @@ def init(context, limit):
@click.pass_obj @click.pass_obj
def createuser(context, superuser, staff, password, name, email): def createuser(context, superuser, staff, password, name, email):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = ScriptRunner(context.root, config, context.docker_compose) runner = ComposeJobRunner(context.root, config, context.docker_compose)
command = scripts.create_user_command( command = jobs.create_user_command(superuser, staff, name, email, password=password)
superuser, staff, name, email, password=password
)
runner.run_job("lms", command) runner.run_job("lms", command)
@ -170,18 +168,18 @@ def createuser(context, superuser, staff, password, name, email):
@click.pass_obj @click.pass_obj
def settheme(context, theme_name, domain_names): def settheme(context, theme_name, domain_names):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = ScriptRunner(context.root, config, context.docker_compose) runner = ComposeJobRunner(context.root, config, context.docker_compose)
for domain_name in domain_names: for domain_name in domain_names:
scripts.set_theme(theme_name, domain_name, runner) jobs.set_theme(theme_name, domain_name, runner)
@click.command(help="Import the demo course") @click.command(help="Import the demo course")
@click.pass_obj @click.pass_obj
def importdemocourse(context): def importdemocourse(context):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = ScriptRunner(context.root, config, context.docker_compose) runner = ComposeJobRunner(context.root, config, context.docker_compose)
fmt.echo_info("Importing demo course") fmt.echo_info("Importing demo course")
scripts.import_demo_course(runner) jobs.import_demo_course(runner)
@click.command( @click.command(

View File

@ -2,3 +2,7 @@
class Context: class Context:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
@staticmethod
def docker_compose(root, config, *command):
raise NotImplementedError

View File

@ -3,42 +3,39 @@ import os
import click import click
from . import compose from . import compose
from .context import Context
from .. import config as tutor_config from .. import config as tutor_config
from .. import env as tutor_env from .. import env as tutor_env
from .. import fmt from .. import fmt
from .. import utils from .. import utils
# pylint: disable=too-few-public-methods def docker_compose(root, config, *command):
class DevContext(Context): """
@staticmethod Run docker-compose with dev arguments.
def docker_compose(root, config, *command): """
args = [] args = []
for folder in ["local", "dev"]: for folder in ["local", "dev"]:
# Add docker-compose.yml and docker-compose.override.yml (if it exists) # Add docker-compose.yml and docker-compose.override.yml (if it exists)
# from "local" and "dev" folders (but not docker-compose.prod.yml) # from "local" and "dev" folders (but not docker-compose.prod.yml)
args += [ args += [
"-f", "-f",
tutor_env.pathjoin(root, folder, "docker-compose.yml"), tutor_env.pathjoin(root, folder, "docker-compose.yml"),
] ]
override_path = tutor_env.pathjoin( override_path = tutor_env.pathjoin(root, folder, "docker-compose.override.yml")
root, folder, "docker-compose.override.yml" if os.path.exists(override_path):
) args += ["-f", override_path]
if os.path.exists(override_path): return utils.docker_compose(
args += ["-f", override_path] *args,
return utils.docker_compose( "--project-name",
*args, config["DEV_PROJECT_NAME"],
"--project-name", *command,
config["DEV_PROJECT_NAME"], )
*command,
)
@click.group(help="Run Open edX locally with development settings") @click.group(help="Run Open edX locally with development settings")
@click.pass_context @click.pass_obj
def dev(context): def dev(context):
context.obj = DevContext(context.obj.root) context.docker_compose = docker_compose
@click.command( @click.command(

View File

@ -8,7 +8,7 @@ from .. import env as tutor_env
from .. import exceptions from .. import exceptions
from .. import fmt from .. import fmt
from .. import interactive as interactive_config from .. import interactive as interactive_config
from .. import scripts from .. import jobs
from .. import serialize from .. import serialize
from .. import utils from .. import utils
@ -135,11 +135,11 @@ def delete(context, yes):
@click.pass_obj @click.pass_obj
def init(context, limit): def init(context, limit):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = K8sScriptRunner(context.root, config) runner = K8sJobRunner(context.root, config)
for service in ["mysql", "elasticsearch", "mongodb"]: for service in ["mysql", "elasticsearch", "mongodb"]:
if tutor_config.is_service_activated(config, service): if tutor_config.is_service_activated(config, service):
wait_for_pod_ready(config, service) wait_for_pod_ready(config, service)
scripts.initialise(runner, limit_to=limit) jobs.initialise(runner, limit_to=limit)
@click.command(help="Create an Open edX user and interactively set their password") @click.command(help="Create an Open edX user and interactively set their password")
@ -155,9 +155,7 @@ def init(context, limit):
@click.pass_obj @click.pass_obj
def createuser(context, superuser, staff, password, name, email): def createuser(context, superuser, staff, password, name, email):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
command = scripts.create_user_command( command = jobs.create_user_command(superuser, staff, name, email, password=password)
superuser, staff, name, email, password=password
)
# This needs to be interactive in case the user needs to type a password # This needs to be interactive in case the user needs to type a password
kubectl_exec(config, "lms", command, attach=True) kubectl_exec(config, "lms", command, attach=True)
@ -167,8 +165,8 @@ def createuser(context, superuser, staff, password, name, email):
def importdemocourse(context): def importdemocourse(context):
fmt.echo_info("Importing demo course") fmt.echo_info("Importing demo course")
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = K8sScriptRunner(context.root, config) runner = K8sJobRunner(context.root, config)
scripts.import_demo_course(runner) jobs.import_demo_course(runner)
@click.command( @click.command(
@ -179,9 +177,9 @@ def importdemocourse(context):
@click.pass_obj @click.pass_obj
def settheme(context, theme_name, domain_names): def settheme(context, theme_name, domain_names):
config = tutor_config.load(context.root) config = tutor_config.load(context.root)
runner = K8sScriptRunner(context.root, config) runner = K8sJobRunner(context.root, config)
for domain_name in domain_names: for domain_name in domain_names:
scripts.set_theme(theme_name, domain_name, runner) jobs.set_theme(theme_name, domain_name, runner)
@click.command(name="exec", help="Execute a command in a pod of the given application") @click.command(name="exec", help="Execute a command in a pod of the given application")
@ -320,7 +318,7 @@ class K8sClients:
return self._core_api return self._core_api
class K8sScriptRunner(scripts.BaseRunner): class K8sJobRunner(jobs.BaseJobRunner):
def load_job(self, name): def load_job(self, name):
jobs = self.render("k8s", "jobs.yml") jobs = self.render("k8s", "jobs.yml")
for job in serialize.load_all(jobs): for job in serialize.load_all(jobs):

View File

@ -7,33 +7,32 @@ from .. import env as tutor_env
from .. import fmt, utils from .. import fmt, utils
from . import compose from . import compose
from .config import save as config_save_command from .config import save as config_save_command
from .context import Context
# pylint: disable=too-few-public-methods def docker_compose(root, config, *command):
class LocalContext(Context): """
@staticmethod Run docker-compose with local and production yml files.
def docker_compose(root, config, *command): """
args = [] args = []
override_path = tutor_env.pathjoin(root, "local", "docker-compose.override.yml") override_path = tutor_env.pathjoin(root, "local", "docker-compose.override.yml")
if os.path.exists(override_path): if os.path.exists(override_path):
args += ["-f", override_path] args += ["-f", override_path]
return utils.docker_compose( return utils.docker_compose(
"-f", "-f",
tutor_env.pathjoin(root, "local", "docker-compose.yml"), tutor_env.pathjoin(root, "local", "docker-compose.yml"),
"-f", "-f",
tutor_env.pathjoin(root, "local", "docker-compose.prod.yml"), tutor_env.pathjoin(root, "local", "docker-compose.prod.yml"),
*args, *args,
"--project-name", "--project-name",
config["LOCAL_PROJECT_NAME"], config["LOCAL_PROJECT_NAME"],
*command *command
) )
@click.group(help="Run Open edX locally with docker-compose") @click.group(help="Run Open edX locally with docker-compose")
@click.pass_context @click.pass_obj
def local(context): def local(context):
context.obj = LocalContext(context.obj.root) context.docker_compose = docker_compose
@click.command(help="Configure and run Open edX from scratch") @click.command(help="Configure and run Open edX from scratch")

View File

@ -8,7 +8,7 @@ echo "Loading settings $DJANGO_SETTINGS_MODULE"
""" """
class BaseRunner: class BaseJobRunner:
def __init__(self, root, config): def __init__(self, root, config):
self.root = root self.root = root
self.config = config self.config = config