6
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-12-12 14:17:46 +00:00

Run pylint on code base

This commit is contained in:
Régis Behmo 2019-04-23 09:57:55 +02:00
parent ce1bb05d8e
commit 207229e16e
9 changed files with 105 additions and 42 deletions

View File

@ -6,9 +6,9 @@ import click_repl
from .__about__ import __version__ from .__about__ import __version__
from .android import android from .android import android
from .config import config from .config import config_command
from .dev import dev from .dev import dev
from .images import images from .images import images_command
from .k8s import k8s from .k8s import k8s
from .local import local from .local import local
from .ui import ui from .ui import ui
@ -24,11 +24,13 @@ def main():
sys.stderr.write(fmt.error("Error: {}\n".format(e.args[0]))) sys.stderr.write(fmt.error("Error: {}\n".format(e.args[0])))
sys.exit(1) sys.exit(1)
@click.group(context_settings={'help_option_names': ['-h', '--help', 'help']}) @click.group(context_settings={'help_option_names': ['-h', '--help', 'help']})
@click.version_option(version=__version__) @click.version_option(version=__version__)
def cli(): def cli():
pass pass
@click.command( @click.command(
help="Print this help", help="Print this help",
name="help", name="help",
@ -37,9 +39,10 @@ def print_help():
with click.Context(cli) as context: with click.Context(cli) as context:
click.echo(cli.get_help(context)) click.echo(cli.get_help(context))
click_repl.register_repl(cli, name="ui") click_repl.register_repl(cli, name="ui")
cli.add_command(images) cli.add_command(images_command, name="images")
cli.add_command(config) cli.add_command(config_command, name="config")
cli.add_command(local) cli.add_command(local)
cli.add_command(dev) cli.add_command(dev)
cli.add_command(android) cli.add_command(android)

View File

@ -17,7 +17,7 @@ from .__about__ import __version__
short_help="Configure Open edX", short_help="Configure Open edX",
help="""Configure Open edX and store configuration values in $TUTOR_ROOT/config.yml""" help="""Configure Open edX and store configuration values in $TUTOR_ROOT/config.yml"""
) )
def config(): def config_command():
pass pass
@ -33,8 +33,7 @@ def save_command(root, silent1, silent2, set_):
def save(root, silent=False, keyvalues=None): def save(root, silent=False, keyvalues=None):
keyvalues = keyvalues or [] keyvalues = keyvalues or []
config = {} config = load_current(root)
load_current(config, root)
for k, v in keyvalues: for k, v in keyvalues:
config[k] = v config[k] = v
if not silent: if not silent:
@ -57,8 +56,7 @@ def printroot(root):
@opts.root @opts.root
@click.argument("key") @click.argument("key")
def printvalue(root, key): def printvalue(root, key):
config = {} config = load_current(root)
load_current(config, root)
load_defaults(config) load_defaults(config)
try: try:
print(config[key]) print(config[key])
@ -71,8 +69,7 @@ def load(root):
Load configuration, and generate it interactively if the file does not Load configuration, and generate it interactively if the file does not
exist. exist.
""" """
config = {} config = load_current(root)
load_current(config, root)
should_update_env = False should_update_env = False
if not os.path.exists(config_path(root)): if not os.path.exists(config_path(root)):
@ -119,20 +116,22 @@ def pre_upgrade_announcement(root):
) )
def load_current(config, root): def load_current(root):
convert_json2yml(root) convert_json2yml(root)
load_base(config, root) config = {}
load_base(config)
load_user(config, root) load_user(config, root)
load_env(config, root) load_env(config)
return config
def load_base(config, root): def load_base(config):
base = serialize.load(env.read("config-base.yml")) base = serialize.load(env.read("config-base.yml"))
for k, v in base.items(): for k, v in base.items():
config[k] = v config[k] = v
def load_env(config, root): def load_env(config):
base_config = serialize.load(env.read("config-base.yml")) base_config = serialize.load(env.read("config-base.yml"))
default_config = serialize.load(env.read("config-defaults.yml")) default_config = serialize.load(env.read("config-defaults.yml"))
keys = set(list(base_config.keys()) + list(default_config.keys())) keys = set(list(base_config.keys()) + list(default_config.keys()))
@ -272,6 +271,6 @@ def config_path(root):
return os.path.join(root, "config.yml") return os.path.join(root, "config.yml")
config.add_command(save_command, name="save") config_command.add_command(save_command, name="save")
config.add_command(printroot) config_command.add_command(printroot)
config.add_command(printvalue) config_command.add_command(printvalue)

View File

@ -13,6 +13,7 @@ from . import utils
def dev(): def dev():
pass pass
@click.command( @click.command(
help="Run a command in one of the containers", help="Run a command in one of the containers",
context_settings={"ignore_unknown_options": True}, context_settings={"ignore_unknown_options": True},
@ -34,6 +35,7 @@ def run(root, edx_platform_path, edx_platform_settings, service, command, args):
root, edx_platform_path, edx_platform_settings, port, *run_command root, edx_platform_path, edx_platform_settings, port, *run_command
) )
@click.command( @click.command(
help="Run a development server", help="Run a development server",
) )
@ -48,11 +50,13 @@ def runserver(root, edx_platform_path, edx_platform_settings, service):
service, "./manage.py", service, "runserver", "0.0.0.0:{}".format(port), service, "./manage.py", service, "runserver", "0.0.0.0:{}".format(port),
) )
@click.command(help="Stop a running development platform",) @click.command(help="Stop a running development platform",)
@opts.root @opts.root
def stop(root): def stop(root):
docker_compose(root, "rm", "--stop", "--force") docker_compose(root, "rm", "--stop", "--force")
@click.command( @click.command(
help="Watch for changes in your themes and recompile assets when needed" help="Watch for changes in your themes and recompile assets when needed"
) )
@ -65,12 +69,14 @@ def watchthemes(root, edx_platform_path, edx_platform_settings):
"--no-deps", "lms", "openedx-assets", "watch-themes", "--env", "dev" "--no-deps", "lms", "openedx-assets", "watch-themes", "--env", "dev"
) )
def docker_compose_run_with_port(root, edx_platform_path, edx_platform_settings, port, *command): def docker_compose_run_with_port(root, edx_platform_path, edx_platform_settings, port, *command):
docker_compose_run( docker_compose_run(
root, edx_platform_path, edx_platform_settings, root, edx_platform_path, edx_platform_settings,
"-p", "{port}:{port}".format(port=port), *command "-p", "{port}:{port}".format(port=port), *command
) )
def docker_compose_run(root, edx_platform_path, edx_platform_settings, *command): def docker_compose_run(root, edx_platform_path, edx_platform_settings, *command):
run_command = [ run_command = [
"run", "--rm", "run", "--rm",
@ -85,6 +91,7 @@ def docker_compose_run(root, edx_platform_path, edx_platform_settings, *command)
run_command += command run_command += command
docker_compose(root, *run_command) docker_compose(root, *run_command)
def docker_compose(root, *command): def docker_compose(root, *command):
return utils.docker_compose( return utils.docker_compose(
"-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"), "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"),
@ -92,9 +99,11 @@ def docker_compose(root, *command):
*command *command
) )
def service_port(service): def service_port(service):
return 8000 if service == "lms" else 8001 return 8000 if service == "lms" else 8001
dev.add_command(run) dev.add_command(run)
dev.add_command(runserver) dev.add_command(runserver)
dev.add_command(stop) dev.add_command(stop)

View File

@ -63,7 +63,6 @@ def render_dict(config):
rendered[key] = value rendered[key] = value
for k, v in rendered.items(): for k, v in rendered.items():
config[k] = v config[k] = v
pass
def render_str(config, text): def render_str(config, text):
@ -146,9 +145,9 @@ def walk_templates(root, target):
def is_part_of_env(path): def is_part_of_env(path):
basename = os.path.basename(path) basename = os.path.basename(path)
return not ( return not (
basename.startswith(".") or basename.startswith(".")
basename.endswith(".pyc") or or basename.endswith(".pyc")
basename == "__pycache__" or basename == "__pycache__"
) )

View File

@ -6,10 +6,12 @@ from . import fmt
from . import opts from . import opts
from . import utils from . import utils
@click.group(short_help="Manage docker images") @click.group(short_help="Manage docker images")
def images(): def images_command():
pass pass
OPENEDX_IMAGES = ["openedx", "forum", "notes", "xqueue", "android"] OPENEDX_IMAGES = ["openedx", "forum", "notes", "xqueue", "android"]
VENDOR_IMAGES = ["elasticsearch", "memcached", "mongodb", "mysql", "nginx", "rabbitmq", "smtp"] VENDOR_IMAGES = ["elasticsearch", "memcached", "mongodb", "mysql", "nginx", "rabbitmq", "smtp"]
argument_openedx_image = click.argument( argument_openedx_image = click.argument(
@ -19,6 +21,7 @@ argument_image = click.argument(
"image", type=click.Choice(["all"] + OPENEDX_IMAGES + VENDOR_IMAGES), "image", type=click.Choice(["all"] + OPENEDX_IMAGES + VENDOR_IMAGES),
) )
@click.command( @click.command(
short_help="Build docker images", short_help="Build docker images",
help="Build the docker images necessary for an Open edX platform." help="Build the docker images necessary for an Open edX platform."
@ -31,8 +34,7 @@ argument_image = click.argument(
) )
def build(root, image, build_arg): def build(root, image, build_arg):
config = tutor_config.load(root) config = tutor_config.load(root)
for image in openedx_image_names(config, image): for tag in openedx_image_tags(config, image):
tag = get_tag(config, image)
click.echo(fmt.info("Building image {}".format(tag))) click.echo(fmt.info("Building image {}".format(tag)))
command = [ command = [
"build", "-t", tag, "build", "-t", tag,
@ -44,26 +46,28 @@ def build(root, image, build_arg):
] ]
utils.docker(*command) utils.docker(*command)
@click.command(short_help="Pull images from the Docker registry") @click.command(short_help="Pull images from the Docker registry")
@opts.root @opts.root
@argument_image @argument_image
def pull(root, image): def pull(root, image):
config = tutor_config.load(root) config = tutor_config.load(root)
for image in image_names(config, image): for img in image_names(config, image):
tag = get_tag(config, image) tag = get_tag(config, img)
click.echo(fmt.info("Pulling image {}".format(tag))) click.echo(fmt.info("Pulling image {}".format(tag)))
utils.execute("docker", "pull", tag) utils.execute("docker", "pull", tag)
@click.command(short_help="Push images to the Docker registry") @click.command(short_help="Push images to the Docker registry")
@opts.root @opts.root
@argument_openedx_image @argument_openedx_image
def push(root, image): def push(root, image):
config = tutor_config.load(root) config = tutor_config.load(root)
for image in openedx_image_names(config, image): for tag in openedx_image_tags(config, image):
tag = get_tag(config, image)
click.echo(fmt.info("Pushing image {}".format(tag))) click.echo(fmt.info("Pushing image {}".format(tag)))
utils.execute("docker", "push", tag) utils.execute("docker", "push", tag)
def get_tag(config, name): def get_tag(config, name):
image = config["DOCKER_IMAGE_" + name.upper()] image = config["DOCKER_IMAGE_" + name.upper()]
return "{registry}{image}".format( return "{registry}{image}".format(
@ -71,9 +75,16 @@ def get_tag(config, name):
image=image, image=image,
) )
def image_names(config, image): def image_names(config, image):
return openedx_image_names(config, image) + vendor_image_names(config, image) return openedx_image_names(config, image) + vendor_image_names(config, image)
def openedx_image_tags(config, image):
for img in openedx_image_names(config, image):
yield get_tag(config, img)
def openedx_image_names(config, image): def openedx_image_names(config, image):
if image == "all": if image == "all":
images = OPENEDX_IMAGES[:] images = OPENEDX_IMAGES[:]
@ -84,6 +95,7 @@ def openedx_image_names(config, image):
return images return images
return [image] return [image]
def vendor_image_names(config, image): def vendor_image_names(config, image):
if image == "all": if image == "all":
images = VENDOR_IMAGES[:] images = VENDOR_IMAGES[:]
@ -100,6 +112,7 @@ def vendor_image_names(config, image):
return images return images
return [image] return [image]
images.add_command(build)
images.add_command(pull) images_command.add_command(build)
images.add_command(push) images_command.add_command(pull)
images_command.add_command(push)

View File

@ -13,6 +13,7 @@ from . import utils
def k8s(): def k8s():
pass pass
@click.command( @click.command(
help="Configure and run Open edX from scratch" help="Configure and run Open edX from scratch"
) )
@ -27,6 +28,7 @@ def quickstart(root):
click.echo(fmt.title("Running migrations. NOTE: this might fail. If it does, please retry 'tutor k8s databases' later")) click.echo(fmt.title("Running migrations. NOTE: this might fail. If it does, please retry 'tutor k8s databases' later"))
databases.callback(root) databases.callback(root)
@click.command(help="Run all configured Open edX services") @click.command(help="Run all configured Open edX services")
@opts.root @opts.root
def start(root): def start(root):
@ -45,10 +47,12 @@ def start(root):
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "services.yml")) kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "services.yml"))
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "deployments.yml")) kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "deployments.yml"))
@click.command(help="Stop a running platform") @click.command(help="Stop a running platform")
def stop(): def stop():
kubectl("delete", "deployments,services,ingress,configmaps", "--all") kubectl("delete", "deployments,services,ingress,configmaps", "--all")
@click.command(help="Completely delete an existing platform") @click.command(help="Completely delete an existing platform")
@click.option("-y", "--yes", is_flag=True, help="Do not ask for confirmation") @click.option("-y", "--yes", is_flag=True, help="Do not ask for confirmation")
def delete(yes): def delete(yes):
@ -56,6 +60,7 @@ def delete(yes):
click.confirm('Are you sure you want to delete the platform? All data will be removed.', abort=True) click.confirm('Are you sure you want to delete the platform? All data will be removed.', abort=True)
kubectl("delete", "namespace", K8s.NAMESPACE) kubectl("delete", "namespace", K8s.NAMESPACE)
@click.command( @click.command(
help="Create databases and run database migrations", help="Create databases and run database migrations",
) )
@ -63,6 +68,7 @@ def delete(yes):
def databases(root): def databases(root):
scripts.migrate(root, run_bash) scripts.migrate(root, run_bash)
@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")
@opts.root @opts.root
@click.option("--superuser", is_flag=True, help="Make superuser") @click.option("--superuser", is_flag=True, help="Make superuser")
@ -72,6 +78,7 @@ def databases(root):
def createuser(root, superuser, staff, name, email): def createuser(root, superuser, staff, name, email):
scripts.create_user(root, run_bash, superuser, staff, name, email) scripts.create_user(root, run_bash, superuser, staff, name, email)
@click.command(help="Import the demo course") @click.command(help="Import the demo course")
@opts.root @opts.root
def importdemocourse(root): def importdemocourse(root):
@ -80,6 +87,7 @@ def importdemocourse(root):
click.echo(fmt.info("Re-indexing courses")) click.echo(fmt.info("Re-indexing courses"))
indexcourses.callback(root) indexcourses.callback(root)
@click.command(help="Re-index courses for better searching") @click.command(help="Re-index courses for better searching")
@opts.root @opts.root
def indexcourses(root): def indexcourses(root):
@ -87,24 +95,26 @@ def indexcourses(root):
# I'm not quite sure the settings are correctly picked up. Which is weird because migrations work very well. # I'm not quite sure the settings are correctly picked up. Which is weird because migrations work very well.
scripts.index_courses(root, run_bash) scripts.index_courses(root, run_bash)
@click.command( @click.command(
help="Launch a shell in LMS or CMS", help="Launch a shell in LMS or CMS",
) )
@opts.root
@click.argument("service", type=click.Choice(["lms", "cms"])) @click.argument("service", type=click.Choice(["lms", "cms"]))
def shell(root, service): def shell(service):
K8s().execute(service, "bash") K8s().execute(service, "bash")
@click.command(help="Create a Kubernetesadmin user") @click.command(help="Create a Kubernetesadmin user")
@opts.root @opts.root
def adminuser(root): def adminuser(root):
utils.kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "adminuser.yml")) utils.kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "adminuser.yml"))
@click.command(help="Print the Kubernetes admin user token") @click.command(help="Print the Kubernetes admin user token")
@opts.root def admintoken():
def admintoken(root):
click.echo(K8s().admin_token()) click.echo(K8s().admin_token())
def kubectl(*command): def kubectl(*command):
""" """
Run kubectl commands in the right namespace. Also, errors are completely Run kubectl commands in the right namespace. Also, errors are completely
@ -116,6 +126,7 @@ def kubectl(*command):
] ]
kubectl_no_fail(*args) kubectl_no_fail(*args)
def kubectl_no_fail(*command): def kubectl_no_fail(*command):
""" """
Run kubectl commands and ignore exceptions, to avoid stopping on Run kubectl commands and ignore exceptions, to avoid stopping on
@ -164,9 +175,11 @@ class K8s:
podname = self.pod_name(app) podname = self.pod_name(app)
kubectl_no_fail("exec", "--namespace", self.NAMESPACE, "-it", podname, "--", *command) kubectl_no_fail("exec", "--namespace", self.NAMESPACE, "-it", podname, "--", *command)
def run_bash(root, service, command):
def run_bash(root, service, command): # pylint: disable=unused-argument
K8s().execute(service, "bash", "-e", "-c", command) K8s().execute(service, "bash", "-e", "-c", command)
k8s.add_command(quickstart) k8s.add_command(quickstart)
k8s.add_command(start) k8s.add_command(start)
k8s.add_command(stop) k8s.add_command(stop)

View File

@ -21,6 +21,7 @@ from . import utils
def local(): def local():
pass pass
@click.command(help="Configure and run Open edX from scratch") @click.command(help="Configure and run Open edX from scratch")
@click.option("-p", "--pullimages", "pullimages_", is_flag=True, help="Update docker images") @click.option("-p", "--pullimages", "pullimages_", is_flag=True, help="Update docker images")
@opts.root @opts.root
@ -39,12 +40,14 @@ def quickstart(pullimages_, root):
click.echo(fmt.title("Starting the platform in detached mode")) click.echo(fmt.title("Starting the platform in detached mode"))
start.callback(root, True) start.callback(root, True)
@click.command(help="Update docker images") @click.command(help="Update docker images")
@opts.root @opts.root
def pullimages(root): def pullimages(root):
config = tutor_config.load(root) config = tutor_config.load(root)
docker_compose(root, config, "pull") docker_compose(root, config, "pull")
@click.command(help="Run all configured Open edX services") @click.command(help="Run all configured Open edX services")
@opts.root @opts.root
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode") @click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
@ -97,6 +100,7 @@ def restart(root, service):
command += [service] command += [service]
docker_compose(root, config, *command) docker_compose(root, config, *command)
@click.command( @click.command(
help="Run a command in one of the containers", help="Run a command in one of the containers",
context_settings={"ignore_unknown_options": True}, context_settings={"ignore_unknown_options": True},
@ -118,6 +122,7 @@ def run(root, service, command, args):
config = tutor_config.load(root) config = tutor_config.load(root)
docker_compose(root, config, *run_command) docker_compose(root, config, *run_command)
@click.command( @click.command(
help="Create databases and run database migrations", help="Create databases and run database migrations",
) )
@ -126,6 +131,7 @@ def databases(root):
init_mysql(root) init_mysql(root)
scripts.migrate(root, run_bash) scripts.migrate(root, run_bash)
def init_mysql(root): def init_mysql(root):
config = tutor_config.load(root) config = tutor_config.load(root)
if not config['ACTIVATE_MYSQL']: if not config['ACTIVATE_MYSQL']:
@ -139,20 +145,23 @@ def init_mysql(root):
click.echo(fmt.info(" waiting for mysql initialization")) click.echo(fmt.info(" waiting for mysql initialization"))
# TODO this is duplicate code with the docker_compose function. We # TODO this is duplicate code with the docker_compose function. We
# should rely on a dedicated function in utils module. # should rely on a dedicated function in utils module.
logs = subprocess.check_output([ mysql_logs = subprocess.check_output([
"docker-compose", "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"), "docker-compose", "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"),
"--project-name", config["LOCAL_PROJECT_NAME"], "logs", "mysql", "--project-name", config["LOCAL_PROJECT_NAME"], "logs", "mysql",
]) ])
if b"MySQL init process done. Ready for start up." in logs: # pylint: disable=unsupported-membership-test
if b"MySQL init process done. Ready for start up." in mysql_logs:
click.echo(fmt.info("MySQL database initialized")) click.echo(fmt.info("MySQL database initialized"))
docker_compose(root, config, "stop", "mysql") docker_compose(root, config, "stop", "mysql")
return return
sleep(4) sleep(4)
@click.group(help="Manage https certificates") @click.group(help="Manage https certificates")
def https(): def https():
pass pass
@click.command(help="Create https certificates", name="create") @click.command(help="Create https certificates", name="create")
@opts.root @opts.root
def https_create(root): def https_create(root):
@ -188,6 +197,7 @@ See the official certbot documentation for your platform: https://certbot.eff.or
"-e", "-c", script, "-e", "-c", script,
) )
@click.command(help="Renew https certificates", name="renew") @click.command(help="Renew https certificates", name="renew")
@opts.root @opts.root
def https_renew(root): def https_renew(root):
@ -211,6 +221,7 @@ See the official certbot documentation for your platform: https://certbot.eff.or
] ]
utils.docker_run(*docker_run) utils.docker_run(*docker_run)
@click.command(help="View output from containers") @click.command(help="View output from containers")
@opts.root @opts.root
@click.option("-f", "--follow", is_flag=True, help="Follow log output") @click.option("-f", "--follow", is_flag=True, help="Follow log output")
@ -226,6 +237,7 @@ def logs(root, follow, tail, service):
config = tutor_config.load(root) config = tutor_config.load(root)
docker_compose(root, config, *command) docker_compose(root, config, *command)
@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")
@opts.root @opts.root
@click.option("--superuser", is_flag=True, help="Make superuser") @click.option("--superuser", is_flag=True, help="Make superuser")
@ -237,6 +249,7 @@ def createuser(root, superuser, staff, name, email):
check_service_is_activated(config, "lms") check_service_is_activated(config, "lms")
scripts.create_user(root, run_bash, superuser, staff, name, email) scripts.create_user(root, run_bash, superuser, staff, name, email)
@click.command(help="Import the demo course") @click.command(help="Import the demo course")
@opts.root @opts.root
def importdemocourse(root): def importdemocourse(root):
@ -247,6 +260,7 @@ def importdemocourse(root):
click.echo(fmt.info("Re-indexing courses")) click.echo(fmt.info("Re-indexing courses"))
indexcourses.callback(root) indexcourses.callback(root)
@click.command(help="Re-index courses for better searching") @click.command(help="Re-index courses for better searching")
@opts.root @opts.root
def indexcourses(root): def indexcourses(root):
@ -254,6 +268,7 @@ def indexcourses(root):
check_service_is_activated(config, "cms") check_service_is_activated(config, "cms")
scripts.index_courses(root, run_bash) scripts.index_courses(root, run_bash)
@click.command( @click.command(
help="Run Portainer (https://portainer.io), a UI for container supervision", help="Run Portainer (https://portainer.io), a UI for container supervision",
short_help="Run Portainer, a UI for container supervision", short_help="Run Portainer, a UI for container supervision",
@ -271,14 +286,17 @@ def portainer(root, port):
click.echo(fmt.info("View the Portainer UI at http://localhost:{port}".format(port=port))) click.echo(fmt.info("View the Portainer UI at http://localhost:{port}".format(port=port)))
utils.docker_run(*docker_run) utils.docker_run(*docker_run)
def check_service_is_activated(config, service): def check_service_is_activated(config, service):
if not config["ACTIVATE_" + service.upper()]: if not config["ACTIVATE_" + service.upper()]:
raise exceptions.TutorError("This command may only be executed on the server where the {} is running".format(service)) raise exceptions.TutorError("This command may only be executed on the server where the {} is running".format(service))
def run_bash(root, service, command): def run_bash(root, service, command):
config = tutor_config.load(root) config = tutor_config.load(root)
docker_compose(root, config, "run", "--rm", service, "bash", "-e", "-c", command) docker_compose(root, config, "run", "--rm", service, "bash", "-e", "-c", command)
def docker_compose(root, config, *command): def docker_compose(root, config, *command):
return utils.docker_compose( return utils.docker_compose(
"-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"), "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"),
@ -286,6 +304,7 @@ def docker_compose(root, config, *command):
*command *command
) )
https.add_command(https_create) https.add_command(https_create)
https.add_command(https_renew) https.add_command(https_renew)

View File

@ -1,6 +1,7 @@
import click import click
import click_repl import click_repl
@click.command( @click.command(
short_help="Interactive shell", short_help="Interactive shell",
help="Launch an interactive shell for launching Tutor commands" help="Launch an interactive shell for launching Tutor commands"
@ -14,5 +15,5 @@ Type <ctrl-d> to exit.""")
try: try:
click_repl.repl(click.get_current_context()) click_repl.repl(click.get_current_context())
return # this happens on a ctrl+d return # this happens on a ctrl+d
except Exception: except Exception: # pylint: disable=broad-except
pass pass

View File

@ -1,9 +1,10 @@
import click
import random import random
import shutil import shutil
import string import string
import subprocess import subprocess
import click
from . import exceptions from . import exceptions
from . import fmt from . import fmt
@ -11,6 +12,7 @@ from . import fmt
def random_string(length): def random_string(length):
return "".join([random.choice(string.ascii_letters + string.digits) for _ in range(length)]) return "".join([random.choice(string.ascii_letters + string.digits) for _ in range(length)])
def common_domain(d1, d2): def common_domain(d1, d2):
""" """
Return the common domain between two domain names. Return the common domain between two domain names.
@ -27,19 +29,23 @@ def common_domain(d1, d2):
break break
return ".".join(common[::-1]) return ".".join(common[::-1])
def docker_run(*command): def docker_run(*command):
return docker("run", "--rm", "-it", *command) return docker("run", "--rm", "-it", *command)
def docker(*command): def docker(*command):
if shutil.which("docker") is None: if shutil.which("docker") is None:
raise exceptions.TutorError("docker is not installed. Please follow instructions from https://docs.docker.com/install/") raise exceptions.TutorError("docker is not installed. Please follow instructions from https://docs.docker.com/install/")
return execute("docker", *command) return execute("docker", *command)
def docker_compose(*command): def docker_compose(*command):
if shutil.which("docker-compose") is None: if shutil.which("docker-compose") is None:
raise exceptions.TutorError("docker-compose is not installed. Please follow instructions from https://docs.docker.com/compose/install/") raise exceptions.TutorError("docker-compose is not installed. Please follow instructions from https://docs.docker.com/compose/install/")
return execute("docker-compose", *command) return execute("docker-compose", *command)
def kubectl(*command): def kubectl(*command):
if shutil.which("kubectl") is None: if shutil.which("kubectl") is None:
raise exceptions.TutorError( raise exceptions.TutorError(
@ -47,6 +53,7 @@ def kubectl(*command):
) )
return execute("kubectl", *command) return execute("kubectl", *command)
def execute(*command): def execute(*command):
click.echo(fmt.command(" ".join(command))) click.echo(fmt.command(" ".join(command)))
with subprocess.Popen(command) as p: with subprocess.Popen(command) as p: