Browse Source

openedx: first implementation

Fixes: main/infrastructure#101
keep-around/d82fecc525b9c8fb723fcd32bf3e99172c602d0d
Loïc Dachary 10 months ago
committed by Loic Dachary
parent
commit
4f3aae1a52
Signed by: dachary GPG Key ID: 992D23B392F9E4F2
  1. 2
      docs/services/index.rst
  2. 10
      docs/services/openedx.rst
  3. 1
      docs/user-guide.rst
  4. 1
      enough-playbook.yml
  5. 1
      inventory/all.yml
  6. 2
      inventory/host_vars/openedx-host/provision.yml
  7. 9
      inventory/services.yml
  8. 14
      playbooks/openedx/conftest.py
  9. 8
      playbooks/openedx/inventory/services.yml
  10. 90
      playbooks/openedx/openedx-playbook.yml
  11. 10
      playbooks/openedx/playbook.yml
  12. 38
      playbooks/openedx/roles/openedx/defaults/main.yml
  13. 2
      playbooks/openedx/roles/openedx/tasks/main.yml
  14. 79
      playbooks/openedx/roles/openedx/tasks/openedx.yml
  15. 5
      playbooks/openedx/roles/openedx/templates/crontab
  16. 48
      playbooks/openedx/roles/openedx/templates/docker-compose-infrastructure.yml
  17. 15
      playbooks/openedx/tests/test_icinga.py
  18. 20
      playbooks/openedx/tests/test_openedx.py
  19. 2
      tox.ini

2
docs/services/index.rst

@ -12,6 +12,7 @@ Services
gitlab
website
wekan
openedx
securedrop
bind
VPN
@ -21,4 +22,3 @@ Services
backup
jitsi
wordpress

10
docs/services/openedx.rst

@ -0,0 +1,10 @@
openedX
=======
`openedX <https://open.edx.org/>`__ is available at
`openedx.example.com`. The user with administrative rights and the
contact email are defined as documented in `this file
<https://lab.enough.community/main/infrastructure/blob/master/playbooks/openedx/roles/openedx/defaults/main.yml>`__
and can be modified in the
`~/.enough/example.com/inventory/group_vars/openedx-service-group.yml`
file.

1
docs/user-guide.rst

@ -130,6 +130,7 @@ The following services are available:
* ``pad``, for `collaborative note taking <https://etherpad.org/>`__ at ``pad.example.com``
* :doc:`Weblate <services/weblate>`, for `online translations <https://weblate.org/>`__ at ``weblate.example.com``
* :doc:`WordPress <services/wordpress>`, for `CMS <https://wordpress.org/>`__ at ``wordpress.example.com``
* :doc:`openedX <services/openedx>`, for `MOOC platform <https://open.edx.org/>`__ at ``openedx.example.com``
* ``website``, for `static websites <https://gohugo.io/>`__ at ``website.example.com``
* ``wekan``, for `kanban <https://wekan.github.io/>`__ at ``wekan.example.com``
* :doc:`gitlab <services/gitlab>`, for `software development <https://gitlab.com/>`__ at ``lab.example.com``

1
enough-playbook.yml

@ -8,6 +8,7 @@
- import_playbook: "{{ '$SHARE_DIR/playbooks/chat/chat-playbook.yml' | expandvars }}"
- import_playbook: "{{ '$SHARE_DIR/playbooks/cloud/cloud-playbook.yml' | expandvars }}"
- import_playbook: "{{ '$SHARE_DIR/playbooks/enough/enough-playbook.yml' | expandvars }}"
- import_playbook: "{{ '$SHARE_DIR/playbooks/openedx/openedx-playbook.yml' | expandvars }}"
- import_playbook: "{{ '$SHARE_DIR/playbooks/website/website-playbook.yml' | expandvars }}"
when: (groups['website-service-group'] | length) > 0
- import_playbook: "{{ '$SHARE_DIR/playbooks/forum/forum-playbook.yml' | expandvars }}"

1
inventory/all.yml

@ -9,6 +9,7 @@ all-hosts:
gitlab-host:
icinga-host:
jitsi-host:
openedx-host:
packages-host:
postfix-host:
runner-host:

2
inventory/host_vars/openedx-host/provision.yml

@ -0,0 +1,2 @@
---
openstack_flavor: s1-8

9
inventory/services.yml

@ -138,6 +138,15 @@ wekan-service-hosts:
wekan-service-group:
essential-service-group:
openedx-service-group:
hosts:
openedx-host:
openedx-service-hosts:
children:
openedx-service-group:
essential-service-group:
pad-service-group:
hosts: {}

14
playbooks/openedx/conftest.py

@ -0,0 +1,14 @@
def pytest_addoption(parser):
parser.addoption(
"--enough-hosts",
action="store",
default="bind-host,postfix-host,openedx-host",
help="list of hosts"
)
parser.addoption(
"--enough-service",
action="store",
default="openedx",
help="service"
)

8
playbooks/openedx/inventory/services.yml

@ -0,0 +1,8 @@
---
icinga-service-group:
hosts:
bind-host:
postfix-service-group:
hosts:
postfix-host:

90
playbooks/openedx/openedx-playbook.yml

@ -0,0 +1,90 @@
---
- name: firewall for web
hosts: localhost
gather_facts: false
tasks:
- include_role:
name: firewall
vars:
firewall_server: "{{ item }}"
firewall_clients: [ 0.0.0.0/0 ]
firewall_protocols: [ tcp ]
firewall_ports: [ 80, 443 ]
when: hostvars[item].ansible_host is defined
with_items: "{{ groups['openedx-service-group'] | default([]) }}"
- name: setup openedx DNS
hosts: openedx-service-group
become: true
pre_tasks:
- name: set CNAME
nsupdate:
server: "{{ hostvars['bind-host']['ansible_host'] }}"
zone: "{{ domain }}"
record: "openedx.{{ domain }}."
ttl: 1800
type: CNAME
value: "{{ groups['openedx-service-group'][0] }}.{{ domain }}."
delegate_to: bind-host
- name: set CNAME
nsupdate:
server: "{{ hostvars['bind-host']['ansible_host'] }}"
zone: "{{ domain }}"
record: "studio.{{ domain }}."
ttl: 1800
type: CNAME
value: "{{ groups['openedx-service-group'][0] }}.{{ domain }}."
delegate_to: bind-host
- name: install openedX
hosts: openedx-service-group
become: true
roles:
- role: ansible-role-docker
docker_install_compose: true
- role: docker
- role: enough-nginx
vars:
enough_nginx_reverse_proxy: 127.0.0.1:{{ openedx_port }}
enough_nginx_reverse_proxy_name: openedxbackend
enough_nginx_fqdn: "openedx.{{ domain }}"
- role: certificate
vars:
certificate_fqdn: "openedx.{{ domain }}"
certificate_installer: nginx
- role: openedx
- role: monitor_http_vhost
http_vhost_https: true
http_vhost_name: openedX
http_vhost_fqdn: "openedx.{{ domain }}"
http_vhost_uri: "/"
http_vhost_string: "openedx"
- name: reverse proxy for openedX studio
hosts: openedx-service-group
become: true
roles:
# this is to get the default value for openedx_port
- role: openedx
when: false
- role: enough-nginx
vars:
enough_nginx_reverse_proxy: 127.0.0.1:{{ openedx_port }}
enough_nginx_reverse_proxy_name: openedxbackend
enough_nginx_fqdn: "studio.{{ domain }}"
- role: certificate
vars:
certificate_fqdn: "studio.{{ domain }}"
certificate_installer: nginx

10
playbooks/openedx/playbook.yml

@ -0,0 +1,10 @@
---
- import_playbook: ../infrastructure/buster-playbook.yml
- import_playbook: ../infrastructure/network-playbook.yml
- import_playbook: ../firewall/firewall-playbook.yml
- import_playbook: ../icinga/test-icinga-playbook.yml
- import_playbook: ../bind/bind-playbook.yml
- import_playbook: ../bind/bind-client-playbook.yml
- import_playbook: ../icinga/icinga-playbook.yml
- import_playbook: ../postfix/postfix-playbook.yml
- import_playbook: openedx-playbook.yml

38
playbooks/openedx/roles/openedx/defaults/main.yml

@ -0,0 +1,38 @@
---
#
####################################################
#
# Name of the user with administrative rights
#
openedx_user: admin
#
####################################################
#
# password of the user with administrative rights
#
openedx_password: "knidCarg#5Knak"
#
####################################################
#
# email of the user with administrative rights
#
openedx_contact: admin@{{ domain }}
#
####################################################
#
# Language of the interface
#
openedx_language: en
#
####################################################
#
# Name of the openedX instance
#
openedx_platform_name: Enough
#
####################################################
# DO NOT MODIFY BELOW THIS LINE
####################################################
#
openedx_port: 8500
openedx_root: /srv/openedx

2
playbooks/openedx/roles/openedx/tasks/main.yml

@ -0,0 +1,2 @@
---
- import_tasks: openedx.yml

79
playbooks/openedx/roles/openedx/tasks/openedx.yml

@ -0,0 +1,79 @@
---
- name: apt-get install python3 python3-pip libyaml-dev curl
apt:
name: [ python3, python3-pip, libyaml-dev, curl ]
state: present
- name: pip install tutor-openedx
pip:
executable: pip3
name: tutor-openedx
- name: "mkdir -p {{ openedx_root }}"
file:
path: "{{ openedx_root }}"
state: directory
owner: debian
group: debian
- name: configure and create openedX
shell: |
set -ex
tutor config save --set ACTIVATE_HTTPS=false \
--set CMS_HOST=studio.{{ domain }} \
--set CONTACT_EMAIL='{{ openedx_contact }}' \
--set LANGUAGE_CODE={{ openedx_language }} \
--set LMS_HOST=openedx.{{ domain }} \
--set PLATFORM_NAME='{{ openedx_platform_name }}' \
--set NGINX_HTTP_PORT={{ openedx_port }} \
--set NGINX_HTTPS_PORT=8543 \
--set SMTP_HOST=openedx-host.{{ domain }} \
--set SMTP_PORt=25
if ! test -f {{ openedx_root }}/configured ; then
tutor local quickstart --non-interactive
tutor local createuser --staff --password '{{ openedx_password }}' --superuser '{{ openedx_user }}' '{{ openedx_contact }}'
touch {{ openedx_root }}/configured
else
tutor local start -d
fi
environment:
HOME: "{{ openedx_root }}"
become: False
- name: wait for openedx.{{ domain }} to be ready
shell: |
set $(curl -k -L -s --head https://openedx.{{ domain }} | grep HTTP | tail -1)
if test "$2" = 200 ; then
exit 0
else
exit 1
fi
register: openedx_get
until: openedx_get is success
retries: 20
delay: 5
- name: git clone https://github.com/overhangio/indigo
git:
repo: https://github.com/overhangio/indigo
force: yes
dest: "{{ openedx_root }}/indigo"
become: False
- name: install indigo theme
shell: |
set -ex
if ! test -f {{ openedx_root }}/themed ; then
tutor config render --extra-config ./indigo/config.yml ./indigo/theme "$(tutor config printroot)/env/build/openedx/themes/indigo"
tutor images build openedx
tutor local start -d
tutor local settheme indigo localhost studio.localhost \
$(tutor config printvalue LMS_HOST) $(tutor config printvalue CMS_HOST)
touch {{ openedx_root }}/themed
fi
args:
chdir: "{{ openedx_root }}"
environment:
HOME: "{{ openedx_root }}"
become: False

5
playbooks/openedx/roles/openedx/templates/crontab

@ -0,0 +1,5 @@
MAILTO=""
*/5 * * * * cd {{ weblate_root }}/weblate; flock --timeout 600 /tmp/weblate sudo docker-compose -f docker-compose-infrastructure.yml run --rm weblate update_index
@daily cd {{ weblate_root }}/weblate; flock --timeout 600 /tmp/weblate sudo docker-compose -f docker-compose-infrastructure.yml run --rm weblate cleanuptrans
@hourly cd {{ weblate_root }}/weblate; flock --timeout 600 /tmp/weblate sudo docker-compose -f docker-compose-infrastructure.yml run --rm weblate commit_pending --all --age=1

48
playbooks/openedx/roles/openedx/templates/docker-compose-infrastructure.yml

@ -0,0 +1,48 @@
version: '2'
services:
weblate:
image: weblate/weblate:{{ weblate_version }}
links:
- database
- cache
volumes:
- weblate-data:/app/data
ports:
- '8000:8080'
env_file:
- ./environment
restart: always
depends_on:
- database
- cache
environment:
- WEBLATE_EMAIL_HOST={{ hostvars["postfix-host"]["ansible_host"] }}
- WEBLATE_EMAIL_PORT=465
- WEBLATE_EMAIL_USE_TLS=0
- WEBLATE_EMAIL_USE_SSL=1
- WEBLATE_SERVER_EMAIL={{ weblate_server_email }}
- WEBLATE_DEFAULT_FROM_EMAIL={{ weblate_default_from_email }}
- WEBLATE_ADMIN_NAME=admin
- WEBLATE_ADMIN_EMAIL={{ weblate_admin_email }}
- WEBLATE_ADMIN_PASSWORD={{ weblate_admin_password }}
- WEBLATE_DEBUG=0
- WEBLATE_ENABLE_HTTPS=1
- WEBLATE_ALLOWED_HOSTS=weblate.{{ domain }},{{ hostvars[groups["weblate-service-group"][0]]["ansible_host"] }}
- WEBLATE_REGISTRATION_OPEN=1
database:
image: postgres:9.6-alpine
env_file:
- ./environment
volumes:
- postgres-data:/var/lib/postgresql/data
restart: always
cache:
image: redis:5-alpine
restart: always
command: [ "redis-server", "--appendonly", "yes" ]
volumes:
- redis-data:/data
volumes:
weblate-data: { }
postgres-data: { }
redis-data: { }

15
playbooks/openedx/tests/test_icinga.py

@ -0,0 +1,15 @@
from tests.icinga_helper import IcingaHelper
testinfra_hosts = ['ansible://bind-host']
IcingaHelper.icinga_host = 'bind-host'
class TestChecks(IcingaHelper):
def test_host(self):
r = self.get_client().objects.get('Host', 'openedx-host')
assert r['attrs']['name'] == 'openedx-host'
def test_service(self, host):
assert self.is_service_ok('openedx-host!openedX')

20
playbooks/openedx/tests/test_openedx.py

@ -0,0 +1,20 @@
import time
import requests
import yaml
def get_address(inventory):
vars_dir = f'{inventory}/group_vars/all'
return 'https://openedx.' + yaml.load(
open(vars_dir + '/domain.yml'))['domain']
def test_openedx(pytestconfig):
# openedx freshly recreated may take few mins to be operationnal
url = get_address(pytestconfig.getoption("--ansible-inventory"))
for i in range(60, 0, -1):
r = requests.get(url, timeout=5, verify='certs')
if r.status_code == requests.codes.ok:
break
time.sleep(5)
assert 'openedx' in r.text

2
tox.ini

@ -24,7 +24,7 @@ commands = flake8 {posargs}
#
# Integration tests
#
[testenv:{infrastructure,bind,authorized_keys,backup,certificate,postfix,icinga,openvpn,wekan,misc,pad,firewall,gitlab,api,wazuh,weblate,website,chat,cloud,enough,forum,packages,securedrop,jitsi,wordpress}]
[testenv:{infrastructure,bind,authorized_keys,backup,certificate,postfix,icinga,openvpn,wekan,misc,pad,firewall,gitlab,api,wazuh,weblate,website,chat,cloud,enough,forum,packages,securedrop,jitsi,wordpress,openedx}]
passenv =
ENOUGH_API_TOKEN
PYTEST_ADDOPTS

Loading…
Cancel
Save