171 lines
6.6 KiB
Python
171 lines
6.6 KiB
Python
|
import textwrap
|
||
|
from urllib.parse import urlparse
|
||
|
|
||
|
from django.utils.translation import gettext_lazy as _
|
||
|
|
||
|
from orchestra.contrib.orchestration import ServiceController
|
||
|
|
||
|
from .. import settings
|
||
|
|
||
|
|
||
|
class MoodleMuController(ServiceController):
|
||
|
"""
|
||
|
Creates a Moodle site on a Moodle multisite installation
|
||
|
|
||
|
// config.php
|
||
|
// map custom domains to sites
|
||
|
$site_map = array(
|
||
|
// "<HTTP_HOST>" => ["<SITE_NAME>", "<WWWROOT>"],
|
||
|
);
|
||
|
|
||
|
$site = getenv("SITE");
|
||
|
if ( $site == '' ) {
|
||
|
$http_host = $_SERVER['HTTP_HOST'];
|
||
|
if (array_key_exists($http_host, $site_map)) {
|
||
|
$site = $site_map[$http_host][0];
|
||
|
$wwwroot = $site_map[$http_host][1];
|
||
|
} elseif (strpos($http_host, '-courses.') !== false) {
|
||
|
$site = array_shift((explode("-courses.", $http_host)));
|
||
|
$wwwroot = "https://{$site}-courses.pangea.org";
|
||
|
} else {
|
||
|
$site = array_shift((explode(".", $http_host)));
|
||
|
$wwwroot = "https://{$site}-courses.pangea.org";
|
||
|
}
|
||
|
} else {
|
||
|
$wwwroot = "https://{$site}-courses.pangea.org";
|
||
|
foreach ($site_map as $key => $value) {
|
||
|
if ($value[0] == $site) {
|
||
|
$wwwroot = $value[1];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$prefix = str_replace('-', '_', $site);
|
||
|
$CFG->prefix = "${prefix}_";
|
||
|
$CFG->wwwroot = $wwwroot;
|
||
|
$CFG->dataroot = "/home/pangea/moodledata/{$site}/";
|
||
|
"""
|
||
|
verbose_name = _("Moodle multisite")
|
||
|
model = 'saas.SaaS'
|
||
|
default_route_match = "saas.service == 'moodle'"
|
||
|
|
||
|
def save(self, webapp):
|
||
|
context = self.get_context(webapp)
|
||
|
self.delete_site_map(context)
|
||
|
if context['custom_url']:
|
||
|
self.insert_site_map(context)
|
||
|
self.append(textwrap.dedent("""\
|
||
|
mkdir -p %(moodledata_path)s
|
||
|
chown %(user)s:%(user)s %(moodledata_path)s
|
||
|
export SITE=%(site_name)s
|
||
|
CHANGE_PASSWORD=0
|
||
|
# TODO su moodle user
|
||
|
php %(moodle_path)s/admin/cli/install_database.php \\
|
||
|
--fullname="%(site_name)s" \\
|
||
|
--shortname="%(site_name)s" \\
|
||
|
--adminpass="%(password)s" \\
|
||
|
--adminemail="%(email)s" \\
|
||
|
--non-interactive \\
|
||
|
--agree-license \\
|
||
|
--allow-unstable || CHANGE_PASSWORD=1
|
||
|
""") % context
|
||
|
)
|
||
|
if context['password']:
|
||
|
self.append(textwrap.dedent("""\
|
||
|
mysql \\
|
||
|
--host="%(db_host)s" \\
|
||
|
--user="%(db_user)s" \\
|
||
|
--password="%(db_pass)s" \\
|
||
|
--execute='UPDATE %(db_prefix)s_user
|
||
|
SET password=MD5("%(password)s")
|
||
|
WHERE username="admin";' \\
|
||
|
%(db_name)s
|
||
|
""") % context
|
||
|
)
|
||
|
if context['crontab']:
|
||
|
context['escaped_crontab'] = context['crontab'].replace('$', '\\$')
|
||
|
self.append(textwrap.dedent("""\
|
||
|
# Configuring Moodle crontabs
|
||
|
if ! crontab -u %(user)s -l | grep 'Moodle:"%(site_name)s"' > /dev/null; then
|
||
|
cat << EOF | su - %(user)s --shell /bin/bash -c 'crontab'
|
||
|
$(crontab -u %(user)s -l)
|
||
|
|
||
|
# %(banner)s - Moodle:"%(site_name)s"
|
||
|
%(escaped_crontab)s
|
||
|
EOF
|
||
|
fi""") % context
|
||
|
)
|
||
|
|
||
|
def delete_site_map(self, context):
|
||
|
self.append(textwrap.dedent("""\
|
||
|
sed -i '/^\s*"[^\s]*"\s*=>\s*\["%(site_name)s",\s*".*/d' %(moodle_path)s/config.php
|
||
|
""") % context
|
||
|
)
|
||
|
|
||
|
def insert_site_map(self, context):
|
||
|
self.append(textwrap.dedent("""\
|
||
|
regex='\s*\$site_map\s+=\s+array\('
|
||
|
newline=' "%(custom_domain)s" => ["%(site_name)s", "%(custom_url)s"], // %(banner)s'
|
||
|
sed -i -r "s#$regex#\$site_map = array(\\n$newline#" %(moodle_path)s/config.php
|
||
|
""") % context
|
||
|
)
|
||
|
|
||
|
def delete(self, saas):
|
||
|
context = self.get_context(saas)
|
||
|
self.append(textwrap.dedent("""
|
||
|
rm -rf %(moodledata_path)s
|
||
|
# Delete tables with prefix %(db_prefix)s
|
||
|
mysql -Nrs \\
|
||
|
--host="%(db_host)s" \\
|
||
|
--user="%(db_user)s" \\
|
||
|
--password="%(db_pass)s" \\
|
||
|
--execute='SET GROUP_CONCAT_MAX_LEN=10000;
|
||
|
SET @tbls = (SELECT GROUP_CONCAT(TABLE_NAME)
|
||
|
FROM information_schema.TABLES
|
||
|
WHERE TABLE_SCHEMA = "%(db_name)s"
|
||
|
AND TABLE_NAME LIKE "%(db_prefix)s_%%");
|
||
|
SET @delStmt = CONCAT("DROP TABLE ", @tbls);
|
||
|
-- SELECT @delStmt;
|
||
|
PREPARE stmt FROM @delStmt;
|
||
|
EXECUTE stmt;
|
||
|
DEALLOCATE PREPARE stmt;' \\
|
||
|
%(db_name)s
|
||
|
""") % context
|
||
|
)
|
||
|
if context['crontab']:
|
||
|
context['crontab_regex'] = '\\|'.join(context['crontab'].splitlines())
|
||
|
context['crontab_regex'] = context['crontab_regex'].replace('*', '\\*')
|
||
|
self.append(textwrap.dedent("""\
|
||
|
crontab -u %(user)s -l \\
|
||
|
| grep -v 'Moodle:"%(site_name)s"\\|%(crontab_regex)s' \\
|
||
|
| su - %(user)s --shell /bin/bash -c 'crontab'
|
||
|
""") % context
|
||
|
)
|
||
|
self.delete_site_map(context)
|
||
|
|
||
|
def get_context(self, saas):
|
||
|
context = {
|
||
|
'banner': self.get_banner(),
|
||
|
'name': saas.name,
|
||
|
'site_name': saas.name,
|
||
|
'full_name': "%s course" % saas.name.capitalize(),
|
||
|
'moodle_path': settings.SAAS_MOODLE_PATH,
|
||
|
'user': settings.SAAS_MOODLE_SYSTEMUSER,
|
||
|
'db_user': settings.SAAS_MOODLE_DB_USER,
|
||
|
'db_pass': settings.SAAS_MOODLE_DB_PASS,
|
||
|
'db_name': settings.SAAS_MOODLE_DB_NAME,
|
||
|
'db_host': settings.SAAS_MOODLE_DB_HOST,
|
||
|
'db_prefix': saas.name.replace('-', '_'),
|
||
|
'email': saas.account.email,
|
||
|
'password': getattr(saas, 'password', None),
|
||
|
'custom_url': saas.custom_url.rstrip('/'),
|
||
|
'custom_domain': urlparse(saas.custom_url).netloc if saas.custom_url else None,
|
||
|
}
|
||
|
context.update({
|
||
|
'crontab': settings.SAAS_MOODLE_CRONTAB % context,
|
||
|
'db_name': context['db_name'] % context,
|
||
|
'moodledata_path': settings.SAAS_MOODLE_DATA_PATH % context,
|
||
|
})
|
||
|
return context
|