Commit e2fe6746 by John Jarvis

Merge pull request #292 from edx/jarv/edxapp-mixedmodule

Jarv/edxapp mixedmodule
parents ff71848b a0b37ec6
......@@ -2,14 +2,16 @@
# when the role is included
---
# These are default values for the env and auth
# configuration files. There should be no
# host identifying or sensitive information and
# the defaults should be appropriate for running
# all roles on a single instance
# These are custom variables that can be overridden
# on the command line to change specific values in the hash
# These are variables that default to a localhost
# setup and are meant to be overwritten for
# different environments.
#
# Variables in all caps are environment specific
# Lowercase variables are internal to the role
#
# Defaults specified here should not contain
# any secrets or host identifying information.
EDXAPP_LMS_BASE: ''
EDXAPP_PREVIEW_LMS_BASE: ''
EDXAPP_CMS_BASE: ''
......@@ -20,10 +22,11 @@ EDXAPP_XQUEUE_DJANGO_AUTH:
username: 'lms'
password: 'password'
EDXAPP_MONGO_HOST: ['localhost']
EDXAPP_MONGO_HOSTS: ['localhost']
EDXAPP_MONGO_PASSWORD: 'password'
EDXAPP_MONGO_PORT: 27017
EDXAPP_MONGO_USER: 'mongo'
EDXAPP_MONGO_DB_NAME: 'edxapp'
EDXAPP_MYSQL_DB_NAME: 'edxapp'
EDXAPP_MYSQL_USER: 'root'
......@@ -73,130 +76,143 @@ EDXAPP_LOGGING_ENV: 'sandbox'
EDXAPP_SYSLOG_SERVER: ''
EDXAPP_RABBIT_HOSTNAME: 'rabbit.{{ENV_NAME}}.vpc.edx.org'
EDXAPP_XML_MAPPINGS: {}
#-------- Everything below this line is internal to the role ------------
#Use YAML references (& and *) and hash merge <<: to factor out shared settings
#see http://atechie.net/2009/07/merging-hashes-in-yaml-conf-files/
edxapp_generic_auth_config: &edxapp_generic_auth
'AWS_ACCESS_KEY_ID': $EDXAPP_AWS_ACCESS_KEY_ID
'AWS_SECRET_ACCESS_KEY': $EDXAPP_AWS_SECRET_ACCESS_KEY
'SECRET_KEY': $EDXAPP_EDXAPP_SECRET_KEY
'XQUEUE_INTERFACE':
'basic_auth': $EDXAPP_XQUEUE_BASIC_AUTH
'django_auth': $EDXAPP_XQUEUE_DJANGO_AUTH
'url': $EDXAPP_XQUEUE_URL
'CONTENTSTORE':
'ENGINE': 'xmodule.contentstore.mongo.MongoContentStore'
'OPTIONS':
'db': $EDXAPP_MONGO_DB_NAME
'host': $EDXAPP_MONGO_HOSTS
'password': $EDXAPP_MONGO_PASSWORD
'port': $EDXAPP_MONGO_PORT
'user': $EDXAPP_MONGO_USER
'MODULESTORE':
'default':
'ENGINE': 'xmodule.modulestore.mongo.DraftMongoModuleStore'
'OPTIONS': &generic_modulestore_default_options
'collection': 'modulestore'
'db': $EDXAPP_MONGO_DB_NAME
'default_class': 'xmodule.hidden_module.HiddenDescriptor'
'fs_root': '/opt/wwc/data'
'host': $EDXAPP_MONGO_HOSTS
'password': $EDXAPP_MONGO_PASSWORD
'port': $EDXAPP_MONGO_PORT
'render_template': 'mitxmako.shortcuts.render_to_string'
'user': $EDXAPP_MONGO_USER
AWS_ACCESS_KEY_ID: $EDXAPP_AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $EDXAPP_AWS_SECRET_ACCESS_KEY
SECRET_KEY: $EDXAPP_EDXAPP_SECRET_KEY
XQUEUE_INTERFACE:
basic_auth: $EDXAPP_XQUEUE_BASIC_AUTH
django_auth: $EDXAPP_XQUEUE_DJANGO_AUTH
url: $EDXAPP_XQUEUE_URL
CONTENTSTORE:
ENGINE: 'xmodule.contentstore.mongo.MongoContentStore'
OPTIONS:
db: $EDXAPP_MONGO_DB_NAME
host: $EDXAPP_MONGO_HOSTS
password: $EDXAPP_MONGO_PASSWORD
port: $EDXAPP_MONGO_PORT
user: $EDXAPP_MONGO_USER
MODULESTORE:
default:
ENGINE: 'xmodule.modulestore.mongo.DraftMongoModuleStore'
OPTIONS: &generic_modulestore_default_options
collection: 'modulestore'
db: $EDXAPP_MONGO_DB_NAME
default_class: 'xmodule.hidden_module.HiddenDescriptor'
fs_root: '/opt/wwc/data'
host: $EDXAPP_MONGO_HOSTS
password: $EDXAPP_MONGO_PASSWORD
port: $EDXAPP_MONGO_PORT
render_template: 'mitxmako.shortcuts.render_to_string'
user: $EDXAPP_MONGO_USER
# Needed for the CMS to be able to run update_templates
'direct':
'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore'
'OPTIONS': *generic_modulestore_default_options
'DATABASES':
'default':
'ENGINE': 'django.db.backends.mysql'
'NAME': $EDXAPP_MYSQL_DB_NAME
'USER': $EDXAPP_MYSQL_USER
'PASSWORD': $EDXAPP_MYSQL_PASSWORD
'HOST': $EDXAPP_MYSQL_HOST
'PORT': $EDXAPP_MYSQL_PORT
'PEARSON_TEST_PASSWORD': $EDXAPP_PEARSON_TEST_PASSWORD
'OPEN_ENDED_GRADING_INTERFACE':
'url': $EDXAPP_OEE_URL
'password': $EDXAPP_OEE_PASSWORD
'peer_grading': 'peer_grading'
'staff_grading': 'staff_grading'
'grading_controller': 'grading_controller'
'username': $EDXAPP_OEE_USER
'ANALYTICS_API_KEY': $EDXAPP_ANALYTICS_API_KEY
'ZENDESK_USER': $EDXAPP_ZENDESK_USER
'ZENDESK_API_KEY': $EDXAPP_ZENDESK_API_KEY
'CELERY_BROKER_USER': $EDXAPP_CELERY_USER
'CELERY_BROKER_PASSWORD': $EDXAPP_CELERY_PASSWORD
direct:
ENGINE: 'xmodule.modulestore.mongo.MongoModuleStore'
OPTIONS: *generic_modulestore_default_options
DATABASES:
default:
ENGINE: 'django.db.backends.mysql'
NAME: $EDXAPP_MYSQL_DB_NAME
USER: $EDXAPP_MYSQL_USER
PASSWORD: $EDXAPP_MYSQL_PASSWORD
HOST: $EDXAPP_MYSQL_HOST
PORT: $EDXAPP_MYSQL_PORT
PEARSON_TEST_PASSWORD: $EDXAPP_PEARSON_TEST_PASSWORD
OPEN_ENDED_GRADING_INTERFACE:
url: $EDXAPP_OEE_URL
password: $EDXAPP_OEE_PASSWORD
peer_grading: 'peer_grading'
staff_grading: 'staff_grading'
grading_controller: 'grading_controller'
username: $EDXAPP_OEE_USER
ANALYTICS_API_KEY: $EDXAPP_ANALYTICS_API_KEY
ZENDESK_USER: $EDXAPP_ZENDESK_USER
ZENDESK_API_KEY: $EDXAPP_ZENDESK_API_KEY
CELERY_BROKER_USER: $EDXAPP_CELERY_USER
CELERY_BROKER_PASSWORD: $EDXAPP_CELERY_PASSWORD
generic_env_config: &edxapp_generic_env
'LMS_BASE': $EDXAPP_LMS_BASE
'CMS_BASE': $EDXAPP_CMS_BASE
'BOOK_URL': $EDXAPP_BOOK_URL
'CERT_QUEUE': 'certificates'
'LOCAL_LOGLEVEL': $EDXAPP_LOG_LEVEL
LMS_BASE: $EDXAPP_LMS_BASE
CMS_BASE: $EDXAPP_CMS_BASE
BOOK_URL: $EDXAPP_BOOK_URL
CERT_QUEUE: 'certificates'
LOCAL_LOGLEVEL: $EDXAPP_LOG_LEVEL
# default email backed set to local SMTP
'EMAIL_BACKEND': $EDXAPP_EMAIL_BACKEND
'MITX_FEATURES': $EDXAPP_MITX_FEATURES
'WIKI_ENABLED': true
'SYSLOG_SERVER': $EDXAPP_SYSLOG_SERVER
'SITE_NAME': $EDXAPP_SITE_NAME
'LOG_DIR': '/mnt/logs/edx'
'MEDIA_URL': $EDXAPP_MEDIA_URL
'ANALYTICS_SERVER_URL': $EDXAPP_ANALYTICS_SERVER_URL
'FEEDBACK_SUBMISSION_EMAIL': $EDXAPP_FEEDBACK_SUBMISSION_EMAIL
'TIME_ZONE': 'America/New_York'
'CACHES':
'default': &default_generic_cache
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache'
'KEY_FUNCTION': 'util.memcache.safe_key'
'KEY_PREFIX': 'sandbox_default'
'LOCATION': $EDXAPP_MEMCACHE
'general':
EMAIL_BACKEND: $EDXAPP_EMAIL_BACKEND
MITX_FEATURES: $EDXAPP_MITX_FEATURES
WIKI_ENABLED: true
SYSLOG_SERVER: $EDXAPP_SYSLOG_SERVER
SITE_NAME: $EDXAPP_SITE_NAME
LOG_DIR: '/mnt/logs/edx'
MEDIA_URL: $EDXAPP_MEDIA_URL
ANALYTICS_SERVER_URL: $EDXAPP_ANALYTICS_SERVER_URL
FEEDBACK_SUBMISSION_EMAIL: $EDXAPP_FEEDBACK_SUBMISSION_EMAIL
TIME_ZONE: 'America/New_York'
CACHES:
default: &default_generic_cache
BACKEND: 'django.core.cache.backends.memcached.MemcachedCache'
KEY_FUNCTION: 'util.memcache.safe_key'
KEY_PREFIX: 'sandbox_default'
LOCATION: $EDXAPP_MEMCACHE
general:
<<: *default_generic_cache
'KEY_PREFIX': 'sandbox_general'
'mongo_metadata_inheritance':
KEY_PREFIX: 'sandbox_general'
mongo_metadata_inheritance:
<<: *default_generic_cache
'KEY_PREFIX': 'integration_mongo_metadata_inheritance'
'staticfiles':
KEY_PREFIX: 'integration_mongo_metadata_inheritance'
staticfiles:
<<: *default_generic_cache
'KEY_PREFIX': 'integration_static_files'
'celery':
KEY_PREFIX: 'integration_static_files'
celery:
<<: *default_generic_cache
'KEY_PREFIX': 'integration_celery'
'CELERY_BROKER_TRANSPORT': 'amqp'
'CELERY_BROKER_HOSTNAME': $EDXAPP_RABBIT_HOSTNAME
'COMMENTS_SERVICE_URL': $EDXAPP_COMMENTS_SERVICE_URL
'LOGGING_ENV': $EDXAPP_LOGGING_ENV
'SESSION_COOKIE_DOMAIN': !!null
'COMMENTS_SERVICE_KEY': $EDXAPP_COMMENTS_SERVICE_KEY
'SEGMENT_IO_LMS': true
'CODE_JAIL':
'limits':
'VMEM': 0
'REALTIME': 3
KEY_PREFIX: 'integration_celery'
CELERY_BROKER_TRANSPORT: 'amqp'
CELERY_BROKER_HOSTNAME: $EDXAPP_RABBIT_HOSTNAME
COMMENTS_SERVICE_URL: $EDXAPP_COMMENTS_SERVICE_URL
LOGGING_ENV: $EDXAPP_LOGGING_ENV
SESSION_COOKIE_DOMAIN: !!null
COMMENTS_SERVICE_KEY: $EDXAPP_COMMENTS_SERVICE_KEY
SEGMENT_IO_LMS: true
CODE_JAIL:
limits:
VMEM: 0
REALTIME: 3
lms_auth_config:
<<: *edxapp_generic_auth
'MODULESTORE':
'default':
'ENGINE': 'xmodule.modulestore.mongo.MongoModuleStore'
'OPTIONS': *generic_modulestore_default_options
MODULESTORE:
default:
ENGINE: 'xmodule.modulestore.mixed.MixedModuleStore'
OPTIONS:
mappings: $EDXAPP_XML_MAPPINGS
stores:
xml:
ENGINE: 'xmodule.modulestore.xml.XMLModuleStore'
OPTIONS:
data_dir: '/opt/wwc/data'
default_class: 'xmodule.hidden_module.HiddenDescriptor'
default:
OPTIONS:
default_class: 'xmodule.hidden_module.HiddenDescriptor'
host: $EDXAPP_MONGO_HOSTS
db: $EDXAPP_MONGO_DB_NAME
collection: 'modulestore'
render_template: 'mitxmako.shortcuts.render_to_string'
user: $EDXAPP_MONGO_USER
password: $EDXAPP_MONGO_PASSWORD
port: $EDXAPP_MONGO_PORT
fs_root: '/opt/wwc/data'
ENGINE: 'xmodule.modulestore.mongo.MongoModuleStore'
lms_env_config:
<<: *edxapp_generic_env
lms_xml_auth_config:
<<: *edxapp_generic_auth
'MODULESTORE':
'default':
'ENGINE': 'xmodule.modulestore.xml.XMLModuleStore'
'OPTIONS':
'data_dir': '/opt/wwc/data'
'default_class': 'xmodule.hidden_module.HiddenDescriptor'
lms_xml_env_config:
<<: *edxapp_generic_env
cms_auth_config:
<<: *edxapp_generic_auth
cms_env_config:
......@@ -216,19 +232,16 @@ edx_platform_code_dir: "{{ app_base_dir }}/edx-platform"
# to serve all content on port 80
lms_xml_nginx_port: 18030
lms_nginx_port: 80
lms_preview_nginx_port: 18020
cms_nginx_port: 18010
edxapp_cms_app_port: 8010
edxapp_lms_app_port: 8000
edxapp_lms_xml_app_port: 8030
edxapp_lms_preview_app_port: 8020
edxapp_cms_app_address: 127.0.0.1
edxapp_lms_app_address: 127.0.0.1
edxapp_lms_xml_app_address: 127.0.0.1
edxapp_lms_preview_app_address: 127.0.0.1
# These vars are for creating the application json config
......@@ -249,7 +262,6 @@ edxapp_lms_env: 'lms.envs.aws'
worker_core_mult:
lms: 4
lms_preview: 2
lms_xml: 2
cms: 2
#Theming
......
......@@ -3,7 +3,6 @@
service: name=edxapp state=started
tags:
- lms
- lms-xml
- lms-preview
- cms
- deploy
......@@ -12,7 +11,6 @@
service: name=edxapp state=stopped
tags:
- lms
- lms-xml
- lms-preview
- cms
- deploy
......@@ -21,7 +19,6 @@
service: name=edxapp state=restarted
tags:
- lms
- lms-xml
- lms-preview
- cms
- deploy
......@@ -4,7 +4,6 @@
when: celery_worker is not defined
tags:
- lms
- lms-xml
- lms-preview
- cms
- deploy
......@@ -46,7 +45,6 @@
when: edxapp_theme_name != ''
tags:
- cms
- lms-xml
- lms-preview
- lms
- update
......@@ -171,7 +169,6 @@
tags:
- lms
- lms-preview
- lms-xml
- deploy
# Gather cms assets using rake if possible
......@@ -198,7 +195,6 @@
tags:
- deploy
- lms
- lms-xml
- lms-preview
- cms
- syncdb
......@@ -209,7 +205,6 @@
tags:
- deploy
- lms
- lms-xml
- lms-preview
- cms
- syncdb
......@@ -220,7 +215,6 @@
tags:
- deploy
- lms
- lms-xml
- lms-preview
- cms
- migrate
......@@ -230,7 +224,6 @@
when: celery_worker is not defined
tags:
- lms
- lms-xml
- lms-preview
- cms
- deploy
......
# requires:
# - group_vars/all
# - common/tasks/main.yml
# - nginx/tasks/main.yml
---
- name: create lms-xml application config
template: src=lms-xml.env.json.j2 dest=$app_base_dir/lms-xml.env.json mode=640 owner=www-data group=adm
tags:
- lms-xml-env
- lmx-xml
- update
- name: create lms-xml auth file
template: src=lms-xml.auth.json.j2 dest=$app_base_dir/lms-xml.auth.json mode=640 owner=www-data group=adm
tags:
- lms-xml-env
- lmx-xml
- update
- name: Create lms-xml log target directory
file: path={{log_base_dir}}/lms-xml state=directory owner=syslog group=adm mode=2770
tags:
- lms-xml
- lms-xml-env
- logging
- update
- include: ../../nginx/tasks/nginx_site.yml state=link site_name=lms-xml
when: celery_worker is not defined
- include: ../../nginx/tasks/nginx_site.yml state=link site_name=lms-xml-backend
when: celery_worker is not defined
# Creates upstart file
- include: upstart.yml basename=lms-xml
when: celery_worker is not defined
- include: upstart.yml basename=edx-worker-lms-xml
when: celery_worker is defined
......@@ -38,8 +38,6 @@
- include: lms.yml
when: "'lms' in service_variants_enabled"
- include: lms-xml.yml
when: "'lms-xml' in service_variants_enabled"
- include: cms.yml
when: "'cms' in service_variants_enabled"
- include: lms-preview.yml
......
# gunicorn
# Templated and placed by ansible from jinja2 source
# lms-xml Celery Worker Upstart Script
description "cms celery worker"
stop on stopping edx-workers
respawn
instance edx.${SERVICE_VARIANT}.core.${QUEUE}
#env NEW_RELIC_CONFIG_FILE=/opt/wwc/newrelic.ini
#env NEWRELIC={{venv_dir}}/bin/newrelic-admin
env CONCURRENCY=${CONCURRENCY}
env LOGLEVEL=info
env DJANGO_SETTINGS_MODULE={{worker_django_settings_module}}
env PYTHONPATH={{edx_platform_code_dir}}
env SERVICE_VARIANT=${SERVICE_VARIANT}
setuid www-data
chdir {{edx_platform_code_dir}}
exec {{venv_dir}}/bin/python {{edx_platform_code_dir}}/manage.py lms --service-variant=$SERVICE_VARIANT --settings=$DJANGO_SETTINGS_MODULE celery worker --loglevel=$LOGLEVEL --queues=edx.${SERVICE_VARIANT}.core.${QUEUE} --hostname=edx.${SERVICE_VARIANT}.core.${QUEUE}.`hostname` --concurrency=$CONCURRENCY
......@@ -20,10 +20,4 @@ pre-start script
start edx-worker-lms QUEUE=high CONCURRENCY=4 SERVICE_VARIANT=lms
{% endif %}
{% if 'lms-xml' in service_variants_enabled %}
start edx-worker-lms-xml QUEUE=low CONCURRENCY=1 SERVICE_VARIANT=lms-xml
start edx-worker-lms-xml QUEUE=default CONCURRENCY=3 SERVICE_VARIANT=lms-xml
start edx-worker-lms-xml QUEUE=high CONCURRENCY=4 SERVICE_VARIANT=lms-xml
{% endif %}
end script
......@@ -11,12 +11,6 @@ stop on runlevel [!2345]
##
pre-start script
{% if 'lms-xml' in service_variants_enabled %}
if [ -e /etc/init/lms-xml.conf ]; then
start wait-for-state WAIT_FOR=lms-xml WAITER=$UPSTART_JOB
fi
{% endif %}
{% if 'lms' in service_variants_enabled %}
if [ -e /etc/init/lms.conf ]; then
start wait-for-state WAIT_FOR=lms WAITER=$UPSTART_JOB
......@@ -51,12 +45,6 @@ end script
pre-stop script
{% if 'lms-xml' in service_variants_enabled %}
if [ -e /etc/init/lms-xml.conf ]; then
start wait-for-state WAIT_FOR=lms-xml WAITER=$UPSTART_JOB TARGET_GOAL="stop"
fi
{% endif %}
{% if 'lms' in service_variants_enabled %}
if [ -e /etc/init/lms.conf ]; then
start wait-for-state WAIT_FOR=lms WAITER=$UPSTART_JOB TARGET_GOAL="stop"
......
# gunicorn
# Templated and placed by ansible from jinja2 source
description "lms-xml gunicorn server"
start on started edxapp
stop on stopped edxapp
respawn
respawn limit 3 30
env PID=/var/tmp/lms-xml.pid
#env NEW_RELIC_CONFIG_FILE={{app_base_dir}}/newrelic.ini
#env NEWRELIC={{venv_dir}}/bin/newrelic-admin
{% if ansible_processor|length > 0 %}
env WORKERS={{ ansible_processor|length * worker_core_mult.lms_xml }}
{% else %}
env WORKERS={{ worker_core_mult.lms_xml }}
{% endif %}
env PORT={{edxapp_lms_xml_app_port}}
env ADDRESS={{edxapp_lms_xml_app_address}}
env LANG=en_US.UTF-8
env DJANGO_SETTINGS_MODULE=lms.envs.aws
env SERVICE_VARIANT="lms-xml"
chdir {{edx_platform_code_dir}}
setuid www-data
exec {{venv_dir}}/bin/gunicorn --preload -b $ADDRESS:$PORT -w $WORKERS --timeout=300 --pythonpath={{edx_platform_code_dir}} lms.wsgi
post-start script
while true
do
if $(curl -s -i localhost:$PORT/heartbeat | egrep -q '200 OK'); then
break;
else
sleep 1;
fi
done
end script
upstream lms-xml-backend {
# For a TCP configuration:
server 127.0.0.1:8030 fail_timeout=0;
}
server {
# LMS-preview configuration file for nginx, templated by ansible
listen {{lms_xml_nginx_port}};
# CS184 requires uploads of up to 4MB for submitting screenshots.
# CMS requires larger value for course assest, values provided
# via hiera.
client_max_body_size 4M;
rewrite ^(.*)/favicon.ico$ /static/images/favicon.ico last;
location @proxy_to_lms-preview_app {
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://lms-xml-backend;
}
location @proxy_to_lms-xml_app {
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://lms-xml-backend;
}
location / {
try_files $uri @proxy_to_lms-xml_app;
}
# No basic auth security on the github_service_hook url, so that github can use it for cms
location /github_service_hook {
try_files $uri @proxy_to_lms-xml_app;
}
# No basic auth security on the heartbeat url, so that ELB can use it
location /heartbeat {
try_files $uri @proxy_to_lms-xml_app;
}
# Check security on this
location ~ /static/(?P<file>.*) {
root {{app_base_dir}};
try_files /staticfiles/$file /course_static/$file =404;
# return a 403 for static files that shouldn't be
# in the staticfiles directory
location ~ ^/static/(?:.*)(?:\.xml|\.json|README.TXT) {
return 403;
}
# Set django-pipelined files to maximum cache time
location ~ "/static/(?P<collected>.*\.[0-9a-f]{12}\..*)" {
expires max;
# Without this try_files, files that have been run through
# django-pipeline return 404s
try_files /staticfiles/$collected /course_static/$collected =404;
}
# Expire other static files immediately (there should be very few / none of these)
expires epoch;
}
# Forward to HTTPS if we're an HTTP request...
if ($http_x_forwarded_proto = "http") {
set $do_redirect "true";
}
# Run our actual redirect...
if ($do_redirect = "true") {
rewrite ^ https://$host$request_uri? permanent;
}
# Monitoring support for datadog.
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1/32;
deny all;
}
}
......@@ -19,7 +19,6 @@ rabbitmq_ip: "{{ ansible_default_ipv4.address }}"
# Vars meant to be overridden.
RABBIT_ERLANG_COOKIE: 'DEFAULT_COOKIE'
RABBIT_USERS:
admins:
- name: 'admin'
password: 'the example admin password'
- name: 'edx'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment