From a61ffe3b29d77af13f91a6f6e49e8d05fa987a10 Mon Sep 17 00:00:00 2001 From: lpm0073 Date: Fri, 13 May 2022 12:56:45 -0500 Subject: [PATCH] configure for credentials service --- setup.py | 4 +- tutorcredentials/patches/caddyfile | 7 ++ tutorcredentials/patches/k8s-deployments | 37 +++++++++ tutorcredentials/patches/k8s-jobs | 25 ++++++ tutorcredentials/patches/k8s-services | 12 +++ .../patches/kustomization-configmapgenerator | 3 + .../local-docker-compose-caddy-aliases | 1 + .../patches/local-docker-compose-dev-services | 15 ++++ .../local-docker-compose-jobs-services | 7 ++ .../patches/local-docker-compose-services | 11 +++ tutorcredentials/patches/mfe-env-development | 1 + tutorcredentials/patches/mfe-env-production | 1 + .../patches/openedx-lms-common-settings | 5 ++ .../patches/openedx-lms-development-settings | 2 + .../patches/openedx-lms-production-settings | 2 + tutorcredentials/plugin.py | 81 +++++++++++------- .../apps/credentials/settings/__init__.py | 0 .../apps/credentials/settings/development.py | 14 ++++ .../credentials/settings/partials/common.py | 82 +++++++++++++++++++ .../apps/credentials/settings/production.py | 14 ++++ .../credentials/build/credentials/Dockerfile | 71 ++++++++++++++++ .../credentials/build/credentials/assets.py | 9 ++ .../requirements/private-sample.txt | 6 ++ .../credentials/tasks/credentials/init | 1 + .../templates/credentials/tasks/lms/init | 0 .../templates/credentials/tasks/mysql/init | 4 + 26 files changed, 385 insertions(+), 30 deletions(-) create mode 100644 tutorcredentials/patches/caddyfile create mode 100644 tutorcredentials/patches/k8s-deployments create mode 100644 tutorcredentials/patches/k8s-jobs create mode 100644 tutorcredentials/patches/k8s-services create mode 100644 tutorcredentials/patches/kustomization-configmapgenerator create mode 100644 tutorcredentials/patches/local-docker-compose-caddy-aliases create mode 100644 tutorcredentials/patches/local-docker-compose-dev-services create mode 100644 tutorcredentials/patches/local-docker-compose-jobs-services create mode 100644 tutorcredentials/patches/local-docker-compose-services create mode 100644 tutorcredentials/patches/mfe-env-development create mode 100644 tutorcredentials/patches/mfe-env-production create mode 100644 tutorcredentials/patches/openedx-lms-common-settings create mode 100644 tutorcredentials/patches/openedx-lms-development-settings create mode 100644 tutorcredentials/patches/openedx-lms-production-settings create mode 100644 tutorcredentials/templates/credentials/apps/credentials/settings/__init__.py create mode 100644 tutorcredentials/templates/credentials/apps/credentials/settings/development.py create mode 100644 tutorcredentials/templates/credentials/apps/credentials/settings/partials/common.py create mode 100644 tutorcredentials/templates/credentials/apps/credentials/settings/production.py create mode 100644 tutorcredentials/templates/credentials/build/credentials/Dockerfile create mode 100644 tutorcredentials/templates/credentials/build/credentials/assets.py create mode 100644 tutorcredentials/templates/credentials/build/credentials/requirements/private-sample.txt create mode 100644 tutorcredentials/templates/credentials/tasks/credentials/init create mode 100644 tutorcredentials/templates/credentials/tasks/lms/init create mode 100644 tutorcredentials/templates/credentials/tasks/mysql/init diff --git a/setup.py b/setup.py index 1970cf6..c761476 100644 --- a/setup.py +++ b/setup.py @@ -31,10 +31,12 @@ setup( project_urls={ "Code": "https://github.com/lpm0073/tutor-contrib-credentials", "Issue tracker": "https://github.com/lpm0073/tutor-contrib-credentials/issues", + "Community": "https://discuss.overhang.io", }, license="AGPLv3", author="Lawrence McDaniel", - description="credentials plugin for Tutor", + author_email="lpm0073@gmail.com", + description="A Tutor plugin for Open edX Credentials service", long_description=load_readme(), packages=find_packages(exclude=["tests*"]), include_package_data=True, diff --git a/tutorcredentials/patches/caddyfile b/tutorcredentials/patches/caddyfile new file mode 100644 index 0000000..b542be6 --- /dev/null +++ b/tutorcredentials/patches/caddyfile @@ -0,0 +1,7 @@ +# credentials service +{{ CREDENTIALS_HOST }}{$default_site_port} { + request_body { + max_size 10MB + } + import proxy "credentials:8000" +} diff --git a/tutorcredentials/patches/k8s-deployments b/tutorcredentials/patches/k8s-deployments new file mode 100644 index 0000000..e8891c8 --- /dev/null +++ b/tutorcredentials/patches/k8s-deployments @@ -0,0 +1,37 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: credentials + labels: + app.kubernetes.io/name: credentials +spec: + selector: + matchLabels: + app.kubernetes.io/name: credentials + template: + metadata: + labels: + app.kubernetes.io/name: credentials + spec: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + containers: + - name: credentials + image: {{ CREDENTIALS_DOCKER_IMAGE }} + ports: + - containerPort: 8000 + env: + - name: DJANGO_SETTINGS_MODULE + value: credentials.settings.tutor.production + volumeMounts: + - mountPath: /openedx/credentials/credentials/settings/tutor/production.py + name: settings + subPath: production.py + securityContext: + allowPrivilegeEscalation: false + volumes: + - name: settings + configMap: + name: credentials-settings diff --git a/tutorcredentials/patches/k8s-jobs b/tutorcredentials/patches/k8s-jobs new file mode 100644 index 0000000..e394320 --- /dev/null +++ b/tutorcredentials/patches/k8s-jobs @@ -0,0 +1,25 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: credentials-job + labels: + app.kubernetes.io/component: job +spec: + template: + spec: + restartPolicy: Never + containers: + - name: credentials + image: {{ CREDENTIALS_DOCKER_IMAGE }} + env: + - name: DJANGO_SETTINGS_MODULE + value: credentials.settings.tutor.production + volumeMounts: + - mountPath: /openedx/credentials/credentials/settings/tutor/production.py + name: settings + subPath: production.py + volumes: + - name: settings + configMap: + name: credentials-settings \ No newline at end of file diff --git a/tutorcredentials/patches/k8s-services b/tutorcredentials/patches/k8s-services new file mode 100644 index 0000000..09f8985 --- /dev/null +++ b/tutorcredentials/patches/k8s-services @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: credentials +spec: + type: NodePort + ports: + - port: 8000 + protocol: TCP + selector: + app.kubernetes.io/name: credentials diff --git a/tutorcredentials/patches/kustomization-configmapgenerator b/tutorcredentials/patches/kustomization-configmapgenerator new file mode 100644 index 0000000..c7022ec --- /dev/null +++ b/tutorcredentials/patches/kustomization-configmapgenerator @@ -0,0 +1,3 @@ +- name: credentials-settings + files: + - plugins/credentials/apps/credentials/settings/production.py diff --git a/tutorcredentials/patches/local-docker-compose-caddy-aliases b/tutorcredentials/patches/local-docker-compose-caddy-aliases new file mode 100644 index 0000000..f7309a4 --- /dev/null +++ b/tutorcredentials/patches/local-docker-compose-caddy-aliases @@ -0,0 +1 @@ +- {{ CREDENTIALS_HOST }} \ No newline at end of file diff --git a/tutorcredentials/patches/local-docker-compose-dev-services b/tutorcredentials/patches/local-docker-compose-dev-services new file mode 100644 index 0000000..2840e06 --- /dev/null +++ b/tutorcredentials/patches/local-docker-compose-dev-services @@ -0,0 +1,15 @@ +credentials: + environment: + DJANGO_SETTINGS_MODULE: credentials.settings.tutor.development + command: ./manage.py runserver 0.0.0.0:8150 + ports: + - "127.0.0.1:8150:8150" + stdin_open: true + tty: true + volumes: + # editable requirements + - ../plugins/credentials/build/credentials/requirements:/openedx/requirements + networks: + default: + aliases: + - "{{ CREDENTIALS_HOST }}" \ No newline at end of file diff --git a/tutorcredentials/patches/local-docker-compose-jobs-services b/tutorcredentials/patches/local-docker-compose-jobs-services new file mode 100644 index 0000000..0ad9f82 --- /dev/null +++ b/tutorcredentials/patches/local-docker-compose-jobs-services @@ -0,0 +1,7 @@ +credentials-job: + image: {{ CREDENTIALS_DOCKER_IMAGE }} + environment: + DJANGO_SETTINGS_MODULE: credentials.settings.tutor.production + volumes: + - ../plugins/credentials/apps/credentials/settings:/openedx/credentials/credentials/settings/tutor:ro + depends_on: {{ [("mysql", RUN_MYSQL)]|list_if }} \ No newline at end of file diff --git a/tutorcredentials/patches/local-docker-compose-services b/tutorcredentials/patches/local-docker-compose-services new file mode 100644 index 0000000..d040a69 --- /dev/null +++ b/tutorcredentials/patches/local-docker-compose-services @@ -0,0 +1,11 @@ +credentials: + image: {{ CREDENTIALS_DOCKER_IMAGE }} + environment: + DJANGO_SETTINGS_MODULE: credentials.settings.tutor.production + restart: unless-stopped + volumes: + - ../plugins/credentials/apps/credentials/settings:/openedx/credentials/credentials/settings/tutor:ro + depends_on: + - discovery + {% if RUN_MYSQL %}- mysql{% endif %} + {% if RUN_LMS %}- lms{% endif %} diff --git a/tutorcredentials/patches/mfe-env-development b/tutorcredentials/patches/mfe-env-development new file mode 100644 index 0000000..a3c1aee --- /dev/null +++ b/tutorcredentials/patches/mfe-env-development @@ -0,0 +1 @@ +CREDENTIALS_BASE_URL='http://{{ CREDENTIALS_HOST }}:8150' diff --git a/tutorcredentials/patches/mfe-env-production b/tutorcredentials/patches/mfe-env-production new file mode 100644 index 0000000..d199113 --- /dev/null +++ b/tutorcredentials/patches/mfe-env-production @@ -0,0 +1 @@ +CREDENTIALS_BASE_URL='{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ CREDENTIALS_HOST }}' diff --git a/tutorcredentials/patches/openedx-lms-common-settings b/tutorcredentials/patches/openedx-lms-common-settings new file mode 100644 index 0000000..06ac61e --- /dev/null +++ b/tutorcredentials/patches/openedx-lms-common-settings @@ -0,0 +1,5 @@ +EDX_API_KEY = "{{ CREDENTIALS_API_KEY }}" +CREDENTIALS_API_SIGNING_KEY = "{{ JWT_COMMON_SECRET_KEY }}" +CREDENTIALS_API_TIMEOUT = {{ CREDENTIALS_API_TIMEOUT }} +EDX_API_KEY = "{{ CREDENTIALS_API_KEY }}" +CREDENTIALS_API_SIGNING_KEY = "{{ JWT_COMMON_SECRET_KEY }}" diff --git a/tutorcredentials/patches/openedx-lms-development-settings b/tutorcredentials/patches/openedx-lms-development-settings new file mode 100644 index 0000000..61ad3e8 --- /dev/null +++ b/tutorcredentials/patches/openedx-lms-development-settings @@ -0,0 +1,2 @@ +CREDENTIALS_PUBLIC_URL_ROOT = "http://{{ CREDENTIALS_HOST }}:8150" +CREDENTIALS_API_URL = CREDENTIALS_PUBLIC_URL_ROOT + "/api/v2" \ No newline at end of file diff --git a/tutorcredentials/patches/openedx-lms-production-settings b/tutorcredentials/patches/openedx-lms-production-settings new file mode 100644 index 0000000..be391fa --- /dev/null +++ b/tutorcredentials/patches/openedx-lms-production-settings @@ -0,0 +1,2 @@ +CREDENTIALS_PUBLIC_URL_ROOT = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ CREDENTIALS_HOST }}" +CREDENTIALS_API_URL = CREDENTIALS_PUBLIC_URL_ROOT + "/api/v2" diff --git a/tutorcredentials/plugin.py b/tutorcredentials/plugin.py index 062b915..ae89146 100644 --- a/tutorcredentials/plugin.py +++ b/tutorcredentials/plugin.py @@ -2,7 +2,7 @@ from glob import glob import os import pkg_resources -from tutor import hooks +from tutor import hooks as tutor_hooks from .__about__ import __version__ @@ -12,6 +12,18 @@ config = { # Add here your new settings "defaults": { "VERSION": __version__, + "API_TIMEOUT": 5, + "CURRENCY": "USD", + "DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-credentials:{{ CREDENTIALS_VERSION }}", + "WORKER_DOCKER_IMAGE": "{{ DOCKER_REGISTRY }}overhangio/openedx-credentials-worker:{{ CREDENTIALS_VERSION }}", + "EXTRA_PIP_REQUIREMENTS": [], + "HOST": "credentials.{{ LMS_HOST }}", + "MYSQL_DATABASE": "credentials", + "MYSQL_USERNAME": "credentials", + "OAUTH2_KEY": "credentials", + "OAUTH2_KEY_DEV": "credentials-dev", + "OAUTH2_KEY_SSO": "credentials-sso", + "OAUTH2_KEY_SSO_DEV": "credentials-sso-dev", }, # Add here settings that don't have a reasonable default for all users. For # instance: passwords, secret keys, etc. @@ -25,39 +37,50 @@ config = { } ################# Initialization tasks -# To run the script from templates/credentials/tasks/myservice/init, add: -# hooks.Filters.COMMANDS_INIT.add_item(( -# "myservice", -# ("credentials", "tasks", "myservice", "init"), -# )) +tutor_hooks.Filters.COMMANDS_INIT.add_item( + ( + "lms", + ("credentials", "tasks", "lms", "init"), + ) +) +tutor_hooks.Filters.IMAGES_BUILD.add_item( + ( + "credentials", + ("plugins", "credentials", "build", "credentials"), + "{{ CREDENTIALS_DOCKER_IMAGE }}", + (), + ) +) -################# Docker image management -# To build an image with `tutor images build myimage`, add a Dockerfile to templates/credentials/build/myimage and write: -# hooks.Filters.IMAGES_BUILD.add_item(( -# "myimage", -# ("plugins", "credentials", "build", "myimage"), -# "docker.io/myimage:\{\{ CREDENTIALS_VERSION \}\}", -# (), -# ) -# To pull/push an image with `tutor images pull myimage` and `tutor images push myimage`, write: -# hooks.Filters.IMAGES_PULL.add_item(( -# "myimage", -# "docker.io/myimage:\{\{ CREDENTIALS_VERSION \}\}", -# ) -# hooks.Filters.IMAGES_PUSH.add_item(( -# "myimage", -# "docker.io/myimage:\{\{ CREDENTIALS_VERSION \}\}", -# ) +@tutor_hooks.Filters.IMAGES_PULL.add() +@tutor_hooks.Filters.IMAGES_PUSH.add() +def _add_remote_credentials_image_iff_customized(images, user_config): + """ + Register CREDENTIALS image for pushing & pulling if and only if it has + been set to something other than the default. + + This is work-around to an upstream issue with CREDENTIALS config. Briefly: + User config is baked into CREDENTIALS builds, so Tutor cannot host a generic + pre-built CREDENTIALS image. Howevever, individual Tutor users may want/need to + build and host their own CREDENTIALS image. So, as a compromise, we tell Tutor + to push/pull the CREDENTIALS image if the user has customized it to anything + other than the default image URL. + """ + image_tag = user_config["CREDENTIALS_DOCKER_IMAGE"] + if not image_tag.startswith("docker.io/lpm0073/openedx-credentials:"): + # Image has been customized. Add to list for pulling/pushing. + images.append(("credentials", image_tag)) + return images ################# You don't really have to bother about what's below this line, ################# except maybe for educational purposes :) # Plugin templates -hooks.Filters.ENV_TEMPLATE_ROOTS.add_item( +tutor_hooks.Filters.ENV_TEMPLATE_ROOTS.add_item( pkg_resources.resource_filename("tutorcredentials", "templates") ) -hooks.Filters.ENV_TEMPLATE_TARGETS.add_items( +tutor_hooks.Filters.ENV_TEMPLATE_TARGETS.add_items( [ ("credentials/build", "plugins"), ("credentials/apps", "plugins"), @@ -71,19 +94,19 @@ for path in glob( ) ): with open(path, encoding="utf-8") as patch_file: - hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read())) + tutor_hooks.Filters.ENV_PATCHES.add_item((os.path.basename(path), patch_file.read())) # Load all configuration entries -hooks.Filters.CONFIG_DEFAULTS.add_items( +tutor_hooks.Filters.CONFIG_DEFAULTS.add_items( [ (f"CREDENTIALS_{key}", value) for key, value in config["defaults"].items() ] ) -hooks.Filters.CONFIG_UNIQUE.add_items( +tutor_hooks.Filters.CONFIG_UNIQUE.add_items( [ (f"CREDENTIALS_{key}", value) for key, value in config["unique"].items() ] ) -hooks.Filters.CONFIG_OVERRIDES.add_items(list(config["overrides"].items())) +tutor_hooks.Filters.CONFIG_OVERRIDES.add_items(list(config["overrides"].items())) diff --git a/tutorcredentials/templates/credentials/apps/credentials/settings/__init__.py b/tutorcredentials/templates/credentials/apps/credentials/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tutorcredentials/templates/credentials/apps/credentials/settings/development.py b/tutorcredentials/templates/credentials/apps/credentials/settings/development.py new file mode 100644 index 0000000..596e5d9 --- /dev/null +++ b/tutorcredentials/templates/credentials/apps/credentials/settings/development.py @@ -0,0 +1,14 @@ +from ..devstack import * + +{% include "credentials/apps/credentials/settings/partials/common.py" %} + +CORS_ORIGIN_WHITELIST = list(CORS_ORIGIN_WHITELIST) + [ + "http://{{ MFE_HOST }}:{{ CREDENTIALS_MFE_APP['port'] }}", +] +CSRF_TRUSTED_ORIGINS = ["{{ MFE_HOST }}:{{ CREDENTIALS_MFE_APP['port'] }}"] + +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = "http://{{ LMS_HOST }}:8000" + +BACKEND_SERVICE_EDX_OAUTH2_KEY = "{{ CREDENTIALS_OAUTH2_KEY_DEV }}" + +{{ patch("credentials-settings-development") }} diff --git a/tutorcredentials/templates/credentials/apps/credentials/settings/partials/common.py b/tutorcredentials/templates/credentials/apps/credentials/settings/partials/common.py new file mode 100644 index 0000000..099f4d4 --- /dev/null +++ b/tutorcredentials/templates/credentials/apps/credentials/settings/partials/common.py @@ -0,0 +1,82 @@ +import json + +SECRET_KEY = "{{ CREDENTIALS_SECRET_KEY }}" +ALLOWED_HOSTS = [ + "{{ CREDENTIALS_HOST }}", + "credentials", +] +PLATFORM_NAME = "{{ PLATFORM_NAME }}" +PROTOCOL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}" + +CORS_ALLOW_CREDENTIALS = True + +OSCAR_DEFAULT_CURRENCY = "{{ CREDENTIALS_CURRENCY }}" + +EDX_API_KEY = "{{ CREDENTIALS_API_KEY }}" +{% set jwt_rsa_key = rsa_import_key(JWT_RSA_PRIVATE_KEY) %} +JWT_AUTH["JWT_ISSUER"] = "{{ JWT_COMMON_ISSUER }}" +JWT_AUTH["JWT_AUDIENCE"] = "{{ JWT_COMMON_AUDIENCE }}" +JWT_AUTH["JWT_SECRET_KEY"] = "{{ JWT_COMMON_SECRET_KEY }}" +JWT_AUTH["JWT_PUBLIC_SIGNING_JWK_SET"] = json.dumps( + { + "keys": [ + { + "kid": "openedx", + "kty": "RSA", + "e": "{{ jwt_rsa_key.e|long_to_base64 }}", + "n": "{{ jwt_rsa_key.n|long_to_base64 }}", + } + ] + } +) +JWT_AUTH["JWT_ISSUERS"] = [ + { + "ISSUER": "{{ JWT_COMMON_ISSUER }}", + "AUDIENCE": "{{ JWT_COMMON_AUDIENCE }}", + "SECRET_KEY": "{{ OPENEDX_SECRET_KEY }}" + } +] + +SOCIAL_AUTH_REDIRECT_IS_HTTPS = {% if ENABLE_HTTPS %}True{% else %}False{% endif %} +SOCIAL_AUTH_EDX_OAUTH2_ISSUER = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}" +SOCIAL_AUTH_EDX_OAUTH2_URL_ROOT = "http://lms:8000" + +BACKEND_SERVICE_EDX_OAUTH2_SECRET = "{{ CREDENTIALS_OAUTH2_SECRET }}" +BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = "http://lms:8000/oauth2" + +EDX_DRF_EXTENSIONS = { + 'OAUTH2_USER_INFO_URL': '{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/oauth2/user_info', +} + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": "{{ CREDENTIALS_MYSQL_DATABASE }}", + "USER": "{{ CREDENTIALS_MYSQL_USERNAME }}", + "PASSWORD": "{{ CREDENTIALS_MYSQL_PASSWORD }}", + "HOST": "{{ MYSQL_HOST }}", + "PORT": "{{ MYSQL_PORT }}", + "OPTIONS": { + "init_command": "SET sql_mode='STRICT_TRANS_TABLES'", + }, + } +} + +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = "{{ SMTP_HOST }}" +EMAIL_PORT = "{{ SMTP_PORT }}" +EMAIL_HOST_USER = "{{ SMTP_USERNAME }}" +EMAIL_HOST_PASSWORD = "{{ SMTP_PASSWORD }}" +EMAIL_USE_TLS = {{SMTP_USE_TLS}} + +ENTERPRISE_SERVICE_URL = '{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/enterprise/' +ENTERPRISE_API_URL = urljoin(ENTERPRISE_SERVICE_URL, 'api/v1/') + +# Get rid of local logger +LOGGING["handlers"].pop("local") +for logger in LOGGING["loggers"].values(): + logger["handlers"].remove("local") + + + +{{ patch("credentials-settings-common") }} diff --git a/tutorcredentials/templates/credentials/apps/credentials/settings/production.py b/tutorcredentials/templates/credentials/apps/credentials/settings/production.py new file mode 100644 index 0000000..5a784ad --- /dev/null +++ b/tutorcredentials/templates/credentials/apps/credentials/settings/production.py @@ -0,0 +1,14 @@ +from ..production import * + +{% include "credentials/apps/credentials/settings/partials/common.py" %} + +CORS_ORIGIN_WHITELIST = list(CORS_ORIGIN_WHITELIST) + [ + "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ MFE_HOST }}", +] +CSRF_TRUSTED_ORIGINS = ["{{ MFE_HOST }}"] + +SOCIAL_AUTH_EDX_OAUTH2_PUBLIC_URL_ROOT = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}" + +BACKEND_SERVICE_EDX_OAUTH2_KEY = "{{ CREDENTIALS_OAUTH2_KEY }}" + +{{ patch("credentials-settings-production") }} diff --git a/tutorcredentials/templates/credentials/build/credentials/Dockerfile b/tutorcredentials/templates/credentials/build/credentials/Dockerfile new file mode 100644 index 0000000..db4c704 --- /dev/null +++ b/tutorcredentials/templates/credentials/build/credentials/Dockerfile @@ -0,0 +1,71 @@ +FROM docker.io/ubuntu:20.04 + +RUN apt update && \ + apt install -y curl git-core language-pack-en libmysqlclient-dev libssl-dev python3 python3-pip python3-venv + +ARG APP_USER_ID=1000 +RUN useradd --home-dir /openedx --create-home --shell /bin/bash --uid ${APP_USER_ID} app +USER ${APP_USER_ID} + +# Create python venv +RUN python3 -m venv /openedx/venv/ +ENV PATH "/openedx/venv/bin:$PATH" +RUN pip install setuptools==44.1.0 pip==20.3.4 wheel==0.37.0 + +# Install a recent version of nodejs +RUN pip install nodeenv +RUN nodeenv /openedx/nodeenv --node=12.13.0 --prebuilt +ENV PATH /openedx/nodeenv/bin:${PATH} + +# Install credentials +ARG CREDENTIALS_REPOSITORY=https://github.com/edx/credentials.git +ARG CREDENTIALS_VERSION={{ OPENEDX_COMMON_VERSION }} +RUN mkdir -p /openedx/credentials && \ + git clone $CREDENTIALS_REPOSITORY --branch $CREDENTIALS_VERSION --depth 1 /openedx/credentials +WORKDIR /openedx/credentials + +# Identify tutor user to cherry-pick commits +RUN git config --global user.email "tutor@overhang.io" \ + && git config --global user.name "Tutor" + +# nodejs requirements (aka: "make requirements.js") +ARG NPM_REGISTRY=https://registry.npmjs.org/ +RUN npm install --verbose --registry=$NPM_REGISTRY +RUN ./node_modules/.bin/bower install --allow-root + +# python requirements +RUN pip install -r requirements.txt +RUN pip install uwsgi==2.0.19.1 + +# Install private requirements +COPY --chown=app:app ./requirements/ /openedx/requirements +RUN cd /openedx/requirements/ \ + && touch ./private.txt \ + && pip install -r ./private.txt + +{% for extra_requirement in CREDENTIALS_EXTRA_PIP_REQUIREMENTS %}RUN pip install {{ extra_requirement }} +{% endfor %} + +# Collect static assets (aka: "make static") +COPY --chown=app:app assets.py ./credentials/settings/assets.py +ENV DJANGO_SETTINGS_MODULE credentials.settings.assets +RUN python3 manage.py update_assets --skip-collect +RUN ./node_modules/.bin/r.js -o build.js +RUN python3 manage.py collectstatic --noinput +RUN python3 manage.py compress --force + +# Setup minimal yml config file, which is required by production settings +RUN echo "{}" > /openedx/config.yml +ENV CREDENTIALS_CFG /openedx/config.yml + +EXPOSE 8000 +CMD uwsgi \ + --static-map /static=/openedx/credentials/assets \ + --static-map /media=/openedx/credentials/course_credentials/media \ + --http 0.0.0.0:8000 \ + --thunder-lock \ + --single-interpreter \ + --enable-threads \ + --processes=2 \ + --buffer-size=8192 \ + --wsgi-file credentials/wsgi.py diff --git a/tutorcredentials/templates/credentials/build/credentials/assets.py b/tutorcredentials/templates/credentials/build/credentials/assets.py new file mode 100644 index 0000000..d9c32cc --- /dev/null +++ b/tutorcredentials/templates/credentials/build/credentials/assets.py @@ -0,0 +1,9 @@ +from .base import * + +# Get rid of local logger +LOGGING["handlers"].pop("local") +for logger in LOGGING["loggers"].values(): + logger["handlers"].remove("local") + +COMPRESS_ENABLED = True +COMPRESS_OFFLINE = True diff --git a/tutorcredentials/templates/credentials/build/credentials/requirements/private-sample.txt b/tutorcredentials/templates/credentials/build/credentials/requirements/private-sample.txt new file mode 100644 index 0000000..c7e74cc --- /dev/null +++ b/tutorcredentials/templates/credentials/build/credentials/requirements/private-sample.txt @@ -0,0 +1,6 @@ +# Add your additional requirements, such as payment processors, to this file. For +# requirements coming from private repositories, clone the repository to this +# folder and then add your requirement with the `-e` flag. Ex: +# +# git clone git@myserver:myprivaterepo.git +# echo "-e ./myprivaterepo/" >> private.txt diff --git a/tutorcredentials/templates/credentials/tasks/credentials/init b/tutorcredentials/templates/credentials/tasks/credentials/init new file mode 100644 index 0000000..93d5e83 --- /dev/null +++ b/tutorcredentials/templates/credentials/tasks/credentials/init @@ -0,0 +1 @@ +./manage.py migrate --noinput diff --git a/tutorcredentials/templates/credentials/tasks/lms/init b/tutorcredentials/templates/credentials/tasks/lms/init new file mode 100644 index 0000000..e69de29 diff --git a/tutorcredentials/templates/credentials/tasks/mysql/init b/tutorcredentials/templates/credentials/tasks/mysql/init new file mode 100644 index 0000000..31c7b98 --- /dev/null +++ b/tutorcredentials/templates/credentials/tasks/mysql/init @@ -0,0 +1,4 @@ +mysql -u {{ MYSQL_ROOT_USERNAME }} --password="{{ MYSQL_ROOT_PASSWORD }}" --host "{{ MYSQL_HOST }}" --port {{ MYSQL_PORT }} -e 'CREATE DATABASE IF NOT EXISTS {{ CREDENTIALS_MYSQL_DATABASE }};' +mysql -u {{ MYSQL_ROOT_USERNAME }} --password="{{ MYSQL_ROOT_PASSWORD }}" --host "{{ MYSQL_HOST }}" --port {{ MYSQL_PORT }} -e "CREATE USER IF NOT EXISTS '{{ CREDENTIALS_MYSQL_USERNAME }}';" +mysql -u {{ MYSQL_ROOT_USERNAME }} --password="{{ MYSQL_ROOT_PASSWORD }}" --host "{{ MYSQL_HOST }}" --port {{ MYSQL_PORT }} -e "ALTER USER '{{ CREDENTIALS_MYSQL_USERNAME }}'@'%' IDENTIFIED BY '{{ CREDENTIALS_MYSQL_PASSWORD }}';" +mysql -u {{ MYSQL_ROOT_USERNAME }} --password="{{ MYSQL_ROOT_PASSWORD }}" --host "{{ MYSQL_HOST }}" --port {{ MYSQL_PORT }} -e "GRANT ALL ON {{ CREDENTIALS_MYSQL_DATABASE }}.* TO '{{ CREDENTIALS_MYSQL_USERNAME }}'@'%';"