1
0
Fork 0
mirror of https://github.com/iiab/iiab.git synced 2025-03-09 15:40:17 +00:00

Move 19 roles into roles/0-DEPRECATED-ROLES

This commit is contained in:
root 2020-01-24 02:27:21 -05:00
parent 0e39c42bbd
commit 2218d2334b
124 changed files with 5 additions and 1 deletions

View file

@ -0,0 +1,139 @@
Serve XO activities from the XS school server
=============================================
XO laptops can update their activities via HTTP, using specially
microformatted html pages to determine what to download.
This package imports XO activities from a USB stick and generates the
correct html to serve them, in as many languages as it knows how,
using the localisation information from the activity bundles. Content
negotiation between Apache and the laptops decides what html is seen.
The URL for this index is http://schoolserver/activities/.
A facility exists to add extra descriptive html to the generated
indexes.
USB import
----------
When a USB drive is inserted, the server looks for a directory in the
root directory called xs-activity-server. In there it expects to find
any number of activity bundles, a file called manifest.sha1, and
optionally a file or files with the suffix ".info". Depending on the
configuration of the school server, a file called "manifest.sha1.sig"
might also be required.
Activity bundles are zip files with the suffix .xo and an internal
layout described at http://wiki.laptop.org/go/Activity_bundles.
The manifest file should contain sha1sums for each activity bundle and
the metadata files, as if you had run
sha1sum *.xo *.info > manifest.sha1
in the directory.
If full XS security is enabled (by the presence of /etc/xs-security-on
-- see the xs-tools documentation), then manifest.sha1.sig should
contain a detached GPG signature for manifest.sha1, signed by a key
that the XS knows. If the school server lacks the /etc/xs-security-on
flag, the manifest.sha1.sig file is ignored.
Multiple languages
------------------
Activities can contain localisation information, which usually
consists of a translated activity name. The localised information is
found in the bundle in a directory like:
SomeWonderful.activity/locale/pt-BR/activity.linfo
where pt-BR is an RFC1788 language code. If any activity contains an
activity.linfo file for a language, then an index is generated. The
server has templates for indexes in some languages (currently Spanish
and English); for other languages the indexes will be in English
except for the localised names.
These index files are saved with names like
activities/index.html.zh-es. You can choose to look at them directly
that way, or let your browser decide which one is best for you by
visiting activities/index.html.
If some activities lack localised information for a multi-part
language code, the index will include information that exists for the
corresponding single part code, before defaulting to English. For
example, a zh-CN page will include zh localisation if need be. (This
may not always be the best result: bn and bn-IN appear to use
different scripts).
Including extra descriptions
----------------------------
The optional .info files in the xs-activation-server directory should
consist of sections in this format:
[com.microsoft.Word]
description = Write replacement, without distraction of collaboration.
[some.other.Something]
description = another description, all on one line.
If a section heading (in square brackets) matches the bundle_id or
service_name of an activity, the description will be displayed on the
generated html page. This information is not used by automatic
updates, but it might assist children in browsing and manually
installing activities. Note: there is no clever localisation here.
Multiple versions
-----------------
Over the course of a server deployment, an activity might be updated
several times. To preserve disk space, only the 4 most recent
versions of an activity are kept. Links to the second, third and
fourth newest versions are presented in the activities html file, but
these do not use the activity microformat and will not be visible to
automated updaters.
To determine which activities are the most recent, the file's modification
times (mtime) are examined. The version number is not considered here.
Note: If you plug in a USB stick with very out-of-date activities they
will be deleted as soon as they get on the server.
HTML microformat
----------------
The microformat is described at
http://wiki.laptop.org/go/Activity_microformat.
Utility script
--------------
/usr/bin/xs-check-activities will print statistics about a directory
of activities to stderr. Its output is not particularly well
formatted or explained, but it is there if you want it.
Files and directories
---------------------
Activities are stored in /library/xs-activity-server/activities, with
the html index being index.html in that directory. Apache is coaxed
into serving this by /etc/httpd/conf.d/xs-activity-server.conf.
Bugs
----
Old versions are only saved if the different versions have different
file names. Most activity bundles have names like 'Maze-4.xo',
'Maze-5.xo' and so on, but some lack the version number in the file
name, so the most recently imported version ends up overwriting the
older ones.
Source
------
This role is based on the xs-activity-server rpm.
http://dev.laptop.org/git/users/martin/xs-activity-server/ v0.4 release

View file

@ -0,0 +1,3 @@
activity_server_enabled: False
activity_server_install: True

View file

@ -0,0 +1,30 @@
#!/usr/bin/python
# Copyright (C) 2008 One Laptop Per Child Association, Inc.
# Licensed under the terms of the GNU GPL v2 or later; see COPYING for details.
#
# written by Douglas Bagnall <douglas@paradise.net.nz>
"""This script reads activity.info from bundle files and reports on
their quality.
"""
import xs_activities
import sys, os
xs_activities.USE_STDERR = True
show_all = '--show-all' in sys.argv
if show_all:
sys.argv.remove('--show-all')
try:
directory = sys.argv[1]
os.stat(directory)
except (IndexError, OSError):
print __doc__
print "USAGE: %s DIRECTORY" % sys.argv[0]
sys.exit(1)
xs_activities.check_all_bundles(directory, show_all)

View file

@ -0,0 +1,93 @@
#!/usr/bin/python
# Copyright (C) 2008 One Laptop Per Child Association, Inc.
# Licensed under the terms of the GNU GPL v2 or later; see COPYING for details.
#
# written by Douglas Bagnall <douglas@paradise.net.nz>
"""Read activity.info files from a directory full of activity bundles
and write an appropriate html manifest of the most recent versions.
The manifest uses the OLPC activity microformat:
http://wiki.laptop.org/go/Activity_microformat
This is put in a place where apache can find it, and apache will serve
it and the activities to the laptops. Messages go to /var/log/user.log.
"""
import os
import sys
import shutil
from time import time
import xs_activities
INPUT_DIR = "/library/xs-activity-server/activities"
OUTPUT_LINK = "/library/xs-activity-server/www"
try:
CURRENT_DIR = os.readlink(OUTPUT_LINK)
except OSError:
CURRENT_DIR = None
def create_dir_manifest(dir_path):
manifest = []
os.chdir(dir_path)
for root, dirs, files in os.walk("."):
for filename in files:
if not filename.endswith(".xo") and not filename.endswith(".xol"):
continue
path = os.path.join(root, filename)
s = os.stat(path)
manifest.append((path, s.st_ino))
manifest.sort()
return manifest
def input_changed():
if CURRENT_DIR is None:
return True
input_manifest = create_dir_manifest(INPUT_DIR)
current_manifest = create_dir_manifest(CURRENT_DIR)
return input_manifest != current_manifest
if not input_changed():
# no changes or nothing to do
sys.exit(0)
# create new output dir
OUTPUT_DIR = OUTPUT_LINK + "." + str(time())
os.mkdir(OUTPUT_DIR)
# link in all activities
os.chdir(INPUT_DIR)
for root, dirs, files in os.walk("."):
output_dir = os.path.join(OUTPUT_DIR, root)
if not os.path.isdir(output_dir):
os.makedirs(output_dir)
for filename in files:
if not filename.endswith(".xo") and not filename.endswith(".xol"):
continue
path = os.path.join(root, filename)
output_path = os.path.join(output_dir, filename)
os.link(path, output_path)
# create html index
output_html = os.path.join(output_dir, 'index.html')
xs_activities.htmlise_bundles(output_dir, output_html)
# update symlink atomically
link = OUTPUT_DIR + ".lnk"
os.symlink(OUTPUT_DIR, link)
os.rename(link, OUTPUT_LINK)
# remove old index
if CURRENT_DIR is not None:
shutil.rmtree(CURRENT_DIR, ignore_errors=True)

View file

@ -0,0 +1,10 @@
<div class="olpc-activity-info">
<h2>%(name)s</h2>
%(description)s
<ul>
<li>Identifier: <span class="olpc-activity-id">%(bundle_id)s</span></li>
<li>Version: <span class="olpc-activity-version">%(activity_version)s</span></li>
<li>URL: <span class="olpc-activity-url"><a href="%(bundle_url)s">%(bundle_url)s</a></span></li>
<li style="display: %(show_older_versions)s">Older versions: %(older_versions)s</li>
</ul>
</div>

View file

@ -0,0 +1,7 @@
<html>
<body>
<h1 id="olpc-activity-group-name">Locally available activities</h1>
<p id="olpc-activity-group-desc">These activities are stored on the school server.</p>
%(activities)s
</body>
</html>

View file

@ -0,0 +1,10 @@
<div class="olpc-activity-info">
<h2>%(name)s</h2>
%(description)s
<ul>
<li>Identificador: <span class="olpc-activity-id">%(bundle_id)s</span></li>
<li>Versión: <span class="olpc-activity-version">%(activity_version)s</span></li>
<li>URL: <span class="olpc-activity-url"><a href="%(bundle_url)s">%(bundle_url)s</a></span></li>
<li style="display: %(show_older_versions)s">Versiones anteriores: %(older_versions)s</li>
</ul>
</div>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<h1 id="olpc-activity-group-name">Actividades disponibles localmente</h1>
<p id="olpc-activity-group-desc">Estas actividades están almacenads en el servidor de la escuela.</p>
%(activities)s
</body>
</html>

View file

@ -0,0 +1,10 @@
<div class="olpc-activity-info">
<h2>%(name)s</h2>
%(description)s
<ul>
<li>Identifiant: <span class="olpc-activity-id">%(bundle_id)s</span></li>
<li>Version: <span class="olpc-activity-version">%(activity_version)s</span></li>
<li>URL: <span class="olpc-activity-url"><a href="%(bundle_url)s">%(bundle_url)s</a></span></li>
<li style="display: %(show_older_versions)s">Anciennes versions: %(older_versions)s</li>
</ul>
</div>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<h1 id="olpc-activity-group-name">Activités disponibles localement</h1>
<p id="olpc-activity-group-desc">Ces activités sont stockées sur le serveur de lécole.</p>
%(activities)s
</body>
</html>

View file

@ -0,0 +1,10 @@
<div class="olpc-activity-info">
<h2>%(name)s</h2>
%(description)s
<ul>
<li>Pou idantifye: <span class="olpc-activity-id">%(bundle_id)s</span></li>
<li>Vesyon: <span class="olpc-activity-version">%(activity_version)s</span></li>
<li>URL: <span class="olpc-activity-url"><a href="%(bundle_url)s">%(bundle_url)s</a></span></li>
<li style="display: %(show_older_versions)s">Vesyon ansyen: %(older_versions)s</li>
</ul>
</div>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<h1 id="olpc-activity-group-name">Aktivite ki disponib nan Bwat la</h1>
<p id="olpc-activity-group-desc">Aktivite sa yo disponib sou sit lekòl la.</p>
%(activities)s
</body>
</html>

View file

@ -0,0 +1,10 @@
<html>
<body>
<h1 id="olpc-activity-group-name">Locally available activities</h1>
<p id="olpc-activity-group-desc">These activities are stored on the school server.</p>
<div class="olpc-activity-info">
There are currently no activities. Insert a USB drive with activities on it to add some.
</div>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<h1 id="olpc-activity-group-name">Activités disponibles localement</h1>
<p id="olpc-activity-group-desc">Ces activités sont stockées sur le serveur de lécole.</p>
<div class="olpc-activity-info">
Il n'y a pas d'activités. Insérez une clé USB avec des activités sur pour ajouter.
</div>
</body>
</html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<h1 id="olpc-activity-group-name">Aktivite ki disponib nan Bwat la</h1>
<p id="olpc-activity-group-desc">Aktivite sa yo disponib sou sit lekòl la.</p>
<div class="olpc-activity-info">
Gen kounye a pa gen okenn aktivite. Antre yon USB ak aktivite sou li ajoute kèk.
</div>
</body>
</html>

View file

@ -0,0 +1,535 @@
# Copyright (C) 2008 One Laptop Per Child Association, Inc.
# Licensed under the terms of the GNU GPL v2 or later; see COPYING for details.
#
# written by Douglas Bagnall <douglas@paradise.net.nz>
"""Functions for processing XO activities, either for indexing and
presentaton to the laptops, or for diagnostics.
"""
import os, sys, shutil
import zipfile
import re
from cStringIO import StringIO
#import traceback
import syslog
from ConfigParser import SafeConfigParser
# we no longer really have a default in that it is set in the conf file
# we assume that we have a lang_template for the default language
TEMPLATE_DIR = '/library/xs-activity-server/lang_templates'
DEFAULT_LANG = 'en'
# how many versions before the latest are worth having around.
KEEP_OLD_VERSIONS = 3
#print to stderr, rathe than syslog?
USE_STDERR=False
REQUIRED_TAGS = ('bundle_id', 'activity_version', 'host_version', 'name', 'license')
OPTIONAL_TAGS = ('show_launcher', 'exec', 'mime_types', 'icon')
#XXX need either icon or show_launcher=no
def log(msg, level=syslog.LOG_NOTICE):
if USE_STDERR:
print >> sys.stderr, msg
else:
syslog.openlog( 'xs-activity-server', 0, syslog.LOG_USER )
syslog.syslog(level, msg)
syslog.closelog()
class BundleError(Exception):
pass
class Bundle(object):
def __init__(self, bundle):
self.linfo = {}
self.zf = zipfile.ZipFile(bundle)
# The activity path will be 'Something.activity/activity/activity.info'
for p in self.zf.namelist():
if p.endswith(self.INFO_PATH):
self.raw_data = read_info_file(self.zf, p, self.INFO_SECTION)
# the file name itself is needed for the URL
self.url = os.path.basename(bundle)
self.mtime = os.stat(bundle).st_mtime
self.name = self.raw_data.get('name')
self.license = self.raw_data.get('license', None)
# child ctor should now call
# _set_bundle_id
# _set_version
# _set_description
def _set_bundle_id(self, id):
if id is None:
raise BundleError("bad bundle: No bundle ID")
self.bundle_id = id
if self.name is None:
self.name = id
def _set_version(self, version):
self.version = version
def _set_description(self, description):
self.description = description
def __cmp__(self, other):
"""Alphabetical sort (locale dependant of course)"""
if self.bundle_id == other.bundle_id:
return cmp(self.version, other.version)
return cmp(self.name, other.name)
def set_older_versions(self, versions):
"""Versions should be a list of (version number, version tuples)"""
self.older_versions = ', '.join('<a href="%s">%s</a>' % (v.url, v.version) for v in versions)
def to_html(self, locale, template=None):
"""Fill in the template with data approriate for the locale."""
if template is None:
template = read_template('activity', locale)
d = {'older_versions': self.older_versions,
'bundle_id': self.bundle_id,
'activity_version': self.version,
'bundle_url': self.url,
'name': self.name,
'description': self.description,
}
d.update(self.linfo.get(locale, {}))
if d['older_versions']:
d['show_older_versions'] = 'inline'
else:
d['show_older_versions'] = 'none'
return template % d
def get_name(self, locale=None):
return self.name
class Content(Bundle):
INFO_PATH = "library/library.info"
INFO_SECTION = "Library"
def __init__(self, bundle):
super(Content, self).__init__(bundle)
d = self.raw_data
# bundle_id is often missing; service name is used instead.
self._set_bundle_id(d.get('global_name', None))
self._set_version(d.get('library_version', 1))
self._set_description(d.get('long_name', ''))
def debug(self, force_recheck=False):
# FIXME: implement debug checking for content bundles
return {}
class Activity(Bundle):
INFO_PATH = "activity/activity.info"
INFO_SECTION = "Activity"
#Activities appear to be looser than RFC3066, using e.g. _ in place of -.
linfo_re = re.compile(r'/locale/([A-Za-z]+[\w-]*)/activity.linfo$')
def __init__(self, bundle):
"""Takes a zipped .xo bundle name, returns a dictionary of its
activity info. Can raise a variety of exceptions, all of
which should indicate the bundle is invalid."""
super(Activity, self).__init__(bundle)
# The locale info will be Something.activity/locale/xx_XX/activity.linfo
for p in self.zf.namelist():
linfo = self.linfo_re.search(p)
if linfo:
lang = canonicalise(linfo.group(1))
self.linfo[lang] = read_info_file(self.zf, p, self.INFO_SECTION)
# Unfortunately the dictionary lacks some information, and
# stores other bits in inconsistent ways.
d = self.raw_data
# bundle_id is often missing; service name is used instead.
self._set_bundle_id(d.get('bundle_id', d.get('service_name')))
self._set_version(d.get('activity_version', 1))
self._set_description(d.get('description', ''))
def debug(self, force_recheck=False):
"""Make a copy of the raw data with added bits so we can work
out what is going on. This is useful for diagnosing problems
with odd activities and composing tut-tut-ing emails to their
authors.
Not used in production."""
if hasattr(self, '_debug_data') and not force_recheck:
return self._debug_data
d = self.raw_data.copy()
correct_forms = {
'name': str.upper,
'activity_version': str.isdigit,
'host_version': str.isdigit,
'bundle_id': re.compile(r'^[\w.]+$').match,
'service_name': re.compile(r'^[\w.]+$').match,
'icon': re.compile(r'^[\S]+$').match,
'exec': str.upper,
'mime_types': re.compile(r'^([\w.+-]+/[\w.+-]+;?)*$').match,
'update_url': re.compile(r'^http://([\w-]+\.?)+(:\d+)?(/[\w~%.-]+)*$').match,
#'update_url': re.compile(r'^$').match,
'show_launcher': re.compile(r'^(yes)|(no)$').match,
'class': re.compile(r'^(\w+.?)+$').match,
'license': str.upper,
#'license': re.compile(r'^GPLv[23]\+?$').match,
}
for k, v in d.items():
if k in correct_forms:
f = correct_forms.get(k, len)
if not f(v):
d['BAD ' + k] = v
rcount = 0
for k in REQUIRED_TAGS:
if k not in d:
d['LACKS %s' % k] = True
rcount += 1
d['MISSING KEYS'] = rcount
for t in OPTIONAL_TAGS:
if t not in d:
d['NO ' + t] = True
if not 'icon' in d and d.get('show_launcher') != 'no':
d['NO icon AND show_launcher'] = True
self._debug_data = d
return d
def get_name(self, locale):
"""Return the best guess at a name for the locale."""
for loc in locale_search_path(locale):
if loc in self.linfo and 'name' in self.linfo[loc]:
return self.linfo[loc]['name']
return super(Activity, self).get_name()
def check_all_bundles(directory, show_all_bundles=False):
"""A verbose debug function."""
all_bundles = []
unique_bundles = {}
counts = {}
# watch for these tags and print out the lists
bad_contents = {}
all_linfo = {}
unique_linfo = {}
linfo_keys = {}
log('Checking all activities in %s\n' % directory)
for f in os.listdir(directory):
if not f.endswith('.xo') and not f.endswith('.xol'):
continue
#log(f)
try:
if f.endswith('.xo'):
bundle = Activity(os.path.join(directory, f))
else:
bundle = Content(os.path.join(directory, f))
except Exception, e:
log("IRREDEEMABLE bundle %-25s (Error: %s)" % (f, e), syslog.LOG_WARNING)
#Clump together bundles of the same ID
x = unique_bundles.setdefault(bundle.bundle_id, [])
x.append(bundle)
all_bundles.append(bundle)
if not show_all_bundles:
#only show the newest one of each set.
bundles = []
for versions in unique_bundles.values():
versions.sort()
bundles.append(versions[-1])
else:
bundles = all_bundles
licenses = {}
for bundle in bundles:
bid = bundle.bundle_id
for k, v in bundle.debug().iteritems():
counts[k] = counts.get(k, 0) + 1
if k.startswith('BAD '):
bc = bad_contents.setdefault(k, {})
bc[bid] = v
for k, v in bundle.linfo.iteritems():
linfo_l = all_linfo.setdefault(k, [])
linfo_l.append(bundle)
for x in v:
linfo_keys[x] = linfo_keys.get(x, 0) + 1
if v['name'] != bundle.name:
linfo_l = unique_linfo.setdefault(k, [])
linfo_l.append(bundle)
if bundle.license:
lic = licenses.setdefault(bundle.license, [])
lic.append(bundle.bundle_id)
citems = counts.items()
rare_keys = [k for k, v in citems if v < 10]
lack_counts = dict((k, v) for k, v in citems if k.startswith('LACKS '))
bad_counts = dict((k, v) for k, v in citems if k.startswith('BAD '))
no_counts = dict((k, v) for k, v in citems if k.startswith('NO '))
tag_counts = dict((k, v) for k, v in citems if k not in lack_counts and
k not in bad_counts and k not in no_counts and k != 'MISSING KEYS')
# flag whether the tag is needed, ok, or not
tag_quality = dict((k, '*') for k in REQUIRED_TAGS)
tag_quality.update((k, '+') for k in OPTIONAL_TAGS)
linfo_counts = dict((k, len(v)) for k, v in all_linfo.iteritems())
linfo_uniq_counts = dict((k, len(v)) for k, v in unique_linfo.iteritems())
log('\nFound: %s bundles\n %s unique bundles' % (len(all_bundles), len(unique_bundles)))
for d, name, d2 in [(tag_counts, '\nattribute counts:', tag_quality),
(lack_counts, '\nmissing required keys:', {}),
(no_counts, '\nunused optional keys:', {}),
(bad_counts, '\nill-formed values:', {}),
(linfo_counts, '\nlinfo counts: total localised', linfo_uniq_counts),
(linfo_keys, '\nlinfo keys:', {})]:
log(name)
counts_reversed = [(v, k) for (k, v) in d.iteritems()]
counts_reversed.sort()
counts_reversed.reverse()
for (k, v) in counts_reversed:
log("%-25s %4s %4s" % (v, k, d2.get(v, '')))
log("\nRare keys:")
for k in rare_keys:
if k.startswith('BAD '):
continue
log(k)
for b in bundles:
v = b.debug().get(k)
if v:
log(' %-25s %s' % (b.bundle_id, v))
log("\nInteresting contents:")
for k, v in bad_contents.iteritems():
log(k)
for x in v.iteritems():
log(' %s: %s' % x)
log("\nInteresting linfo:")
for k in ('pseudo',):
log(k)
for a in all_linfo[k]:
if a in unique_linfo.get(k, []):
log(' * %s (%s vs. %s)' % (a.bundle_id, a.name, a.linfo[k]['name']))
else:
log(' %s (%s)' % (a.bundle_id, a.name))
log("\nLicenses:")
for lic, v in licenses.iteritems():
log("%-20s %s" %(repr(lic), len(v)))
log("\nRare licenses:")
for lic, v in licenses.iteritems():
if len(v) < 3:
log(' %s' % lic)
for x in v:
log(" %s" %(x))
log("\nAlmost valid activities:")
for b in bundles:
d = b.debug()
if d['MISSING KEYS'] == 1:
missing = ', '.join(x for x in d if x.startswith('LACKS'))
bad_values = ', '. join(x for x in d if x.startswith('BAD'))
log("%-20s %s %s" %(b.name, missing, bad_values))
log("\nValid activities (maybe):")
for b in bundles:
d = b.debug()
bid = b.bundle_id
if (d['MISSING KEYS'] == 0 and
bid not in bad_contents['BAD mime_types']):
log("%-20s - %s" %(b.name, bid))
#log(a.raw_data)
def read_info_file(zipfile, path, section):
"""Return a dictionary matching the contents of the config file at
path in zipfile"""
cp = SafeConfigParser()
info = StringIO(zipfile.read(path))
cp.readfp(info)
return dict(cp.items(section))
def canonicalise(lang):
"""Make all equivalent language strings the same.
>>> canonicalise('Zh-cN')
zh-CN
>>> canonicalise('zh_CN')
zh-CN
"""
lang = lang.replace('_', '-').upper()
bits = lang.split('-', 1)
bits[0] = bits[0].lower()
return '-'.join(bits)
def locale_search_path(locale):
"""Find a series of sensible locales to try, including
DEFAULT_LANG. For example 'zh-CN' would become ('zh-CN', 'zh',
'DEFAULT_LANG')."""
#XXX might be better to be storing locale as tuple
if '-' in locale:
return (locale, locale.split('-')[0], DEFAULT_LANG)
return (locale, DEFAULT_LANG)
def read_metadata(bundle_dir):
"""Attempt to read data in a metadata file. Raises expected
exceptions if the metadata file isn't readable. The file should
look something like this:
[org.laptop.Pippy]
description = Succinct description of this activity.
[org.laptop.Develop]
description = Succinct description of this activity.
web_icon = develop.png
"""
md_files = [os.path.join(bundle_dir, x)
for x in os.listdir(bundle_dir) if x.endswith('.info')]
cp = SafeConfigParser()
cp.read(md_files)
metadata = {}
for section in cp.sections():
metadata[section] = dict(x for x in cp.items(section))
return metadata
def htmlise_bundles(bundle_dir, dest_html):
"""Makes a nice html manifest for the bundles in a directory. The
manifest only shows the newest version of each bundle.
"""
#so, we collect up a dictionary of lists, then sort each list on
#the version number to find the newest.
bundles = [os.path.join(bundle_dir, x)
for x in os.listdir(bundle_dir) if x.endswith('.xo') or x.endswith('.xol')]
try:
metadata = read_metadata(bundle_dir)
except Exception, e:
log("had trouble reading metadata: %s" % e)
metadata = {}
all_bundles = {}
for filename in bundles:
try:
if filename.endswith('.xo'):
bundle = Activity(filename)
else:
bundle = Content(filename)
x = all_bundles.setdefault(bundle.bundle_id, [])
x.append((bundle.mtime, bundle))
except Exception, e:
log("Couldn't find good activity/library info in %s (Error: %s)" % (filename, e))
newest = []
# create an index for each language that has a template
# but track any locales in bundles in case we do not have templates for them
locales = [os.path.join(o) for o in os.listdir(TEMPLATE_DIR) if os.path.isdir(os.path.join(TEMPLATE_DIR,o))]
locales_found = set ()
for versions in all_bundles.values():
versions = [x[1] for x in sorted(versions)]
# end of list is the newest; beginning of list might need deleting
latest = versions.pop()
locales_found.update(latest.linfo)
newest.append(latest)
goners = versions[:-KEEP_OLD_VERSIONS]
keepers = versions[-KEEP_OLD_VERSIONS:]
for v in goners:
fn = os.path.join(bundle_dir, v.url)
os.remove(fn)
latest.set_older_versions(keepers)
if latest.bundle_id in metadata:
# we have extra metadata with which to fill out details
# presumably this is mainly human-oriented description.
d = metadata[latest.bundle_id]
for k in ('description', 'name'):
if k in d:
setattr(latest, k, d[k])
log('found locales: %s' % locales)
# assume locales is not empty as we have at least the default language
for locale in locales:
try:
make_html(newest, locale, '%s.%s' % (dest_html, locale))
except Exception, e:
log("Couldn't make page for %s (Error: %s)" % (locale, e), syslog.LOG_WARNING)
# make_varfile(locales, dest_html)- have switched to multiviews, so var not needed
def make_varfile(locales, dest_html):
f = open(dest_html + '.var', 'w')
index = os.path.basename(dest_html)
f.write('URI: %s\n\n' % index)
for locale in locales:
f.write('URI: %s.%s\n' % (index, locale))
f.write('Content-type: text/html; charset=utf-8\n')
f.write('Content-language: %s\n\n' % locale)
# now the default, slightly higher qs
f.write('URI: %s.DEFAULT\n' % index)
f.write('Content-type: text/html; charset=utf-8\n')
f.write('Content-language: en\n\n')
f.close()
def read_template(name, locale):
"""Try to read the locale's template, falling back to the
default."""
#also try containing locales, eg 'zh' for 'zh-CN'
for x in locale_search_path(locale):
try:
f = open(os.path.join(TEMPLATE_DIR, x, name))
break
except (OSError, IOError), e:
#log(str(e))
continue
s = f.read()
f.close()
return s
def make_html(bundles, locale, filename):
"""Write a microformated index for the activities in the appropriate language,
and save it to filename."""
page_tmpl = read_template('page', locale)
act_tmpl = read_template('activity', locale)
#bundles.sort() won't cut it.
schwartzian = [ (x.get_name(locale), x.to_html(locale, act_tmpl)) for x in bundles ]
schwartzian.sort()
s = page_tmpl % {'activities': '\n'.join(x[1] for x in schwartzian)}
if os.path.exists(filename):
shutil.move(filename, filename + '~')
f = open(filename, 'w')
f.write(s)
f.close()

View file

@ -0,0 +1,134 @@
# assume apache in admin group
- name: Create xs-activity-server directory tree
file: path={{ item }}
mode=0755
owner=root
group=admin
state=directory
with_items:
- /library/xs-activity-server
- /library/xs-activity-server/activities
- /library/xs-activity-server/lang_templates
- /library/xs-activity-server/www.0
- /library/xs-activity-server/tmp
# Wish synchronize worked, but it doesn't
- name: Copy language templates
command: rsync -a {{ iiab_dir }}/roles/activity-server/files/lang_templates /library/xs-activity-server/
- name: Copy default index files
copy: src={{ item }}
dest=/library/xs-activity-server/www.0
mode=0755
owner=root
group=root
with_fileglob:
- www.0/index.html.*
- name: Point www to www.0 as default
file: src=/library/xs-activity-server/www.0
dest=/library/xs-activity-server/www
owner=root
group=admin
state=link
- name: Chown language templates
file: path=/library/xs-activity-server/lang_templates
mode=0644
owner=root
group=admin
state=directory
recurse=yes
# We should have a var for python site-packages directory
- name: Create xs-activity-server python site-packages directory
file: path=/usr/lib/python2.7/site-packages/xs_activities
mode=0755
owner=root
group=root
state=directory
- name: Install Python module
copy: src=xs_activities/__init__.py
dest=/usr/lib/python2.7/site-packages/xs_activities
mode=0644
owner=root
group=root
- name: Copy scripts to /usr/bin
copy: src={{ item }}
dest=/usr/bin
mode=0755
owner=root
group=root
with_items:
- bin/xs-regenerate-activities
- bin/xs-check-activities
# Do in ansible what was done in /etc/sysconfig/olpc-scripts/setup.d/xs-activity-server script
- name: Copy xs-activity-server config file
template: src=xs-activity-server.conf
dest=/etc/{{ apache_config_dir }}
owner=root
group=root
mode=0644
# SEE ALSO THE apache2_module SECTION IN roles/httpd/tasks/main.yml
- name: enable mod_expires for debian
command: a2enmod expires
when: is_debuntu | bool
- name: create the link which enables the site
file: src=/etc/apache2/sites-available/xs-activity-server.conf
dest=/etc/apache2/sites-enabled/xs-activity-server.conf
state=link
when: activity_server_enabled and is_debuntu
- name: delete the link which enables the site
file: src=/etc/apache2/sites-available/xs-activity-server.conf
dest=/etc/apache2/sites-enabled/xs-activity-server.conf
state=absent
when: not activity_server_enabled and is_debuntu
- name: Copy xs-activity-server usbmount file
template: src=usbmount-60-xs-activity-server-installcontent
dest=/etc/usbmount/mount.d
owner=root
group=root
mode=0755
# TODO: Fix multiview so it supports portal language menu
# For it only supports client's language code
# TODO: Upload Activity via web interface
# and figure out what to do with olpc_activities.service
# short term addition of link for upload-activity server
# ln -sf /usr/share/xs-config/cfg/html/top/en/cntr_upl_activity.php {{ doc_root }}/upload_activity.php
- name: Restart httpd
service: name={{ apache_service }}
enabled=yes
state=restarted
- name: Add 'activity-server' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: activity-server
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: "Activity Server"
- option: description
value: "Download an Activity."
- option: path
value: /activities
- option: enabled
value: "{{ xo_services_enabled }}"

View file

@ -0,0 +1,115 @@
#!/bin/bash
# Part of the xs-activity-server package
#
# based on a similarly named script in the xs-rsync package
# by Martin Langhoff <martin@laptop.org>
#
# Adapted for xs-activity-server by Douglas Bagnall
# <douglas@paradise.net.nz>
#
# Copyright: One Laptop per Child
set -e
VERBOSE=yes
MAGIC_DIR=$UM_MOUNTPOINT/xs-activity-server
FINAL_DIR=/library/xs-activity-server/activities
FILES_TO_RM=""
# combined with set -e, error() is called if something fails.
error(){
logger -puser.err -t "xs-activity-server[$$]" "Error at line $(caller)"
[ "$FILES_TO_RM" ] && rm -rf $FILES_TO_RM
}
trap error ERR
# Log a string via the syslog facility.
log()
{
if test $1 != debug || expr "$VERBOSE" : "[yY]" > /dev/null; then
logger -p user.$1 -t "xs-activity-server[$$]" -- "$2"
fi
}
STEPS=7
[ -d $MAGIC_DIR ] || exit 0
log notice 'Found activity install directory';
log notice "[1/$STEPS] Checking whether it has a manifest";
if [ -r $MAGIC_DIR/manifest.sha1 ];then
log notice "[2/$STEPS] Seems to have a manifest";
else
log err "[2/$STEPS] Missing manifest"
exit 1;
fi
## Do we have enough space?
# note: we could use awk {'print $4'} instead of the
# perl regex, but it breaks with long /dev nodes
# such as those from LVMs -which wrap. The regex captures the
# number just left of the number with the percentage sign.
NEED=`du -s -B1M $MAGIC_DIR | awk {'print $1'}`
HAVE=`df -B1M $FINAL_DIR | tail -n1 | \
perl -pe 'm/(\d+)\s+\d+\%/; $_=($1-1);'`
if [ $NEED -gt $HAVE ];then
log err 'Not enough free space in /library for these activities - cancelling';
exit 1;
fi
### Copy it first - as the media is bound to be slow
# - make this atomic by cp'ing to a tmpdir, and mv'ing into place
# to be fail-safe
# - mv aside manifest.sha1 and its sig
# - TODO? we could avoid cp'ing files we already have using
# rsync --copy-dest instead of cp
#
log notice "[3/$STEPS] Copying activities to disk";
TMPDEST=`mktemp -d -p /library/xs-activity-server/tmp`
#make sure the tmp directory goes
FILES_TO_RM="$FILES_TO_RM '$TMPDEST'"
cp --preserve=timestamps $MAGIC_DIR/* $TMPDEST
# In a tmpdir we own, safe from race conditions
# run the checksums...
log notice "[4/$STEPS] Checking the manifest";
# mv the manifest to a different dir
TMPMANIF=`mktemp -d -p /library/xs-activity-server/tmp`
FILES_TO_RM="$FILES_TO_RM '$TMPMANIF'"
mv $TMPDEST/manifest.sha1 $TMPMANIF/
if [ -e $TMPDEST/manifest.sha1.sig ]; then
mv $TMPDEST/manifest.sha1.sig $TMPMANIF/
fi
xs-sum -c $TMPMANIF/manifest.sha1 -d $TMPDEST
#Let syslog know what we're doing
cd $TMPDEST
log notice "found $(ls *.xo |wc -l) activities"
log debug "found these activities: $(ls *.xo)"
cd -
log notice "[5/$STEPS] Copy the directories into place";
#XXX not checking whether this clobbers existing files.
mv $TMPDEST/* $FINAL_DIR
#So, now all the activities are in place, but maybe they're not
#newer than what we have. So xs-regenerate-activities has to work that out.
log notice "[6/$STEPS] Regenerating the list of available activities";
/usr/bin/xs-regenerate-activities $FINAL_DIR 2>&1 | logger -p user.debug -t "xs-activity-server[$$]"
log notice "[$STEPS/$STEPS] Finished - XOs can now update activities.";
rm -fr $FILES_TO_RM

View file

@ -0,0 +1,30 @@
# xs-activity-server
#
# Copyright: On Laptop per Child
# GPL v2
# written by Douglas Bagnall <douglas@paradise.net.nz>
#
# This belongs in the apache conf.d directory.
# (probably /etc/httpd/conf.d/)
Alias /activities /library/xs-activity-server/www
<Directory /library/xs-activity-server/www >
# Languages are set in 010-iiab.conf
ExpiresActive On
ExpiresDefault now
Options +MultiViews
Require all granted
#NOTE: an index.html.var file is generated, which ought to make
# MultiViews redundant (by my reading) but it doesn't seem to
# work. Someone could look at that sometime.
</Directory>
#<Directory /activities >
# ExpiresActive On
# ExpiresDefault now
#</Directory>
#<Location /activities >
# ExpiresActive On
# ExpiresDefault now
#</Location>

View file

@ -0,0 +1,5 @@
---
- name: restart ajenti service
service: name=ajenti
enabled=yes
state=restarted

View file

@ -0,0 +1,3 @@
- name: Install wondershaper ajenti plugin
pip: name="{{ iiab_download_url }}"/ajenti-plugin-wondershaper-0.3.tar.gz
when: internet_available | bool

View file

@ -0,0 +1,62 @@
- name: Install python-pip package
package: name=python-pip
state=present
- name: Install required libraries
package: name={{ item.pkg }}
state=present
with_items:
- pkg: python-imaging
- pkg: python-devel
- pkg: libxslt-devel
- pkg: pyOpenSSL
- pkg: python-daemon
- pkg: gcc
- name: Install ajenti from our repo
pip: name="{{ iiab_download_url }}"/ajenti-0.99.34-patched5.tar.gz
when: internet_available
# notify:
# - restart ajenti service
- name: download python-catcher
pip: name=python-catcher version=0.1.3
when: internet_available
- name: change default port
lineinfile: backup=yes
dest=/etc/ajenti/config.json
state=present
backrefs=yes
regexp='"port":\s*[0-9]{1,5}'
line='"port":9990'
- name: exe permission to ajenti
file: path=/etc/rc.d/init.d/ajenti
mode=0744
state=file
- include_tasks: ajenti-wondershaper.yml
when: 'iiab_lan_iface != ""'
# handler doesn't fire
- name: restart ajenti service
service: name=ajenti
enabled=yes
state=restarted
when: ajenti_enabled | bool
- name: Add 'ajenti' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: ajenti
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: ajenti
- option: description
value: "Ajenti is a client server systems administration tool controlled by a web browser"
- option: enabled
value: "{{ ajenti_enabled }}"

View file

@ -0,0 +1,69 @@
- name: check pip is installed
package: name=python-pip
state=present
- name: Install xs-authserver from pypi
pip: name=xs-authserver
when: internet_available | bool
- name: install gunicorn
package: name=python-gunicorn
state=present
- name: Configure xs-authserver
template: backup=yes
src={{ item.src }}
dest={{ item.dest }}
owner=root
group=root
mode={{ item.mode }}
with_items:
- src: xs-authserver.env.j2
dest: /etc/sysconfig/xs-authserver
mode: 0644
- src: xs-authserver.service.j2
dest: /etc/systemd/system/xs-authserver.service
mode: 0644
- name: create database folder
file: state=directory
path=/var/lib/xs-authserver/
owner=root
group=root
mode=0644
- name: init database
command: xs-authserverctl initdb
ignore_errors: yes
environment:
XS_AUTHSERVER_DATABASE: /var/lib/xs-authserver/data.db
- name: Stop authserver service
service: name=xs-authserver
state=stopped
enabled=no
when: not authserver_enabled
- name: Start xs-authserver service
service: name=xs-authserver
state=restarted
enabled=yes
when: authserver_enabled | bool
- name: Add 'authserver' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: authserver
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: XS-authserver
- option: description
value: '"authserver (xs-authserver) implements a seamless web authentication
service using XO laptop registration capabilities. It is heavily
inspired by the Moodle OLPC-XS authentication plugin"'
- option: port
value: 5000
- option: path
value: /

View file

@ -0,0 +1,2 @@
XS_AUTHSERVER_OLPC_XS_DB='/home/idmgr/identity.db'
XS_AUTHSERVER_DATABASE='/var/lib/xs-authserver/data.db'

View file

@ -0,0 +1,10 @@
[Unit]
Description=XS authentication server
After={{ apache_service }}.service local-fs.target
[Service]
EnvironmentFile=-/etc/sysconfig/xs-authserver
ExecStart=/usr/bin/gunicorn -n xs-authserver xs_authserver:app -b 0.0.0.0:5000
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,5 @@
schooltool_version: schooltool-2.8.5
schooltool_src: '{{ schooltool_version }}.tar.gz'
debian_schooltool_install: True
debian_schooltool_enabled: False

View file

@ -0,0 +1,47 @@
- name: get the required build packages
package: name={{ item }}
state=present
with_items:
- build-essential
- gettext
- python-dev
- libicu-dev
- libxslt1-dev
- libfreetype6-dev
- libjpeg-dev
- enscript
- python-virtualenv
- ttf-liberation
- redis-server
- libjpeg-dev
- xvfb
when: debian_schooltool_install and is_debuntu
- name: Create the font directory
file: path=/usr/share/fonts/truetype/ttf-ubuntu
state=directory
- name: get the ttf-ubuntu-font-family
get_url: url={{ iiab_download_url }}/ubuntu-font-family-0.83.zip
dest={{ downloads_dir }}
- name: expand the ttf fonts to the right place
unarchive: src={{ downloads_dir }}/ubuntu-font-family-0.83.zip
dest=/usr/share/fonts/truetype/ttf-ubuntu/
- name: get the schooltool source
get_url: url={{ iiab_download_url }}/{{ schooltool_src }}
dest={{ downloads_dir }}
- name: expand source to dest
unarchive: src={{ downloads_dir }}/{{ schooltool_src }}
dest={{ iiab_base }}
- name: create a link for schooltool
file: src={{ iiab_base }}/{{ schooltool_version }}
dest={{ iiab_base }}/schooltool
state=link
- name: build the schooltool from source
shell: command='$( cd {{ iiab_base }}/schooltool; /usr/bin/make ) '

View file

@ -0,0 +1,26 @@
[buildout]
extends = base.cfg
develop = .
[versions]
# Unset versions of packages you want to develop
schooltool =
[package]
eggs += schooltool
schooltool.gradebook
schooltool.lyceum.journal
schooltool.intervention
[test]
eggs = schooltool [test]
# To run selenium tests:
# - Download standalone selenium server from
# http://code.google.com/p/selenium/downloads/list
# - Start the server: "java -jar selenium-server-standalone-2.7.0.jar"
# - Uncomment the lines below:
#
#selenium.default = html_unit
#selenium.html_unit.web_driver = remote
#selenium.html_unit.capabilities = HTMLUNITWITHJS

View file

@ -0,0 +1,2 @@
docker_install: True
docker_enabled: False

View file

@ -0,0 +1,55 @@
- name: Install docker
package: name={{ item }}
state=present
with_items:
- docker
- python-docker-py
when: docker_install | bool
#tags: download
- name: put the systemd startup file in place
template: src=docker.service
dest=/etc/systemd/system/
owner=root
group=root
mode=0644
- name: create the socket for docker
template: src=docker.socket
dest=/etc/systemd/system/
owner=root
group=root
mode=0644
- name: Create a folder for systemd unit files that are docker containers
file: path=/etc/systemd/system/docker.service.d
owner=root
group=root
mode=0644
state=directory
- name: Enable docker
service: name=docker
state=started
enabled=true
when: docker_enabled | bool
- name: Disable docker
service: name=docker
state=stopped
enabled=false
when: not docker_enabled
- name: Add 'docker' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: docker
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: Docker Container
- option: description
value: '"Docker allows a person to package an application with all of its dependencies into a standardized unit for software development."'
- option: enabled
value: "{{ docker_enabled }}"

View file

@ -0,0 +1,26 @@
[unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/docker daemon
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,13 @@
[unit]
Description=Docker Socket for the API
PartOf=docker.service
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target

View file

@ -0,0 +1,36 @@
===============
DokuWiki README
===============
DokuWiki is a simple to use and highly versatile Open Source wiki software that
doesn't require a database. It is loved by users for its clean and readable
syntax. The ease of maintenance, backup and integration makes it an
administrator's favorite. Built in access controls and authentication connectors
make DokuWiki especially useful in the enterprise context and the large number of
plugins contributed by its vibrant community allow for a broad range of use cases
beyond a traditional wiki.
http://dokuwiki.org
After Installation
------------------
Head to http://box.lan/wiki. The webpage will probably throw up an error
saying you haven't run install.php yet, with a link to it. Click the link to be
taken to the install page which does the initial configuration of the wiki. After
this, you should be all set!
Locations
---------
Everything is copied to the /opt/dokuwiki folder. An apache configuration file is
installed in the usual conf.d directory.
Parameters
----------
None yet other than the basic enabled/disabled. Haven't really tested if they work.
Todo
----
* Preinstall some popular plugins.
* Additional IIAB customizations.

View file

@ -0,0 +1,9 @@
# dokuwiki_install: False
# dokuwiki_enabled: False
# dokuwiki_url: /dokuwiki
# All above are set in: github.com/iiab/iiab/blob/master/vars/default_vars.yml
# If nec, change them by editing /etc/iiab/local_vars.yml prior to installing!
dokuwiki_version: "dokuwiki-2018-04-22b"

View file

@ -0,0 +1,52 @@
# Apache
- name: Enable http://box{{ dokuwiki_url }} via Apache # http://box/dokuwiki
command: a2ensite dokuwiki.conf
when: apache_install and dokuwiki_enabled
- name: Disable http://box{{ dokuwiki_url }} via Apache # http://box/dokuwiki
command: a2dissite dokuwiki.conf
when: apache_install and not dokuwiki_enabled
- name: Restart Apache systemd service ({{ apache_service }})
systemd:
name: "{{ apache_service }}"
state: restarted
when: apache_enabled | bool
# NGINX
- name: "SHIM: Enable http://box{{ dokuwiki_url }} via NGINX, by installing {{ nginx_conf_dir }}/dokuwiki-nginx.conf from template" # http://box/dokuwiki
template:
src: dokuwiki-nginx.conf.j2
dest: "{{ nginx_conf_dir }}/dokuwiki-nginx.conf"
when: nginx_install and dokuwiki_enabled
- name: "SHIM: Disable http://box{{ dokuwiki_url }} via NGINX, by removing {{ nginx_conf_dir }}/dokuwiki-nginx.conf" # http://box/dokuwiki
file:
path: "{{ nginx_conf_dir }}/dokuwiki-nginx.conf"
state: absent
when: nginx_install and not dokuwiki_enabled
- name: Restart 'nginx' systemd service
systemd:
name: nginx
state: restarted
when: nginx_enabled | bool
- name: Add 'dokuwiki' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: dokuwiki
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: DokuWiki
- option: description
value: '"DokuWiki is a simple to use and highly versatile Open Source wiki software that does not require a database."'
- option: installed
value: "{{ dokuwiki_install }}"
- option: enabled
value: "{{ dokuwiki_enabled }}"

View file

@ -0,0 +1,54 @@
- name: Download {{ iiab_download_url }}/{{ dokuwiki_version }}.tgz # iiab_download_url is http://download.iiab.io/packages
get_url:
url: "{{ iiab_download_url }}/{{ dokuwiki_version }}.tgz"
dest: "{{ downloads_dir }}/"
timeout: "{{ download_timeout }}"
when: internet_available | bool
- name: Unarchive (unpack) it to /library/{{ dokuwiki_version }}
unarchive:
src: "{{ downloads_dir }}/{{ dokuwiki_version }}.tgz"
dest: /library
creates: "/library/{{ dokuwiki_version }}/VERSION"
- name: Ensure dir /library/{{ dokuwiki_version }} is owned by {{ apache_user }} with 644/755 permissions
file:
path: "/library/{{ dokuwiki_version }}"
owner: "{{ apache_user }}"
mode: u+rw,go+r,go-w # '0755' had forced 'x' bits for non-dirs
state: directory
recurse: yes
- name: Symlink /library/dokuwiki -> /library/{{ dokuwiki_version }}
#shell: if [ ! -d /library/dokuwiki ]; then ln -sf /library/{{ dokuwiki_version }} /library/dokuwiki; fi
#shell: ln -sf /library/{{ dokuwiki_version }} /library/dokuwiki
#BOTH LINES ABOVE FAIL TO UPDATE LINK; Ansible approach below works
file:
src: /library/{{ dokuwiki_version }}
path: /library/dokuwiki
state: link
force: yes
- name: Install /etc/{{ apache_config_dir }}/dokuwiki.conf from template, for DokuWiki's http://box{{ dokuwiki_url }}
template:
src: dokuwiki.conf.j2
dest: "/etc/{{ apache_config_dir }}/dokuwiki.conf"
# - name: Symlink /etc/apache2/sites-enabled/dokuwiki.conf to /etc/apache2/sites-available/dokuwiki.conf if dokuwiki_enabled (debuntu)
# file:
# src: /etc/apache2/sites-available/dokuwiki.conf
# path: /etc/apache2/sites-enabled/dokuwiki.conf
# state: link
# when: dokuwiki_enabled and is_debuntu
#
# - name: Remove symlink /etc/apache2/sites-enabled/dokuwiki.conf if not dokuwiki_enabled (debuntu)
# file:
# path: /etc/apache2/sites-enabled/dokuwiki.conf
# state: absent
# when: not dokuwiki_enabled and is_debuntu
- name: "Add 'dokuwiki_installed: True' to {{ iiab_state_file }}"
lineinfile:
dest: "{{ iiab_state_file }}" # /etc/iiab/iiab_state.yml
regexp: '^dokuwiki_installed'
line: 'dokuwiki_installed: True'

View file

@ -0,0 +1,7 @@
- name: Install DokuWiki
include_tasks: install.yml
when: dokuwiki_install and not dokuwiki_installed is defined
- name: Enable DokuWiki
include_tasks: enable.yml
when: dokuwiki_install or dokuwiki_installed is defined

View file

@ -0,0 +1,3 @@
location {{ dokuwiki_url }}/ {
proxy_pass http://127.0.0.1:{{ apache_port }}{{ dokuwiki_url }}/;
}

View file

@ -0,0 +1,8 @@
RewriteEngine on
Alias {{ dokuwiki_url }} /library/dokuwiki
<Directory /library/dokuwiki>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

View file

@ -0,0 +1,96 @@
- name: Install ejabberd package
package:
name: ejabberd
state: present
#tags: download
#- name: Configure ejabberd
# template:
# backup: yes
# src: "{{ item.src }}"
# dest: "{{ item.dest }}"
# owner: root
# group: root
# mode: "{{ item.mode }}"
# with_items:
# - { src: 'ejabberd-iiab.cfg.j2', dest: '/etc/ejabberd/ejabberd-iiab.cfg' , mode: '0644' }
# - { src: 'ejabberdctl.cfg.j2', dest: '/etc/ejabberd/ejabberdctl-iiab.cfg', mode: '0644' }
# - { src: 'ejabberd-iiab', dest: '/etc/sysconfig/ejabberd-iiab', mode: '0755' }
# #- { src: 'ejabberd-domain-config', dest: '/etc/sysconfig/olpc-scripts/domain_config.d/ejabberd', mode: '0755'}
# #- { src: 'ejabberd', dest: '/etc/sysconfig/olpc-scripts/domain_config.d/ejabberd' , mode: '0755' }
# - { src: 'ejabberd-iiab.service.j2', dest: '/etc/systemd/system/ejabberd-iiab.service', mode: '0644' }
# - { src: 'iiab-ejabberd-srg', dest: '/usr/bin/iiab-ejabberd-srg' , mode: '0755' }
# #- { src: '10-ejabberdmoodle', dest: '/etc/sudoers.d/10-ejabberdmoodle', mode: '0440' }
# - { src: 'ejabberd.tmpfiles', dest: '/etc/tmpfiles.d/ejabberd.conf', mode: '0640' }
# register: ejabberd_config
#- name: Stop and disable OS provided systemd ejabberd service
# service:
# name: ejabberd
# state: stopped
# enabled: no
#- name: Put the startup script in place - debian
# template:
# src: ejabberd-iiab.init
# dest: /etc/init.d/ejabberd-iiab
# mode: 0755
# when: is_debuntu | bool
#- name: Put the startup script in place - non debian
# template:
# src: ejabberd-iiab.init
# dest: /usr/libexec/ejabberd-iiab
# mode: 0755
# when: not is_debuntu
#- name: Remove ejabberd_domain if domain changes
# file:
# path: /etc/sysconfig/ejabberd_domain_name
# state: absent
# when: ejabberd_config.changed
#- name: Enable ejabberd service
# file:
# src: /etc/systemd/system/ejabberd-iiab.service
# dest: /etc/systemd/system/multi-user.target.wants/ejabberd-iiab.service
# owner: root
# group: root
# state: link
- name: Stop ejabberd service
service:
name: ejabberd
#name: ejabberd-iiab
state: stopped
enabled: no
when: not ejabberd_enabled
- name: Start ejabberd service
service:
name: ejabberd
#name: ejabberd-iiab
state: restarted
enabled: yes
when: ejabberd_enabled | bool
#when: ejabberd_config.changed and ejabberd_enabled
#- name: Wait for ejabberd service start
# wait_for:
# port: 5280
# delay: 15
# state: started
# timeout: 300
# when: ejabberd_config.changed and ejabberd_enabled
# ejabberd-iiab.init has the logic for the below, needs to be done once
# and only if the group does not exist based on presence of
# /var/lib/ejabberd online_src_created
#- name: Create online group
# shell: ejabberdctl srg_create Online "{{ iiab_hostname }}" Online "Online_Users" Online
# when: ejabberd_config.changed
#- name: Add all users to online group
# shell: ejabberdctl srg_user_add '@online@' "{{ iiab_hostname }}" Online "schoolserver"
# when: ejabberd_config.changed

View file

@ -0,0 +1,12 @@
##
## 10-ejabberdmoodle
## for ejabberd-moodle interaction
##
# allow the apache user to invoke ejabberdctl and start/stop/condrestart
Defaults:apache !requiretty
Cmnd_Alias EJABBERDCTL = /usr/sbin/ejabberdctl
Cmnd_Alias EJABBERDINIT = /etc/init.d/ejabberd start , /etc/init.d/ejabberd stop , /etc/init.d/ejabberd condrestart
apache ALL = (ejabberd) NOPASSWD: EJABBERDCTL
apache ALL = (root) NOPASSWD: EJABBERDINIT

View file

@ -0,0 +1,62 @@
#!/bin/sh -e
#
# ejabberd now handles domain changes in the initrd script
#
SERVICE_NAME=ejabberd-iiab
CONFIG_LIST="/etc/ejabberd/ejabberd-iiab.cfg"
# taken from ejabberd spec %post
# taken from ejabberd spec %post
#function do-cert(){
# (cd /etc/ejabberd
# if [ ! -f ejabberd.pem ]
# then
# echo "Generating SSL certificate /etc/ejabberd/ejabberd.pem..."
# HOSTNAME=$(hostname -s)
# DOMAINNAME=$(hostname -d)
# openssl req -new -x509 -days 36500 -nodes -out ejabberd.pem -keyout ejabberd.pem > /dev/null 2>&1 << +++
# .
# .
# .
# $DOMAINNAME
# $HOSTNAME
# ejabberd
# root@$HOSTNAME.$DOMAINNAME
# +++
# chown ejabberd:ejabberd ejabberd.pem
# chmod 600 ejabberd.pem
# fi)
#}
# This is the suffix which original versions of modified files will have
BACKUP_SUFFIX=old
short_host=`hostname -s`
new_name=$short_host.$1
for config in $CONFIG_LIST;
do
if [ -e $config.in ]; then
if [ -e $config ]; then
mv $config $config.$BACKUP_SUFFIX
fi
sed -e s/{{ iiab_hostname }}/$new_name/ $config.in > $config ;
else
echo WARNING: Skipped $config - template file is missing!
fi
done
#if [ -e /etc/ejabberd/ejabberd.pem.$1 ]; then
# rm /etc/ejabberd/ejabberd.pem.$1
#fi
#mv /etc/ejabberd/ejabberd.pem /etc/ejabberd/ejabberd.pem.$1
#do-cert
# Since for the community edition, we don't really expect all modules to be present
# Just exit, and expect the user to do a restart
exit 0

View file

@ -0,0 +1,13 @@
## Settings for ejabberd
## Where should ejabberd find its configuration file?
#
CONFIG_FILE=/etc/ejabberd/ejabberd-iiab.cfg
## ULIMIT_MAX_FILES alters the number of files that ejabberd is
## allowed to have open at once. If it is unset the system default
## (usually 1024) will be used. ejabberd will want over twice as many
## open files as it has active connections, so if you have a few
## hundred or more users you will want to set this.
#
ULIMIT_MAX_FILES=40000

View file

@ -0,0 +1,454 @@
%%%
%%% ejabberd configuration file
%%%
%%% The parameters used in this configuration file are explained in more detail
%%% in the ejabberd Installation and Operation Guide.
%%% Please consult the Guide in case of doubts, it is included in
%%% your copy of ejabberd, and is also available online at
%%% http://www.process-one.net/en/ejabberd/docs/
%%% This configuration file contains Erlang terms.
%%% In case you want to understand the syntax, here are the concepts:
%%%
%%% - The character to comment a line is %
%%%
%%% - Each term ends in a dot, for example:
%%% override_global.
%%%
%%% - A tuple has a fixed definition, its elements are
%%% enclosed in {}, and separated with commas:
%%% {loglevel, 4}.
%%%
%%% - A list can have as many elements as you want,
%%% and is enclosed in [], for example:
%%% [http_poll, web_admin, tls]
%%%
%%% - A keyword of ejabberd is a word in lowercase.
%%% The strings are enclosed in "" and can have spaces, dots...
%%% {language, "en"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%%
%%% - This term includes a tuple, a keyword, a list and two strings:
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
%%%
%%% =======================
%%% OVERRIDE STORED OPTIONS
%%
%% Override the old values stored in the database.
%%
%%
%% Override global options (shared by all ejabberd nodes in a cluster).
%%
override_global.
%%
%% Override local options (specific for this particular ejabberd node).
%%
override_local.
%%
%% Remove the Access Control Lists before new ones are added.
%%
override_acls.
%%% =========
%%% DEBUGGING
%%
%% loglevel: Verbosity of log files generated by ejabberd.
%% 0: No ejabberd log at all (not recommended)
%% 1: Critical
%% 2: Error
%% 3: Warning
%% 4: Info
%% 5: Debug
%%
{loglevel, 4}.
%%
%% watchdog_admins: If an ejabberd process consumes too much memory,
%% send live notifications to those Jabber accounts.
%%
%%{watchdog_admins, ["bob@example.com"]}.
%%% ================
%%% SERVED HOSTNAMES
%%
%% hosts: Domains served by ejabberd.
%% You can define one or several, for example:
%% {hosts, ["example.net", "example.com", "example.org"]}.
%%
{hosts, ["{{ iiab_hostname }}.{{ iiab_domain }}"]}.
%%
%% route_subdomains: Delegate subdomains to other Jabber server.
%% For example, if this ejabberd serves example.org and you want
%% to allow communication with a Jabber server called im.example.org.
%%
%%{route_subdomains, s2s}.
%%% ===============
%%% LISTENING PORTS
%%
%% listen: Which ports will ejabberd listen, which service handles it
%% and what options to start it with.
%%
{listen,
[
{5222, ejabberd_c2s, [
%%
%% If TLS is compiled and you installed a SSL
%% certificate, put the correct path to the
%% file and uncomment this line:
%%
%%{certfile, "/path/t/etc/ejabberd/ejabberd.pem"}, starttls,
inet6,
{access, c2s},
{shaper, c2s_shaper},
{max_stanza_size, 524288}
]}
%%
%% To enable the old SSL connection method in port 5223:
%%
, {5223, ejabberd_c2s, [
inet6,
{access, c2s},
{shaper, c2s_shaper},
tls, {certfile, "/etc/ejabberd/ejabberd.pem"},
{max_stanza_size, 524288}
]}
%% , {5269, ejabberd_s2s_in, [
%% {shaper, s2s_shaper},
%% {max_stanza_size, 131072}
%% ]},
%%
%% ejabberd_service: Interact with external components (transports...)
%%
%% , {8888, ejabberd_service, [
%% {access, all},
%% {shaper_rule, fast},
%% {ip, {127, 0, 0, 1}},
%% {hosts, ["icq.example.org", "sms.example.org"],
%% [{password, "secret"}]
%% }
%% ]}
, {5280, ejabberd_http, [
inet6,
http_poll,
web_admin
]}
]}.
%%
%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
%% Allowed values are: true or false.
%% You must specify a certificate file.
%%
%%{s2s_use_starttls, true}.
%%
%% s2s_certfile: Specify a certificate file.
%%
%%{s2s_certfile, "/path/t/etc/ejabberd/ejabberd.pem"}.
%%
%% domain_certfile: Specify a different certificate for each served hostname.
%%
%%{domain_certfile, "example.org", "/path/to/example_org.pem"}.
%%{domain_certfile, "example.com", "/path/to/example_com.pem"}.
%%
%% S2S whitelist or blacklist
%%
%% Default s2s policy for undefined hosts.
%%
{s2s_default_policy, deny}.
%%
%% Allow or deny communication with specific servers.
%%
%%{{ '{{' }}s2s_host, "goodhost.org"}, allow}.
%%{{ '{{' }}s2s_host, "badhost.org"}, deny}.
%%% ==============
%%% AUTHENTICATION
%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal.
%% If you want to use a different method,
%% comment this line and enable the correct ones.
%%
{auth_method, internal}.
%%
%% Authentication using external script
%% Make sure the script is executable by ejabberd.
%%
%%{auth_method, external}.
%%{extauth_program, "/path/to/authentication/script"}.
%%
%% Authentication using ODBC
%% Remember to setup a database in the next section.
%%
%%{auth_method, odbc}.
%%
%% Authentication using PAM
%%
%%{auth_method, pam}.
%%{pam_service, "pamservicename"}.
%%
%% Authentication using LDAP
%%
%%{auth_method, ldap}.
%%
%% List of LDAP servers:
%%{ldap_servers, ["localhost"]}.
%%
%% LDAP attribute that holds user ID:
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
%%
%% Search base of LDAP directory:
%%{ldap_base, "dc=example,dc=com"}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password to LDAP manager:
%%{ldap_password, "******"}.
%%
%% Anonymous login support:
%% auth_method: anonymous
%% anonymous_protocol: sasl_anon | login_anon | both
%% allow_multiple_connections: true | false
%%
%%{host_config, "public.example.org", [{auth_method, anonymous},
%% {allow_multiple_connections, false},
%% {anonymous_protocol, sasl_anon}]}.
%%
%% To use both anonymous and internal authentication:
%%
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
%%% ==============
%%% DATABASE SETUP
%% ejabberd uses by default the internal Mnesia database,
%% so you can avoid this section.
%% This section provides configuration examples in case
%% you want to use other database backends.
%% Please consult the ejabberd Guide for details about database creation.
%%
%% MySQL server:
%%
%%{odbc_server, {mysql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}.
%%
%% PostgreSQL server:
%%
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}.
%%
%% If you use PostgreSQL, have a large database, and need a
%% faster but inexact replacement for "select count(*) from users"
%%
%%{pgsql_users_number_estimate, true}.
%%
%% ODBC compatible or MSSQL server:
%%
%%{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
%%% ===============
%%% TRAFFIC SHAPERS
%%
%% The "normal" shaper limits traffic speed to 1.000 B/s
%%
{shaper, normal, {maxrate, 1000}}.
%%
%% The "fast" shaper limits traffic speed to 50.000 B/s
%%
{shaper, fast, {maxrate, 50000}}.
%%% ====================
%%% ACCESS CONTROL LISTS
%%
%% The 'admin' ACL grants administrative privileges to Jabber accounts.
%% You can put as many accounts as you want.
%%
%%{acl, admin, {user, "aleksey", "localhost"}}.
%%{acl, admin, {user, "ermine", "example.org"}}.
{acl, admin, {user, "admin", "{{ iiab_hostname }}.{{ iiab_domain }}"}}.
%%
%% Blocked users
%%
%%{acl, blocked, {user, "baduser", "example.org"}}.
%%{acl, blocked, {user, "test"}}.
%%
%% Local users: dont modify this line.
%%
{acl, local, {user_regexp, ""}}.
%%
%% More examples of ACLs
%%
%%{acl, jabberorg, {server, "jabber.org"}}.
%%{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
%%{acl, test, {user_regexp, "^test"}}.
%%{acl, test, {user_glob, "test*"}}.
%%% ============
%%% ACCESS RULES
%% Define the maximum number of time a single user is allowed to connect:
{access, max_user_sessions, [{10, all}]}.
%% This rule allows access only for local users:
{access, local, [{allow, local}]}.
%% Only non-blocked users can use c2s connections:
{access, c2s, [{deny, blocked},
{allow, all}]}.
%% For all users except admins used "normal" shaper
{access, c2s_shaper, [{none, admin},
{fast, all}]}.
%% For all S2S connections used "fast" shaper
{access, s2s_shaper, [{fast, all}]}.
%% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
%% Only admins can use configuration interface:
{access, configure, [{allow, admin}]}.
%% Admins of this server are also admins of MUC service:
{access, muc_admin, [{allow, admin}]}.
%% All users are allowed to use MUC service:
{access, muc, [{allow, all}]}.
%% Every username can be registered via in-band registration:
%% To disable in-band registration, replace 'allow' with 'deny'.
{access, register, [{allow, all}]}.
%% Allow repeat registration from the same client (necessary for testing)
%% Set to a positive integer (or comment out) to restrict with a timeout.
%% (infinity means zero; 0 does not work)
% {registration_timeout, infinity}.
%% Everybody can create pubsub nodes
{access, pubsub_createnode, [{allow, all}]}.
%%% ================
%%% DEFAULT LANGUAGE
%%
%% language: Default language used for server messages.
%%
{language, "en"}.
%%% =======
%%% MODULES
%%
%% Modules enabled in all ejabberd virtual hosts.
%%
{modules,
[
{mod_adhoc, []},
{mod_announce, [{access, announce}]}, % requires mod_adhoc
{mod_caps, []},
{mod_configure,[]}, % requires mod_adhoc
{mod_admin_extra, []},
{mod_disco, []},
%%{mod_echo, [{host, "echo.localhost"}]},
{mod_irc, []},
{mod_last, []},
{mod_muc, [
{host, "conference.@HOST@"},
{access, muc},
{access_create, muc},
{access_persistent, muc},
{access_admin, muc_admin}
]},
%%{mod_muc_log,[]},
{mod_offline, []},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
{mod_pubsub, [{access_createnode, pubsub_createnode},
{plugins, ["default", "pep"]}
]},
{mod_register, [
%%
%% After successful registration, the user receives
%% a message with this subject and body.
%%
%%{welcome_message, {"Welcome!",
%% "Welcome to this Jabber server."}},
%%
%% When a user registers, send a notification to
%% these Jabber accounts.
%%
%%{registration_watchers, ["admin1@example.org"]},
{access, register}
]},
{mod_roster, []},
%%{mod_service_log,[]},
{mod_shared_roster,[]},
{mod_stats, []},
{mod_time, []},
{mod_vcard, []},
{mod_version, []}
]}.
%%% $Id: ejabberd.cfg.example 988 2007-11-26 21:29:14Z badlop $
%%% Local Variables:
%%% mode: erlang
%%% End:
%%% vim: set filetype=erlang tabstop=8:

View file

@ -0,0 +1,220 @@
#!/bin/bash
#
# ejabberd Start and stop ejabberd.
# chkconfig: - 40 60
# description: ejabberd
# processname: ejabberd
# pidfile: /var/run/ejabberd/ejabberd.pid
### BEGIN INIT INFO
# Provides: ejabberd
# Required-Start: network
# Required-Stop: network
# Default-Start: 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start and stop ejabberd
# Description: A distributed, fault-tolerant Jabber/XMPP server
### END INIT INFO
SYS_DOMAIN_FILE=/etc/sysconfig/iiab_domain_name
OUR_DOMAIN_FILE=/etc/sysconfig/ejabberd_domain_name
. /etc/rc.d/init.d/functions
if [ -r /etc/sysconfig/ejabberd-iiab ]; then
. /etc/sysconfig/ejabberd-iiab
fi
if [ ! "$CONFIG_FILE" ]; then
CONFIG_FILE=/etc/ejabberd/ejabberd-iiab.cfg
fi
# /var/run is tmpfs in fc18, so need to create every time
mkdir -p /var/run/ejabberd
chown ejabberd:ejabberd /var/run/ejabberd
# avoid using consolehelper, call ejabberdctl directly
progctl=/usr/sbin/ejabberdctl
check_domain_configured() {
if [ ! -e $SYS_DOMAIN_FILE ]; then
echo "Domain not configured yet 1" > /dev/stderr
exit 1;
fi
domain=`cat "$SYS_DOMAIN_FILE" `
if [ "$domain" == "random.xs.laptop.org" ]; then
echo "Domain not configured yet 2" > /dev/stderr
exit 1;
fi
#hostname=`hostname -f`
hostname=`hostname `
if [ "$hostname" == "localhost.localdomain" ]; then
echo "Domain not configured yet 3" > /dev/stderr
fi
# if [ "$hostname" != "schoolserver.$domain" ]; then
# echo "Domain changed -- restart to enable ejabberd" > /dev/stderr
# fi
short_host=`hostname -s`
node_name=`cat $OUR_DOMAIN_FILE`
# if [ ! -e "$OUR_DOMAIN_FILE" ] || ! cmp "$SYS_DOMAIN_FILE" "$OUR_DOMAIN_FILE" ; then
if [ ! -e "$OUR_DOMAIN_FILE" ] ; then
update_domain
fi
}
update_domain() {
BACKUP_SUFFIX=old
if [ -e $CONFIG_FILE ]; then
cp $CONFIG_FILE $CONFIG_FILE.$BACKUP_SUFFIX || exit 1
fi
new_name=$short_host.$domain
#(sed -e s/@@BASEDNSNAME2@@/$new_name/ $CONFIG_FILE.in > $CONFIG_FILE.tmp ) && mv $CONFIG_FILE.tmp $CONFIG_FILE || exit 1
# If we are changing the domain, we must clear the DB.
if [ -e /var/lib/ejabberd/online_src_created ] ; then
rm -f /var/lib/ejabberd/online_src_created
fi
if [ -d /var/lib/ejabberd/spool/ ]; then
rm -f /var/lib/ejabberd/spool/*
fi
# Mark as done -
# cp "$SYS_DOMAIN_FILE" "$OUR_DOMAIN_FILE"
echo "$domain" > "$OUR_DOMAIN_FILE"
}
setup_online_srg() {
if [ -e /var/lib/ejabberd/online_src_created ]; then
return 0
fi;
# give ejabberd a bit of time to startup on XO-1 HW :-)
sleep 10;
short_host=`hostname -s`
domain=`cat "$SYS_DOMAIN_FILE"`
# Note: grep -q exits as soon as the match is found, which ejabberdctl
# doesn't like. So we send the output to /dev/null instead - more
# portable too.
#
# ejabberdctl should handle SIGPIPE without messing up, but that's
# a minor problem anyway.
#
if ! ejabberdctl srg_list "$short_host.$domain" | grep '^Online$' > /dev/null ; then
# ejabberdctl doesn't like spaces in the description field.
# backslashes work - but escaping is better left alone for now :-)
ejabberdctl srg_create Online "$short_host.$domain" \
Online "Created_by_ejabberd_init" Online
[ $? -eq 0 ] || return 1
fi
if ! ejabberdctl srg_get_info Online "$short_host.$domain" | grep '^online_users: true$' > /dev/null ; then
ejabberdctl srg_user_add '@online@' "$short_host.$domain" \
Online "$short_host.$domain"
[ $? -eq 0 ] || return 1
fi
# mark success
touch /var/lib/ejabberd/online_src_created
}
is_running() {
/sbin/runuser -s /bin/bash - ejabberd -c "$progctl status" &>/dev/null
}
start() {
echo -n $"Starting ejabberd: "
#if [ "$ULIMIT_MAX_FILES" ]; then
# ulimit -n $ULIMIT_MAX_FILES
#fi
check_domain_configured
# check whether ejabberd was already started
if is_running; then
echo -n "already running" && warning && echo
return 0
fi
daemon --user=ejabberd $progctl start --config $CONFIG_FILE \
--ctl-config /etc/ejabberd/ejabberdctl-iiab.cfg \
--logs "/var/log/ejabberd" \
--spool "/var/lib/ejabberd/spool" \
2>/dev/null
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ejabberd
echo
# it takes some time to actually start necessary nodes
sleep 5
# Ignore the return val of setup_online_srg
# ==> startup even if the SRG setup had errors.
set +e;
setup_online_srg
return $RETVAL
}
stop() {
# Stop daemons.
echo -n "Shutting down ejabberd: "
# check whether ejabberd was already stopped
if ! is_running; then
echo -n "already stopped" && warning && echo
return 0
fi
daemon $progctl stop 2>/dev/null
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ejabberd
echo
# it takes some time to actually stop necessary nodes
sleep 5
return $RETVAL
}
restart() {
stop
sleep 5
start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|force-reload)
restart
;;
condrestart|try-restart)
[ -f /var/lock/subsys/ejabberd ] && restart || :
;;
status)
$progctl status
;;
*)
echo "Usage: ejabberd {start|stop|restart|force-reload|condrestart|try-restart|status}"
exit 2
esac
exit $RETVAL

View file

@ -0,0 +1,17 @@
[Unit]
Description=A distributed, fault-tolerant Jabber/XMPP server
After=network.target local-fs.target
[Service]
Type=oneshot
User=root
Group=root
LimitNOFILE=50000
RestartSec=5
EnvironmentFile=/etc/sysconfig/ejabberd-iiab
ExecStart=/usr/libexec/ejabberd-iiab start
ExecStop=/usr/libexec/ejabberd-iiab stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,2 @@
d /run/lock/ejabberdctl 0750 ejabberd ejabberd
d /var/run/ejabberd 0750 ejabberd ejabberd

View file

@ -0,0 +1,154 @@
#
# In this file you can configure options that are passed by ejabberdctl
# to the erlang runtime system when starting ejabberd
#
#' POLL: Kernel polling ([true|false])
#
# The kernel polling option requires support in the kernel.
# Additionally, you need to enable this feature while compiling Erlang.
#
# Default: true
#
#POLL=true
#.
#' SMP: SMP support ([enable|auto|disable])
#
# Explanation in Erlang/OTP documentation:
# enable: starts the Erlang runtime system with SMP support enabled.
# This may fail if no runtime system with SMP support is available.
# auto: starts the Erlang runtime system with SMP support enabled if it
# is available and more than one logical processor are detected.
# disable: starts a runtime system without SMP support.
#
# Default: auto
#
#SMP=auto
#.
#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
#
# ejabberd consumes two or three ports for every connection, either
# from a client or from another Jabber server. So take this into
# account when setting this limit.
#
# Default: 32000
# Maximum: 268435456
#
#ERL_MAX_PORTS=32000
#.
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
#
# If Ejabberd is configured to run in cluster, and a firewall is blocking ports,
# it's possible to make Erlang use a defined range of port (instead of dynamic
# ports) for node communication.
#
# Default: not defined
# Example: 4200-4210
#
#FIREWALL_WINDOW=
#.
#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes
#
# This communication is used by ejabberdctl command line tool,
# and in a cluster of several ejabberd nodes.
# Notice that the IP address must be specified in the Erlang syntax.
#
# Default: {127,0,0,1}
#
#INET_DIST_INTERFACE={127,0,0,1}
#.
#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
#
# IMPORTANT: This option works only in Erlang/OTP R14B03 and newer.
#
# This environment variable may be set to a comma-separated
# list of IP addresses, in which case the epmd daemon
# will listen only on the specified address(es) and on the
# loopback address (which is implicitly added to the list if it
# has not been specified). The default behaviour is to listen on
# all available IP addresses.
#
# Default: 0.0.0.0
#
#ERL_EPMD_ADDRESS=127.0.0.1
#.
#' ERL_PROCESSES: Maximum number of Erlang processes
#
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
# on ejabberd so that the maximum number of processes is reached, people will
# experience greater latency times. As these processes are implemented in
# Erlang, and therefore not related to the operating system processes, you do
# not have to worry about allowing a huge number of them.
#
# Default: 250000
# Maximum: 268435456
#
#ERL_PROCESSES=250000
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
#
# The number of concurrent ETS and Mnesia tables is limited. When the limit is
# reached, errors will appear in the logs:
# ** Too many db tables **
# You can safely increase this limit when starting ejabberd. It impacts memory
# consumption but the difference will be quite small.
#
# Default: 1400
#
#ERL_MAX_ETS_TABLES=1400
#.
#' ERL_OPTIONS: Additional Erlang options
#
# The next variable allows to specify additional options passed to erlang while
# starting ejabberd. Some useful options are -noshell, -detached, -heart. When
# ejabberd is started from an init.d script options -noshell and -detached are
# added implicitly. See erl(1) for more info.
#
# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you
# want to add local modules in this path.
#
# Default: ""
#
#ERL_OPTIONS=""
#.
#' ERLANG_NODE: Erlang node name
#
# The next variable allows to explicitly specify erlang node for ejabberd
# It can be given in different formats:
# ERLANG_NODE=ejabberd
# Lets erlang add hostname to the node (ejabberd uses short name in this case)
# ERLANG_NODE=ejabberd@hostname
# Erlang uses node name as is (so make sure that hostname is a real
# machine hostname or you'll not be able to control ejabberd)
# ERLANG_NODE=ejabberd@hostname.domainname
# The same as previous, but erlang will use long hostname
# (see erl (1) manual for details)
#
# Default: ejabberd@localhost
#
#ERLANG_NODE=ejabberd@localhost
#.
#' EJABBERD_PID_PATH: ejabberd PID file
#
# Indicate the full path to the ejabberd Process identifier (PID) file.
# If this variable is defined, ejabberd writes the PID file when starts,
# and deletes it when stops.
# Remember to create the directory and grant write permission to ejabberd.
#
# Default: don't write PID file
#
EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid
#.
#'
# vim: foldmarker=#',#. foldmethod=marker:

View file

@ -0,0 +1,46 @@
#!/bin/bash
progctl=/usr/sbin/ejabberdctl
SYS_DOMAIN_FILE=/etc/sysconfig/iiab_domain_name
OUR_DOMAIN_FILE=/etc/sysconfig/ejabberd_domain_name
setup_online_srg() {
if [ -e /var/lib/ejabberd/online_src_created ]; then
return 0
fi;
# give ejabberd a bit of time to startup on XO-1 HW :-)
sleep 10;
short_host=`hostname -s`
domain=`cat "$SYS_DOMAIN_FILE"`
# Note: grep -q exits as soon as the match is found, which ejabberdctl
# doesn't like. So we send the output to /dev/null instead - more
# portable too.
#
# ejabberdctl should handle SIGPIPE without messing up, but that's
# a minor problem anyway.
#
if ! ejabberdctl srg_list "$short_host.$domain" | grep '^Online$' > /dev/null ; then
# ejabberdctl doesn't like spaces in the description field.
# backslashes work - but escaping is better left alone for now :-)
ejabberdctl srg_create Online "$short_host.$domain" \
Online "Created_by_ejabberd_init" Online
[ $? -eq 0 ] || return 1
fi
if ! ejabberdctl srg_get_info Online "$short_host.$domain" | grep '^online_users: true$' > /dev/null ; then
ejabberdctl srg_user_add '@online@' "$short_host.$domain" \
Online "$short_host.$domain"
[ $? -eq 0 ] || return 1
fi
# mark success
touch /var/lib/ejabberd/online_src_created
}
setup_online_srg

View file

@ -0,0 +1,84 @@
- name: Install ejabberd packages
package: name={{ item }}
state=present
with_items:
- ejabberd-2.1.11
#tags: download
when: not is_debuntu
# need to use lineinfile and better regexp
- name: Disable updating ejabberd on CentOS
shell: sed -i -e '/^enabled=/a exclude=ejabberd' {{ item }}
with_items:
- /etc/yum.repos.d/CentOS-Base.repo
- /etc/yum.repos.d/CentOS-CR.repo
- /etc/yum.repos.d/CentOS-fasttrack.repo
- /etc/yum.repos.d/CentOS-Vault.repo
when: ejabberd_xs_install and is_centos
- name: Disable updating ejabberd on Fedora
shell: sed -i -e '/^enabled=/a exclude=ejabberd' {{ item }}
with_items:
- /etc/yum.repos.d/fedora.repo
- /etc/yum.repos.d/fedora-updates.repo
- /etc/yum.repos.d/fedora-updates-testing.repo
when: ejabberd_xs_install and ansible_distribution == "Fedora"
- name: Configure ejabberd
template: backup=yes
src={{ item.src }}
dest={{ item.dest }}
owner=root
group=root
mode={{ item.mode }}
with_items:
- { src: 'ejabberd-xs.cfg.j2', dest: '/etc/ejabberd/ejabberd-xs.cfg' , mode: '0644' }
- { src: 'ejabberdctl.cfg.j2', dest: '/etc/ejabberd/ejabberdctl-xs.cfg', mode: '0644' }
- { src: 'ejabberd-xs', dest: '/etc/sysconfig/ejabberd-xs', mode: '0755' }
# - { src: 'ejabberd-domain-config', dest: '/etc/sysconfig/olpc-scripts/domain_config.d/ejabberd', mode: '0755'}
# - { src: 'ejabberd', dest: '/etc/sysconfig/olpc-scripts/domain_config.d/ejabberd' , mode: '0755' }
- { src: 'ejabberd-xs.service.j2', dest: '/etc/systemd/system/ejabberd-xs.service', mode: '0755' }
- { src: 'xs-ejabberd-srg', dest: '/usr/bin/xs-ejabberd-srg' , mode: '0755' }
- { src: '10-ejabberdmoodle', dest: '/etc/sudoers.d/10-ejabberdmoodle', mode: '0440' }
- { src: 'ejabberd.tmpfiles', dest: '/etc/tmpfiles.d/ejabberd.conf', mode: '0640' }
register: ejabberd_config
when: not is_debuntu
- name: Put the startup script in place - non debian
template: src='ejabberd-xs.init'
dest='/usr/libexec/ejabberd-xs'
when: not is_debuntu
- name: Remove ejabberd_domain if domain changes
file: path=/etc/sysconfig/ejabberd_domain_name
state=absent
when: ejabberd_config.changed and ejabberd_config is defined and not is_debuntu
- name: Enable ejabberd service
file: src=/etc/systemd/system/ejabberd-xs.service
dest=/etc/systemd/system/multi-user.target.wants/ejabberd-xs.service
owner=root
group=root
state=link
when: not is_debuntu and ejabberd_xs_enabled
- name: Start ejabberd service
service: name=ejabberd-xs
state=restarted
enabled=yes
when: ejabberd_config.changed and ejabberd_xs_enabled and not is_debuntu
- name: Wait for ejabberd service start
wait_for: port=5280
delay=15
state=started
timeout=300
when: ejabberd_config.changed and ejabberd_xs_enabled
#- name: Create online group
# shell: ejabberdctl srg_create Online "schoolserver" Online "Online_Users" Online
# when: ejabberd_config.changed and not is_debuntu and ejabberd_xs_enabled
#- name: Add all users to online group
# shell: ejabberdctl srg_user_add '@online@' "schoolserver" Online "schoolserver"
# when: ejabberd_config.changed and not is_debuntu and ejabberd_xs_enabled

View file

@ -0,0 +1,12 @@
##
## 10-ejabberdmoodle
## for ejabberd-moodle interaction
##
# allow the apache user to invoke ejabberdctl and start/stop/condrestart
Defaults:apache !requiretty
Cmnd_Alias EJABBERDCTL = /usr/sbin/ejabberdctl
Cmnd_Alias EJABBERDINIT = /etc/init.d/ejabberd start , /etc/init.d/ejabberd stop , /etc/init.d/ejabberd condrestart
apache ALL = (ejabberd) NOPASSWD: EJABBERDCTL
apache ALL = (root) NOPASSWD: EJABBERDINIT

View file

@ -0,0 +1,62 @@
#!/bin/sh -e
#
# ejabberd now handles domain changes in the initrd script
#
SERVICE_NAME=ejabberd-xs
CONFIG_LIST="/etc/ejabberd/ejabberd-xs.cfg"
# taken from ejabberd spec %post
# taken from ejabberd spec %post
#function do-cert(){
# (cd /etc/ejabberd
# if [ ! -f ejabberd.pem ]
# then
# echo "Generating SSL certificate /etc/ejabberd/ejabberd.pem..."
# HOSTNAME=$(hostname -s)
# DOMAINNAME=$(hostname -d)
# openssl req -new -x509 -days 36500 -nodes -out ejabberd.pem -keyout ejabberd.pem > /dev/null 2>&1 << +++
# .
# .
# .
# $DOMAINNAME
# $HOSTNAME
# ejabberd
# root@$HOSTNAME.$DOMAINNAME
# +++
# chown ejabberd:ejabberd ejabberd.pem
# chmod 600 ejabberd.pem
# fi)
#}
# This is the suffix which original versions of modified files will have
BACKUP_SUFFIX=old
short_host=`hostname -s`
new_name=$short_host.$1
for config in $CONFIG_LIST;
do
if [ -e $config.in ]; then
if [ -e $config ]; then
mv $config $config.$BACKUP_SUFFIX
fi
sed -e s/{{ iiab_hostname }}/$new_name/ $config.in > $config ;
else
echo WARNING: Skipped $config - template file is missing!
fi
done
#if [ -e /etc/ejabberd/ejabberd.pem.$1 ]; then
# rm /etc/ejabberd/ejabberd.pem.$1
#fi
#mv /etc/ejabberd/ejabberd.pem /etc/ejabberd/ejabberd.pem.$1
#do-cert
# Since for the community edition, we don't really expect all modules to be present
# Just exit, and expect the user to do a restart
exit 0

View file

@ -0,0 +1,13 @@
## Settings for ejabberd
## Where should ejabberd find its configuration file?
#
CONFIG_FILE=/etc/ejabberd/ejabberd-xs.cfg
## ULIMIT_MAX_FILES alters the number of files that ejabberd is
## allowed to have open at once. If it is unset the system default
## (usually 1024) will be used. ejabberd will want over twice as many
## open files as it has active connections, so if you have a few
## hundred or more users you will want to set this.
#
ULIMIT_MAX_FILES=40000

View file

@ -0,0 +1,454 @@
%%%
%%% ejabberd configuration file
%%%
%%% The parameters used in this configuration file are explained in more detail
%%% in the ejabberd Installation and Operation Guide.
%%% Please consult the Guide in case of doubts, it is included in
%%% your copy of ejabberd, and is also available online at
%%% http://www.process-one.net/en/ejabberd/docs/
%%% This configuration file contains Erlang terms.
%%% In case you want to understand the syntax, here are the concepts:
%%%
%%% - The character to comment a line is %
%%%
%%% - Each term ends in a dot, for example:
%%% override_global.
%%%
%%% - A tuple has a fixed definition, its elements are
%%% enclosed in {}, and separated with commas:
%%% {loglevel, 4}.
%%%
%%% - A list can have as many elements as you want,
%%% and is enclosed in [], for example:
%%% [http_poll, web_admin, tls]
%%%
%%% - A keyword of ejabberd is a word in lowercase.
%%% The strings are enclosed in "" and can have spaces, dots...
%%% {language, "en"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%%
%%% - This term includes a tuple, a keyword, a list and two strings:
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
%%%
%%% =======================
%%% OVERRIDE STORED OPTIONS
%%
%% Override the old values stored in the database.
%%
%%
%% Override global options (shared by all ejabberd nodes in a cluster).
%%
override_global.
%%
%% Override local options (specific for this particular ejabberd node).
%%
override_local.
%%
%% Remove the Access Control Lists before new ones are added.
%%
override_acls.
%%% =========
%%% DEBUGGING
%%
%% loglevel: Verbosity of log files generated by ejabberd.
%% 0: No ejabberd log at all (not recommended)
%% 1: Critical
%% 2: Error
%% 3: Warning
%% 4: Info
%% 5: Debug
%%
{loglevel, 4}.
%%
%% watchdog_admins: If an ejabberd process consumes too much memory,
%% send live notifications to those Jabber accounts.
%%
%%{watchdog_admins, ["bob@example.com"]}.
%%% ================
%%% SERVED HOSTNAMES
%%
%% hosts: Domains served by ejabberd.
%% You can define one or several, for example:
%% {hosts, ["example.net", "example.com", "example.org"]}.
%%
{hosts, ["{{ iiab_hostname }}.{{ iiab_domain }}"]}.
%%
%% route_subdomains: Delegate subdomains to other Jabber server.
%% For example, if this ejabberd serves example.org and you want
%% to allow communication with a Jabber server called im.example.org.
%%
%%{route_subdomains, s2s}.
%%% ===============
%%% LISTENING PORTS
%%
%% listen: Which ports will ejabberd listen, which service handles it
%% and what options to start it with.
%%
{listen,
[
{5222, ejabberd_c2s, [
%%
%% If TLS is compiled and you installed a SSL
%% certificate, put the correct path to the
%% file and uncomment this line:
%%
%%{certfile, "/path/t/etc/ejabberd/ejabberd.pem"}, starttls,
inet6,
{access, c2s},
{shaper, c2s_shaper},
{max_stanza_size, 524288}
]}
%%
%% To enable the old SSL connection method in port 5223:
%%
, {5223, ejabberd_c2s, [
inet6,
{access, c2s},
{shaper, c2s_shaper},
tls, {certfile, "/etc/ejabberd/ejabberd.pem"},
{max_stanza_size, 524288}
]}
%% , {5269, ejabberd_s2s_in, [
%% {shaper, s2s_shaper},
%% {max_stanza_size, 131072}
%% ]},
%%
%% ejabberd_service: Interact with external components (transports...)
%%
%% , {8888, ejabberd_service, [
%% {access, all},
%% {shaper_rule, fast},
%% {ip, {127, 0, 0, 1}},
%% {hosts, ["icq.example.org", "sms.example.org"],
%% [{password, "secret"}]
%% }
%% ]}
, {5280, ejabberd_http, [
inet6,
http_poll,
web_admin
]}
]}.
%%
%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
%% Allowed values are: true or false.
%% You must specify a certificate file.
%%
%%{s2s_use_starttls, true}.
%%
%% s2s_certfile: Specify a certificate file.
%%
%%{s2s_certfile, "/path/t/etc/ejabberd/ejabberd.pem"}.
%%
%% domain_certfile: Specify a different certificate for each served hostname.
%%
%%{domain_certfile, "example.org", "/path/to/example_org.pem"}.
%%{domain_certfile, "example.com", "/path/to/example_com.pem"}.
%%
%% S2S whitelist or blacklist
%%
%% Default s2s policy for undefined hosts.
%%
{s2s_default_policy, deny}.
%%
%% Allow or deny communication with specific servers.
%%
%%{{ '{{' }}s2s_host, "goodhost.org"}, allow}.
%%{{ '{{' }}s2s_host, "badhost.org"}, deny}.
%%% ==============
%%% AUTHENTICATION
%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal.
%% If you want to use a different method,
%% comment this line and enable the correct ones.
%%
{auth_method, internal}.
%%
%% Authentication using external script
%% Make sure the script is executable by ejabberd.
%%
%%{auth_method, external}.
%%{extauth_program, "/path/to/authentication/script"}.
%%
%% Authentication using ODBC
%% Remember to setup a database in the next section.
%%
%%{auth_method, odbc}.
%%
%% Authentication using PAM
%%
%%{auth_method, pam}.
%%{pam_service, "pamservicename"}.
%%
%% Authentication using LDAP
%%
%%{auth_method, ldap}.
%%
%% List of LDAP servers:
%%{ldap_servers, ["localhost"]}.
%%
%% LDAP attribute that holds user ID:
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
%%
%% Search base of LDAP directory:
%%{ldap_base, "dc=example,dc=com"}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password to LDAP manager:
%%{ldap_password, "******"}.
%%
%% Anonymous login support:
%% auth_method: anonymous
%% anonymous_protocol: sasl_anon | login_anon | both
%% allow_multiple_connections: true | false
%%
%%{host_config, "public.example.org", [{auth_method, anonymous},
%% {allow_multiple_connections, false},
%% {anonymous_protocol, sasl_anon}]}.
%%
%% To use both anonymous and internal authentication:
%%
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
%%% ==============
%%% DATABASE SETUP
%% ejabberd uses by default the internal Mnesia database,
%% so you can avoid this section.
%% This section provides configuration examples in case
%% you want to use other database backends.
%% Please consult the ejabberd Guide for details about database creation.
%%
%% MySQL server:
%%
%%{odbc_server, {mysql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}.
%%
%% PostgreSQL server:
%%
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}.
%%
%% If you use PostgreSQL, have a large database, and need a
%% faster but inexact replacement for "select count(*) from users"
%%
%%{pgsql_users_number_estimate, true}.
%%
%% ODBC compatible or MSSQL server:
%%
%%{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
%%% ===============
%%% TRAFFIC SHAPERS
%%
%% The "normal" shaper limits traffic speed to 1.000 B/s
%%
{shaper, normal, {maxrate, 1000}}.
%%
%% The "fast" shaper limits traffic speed to 50.000 B/s
%%
{shaper, fast, {maxrate, 50000}}.
%%% ====================
%%% ACCESS CONTROL LISTS
%%
%% The 'admin' ACL grants administrative privileges to Jabber accounts.
%% You can put as many accounts as you want.
%%
%%{acl, admin, {user, "aleksey", "localhost"}}.
%%{acl, admin, {user, "ermine", "example.org"}}.
{acl, admin, {user, "admin", "{{ iiab_hostname }}.{{ iiab_domain }}"}}.
%%
%% Blocked users
%%
%%{acl, blocked, {user, "baduser", "example.org"}}.
%%{acl, blocked, {user, "test"}}.
%%
%% Local users: dont modify this line.
%%
{acl, local, {user_regexp, ""}}.
%%
%% More examples of ACLs
%%
%%{acl, jabberorg, {server, "jabber.org"}}.
%%{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
%%{acl, test, {user_regexp, "^test"}}.
%%{acl, test, {user_glob, "test*"}}.
%%% ============
%%% ACCESS RULES
%% Define the maximum number of time a single user is allowed to connect:
{access, max_user_sessions, [{10, all}]}.
%% This rule allows access only for local users:
{access, local, [{allow, local}]}.
%% Only non-blocked users can use c2s connections:
{access, c2s, [{deny, blocked},
{allow, all}]}.
%% For all users except admins used "normal" shaper
{access, c2s_shaper, [{none, admin},
{fast, all}]}.
%% For all S2S connections used "fast" shaper
{access, s2s_shaper, [{fast, all}]}.
%% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
%% Only admins can use configuration interface:
{access, configure, [{allow, admin}]}.
%% Admins of this server are also admins of MUC service:
{access, muc_admin, [{allow, admin}]}.
%% All users are allowed to use MUC service:
{access, muc, [{allow, all}]}.
%% Every username can be registered via in-band registration:
%% To disable in-band registration, replace 'allow' with 'deny'.
{access, register, [{allow, all}]}.
%% Allow repeat registration from the same client (necessary for testing)
%% Set to a positive integer (or comment out) to restrict with a timeout.
%% (infinity means zero; 0 does not work)
% {registration_timeout, infinity}.
%% Everybody can create pubsub nodes
{access, pubsub_createnode, [{allow, all}]}.
%%% ================
%%% DEFAULT LANGUAGE
%%
%% language: Default language used for server messages.
%%
{language, "en"}.
%%% =======
%%% MODULES
%%
%% Modules enabled in all ejabberd virtual hosts.
%%
{modules,
[
{mod_adhoc, []},
{mod_announce, [{access, announce}]}, % requires mod_adhoc
{mod_caps, []},
{mod_configure,[]}, % requires mod_adhoc
{mod_admin_extra, []},
{mod_disco, []},
%%{mod_echo, [{host, "echo.localhost"}]},
{mod_irc, []},
{mod_last, []},
{mod_muc, [
{host, "conference.@HOST@"},
{access, muc},
{access_create, muc},
{access_persistent, muc},
{access_admin, muc_admin}
]},
%%{mod_muc_log,[]},
{mod_offline, []},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
{mod_pubsub, [{access_createnode, pubsub_createnode},
{plugins, ["default", "pep"]}
]},
{mod_register, [
%%
%% After successful registration, the user receives
%% a message with this subject and body.
%%
%%{welcome_message, {"Welcome!",
%% "Welcome to this Jabber server."}},
%%
%% When a user registers, send a notification to
%% these Jabber accounts.
%%
%%{registration_watchers, ["admin1@example.org"]},
{access, register}
]},
{mod_roster, []},
%%{mod_service_log,[]},
{mod_shared_roster,[]},
{mod_stats, []},
{mod_time, []},
{mod_vcard, []},
{mod_version, []}
]}.
%%% $Id: ejabberd.cfg.example 988 2007-11-26 21:29:14Z badlop $
%%% Local Variables:
%%% mode: erlang
%%% End:
%%% vim: set filetype=erlang tabstop=8:

View file

@ -0,0 +1,222 @@
#!/bin/bash
#
# ejabberd Start and stop ejabberd.
# chkconfig: - 40 60
# description: ejabberd
# processname: ejabberd
# pidfile: /var/run/ejabberd/ejabberd.pid
### BEGIN INIT INFO
# Provides: ejabberd
# Required-Start: network
# Required-Stop: network
# Default-Start:
# Default-Stop: 0 1 6
# Short-Description: Start and stop ejabberd
# Description: A distributed, fault-tolerant Jabber/XMPP server
### END INIT INFO
SYS_DOMAIN_FILE=/etc/sysconfig/iiab_domain_name
OUR_DOMAIN_FILE=/etc/sysconfig/ejabberd_domain_name
. /etc/rc.d/init.d/functions
if [ -r /etc/sysconfig/ejabberd-xs ]; then
. /etc/sysconfig/ejabberd-xs
fi
if [ ! "$CONFIG_FILE" ]; then
CONFIG_FILE=/etc/ejabberd/ejabberd-xs.cfg
fi
# /var/run is tmpfs in fc18, so need to create every time
mkdir -p /var/run/ejabberd
chown ejabberd:ejabberd /var/run/ejabberd
# avoid using consolehelper, call ejabberdctl directly
progctl=/usr/sbin/ejabberdctl
check_domain_configured() {
if [ ! -e $SYS_DOMAIN_FILE ]; then
echo "Domain not configured yet 1" > /dev/stderr
exit 1;
fi
domain=`cat "$SYS_DOMAIN_FILE" `
if [ "$domain" == "random.xs.laptop.org" ]; then
echo "Domain not configured yet 2" > /dev/stderr
exit 1;
fi
#hostname=`hostname -f`
hostname=`hostname `
if [ "$hostname" == "localhost.localdomain" ]; then
echo "Domain not configured yet 3" > /dev/stderr
fi
# if [ "$hostname" != "schoolserver.$domain" ]; then
# echo "Domain changed -- restart to enable ejabberd" > /dev/stderr
# fi
short_host=`hostname -s`
node_name=`cat $OUR_DOMAIN_FILE`
# if [ ! -e "$OUR_DOMAIN_FILE" ] || ! cmp "$SYS_DOMAIN_FILE" "$OUR_DOMAIN_FILE" ; then
if [ ! -e "$OUR_DOMAIN_FILE" ] ; then
update_domain
fi
}
update_domain() {
BACKUP_SUFFIX=old
if [ -e $CONFIG_FILE ]; then
cp $CONFIG_FILE $CONFIG_FILE.$BACKUP_SUFFIX || exit 1
fi
new_name=$short_host.$domain
#(sed -e s/@@BASEDNSNAME2@@/$new_name/ $CONFIG_FILE.in > $CONFIG_FILE.tmp ) && mv $CONFIG_FILE.tmp $CONFIG_FILE || exit 1
# If we are changing the domain, we must clear the DB.
if [ -e /var/lib/ejabberd/online_src_created ] ; then
rm -f /var/lib/ejabberd/online_src_created
fi
if [ -d /var/lib/ejabberd/spool/ ]; then
rm -f /var/lib/ejabberd/spool/*
fi
# Mark as done -
# cp "$SYS_DOMAIN_FILE" "$OUR_DOMAIN_FILE"
echo "$domain" > "$OUR_DOMAIN_FILE"
}
setup_online_srg() {
if [ -e /var/lib/ejabberd/online_src_created ]; then
return 0
fi;
# give ejabberd a bit of time to startup on XO-1 HW :-)
sleep 10;
short_host=`hostname -s`
domain=`cat "$SYS_DOMAIN_FILE"`
# Note: grep -q exits as soon as the match is found, which ejabberdctl
# doesn't like. So we send the output to /dev/null instead - more
# portable too.
#
# ejabberdctl should handle SIGPIPE without messing up, but that's
# a minor problem anyway.
#
if ! ejabberdctl srg_list "$short_host.$domain" | grep '^Online$' > /dev/null ; then
# ejabberdctl doesn't like spaces in the description field.
# backslashes work - but escaping is better left alone for now :-)
ejabberdctl srg_create Online "$short_host.$domain" \
Online "Created_by_ejabberd_init" Online
[ $? -eq 0 ] || return 1
fi
if ! ejabberdctl srg_get_info Online "$short_host.$domain" | grep '^online_users: true$' > /dev/null ; then
ejabberdctl srg_user_add '@online@' "$short_host.$domain" \
Online "$short_host.$domain"
[ $? -eq 0 ] || return 1
fi
# mark success
touch /var/lib/ejabberd/online_src_created
}
is_running() {
/sbin/runuser -s /bin/bash - ejabberd -c "$progctl status" &>/dev/null
}
start() {
echo -n $"Starting ejabberd: "
#if [ "$ULIMIT_MAX_FILES" ]; then
# ulimit -n $ULIMIT_MAX_FILES
#fi
check_domain_configured
# check whether ejabberd was already started
if is_running; then
echo -n "already running" && warning && echo
return 0
fi
daemon --user=ejabberd $progctl start --config $CONFIG_FILE \
--ctl-config /etc/ejabberd/ejabberdctl-xs.cfg \
--logs "/var/log/ejabberd" \
--spool "/var/lib/ejabberd/spool" \
2>/dev/null
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ejabberd
echo
# it takes some time to actually start necessary nodes
sleep 5
# Ignore the return val of setup_online_srg
# ==> startup even if the SRG setup had errors.
set +e;
setup_online_srg
return $RETVAL
}
stop() {
# Stop daemons.
echo -n "Shutting down ejabberd: "
# check whether ejabberd was already stopped
if ! is_running; then
echo -n "already stopped" && warning && echo
return 0
fi
daemon $progctl stop 2>/dev/null
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ejabberd
echo
# it takes some time to actually stop necessary nodes
sleep 5
return $RETVAL
}
restart() {
stop
sleep 5
start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart|force-reload)
restart
;;
condrestart|try-restart)
[ -f /var/lock/subsys/ejabberd ] && restart || :
;;
status)
$progctl status
;;
*)
echo "Usage: ejabberd {start|stop|restart|force-reload|condrestart|try-restart|status}"
exit 2
esac
exit $RETVAL

View file

@ -0,0 +1,17 @@
[Unit]
Description=A distributed, fault-tolerant Jabber/XMPP server
After=network.target local-fs.target
[Service]
Type=oneshot
User=root
Group=root
LimitNOFILE=50000
RestartSec=5
EnvironmentFile=/etc/sysconfig/ejabberd-xs
ExecStart=/usr/libexec/ejabberd-xs start
ExecStop=/usr/libexec/ejabberd-xs stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,2 @@
d /run/lock/ejabberdctl 0750 ejabberd ejabberd
d /var/run/ejabberd 0750 ejabberd ejabberd

View file

@ -0,0 +1,154 @@
#
# In this file you can configure options that are passed by ejabberdctl
# to the erlang runtime system when starting ejabberd
#
#' POLL: Kernel polling ([true|false])
#
# The kernel polling option requires support in the kernel.
# Additionally, you need to enable this feature while compiling Erlang.
#
# Default: true
#
#POLL=true
#.
#' SMP: SMP support ([enable|auto|disable])
#
# Explanation in Erlang/OTP documentation:
# enable: starts the Erlang runtime system with SMP support enabled.
# This may fail if no runtime system with SMP support is available.
# auto: starts the Erlang runtime system with SMP support enabled if it
# is available and more than one logical processor are detected.
# disable: starts a runtime system without SMP support.
#
# Default: auto
#
#SMP=auto
#.
#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
#
# ejabberd consumes two or three ports for every connection, either
# from a client or from another Jabber server. So take this into
# account when setting this limit.
#
# Default: 32000
# Maximum: 268435456
#
#ERL_MAX_PORTS=32000
#.
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
#
# If Ejabberd is configured to run in cluster, and a firewall is blocking ports,
# it's possible to make Erlang use a defined range of port (instead of dynamic
# ports) for node communication.
#
# Default: not defined
# Example: 4200-4210
#
#FIREWALL_WINDOW=
#.
#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes
#
# This communication is used by ejabberdctl command line tool,
# and in a cluster of several ejabberd nodes.
# Notice that the IP address must be specified in the Erlang syntax.
#
# Default: {127,0,0,1}
#
#INET_DIST_INTERFACE={127,0,0,1}
#.
#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
#
# IMPORTANT: This option works only in Erlang/OTP R14B03 and newer.
#
# This environment variable may be set to a comma-separated
# list of IP addresses, in which case the epmd daemon
# will listen only on the specified address(es) and on the
# loopback address (which is implicitly added to the list if it
# has not been specified). The default behaviour is to listen on
# all available IP addresses.
#
# Default: 0.0.0.0
#
#ERL_EPMD_ADDRESS=127.0.0.1
#.
#' ERL_PROCESSES: Maximum number of Erlang processes
#
# Erlang consumes a lot of lightweight processes. If there is a lot of activity
# on ejabberd so that the maximum number of processes is reached, people will
# experience greater latency times. As these processes are implemented in
# Erlang, and therefore not related to the operating system processes, you do
# not have to worry about allowing a huge number of them.
#
# Default: 250000
# Maximum: 268435456
#
#ERL_PROCESSES=250000
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
#
# The number of concurrent ETS and Mnesia tables is limited. When the limit is
# reached, errors will appear in the logs:
# ** Too many db tables **
# You can safely increase this limit when starting ejabberd. It impacts memory
# consumption but the difference will be quite small.
#
# Default: 1400
#
#ERL_MAX_ETS_TABLES=1400
#.
#' ERL_OPTIONS: Additional Erlang options
#
# The next variable allows to specify additional options passed to erlang while
# starting ejabberd. Some useful options are -noshell, -detached, -heart. When
# ejabberd is started from an init.d script options -noshell and -detached are
# added implicitly. See erl(1) for more info.
#
# It might be useful to add "-pa /usr/local/lib/ejabberd/ebin" if you
# want to add local modules in this path.
#
# Default: ""
#
#ERL_OPTIONS=""
#.
#' ERLANG_NODE: Erlang node name
#
# The next variable allows to explicitly specify erlang node for ejabberd
# It can be given in different formats:
# ERLANG_NODE=ejabberd
# Lets erlang add hostname to the node (ejabberd uses short name in this case)
# ERLANG_NODE=ejabberd@hostname
# Erlang uses node name as is (so make sure that hostname is a real
# machine hostname or you'll not be able to control ejabberd)
# ERLANG_NODE=ejabberd@hostname.domainname
# The same as previous, but erlang will use long hostname
# (see erl (1) manual for details)
#
# Default: ejabberd@localhost
#
#ERLANG_NODE=ejabberd@localhost
#.
#' EJABBERD_PID_PATH: ejabberd PID file
#
# Indicate the full path to the ejabberd Process identifier (PID) file.
# If this variable is defined, ejabberd writes the PID file when starts,
# and deletes it when stops.
# Remember to create the directory and grant write permission to ejabberd.
#
# Default: don't write PID file
#
EJABBERD_PID_PATH=/var/run/ejabberd/ejabberd.pid
#.
#'
# vim: foldmarker=#',#. foldmethod=marker:

View file

@ -0,0 +1,46 @@
#!/bin/bash
progctl=/usr/sbin/ejabberdctl
SYS_DOMAIN_FILE=/etc/sysconfig/xs_domain_name
OUR_DOMAIN_FILE=/etc/sysconfig/ejabberd_domain_name
setup_online_srg() {
if [ -e /var/lib/ejabberd/online_src_created ]; then
return 0
fi;
# give ejabberd a bit of time to startup on XO-1 HW :-)
sleep 10;
short_host=`hostname -s`
domain=`cat "$SYS_DOMAIN_FILE"`
# Note: grep -q exits as soon as the match is found, which ejabberdctl
# doesn't like. So we send the output to /dev/null instead - more
# portable too.
#
# ejabberdctl should handle SIGPIPE without messing up, but that's
# a minor problem anyway.
#
if ! ejabberdctl srg_list "$short_host.$domain" | grep '^Online$' > /dev/null ; then
# ejabberdctl doesn't like spaces in the description field.
# backslashes work - but escaping is better left alone for now :-)
ejabberdctl srg_create Online "$short_host.$domain" \
Online "Created_by_ejabberd_init" Online
[ $? -eq 0 ] || return 1
fi
if ! ejabberdctl srg_get_info Online "$short_host.$domain" | grep '^online_users: true$' > /dev/null ; then
ejabberdctl srg_user_add '@online@' "$short_host.$domain" \
Online "$short_host.$domain"
[ $? -eq 0 ] || return 1
fi
# mark success
touch /var/lib/ejabberd/online_src_created
}
setup_online_srg

View file

@ -0,0 +1,93 @@
- name: Install idmgr packages
package: name={{ item }}
state=present
with_items:
- ds-backup-server
- idmgr
- xinetd
- xs-rsync
- incron
#tags: download
- name: Configure idmgr
template: backup=yes
src={{ item.src }}
dest={{ item.dest }}
owner=root
group=root
mode={{ item.mode }}
with_items:
- { src: 'idmgr', dest: '/etc/idmgr.conf', mode: '0644' }
- { src: 'idmgr.service.j2', dest: '/etc/systemd/system/idmgr.service', mode: '0644'}
- name: Configure ds-backup
command: /etc/sysconfig/olpc-scripts/setup.d/ds-backup
creates=/etc/incron.d/ds-backup.conf
- name: Configure idmgr sqlite db
command: /etc/sysconfig/olpc-scripts/setup.d/idmgr
creates=/home/idmgr/identity.db
- name: Configure xs-rsync
command: /etc/sysconfig/olpc-scripts/setup.d/xs-rsync
creates=/etc/xinetd.d/xs-rsyncd
- name: Copy idmgr init script
command: /bin/cp /etc/init.d/idmgr /usr/libexec/idmgr.init
creates=/usr/libexec/idmgr.init
- name: Enable idmgr service
service: name={{ item }}
enabled=yes
state=started
with_items:
- idmgr
- xinetd
when: xo_services_enabled | bool
- name: Disable idmgr service
service: name={{ item }}
enabled=no
state=stopped
with_items:
- idmgr
- xinetd
when: not xo_services_enabled
#idmgr needs an extra step
- name: Enable ejabberd service
file: src=/etc/systemd/system/idmgr.service
dest=/etc/systemd/system/multi-user.target.wants/idmgr.service
owner=root
group=root
state=link
- name: Configure rssh rsync permissions to allow OLPC Backup clients
lineinfile: backup=yes
dest=/etc/rssh.conf
state=present
regexp='^#allowrsync'
insertafter='^#allowrsync'
line=allowrsync
- name: Configure rssh sftp permissions for backup restore clients
lineinfile: backup=yes
dest=/etc/rssh.conf
state=present
regexp='^#allowsftp'
insertafter='^#allowsftp'
line=allowsftp
- name: Add 'idmgr' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: idmgr
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: idmgr
- option: description
value: '"IdMgr is an automatic identity manager for XO clients which enables automatic backup"'
- option: enabled
value: "{{ xo_services_enabled }}"

View file

@ -0,0 +1,5 @@
# This is a configuration file for the OLPC idmgr
# See http://wiki.laptop.org/go/School_Identity_Manager
BACKUP={{ iiab_hostname }}.{{ iiab_domain }}
PRESENCE={{ iiab_hostname }}.{{ iiab_domain }}
BIND_ADDRESS=0.0.0.0

View file

@ -0,0 +1,12 @@
[Unit]
Description=Provides the OLPC laptop identity service
After=syslog.target network.target local-fs.target
[Service]
Type=forking
PIDFile=/var/run/idmgr.pid
ExecStart=/usr/libexec/idmgr.init start
ExecStop=/usr/libexec/idmgr.init stop
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,3 @@
---
dependencies:
- { role: postgresql }

View file

@ -0,0 +1,94 @@
---
- name: Install moodle required packages
package: name={{ item }}
state=present
with_items:
- moodle-xs
- python-psycopg2
tags:
- download
- name: Remove stock moodle conf
file: path='/etc/{{ apache_config_dir }}/moodle.conf'
state=absent
- name: Configure moodle
template: backup=yes
src={{ item.src }}
dest={{ item.dest }}
owner=root
group=root
mode={{ item.mode }}
with_items:
- src: '020-iiab-moodle.conf.j2'
dest: '/etc/{{ apache_config_dir }}/020-iiab-moodle.conf'
mode: '0655'
- src: 'moodle-xs.service.j2'
dest: '/etc/systemd/system/moodle-xs.service'
mode: '0655'
- src: 'moodle-xs-init'
dest: '/usr/libexec/moodle-xs-init'
mode: '0755'
- name: Stop postgresql
service: name=postgresql
state=stopped
- name: Start postgresql-iiab
service: name=postgresql-iiab
state=started
- name: Create db user
postgresql_user: name=apache
password=apache
role_attr_flags=NOSUPERUSER,NOCREATEROLE,NOCREATEDB
state=present
become: yes
become_user: postgres
- name: Create database
postgresql_db: name=moodle-xs
encoding=utf8
owner=apache
template=template0
state=present
sudo: yes
sudo_user: postgres
- name: Execute moodle startup script
command: /usr/libexec/moodle-xs-init start
- name: Restart postgresql-iiab
service: name=postgresql-iiab
state=restarted
- name: Restart httpd
service: name={{ apache_service }}
state=restarted
- name: Enable moodle service
service: name=moodle-xs
enabled=yes
state=started
- name: fetch the administrative password for moodle
shell: cat /etc/moodle/adminpw
register: moodlepw
- name: Add 'moodle' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: moodle
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: Moodle
- option: description
value: '"Access the Moodle learning management system."'
- option: path
value: /moodle
- option: enabled
value: "{{ moodle_enabled }}"
- option: adminpw
value: "{{ moodlepw.stdout }}"

View file

@ -0,0 +1,12 @@
# replaces stock moodle.conf installed by moodle-xs.rpm
Alias /moodle /var/www/moodle/web
# Moodle public web pages - must be publically accessible
<Directory /var/www/moodle/web>
Require all granted
</Directory>
# Moodle private data - must NOT be publically accessible
<Directory /var/www/moodle/data>
Require all denied
</Directory>

View file

@ -0,0 +1,12 @@
# replaces stock moodle.conf installed by moodle-xs.rpm
Alias /moodle /var/www/moodle/web
# Moodle public web pages - must be publically accessible
<Directory /var/www/moodle/web>
Require all granted
</Directory>
# Moodle private data - must NOT be publically accessible
<Directory /var/www/moodle/data>
Require all denied
</Directory>

View file

@ -0,0 +1,97 @@
#!/bin/bash
#
# moodle This shell script is modified from sysVinit init.d moodle
# --checks for moodle upgrade flag and enables the cron
# job for Moodle
#
# Author: Ignacio Vazquez-Abrams <ivazquez@ivazquez.net>
# Adapted from the yum initscript by Seth Vidal
# Adapted for systemd by George Hunt <georgejhunt@gmail.com>
#
# description: Enable the Moodle cron job
#
# source function library
. /etc/rc.d/init.d/functions
# both moodle cron and config.php check
# for this file -
lockfile=/var/lock/subsys/moodle
RETVAL=0
start() {
if [ -e /etc/moodle/needsupgrade ]; then
echo "Moodle installation or upgrade required..."
pushd /var/www/moodle/web
echo "["`date`"]" Start install / upgrade >> /var/log/moodle-instupg.log
# Correct a bungled 'version' variable in mdl_config. If version matches local_version, and
# is one of the known-to-be-bungled local_version/version pairs, fix it to the last-known-good
# value.
echo "Correcting version/local_version mangling - will error out on fresh DBs" >> /var/log/moodle-instupg.log
(su -c "psql -c \"UPDATE mdl_config
SET value='2007101526'
WHERE id=(SELECT v.id
FROM mdl_config v
JOIN mdl_config lv
ON (v.name='version' AND lv.name='local_version'
AND v.value=lv.value)
WHERE lv.value IN ('2009030301', '2009042801',
'2009051800', '2009052500'));\" moodle-xs " postgres 2>&1 ) >> /var/log/moodle-instupg.log
# Before install/upgrade, enable the admin user
# (will DTRT for upgrades, fail silently in fresh installs)
( runuser -s /bin/bash -c "/usr/bin/php /var/www/moodle/web/local/scripts/adminuser-enable.php" apache 2>&1 ) >> /var/log/moodle-instupg.log
# Install/upgrade moodle DB schema
( runuser -s /bin/bash -c "/usr/bin/php /var/www/moodle/web/admin/cliupgrade.php \
--agreelicense=yes --confirmrelease=yes \
--sitefullname='School Server' \
--siteshortname='XS' \
--sitesummary='Put the name of your school here' \
--adminfirstname=Admin --adminlastname=OLPC \
--adminusername=admin --adminpassword=changeme \
--adminemail=admin@localhost \
--verbose=0 --interactivelevel=0" apache 2>&1 ) #&& \
# runuser -s /bin/bash -c "/usr/bin/php /var/www/moodle/web/local/scripts/adminuser-disable.php" apache 2>&1 ) \
# >> /var/log/moodle-instupg.log
if [ $? = 0 ]; then
# success
echo "["`date`"]" Finished install / upgrade - Success >> /var/log/moodle-instupg.log
rm -f /etc/moodle/needsupgrade
else
# failure
echo "["`date`"]" Finished install / upgrade - Failure >> /var/log/moodle-instupg.log
exit 1
fi
popd
fi
echo -n $"Enabling Moodle access and cron job: "
touch "$lockfile" && success || failure
RETVAL=$?
echo
}
stop() {
echo -n $"Disabling Moodle access and cron job: "
rm -f "$lockfile" && success || failure
RETVAL=$?
echo
}
case "$1" in
start)
start
;;
stop)
stop
;;
*)
exit 1
esac
exit $RETVAL

View file

@ -0,0 +1,14 @@
[Unit]
Description=Moodle Course Management OLPC edition
After={{ apache_service }}.service
[Service]
Type=oneshot
{% if is_debuntu %}
ExecStart=/etc/init.d/moodle-xs-init start
{% else $}
ExecStart=/usr/libexec/moodle-xs-init start
{% endif %}
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,10 @@
[Unit]
Description=Moodle Course Management OLPC edition
After={{ apache_service }}.service
[Service]
Type=oneshot
ExecStart=/usr/libexec/moodle-xs-init start
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,3 @@
nodogsplash_install : False
nodogsplash_enabled : False
nodogsplash_arm_deb : nodogsplash_2.0.0-1_armhf.deb

View file

@ -0,0 +1,3 @@
- name: Install nodogsplash (Raspbian only)
include_tasks: rpi.yml
when: is_rpi | bool

View file

@ -0,0 +1,69 @@
- name: Install package libmicrohttpd12 (Nodogsplash dependencies)
package:
name: libmicrohttpd12
state: present
- name: Download {{ iiab_download_url }}/{{ nodogsplash_arm_deb }} to {{ downloads_dir }}
get_url:
url: "{{ iiab_download_url }}/{{ nodogsplash_arm_deb }}"
dest: "{{ downloads_dir }}/{{ nodogsplash_arm_deb }}"
timeout: "{{ download_timeout }}"
when: internet_available | bool
#async: 300
#poll: 5
- name: Install Nodogsplash
apt:
deb: "{{ downloads_dir }}/{{ nodogsplash_arm_deb }}"
#- name: Create nodogsplash.service # deb file has one
# template:
# backup: no
# src: nodogsplash.service.j2
# dest: "/etc/systemd/system/nodogsplash.service"
# owner: root
# group: root
# mode: 0644
- name: Install custom /etc/nodogsplash/nodogsplash.conf, /etc/nodogsplash/htdocs/splash.html
template:
backup: no
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: root
group: root
mode: "{{ item.mode }}"
with_items:
- { src: 'nodogsplash.conf.j2', dest: '/etc/nodogsplash/nodogsplash.conf', mode: '0644'}
- { src: 'splash.html.j2', dest: '/etc/nodogsplash/htdocs/splash.html', mode: '0644'}
# We should probably only start this service on next boot
- name: Enable & Start 'nodogsplash' systemd service, if nodogsplash_enabled
systemd:
name: nodogsplash
enabled: yes
state: started
when: nodogsplash_enabled | bool
- name: Disable 'nodogsplash' systemd service, if not nodogsplash_enabled
systemd:
name: nodogsplash
enabled: no
state: stopped
when: not nodogsplash_enabled
- name: Add 'nodogsplash' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: nodogsplash
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: nodogsplash
- option: description
value: '"Nodogsplash is a lightweight Captive Portal."'
- option: source
value: "{{ nodogsplash_arm_deb }}"
- option: enabled
value: "{{ nodogsplash_enabled }}"

View file

@ -0,0 +1,413 @@
#
# Nodogsplash Configuration File
#
# Parameter: GatewayInterface
# Default: NONE
#
# GatewayInterface is not autodetected, has no default, and must be set here.
# Set GatewayInterface to the interface on your router
# that is to be managed by Nodogsplash.
# Typically br0 for the wired and wireless lan on OpenWrt White Russian.
# May be br-lan on OpenWrt Kamikaze.
#
GatewayInterface br0
# FirewallRuleSet: authenticated-users
#
# Control access for users after authentication.
# These rules are inserted at the beginning of the
# FORWARD chain of the router's filter table, and
# apply to packets that have come in to the router
# over the GatewayInterface from MAC addresses that
# have authenticated with Nodogsplash, and that are
# destined to be routed through the router. The rules are
# considered in order, and the first rule that matches
# a packet applies to it.
# If there are any rules in this ruleset, an authenticated
# packet that does not match any rule is rejected.
# N.B.: This ruleset is completely independent of
# the preauthenticated-users ruleset.
#
FirewallRuleSet authenticated-users {
# You may want to open access to a machine on a local
# subnet that is otherwise blocked (for example, to
# serve a redirect page; see RedirectURL). If so,
# allow that explicitly here, e.g:
# FirewallRule allow tcp port 80 to 192.168.254.254
# Your router may have several interfaces, and you
# probably want to keep them private from the GatewayInterface.
# If so, you should block the entire subnets on those interfaces, e.g.:
FirewallRule block to 192.168.0.0/16
FirewallRule block to 10.0.0.0/8
# Typical ports you will probably want to open up include
# 53 udp and tcp for DNS,
# 80 for http,
# 443 for https,
# 22 for ssh:
FirewallRule allow tcp port 53
FirewallRule allow udp port 53
FirewallRule allow tcp port 80
FirewallRule allow tcp port 443
FirewallRule allow tcp port 22
# You might use ipset to easily allow/block range of ips, e.g.:
# FirewallRule allow ipset WHITELISTED_IPS
# FirewallRule allow tcp port 80 ipset WHITELISTED_IPS
}
# end FirewallRuleSet authenticated-users
# FirewallRuleSet: preauthenticated-users
#
# Control access for users before authentication.
# These rules are inserted in the PREROUTING chain
# of the router's nat table, and in the
# FORWARD chain of the router's filter table.
# These rules apply to packets that have come in to the
# router over the GatewayInterface from MAC addresses that
# are not on the BlockedMACList or TrustedMACList,
# are *not* authenticated with Nodogsplash. The rules are
# considered in order, and the first rule that matches
# a packet applies to it. A packet that does not match
# any rule here is rejected.
# N.B.: This ruleset is completely independent of
# the authenticated-users and users-to-router rulesets.
#
FirewallRuleSet preauthenticated-users {
# For preauthenticated users to resolve IP addresses in their initial
# request not using the router itself as a DNS server,
# you probably want to allow port 53 udp and tcp for DNS.
FirewallRule allow tcp port 53
FirewallRule allow udp port 53
# For splash page content not hosted on the router, you
# will want to allow port 80 tcp to the remote host here.
# Doing so circumvents the usual capture and redirect of
# any port 80 request to this remote host.
# Note that the remote host's numerical IP address must be known
# and used here.
# FirewallRule allow tcp port 80 to 123.321.123.321
}
# end FirewallRuleSet preauthenticated-users
# FirewallRuleSet: users-to-router
#
# Control access to the router itself from the GatewayInterface.
# These rules are inserted at the beginning of the
# INPUT chain of the router's filter table, and
# apply to packets that have come in to the router
# over the GatewayInterface from MAC addresses that
# are not on the TrustedMACList, and are destined for
# the router itself. The rules are
# considered in order, and the first rule that matches
# a packet applies to it.
# If there are any rules in this ruleset, a
# packet that does not match any rule is rejected.
#
FirewallRuleSet users-to-router {
# Nodogsplash automatically allows tcp to GatewayPort,
# at GatewayAddress, to serve the splash page.
# However you may want to open up other ports, e.g.
# 53 for DNS and 67 for DHCP if the router itself is
# providing these services.
FirewallRule allow udp port 53
FirewallRule allow tcp port 53
FirewallRule allow udp port 67
# You may want to allow ssh, http, and https to the router
# for administration from the GatewayInterface. If not,
# comment these out.
FirewallRule allow tcp port 22
FirewallRule allow tcp port 80
FirewallRule allow tcp port 443
# FirewallRule allow tcp port 3000
}
# end FirewallRuleSet users-to-router
# EmptyRuleSetPolicy directives
# The FirewallRuleSets that NoDogSplash permits are:
#
# authenticated-users
# preauthenticated-users
# users-to-router
# trusted-users
# trusted-users-to-router
#
# For each of these, an EmptyRuleSetPolicy can be specified.
# An EmptyRuleSet policy applies to a FirewallRuleSet if the
# FirewallRuleSet is missing from this configuration file,
# or if it exists but contains no FirewallRules.
#
# The possible values of an EmptyRuleSetPolicy are:
# allow -- packets are accepted
# block -- packets are rejected
# passthrough -- packets are passed through to pre-existing firewall rules
#
# Default EmptyRuleSetPolicies are set as follows:
# EmptyRuleSetPolicy authenticated-users passthrough
# EmptyRuleSetPolicy preauthenticated-users block
EmptyRuleSetPolicy users-to-router allow
# EmptyRuleSetPolicy trusted-users allow
# EmptyRuleSetPolicy trusted-users-to-router allow
# Parameter: GatewayName
# Default: NoDogSplash
#
# Set GatewayName to the name of your gateway. This value
# will be available as variable $gatewayname in the splash page source
# and in status output from ndsctl, but otherwise doesn't matter.
# If none is supplied, the value "NoDogSplash" is used.
#
# GatewayName NoDogSplash
# Parameter: GatewayAddress
# Default: Discovered from GatewayInterface
#
# This should be autodetected on an OpenWRT system, but if not:
# Set GatewayAddress to the IP address of the router on
# the GatewayInterface. This is the address that the Nodogsplash
# server listens on.
#
# GatewayAddress 192.168.1.1
# Parameter: RedirectURL
# Default: none
#
# After authentication, normally a user is redirected
# to their initially requested page.
# If RedirectURL is set, the user is redirected to this URL instead.
#
# RedirectURL http://www.ilesansfil.org/
# Parameter: GatewayPort
# Default: 2050
#
# Nodogsplash's own http server uses GatewayAddress as its IP address.
# The port it listens to at that IP can be set here; default is 2050.
#
# GatewayPort 2050
# Parameter: MaxClients
# Default: 20
#
# Set MaxClients to the maximum number of users allowed to
# connect at any time. (Does not include users on the TrustedMACList,
# who do not authenticate.)
#
# MaxClients 20
# ClientIdleTimeout
# Parameter: ClientIdleTimeout
# Default: 10
#
# Set ClientIdleTimeout to the desired of number of minutes
# of inactivity before a user is automatically 'deauthenticated'.
#
# ClientIdleTimeout 10
# Parameter: ClientForceTimeout
# Default: 360
#
# Set ClientForceTimeout to the desired number of minutes before
# a user is automatically 'deauthenticated', whether active or not
#
# ClientForceTimeout 360
# Parameter: AuthenticateImmediately
# Default: no
#
# Set to yes (or true or 1), to immediately authenticate users
# who make a http port 80 request on the GatewayInterface (that is,
# do not serve a splash page, just redirect to the user's request,
# or to RedirectURL if set).
#
# AuthenticateImmediately no
# Parameter: MACMechanism
# Default: block
#
# Either block or allow.
# If 'block', MAC addresses on BlockedMACList are blocked from
# authenticating, and all others are allowed.
# If 'allow', MAC addresses on AllowedMACList are allowed to
# authenticate, and all other (non-trusted) MAC's are blocked.
#
# MACMechanism block
# Parameter: BlockedMACList
# Default: none
#
# Comma-separated list of MAC addresses who will be completely blocked
# from the GatewayInterface. Ignored if MACMechanism is allow.
# N.B.: weak security, since MAC addresses are easy to spoof.
#
# BlockedMACList 00:00:DE:AD:BE:EF,00:00:C0:1D:F0:0D
# Parameter: AllowedMACList
# Default: none
#
# Comma-separated list of MAC addresses who will not be completely
# blocked from the GatewayInterface. Ignored if MACMechanism is block.
# N.B.: weak security, since MAC addresses are easy to spoof.
#
# AllowedMACList 00:00:12:34:56:78
# Parameter: TrustedMACList
# Default: none
#
# Comma-separated list of MAC addresses who are not subject to
# authentication, and are not restricted by any FirewallRuleSet.
# N.B.: weak security, since MAC addresses are easy to spoof.
#
# TrustedMACList 00:00:CA:FE:BA:BE, 00:00:C0:01:D0:0D
# Parameter: PasswordAuthentication
# Default: no
# Set to yes (or true or 1), to require a password matching
# the Password parameter to be supplied when authenticating.
#
#
# PasswordAuthentication no
# Parameter: Password
# Default: none
# Whitespace delimited string that is compared to user-supplied
# password when authenticating.
#
#
# Password nodog
# Parameter: UsernameAuthentication
# Default: no
# Set to yes (or true or 1), to require a username matching
# the Username parameter to be supplied when authenticating.
#
#
# UsernameAuthentication no
# Parameter: Username
# Default: none
# Whitespace delimited string that is compared to user-supplied
# username when authenticating.
#
#
# Username guest
# Parameter: PasswordAttempts
# Default: 5
# Integer number of failed password/username entries before
# a user is forced to reauthenticate.
#
#
# PasswordAttempts 5
# Parameter: TrafficControl
# Default: no
#
# Set to yes (or true or 1), to enable traffic control in Nodogsplash.
#
# TrafficControl no
# Parameter: DownloadLimit
# Default: 0
#
# If TrafficControl is enabled, this sets the maximum download
# speed to the GatewayInterface, in kilobits per second.
# For example if you have an ADSL connection with 768 kbit
# download speed, and you want to allow about half of that
# bandwidth for the GatewayInterface, set this to 384.
# A value of 0 means no download limiting is done.
#
# DownloadLimit 384
# Parameter: UploadLimit
# Default: 0
#
# If TrafficControl is enabled, this sets the maximum upload
# speed from the GatewayInterface, in kilobits per second.
# For example if you have an ADSL connection with 128 kbit
# upload speed, and you want to allow about half of that
# bandwidth for the GatewayInterface, set this to 64.
# A value of 0 means no upload limiting is done.
#
# UploadLimit 64
# Parameter: GatewayIPRange
# Default: 0.0.0.0/0
#
# By setting this parameter, you can specify a range of IP addresses
# on the GatewayInterface that will be responded to and managed by
# Nodogsplash. Addresses outside this range do not have their packets
# touched by Nodogsplash at all.
# Defaults to 0.0.0.0/0, that is, all addresses.
#
# GatewayIPRange 0.0.0.0/0
# Parameter: ImagesDir
# Default: images
#
# Set the directory from which images are served.
# Use $imagesdir in HTML files to reference this directory.
#
# ImagesDir images
# Parameter: BinVoucher
# Default: None
#
# Enable Voucher Support.
# If set, an alphanumeric voucher HTTP parameter is accepted
# and passed to a command line call along with the clients MAC:
#
# $<BinVoucher> auth_voucher <mac> <voucher>
#
# BinVoucher must point to a program that will be called as described above.
# The call is expected to output the number of seconds the client
# is to be authenticated. Zero or negative seconds will cause the
# authentification request to be rejected.
# The output may contain a user specific download and upload limit in KBit/s:
# <seconds> <upload> <download>
#
# BinVoucher "/bin/myauth"
# Parameter: ForceVoucher
# Default: no
#
# Force the use of a voucher. Authentification is not possible without voucher.
#
# ForceVoucher no
# Parameter: EnablePreAuth
# Default: no
#
# Enable pre-authentication support.
# Pass the MAC of a client to a command line call before the splash page
# would be send:
#
# $<BinVoucher> auth_status <mac>
#
# The call is expected to output the number of seconds the client
# is to be authenticated. Zero or negative seconds will cause the
# splash page to be displayed.
# The output may contain a user specific download and upload limit in KBit/s:
# <seconds> <download> <upload>
#
# EnablePreAuth no
# Parameter: FW_MARK_BLOCKED
# Default: 0x100
#
# Parameter: FW_MARK_TRUSTED
# Default: 0x200
#
# Parameter: FW_MARK_AUTHENTICATED
# Default: 0x400
#
# Nodogsplash uses specific values to mark packet using iptables.
# In rare cases these might conflict with other programs and need
# to be changed.

View file

@ -0,0 +1,12 @@
[Unit]
Description=NoDogSplash Captive Portal
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/nodogsplash -d 5 $OPTIONS
ExecStop=/usr/bin/ndsctl stop
Restart=on-failure
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<!--
A client is authenticated by requesting the page $authtarget.
So, href to it here, with an img or link text the user can click on.
Alternatively submit an HTTP form method=get, passing $authaction, $tok and $redir
Also, note that any images you reference must reside in the
subdirectory that is the value of $imagesdir (default: "images").
Available variables:
error_msg: $error_msg
gatewayname: $gatewayname
tok: $tok
redir: $redir
authaction: $authaction
denyaction: $denyaction
authtarget: $authtarget
clientip: $clientip
clientmac: $clientmac
gatewaymac: $gatewaymac
nclients: $nclients
maxclients: $maxclients
uptime: $uptime
imagesdir: $imagesdir
pagesdir: $pagesdir
Additional Variables that can also be passed back via HTTP get.
Or just append them to the authentication link:
nodoguser
nodogpass
info
voucher
-->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel='shortcut icon' href='$imagesdir/splash.jpg' type='image/x-icon' />
<title>$gatewayname Entry</title>
<style>
body
{
background-color:lightgrey;
color:black;
max-width: 500px;
margin: auto;
text-align: left;
}
img
{
width: 40%;
max-width: 180px;
margin-left: 0%;
margin-right: 5%;
}
input[type=submit]
{
color:black;
margin-left: 0%;
margin-right: 5%;
text-align:left;
font-size: 1.0em;
line-height: 2.5em;
font-weight: bold;
border: 1px solid;
}
</style>
</head>
<body>
<br>
<h3>Redirecting to Internet in a Box ...</h3>
<h3>If not redirected automatically, <BR>Please click Continue Button.</h3>
<br>
<br>
<form method='get' action='$authaction' name='redirectForm'>
<input type='hidden' name='tok' value='$tok'>
<input type='hidden' name='redir' value='http://{{ iiab_hostname }}.{{ iiab_domain }}{{ iiab_home_url }}'>
<input type='submit' value='Continue to Internet in a Box'>
</form>
<script type="text/javascript">
setTimeout(function () {
document.forms["redirectForm"].submit();
}, 1000);
</script>
</body>
</html>

View file

@ -0,0 +1,4 @@
osm_install: True
osm_enabled: False
osm_path: ""
osm_venv: /usr/local/osm/

View file

@ -0,0 +1,190 @@
- name: Install 5 OSM required packages (debuntu)
package:
name:
- gcc
- python-dev
- liblzma-dev
- libapache2-mod-wsgi
- libapache2-mod-xsendfile
state: present
when: is_debuntu | bool
- name: Install 6 OSM required packages (not debuntu)
package:
name:
- python-pip
- gcc
- python-devel
- xz-devel
- mod_wsgi
- mod_xsendfile
state: present
when: not is_debuntu
# OSM wants a specific version do that first
- name: Install Whoosh 2.6 using pip, into virtualenv (debuntu)
pip:
name: whoosh
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
version: 2.6
extra_args: "--no-cache-dir"
when: internet_available and is_debuntu
- name: Install Flask 0.12.4 using pip, into virtualenv (debuntu)
pip:
name: Flask
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
version: 0.12.4
extra_args: "--no-cache-dir"
when: internet_available and is_debuntu
- name: Install OSM with dependencies using pip, into virtualenv (debuntu)
pip:
name: "{{ item }}"
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
extra_args: "--no-cache-dir"
with_items:
- MarkupSafe
- pytz
- Internet-in-a-Box
when: internet_available and is_debuntu
# OSM wants a specific version do that first
- name: Install Whoosh 2.6 using pip, into virtualenv (not debuntu)
pip:
name: whoosh
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
version: 2.6
#extra_args: "--no-cache-dir"
when: internet_available and not is_debuntu
- name: Install Flask 0.12.4 using pip, into virtualenv (not debuntu)
pip:
name: Flask
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
version: 0.12.4
#extra_args: "--no-cache-dir"
when: internet_available and not is_debuntu
- name: Install OSM with dependencies using pip, into virtualenv (not debuntu)
pip:
name: "{{ item }}"
virtualenv: "{{ osm_venv }}"
virtualenv_site_packages: no
#extra_args: "--no-cache-dir"
with_items:
- MarkupSafe
- pytz
- Internet-in-a-Box
when: internet_available and not is_debuntu
- name: Set osm_path fact (redhat)
set_fact:
#osm_path: "{{ osm_venv }}/{{ python_path }}/iiab"
osm_path: "{{ osm_venv }}{{ python_path }}/iiab"
when: osm_enabled and is_redhat
- name: Set osm_path fact (debuntu)
set_fact:
#osm_path: "{{ osm_venv }}/lib/python2.7/site-packages/iiab"
osm_path: "{{ osm_venv }}lib/python2.7/site-packages/iiab"
when: osm_enabled and is_debuntu
- name: Point wsgi to virtual environment
lineinfile:
path: "{{ osm_venv }}/bin/iiab.wsgi"
regexp: "path_to_virtualenv = None"
line: "path_to_virtualenv = '/usr/local/osm'"
state: present
- name: Install /etc/{{ apache_config_dir }}/osm.conf from template
template:
src: osm.conf.j2
dest: "/etc/{{ apache_config_dir }}/osm.conf"
owner: root
group: root
mode: 0644
backup: no
when: osm_enabled | bool
- name: Create softlink osm.conf from sites-enabled to sites-available (debuntu)
file:
src: "/etc/{{ apache_config_dir }}/osm.conf"
path: /etc/apache2/sites-enabled/osm.conf
state: link
when: osm_enabled and is_debuntu
- name: Remove softlink osm.conf from sites-enabled (debuntu)
file:
path: /etc/apache2/sites-enabled/osm.conf
state: absent
when: not osm_enabled and is_debuntu
- name: Remove /{{ apache_config_dir }}/osm.conf (redhat)
file:
path: "/{{ apache_config_dir }}/osm.conf"
state: absent
when: not osm_enabled and is_redhat
- name: Remove link {{ doc_root }}/osm.wsgi
file:
path: "{{ doc_root }}/osm.wsgi"
state: absent
when: not osm_enabled
- name: Create softlink osm.wsgi to iiab.cgi
file:
src: "{{ osm_venv }}/bin/iiab.wsgi"
path: "{{ doc_root }}/osm.wsgi"
owner: root
group: root
state: link
when: osm_enabled | bool
- name: Create dir /library/knowledge/modules
file:
path: /library/knowledge/modules
state: directory
owner: "{{ apache_user }}"
group: "{{ apache_user }}"
# the following was brought into OSM playbook from iiab-factory osm-fix script
- name: Install 6 files from templates
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
with_items:
- { src: 'defaults.ini', dest: "{{ osm_path }}/" }
- { src: 'etc.iiab.conf', dest: '/etc/iiab.conf' }
- { src: 'map_search.py', dest: "{{ osm_path }}/map_search.py" }
- { src: 'map.html', dest: "{{ osm_path }}/static/map.html" }
- { src: 'l.control.geosearch.js', dest: "{{ osm_path }}/static/lib/leaflet/geosearch/l.control.geosearch.js" }
- { src: "{{ osm_path }}/static/map.html", dest: "{{ osm_path }}/static/index.html" }
when: osm_enabled | bool
- name: Restart httpd service
service:
name: "{{ apache_service }}"
state: restarted
- name: Add 'osm' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: osm
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: OpenStreetMap
- option: description
value: '"OpenStreetMap offers beautiful maps of the entire planet, continually created & updated by volunteers (much in the same way as Wikipedia) but for maps."'
# value: '"The Internet-in-a-Box is a small, inexpensive device which provides essential Internet resources without any Internet connection. It provides a local copy of half a terabyte of the worlds Free information."'
- option: path
value: /osm
- option: enabled
value: "{{ osm_enabled }}"

View file

@ -0,0 +1,83 @@
;; Configuration file for Internet-in-a-Box
;;
;; You should NOT edit this file if you are only
;; making changes for your local machine.
;;
;; Instead create a local.ini file which will automatically
;; be loaded AFTER this file loads, and can be used to
;; override any settings in this file. Do NOT check your local.ini
;; into the repository, it is for your personal use only.
;;
;; Variable "interpolation" can be used to incorporate
;; values from previous assignments within a setting value.
;;
;; For example,
;; b = BAAAH
;; a = a%(b)sc
;;
;; will result in the value of 'a' being 'aBAAHc'. Note the 's'
;; following the parenthesis is NECESSARY (to denote a string?)
;;
;; [DEFAULT] is a special section. Any settings there
;; will automatically appear in all other sections. [DEFAULT]
; Location of our dataset
[DEFAULT]
knowledge_dir = /library/knowledge
processed_dir = %(knowledge_dir)s/processed
modules_dir = %(knowledge_dir)s/modules
data_dir = %(knowledge_dir)s/data
; If search_for_knowledge_dir is true, then
; the system will search all mounted volumes
; for a "knowledge/" directory if the path
; specified in knowledge_dir does not exist.
search_for_knowledge_dir = False
; Machine architecture. This is set by the
; application at run-time.
arch = unset
bin_dir = %(knowledge_dir)s/sys/bin-%(arch)s
[WEBAPP]
port = 25000
interface = 0.0.0.0
base_prefix = /iiab/
use_x_sendfile = False
[ZIM]
url = /iiab/zim
wikipedia_zim_dir = %(modules_dir)s/wikipedia-zim
wikipedia_index_dir = %(modules_dir)s/wikipedia-index
kiwix_library_file = %(wikipedia_zim_dir)s/library.xml
old_kiwix_library_file = %(modules_dir)s/wikipedia-kiwix/library.xml
[GUTENBERG]
gutenberg_dir = %(modules_dir)s/gutenberg
gutenberg_mirror = %(modules_dir)s/gutenberg-mirror
htmlz_dir = %(modules_dir)s/gutenberg-htmlz
htmlz_images_dir = %(modules_dir)s/gutenberg-htmlz-images
epub_dir = %(modules_dir)s/gutenberg-epub
epub_images_dir = %(modules_dir)s/gutenberg-epub-images
sqlalchemy_echo = True
sqlalchemy_database_uri = %(gutenberg_dir)s/gutenberg.db
index_dir = %(gutenberg_dir)s/whoosh/gutenberg_index
root_dir = %(gutenberg_mirror)s/
[VIDEO]
khanacademy_dir = %(modules_dir)s/khanacademy
khan_webm_dir = %(khanacademy_dir)s/webm
khan_h264_dir = %(khanacademy_dir)s/h264
khan_cache_file = /tmp/khan_cache.json
; Where we make easy 0/1/2/3 sym links for all videos
; so they can be served directly by the front end web server
symlink_dir = %(khanacademy_dir)s/khanlinks
; This is static content, so it can change based on web server config
video_url = /iiab/video/khanvideo
[OSM]
openstreetmap_dir = %(modules_dir)s/openstreetmap
osm_search_dir = %(modules_dir)s/geonames_index
[SOFTWARE]
software_dir = %(modules_dir)s/ubuntu/12.04/mirror/archive.ubuntu.com/ubuntu
software_url = /iiab/software

View file

@ -0,0 +1,25 @@
;; Local Configuration file for Internet-in-a-Box
;;
;;
;
;; [DEFAULT] is a special section. Any settings there
;; will automatically appear in all other sections.
[DEFAULT]
; Location of our dataset
knowledge_dir = /library/knowledge
; repeat all the other assignments to get the new dir
processed_dir = %(knowledge_dir)s/processed
modules_dir = %(knowledge_dir)s/modules
data_dir = %(knowledge_dir)s/data
; If search_for_knowledge_dir is true, then
; the system will search all mounted volumes
; for a "knowledge/" directory if the path
; specified in knowledge_dir does not exist.
search_for_knowledge_dir = True
; Machine architecture. This is set by the
; application at run-time.
arch = unset
bin_dir = %(knowledge_dir)s/sys/bin-%(arch)s

View file

@ -0,0 +1,425 @@
/*
* L.Control.GeoSearch - search for an address and zoom to it's location
* https://github.com/smeijer/leaflet.control.geosearch
*/
L.GeoSearch = {};
L.GeoSearch.Provider = {};
// MSIE needs cors support
jQuery.support.cors = true;
L.GeoSearch.Result = function (x, y, label) {
this.X = x;
this.Y = y;
this.Label = label;
};
L.Control.GeoSearch = L.Control.extend({
options: {
position: 'topcenter'
},
initialize: function (options) {
this._config = {};
L.Util.extend(this.options, options);
this.setConfig(options);
},
setConfig: function (options) {
this._config = {
'country': options.country || '',
'provider': options.provider,
'searchLabel': options.searchLabel || 'search for address...',
'notFoundMessage' : options.notFoundMessage || 'Sorry, that address could not be found.',
'messageHideDelay': options.messageHideDelay || 3000,
'zoomLevel': options.zoomLevel || 18,
'maxMarkers': options.maxMarkers || 1,
'enableButtons': options.enableButtons || false,
'enableAutocomplete': options.enableAutocomplete || false,
'autocompleteMinQueryLen': options.autocompleteMinQueryLen || 3, // query length request threshold
'autocompleteQueryDelay_ms': options.autocompleteQueryDelay_ms || 800
};
},
onAdd: function (map) {
var $controlContainer = $(map._controlContainer);
if ($controlContainer.children('.leaflet-top.leaflet-center').length == 0) {
$controlContainer.append('<div class="leaflet-top leaflet-center"></div>');
map._controlCorners.topcenter = $controlContainer.children('.leaflet-top.leaflet-center').first()[0];
}
this._map = map;
this._container = L.DomUtil.create('div', 'leaflet-control-geosearch');
var searchbox = document.createElement('input');
searchbox.id = 'leaflet-control-geosearch-qry';
searchbox.type = 'text';
searchbox.placeholder = this._config.searchLabel;
this._searchbox = searchbox;
if (this._autocomplete) {
this._autocomplete.recordLastUserInput('');
}
if (this._config.enableButtons) {
var submitContainer = L.DomUtil.create('div', 'leaflet-control-geosearch-button-submit-container', this._container);
L.DomUtil.create('span', 'leaflet-geosearch-submit-button', submitContainer);
var cancelButton = L.DomUtil.create('span', 'leaflet-geosearch-cancel-button', this._container);
L.DomEvent.on(submitContainer, 'click', this._submitRequest, this);
L.DomEvent.on(cancelButton, 'click', this._clearUserSearchInput, this);
}
var msgbox = document.createElement('div');
msgbox.id = 'leaflet-control-geosearch-msg';
msgbox.className = 'leaflet-control-geosearch-msg';
this._msgbox = msgbox;
var resultslist = document.createElement('ul');
resultslist.id = 'leaflet-control-geosearch-results';
this._resultslist = resultslist;
$(this._msgbox).append(this._resultslist);
$(this._container).append(this._searchbox, this._msgbox);
if (this._config.enableAutocomplete) {
this._autocomplete = new L.AutoComplete(this.options).addTo(this._container, function (suggestionText) {
this._searchbox.value = suggestionText;
}.bind(this));
$(this._container).append(this._autocomplete);
}
// TODO This will result in duplicate processing of events. Options?
L.DomEvent
.addListener(this._container, 'click', L.DomEvent.stop)
.addListener(this._container, 'keyup', this._onKeyUp, this)
.addListener(this._container, 'change', this._onInputUpdate, this)
.addListener(this._container, 'paste', this._onPasteToInput, this);
L.DomEvent.disableClickPropagation(this._container);
return this._container;
},
geosearch: function (qry) {
this.geosearch_ext(qry, this._processResults.bind(this), this._printError.bind(this));
},
geosearch_ext: function(qry, onSuccess, onFailure) {
try {
var provider = this._config.provider;
if(typeof provider.GetLocations == 'function') {
var results = provider.GetLocations(qry, function(results) {
onSuccess(results);
}.bind(this));
}
else {
var url = provider.GetServiceUrl(qry);
$.getJSON(url, function (data) {
try {
var results = provider.ParseJSON(data);
onSuccess(results);
}
catch (error) {
onFailure(error);
}
}.bind(this));
}
}
catch (error) {
onFailure(error);
}
},
// qry may be a String or a function
geosearch_autocomplete: function (qry, requestDelay_ms) {
if (!this._config.enableAutocomplete) {
return;
}
clearTimeout(this._autocompleteRequestTimer);
this._autocompleteRequestTimer = setTimeout(function () {
var q = qry;
if (typeof qry === 'function') {
q = qry();
}
if (q.length >= this._config.autocompleteMinQueryLen) {
this.geosearch_ext(q, this._autocomplete.show.bind(this._autocomplete), this._autocomplete.hide.bind(this._autocomplete));
} else {
this._autocomplete.hide();
}
}.bind(this), requestDelay_ms);
},
_processResults: function(results) {
if (results.length == 0)
throw this._config.notFoundMessage;
this._map.fireEvent('geosearch_foundlocations', {Locations: results});
this._showLocations(results);
},
_showLocations: function (results) {
if (typeof this._layer !== 'undefined') {
this._map.removeLayer(this._layer);
this._layer = null;
}
this._markerList = []
for (var ii=0; ii < results.length && ii < this._config.maxMarkers; ii++) {
var location = results[ii];
var marker = L.marker([location.Y, location.X]).bindPopup(location.Label);
this._markerList.push(marker);
}
this._layer = L.layerGroup(this._markerList).addTo(this._map);
this._printError('Displaying ' + Math.min(this._autocomplete._config.maxResultCount, results.length) + ' of ' + results.length +' results.');
var premierResult = results[0];
this._map.setView([premierResult.Y, premierResult.X], this._config.zoomLevel, false);
this._map.fireEvent('geosearch_showlocation', {Location: premierResult});
},
_printError: function(message) {
$(this._resultslist)
.html('<li>'+message+'</li>')
.fadeIn('slow').delay(this._config.messageHideDelay).fadeOut('slow',
function () { $(this).html(''); });
},
_submitRequest: function () {
var q = $('#leaflet-control-geosearch-qry').val();
if (q.length > 0) {
this._hideAutocomplete();
this.geosearch(q);
}
},
_hideAutocomplete: function () {
clearTimeout(this._autocompleteRequestTimer);
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
this._autocomplete.hide();
return true;
}
return false;
},
_clearUserSearchInput: function () {
this._hideAutocomplete();
$('#leaflet-control-geosearch-qry').val('');
$('.leaflet-geosearch-cancel-button').hide();
},
_onPasteToInput: function () {
// onpaste requires callback to allow for input update do this by default.
setTimeout(this._onInputUpdate.bind(this), 0);
},
_onInputUpdate: function () {
// define function for requery of user input after delay
function getQuery() {
return $('#leaflet-control-geosearch-qry').val();
}
var qry = getQuery();
if (this._config.enableAutocomplete) {
this._autocomplete.recordLastUserInput(qry);
if (qry.length >= this._config.autocompleteMinQueryLen) {
this.geosearch_autocomplete(getQuery, this._config.autocompleteQueryDelay_ms);
} else {
this._autocomplete.hide();
}
}
if (qry.length > 0) {
$('.leaflet-geosearch-cancel-button').show();
} else {
$('.leaflet-geosearch-cancel-button').hide();
}
},
_onKeyUp: function (e) {
var REQ_DELAY_MS = 800;
var MIN_AUTOCOMPLETE_LEN = 3;
var enterKey = 13;
var shift = 16;
var ctrl = 17;
var escapeKey = 27;
var leftArrow = 37;
var upArrow = 38;
var rightArrow = 39;
var downArrow = 40;
switch (e.keyCode) {
case escapeKey:
// ESC first closes autocomplete if open. If closed then clears input.
if (!this._hideAutocomplete()) {
this._clearUserSearchInput();
}
break;
case enterKey:
this._submitRequest();
break;
case upArrow:
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
this._autocomplete.moveUp();
}
break;
case downArrow:
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
this._autocomplete.moveDown();
}
break;
case leftArrow:
case rightArrow:
case shift:
case ctrl:
break;
default:
this._onInputUpdate();
}
}
});
L.AutoComplete = L.Class.extend({
initialize: function (options) {
this._config = {};
this.setConfig(options);
},
setConfig: function (options) {
this._config = {
'maxResultCount': options.maxResultCount || 10,
'onMakeSuggestionHTML': options.onMakeSuggestionHTML || function (geosearchResult) {
return this._htmlEscape(geosearchResult.Label);
}.bind(this),
};
},
addTo: function (container, onSelectionCallback) {
this._container = container;
this._onSelection = onSelectionCallback;
return this._createUI(container, 'leaflet-geosearch-autocomplete');
},
recordLastUserInput: function (str) {
this._lastUserInput = str;
},
_createUI: function (container, className) {
this._tool = L.DomUtil.create('div', className, container);
this._tool.style.display = 'none';
L.DomEvent
.disableClickPropagation(this._tool)
// consider whether to make delayed hide onBlur.
// If so, consider canceling timer on mousewheel and mouseover.
.on(this._tool, 'blur', this.hide, this)
.on(this._tool, 'mousewheel', function(e) {
L.DomEvent.stopPropagation(e); // to prevent map zoom
if (e.axis === e.VERTICAL_AXIS) {
if (e.detail > 0) {
this.moveDown();
} else {
this.moveUp();
}
}
}, this);
return this;
},
show: function (results) {
this._tool.innerHTML = '';
this._tool.currentSelection = -1;
var count = 0;
while (count < results.length && count < this._config.maxResultCount) {
var entry = this._newSuggestion(results[count]);
this._tool.appendChild(entry);
++count;
}
if (count > 0) {
this._tool.style.display = 'block';
} else {
this.hide();
}
return count;
},
hide: function () {
this._tool.style.display = 'none';
this._tool.innerHTML = '';
},
isVisible: function() {
return this._tool.style.display !== 'none';
},
_htmlEscape: function (str) {
// implementation courtesy of http://stackoverflow.com/a/7124052
return String(str)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
},
_newSuggestion: function (result) {
var tip = L.DomUtil.create('li', 'leaflet-geosearch-suggestion');
tip.innerHTML = this._config.onMakeSuggestionHTML(result);
tip._text = result.Label;
L.DomEvent
.disableClickPropagation(tip)
.on(tip, 'click', function(e) {
this._onSelection(tip._text);
}.bind(this), this);
return tip;
},
_onSelectedUpdate: function () {
var entries = this._tool.hasChildNodes() ? this._tool.childNodes : [];
for (var ii=0; ii < entries.length; ++ii) {
L.DomUtil.removeClass(entries[ii], 'leaflet-geosearch-suggestion-selected');
}
// if selection is -1, then show last user typed text
if (this._tool.currentSelection >= 0) {
L.DomUtil.addClass(entries[this._tool.currentSelection], 'leaflet-geosearch-suggestion-selected');
// scroll:
var tipOffsetTop = entries[this._tool.currentSelection].offsetTop;
if (tipOffsetTop + entries[this._tool.currentSelection].clientHeight >= this._tool.scrollTop + this._tool.clientHeight) {
this._tool.scrollTop = tipOffsetTop - this._tool.clientHeight + entries[this._tool.currentSelection].clientHeight;
}
else if (tipOffsetTop <= this._tool.scrollTop) {
this._tool.scrollTop = tipOffsetTop;
}
this._onSelection(entries[this._tool.currentSelection]._text);
} else {
this._onSelection(this._lastUserInput);
}
},
moveUp: function () {
// permit selection to decrement down to -1 (none selected)
if (this.isVisible() && this._tool.currentSelection >= 0) {
--this._tool.currentSelection;
this._onSelectedUpdate();
}
return this;
},
moveDown: function () {
if (this.isVisible()) {
this._tool.currentSelection = (this._tool.currentSelection + 1) % this.suggestionCount();
this._onSelectedUpdate();
}
return this;
},
suggestionCount: function () {
return this._tool.hasChildNodes() ? this._tool.childNodes.length : 0;
},
});

View file

@ -0,0 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="lib/leaflet/leaflet.css" />
<link rel="stylesheet" href="lib/leaflet/geosearch/l.geosearch.css" />
<style type="text/css">
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
</style>
<script type="text/javascript">
// Required for Firefox 3.6
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
</script>
<script src="lib/jquery-1.9.0.js"></script>
<script src="lib/leaflet/leaflet.js"></script>
<script src="lib/leaflet/geosearch/l.control.geosearch.js"></script>
<script src="lib/leaflet/geosearch/l.geosearch.provider.iiab.js"></script>
<script type="text/javascript">
$(function () {
var map = L.map('map'); /*.setView([51.505, -0.09], 14);*/
L.tileLayer('/iiab/maps/tile/{z}/{x}/{y}.png', {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
maxZoom: 15
}).addTo(map);
var geoOptions = {
provider: new L.GeoSearch.Provider.iiab(),
searchLabel: "Search by City Name...",
notFoundMessage: "No matches found",
zoomLevel: 8,
maxMarkers: 10,
maxResultCount: 15,
enableAutocomplete: true,
enableButtons: true
};
new L.Control.GeoSearch(geoOptions).addTo(map);
map.fitWorld().setZoom(3); // default world view
//map.locate({setView: true, maxZoom: 15});
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>

View file

@ -0,0 +1,58 @@
# Internet-in-a-Box System
# By Braddock Gaskill, 16 Feb 2013
# Modified by Tim Moody, 8 Apr 2016
from utils import whoosh_open_dir_32_or_64
# from whoosh.qparser import QueryParser
from whoosh.qparser import MultifieldParser
from whoosh import sorting
from utils import whoosh2dict
class MapSearch(object):
def __init__(self, index_dir):
"""Initialize a search object.
index_dir is the Whoosh index directory to use."""
self.index_dir = index_dir
def search(self, query, page=1, pagelen=20):
"""Return a sorted list of results.
pagelen specifies the number of hits per page.
page specifies the page of results to return (first page is 1)
Set pagelen = None or 0 to retrieve all results.
"""
query = unicode(query) # Must be unicode
population_sort_facet = sorting.FieldFacet("population", reverse=True)
ix = whoosh_open_dir_32_or_64(self.index_dir)
with ix.searcher() as searcher:
# query = QueryParser("ngram_name", ix.schema).parse(query)
mparser = MultifieldParser(["ngram_name", "admin1_code", "country_code"], schema=ix.schema)
query = mparser.parse(query)
if pagelen is not None and pagelen != 0:
try:
results = searcher.search_page(query, page, pagelen=pagelen)
except ValueError, e: # Invalid page number
results = []
else:
results = searcher.search(query, limit=None)
#r = [x.items() for x in results]
r = whoosh2dict(results)
ix.close()
# experiment with tucking away content for display in popup.
print r
for d in r:
d['popupText'] = 'test content'
d['name'] = d['name'] + ', ' + d['admin1_code'] + ', ' + d['country_code']
return r
def count(self, query):
"""Return total number of matching documents in index"""
query = unicode(query) # Must be unicode
ix = whoosh_open_dir_32_or_64(self.index_dir)
with ix.searcher() as searcher:
query = QueryParser("title", ix.schema).parse(query)
results = searcher.search(query)
n = len(results)
ix.close()
return n

View file

@ -0,0 +1,18 @@
#IIAB Apache2 configuration file
XSendFile on
XSendFilePath /
WSGIScriptAlias /iiab {{ doc_root }}/osm.wsgi
# For old bitmap/raster tileset
Alias /iiabstatic {{ osm_path }}/static
# 2018-09-19: placement of osm.conf (for http://box/maps) moved to roles/httpd/tasks/main.yml to economize ~5 min during RPi install, now that this (older) osm playbook is rarely used
## For new vector tileset, as documented @ http://FAQ.IIAB.IO ("How do I add zoomable maps for my region? ") & http://download.iiab.io/content/OSM/vector-tiles/
#Alias /maps /library/www/html/modules/en-osm-omt-min/
#Alias /osm /library/www/html/modules/en-osm-omt-min/
<Directory {{ osm_path }}/static>
require all granted
</Directory>

View file

@ -0,0 +1,5 @@
[osm]
name=Internet-in-a-Box
baseurl=http://downloads.internet-in-a-box.org/fedora/18
enabled=1
gpgcheck=0

View file

@ -0,0 +1,37 @@
===============
Owncloud README
===============
This role installs Owncloud, a local cloud type server to share files, calendars, and contacts.
Configuration Parameters
------------------------
The following are set as defaults in var/main.yml:
* owncloud_install: True
* owncloud_enabled: False
* owncloud_prefix: "/opt"
* owncloud_data_dir: /library/owncloud/data
* owncloud_src_file: owncloud-7.0.12.tar.bz2
* owncloud_admin_user: 'Admin'
* owncloud_admin_password: 'changeme'
We install on mysql with these setting or those from default_vars, etc.
* owncloud_dbname: owncloud
* owncloud_dbhost: localhost
* owncloud_dbuser: owncloud
* owncloud_dbpassword: owncloudmysql
Access and Installation Wizard
------------------------------
The ansible installation performs the Owncloud Wizard.
After the ansible installation completes, you can access Owncloud at http://schoolserve/owncloud.
The default admin user name and password are Admin / changeme.
Login and change the password. You can now add users and start sharing content.

View file

@ -0,0 +1,19 @@
owncloud_install: True
owncloud_enabled: False
owncloud_url: /owncloud
owncloud_prefix: /opt
owncloud_data_dir: /library/owncloud/data
owncloud_dl_url: https://download.owncloud.org/community/
owncloud_src_file: owncloud-9.0.2.tar.bz2
# we install on mysql with these setting or those from default_vars, etc.
owncloud_dbname: owncloud
owncloud_dbhost: localhost
owncloud_dbuser: owncloud
owncloud_dbpassword: owncloudmysql
owncloud_admin_user: 'Admin'
owncloud_admin_password: 'changeme'
owncloud_required_ip: 10.0.0.0/8 192.168.0.0/16

View file

@ -0,0 +1,11 @@
- name: Remove /etc/owncloud to avoid confusion as we use the config in {{ owncloud_prefix }}/owncloud/config/
file: path=/etc/owncloud
state=absent
# but we use the tar file to get the latest version; really only benefits the xo4 on fedora 18
- name: Get the owncloud software
get_url: url="{{ owncloud_dl_url }}"/{{ owncloud_src_file }} dest={{ downloads_dir }}/{{ owncloud_src_file }}
when: internet_available
- name: Copy it to permanent location /opt
unarchive: src={{ downloads_dir }}/{{ owncloud_src_file }} dest=/opt/

View file

@ -0,0 +1,124 @@
# we need to install the rpm in order to get the dependencies
# but we only need to do this the first time
- name: add a repo def for ubuntu
template: dest=/etc/apt/sources.list.d/
src=owncloud.list
when: is_ubuntu | bool
- name: See if the owncloud startup page exists
stat: path={{ owncloud_prefix }}/owncloud/index.php
register: owncloud_page
- name: Install owncloud package
package: name={{ item }}
state=present
with_items:
- curl
- owncloud
when: owncloud_page.stat.exists is defined and not owncloud_page.stat.exists
- name: Remove owncloud package
package: name=owncloud
state=absent
when: owncloud_page.stat.exists is defined and not owncloud_page.stat.exists
- name: remove config files for package
file: src=/etc/apache2/conf-available/owncloud.conf
dest=/etc/apache2/conf-enabled/owncloud.conf
state=absent
- name: remove config files for package
file: path=/etc/apache2/conf-available/owncloud.conf
state=absent
#- name: Remove /etc/owncloud to avoid confusion as we use the config in {{ owncloud_prefix }}/config/
# file: path=/etc/owncloud
# state=absent
# but we use the tar file to get the latest version
- name: Get the owncloud software
get_url: url={{ iiab_download_url }}/{{ owncloud_src_file }} dest={{ downloads_dir }}/{{ owncloud_src_file }}
when: internet_available | bool
async: 300
poll: 5
- name: Copy it to permanent location /opt
unarchive: src={{ downloads_dir }}/{{ owncloud_src_file }}
dest={{ owncloud_prefix }}
creates={{ owncloud_prefix }}/owncloud/version.php
when: not is_F18
# ansible 1.4.1 does not have "creates"
- name: Copy it to permanent location /opt
unarchive: src={{ downloads_dir }}/{{ owncloud_src_file }}
dest={{ owncloud_prefix }}
when: is_F18 | bool
- name: in Centos, the following config dir is symlink to /etc/owncloud
file: path=/etc/owncloud
state=directory
- name: Add autoconfig file
template: src=autoconfig.php.j2
dest={{ owncloud_prefix }}/owncloud/config/autoconfig.php
owner={{ apache_user }}
group=apache
mode=0640
- name: Make apache owner
file: path={{ owncloud_prefix }}/owncloud
owner={{ apache_user }}
group=apache
recurse=yes
state=directory
- name: Create data directory library
file: path={{ item }}
mode=0750
owner={{ apache_user }}
group=apache
state=directory
with_items:
- "{{ owncloud_data_dir }}"
- name: Create a mysql database for owncloud
mysql_db: name={{ owncloud_dbname }}
when: mysql_enabled and owncloud_enabled
- name: Create a user to access the owncloud database
mysql_user: name={{ owncloud_dbuser }} host={{ item }} password={{ owncloud_dbpassword }} priv={{ owncloud_dbname }}.*:ALL,GRANT
with_items:
- "{{ owncloud_dbhost }}"
- 127.0.0.1
- ::1
- localhost
when: mysql_enabled and owncloud_enabled
- name: Restart apache, so it picks up the new aliases
service: name={{ apache_service }} state=restarted
when: not owncloud_enabled
# Enable owncloud by copying template to httpd config
- include_tasks: owncloud_enabled.yml
when: owncloud_enabled | bool
- name: Add 'owncloud' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: owncloud
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: owncloud
- option: description
value: '"OwnCloud is a local server-based facility for sharing files, photos, contacts, calendars, etc."'
- option: path
value: "{{ owncloud_prefix }}/owncloud"
- option: source
value: "{{ owncloud_src_file }}"
- option: enabled
value: "{{ owncloud_enabled }}"

View file

@ -0,0 +1,35 @@
# This chould go in computed_network.yml, but here for now
- name: Compute owncloud listen ip addr for owncloud.conf
set_fact:
owncloud_required_ip: "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}"
when: ansible_default_ipv4.network is defined
- name: Enable owncloud by copying template to httpd config
template: src=owncloud.conf.j2
dest=/etc/{{ apache_config_dir }}/owncloud.conf
owner=root
group=root
mode=0644
- name: Enable owncloud
file: path=/etc/apache2/sites-enabled/owncloud.conf
src=/etc/apache2/sites-available/owncloud.conf
state=link
when: owncloud_enabled and is_debuntu
- name: Disable owncloud
file: path=/etc/apache2/sites-enabled/owncloud.conf
state=absent
when: not owncloud_enabled and is_debuntu
- name: Restart apache, so it picks up the new aliases
service: name={{ apache_service }} state=restarted
- name: Run owncloud initial install wizard
shell: curl http://{{ iiab_hostname }}{{ owncloud_url }}/index.php
- name: Remove Rewrite URL
lineinfile: regexp='overwrite.cli.url'
state=absent
dest="{{ owncloud_prefix }}/owncloud/config/config.php"

View file

@ -0,0 +1,28 @@
<?php
$AUTOCONFIG = array(
'directory' => '{{ owncloud_data_dir }}',
'trusted_domains' =>
array (
0 => '{{ iiab_hostname }}.{{ iiab_domain }}',
1 => "{{ iiab_hostname }}",
2 => 'localhost',
3 => 'internet-in-a-box.lan',
4 => 'internet-in-a-box',
5 => 'schoolserver.lan',
6 => 'schoolserver',
7 => 'school.lan',
8 => 'school',
9 => 'box.lan',
10 => 'box',
11 => '172.18.96.1',
),
'overwrite.cli.url' => 'http://{{ iiab_hostname }}.{{ iiab_domain }}/owncloud',
'dbtype' => 'mysql',
'dbname' => '{{ owncloud_dbname }}',
'dbhost' => '{{ owncloud_dbhost }}',
'dbtableprefix' => '',
'dbuser' => '{{ owncloud_dbuser }}',
'dbpass' => '{{ owncloud_dbpassword }}',
'adminlogin' => '{{ owncloud_admin_user }}',
'adminpass' => '{{ owncloud_admin_password }}',
);

View file

@ -0,0 +1,38 @@
Alias {{ owncloud_url }} {{ owncloud_prefix }}/owncloud
<Directory {{ owncloud_prefix }}/owncloud/>
Options -Indexes
<IfModule mod_authz_core.c>
# Apache 2.4
Require host localhost
Require ip 127.0.0.1 {{ lan_ip }}/{{ lan_netmask }} {{ owncloud_required_ip }}
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
Allow from ::1
</IfModule>
ErrorDocument 404 /core/templates/404.php
<IfModule mod_php5.c>
php_value upload_max_filesize 512M
php_value post_max_size 512M
php_value memory_limit 512M
php_value mbstring.func_overload 0
</IfModule>
SetEnv htaccessWorking true
<IfModule pagespeed_module>
ModPagespeed Off
</IfModule>
RewriteEngine on
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
RewriteRule ^\.well-known/carddav /remote.php/carddav/ [R]
RewriteRule ^\.well-known/caldav /remote.php/caldav/ [R]
</Directory>

View file

@ -0,0 +1 @@
deb https://download.owncloud.org/download/repositories/stable/Ubuntu_16.04/ /

View file

@ -0,0 +1,17 @@
---
# variables for pathagar
pathagar_subpath: /books
pathagar_dir: /usr/local/pathagar
pathagar_media: /library/pathagar/media
pathagar_src: '{{ pathagar_dir }}/pathagar'
pathagar_venv: '{{ pathagar_dir }}/venv'
pathagar_collectstatic: '{{ pathagar_dir }}/static'
pathagar_db_name: pathagar
pathagar_db_user: pathagar
pathagar_db_password: pathagar
pathagar_username: pathagar
pathagar_password: "pbkdf2_sha256$10000$qkA7MPkQWHTY$AO5j/ByLC68qEt8X1c9QvieArbadYKhiBnlKe8uR6G8="

View file

@ -0,0 +1,228 @@
- name: "Set PostgreSQL vars 'postgresql_install: True' and 'postgresql_enabled: True'"
set_fact:
postgresql_install: True
postgresql_enabled: True
- name: POSTGRESQL - run the 'postgresql' role
include_role:
name: postgresql
- name: Remove package Pathagar (in case rpm?)
package:
name: pathagar
state: absent
- name: "Install Pathagar prerequisites: python-virtualenv, python-pip, python-psycopg2"
package:
name: "{{ item }}"
state: present
with_items:
- python-virtualenv
- python-pip
- python-psycopg2
- name: "Install Pathagar prerequisites: libapache2-mod-wsgi, libxml2-dev, libxslt-dev (debuntu)"
package:
name: "{{ item }}"
state: present
with_items:
- libapache2-mod-wsgi
- libxml2-dev
- libxslt-dev
when: is_debuntu | bool
- name: "Install Pathagar prerequisites: mod_wsgi, libxml2-devel, libxslt-devel (not debuntu)"
package:
name: "{{ item }}"
state: present
with_items:
- mod_wsgi
- libxml2-devel
- libxslt-devel
when: not is_debuntu
- name: "Create destination folder: {{ pathagar_src }}"
file:
path: "{{ pathagar_src }}"
state: directory
# owner: root
# group: root
# mode: '0755'
- name: "Create books destination folder: {{ pathagar_media }}"
file:
path: "{{ pathagar_media }}"
state: directory
owner: "{{ apache_user }}"
group: "{{ apache_user }}"
mode: '0755'
- name: Determine if Pathagar has already been downloaded from git
stat:
path: "{{ pathagar_src }}/settings.py"
register: pathagar
- name: Clone Pathagar repo
git:
repo: https://github.com/PathagarBooks/pathagar.git
dest: "{{ pathagar_src }}"
update: yes
version: master
when: internet_available and pathagar.stat.exists is defined and not pathagar.stat.exists
- name: Install Pathagar requirements in a virtualenv
pip:
name: "{{ item }}"
with_items:
- Django==1.4.5
- django-tagging==0.3.1
- django-sendfile==0.3.6
- lxml==3.4.4
when: internet_available | bool
- name: Install Pathagar requirements in a virtualenv
pip:
name: "{{ item }}"
extra_args: "--use-wheel"
virtualenv: "{{ pathagar_venv }}"
virtualenv_site_packages: yes
with_items:
- django-taggit==0.14
- name: Create Pathagar postgresql user
postgresql_user:
name: "{{ pathagar_db_user }}"
password: "{{ pathagar_db_password }}"
role_attr_flags: NOSUPERUSER,NOCREATEROLE,NOCREATEDB
state: present
become: yes
become_user: postgres
- name: Start 'postgresql-iiab' systemd service
systemd:
name: postgresql-iiab
state: started
enabled: yes
when: pathagar_enabled
- name: Enable Pathagar postgresql user access by md5 method
lineinfile:
backup: yes
dest: /library/pgsql-iiab/pg_hba.conf
regexp: '^host\s+pathagar'
line: "host pathagar pathagar samehost md5"
state: present
insertafter: "^# IPv4 local connections"
owner: postgres
group: postgres
register: enable_pathagar_md5_access
- name: Reload 'postgresql-iiab' systemd service
systemd:
name: postgresql-iiab
state: reloaded
when: enable_pathagar_md5_access.changed
- name: Create Pathagar postgresql database
postgresql_db:
name: "{{ pathagar_db_name }}"
encoding: utf8
owner: "{{ pathagar_db_user }}"
state: present
template: template0
become: yes
become_user: postgres
- name: Install IIAB custom settings for Pathagar
template:
src: prod_settings.py
dest: "{{ pathagar_src }}/prod_settings.py"
# owner: root
# group: root
# mode: '0644'
- name: Create Pathagar initial db
django_manage:
app_path: "{{ pathagar_src }}"
command: syncdb
virtualenv: "{{ pathagar_venv }}"
settings: pathagar.prod_settings
- name: Upload Pathagar admin user
template:
src: auth.User.json
dest: "{{ pathagar_dir }}/auth.User.json"
owner: root
group: root
mode: '0600'
- name: Load Pathagar admin user
django_manage:
app_path: "{{ pathagar_src }}"
command: loaddata
virtualenv: "{{ pathagar_venv }}"
settings: pathagar.prod_settings
fixtures: "{{ pathagar_dir }}/auth.User.json"
- name: Collect Pathagar static files
django_manage:
app_path: "{{ pathagar_src }}"
command: collectstatic
virtualenv: "{{ pathagar_venv }}"
settings: pathagar.prod_settings
- name: Install wsgi.py for Pathagar
template:
src: wsgi.py
dest: "{{ pathagar_dir }}/wsgi.py"
# owner: root
# group: root
# mode: '0644'
- name: Install /etc/{{ apache_config_dir }}/pathagar.conf from template
template:
src: pathagar.conf
backup: yes
dest: "/etc/{{ apache_config_dir }}/pathagar.conf"
mode: 0644
- name: Enable Pathagar via Apache (debuntu)
file:
path: /etc/apache2/sites-enabled/pathagar.conf
src: /etc/apache2/sites-available/pathagar.conf
state: link
when: pathagar_enabled and is_debuntu
- name: Disable Pathagar via Apache (debuntu)
file:
path: /etc/apache2/sites-enabled/pathagar.conf
state: absent
when: not pathagar_enabled and is_debuntu
- name: Reload '{{ apache_service }}' systemd service
systemd:
name: "{{ apache_service }}"
state: reloaded
# if the only service using the backend db disable if not running
- name: Disable 'postgresql-iiab' systemd service, if not moodle_enabled and not pathagar_enabled
systemd:
name: postgresql-iiab
state: stopped
enabled: no
when: not moodle_enabled and not pathagar_enabled
- name: Add 'pathagar' variable values to {{ iiab_ini_file }}
ini_file:
path: "{{ iiab_ini_file }}"
section: pathagar
option: "{{ item.option }}"
value: "{{ item.value | string }}"
with_items:
- option: name
value: pathagar
- option: description
value: '"Pathagar is a simple bookserver serving OPDS feeds"'
- option: path
value: /books

View file

@ -0,0 +1,20 @@
[
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "{{ pathagar_username }}",
"first_name": "",
"last_name": "",
"is_active": true,
"is_superuser": true,
"is_staff": true,
"last_login": "2013-11-12T05:06:17.207",
"groups": [],
"user_permissions": [],
"password": "{{ pathagar_password }}",
"email": "{{ pathagar_username }}@{{ iiab_hostname }}.{{ iiab_domain }}",
"date_joined": "2013-11-12T05:06:17.207"
}
}
]

View file

@ -0,0 +1,30 @@
Alias {{ pathagar_subpath }}/static/ {{ pathagar_collectstatic }}/
Alias {{ pathagar_subpath }}/static_media/ {{ pathagar_media }}/
<Directory {{ pathagar_collectstatic }}>
Order deny,allow
Allow from all
Require all granted
</Directory>
<Directory {{ pathagar_media }}>
Order deny,allow
Allow from all
Require all granted
</Directory>
WSGIPythonPath {{ pathagar_dir }}:{{ pathagar_venv }}/lib/python2.7/site-packages
WSGIScriptAlias {{ pathagar_subpath }} {{ pathagar_dir }}/wsgi.py
<Directory {{ pathagar_dir }}>
<Files wsgi.py>
Order allow,deny
Allow from all
Require all granted
</Files>
</Directory>
CustomLog /var/log/{{ apache_service }}/pathagar-access.log combined
ServerSignature On

View file

@ -0,0 +1,22 @@
from settings import *
FORCE_SCRIPT_NAME = '{{ pathagar_subpath }}'
LOGIN_REDIRECT_URL = FORCE_SCRIPT_NAME
MEDIA_ROOT = '{{ pathagar_media }}'
MEDIA_URL = '{{ pathagar_subpath }}/static_media/'
SECRET_KEY = '7ks@b7+gi^c4adff)6ka228#rd4f62v*g_dtmo*@i62k)qn=cs'
DATABASES = {
'default': {
'ENGINE':'django.db.backends.postgresql_psycopg2',
'NAME': '{{ pathagar_db_name }}',
'USER': '{{ pathagar_db_user }}',
'PASSWORD': '{{ pathagar_db_password }}',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
STATIC_ROOT = '{{ pathagar_collectstatic }}'
STATIC_URL = '{{ pathagar_subpath }}/static/'

View file

@ -0,0 +1,11 @@
"""
WSGI config for pathagar project.
It exposes the WSGI callable as a module-level variable named ``application``.
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pathagar.prod_settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

View file

@ -0,0 +1,22 @@
=============
RACHEL README
=============
This is the second pass at adding RACHEL (http://www.rachel.worldpossible.org/) to IIAB.
It takes RACHEL in its entirety and the download must be copied manually.
This version is based on rachelusb_32EN_3.1.5.zip.
Do the following:
* Uuzip rachelusb_32EN_3.1.5.zip into /library. You should get /library/rachelusb_32EN_3.1.4.
* mkdir /library/rachel
* cd /library/rachel
* mv /library/rachelusb_32EN_3.1.4/RACHEL/bin .
* you should see /library/rachel/bin/www/index.php
* re-run ansible (making sure that rachel_enabled: True has been set in /etc/iiab/local_vars.yml
Locations
---------
- The RACHEL download is expected to be in /library/rachel
- The URL is /rachel

View file

@ -0,0 +1,11 @@
rachel_url: /rachel
rachel_content_path: /library/rachel/www
rachel_mysqldb_path: /library/rachel/bin/database/mysql-5.6.20/data/sphider_plus/
# These two must be in sync, second saves parsing
rachel_src_url: http://rachelfriends.org/downloads/public_ftp/rachelusb_32EN/rachelusb_32EN_3.1.5.zip
rachel_version: rachelusb_32EN_3.1.5
rachel_install: False
rachel_enabled: False
rachel_content_found: False

Some files were not shown because too many files have changed in this diff Show more