Compare commits

..

No commits in common. "master" and "last-alpine3.7" have entirely different histories.

760 changed files with 5683 additions and 94300 deletions

View File

@ -0,0 +1,13 @@
### Steps to reproduce
1.
2.
3.
### Expected behaviour
### Observed behaviour
### Additional data (ticket URL, log, timestamp, stack trace etc.)

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "app-vmmgr"]
path = apk/vmmgr
url = ssh://git@git.spotter.cz:2222/Spotter-Cluster/vmmgr.git
[submodule "spoc"]
path = apk/spoc
url = ssh://git@git.spotter.cz:2222/Spotter-Cluster/spoc.git

34
00-install.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/sh
# For production builds change to DEBUG=0 or comment the line entirely
export DEBUG=1
SOURCE_DIR=$(realpath $(dirname "${0}"))
# Install shared packages and perform OS customization
${SOURCE_DIR}/basic.sh
${SOURCE_DIR}/basic-runtimes.sh
# Install applications
${SOURCE_DIR}/ckan.sh
# ${SOURCE_DIR}/crisiscleanup.sh
# ${SOURCE_DIR}/cts.sh
${SOURCE_DIR}/frontlinesms.sh
${SOURCE_DIR}/gnuhealth.sh
${SOURCE_DIR}/kanboard.sh
${SOURCE_DIR}/mifosx.sh
${SOURCE_DIR}/motech.sh
${SOURCE_DIR}/opendatakit-build.sh
${SOURCE_DIR}/opendatakit.sh
${SOURCE_DIR}/openmapkit.sh
${SOURCE_DIR}/pandora.sh
${SOURCE_DIR}/sahana.sh
${SOURCE_DIR}/sambro.sh
${SOURCE_DIR}/seeddms.sh
${SOURCE_DIR}/sigmah.sh
${SOURCE_DIR}/ushahidi.sh
# Perform cleanup only if DEBUG environment variable is not set
if [ ${DEBUG:-0} -eq 0 ]; then
${SOURCE_DIR}/zz-cleanup.sh
fi

88
README.md Normal file
View File

@ -0,0 +1,88 @@
This is the main repository containing all installation scripts, configuration and customization of operating system all application present in Spotter Cluster virtual machine.
## Virtual machine specifications
- **Memory:** 4 GB
- **CPU:** 1 processor, 2 cores
- **Hard Disk:** SCSI, 60 GB
## Operating system installation
Download **Alpine Virtual 3.7.0 x86_64** from <https://alpinelinux.org/downloads/> and boot from it. At the login prompt, use the root user without password to log in.
```
# Set up interfaces (leave the default choices)
setup-interfaces
ifup eth0
# Download and launch the setup script
wget dl.dasm.cz/alpine.sh
sh alpine.sh
```
The script will perform the bare Alpine linux installation into VM using LUKS-on-LVM. The default disk encryption password is `password`. No root password is set.
## Application installation
### First time setup
```
# Install git
apk --no-cache add git
# Clone the repository
git clone https://gitlab.dasm.cz:8443/Spotter-Cluster/Spotter-Cluster.git
# Enter the repository directory
cd Spotter-Cluster
# Optional: Edit the install sequence script
vi 00-install.sh
# Launch the script
./00-install.sh
```
### Resuming from a snapshot
Assumes that the repository has already been cloned.
```
# Enter the repository directory
cd Spotter-Cluster
# Update repository
git pull
# Optional: Edit the install sequence script
vi 00-install.sh
# Launch the script
./00-install.sh
```
## Host assignment
| Application | Container | UID/GID | Internal Port | Host |
|-----------------|------------------:|--------:|-----------------:|----------|
| ActiveMQ | activemq | 61616 | 61616 (ActiveMQ) | - |
| CKAN | ckan | 8003 | 8080 (HTTP) | ckan |
| CKAN Datapusher | ckan-datapusher | 8004 | 8080 (HTTP) | - |
| Crisis Cleanup | crisiscleanup | 8005 | 8080 (HTTP) | cc |
| CTS | cts | 8006 | 8080 (HTTP) | cts |
| FrontlineSMS | frontlinesms | 8018 | 8080 (HTTP) | sms |
| GNU Health | gnuhealth | 8008 | 8080 (HTTP) | gh |
| KanBoard | kanboard | 8009 | 8080 (HTTP) | kb |
| MariaDB | mariadb | 3306 | 3306 (MySQL) | - |
| Mifos X | mifosx | 8012 | 8080 (HTTP) | mifosx |
| Motech | motech | 8013 | 8080 (HTTP) | motech |
| ODK Aggregate | opendatakit | 8015 | 8080 (HTTP) | odk |
| ODK Build | opendatakit-build | 8017 | 8080 (HTTP) | odkbuild |
| OpenMapKit | openmapkit | 8007 | 8080 (HTTP) | omk |
| Pan.do/ra | pandora | 8002 | 8080 (HTTP) | pandora |
| Postfix | postfix | 587 | 25 (SMTP) | - |
| Postgres | postgres | 5432 | 5432 (Postgres) | - |
| RabbitMQ | rabbitmq | 5672 | 5672 (AMQP) | - |
| Redis | redis | 6379 | 6379 (Redis) | - |
| Sahana | sahana | 8001 | 8080 (HTTP) | sahana |
| SAMBRO | sambro | 8001 | 8080 (HTTP) | sambro |
| SeedDMS | seeddms | 8010 | 8080 (HTTP) | dms |
| Sigmah | sigmah | 8011 | 8080 (HTTP) | sigmah |
| Solr | solr | 8983 | 8983 (HTTP) | - |
| Ushahidi | ushahidi | 8014 | 8080 (HTTP) | ush |

12
activemq.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
SOURCE_DIR=$(realpath $(dirname "${0}"))/activemq
# Build Docker container
docker build -t activemq ${SOURCE_DIR}
cp ${SOURCE_DIR}/etc/init.d/activemq /etc/init.d/activemq
rc-update -u
# Configure ActiveMQ
mkdir -p /srv/activemq/data
chown -R 61616:61616 /srv/activemq/data

23
activemq/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
FROM java
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Download and install ActiveMQ
wget http://archive.apache.org/dist/activemq/5.15.2/apache-activemq-5.15.2-bin.tar.gz -O /tmp/activemq.tgz \
&& tar xf /tmp/activemq.tgz -C /srv \
&& mv /srv/apache-activemq-5.15.2 /srv/activemq \
&& rm -f /tmp/activemq.tgz \
# Create OS user
&& addgroup -S -g 61616 activemq \
&& adduser -S -u 61616 -h /srv/activemq -s /bin/false -g activemq -G activemq activemq \
&& mkdir /srv/activemq/tmp \
&& chown activemq:activemq /srv/activemq/tmp \
# Configure Java heap size
&& sed -i "s/-Xms64M -Xmx1G/-Xms32M -Xmx256M/" /srv/activemq/bin/env
COPY docker/ /
VOLUME ["/srv/activemq/data"]
EXPOSE 61616
CMD ["s6-svscan", "/etc/services.d"]

View File

@ -0,0 +1,5 @@
#!/bin/execlineb -P
fdmove -c 2 1
s6-setuidgid 61616:61616
/srv/activemq/bin/activemq console

19
activemq/etc/init.d/activemq Executable file
View File

@ -0,0 +1,19 @@
#!/sbin/openrc-run
description="ActiveMQ docker container"
depend() {
need docker
}
start() {
/usr/bin/docker run -d --rm \
--name activemq \
-h activemq \
-v /srv/activemq/data:/srv/activemq/data \
activemq
}
stop() {
/usr/bin/docker stop activemq
}

100
alpine.sh Executable file
View File

@ -0,0 +1,100 @@
#!/bin/sh
# Prerequisites
# setup-interfaces
# ifup eth0
# Set up repositories
cat <<EOF >/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/v3.7/main
http://dl-cdn.alpinelinux.org/alpine/v3.7/community
#http://dl-cdn.alpinelinux.org/alpine/edge/main
#http://dl-cdn.alpinelinux.org/alpine/edge/community
#http://dl-cdn.alpinelinux.org/alpine/edge/testing
EOF
# Install disk management tools
apk --no-cache add lvm2 cryptsetup e2fsprogs syslinux
# Create disk partitions
cat <<EOF | fdisk /dev/sda
n
p
1
+100m
a
1
n
p
2
t
2
8e
w
EOF
# Set up partition encryption
echo -n 'password' | cryptsetup -q luksFormat /dev/sda2
echo -n 'password' | cryptsetup open --type luks /dev/sda2 system
# Set up LVM
pvcreate /dev/mapper/system
vgcreate vg0 /dev/mapper/system
lvcreate -L 4G vg0 -n swap
lvcreate -l 100%FREE vg0 -n root
# Format
mkfs.ext4 -m0 /dev/sda1
mkfs.ext4 -m1 /dev/vg0/root
mkswap /dev/vg0/swap
# Mount
mount -t ext4 /dev/vg0/root /mnt
mkdir /mnt/boot
mount -t ext4 /dev/sda1 /mnt/boot
# Install Alpine linux
setup-disk -m sys /mnt
# Update boot-time volume information
BOOT_UUID=$(blkid /dev/sda1 | awk '{print $2}' | tr -d '"')
cat <<EOF >/mnt/etc/fstab
/dev/vg0/root / ext4 rw,noatime,data=ordered 0 1
${BOOT_UUID} /boot ext4 rw,noatime,data=ordered 0 2
/dev/vg0/swap swap swap defaults 0 0
EOF
echo "system /dev/sda2 none luks" >/mnt/etc/crypttab
# Rebuild initfs
sed -i 's/lvm/lvm cryptsetup/' /mnt/etc/mkinitfs/mkinitfs.conf
mkinitfs -c /mnt/etc/mkinitfs/mkinitfs.conf -b /mnt $(ls /mnt/lib/modules)
# Update extlinux
sed -i 's/rootfstype=ext4/rootfstype=ext4 cryptroot=\/dev\/sda2 cryptdm=system/' /mnt/etc/update-extlinux.conf
chroot /mnt update-extlinux
# Set time zone
chroot /mnt setup-timezone -z Europe/Prague
# Set hostname
echo 'spottervm' >/mnt/etc/hostname
echo '127.0.0.1 spottervm localhost localhost.localdomain' >/mnt/etc/hosts
sed -i '/hostname/d' /mnt/etc/network/interfaces
# Enable services on boot
ln -s /etc/init.d/networking /mnt/etc/runlevels/boot
ln -s /etc/init.d/urandom /mnt/etc/runlevels/boot
# Install bootloader to MBR
dd bs=440 count=1 conv=notrunc if=/mnt/usr/share/syslinux/mbr.bin of=/dev/sda
# Unmount and shut down
umount /mnt/boot
umount /mnt
swapoff -a
vgchange -a n
cryptsetup luksClose system
poweroff

View File

@ -1,28 +0,0 @@
# Maintainer: Disassembler <disassembler@dasm.cz>
pkgname=py3-secure-cookie
_pkgname=secure-cookie
pkgver=0.1.0
pkgrel=0
pkgdesc="Secure cookie and session interface for WSGI applications"
url="https://secure-cookie.readthedocs.io/"
arch="noarch"
license="MIT"
depends="python3"
makedepends="py3-setuptools"
checkdepends="py3-pytest py3-werkzeug"
source="https://files.pythonhosted.org/packages/source/${_pkgname:0:1}/$_pkgname/$_pkgname-$pkgver.tar.gz"
builddir="$srcdir/$_pkgname-$pkgver"
build() {
python3 setup.py build
}
package() {
python3 setup.py install --prefix=/usr --root="$pkgdir"
}
check() {
PYTHONPATH=$PWD/build/lib pytest
}
sha512sums="2e57dba6f73ceb03eda33c804dbe2277c9fe700dd1be219bb3d8d43a5c9105c2323fb6b28d74d3a1dfc8fbbd938b91ab54d3e1bac1dc74490335b1d27e43b55a secure-cookie-0.1.0.tar.gz"

@ -1 +0,0 @@
Subproject commit 8c22df2e71de329a286e75af9bff69e82876db35

@ -1 +0,0 @@
Subproject commit 1c810db9472f50bd9dbe1e0f38df72590b120124

11
basic-runtimes.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
SOURCE_DIR=$(realpath $(dirname "${0}"))/basic-runtimes
# Build Docker images
docker build -t java ${SOURCE_DIR}/java
docker build -t php ${SOURCE_DIR}/php
docker build -t python2 ${SOURCE_DIR}/python2
docker build -t python3 ${SOURCE_DIR}/python3
docker build -t ruby ${SOURCE_DIR}/ruby
docker build -t tomcat ${SOURCE_DIR}/tomcat

View File

@ -0,0 +1,13 @@
FROM alpine
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install Java 1.8 JRE
apk --no-cache add openjdk8-jre-base paxctl \
# Fix grsec attributes to loosen memory protection restrictions
&& paxctl -cm /usr/lib/jvm/java-1.8-openjdk/bin/java \
&& paxctl -cm /usr/lib/jvm/java-1.8-openjdk/bin/keytool \
&& paxctl -cm /usr/lib/jvm/java-1.8-openjdk/jre/bin/java \
&& paxctl -cm /usr/lib/jvm/java-1.8-openjdk/jre/bin/keytool \
# Cleanup
&& apk --no-cache del paxctl

View File

@ -0,0 +1,6 @@
FROM alpine
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install PHP runtime
apk --no-cache add nginx php7 php7-ctype php7-fpm php7-gd php7-json php7-mbstring php7-mcrypt php7-opcache php7-session

View File

@ -0,0 +1,10 @@
FROM alpine
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install XML libs
apk --no-cache add libxml2 libxslt
RUN \
# Install Python2 runtime
apk --no-cache add python2

View File

@ -0,0 +1,11 @@
FROM alpine
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install XML libs
apk --no-cache add libxml2 libxslt
RUN \
# Install Python3 runtime
apk --no-cache add python3 \
&& ln -s /usr/bin/python3 /usr/bin/python

View File

@ -0,0 +1,33 @@
FROM alpine
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install Ruby runtime dependencies
apk --no-cache add gdbm libressl readline zlib
RUN \
# Install Ruby build dependencies
apk --no-cache add --virtual .deps build-base autoconf gdbm-dev libressl-dev linux-headers readline-dev zlib-dev \
# Download and unpack Ruby
&& wget http://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.6.tar.xz -O ruby.tar.xz \
&& mkdir -p /usr/src/ruby \
&& tar -xJf ruby.tar.xz -C /usr/src/ruby --strip-components=1 \
&& rm ruby.tar.xz \
&& cd /usr/src/ruby \
# Hackfix to suppress "Insecure world writable dir" warning
&& sed -ni 'p;13a #define ENABLE_PATH_CHECK 0' file.c \
# Configure compilation + hackfix to detect isnan/isinf macros
&& autoconf \
&& ac_cv_func_isnan=yes ac_cv_func_isinf=yes ./configure --build=x86_64-linux-musl --disable-install-doc --enable-shared \
# Compile and install Ruby
&& make -j $(nproc) \
&& make install \
# Install RubyGems and Bundler
&& mkdir -p /usr/local/etc \
&& echo -e 'install: --no-document\nupdate: --no-document' >/usr/local/etc/gemrc \
&& gem update --system \
# Cleanup
&& cd /tmp \
&& rm -r /usr/src/ruby \
&& apk --no-cache del .deps \
&& rm -rf /root/.gem

View File

@ -0,0 +1,15 @@
FROM java
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install Tomcat 8
wget http://mirror.hosting90.cz/apache/tomcat/tomcat-8/v8.0.51/bin/apache-tomcat-8.0.51.tar.gz -O /tmp/apache-tomcat-8.tgz \
&& tar xf /tmp/apache-tomcat-8.tgz -C /srv \
&& mv /srv/apache-tomcat-8.0.51 /srv/tomcat \
# Make catalina.sh available globally
&& ln -s /srv/tomcat/bin/catalina.sh /usr/bin/catalina.sh \
# Cleanup
&& rm -rf /srv/tomcat/webapps/ROOT /srv/tomcat/webapps/docs /srv/tomcat/webapps/examples /srv/tomcat/webapps/host-manager /srv/tomcat/webapps/manager \
&& rm -f /tmp/apache-tomcat-8.tgz
COPY docker/ /

64
basic.sh Executable file
View File

@ -0,0 +1,64 @@
#!/bin/sh
SOURCE_DIR=$(realpath $(dirname "${0}"))/basic
# Install packages
apk --no-cache add --virtual .useful curl git file htop libressl openssh-server openssh-sftp-server
apk --no-cache add docker gettext kbd-misc python2 nginx
# Copy profile files and settings
mkdir -p /root/.config/htop /root/.ssh
cp ${SOURCE_DIR}/root/.profile /root/.profile
cp ${SOURCE_DIR}/root/.ssh/authorized_keys /root/.ssh/authorized_keys
cp ${SOURCE_DIR}/root/.config/htop/htoprc /root/.config/htop/htoprc
# Copy boot configuration
cp ${SOURCE_DIR}/boot/extlinux.conf /boot/extlinux.conf
cp ${SOURCE_DIR}/boot/spotter.txt /boot/spotter.txt
cp ${SOURCE_DIR}/etc/inittab /etc/inittab
>/etc/motd
# Enable support for Czech characters
cp ${SOURCE_DIR}/etc/rc.conf /etc/rc.conf
cp ${SOURCE_DIR}/etc/conf.d/consolefont /etc/conf.d/consolefont
# Configure NTP client
cp ${SOURCE_DIR}/etc/conf.d/ntpd /etc/conf.d/ntpd
# Create a self-signed certificate
mkdir /etc/ssl/private
openssl req -x509 -new -out /etc/ssl/certs/services.pem -keyout /etc/ssl/private/services.key -nodes -days 7305 -subj "/CN=$(hostname)"
chmod 640 /etc/ssl/private/services.key
# Configure nginx
cp ${SOURCE_DIR}/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# Download and configure acme.sh
mkdir /etc/acme.sh.d
wget https://raw.githubusercontent.com/Neilpang/acme.sh/master/acme.sh -O /usr/bin/acme.sh
sed -i 's|$HOME/.$PROJECT_NAME|/etc/acme.sh.d|' /usr/bin/acme.sh
cp ${SOURCE_DIR}/etc/periodic/daily/acme-sh /etc/periodic/daily/acme-sh
chmod +x /usr/bin/acme.sh
# Copy Spotter resources
mkdir /etc/spotter
cp ${SOURCE_DIR}/srv/config.json /srv/config.json
cp ${SOURCE_DIR}/usr/bin/spotter-appmgr /usr/bin/spotter-appmgr
cp -r ${SOURCE_DIR}/srv/portal /srv/portal
# Configure services
for SERVICE in consolefont crond nginx ntpd sshd; do
rc-update add ${SERVICE} boot
service ${SERVICE} start
done
# Configure Docker service
cp ${SOURCE_DIR}/etc/init.d/docker /etc/init.d/docker
rc-update add docker
service docker start
# Create basic images
docker build -t alpine ${SOURCE_DIR}
# Set dummy domain and generate related files
spotter-appmgr update-domain spotter.vm 443

6
basic/Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM alpine:3.7
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install S6 supervisor
apk --no-cache add s6

9
basic/boot/extlinux.conf Normal file
View File

@ -0,0 +1,9 @@
DEFAULT vm
PROMPT 0
ALLOWOPTIONS 0
NOESCAPE 1
DISPLAY spotter.txt
LABEL vm
LINUX vmlinuz-virthardened
INITRD initramfs-virthardened
APPEND root=/dev/vg0/root modules=sd-mod,usb-storage,ext4 pax_nouderef quiet rootfstype=ext4 cryptroot=/dev/sda2 cryptdm=system

4
basic/boot/spotter.txt Normal file
View File

@ -0,0 +1,4 @@
Startuji SpotterVM...

1
basic/etc/conf.d/ntpd Normal file
View File

@ -0,0 +1 @@
NTPD_OPTS="-N -p tik.cesnet.cz -p tak.cesnet.cz"

40
basic/etc/init.d/docker Executable file
View File

@ -0,0 +1,40 @@
#!/sbin/openrc-run
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
command="${DOCKERD_BINARY:-/usr/bin/dockerd}"
pidfile="${DOCKER_PIDFILE:-/run/${RC_SVCNAME}.pid}"
command_args="-p \"${pidfile}\" ${DOCKER_OPTS}"
DOCKER_LOGFILE="${DOCKER_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
DOCKER_ERRFILE="${DOCKER_ERRFILE:-${DOCKER_LOGFILE}}"
DOCKER_OUTFILE="${DOCKER_OUTFILE:-${DOCKER_LOGFILE}}"
start_stop_daemon_args="--background \
--stderr \"${DOCKER_ERRFILE}\" --stdout \"${DOCKER_OUTFILE}\""
grsecdir=/proc/sys/kernel/grsecurity
depend() {
need sysfs
}
start_pre() {
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
for i in $disable_grsec; do
if [ -e "$grsecdir/$i" ]; then
einfo " Disabling $i"
echo 0 > "$grsecdir/$i"
fi
done
ulimit -n 1048576
# Having non-zero limits causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
ulimit -p unlimited
return 0
}
start_post() {
ewaitfile 1 /var/run/docker.sock
}

View File

@ -5,7 +5,7 @@
::wait:/sbin/openrc default >/dev/null 2>&1 ::wait:/sbin/openrc default >/dev/null 2>&1
# Set up getty # Set up getty
tty1::respawn:/sbin/getty -n -l /sbin/vmtty 38400 tty1 tty1::respawn:/sbin/getty -l /sbin/nologin 38400 tty1
# Stuff to do for the 3-finger salute # Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot ::ctrlaltdel:/sbin/reboot

View File

@ -15,17 +15,15 @@ http {
server_tokens off; server_tokens off;
client_max_body_size 100m; client_max_body_size 100m;
sendfile on; sendfile on;
tcp_nodelay on;
gzip_vary on; gzip_vary on;
charset utf-8; charset utf-8;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off; ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_certificate /etc/ssl/services.pem; ssl_prefer_server_ciphers on;
ssl_certificate_key /etc/ssl/services.key; ssl_certificate /etc/ssl/certs/services.pem;
ssl_session_timeout 1d; ssl_certificate_key /etc/ssl/private/services.key;
ssl_session_cache shared:SSL:1m; ssl_session_cache shared:SSL:1m;
ssl_session_tickets off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'; log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main; access_log /var/log/nginx/access.log main;

View File

@ -0,0 +1,3 @@
#!/bin/sh
[ -x /usr/bin/acme.sh ] && /usr/bin/acme.sh --cron >/dev/null

View File

@ -1,3 +1,2 @@
rc_cgroup_mode=unified
rc_tty_number=1
unicode="YES" unicode="YES"
rc_tty_number=1

2
basic/root/.profile Normal file
View File

@ -0,0 +1,2 @@
alias ll="ls -la"
alias view="vi"

View File

@ -0,0 +1,2 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILc3Mu7OlKrV7VqDQZ31vT3I3JJxtNNBiemUTRQVOZ3I Disassembler
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDMLx88cP67gOmmwDj2vjnPZnZp4KT/aqAkIEVBasss073wtU+tHAia5qKB+PJau3WnUSid/ZVcwHNXgrXE69DS2ZlBQFFBCJdWKP1Pd528Ot66mw9FaZvxRLaeA60yxC9dTFD0WCyVJw3HSdkJf17NYTtKcPQcn5DGfrdPHX16C3KUxOJXveTBOiieWbkQ1uUCTYyfeR9Qj+RR0gPogK217dNxGd4F3PJ3hXPKWDVpSH9JBnpG64mab3krhb6/eMUnLPUUAtgF6b0vXWNahFlA3NsriQiJy5mroLQCL2feqfkGVKlbxpRwgkGOPph4UK6RgNehF7oPwni/zMQ2rjxbpIWredlOPNvU7F8BebiuU8K4/16tz6xRiSgYzpm9nTHvJaz3W12b8Co145zPcmIdRg5KCQDEf+xB7gfpK/uo3qmc7ddMtA4oqUztbAlpfW6qR+i4X5ed9LnWdMKoWeB5Xn52cbKuTvD1qmVWGm0IPF/r+hw7Gn97nyq1Oatn9LKTJaLZeaJ9b1nBGL56U5i+4hdZPema7tVgWEYfYKTq4hrKWdWwJjlpJjqZ2qLltJmkJMNji9Ve+xBe+nRjW9wNk7c7fDxPvJe45EbrqDQNFxXjw4CKOIIt/k6e/imrVf9S7Or4Vxi+OJCQLZYT8EPb/VUuPn0JhtpIlBvD3xCDjw== vampola.karel@gmail.com

134
basic/srv/config.json Normal file
View File

@ -0,0 +1,134 @@
{
"apps":{
"ckan":{
"host":"ckan",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"crisiscleanup":{
"host":"cc",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"cts":{
"host":"cts",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"frontlinesms":{
"host":"sms",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"gnuhealth":{
"host":"gh",
"login":"N/A",
"password":"N/A",
"tiles":["gnuhealth-clients"],
"tiles-shown":false
},
"kanboard":{
"host":"kb",
"login":"N/A",
"password":"N/A",
"tiles":["kanboard-mobile"],
"tiles-shown":false
},
"mifosx":{
"host":"mifosx",
"login":"N/A",
"password":"N/A",
"tiles":["mifosx-mobile"],
"tiles-shown":false
},
"motech":{
"host":"motech",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"opendatakit":{
"host":"odk",
"login":"N/A",
"password":"N/A",
"tiles":["opendatakit-clients"],
"tiles-shown":false
},
"opendatakit-build":{
"host":"odkbuild",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"openmapkit":{
"host":"omk",
"login":"N/A",
"password":"N/A",
"tiles":["geoodk-clients", "openmapkit-clients"],
"tiles-shown":false
},
"pandora":{
"host":"pandora",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"sahana":{
"host":"sahana",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"sahana-demo":{
"host":"sahana-demo",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"sambro":{
"host":"sambro",
"login":"N/A",
"password":"N/A",
"tiles":["sambro-mobile"],
"tiles-shown":false
},
"seeddms":{
"host":"dms",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"sigmah":{
"host":"sigmah",
"login":"N/A",
"password":"N/A",
"tiles":[],
"tiles-shown":false
},
"ushahidi":{
"host":"ush",
"login":"N/A",
"password":"N/A",
"tiles":["ushahidi-mobile"],
"tiles-shown":false
}
},
"host":{
"domain":"spotter.vm",
"port": "443"
}
}

View File

@ -0,0 +1,86 @@
* {
margin: 0;
padding: 0;
border: 0;
}
body {
font-family: 'Calibri', 'Verdana', 'Tahoma', sans-serif;
background-color: silver;
color: black;
line-height: 150%;
margin: 25px 30px;
}
a {
text-decoration: none;
}
h1, h2 {
font-size: 150%;
font-weight: normal;
}
h2 a {
color: inherit;
}
h2 img {
float: right;
margin-left: 10px;
margin-bottom:10px;
width: 100px;
height: 100px;
}
ul {
margin-left: 30px;
}
header {
color: white;
}
header h1 {
font-weight: bold;
}
header p {
padding: 0px;
margin: 0px;
}
.c {
background-color: white;
position: relative;
min-width: 365px;
max-width: 365px;
width: 90%;
float: left;
min-height: 175px;
margin-top: 13px;
margin-right: 13px;
border: solid 1px black;
padding: 10px;
display: none;
}
.c2 {
max-width: 765px;
width: 95%;
}
.visible {
display: initial;
}
.ico {
margin-right: 5px;
width: 20px;
height: 20px;
vertical-align: top;
}
.cleaner {
clear: both;
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8">
<meta name="author" content="TS">
<meta name="copyright" content="page is under CC BY-NC-ND 3.0 CZ">
<meta name="generator" content="Spotter.ngo">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chyba</title>
</head>
<body>
<h1>Chyba spojení</h1>
<p>Aplikace ke které se pokoušíte připojit není dostupná. Nejspíše byla vypnuta správcem serveru.</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

308
basic/srv/portal/index.html Normal file
View File

@ -0,0 +1,308 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8">
<meta name="author" content="TS">
<meta name="copyright" content="page is under CC BY-NC-ND 3.0 CZ">
<meta name="generator" content="Spotter.ngo">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cluster NGO</title>
<link rel="icon" href="img/cluster_spotter.png" type="image/png">
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen">
<script src="js/jquery-3.3.1.min.js" type="text/javascript"></script>
<script src="js/script.js" type="text/javascript"></script>
</head>
<body>
<header>
<h1>CLUSTER NGO</h1>
<p>Sada softwarových nástrojů určená pro krizový management.</p>
</header>
<div class="c c2" id="sahana">
<h2><a href="https://sahana.{host}/eden/"><img src="img/EDEN.png" alt="Sahana EDEN" title="Sahana EDEN">Sahana EDEN</a></h2>
<p><strong>Registr kontaktů</strong> asociací, organizací, jednotek zaměstnanců, dobrovolníků, <strong>Registr prostředků</strong>, materiálních zdrojů určených pro činnost v krizových situacích, <strong>logistika</strong> krizového zboží ve skladištích, úkrytech, <strong>organizace lidských zdrojů</strong>, diobrovolníků, <strong>mapová vizualizace</strong> pro lokalizaci a popis krizové události a <strong>mnoho dalších funkcí</strong>.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="sahana-demo">
<h2><a href="https://sahana-demo.{host}/eden/"><img src="img/EDEN.png" alt="Sahana EDEN DEMO" title="Sahana EDEN DEMO">Sahana EDEN DEMO</a></h2>
<p>Přístup určený k bezpečnému vyzkoušení aplikace. Zde můžete přidávat i mazat testovací data.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="sambro">
<h2><a href="https://sambro.{host}/eden/"><img src="img/EDEN.png" alt="Sahana EDEN SAMBRO" title="Sahana EDEN SAMBRO">Sahana EDEN SAMBRO</a></h2>
<p>Samostatná instance Sahana EDEN s šablonou SAMBRO.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="sambro-mobile">
<h2><a href="#"><img src="img/EDEN.png" alt="SAMBRO Mobile" title="SAMBRO Mobile">SAMBRO Mobile</a></h2>
<p>Mobilní klient k aplikaci Sahana EDEN.<br>
<a href="https://itunes.apple.com/us/app/sambro-mobile/id1127251669"><img src="img/ios.png" class="ico" alt="IOS">IOS 6.0 a vyšší</a><br>
<a href="https://play.google.com/store/apps/details?id=io.sahana.sambro.mobile"><img src="img/android.png" class="ico" alt="Android">Android 4.0 a vyšší</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">https://sambro.{host}/eden/</span></li>
</ul>
</div>
<div class="c" id="crisiscleanup">
<h2><a href="https://cc.{host}"><img src="img/Crisis_Cleanup.png" alt="Crisis Cleanup" title="Crisis Cleanup">Crisis Cleanup</a></h2>
<p><strong>Mapování krizové pomoci</strong> při odstraňování následků katastrof a koordinaci práce. Jde o majetek, ne o lidi.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="ckan">
<h2><a href="https://ckan.{host}"><img src="img/CKAN.png" alt="CKAN" title="CKAN">CKAN</a></h2>
<p><strong>Repository</strong> management a datová analýza pro vytváření otevřených dat.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="opendatakit-build">
<h2><a href="https://odkbuild.{host}"><img src="img/ODK.png" alt="Open Data Kit" title="Open Data Kit">ODK Build</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.<br>Aplikace pro návrh formulářů<br>
<p><a href="http://opendatakit.org/xiframe/">XLSForm</a> - online konverter XLS.<br>
<a href="https://opendatakit.org/downloads/download-info/odk-formuploader/"><img src="img/java.png" class="ico" alt="ODK Form Uploader">ODK Form Uploader</a><br>
<a href="https://opendatakit.org/downloads/download-info/odk-validate-2/"><img src="img/java.png" class="ico" alt="ODK Validate">ODK Validate</a></p>
</div>
<div class="c" id="opendatakit-clients">
<h2><a href="#"><img src="img/ODK_Collect.png" alt="Open Data Kit" title="Open Data Kit">ODK Collect</a></h2>
<p>Mobilní aplikace<br>
<a href="https://play.google.com/store/apps/details?id=org.odk.collect.android"><img src="img/android.png" class="ico" alt="ODK Collect">ODK Collect pro Android</a><br>
<a href="https://opendatakit.org/downloads/download-info/odk-briefcase/"><img src="img/java.png" class="ico" alt="ODK Briefcase">ODK Briefcase</a><br>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">https://odk.{host}</span></li>
</ul>
</div>
<div class="c" id="opendatakit">
<h2><a href="https://odk.{host}/"><img src="img/ODK.png" alt="Open Data Kit" title="Open Data Kit">ODK Aggregate</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.<br>
<a href="http://geoodk.com">GeoODK Collect</a> - náhrada papírových dotazníků smartphonem.
</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="openmapkit">
<h2><a href="https://omk.{host}"><img src="img/OMK.png" alt="Open Map Kit" title="Open Map Kit">OpenMapKit Server</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.<br>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="geoodk-clients">
<h2><a href="#"><img src="img/GeoODK_Collect.png" alt="GeoODK Collect" title="GeoODK Collect">GeoODK Collect</a></h2>
<p>Mobilní aplikace<br>
<a href="https://play.google.com/store/apps/details?id=com.geoodk.collect.android"><img src="img/android.png" class="ico" alt="GeoODK Collect">GeoODK Collect pro Android</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">https://omk.{host}</span></li>
</ul>
</div>
<div class="c" id="openmapkit-clients">
<h2><a href="#"><img src="img/OMK.png" alt="Open Map Kit" title="Open Map Kit">OpenMapKit</a></h2>
<p>Mobilní aplikace<br>
<a href="https://play.google.com/store/apps/details?id=org.odk.collect.android"><img src="img/android.png" class="ico" alt="ODK Collect">ODK Collect pro Android</a><br>
<a href="https://play.google.com/store/apps/details?id=org.redcross.openmapkit"><img src="img/android.png" class="ico" alt="Android">OpenMapKit pro Android 4.1 a vyšší</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">https://omk.{host}</span></li>
</ul>
</div>
<div class="c" id="frontlinesms">
<h2><a href="https://sms.{host}"><img src="img/FrontlineSMS.png" alt="FrontlineSMS" title="FrontlineSMS">FrontlineSMS</a></h2>
<p><strong>SMS messaging</strong> přes veřejné datové brány</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="seeddms">
<h2><a href="https://dms.{host}"><img src="img/SeedDMS.png" alt="SeedDMS" title="SeedDMS">SeedDMS</a></h2>
<p><strong>Dokument management</strong> na dokumentaci a projektovou dokumentaci</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="pandora">
<h2><a href="https://pandora.{host}"><img src="img/Pandora.png" alt="Pan.do/ra" title="Pan.do/ra">Pan.do/ra</a></h2>
<p><strong>Media management</strong> na foto a video z krizové události. Tvorba metadat, komentářů, lokalizace v čase a na mapě.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="ushahidi">
<h2><a href="https://ush.{host}"><img src="img/Ushahidi.png" alt="Ushahidi" title="Ushahidi">Ushahidi</a></h2>
<p>Reakce na krizovou událost. Shromažďujte zprávy od obětí a pracovníků v terénu prostřednictvím SMS, e-mailu, webu, Twitteru.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="ushahidi-mobile">
<h2><a href="#"><img src="img/Ushahidi_mobile.png" alt="Ushahidi" title="Ushahidi">Ushahidi Mobile</a></h2>
<p>Mobilní aplikace Ushahidi pro<br>
<a href="https://itunes.apple.com/us/app/ushahidi-mobile/id1205994516?mt=8"><img src="img/ios.png" class="ico" alt="IOS">IOS 9.0 a vyšší</a><br>
<a href="https://play.google.com/store/apps/details?id=com.ushahidi.mobile"><img src="img/android.png" class="ico" alt="Android">Android 4.4 a vyšší</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">ushahidi.{host}</span></li>
</ul>
</div>
<div class="c" id="sms-sync-gateway">
<h2><a href="#"><img src="img/SMS_Sync.png" alt="SMS Sync Gateway" title="SMS Sync Gateway">SMS Sync Gateway</a></h2>
<p>Mobilní aplikace pro<br>
<a href="https://play.google.com/store/apps/details?id=org.addhen.smssync"><img src="img/android.png" class="ico" alt="Android">Android 2.3 a vyšší</a>
</p>
</div>
<div class="c" id="kanboard">
<h2><a href="https://kb.{host}"><img src="img/Kanboard.png" alt="Kanboard" title="Kanboard">Kanboard</a></h2>
<p>Usnadňuje tvorbu a řízení projektů s pomocí Kanban metodiky.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="kanboard-mobile">
<h2><a href="#"><img src="img/Kanboard.png" alt="Kanboard" title="Kanboard">Kanboard Mobile</a></h2>
<p>Mobilní aplikace<br>
<a href="https://play.google.com/store/apps/details?id=eu.it_quality.kanboard"><img src="img/android.png" class="ico" alt="KanBoard">KanBoard client pro Android 4.1 a vyšší</a><br>
<a href="https://f-droid.org/packages/in.andres.kandroid/"><img src="img/android.png" class="ico" alt="Android">Kandroid pro Android 4.2 a vyšší</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">https://kb.{host}</span></li>
</ul>
</div>
<div class="c" id="cts">
<h2><a href="https://cts.{host}"><img src="img/CTS.png" alt="CTS" title="CTS">CTS</a></h2>
<p>Logistika hmotné pomoci pro humanitární potřeby.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="gnuhealth">
<h2><a href="https://gh.{host}/index.html"><img src="img/GNU_Health.png" alt="GNU Health" title="GNU Health">GNU Health</a></h2>
<p>Zdravotní a nemocniční informační systém.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
<li><strong>Heslo k demu:</strong> <span class="demopassword">gnusolidario</span></li>
</ul>
</div>
<div class="c" id="gnuhealth-clients">
<h2><a href="#"><img src="img/GNU_Health.png" alt="GNU Health" title="GNU Health">GNU Health klienti</a></h2>
<p>Klientské aplikace platformy Tryton GNU Health pro<br>
<a href="https://downloads.tryton.org/4.2/tryton-last.exe"><img src="img/Windows.png" class="ico" alt="Windows">Windows</a><br>
<a href="https://downloads.tryton.org/4.2/tryton-last.dmg"><img src="img/MacOS.png" class="ico" alt="MacOS">MacOS</a><br>
<a href="https://downloads.tryton.org/4.2/tryton-last.tar.gz"><img src="img/Linux.png" class="ico" alt="Linux">Linux</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">gh.{host}</span></li>
</ul>
</div>
<div class="c" id="sigmah">
<h2><a href="https://sigmah.{host}/sigmah/"><img src="img/Sigmah.png" alt="Sigmah" title="Sigmah">Sigmah</a></h2>
<p>Rozpočtování získávání finančních prostředků.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="motech">
<h2><a href="https://motech.{host}/"><img src="img/Motech.png" alt="Motech" title="Motech">Motech</a></h2>
<p>Integrace zdravotnických a komunikačních služeb.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="mifosx">
<h2><a href="https://mifosx.{host}/"><img src="img/MifosX.png" alt="Mifos X" title="Mifos X">Mifos X</a></h2>
<p>Nástroj na rozvojovou, humanitární pomoc a mikrofinancování.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="mifosx-mobile">
<h2><a href="#"><img src="img/MifosX_Mobile.png" alt="Mifos X" title="Mifos X">Mifos X</a></h2>
<p>Mobilní aplikace<br>
<a href="https://play.google.com/store/apps/details?id=com.mifos.mifosxdroid"><img src="img/android.png" class="ico" alt="KanBoard">Mifos X client pro Android 3.0 a vyšší</a><br>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">mifosx.{host}</span></li>
<li><strong>Tenant ID:</strong> <span>default</span></li>
</ul>
</div>
<div class="c" id="diaspora">
<h2><a href="#"><img src="img/Diaspora.png" alt="diaspora*" title="diaspora*">diaspora*</a></h2>
<p>Autonomní sociání síť s možností propojení do cizích sociálních sítí.</p>
<ul>
<li><strong>Login:</strong> <span class="login"></span></li>
<li><strong>Heslo:</strong> <span class="password"></span></li>
</ul>
</div>
<div class="c" id="openid">
<h2><a href="http://openid.net"><img src="img/OpenID.png" alt="OpenID" title="OpenID">OpenID</a></h2>
<p>Pro ověření identity budete potřebovat účet OpenID. Zaregistrujte se. Registraci využijete v software Sahana EDEN.</p>
</div>
<div class="c" id="posm">
<h2><a href="#"><img src="img/POSM.png" alt="POSM" title="POSM">POSM</a></h2>
<p><strong>Portable Open Street Map</strong> - softwarový balík na offline používání OpenStreet Map v samostatné virtuální image.</p>
</div>
<div class="c visible" id="cluster-spotter">
<h2><a href="http://spotter.ngo"><img src="img/cluster_spotter.png" alt="Cluster Spotter" title="Cluster Spotter">Cluster Spotter</a></h2>
<p>Info o Misi a Vizi projektu, včetně kontaktu. Zachovejte data bezpečná a neposkytujte je nepovolaným osobám.<br>
<small>CC 4.0 CZ by <a href="http://trendspotter.cz">TS</a>. Content is based on PD, CC, GNU/GPL. Brand names, trademarks belong to their respective holders.</small>
</p>
</div>
<div class="cleaner"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
$(function() {
$.getJSON('config.json', function(data) {
$.each(data.apps, function(app, appdata) {
if (!appdata['tiles-shown'])
return true;
var div = $('#'+app).show();
div.find('.login').text(appdata.login);
div.find('.password').text(appdata.password);
$.each(appdata.tiles, function(idx, tile) {
$('#'+tile).show();
});
});
var host = data.host.domain + (data.host.port != '443' ? ':'+data.host.port : '')
$('a').each(function(){
$(this).attr('href', $(this).attr('href').replace('{host}', host));
});
$('span').each(function(){
$(this).text($(this).text().replace('{host}', host));
});
});
});

318
basic/usr/bin/spotter-appmgr Executable file
View File

@ -0,0 +1,318 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import argparse
import json
import os
import subprocess
CONF_FILE = '/srv/config.json'
DISCARD_IP = '[100::1]'
ISSUE_FILE = '/etc/issue'
NGINX_DIR = '/etc/nginx/conf.d'
NGINX_TEMPLATE = '''server {{
listen [::]:{port} ssl http2;
server_name {host}.{domain};
access_log /var/log/nginx/{app}.access.log;
error_log /var/log/nginx/{app}.error.log;
location / {{
proxy_pass http://{ip}:8080;
}}
error_page 502 /error.html;
location /error.html {{
root /srv/portal;
}}
}}
'''
NGINX_DEFAULT_TEMPLATE = '''server {{
listen [::]:80 default_server ipv6only=off;
location / {{
return 301 https://$host:{port}$request_uri;
}}
location /.well-known/acme-challenge/ {{
root /etc/acme.sh.d;
}}
}}
server {{
listen [::]:{port} ssl http2 default_server ipv6only=off;
root /srv/portal;
index index.html;
location / {{
try_files $uri $uri/ =404;
}}
location /config.json {{
alias /srv/config.json;
}}
}}
'''
ISSUE_TEMPLATE = '''
\x1b[1;32m _____ _ _ __ ____ __
/ ____| | | | | \\\\ \\\\ / / \\\\/ |
| (___ _ __ ___ | |_| |_ ___ _ _\\\\ \\\\ / /| \\\\ / |
\\\\___ \\\\| '_ \\\\ / _ \\\\| __| __/ _ \\\\ '__\\\\ \\\\/ / | |\\\\/| |
____) | |_) | (_) | |_| || __/ | \\\\ / | | | |
|_____/| .__/ \\\\___/ \\\\__|\\\\__\\\\___|_| \\\\/ |_| |_|
| |
|_|\x1b[0m
\x1b[1;33mUPOZORNĚNÍ:\x1b[0m Neoprávněný přístup k tomuto zařízení je zakázán.
Musíte mít výslovné oprávnění k přístupu nebo konfiguraci tohoto zařízení.
Neoprávněné pokusy a kroky k přístupu nebo používání tohoto systému mohou mít
za následek občanské nebo trestní sankce.
\x1b[1;33mCAUTION:\x1b[0m Unauthozired access to this device is prohibited.
You must have explicit, authorized permission to access or configure this
device. Unauthorized attempts and actions to access or use this system may
result in civil or criminal penalties.
Pro přístup k aplikacím otevřete URL \x1b[1mhttps://{host}\x1b[0m ve Vašem
internetovém prohlížeči.
\x1b[0;30m
'''
class SpotterManager:
def __init__(self):
# Load JSON configuration
with open(CONF_FILE, 'r') as f:
self.conf = json.load(f)
self.domain = self.conf['host']['domain']
self.port = self.conf['host']['port']
def save_conf(self):
# Save a sorted JSON configuration object with indentation
with open(CONF_FILE, 'w') as f:
json.dump(self.conf, f, sort_keys=True, indent=4)
def update_login(self, app, login, password):
# Update login and password for an app in the configuration
if login is not None:
self.conf['apps'][app]['login'] = login
if password is not None:
self.conf['apps'][app]['password'] = password
self.save_conf()
def show_tiles(self, app):
# Update tiles-shown for the app in the configuration
self.conf['apps'][app]['tiles-shown'] = True
self.save_conf()
def hide_tiles(self, app):
# Update tiles-shown for the app in the configuration
self.conf['apps'][app]['tiles-shown'] = False
self.save_conf()
def start_app(self, app):
# Start the actual app service
subprocess.call(['/sbin/service', app, 'start'])
def stop_app(self, app):
# Stop the actual app service
subprocess.call(['/sbin/service', app, 'stop'])
# Stop the app service's dependencies if they are not used by another running app
deps = self.build_deps_tree()
for dep in self.get_app_deps(app):
if not any([self.is_app_started(d) for d in deps[dep]]):
subprocess.call(['/sbin/service', dep, 'stop'])
def build_deps_tree(self):
# Fisrt, build a dictionary of {app: [needs]}
needs = {}
for app in self.conf['apps']:
needs[app] = self.get_app_deps(app)
# Then reverse it to {need: [apps]}
deps = {}
for app, need in needs.iteritems():
for n in need:
deps.setdefault(n, []).append(app)
return deps
def get_app_deps(self, app):
# Get "needs" line from init script and split it to list, skipping first two elements (docker, net)
try:
with open(os.path.join('/etc/init.d', app), 'r') as f:
return [l.split()[2:] for l in f.readlines() if l.startswith('\tneed')][0]
except:
return []
def is_app_started(self, app):
# Check OpenRC service status without calling any binary
return os.path.exists(os.path.join('/run/openrc/started', app))
def enable_autostart(self, app):
# Add the app to OpenRC default runlevel
subprocess.call(['/sbin/rc-update', 'add', app])
def disable_autostart(self, app):
# Remove the app from OpenRC default runlevel
subprocess.call(['/sbin/rc-update', 'del', app])
def register_proxy(self, app):
# Rebuild nginx configuration using IP of referenced app container and reload nginx
self.update_proxy_conf(app, self.get_container_ip(app))
subprocess.call(['/sbin/service', 'nginx', 'reload'])
def update_proxy_conf(self, app, ip):
with open(os.path.join(NGINX_DIR, '{}.conf'.format(app)), 'w') as f:
f.write(NGINX_TEMPLATE.format(app=app, host=self.conf['apps'][app]['host'], ip=ip, domain=self.domain, port=self.port))
def unregister_proxy(self, app):
# Remove nginx configuration to prevent proxy mismatch when the container IP is reassigned to another container
self.update_proxy_conf(app, DISCARD_IP)
subprocess.call(['/sbin/service', 'nginx', 'reload'])
def get_container_ip(self, app):
# Return an IP address of a container. If the container is not running, return address from IPv6 discard prefix instead
try:
return subprocess.check_output(['/usr/bin/docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}', app]).strip()
except:
return DISCARD_IP
def update_domain(self, domain, port):
self.domain = self.conf['host']['domain'] = domain
self.port = self.conf['host']['port'] = port
self.save_conf()
self.rebuild_nginx()
self.rebuild_issue()
self.restart_apps()
def rebuild_nginx(self):
# Rebuild nginx config for the portal app
with open(os.path.join(NGINX_DIR, 'default.conf'), 'w') as f:
f.write(NGINX_DEFAULT_TEMPLATE.format(port=self.port))
# Unregister nginx proxy for apps (will be repopulated on app restart)
for app in self.conf['apps']:
self.update_proxy_conf(app, DISCARD_IP)
# Restart nginx to properly bind the new listen port
subprocess.call(['/sbin/service', 'nginx', 'restart'])
def rebuild_issue(self):
# Compile the HTTPS host displayed in terminal banner
host = self.domain
# If the dummy host is used, take an IP address of a primary interface instead
if self.domain == 'spotter.vm':
host = subprocess.check_output(['/sbin/ip', 'route', 'get', '1']).split()[-1]
# Show port number only when using the non-default HTTPS port
if self.port != '443':
host += ':{}'.format(self.port)
# Rebuild the terminal banner
with open(ISSUE_FILE, 'w') as f:
f.write(ISSUE_TEMPLATE.format(host=host))
def restart_apps(self):
for app in self.conf['apps']:
# Check if a script for internal update of URL in the app exists and is executable and run it
script_path = os.path.join('/srv', app, 'update-url.sh')
if os.path.exists(script_path) and os.access(script_path, os.X_OK):
subprocess.call([script_path, '{}.{}'.format(self.conf['apps'][app]['host'], self.domain), self.port])
# If the app is currently running, restart the app service
if self.is_app_started(app):
subprocess.call(['/sbin/service', app, 'restart'])
def request_cert(self, email):
# Compile an acme.sh command for certificate requisition
cmd = ['/usr/bin/acme.sh', '--issue', '-d', self.domain]
for app in self.conf['apps']:
cmd += ['-d', '{}.{}'.format(self.conf['apps'][app]['host'], self.domain)]
cmd += ['-w', '/etc/acme.sh.d', '--accountemail', email]
# Request the certificate. If the requisition command fails, CalledProcessError will be raised
subprocess.check_output(cmd, stderr=subprocess.STDOUT)
# Install the issued certificate
subprocess.call(['/usr/bin/acme.sh', '--installcert', '-d', self.domain, '--keypath', '/etc/ssl/private/services.key', '--fullchainpath', '/etc/ssl/certs/services.pem', '--reloadcmd', 'service nginx reload'])
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Spotter VM application manager')
subparsers = parser.add_subparsers()
parser_update_login = subparsers.add_parser('update-login', help='Updates application login')
parser_update_login.set_defaults(action='update-login')
parser_update_login.add_argument('app', help='Application name')
parser_update_login.add_argument('login', help='Administrative login')
parser_update_login.add_argument('password', help='Administrative password')
parser_show_tiles = subparsers.add_parser('show-tiles', help='Shows application tiles in Portal')
parser_show_tiles.set_defaults(action='show-tiles')
parser_show_tiles.add_argument('app', help='Application name')
parser_hide_tiles = subparsers.add_parser('hide-tiles', help='Hides application tiles in Portal')
parser_hide_tiles.set_defaults(action='hide-tiles')
parser_hide_tiles.add_argument('app', help='Application name')
parser_start_app = subparsers.add_parser('start-app', help='Start application including it\'s dependencies')
parser_start_app.set_defaults(action='start-app')
parser_start_app.add_argument('app', help='Application name')
parser_stop_app = subparsers.add_parser('stop-app', help='Stops application including it\'s dependencies if they are not used by another running application')
parser_stop_app.set_defaults(action='stop-app')
parser_stop_app.add_argument('app', help='Application name')
parser_enable_autostart = subparsers.add_parser('enable-autostart', help='Enables application autostart')
parser_enable_autostart.set_defaults(action='enable-autostart')
parser_enable_autostart.add_argument('app', help='Application name')
parser_disable_autostart = subparsers.add_parser('disable-autostart', help='Disables application autostart')
parser_disable_autostart.set_defaults(action='disable-autostart')
parser_disable_autostart.add_argument('app', help='Application name')
parser_register_proxy = subparsers.add_parser('register-proxy', help='Rebuilds nginx proxy target for an application container')
parser_register_proxy.set_defaults(action='register-proxy')
parser_register_proxy.add_argument('app', help='Application name')
parser_unregister_proxy = subparsers.add_parser('unregister-proxy', help='Removes nginx proxy target for an application container')
parser_unregister_proxy.set_defaults(action='unregister-proxy')
parser_unregister_proxy.add_argument('app', help='Application name')
parser_update_domain = subparsers.add_parser('update-domain', help='Rebuilds domain structure of VM with new domain name and new HTTPS port')
parser_update_domain.set_defaults(action='update-domain')
parser_update_domain.add_argument('domain', help='Domain name')
parser_update_domain.add_argument('port', help='HTTPS port')
parser_request_cert = subparsers.add_parser('request-cert', help='Requests and installs Let\'s Encrypt certificate for currently set domain')
parser_request_cert.set_defaults(action='request-cert')
parser_request_cert.add_argument('email', help='Email address to receive certificate notifications')
args = parser.parse_args()
sm = SpotterManager()
if args.action == 'update-login':
sm.update_login(args.app, args.login, args.password)
elif args.action == 'show-tiles':
sm.show_tiles(args.app)
elif args.action == 'hide-tiles':
sm.hide_tiles(args.app)
elif args.action == 'start-app':
sm.start_app(args.app)
elif args.action == 'stop-app':
sm.stop_app(args.app)
elif args.action == 'enable-autostart':
sm.enable_autostart(args.app)
elif args.action == 'disable-autostart':
sm.disable_autostart(args.app)
elif args.action == 'register-proxy':
sm.register_proxy(args.app)
elif args.action == 'unregister-proxy':
sm.unregister_proxy(args.app)
elif args.action == 'update-domain':
sm.update_domain(args.domain, args.port)
elif args.action == 'request-cert':
sm.request_cert(args.email)

View File

@ -1,117 +0,0 @@
#!/bin/sh
set -ev
ROOT=$(dirname $(dirname $(realpath "${0}")))
# Build documentation
cd ${ROOT}/doc
make html
# Build basic tar
cd ${ROOT}/vm
tar czpf /srv/build/vm.tar.gz *
# Build native apps
cd ${ROOT}/apk/py3-secure-cookie
apk add -U py3-setuptools py3-pytest py3-werkzeug
abuild -F
cd ${ROOT}/apk/spoc
abuild -F
cd ${ROOT}/apk/vmmgr
abuild -F
# Build runtimes
cd ${ROOT}/lxc-shared
spoc-image build -p alpine3.8/image
spoc-image build -p alpine3.8-java8/image
spoc-image build -p alpine3.8-ruby2.4/image
spoc-image build -p alpine3.10/image
spoc-image build -p alpine3.10-nodejs10/image
spoc-image build -p alpine3.11/image
spoc-image build -p alpine3.11-python2.7/image
spoc-image build -p alpine3.12/image
spoc-image build -p alpine3.12-java8/image
spoc-image build -p alpine3.12-php7.3/image
spoc-image build -p alpine3.12-python3.8/image
spoc-image build -p alpine3.12-ruby2.4/image
spoc-image build -p alpine3.12-ruby2.7/image
spoc-image build -p alpine3.12-tomcat7/image
spoc-image build -p alpine3.12-tomcat8.5/image
spoc-image build -p debian10/image
# Build services
cd ${ROOT}/lxc-services
spoc-image build -p activemq/image
spoc-image build -p mariadb/image
spoc-image build -p mongodb/image
spoc-image build -p postgres/image
spoc-image build -p postgis/image
spoc-image build -p rabbitmq/image
spoc-image build -p redis/image
spoc-image build -p solr6/image
# Build applications
cd ${ROOT}/lxc-apps
spoc-image build -p ckan/ckan.image
spoc-image build -p ckan/ckan-datapusher.image
spoc-app publish ckan/app
spoc-image build -p crisiscleanup/image
spoc-app publish crisiscleanup/app
spoc-image build -p cts/image
spoc-app publish cts/app
spoc-image build -p decidim/decidim-nginx.image
spoc-image build -p decidim/decidim.image
spoc-app publish decidim/app
spoc-image build -p dhis2/image
spoc-app publish dhis2/app
spoc-image build -p frontlinesms/image
spoc-app publish frontlinesms/app
spoc-image build -p gnuhealth/image
spoc-app publish gnuhealth/app
spoc-image build -p kanboard/image
spoc-app publish kanboard/app
spoc-image build -p mifosx/image
spoc-app publish mifosx/app
spoc-image build -p motech/image
spoc-app publish motech/app
spoc-image build -p odoo/image
spoc-app publish odoo/app
spoc-image build -p opendatakit/opendatakit.image
spoc-image build -p opendatakit/opendatakit-build.image
spoc-app publish opendatakit/app
spoc-image build -p openmapkit/image
spoc-app publish openmapkit/app
spoc-image build -p pandora/image
spoc-app publish pandora/app
spoc-image build -p sahana/image
spoc-app publish sahana/app
spoc-app publish sahana-demo/app
spoc-app publish sambro/app
spoc-app publish safire/app
spoc-app publish share/app
spoc-image build -p seeddms/image
spoc-app publish seeddms/app
spoc-image build -p taarifa/image
spoc-app publish taarifa/app
spoc-image build -p ushahidi/image
spoc-app publish ushahidi/app

View File

@ -1,29 +0,0 @@
#!/bin/sh
set -ev
# Clean documentation
rm -rf /srv/build/doc/*
# Clean basic tar
rm -f /srv/build/vm.tar.gz
# Clean native apps
rm -rf /srv/build/alpine/*
# Clean built LXC packages
rm -rf /srv/build/spoc
# Remove nginx configs
for CONF in $(find /etc/nginx/conf.d -name '*.conf' -a ! -name repo.conf -a ! -name default.conf); do
rm -f ${CONF}
done
service nginx reload
# Stop running containers
for APP in $(spoc-container list); do
spoc-container stop ${APP}
done
# Remove data
rm -rf /var/lib/spoc
rm -rf /var/log/spoc

View File

@ -1,32 +0,0 @@
export CFLAGS="-Os -fomit-frame-pointer"
export CXXFLAGS="$CFLAGS"
export CPPFLAGS="$CFLAGS"
export LDFLAGS="-Wl,--as-needed"
export JOBS=2
export MAKEFLAGS=-j$JOBS
# remove line below to disable colors
USE_COLORS=1
# uncomment line below to enable ccache support.
#USE_CCACHE=1
SRCDEST=/var/cache/distfiles
# uncomment line below to store built packages in other location
# The package will be stored as $REPODEST/$repo/$pkgname-$pkgver-r$pkgrel.apk
# where $repo is the name of the parent directory of $startdir.
REPODEST=/srv/build/alpine/v3.12
# PACKAGER and MAINTAINER are used by newapkbuild when creating new aports for
# the APKBUILD's "Contributor:" and "Maintainer:" comments, respectively.
#PACKAGER="Your Name <your@email.address>"
#MAINTAINER="$PACKAGER"
PACKAGER_PRIVKEY="/root/repo.spotter.cz.rsa"
# what to clean up after a successful build
CLEANUP="srcdir bldroot pkgdir deps"
# what to cleanup after a failed build
ERROR_CLEANUP="bldroot deps"

View File

@ -1,8 +0,0 @@
server {
listen [::]:80;
server_name repo.build.vm;
location / {
root /srv/build;
}
}

View File

@ -1,36 +0,0 @@
#!/bin/sh
set -ev
cd $(realpath $(dirname "${0}"))
# Install basic build tools
apk update
apk add git file htop less openssh-client tree
# Install Alpine SDK (for APK builds)
apk add alpine-sdk
# Install Sphinx support (for documentation builds)
apk add py3-sphinx py3-sphinx_rtd_theme
# Copy root profile files and settings
mkdir -p /root/.config/htop
cp root/.profile /root/.profile
cp root/.config/htop/htoprc /root/.config/htop/htoprc
# Prepare abuild toolchain
adduser root abuild
cp etc/abuild.conf /etc/abuild.conf
# Prepare local APK repository
cp etc/nginx/conf.d/repo.conf /etc/nginx/conf.d/repo.conf
echo "172.17.0.1 repo.build.vm" >>/etc/hosts
service nginx reload
# Change SPOC repository
sed -i 's/https:\/\/repo\.spotter\.cz/http:\/\/repo.build.vm/' /etc/spoc/spoc.conf
# Supply abuild key
# echo '/root/repo.spotter.cz.rsa' | abuild-keygen
# Supply SPOC key
# openssl ecparam -genkey -name secp384r1 -out /etc/spoc/publish.key
# openssl ec -in /etc/spoc/publish.key -pubout -out /tmp/repository.pub

View File

@ -1,2 +0,0 @@
alias ll="ls -la"
alias view="vi -R"

14
ckan-datapusher.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
SOURCE_DIR=$(realpath $(dirname "${0}"))/ckan-datapusher
# Build Docker container
docker build -t ckan-datapusher ${SOURCE_DIR}
cp ${SOURCE_DIR}/etc/init.d/ckan-datapusher /etc/init.d/ckan-datapusher
rc-update -u
# Configure CKAN DataPusher
mkdir -p /srv/ckan-datapusher/conf /srv/ckan-datapusher/data
cp ${SOURCE_DIR}/srv/ckan-datapusher/conf/datapusher.wsgi /srv/ckan-datapusher/conf/datapusher.wsgi
cp ${SOURCE_DIR}/srv/ckan-datapusher/conf/datapusher_settings.py /srv/ckan-datapusher/conf/datapusher_settings.py
chown -R 8004:8004 /srv/ckan-datapusher/data

View File

@ -0,0 +1,32 @@
FROM python2
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Install runtime dependencies
apk --no-cache add libffi libressl uwsgi-python
RUN \
# Install build dependencies
apk --no-cache add --virtual .deps build-base git libffi-dev libressl-dev libxml2-dev libxslt-dev py2-pip python2-dev \
# Install CKAN DataPusher
&& mkdir -p /srv/ckan-datapusher \
&& cd /srv/ckan-datapusher \
&& pip install -U setuptools \
&& pip install -e 'git+https://github.com/ckan/datapusher.git#egg=datapusher' \
# Hackfix the X509_STORE_CTX wrapper
&& sed -i 's/\[security\]//' /srv/ckan-datapusher/src/datapusher/requirements.txt \
&& pip install -r /srv/ckan-datapusher/src/datapusher/requirements.txt \
# Create OS user
&& addgroup -S -g 8004 ckandp \
&& adduser -S -u 8004 -h /srv/ckan-datapusher -s /bin/false -g ckandp -G ckandp ckandp \
&& chown -R ckandp:ckandp /srv/ckan-datapusher \
# Cleanup
&& apk --no-cache del .deps \
&& find /srv/ckan-datapusher/src -name '.git*' -exec rm -rf {} + \
&& rm -rf /root/.cache
VOLUME ["/etc/ckan-datapusher", "/srv/ckan-datapusher/data"]
EXPOSE 8080
USER ckandp
CMD ["uwsgi", "--plugin", "python", "--http-socket", "0.0.0.0:8080", "--wsgi-file", "/etc/ckan-datapusher/datapusher.wsgi", "--enable-threads"]

View File

@ -0,0 +1,20 @@
#!/sbin/openrc-run
description="CKAN DataPusher docker container"
depend() {
need docker
}
start() {
/usr/bin/docker run -d --rm \
--name ckan-datapusher \
-h ckan-datapusher \
-v /srv/ckan-datapusher/conf:/etc/ckan-datapusher \
-v /srv/ckan-datapusher/data:/srv/ckan-datapusher/data \
ckan-datapusher
}
stop() {
/usr/bin/docker stop ckan-datapusher
}

View File

@ -15,6 +15,6 @@ SQLALCHEMY_DATABASE_URI = 'sqlite:////srv/ckan-datapusher/data/jobs.db'
HOST = '0.0.0.0' HOST = '0.0.0.0'
PORT = 8080 PORT = 8080
FROM_EMAIL = 'admin@example.com' FROM_EMAIL = 'ckan@spotter.ngo'
STDERR = True STDERR = True

62
ckan.sh Executable file
View File

@ -0,0 +1,62 @@
#!/bin/sh
SOURCE_DIR=$(realpath $(dirname "${0}"))/ckan
# Check prerequisites
docker image ls | grep -q ckan-datapusher || $(realpath $(dirname "${0}"))/ckan-datapusher.sh
docker image ls | grep -q postfix || $(realpath $(dirname "${0}"))/postfix.sh
docker image ls | grep -q postgres || $(realpath $(dirname "${0}"))/postgres.sh
docker image ls | grep -q redis || $(realpath $(dirname "${0}"))/redis.sh
docker image ls | grep -q solr || $(realpath $(dirname "${0}"))/solr.sh
service postgres start
service redis start
service solr start
# Build Docker container
docker build -t ckan ${SOURCE_DIR}
cp ${SOURCE_DIR}/etc/init.d/ckan /etc/init.d/ckan
rc-update -u
# Create database
export CKAN_PWD=$(head -c 18 /dev/urandom | base64)
export CKAN_DS_PWD=$(head -c 18 /dev/urandom | base64)
envsubst <${SOURCE_DIR}/createdb.sql | docker exec -i postgres psql
# Configure CKAN Solr core
docker exec solr solr create -p 8983 -c ckan
cp ${SOURCE_DIR}/srv/solr/data/ckan/conf/schema.xml /srv/solr/data/ckan/conf/schema.xml
cp ${SOURCE_DIR}/srv/solr/data/ckan/conf/solrconfig.xml /srv/solr/data/ckan/conf/solrconfig.xml
chown 8983:8983 /srv/solr/data/ckan/conf/schema.xml
service solr restart
# Configure CKAN
mkdir -p /srv/ckan/conf /srv/ckan/data
chown -R 8003:8003 /srv/ckan/data
export CKAN_SECRET=$(head -c 18 /dev/urandom | base64)
export CKAN_UUID=$(cat /proc/sys/kernel/random/uuid)
envsubst <${SOURCE_DIR}/srv/ckan/conf/ckan.ini >/srv/ckan/conf/ckan.ini
cp ${SOURCE_DIR}/srv/ckan/conf/who.ini /srv/ckan/conf/who.ini
cp ${SOURCE_DIR}/srv/ckan/update-url.sh /srv/ckan/update-url.sh
# Set "production values" (increases performance) only if the DEBUG environment variable is not set
if [ ${DEBUG:-0} -eq 0 ]; then
sed -i 's/debug = true/debug = false/' /srv/ckan/conf/ckan.ini
fi
# Populate database
docker run --rm -h ckan --link postgres --link redis --link solr -v /srv/ckan/conf:/etc/ckan -v /srv/ckan/data:/srv/ckan/storage ckan paster --plugin=ckan db init -c /etc/ckan/ckan.ini
docker run --rm -h ckan --link postgres --link redis --link solr -v /srv/ckan/conf:/etc/ckan -v /srv/ckan/data:/srv/ckan/storage ckan paster --plugin=ckanext-spatial spatial initdb -c /etc/ckan/ckan.ini
docker run --rm -h ckan --link postgres --link redis --link solr -v /srv/ckan/conf:/etc/ckan -v /srv/ckan/data:/srv/ckan/storage ckan paster --plugin=ckan datastore set-permissions -c /etc/ckan/ckan.ini | docker exec -i postgres psql
# Create admin account
export CKAN_ADMIN_USER="admin"
export CKAN_ADMIN_UUID=$(cat /proc/sys/kernel/random/uuid)
export CKAN_ADMIN_APIKEY=$(cat /proc/sys/kernel/random/uuid)
export CKAN_ADMIN_PWD=$(head -c 12 /dev/urandom | base64)
export CKAN_ADMIN_HASH=$(docker run --rm ckan python -c "from passlib.hash import pbkdf2_sha512;print pbkdf2_sha512.encrypt('${CKAN_ADMIN_PWD}')")
export CKAN_ADMIN_EMAIL="admin@example.com"
envsubst <${SOURCE_DIR}/adminpwd.sql | docker exec -i postgres psql ckan
spotter-appmgr update-login ckan "${CKAN_ADMIN_USER}" "${CKAN_ADMIN_PWD}"
# Install cron job
cp ${SOURCE_DIR}/etc/periodic/hourly/ckan /etc/periodic/hourly/ckan

47
ckan/Dockerfile Normal file
View File

@ -0,0 +1,47 @@
FROM python2
MAINTAINER Disassembler <disassembler@dasm.cz>
RUN \
# Add edge/testing repository
echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/testing' >>/etc/apk/repositories \
# Install runtime dependencies
&& apk --no-cache add geos@edge libjpeg-turbo libmagic libpq mailcap py2-pip zlib
RUN \
# Install build dependencies
apk --no-cache add --virtual .deps build-base git libjpeg-turbo-dev libxml2-dev libxslt-dev postgresql-dev python2-dev zlib-dev \
# Hackfix for python find_library('c') call
&& ln -s /lib/ld-musl-x86_64.so.1 /lib/libc.so.1 \
# Install CKAN
&& mkdir -p /srv/ckan \
&& cd /srv/ckan \
&& pip install -U setuptools \
&& pip install -e 'git+https://github.com/ckan/ckan.git#egg=ckan' \
# Force psycopg2 version update for compatibility with PostgreSQL 10
&& sed -i 's/psycopg2==2.4.5/psycopg2==2.7.1/' /srv/ckan/src/ckan/requirements.txt \
&& pip install -r /srv/ckan/src/ckan/requirements.txt \
# Install CKAN extensions
&& pip install -e 'git+https://github.com/ckan/ckanext-basiccharts#egg=ckanext_basiccharts' \
&& pip install -e 'git+https://github.com/ckan/ckanext-spatial#egg=ckanext_spatial' \
&& pip install -e 'git+https://github.com/ckan/ckanext-geoview#egg=ckanext_geoview' \
&& pip install -e 'git+https://github.com/ckan/ckanext-mapviews#egg=ckanext_mapviews' \
&& pip install -e 'git+https://github.com/XVTSolutions/ckanext-spatialUI#egg=ckanext_spatialui' \
&& pip install -e 'git+https://github.com/aptivate/ckanext-datasetthumbnail#egg=ckanext_datasetthumbnail' \
&& pip install -e 'git+https://github.com/datagvat/ckanext-dgvat_xls#egg=ckanext_dgvat_xls' \
&& pip install -r /srv/ckan/src/ckanext-spatial/pip-requirements.txt \
&& pip install -r /srv/ckan/src/ckanext-dgvat-xls/requirements.txt \
# Create OS user
&& addgroup -S -g 8003 ckan \
&& adduser -S -u 8003 -h /srv/ckan -s /bin/false -g ckan -G ckan ckan \
&& chown -R ckan:ckan /srv/ckan \
# Cleanup
&& apk --no-cache del .deps \
&& find /srv/ckan/src -name '.git*' -exec rm -rf {} + \
&& rm -rf /root/.cache
COPY docker/ /
VOLUME ["/etc/ckan", "/srv/ckan/storage"]
EXPOSE 8080
CMD ["s6-svscan", "/etc/services.d"]

View File

@ -0,0 +1,3 @@
#!/bin/sh
/bin/true

View File

@ -0,0 +1,5 @@
#!/bin/execlineb -P
fdmove -c 2 1
s6-setuidgid 8003:8003
/usr/bin/paster serve /etc/ckan/ckan.ini

33
ckan/etc/init.d/ckan Executable file
View File

@ -0,0 +1,33 @@
#!/sbin/openrc-run
description="CKAN docker container"
depend() {
need docker ckan-datapusher postfix postgres redis solr
}
start() {
/usr/bin/docker run -d --rm \
--name ckan \
-h ckan \
--link ckan-datapusher \
--link postfix \
--link postgres \
--link redis \
--link solr \
-v /srv/ckan/conf:/etc/ckan \
-v /srv/ckan/data:/srv/ckan/storage \
ckan
}
start_post() {
/usr/bin/spotter-appmgr register-proxy ckan
}
stop_pre() {
/usr/bin/spotter-appmgr unregister-proxy ckan
}
stop() {
/usr/bin/docker stop ckan
}

6
ckan/etc/periodic/hourly/ckan Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
if docker ps | grep -q 'ckan$'; then
docker exec ckan paster --plugin=ckan tracking update -c /etc/ckan/ckan.ini >/dev/null
docker exec ckan paster --plugin=ckan search-index rebuild -r -c /etc/ckan/ckan.ini >/dev/null
fi

View File

@ -13,9 +13,8 @@
[DEFAULT] [DEFAULT]
# WARNING: *THIS SETTING MUST BE SET TO FALSE ON A PUBLIC ENVIRONMENT* # WARNING: *THIS SETTING MUST BE SET TO FALSE ON A PRODUCTION ENVIRONMENT*
# With debug mode enabled, a visitor to your site could execute malicious commands. debug = true
debug = false
[server:main] [server:main]
use = egg:Paste#http use = egg:Paste#http
@ -29,11 +28,11 @@ cache_dir = /tmp/%(ckan.site_id)s/
beaker.session.key = ckan beaker.session.key = ckan
# This is the secret token that the beaker library uses to hash the cookie sent # This is the secret token that the beaker library uses to hash the cookie sent
# to the client. `ckan generate config` generates a unique value for this each # to the client. `paster make-config` generates a unique value for this each
# time it generates a config file. # time it generates a config file.
beaker.session.secret = ${CKAN_SECRET} beaker.session.secret = ${CKAN_SECRET}
# `ckan generate config` generates a unique value for this each time it generates # `paster make-config` generates a unique value for this each time it generates
# a config file. # a config file.
app_instance_uuid = ${CKAN_UUID} app_instance_uuid = ${CKAN_UUID}
@ -46,16 +45,15 @@ who.log_file = %(cache_dir)s/who_log.ini
# who.timeout = 86400 # who.timeout = 86400
## Database Settings ## Database Settings
sqlalchemy.url = postgresql://ckan:${CKAN_PWD}@ckan-postgres/ckan sqlalchemy.url = postgresql://ckan:${CKAN_PWD}@postgres/ckan
ckan.datastore.write_url = postgresql://ckan:${CKAN_PWD}@ckan-postgres/ckan_datastore ckan.datastore.write_url = postgresql://ckan:${CKAN_PWD}@postgres/ckan_datastore
ckan.datastore.read_url = postgresql://ckan_datastore:${CKAN_DS_PWD}@ckan-postgres/ckan_datastore ckan.datastore.read_url = postgresql://ckan_datastore:${CKAN_DS_PWD}@postgres/ckan_datastore
# PostgreSQL' full-text search parameters # PostgreSQL' full-text search parameters
ckan.datastore.default_fts_lang = english ckan.datastore.default_fts_lang = english
ckan.datastore.default_fts_index_method = gist ckan.datastore.default_fts_index_method = gist
## Site Settings ## Site Settings
ckan.site_url = https://ckan.spotter.vm ckan.site_url = https://ckan.spotter.vm
@ -73,30 +71,18 @@ ckan.auth.user_delete_organizations = false
ckan.auth.create_user_via_api = false ckan.auth.create_user_via_api = false
ckan.auth.create_user_via_web = true ckan.auth.create_user_via_web = true
ckan.auth.roles_that_cascade_to_sub_groups = admin ckan.auth.roles_that_cascade_to_sub_groups = admin
ckan.auth.public_user_details = true
ckan.auth.public_activity_stream_detail = true
ckan.auth.allow_dataset_collaborators = true
ckan.auth.create_default_api_keys = false
## API Token Settings
api_token.nbytes = 60
api_token.jwt.encode.secret = string:$app_instance_secret
api_token.jwt.decode.secret = string:$app_instance_secret
api_token.jwt.algorithm = HS256
## API Token: expire_api_token plugin
expire_api_token.default_lifetime = 3600
## Search Settings ## Search Settings
ckan.site_id = default ckan.site_id = default
solr_url = http://ckan-solr:8983/solr/ckan solr_url = http://solr:8983/solr/ckan
## Redis Settings ## Redis Settings
# URL to your Redis instance, including the database to be used. # URL to your Redis instance, including the database to be used.
ckan.redis.url = redis://ckan-redis:6379/0 ckan.redis.url = redis://redis:6379/0
## CORS Settings ## CORS Settings
@ -114,22 +100,40 @@ ckan.redis.url = redis://ckan-redis:6379/0
# Add ``datapusher`` to enable DataPusher # Add ``datapusher`` to enable DataPusher
# Add ``resource_proxy`` to enable resorce proxying and get around the # Add ``resource_proxy`` to enable resorce proxying and get around the
# same origin policy # same origin policy
ckan.plugins = stats text_view image_view recline_view datastore datapusher resource_proxy ckan.plugins = stats text_view image_view recline_view datastore datapusher resource_proxy linechart barchart piechart basicgrid spatial_metadata spatial_query geo_view geojson_view wmts_view navigablemap choroplethmap spatialUI datasetthumbnail dgvat_xls
# Define which views should be created by default # Define which views should be created by default
# (plugins must be loaded in ckan.plugins) # (plugins must be loaded in ckan.plugins)
ckan.views.default_views = image_view text_view recline_view ckan.views.default_views = image_view text_view recline_view geo_view geojson_view wmts_view
# Customize which text formats the text_view plugin will show # Customize which text formats the text_view plugin will show
#ckan.preview.json_formats = json #ckan.preview.json_formats = json
#ckan.preview.xml_formats = xml rdf rdf+xml owl+xml atom rss #ckan.preview.xml_formats = xml rdf rdf+xml owl+xml atom rss
#ckan.preview.text_formats = txt plain text/plain #ckan.preview.text_formats = text plain text/plain
# Customize which image formats the image_view plugin will show # Customize which image formats the image_view plugin will show
#ckan.preview.image_formats = png jpeg jpg gif #ckan.preview.image_formats = png jpeg jpg gif
# GeoView plugin settings
ckanext.geoview.ol_viewer.formats = wms wfs geojson gml kml arcgis_rest gft
ckanext.geoview.gapi_key = AIzaSyBvIF3D550tlpL6o1xRrDurGo-81VhHlOw
# Pages plugin settings
ckanext.pages.organization = true
ckanext.pages.group = true
ckanext.pages.allow_html = true
ckanext.pages.editor = ckeditor
# Dataset thumbnail plugin settings
ckan.datasetthumbnail.show_thumbnail = true
ckan.datasetthumbnail.auto_generate = true
## Front-End Settings ## Front-End Settings
# Uncomment following configuration to enable using of Bootstrap 2
#ckan.base_public_folder = public-bs2
#ckan.base_templates_folder = templates-bs2
ckan.site_title = CKAN ckan.site_title = CKAN
ckan.site_logo = /base/images/ckan-logo.png ckan.site_logo = /base/images/ckan-logo.png
ckan.site_description = ckan.site_description =
@ -142,6 +146,7 @@ ckan.display_timezone = server
# package_hide_extras = for_search_index_only # package_hide_extras = for_search_index_only
#package_edit_return_url = http://another.frontend/dataset/<NAME> #package_edit_return_url = http://another.frontend/dataset/<NAME>
#package_new_return_url = http://another.frontend/dataset/<NAME> #package_new_return_url = http://another.frontend/dataset/<NAME>
#ckan.recaptcha.version = 1
#ckan.recaptcha.publickey = #ckan.recaptcha.publickey =
#ckan.recaptcha.privatekey = #ckan.recaptcha.privatekey =
#licenses_group_url = http://licenses.opendefinition.org/licenses/groups/ckan.json #licenses_group_url = http://licenses.opendefinition.org/licenses/groups/ckan.json
@ -167,11 +172,6 @@ ckan.storage_path = /srv/ckan/storage
ckan.max_resource_size = 100 ckan.max_resource_size = 100
ckan.max_image_size = 10 ckan.max_image_size = 10
## Webassets Settings
#ckan.webassets.use_x_sendfile = false
#ckan.webassets.path = /var/lib/ckan/webassets
## Datapusher settings ## Datapusher settings
# Make sure you have set up the DataStore # Make sure you have set up the DataStore
@ -199,19 +199,16 @@ ckan.hide_activity_from_users = %(ckan.site_id)s
#email_to = errors@example.com #email_to = errors@example.com
#error_email_from = ckan-errors@example.com #error_email_from = ckan-errors@example.com
smtp.server = host smtp.server = postfix
smtp.starttls = False smtp.starttls = False
#smtp.user = username@example.com #smtp.user = username@example.com
#smtp.password = your_password #smtp.password = your_password
smtp.mail_from = admin@example.com smtp.mail_from = ckan@spotter.ngo
#smtp.reply_to =
## Background Job Settings
ckan.jobs.timeout = 180
## Logging configuration ## Logging configuration
[loggers] [loggers]
keys = root, ckan, ckanext, werkzeug keys = root, ckan, ckanext
[handlers] [handlers]
keys = console keys = console
@ -223,12 +220,6 @@ keys = generic
level = WARNING level = WARNING
handlers = console handlers = console
[logger_werkzeug]
level = WARNING
handlers = console
qualname = werkzeug
propagate = 0
[logger_ckan] [logger_ckan]
level = INFO level = INFO
handlers = console handlers = console

View File

@ -1,10 +1,10 @@
[plugin:auth_tkt] [plugin:auth_tkt]
use = ckan.lib.repoze_plugins.auth_tkt:make_plugin use = ckan.lib.auth_tkt:make_plugin
# If no secret key is defined here, beaker.session.secret will be used # If no secret key is defined here, beaker.session.secret will be used
#secret = somesecret #secret = somesecret
[plugin:friendlyform] [plugin:friendlyform]
use = ckan.lib.repoze_plugins.friendly_form:FriendlyFormPlugin use = repoze.who.plugins.friendlyform:FriendlyFormPlugin
login_form_url= /user/login login_form_url= /user/login
login_handler_path = /login_generic login_handler_path = /login_generic
logout_handler_path = /user/logout logout_handler_path = /user/logout
@ -13,6 +13,10 @@ post_login_url = /user/logged_in
post_logout_url = /user/logged_out post_logout_url = /user/logged_out
charset = utf-8 charset = utf-8
#[plugin:basicauth]
#use = repoze.who.plugins.basicauth:make_plugin
#realm = 'CKAN'
[general] [general]
request_classifier = repoze.who.classifiers:default_request_classifier request_classifier = repoze.who.classifiers:default_request_classifier
challenge_decider = repoze.who.classifiers:default_challenge_decider challenge_decider = repoze.who.classifiers:default_challenge_decider
@ -30,3 +34,4 @@ plugins =
[challengers] [challengers]
plugins = plugins =
friendlyform;browser friendlyform;browser
# basicauth

6
ckan/srv/ckan/update-url.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
HOST="${1}"
[ "${2}" != "443" ] && HOST="${1}:${2}"
sed -i "s|^ckan\.site_url.*|ckan.site_url = https://${HOST}|" /srv/ckan/conf/ckan.ini

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