Compare commits

...

668 Commits

Author SHA1 Message Date
440317c552 Update cs.py změna Organizační jednotky, Zařízení, Pobočky 2021-11-19 15:10:32 +01:00
fd23d27bba
Add Decidim Twilio SMS configuration setup 2021-04-18 15:21:18 +02:00
c9af05aeb0
Bump Decidim to 0.23.5, add omniauth plugin 2021-04-08 20:23:54 +02:00
5bd1f5e97c
Fix Decidim config population during clean install 2021-04-02 19:10:27 +02:00
215ffb81ae
Update fix for Decidim font diacritics 2021-04-02 17:54:46 +02:00
7052ea8859
Bump Decidim to 0.23.4 2021-04-02 11:23:00 +02:00
dd922b7775
Inject qt-patched wkhtmltopdf to Odoo 2021-03-21 11:24:17 +01:00
2877cd2748
Install wkhtmltopdf for Odoo 2021-03-20 22:33:10 +01:00
1d688ad1ff
Set Decidim currency, resolves 2021-02-08 06:46:55 +01:00
723a6a494f
Mount only currently customized Decidim configs, resolves for new installations 2021-02-06 13:50:28 +01:00
db26467d0b Update cs.py 2021-02-02 01:51:04 +00:00
8d15e2806d Update cs.py 2021-02-02 00:42:19 +00:00
f4700bef17
Update custom Decidim translations and helper script, related to 2021-01-30 14:42:37 +01:00
abf763683d
Replace Decidim Source Sans Pro with full version, resolves 2021-01-30 13:25:24 +01:00
0ad56ac087
Add custom Decidim translations, relates to 2021-01-30 13:22:44 +01:00
81226d3bcc
Bump vmmgr 2021-01-27 23:55:48 +01:00
358281816f Update cs.py 2021-01-25 01:41:03 +00:00
98327336ac
Bump Taarifa to Node.js 8 build 2021-01-24 19:40:00 +01:00
89c4e2e88f
Update docs 2021-01-24 12:14:59 +01:00
521f3f2ab6
Bump VMMgr 2021-01-24 11:34:23 +01:00
b17f6a3279
Add Taarifa to VMMgr portal 2021-01-24 10:13:18 +01:00
08313f07db
Add Mongodb on Debian10 + Taarifa Waterpoints 2021-01-24 09:16:50 +01:00
01d19fe5fb Update cs.py 2021-01-20 21:49:06 +00:00
093f306ec7
Disable Decidim templates module due to upstream 2021-01-18 18:42:00 +01:00
667354a158
Enable Decidim comparative_stats module, relates to 2021-01-18 17:58:14 +01:00
53141556f7
Enable bundled plugins, related to 2021-01-16 20:58:04 +01:00
88893abc50
Install and configure Decidim plugins, related to 2021-01-11 12:38:28 +01:00
082a9fb50d
Bump spoc 2021-01-10 16:45:17 +01:00
917c15420c
Bump Alpine 3.11, 3.12, services and apps to current versions 2021-01-06 19:28:37 +01:00
ef116c12ef
Create Odoo instance without demo data, resolves 2021-01-06 19:02:22 +01:00
03d56ac0c9
Bump Ruby to 2.7.2, Decidim to 0.23.1
- Split image to nginx and decidim
 - Make database migrations persistent, resolves 
2020-11-21 09:25:40 +01:00
86c97de908
Update DHIS2 app description 2020-11-09 09:49:08 +01:00
967ccc0d44
Align Sahana Spotter template with the current default template 2020-11-09 07:52:20 +01:00
6f52ea0f1a
Align Tomcat configs for ODK and Mifos with Tomcat upstream 2020-11-09 07:50:19 +01:00
c50e67dbc0
Add DHIS2 image and application 2020-11-09 07:45:55 +01:00
31876f3776 Update cs.py Dump - výprodej 2020-10-25 15:12:44 +01:00
4fd2de3935 Update cs.py Theme - Téma 2020-10-25 14:12:54 +01:00
b53f8b0a24 Update cs.py indikátor - ukazatel 2020-10-25 13:57:07 +01:00
1c2e59e64b Update cs.py - datum vypršení 2020-10-25 13:27:44 +01:00
c757630f7a
Use -i to apply patches instead of stdin redirect 2020-10-24 22:09:21 +02:00
1c140bb593
Apply Alpine patches for Ruby images 2020-10-24 22:08:12 +02:00
5c1130eafe
Bump VMMgr 2020-10-23 20:16:13 +02:00
b189f3c9a2
Disable Sahana vulnerability module, bump SAMBRO and SHARE configs 2020-10-23 19:47:36 +02:00
783fd3c094
Update docs and submodules 2020-10-22 23:05:13 +02:00
8bc038ea02
Bump Sahana to newer commit on Alpine 3.12
Bumped web2py to 2.20.4, python 3 now officially fully supported
2020-10-22 23:05:01 +02:00
8428373178
Bump Ushahidi to version 4.6.1 on Alpine 3.12 2020-10-22 23:03:44 +02:00
ddcca22498
Bump Odoo to version 6.0.13 on Alpine 3.12
Add section about updating to docs
2020-10-22 23:02:59 +02:00
0f89b0ae4b
Bump Pandora to newer commit on Alpine 3.12, add update script 2020-10-22 23:01:33 +02:00
9a83b97d33
Bump OpenMapKit date 2020-10-22 23:00:34 +02:00
a993e2f4ce
Bump OpenDataKit to Ruby 2.4.10 on Alpine 3.12 2020-10-22 22:59:58 +02:00
fe9928443f
Bump Odoo to version 14.0.0 on Alpine 3.12 2020-10-22 22:59:09 +02:00
d2082a896b
Bump Motech to Alpine 3.12 2020-10-22 22:58:17 +02:00
a763665f32
Bump MifosX to Alpine 3.12 2020-10-22 22:57:45 +02:00
2b09ee23c8
Bump Kanboard to version 1.2.16 on Alpine 3.12 2020-10-22 22:56:54 +02:00
40a46cd675
Bump GNU Health to version 3.6.5 on Alpine 3.12 2020-10-22 21:03:16 +02:00
9e2075a4af
Bump FrontlineSMS date, add comment Java/Jetty compatibility 2020-10-22 21:02:39 +02:00
7355cdb888
Add docs for Decidim middleware and DB migration 2020-10-22 21:00:32 +02:00
a4c52f9b3b
Fix Decidim HTTP proxy 2020-10-22 21:00:05 +02:00
013f0d110e
Bump Decidim to Alpine 3.12 2020-10-22 20:59:21 +02:00
4ba0069a8a
Bump CTS date, add comment about python2 and geos 2020-10-22 20:58:09 +02:00
99099e03bb
Bump CrisisCleanup to Ruby 2.4.10 2020-10-22 20:56:50 +02:00
6ec890aa30
Bump CKAN to 2.9.0, use Python 3 runtime 2020-10-22 20:56:10 +02:00
e39aa41c7c
Bump service images to Alpine 3.12 2020-10-22 20:53:40 +02:00
a7202756ab
Bump shared images based on Alpine 3.8, 3.10, 3.11
Remove custom repo key on 3.11
2020-10-22 20:45:13 +02:00
596955f6b4
Bump shared images to Alpine 12 2020-10-22 20:42:45 +02:00
14e07c9b56
Bump services built directly on Alpine layer to Alpine 3.12 2020-10-15 09:58:11 +02:00
3f9accced2
Build whole custom RabbitMQ image instead of just APK 2020-10-15 09:20:05 +02:00
1cd9fb1485
Add Alpine 3.12 image 2020-10-13 21:13:53 +02:00
9b517ceebb
Add py3-secure-cookie for VMMgr, install py3-sphinx_rtd_theme 2020-10-12 21:36:39 +02:00
97a5c63d48
Bump basic VM to Alpine 3.12, drop custom LXC as 3.12 uses LXC 4.0.2 2020-10-11 21:45:38 +02:00
f79cddbf44
Bump Ruby to 2.6.6 and Decidim to 0.22.0 2020-10-04 23:15:31 +02:00
c3d5542bee
Bump VMMgr with demo mode feature 2020-08-26 18:07:08 +02:00
a28b29f953 Update cs.py 2020-07-05 22:33:53 +02:00
4cc79de59c
Fix typo in OpenMapKit update-conf.sh, resolves 2020-06-25 17:43:29 +02:00
af7be5c1be
Add Sahana update scripts, remove unused DEBUG envvar 2020-06-21 20:45:32 +02:00
09b7ce481f
Add a note about Pandora celery workaround 2020-06-21 18:54:05 +02:00
3839eddb60
Bump Pandora to Alpine 3.11 + Python 3.8 2020-06-21 18:38:22 +02:00
ebe3828b5e
Make self-signed certificates work in OpenMapKit + fix build 2020-06-21 17:25:53 +02:00
d532d087fe
Future-proof Decidim passenger + nginx some more 2020-06-21 14:51:10 +02:00
bbc669d2a7
Hardcode SaFire and ShaRe VMMgr tiles 2020-06-21 14:50:30 +02:00
74df7b6a59
Fix GNU Health build 2020-06-21 13:10:24 +02:00
624693bb22
Fix Decidim build 2020-06-21 12:55:46 +02:00
5218d4d094
Update liboggplay (Pandora dependency) git repo URL 2020-06-21 12:29:48 +02:00
c9978e21c9
Future-proof Decidim passenger + nginx compilation 2020-06-21 10:45:12 +02:00
547c3cf84f
Documentation update for Sahana local development, closes 2020-06-21 10:13:19 +02:00
c41a007870
Bump Ushahidi to 4.5.0 2020-06-21 08:47:53 +02:00
60c0e25c49
Bump SeedDMS to 5.1.17 2020-06-21 08:46:27 +02:00
0d1b4942c3
Bump Kanboard to 1.2.15 2020-06-21 08:44:29 +02:00
cba47bc0b2
Bump GNU Health to 3.6.4 2020-06-21 08:43:35 +02:00
e1e4f706ee
Bump Decidim to 0.21.0 2020-06-21 08:42:08 +02:00
603bd923e1
Correctly report installed MariaDB version 2020-06-21 08:39:38 +02:00
c2064220d0
Bump ActiveMQ to 5.15.13 2020-06-21 08:37:51 +02:00
1fb67a69f9
Bump Tomcat 8.5 to 8.5.56 2020-06-21 08:36:30 +02:00
e0a071e9e5
Correctly report installed Python and PHP runtime version 2020-06-21 08:35:42 +02:00
a90cb7679b
Bump Tomcat 7 to 7.0.104 2020-06-21 08:33:20 +02:00
d307a559c0
Bump build date on all apps 2020-06-21 08:32:40 +02:00
3659f3d1ed
Bump Alpine 3.11 to 3.11.6 2020-06-21 08:26:58 +02:00
87429cda34
Bump Alpine 3.10 to 3.10.5 2020-06-21 08:22:36 +02:00
b2db2816fa
Update project URL after rename 2020-06-20 18:28:10 +02:00
d5aca4ad52
Add schemata into documentation, closes 2020-06-16 22:39:46 +02:00
57cef0f4cf
Add more docs 2020-06-03 18:56:46 +02:00
ea2ba79f96
Update OpenDataKit repo URLs 2020-06-03 18:38:01 +02:00
f5416a4501
More doc updated 2020-06-02 18:30:08 +02:00
553930da0d
Update docs with FrontlineSMS + comments in 2020-06-02 08:59:03 +02:00
40e98ff42a
Update technical documentation 2020-06-01 22:09:39 +02:00
615b847cf9
Properly capitalize Kanboard 2020-06-01 22:04:31 +02:00
8e4b38ef18 Update cs.py 2020-05-15 19:52:12 +02:00
004f35c186
Update Sahana Czech translation 2020-05-04 11:11:02 +02:00
a2ffc2ab63
Bump spoc and vmmgr 2020-05-04 11:07:19 +02:00
837466742e
Make Sahana errors and sessions persistent 2020-05-04 11:06:50 +02:00
b1ff00e36b
Make Sahana Setup module compatible with Alpine containers, closes 2020-05-04 11:04:29 +02:00
04c9795586
Add Debian 10 image to graveyard (LXC URL for doc purposes) 2020-05-04 10:51:08 +02:00
001faa160e
Remove RSS feeds (and Google scripts) from Sahana Spotter template, closes 2020-05-02 19:28:01 +02:00
eb5b8365c3
Unify Sahana language code for English, closes 2020-05-02 19:26:11 +02:00
29f1b52dee
Update Sahana Czech translation 2020-05-02 19:23:41 +02:00
93f94e16ac
Bump Sahana build after a bunch of upstream fixes 2020-04-26 18:52:43 +02:00
16c9a6c862
Bump spoc version and reflect /tmp mode change in spoc#6 2020-04-26 18:49:26 +02:00
92b61944dd
Update Sahana Czech translation 2020-04-26 18:49:01 +02:00
1620028382
Add Sahana compat patch for PostGIS 3 2020-04-22 21:39:40 +02:00
df2eb81928
Bump Sahana build after a bunch of upstream fixes 2020-04-21 16:58:56 +02:00
52016223ab
Hackfix Sahana's Web2Py gis/proxy
https://github.com/sahana/eden_deploy/commit/5f1d8d8b2
https://github.com/web2py/web2py/issues/2262
2020-04-18 19:16:55 +02:00
50e6ec1c3a
Move Crismapp + Alpine 3.8 - PHP 5.6 to graveyard 2020-04-18 19:01:12 +02:00
b3b1daf989
Reflect Kanboard plugin repo changes introduced in 2020-04-18 18:14:17 +02:00
2163506a8e
Update non-verbatim string in Czech Sahana translation 2020-04-18 15:32:49 +02:00
21f695d7ba
Update Czech Sahana translation + helper scripts, closes 2020-04-18 12:32:40 +02:00
5107631271
Update Czech Sahana translation, related to 2020-04-16 23:08:06 +02:00
676a9d24b7
Bump Kanboard and add Czech translation 2020-04-16 12:56:38 +02:00
e8e01417b2
Add SaFiRe + ShaRe to build-all.sh 2020-04-14 14:18:01 +02:00
1885b9e18e
Add SaFiRe + ShaRe, closes 2020-04-14 14:17:21 +02:00
780f44246f
Reflect small SAMBRO config update 2020-04-14 13:55:43 +02:00
1eea6c8e99
Add Crismapp, closes 2020-04-11 19:52:10 +02:00
9417ad24a2
Revert "Move alpine3.8-php5.6 used by EcoGIS to graveyard"
This reverts commit 7331ab6d96f18565a99a7fbff12cd1a7fe14cecd.
2020-04-11 19:25:45 +02:00
7331ab6d96
Move alpine3.8-php5.6 used by EcoGIS to graveyard 2020-04-11 16:59:07 +02:00
cc1ea7fa25
Add Odoo 10 to graveyard (cherry-picked from 2018-11-17) 2020-04-11 16:54:57 +02:00
e5574db63c
Add CrisisCleanup3 to graveyard (cherry-picked from 2018-08-10) 2020-04-11 16:52:28 +02:00
8771ac9828
Merge branch 'compose' 2020-04-11 16:47:26 +02:00
6047cbcd0a
Move EcoGIS and Sigmah to graveyard, closes , 2020-04-11 16:40:25 +02:00
ad437292ab
Rewrite extend-disk in python and move vmtty back to basic vm setup 2020-04-11 14:55:18 +02:00
bd946bf564
Bump submodules 2020-04-10 20:20:13 +02:00
867997b588
Include DOMAIN directly in HOST envvar for update-conf.sh, update add-ca-cert 2020-04-10 17:57:42 +02:00
6bab2bda8d
Bump vmmgr submodule 2020-04-10 14:08:11 +02:00
de5e7da26d
Make update-conf.sh executable 2020-04-10 13:40:40 +02:00
c287b1ea6e
Fix typo in ODK app definition 2020-04-10 13:09:29 +02:00
a12b0f101e
Update update-conf.sh, revert custom prop definitions
Partially reverts 0028a3ba5b1e20276a56024d1ba3ff60af6059c1
2020-04-10 13:03:34 +02:00
0028a3ba5b
Define custom props during application installation 2020-04-10 11:21:39 +02:00
09a146b54c
Make CKAN and ODK add-ca-cert parametrizable 2020-04-06 10:45:46 +02:00
5f6a7a2517
Fix Odoo setup when tty is attached 2020-04-05 20:38:07 +02:00
1a0c641df3
Fix vmmgr package creation 2020-04-04 23:01:02 +02:00
d16fcb8a9d
Move files managed by vmmgr to vmmgr package 2020-04-04 22:08:19 +02:00
391859ded4
Add acme.sh cron job 2020-04-04 20:33:08 +02:00
e7e255488d
Fix line endings 2020-04-04 18:04:56 +02:00
cb4ff53efd
Fix FrontlineSMS mount 2020-04-04 17:39:02 +02:00
087ad65518
Revert CrisisCleanup to working v2 revision 2020-04-04 17:33:04 +02:00
15be9aad67
Update forgotten Ushahidi version number 2020-04-04 13:44:02 +02:00
c04cf033a8
Hackfix GNU Health to install specific version of python dependency which doesn't fail during setup 2020-04-04 11:29:09 +02:00
0bae44985c
Bump Alpine to 3.11.5 + all apps 2020-04-04 00:17:24 +02:00
e788060456
Fix homeless .bundle paths 2020-03-25 21:32:19 +01:00
d93c739d38
Fix Sigmah mounts 2020-03-24 22:15:28 +01:00
4c0fcc5535
Bump postgres configs to version 12 2020-03-24 19:52:27 +01:00
268dc6447c
Make Ushahidi SPOC-compatible, cont'd 2020-03-24 19:17:46 +01:00
6cb0440d4a
Make Ushahidi SPOC-compatible 2020-03-24 15:15:26 +01:00
bd70f07f8b
Make Sigmah SPOC-compatible, cont'd 2020-03-23 16:08:21 +01:00
ecfafd0c4a
Make Sigmah SPOC-compatible 2020-03-23 13:51:23 +01:00
236c15dbac
Make SeedDMS SPOC-compatible, cont'd 2020-03-23 11:32:11 +01:00
e0e49ec31a
Make SeedDMS SPOC-compatible 2020-03-23 10:14:47 +01:00
746713eb9f
Work with ${LAYERS_DIR} bit more predictably 2020-03-23 10:10:57 +01:00
102761efac
Make SAMBRO SPOC-compatible 2020-03-22 21:16:22 +01:00
caf30e9958
Make Sahana-Demo SPOC-compatible 2020-03-22 20:45:07 +01:00
9f8571f622
Make Sahana SPOC-compatible, cont'd 2020-03-22 20:36:56 +01:00
b804987254
Make Sahana SPOC-compatible 2020-03-22 19:52:00 +01:00
2b9d73c847
Update Pandora celery setting 2020-03-22 16:03:24 +01:00
cab95d15f3
Downgrade Pandora to Alpine 10 + Python 3.7 2020-03-22 14:17:52 +01:00
b79323b4b7
Make Pandora SPOC-compatible 2020-03-22 13:44:46 +01:00
3e8032d867
Revert CrisisCleanup bump to Alpine 3.10 2020-03-22 12:40:37 +01:00
ef52c066d2
Bump CrisisCleanup to Alpine 3.10 + Node.js 10 2020-03-22 12:17:13 +01:00
c32365d671
OMK requires nodejs<=10 2020-03-22 11:08:52 +01:00
7a45daf853
Make OMK SPOC-compatible 2020-03-22 10:28:57 +01:00
fea0a7911a
Make ODK SPOC-compatible 2020-03-21 22:42:35 +01:00
f63e78a800
Reflect passlib depreciation in Odoo install.sh 2020-03-20 22:32:46 +01:00
0790a9243b
Make Odoo SPOC-compatible 2020-03-20 20:52:25 +01:00
590dde8206
Tweak Tomcat permissions 2020-03-20 15:21:16 +01:00
40e26e4407
Make Motech SPOC-compatible 2020-03-20 14:57:40 +01:00
35345dc529
Bump postgres JDBC driver and use full catalina.sh path 2020-03-20 14:50:41 +01:00
36181e3593
Patch lxc-attach to return correct returncode 2020-03-19 22:36:59 +01:00
dadda1c175
MySQL socket auth tries to be funny, so run init as root 2020-03-19 21:59:41 +01:00
719b4e04b6
Make MifosX SPOC-compatible, cont'd 2020-03-18 22:36:06 +01:00
692571a7f8
Add custom LXC with fixed -g/-u for lxc-execute/attach 2020-03-18 22:25:01 +01:00
ff3d37517f
Make MifosX SPOC-compatible 2020-03-18 16:51:21 +01:00
d8d9f5431e
Make KanBoard SPOC-compatible 2020-03-17 16:51:44 +01:00
8f27ee6afe
Make GNU Health SPOC-compatible 2020-03-17 14:47:28 +01:00
797e900268
Base FrontlineSMS on Alpine 3.8 Java 8 2020-03-17 12:54:43 +01:00
74ff517e09
Convert CRLF to LF 2020-03-17 12:53:44 +01:00
0455738fa8
Make FrontlineSMS SPOC-compatible 2020-03-17 11:03:24 +01:00
5782083921
Make EgoGIS SPOC-compatible 2020-03-17 10:48:06 +01:00
be4042d7e4
Make Decidim SPOC-compatible, cont'd. 2020-03-17 09:52:04 +01:00
f32b719630
Make Decidim SPOC-compatible 2020-03-17 09:18:13 +01:00
512895a6f2
Make CTS SPOC-compatible 2020-03-16 21:54:30 +01:00
f6328158ed
Add owner and mode for install in CKAN and CC 2020-03-16 21:34:46 +01:00
042a82c463
Fix CrisisCleanup data population 2020-03-16 20:53:27 +01:00
853c3852fd
Make CrisiCleanup SPOC-compatible 2020-03-16 20:06:51 +01:00
b55a5dfdbd
Use install binary to copy / create CKAN files 2020-03-16 19:13:43 +01:00
4e0cbe0dcb
Re-add CKAN DP X509_STORE_CTX wrapper hackfix 2020-03-14 15:16:48 +01:00
58960e5e01
Retain TLSv1.2 compatibility as old apps still need it 2020-03-14 14:26:32 +01:00
84d43f51ff
Append the CKAN cert to both modules 2020-03-14 11:36:58 +01:00
e02fc0f97d
Fix CKAN service provider instead 2020-03-14 11:10:36 +01:00
157a0b8660
Fix CKAN werkzeug compatibility issue 2020-03-14 11:02:18 +01:00
202aa1e8ca
Re-add accidentally dropped CKAN-DP requirements 2020-03-14 10:40:22 +01:00
72a4ea9e5c
Tryfix for missing local timezone data 2020-03-14 10:15:40 +01:00
243c8a4542
Keep CKAN DataPusher add-ca-cert on py2.7 2020-03-14 09:47:33 +01:00
c7b0ea28b2
Hackfix CKAN support for PostgreSQL 12 2020-03-13 22:55:12 +01:00
0b46076ae7
Revert CKAN who.ini to use pre-2.9 modules 2020-03-13 21:47:25 +01:00
3632568e29
Local installation repo must use plain HTTP due to cert mismatch 2020-03-13 21:27:47 +01:00
361bb2dc7b
Make CKAN SPOC-compatible, cont'd. 2020-03-13 21:12:16 +01:00
61ab0b0b48
Using tech scheduled to EOL 5 years ago should be a criminal offense 2020-03-13 20:42:12 +01:00
734a9611e5
Bump redis version 2020-03-13 20:20:11 +01:00
368a060a5e
Make CKAN SPOC-compatible, cont'd. 2020-03-13 20:19:26 +01:00
923b794cc6
Make CKAN SPOC-compatible 2020-03-13 20:13:28 +01:00
f45e25ea2c
Remove obsolete build files 2020-03-13 20:09:23 +01:00
81b9e8d0af
Bump forgotten Solr files 2020-03-13 20:05:46 +01:00
07163889a3
Name the repo key properly 2020-03-13 17:53:31 +01:00
04804d8883
Build fixes 2020-03-13 17:36:50 +01:00
bedbbb0c3a
Bump RabbitMQ sources 2020-03-13 17:36:06 +01:00
4c47c49eab
Bump packages for shared Alpine 3.8 images 2020-03-13 17:12:24 +01:00
29cad671dc
Mass bump shared and service images to Alpine 3.11 2020-03-13 17:03:03 +01:00
705ac8104a
Set proper filename for extlinux.conf 2020-03-13 16:36:11 +01:00
d73b0c381f
Build toolchain amendments 2020-03-13 13:22:47 +01:00
fe0777eaf2
Start cgroupfs on boot 2020-03-13 13:18:05 +01:00
f16d2cde9b
Compress vm.tar and update vmmgr config.json adminpwd init 2020-03-13 00:19:00 +01:00
7a19274211
Bump abuild.conf to Alpine 3.11 2020-03-13 00:01:59 +01:00
36d0b9156c
Update submodules 2020-03-12 23:56:06 +01:00
6aa4eb7778
Bump Decidim to 0.20.0 + install imagick 2020-03-12 23:54:17 +01:00
76bef22633
Drop custom acme-sh and use the default instead 2020-03-12 23:10:12 +01:00
7cb420dc4c
Add SPOC as a submodule 2020-03-12 22:56:40 +01:00
99c39d5ee9
Update KanBoard install scripts for spoc 2020-02-22 19:59:48 +01:00
2ee9b97020
Bump KanBoard app compose file 2020-02-22 15:48:05 +01:00
29d791afe1
Bump Kanboard to 1.2.13 on Alpine 3.11 2020-02-22 15:34:59 +01:00
7b1298d7d0
Bump PHP to Alpine 3.11 PHP 7.3 2020-02-22 15:32:25 +01:00
f948c885bc
Add translation-toolkit to Sahana 2020-02-10 08:16:24 +01:00
473dd4af61
Update Sahana + Sahana Demo for spoc 2020-02-09 15:56:37 +01:00
f5fee5afa1
Use full path for s6-svscan 2020-02-09 15:54:46 +01:00
5e7846b519
Anotate Sahana pip requirements exclusions 2020-02-07 18:49:22 +01:00
e5c6203412
Bump Sahana to Alpine 3.11 2020-02-07 18:35:25 +01:00
bba8f06422
Bump python, postgres, postgis to Alpine 3.11 2020-02-07 18:28:24 +01:00
076786f482
Bump nginx configs (tcp_nodelay, TLSv1.3) 2020-02-07 18:27:15 +01:00
28a70e878e
Bump the Alpine VM to 3.11 2020-02-04 16:09:48 +01:00
d7d89b9db6
Update web2py and hackfix SAMBRO installation 2019-12-22 10:59:47 +01:00
44209ddfb3
Fix wrong layer ordering 2019-12-21 17:45:05 +01:00
e355510575
Fix required bundler version for ruby app 2019-12-21 14:50:23 +01:00
3713365950
Bump version of Web2py for Sahana 2019-12-20 23:28:11 +01:00
1801fcdc3d
Bring Sahana config up-to-date 2019-12-20 17:53:39 +01:00
18698ef5d4
Fix Pandora password hash generation 2019-12-20 08:55:31 +01:00
d08848a4d0
Improve RabbitMQ ready command 2019-12-20 08:54:31 +01:00
48510beb28
Update Pandora config to align with upstream 2019-12-20 08:20:13 +01:00
751afa6cf2
Add Decidim uninstall script 2019-12-18 14:37:37 +01:00
64dced3dc8
Fix MifosX schema creation 2019-12-18 14:35:39 +01:00
b2b2c12cdf
Fix Decidim rake secret 2019-12-18 10:57:24 +01:00
91c413ecbf
Assign explicit UID/GID to decidim user 2019-12-18 10:14:14 +01:00
2bd45fea0d
Fix a few build omissions 2019-12-18 10:13:32 +01:00
c73c5f1eef
Reorder Decidim rake secret generation 2019-12-17 21:31:05 +01:00
7426ff6f9c
Fix MifosX install script 2019-12-13 22:20:27 +01:00
0e465b0820
Workaround for LXC root priv for mysql 2019-12-13 21:28:55 +01:00
19b62a4370
Fix SeedDMS install 2019-12-10 18:56:15 +01:00
ed997ab417
Fix Motech install 2019-12-10 18:48:39 +01:00
376a0f87ef
Fix Ecogis directory names 2019-12-10 08:38:51 +01:00
c2a30bc4c1
Reorder KanBoard install script 2019-12-09 22:28:11 +01:00
9532bc7405
Use repo.build.vm as local build host 2019-12-09 21:41:04 +01:00
0351abcb92
Rename apkrepo.conf to repo.conf 2019-12-08 14:54:00 +01:00
a2605594d3
Fix Decidim meta file 2019-12-07 19:46:22 +01:00
f2176428bc
Use find in clean-all instead of ls 2019-12-07 16:29:41 +01:00
91a5a24b1b
Use lxchelper extract where appropriate 2019-12-07 15:52:09 +01:00
d94db19410
Fix CrisisCleanup admin user creation 2019-12-01 14:46:45 +01:00
515672c170
Update CKAN conf files to 2.9 2019-12-01 07:44:47 +01:00
8a23276748
Add clean-all build script 2019-11-30 22:12:15 +01:00
a7a4004f53
Introduce lxc- prefix for services 2019-11-30 22:11:38 +01:00
22d10b5a69
Reflect recent change in CKAN python requirements 2019-11-30 21:51:54 +01:00
7809cc8a5e
Add logrotate to basic setup 2019-11-30 19:05:14 +01:00
bdf4a01b3b
Create OS user for tomcat directly instead of individual apps using it 2019-11-30 19:00:03 +01:00
c71817c2e8
Don't fail if image dir doesn't exist during build cleanup 2019-11-30 16:17:20 +01:00
c22d2c7393
Move BuildType to imagebuilder to prevent dependency conflicts 2019-11-30 16:08:04 +01:00
e794ced82a
Introduce BuildType for normal, force, scratch and metadata builds 2019-11-30 15:56:29 +01:00
e1b7ba1204
Remove unused nginx and nodejs images 2019-11-30 15:54:09 +01:00
f82ad15689
Remove nginx layers, convert to FROM 2019-11-30 09:59:32 +01:00
f8403c5f42
Remove MERGE capability, add FROM
layer inheritance is now linear
2019-11-30 09:59:11 +01:00
4d579ef8c1
Compile nginx+passenger for Decidim and finalize install script 2019-11-23 18:11:18 +01:00
b6c3949d41
Correctly rename crontabs dir 2019-11-20 23:05:31 +01:00
c10b1a7920
Wait for cron service on exit 2019-11-20 22:23:48 +01:00
9c3cee22a6
Bunch of install script fixes 2019-11-18 22:12:01 +01:00
a41d270743
Replace single quotes with double quotes in solr ready command 2019-11-18 20:48:45 +01:00
ebbbab71fb
Fix Sigmah version 2019-11-18 00:15:08 +01:00
a9a930b37b
Add more common libs to basic Alpine image 2019-11-17 21:40:14 +01:00
b5eabcb311
Create nginx user and group beforehand 2019-11-17 21:28:21 +01:00
7ed4628597
Add meta for Decidim 2019-11-17 17:36:25 +01:00
827991d7ac
Revert order of layers for MERGE 2019-11-17 16:28:49 +01:00
56af4a0b66
Leave ActiveMQ heap settings in default 2019-11-17 16:01:04 +01:00
3d8154d87f
Add and use alpine3.8-nginx image 2019-11-17 15:24:26 +01:00
d56afb17c2
Update naming in docs 2019-11-17 15:04:47 +01:00
5084dc1579
Rename FIXLAYER to MERGE and update for merging passwd/group/shadow 2019-11-17 15:04:34 +01:00
d3129d81ab
Move readline to basic alpine image 2019-11-17 14:53:05 +01:00
e8138099cb
Move libressl to basic alpine image 2019-11-17 14:48:16 +01:00
fe9fb27679
Add Decidim LXC app 2019-11-15 18:03:17 +01:00
692897c9bf
Introduce separate nginx layer 2019-11-15 17:45:34 +01:00
85e8b631a1
Add Alpine3.9-Ruby2.6 2019-11-13 22:07:59 +01:00
9c50b29d22
Start Odoo Postgres in install.sh 2019-11-13 21:07:31 +01:00
de80024445
Properly identify Odoo 13 2019-11-13 19:46:38 +01:00
5a43c23b83
Remove cwd magic as it's pkgmgr's responsibility now 2019-10-14 08:29:55 +02:00
4458be2763
Fix postgis version and replace with postgres in appropriate composes 2019-10-14 08:15:31 +02:00
0f5c1d6433
Change application users UID/GID to 8080 2019-10-14 07:59:06 +02:00
4e9c63d8aa
Make the executable files executable 2019-10-07 09:52:53 +02:00
7e3431a4c0
Add cron jobs for KanBoard, SeedDMS, Ushahidi 2019-10-07 09:48:37 +02:00
79efa46226
Fix rabbitmq image for Pandora 2019-10-06 00:03:39 +02:00
f9507ae4b7
Fix ODK build 2019-10-05 23:53:32 +02:00
8434f192c9
Fix missing import 2019-10-05 23:39:00 +02:00
d476a36f24
Fix propagated typo 2019-10-05 23:37:44 +02:00
3a3552f154
Fix GNU Health build via symlink to current version of trytond 2019-10-05 23:09:59 +02:00
466a83e407
Allow scratch builds with dir as argument 2019-10-05 23:09:30 +02:00
93cc9f435b
String formatting simplification 2019-10-05 22:42:29 +02:00
62a6612a79
Implement scratch containers and image/app removal 2019-10-05 22:26:54 +02:00
f2016d1b71
Fix FlSMS meta version 2019-10-05 17:51:14 +02:00
715ad22409
Typo fix 2019-10-05 17:47:33 +02:00
1aaf16e8b7
Fix CKAN build 2019-10-05 17:26:19 +02:00
3a554e1c84
Simplify composed builds 2019-10-05 16:35:10 +02:00
cf99826386
Fix hostnames 2019-10-05 16:34:10 +02:00
9b18c94ddd
Rework SAMBRO 2019-10-05 16:10:29 +02:00
985dd2998a
Rework Sahana Eden - Demo 2019-10-05 16:01:55 +02:00
f46fafa4ed
Rework Sahana Eden 2019-10-05 15:49:29 +02:00
4ba938d17f
Add forgotten Pandora Postgres config 2019-10-05 15:43:20 +02:00
0f093a1087
Rework Ushahidi 2019-10-05 15:40:27 +02:00
4ac414c691
Rework Sigmah 2019-10-05 15:34:42 +02:00
4391b33fbc
Rework SeedDMS 2019-10-05 15:27:14 +02:00
826b244bae
Rework Pan.do/ra 2019-10-05 15:26:48 +02:00
eac6129fb3
Rework RabbitMQ 2019-10-05 15:13:00 +02:00
ed3aeb60d8
Rework OpenMapKit 2019-10-05 15:07:53 +02:00
6c16aedadd
Merge CKAN+Datapusher and ODK+Build into respective single build directories 2019-10-05 15:01:03 +02:00
d1fc5b7796
Rework OpenDataKit 2019-10-05 14:37:43 +02:00
4e107840a1
Rework Odoo 2019-10-03 21:53:42 +02:00
8c7890fcbc
Rework Motech 2019-10-03 21:48:36 +02:00
15e7600ae4
Rework ActiveMQ 2019-10-03 21:41:02 +02:00
57cd65115d
Rework MifosX 2019-10-03 21:29:19 +02:00
990a9dcb71
Rework MariaDB 2019-10-03 21:28:43 +02:00
a8bca6727b
Rework KanBoard 2019-10-03 20:48:09 +02:00
8b6f09c7d5
Rework GNU Health 2019-10-03 20:36:14 +02:00
1ec7dfcc95
Remove meta['proxy'] and use vmmgr register-app instead 2019-10-03 20:35:51 +02:00
0bc2daf4ad
Rework FrontlineSMS 2019-10-03 20:19:13 +02:00
ed0c6c90a7
Rework EcoGIS 2019-10-03 20:09:58 +02:00
2e674aa2d0
Update build-all.sh 2019-10-03 20:08:37 +02:00
c9ceaff648
Rework CTS 2019-10-03 13:19:52 +02:00
dfdd1de8e8
Fix fix-layer launching and env var population 2019-10-03 12:13:39 +02:00
77196fdcca
Rework fix-apk to cover all apk files 2019-10-03 12:12:45 +02:00
99d31eb0b5
Rework CrisisCleanup 2019-09-27 11:28:00 +02:00
8171f20309
Hostnames shouldn't have underscores 2019-09-24 20:09:08 +02:00
8d42eac029
Fix CKAN install script 2019-09-24 19:15:40 +02:00
9d1e3f2d60
Fix layers, destroy container on build cleanup 2019-09-24 19:15:22 +02:00
f9cc283477
Fix CKAN scripts 2019-09-24 10:53:12 +02:00
89d3dd7d0c
Fix layer ordering 2019-09-24 10:53:01 +02:00
7f0d9572e3
Add unpacked sizes 2019-09-24 10:04:13 +02:00
69f67649f3
Make CKAN script executable 2019-09-23 15:40:59 +02:00
b1d705487a
Fix packaging 2019-09-23 15:34:37 +02:00
bbfe11f557
Add checks, fix build 2019-09-20 15:43:01 +02:00
7116566519
Allow lxcbuilder to pack meta files 2019-09-20 10:13:41 +02:00
2ea88cabce
Install ncurses-libs by default in basic Alpine images 2019-09-20 10:12:53 +02:00
846a85e939
Move CKAN app meta+files back to lxc-apps 2019-09-20 10:12:18 +02:00
9f1f247484
Introduce LXC-composer 2019-09-18 11:29:58 +02:00
1efc713ae3
Bump wireguard to 0.0.20190702 - 4.19.52 2019-08-21 11:11:15 +02:00
ec7e843024
Bump wireguard to 0.0.20190702 - 4.19.52 2019-08-21 11:09:06 +02:00
afbd4a0f60
New approach in package building and versioning 2019-06-25 15:56:35 +02:00
446b855d03
Fix extlinux disk UUID configuration 2019-06-13 09:46:24 +02:00
7186daeb1c
Use only UUIDs for runtime disk management 2019-06-12 16:27:49 +02:00
4fbeae6f7e
Sanitize all generated passwords 2019-06-05 18:55:15 +02:00
b96aae6780
Fix forgotten values 2019-06-05 18:15:34 +02:00
d3d8e3b766
Bump vmmgr 2019-06-05 15:15:28 +02:00
f1fb7607b5
Finalize restructuralization 2019-06-05 13:19:22 +02:00
048c0053f5
Update apk cache before attempting local installation 2019-06-05 10:17:53 +02:00
a7c85af7cc
Reintroduce repo tagging 2019-06-05 09:42:40 +02:00
6822f605d1
Add packages for wireguard 2019-06-04 19:16:46 +02:00
64aced5d8d
Simplify prereq installation for abuild 2019-06-03 13:23:03 +02:00
bdc0d0a2a6
Add custom rabbitmq-server build 2019-06-03 11:24:54 +02:00
8e57996b9c
Add spotter repo key to Alpine 3.9 basic image 2019-06-03 11:16:01 +02:00
9d0e30f728
Switch edge repositories to spotter 2019-06-02 11:31:24 +02:00
b556ee3c30
Add local nginx repository 2019-06-02 11:30:53 +02:00
cd4591501f
Build custom GDAL, GEOS, PROJ.4, PostGIS 2019-06-02 09:51:21 +02:00
1989b886f5
Reflect restructuralization in build-all.sh 2019-06-02 09:37:06 +02:00
6e9e0dffe1
Restructure repository 2019-06-02 08:24:26 +02:00
8f07df8c43
Bump Tomcat to 8.5.41 2019-06-01 20:03:09 +02:00
f35efa4a05
Bump acme.sh to 2.8.1 2019-06-01 19:55:06 +02:00
79442aa60e
Update SeedDMS execution time limit + cronjob 2019-05-17 18:08:37 +02:00
bc587252b4
Add myip.php to extras 2019-05-15 10:26:59 +02:00
1824e05393
Point URLs to repo.spotter.cz 2019-05-15 10:24:38 +02:00
e0637ce2a2
Add php-openssl as SeedDMS dependency for SMTP authentication 2019-05-11 13:45:15 +02:00
7e1e54a63e
Add php7-fileinfo as dependency for SeedDMS 2019-05-08 19:13:15 +02:00
42ec6eeb95
Bump SeedDMS to 5.1.9
Revert "Bump SeedDMS to 5.1.10" due to SeedDMS ticket 435.

This reverts commit 5c48a8354704cc21d8967360c04243adbf516fcb.
2019-05-08 17:25:10 +02:00
5c48a83547
Bump SeedDMS to 5.1.10 2019-05-08 11:18:52 +02:00
e165e9d8f7
Bump ODK to 2.0.3 2019-05-08 10:54:03 +02:00
f97d06873e
Bump KanBoard to 1.2.9 2019-05-08 10:44:14 +02:00
959da1a423
Bump GNU Health to 3.4.1 + Trytond 4.6.15 2019-05-08 10:34:35 +02:00
081c517e21
Bump ActiveMQ to 5.15.9 2019-05-08 10:03:27 +02:00
dc41cd5f4a
Bump Tomcat 8.5 to 8.5.40 2019-05-08 10:01:39 +02:00
893c3028a1
Bump Tomcat 7 to 7.0.94 2019-05-08 10:00:49 +02:00
13153d341b
Fix diacritics in Sahana PDF exports, closes 2019-04-13 20:50:56 +02:00
71fb5a7ca3 Update cs.py 2019-04-02 20:02:08 +02:00
387a7072f9 Update cs.py 2019-04-02 19:43:40 +02:00
65adfe8e16 Update cs.py 2019-04-02 18:49:28 +02:00
efff62d21e Update cs.py 2019-04-02 18:48:35 +02:00
4e36b2fb9e Update lang.inc 2019-04-02 11:49:15 +02:00
fda64ee225
Hackfix KanBoard postgres schema (will be fixed in 1.2.9) 2019-03-22 14:39:25 +01:00
b4b03d3505
Reflect SSH changes in documentation 2019-03-22 12:43:15 +01:00
ca3fd66ad3
Add nss to Java image as workaround for upstream bug 2019-03-22 11:39:23 +01:00
1bb3a4330e
Add empty line expected by vmmgr parser 2019-03-22 10:55:23 +01:00
0c9c54f481
Enable SSH only if any keys exist 2019-03-22 10:31:59 +01:00
db81cd38b8
Don't remove empty /root/.ssh 2019-03-22 10:14:29 +01:00
4f72107c98
Phase out serial TTY, update SSH MOTD 2019-03-22 09:59:33 +01:00
dfd0273a2c
Implement VPN + SSH configuration 2019-03-22 08:49:00 +01:00
508cb47c1e
Add wireguard remote support config 2019-03-20 08:49:50 +01:00
f155f0bc22
Use noop I/O scheduler elevator 2019-03-20 08:20:02 +01:00
8ddbc72644
Prevent extlinux.conf overwrites 2019-03-19 21:46:39 +01:00
91b1cfb08c
Hackfix python-barcode support for GNU Health 2019-03-19 18:21:10 +01:00
cd6ea369d7
Run apk upgrade for the base images 2019-03-19 15:00:32 +01:00
95665357f5
Add documentation build to build-all.sh 2019-03-19 14:04:13 +01:00
8cc7553acd
Add documentation 2019-03-19 11:32:31 +01:00
938c47f950
Update vmmgr submodule 2019-03-01 15:16:33 +01:00
eb079b9699
Make Sigmah install script independent on internet 2019-03-01 14:53:30 +01:00
98e87aa772
Upgrade GNU Health to 3.4.0 2019-03-01 14:30:32 +01:00
d0751b1f2c
Switch Sigmah to Tomcat 8.5 2019-03-01 12:23:36 +01:00
4f81baf02f
Upgrade OpenDataKit Aggregate to 2.0 + switch to Tomcat 8.5 2019-03-01 12:23:22 +01:00
3e51996286
Switch Motech to Tomcat 7 2019-03-01 12:22:43 +01:00
bf1c8b3fbf
Switch MifosX to Tomcat 8.5 2019-03-01 12:22:17 +01:00
e051ad1e06
Downgrade Tomcat 8.0 to 7.0 which is still supported 2019-03-01 12:21:49 +01:00
6977e1e7bd
Add Tomcat 8.5 layer 2019-03-01 12:21:18 +01:00
aaf2611b82
Adapt MariaDB config for 10.3.13 2019-02-28 16:06:03 +01:00
4129eb85c3
Bump KanBoard version to 1.2.8 2019-02-28 15:02:47 +01:00
180997be4a
Simplify MariaDB installation script 2019-02-27 13:46:24 +01:00
6af3888fda
Fix register-app calls 2019-02-26 21:16:00 +01:00
cb4b17e1d5
Remove /usr/bin/ from init scripts as it's in $PATH 2019-02-26 21:11:08 +01:00
3a424c5726
Use lxc start/stop commands in install script instead of service 2019-02-26 21:08:42 +01:00
3f6a74b5bd
Fix crisiscleanup dependencies 2019-02-26 20:48:08 +01:00
ce325cf3d0
Squashed commit of the following:
- Bump basic OS to Alpine 3.9
 - Restructure repo and add layer versioning
 - Use JSON for all metadata
 - Merge abuild branch (but without abuild)
2019-02-26 20:24:02 +01:00
b4f5979354
Make MifosX installation a bit less error-prone 2018-12-10 09:31:18 +01:00
bbf8219504
Add FrontlineSMS Czech translation, closes 2018-12-07 17:02:47 +01:00
e58fc05a7d
Update Ruby to 2.4.5, reflect in CrisisCleanup, closes 2018-12-05 14:07:45 +01:00
e17da9f060
Update pandora config to align with upstream, closes 2018-12-05 12:39:59 +01:00
b134f3c935 Update cs.py 2018-12-04 20:49:53 +01:00
1ce6abc6e4
Add missing comma to Ushahidi config.json, fixes 2018-12-04 20:19:29 +01:00
64dda6172e
Bump ActiveMQ version to 5.15.8 2018-12-04 14:53:10 +01:00
f623ce13ba Update cs.py 2018-12-01 01:04:10 +01:00
ea289aff48 Update cs.py 2018-12-01 00:27:20 +01:00
2dbefce8db Update cs.py 2018-12-01 00:25:00 +01:00
1dce7601cf
Introduce Odoo application package 2018-11-17 22:26:55 +01:00
aecf3eede2
Remove extraneous strings 2018-11-17 20:43:34 +01:00
3dfd71eb03 Update cs.py 2018-11-13 22:12:56 +01:00
8d6b2bdee6
Suppress agetty spam when ttyS0 doesn't exist 2018-11-13 22:02:38 +01:00
afb121c72e Update cs.py 2018-11-13 20:33:07 +01:00
e09669fb73
Fix postfix networks, closes , 2018-11-13 18:56:25 +01:00
96490c6c3e
Move vmmgr init script to proper place 2018-11-07 22:59:56 +01:00
2a75965449
Update app-vmmgr 2018-11-07 22:35:10 +01:00
8adf762acc
Create directory for Acme.sh 2018-11-07 21:53:22 +01:00
a13c44d2d6
Update build part in README 2018-11-07 20:14:49 +01:00
718a3b7a3f
Update app-vmmgr 2018-11-07 18:41:26 +01:00
5992629869
Fix Motech install URL 2018-11-07 14:08:30 +01:00
43922d8192
Distribute GNU Health demo database along with image 2018-11-07 10:10:07 +01:00
49dffce0d0
Fix acme.sh APKBUILD 2018-11-07 10:06:20 +01:00
e4d2422974
Update app-vmmgr 2018-11-07 10:00:39 +01:00
0ffbe9bb58
Add acme cron script to the package 2018-11-06 22:07:27 +01:00
12869d5dca
Add build key creation notes 2018-11-06 22:06:33 +01:00
5de59917cd
Add fallback nginx host 2018-11-04 19:50:48 +01:00
89a430fe5a
Update motech install script to use local hostname 2018-11-04 19:50:23 +01:00
e4bf6effe1
Update install scripts for upcomming vmmgr changes 2018-11-03 15:53:51 +01:00
d833b439c7
Remove extraneous variable 2018-11-02 17:46:16 +01:00
af6f90f9cb
Update app-vmmgr 2018-11-01 22:56:35 +01:00
6e182a9414
CRLF fix 2018-11-01 22:33:39 +01:00
6822269c84
Fix VM provisioning, update README 2018-11-01 15:30:28 +01:00
1812e27e1e
Add openssh-client to build toolchain 2018-11-01 13:37:24 +01:00
b7d9cec76a
Add vmmgr submodule 2018-11-01 13:04:42 +01:00
e225af87fb
Preparation for vmmgr submodule 2018-11-01 12:51:06 +01:00
58dc418e87
Create basic.tar as part of build-all 2018-11-01 10:01:15 +01:00
ab62d9bafc
Enable swap immediately after creation 2018-10-31 23:09:24 +01:00
35a70fd5c1
Streamline VM provisioning 2018-10-31 22:44:13 +01:00
072b529c9c
Create /var/log/lxc/ as part of lxc package 2018-10-31 21:49:17 +01:00
979060da69
Fix sahana-demo admin creation 2018-10-31 18:02:22 +01:00
410958a2a7
Simplify compile_url 2018-10-31 16:42:45 +01:00
76220d811d
Allow to set HDD password via command line 2018-10-31 14:16:03 +01:00
5919719f3e
Clean log and autostart on uninstall 2018-10-31 13:56:59 +01:00
20a6d670ca
Make AppMgr table more rigid 2018-10-31 11:27:15 +01:00
b76a350d7b
Stop app before uninstalling 2018-10-31 10:21:42 +01:00
cdb74d9677
Typo fix 2018-10-31 09:58:54 +01:00
905f2c62c1
Drop DB object only if they exist 2018-10-31 09:55:46 +01:00
61fab326c3
Revert "Update uninstall script not to fail on clean installation"
This reverts commit a339c8e8ff8b0fdcde1d3367afd26ea980b1149e.
2018-10-31 09:42:01 +01:00
237342254f
Partially revert unpacking stage in AppMgr 2018-10-31 09:40:53 +01:00
a339c8e8ff
Update uninstall script not to fail on clean installation 2018-10-31 08:28:26 +01:00
f98edaff58
Fix appmgr metadata fetching logic 2018-10-31 08:16:06 +01:00
d5a5962ee2
Don't fail on rabbitmq objects removal in Pandora uninstall 2018-10-31 07:47:08 +01:00
5ba5461a80
Add unpacking stage to AppMgr installation 2018-10-31 07:42:38 +01:00
0f4c2756ec
Fix SeedDMS uninstall script 2018-10-31 07:33:30 +01:00
6111325402
Fix db names in ODK Build uninstall script 2018-10-31 07:29:35 +01:00
b772f92c22
Transform PackageMgr into queue-backed AppMgr 2018-10-30 23:59:59 +01:00
eb27d92383
Escape names in Mifos uninstall script 2018-10-30 23:53:15 +01:00
f6c44f3d0c
rm -f cronjobs in uninstall scripts 2018-10-30 17:54:19 +01:00
7bca441acd
Add exit code to install scripts 2018-10-28 19:50:35 +01:00
25689d6345
Start with race condition mitigations 2018-10-28 18:20:27 +01:00
f675996e60
Add config file locking 2018-10-28 18:19:45 +01:00
cb0d0012c9
set -ev 2018-10-28 16:04:11 +01:00
1400bab1e1
Fix typo 2018-10-28 15:07:11 +01:00
cb2a3d65d8
Fix Sahana install scripts 2018-10-28 14:31:52 +01:00
6bafd28e3e
Split off sahana-shared from Sahana 2018-10-28 08:56:24 +01:00
5e4dbd6adf
Uninstall both CKAN databases 2018-10-28 08:27:36 +01:00
0a32d9ed9d
Make vm-ping more resilient, closes 2018-10-28 08:00:14 +01:00
6b38073372
Redirect to login when trying to access setup unauthenticated 2018-10-27 22:20:09 +02:00
d2b410efe8
Move common app settings below app manager 2018-10-27 21:35:49 +02:00
7c5b482392
fixes 2018-10-27 21:33:56 +02:00
874700ecb4
Remove excessive param 2018-10-27 21:20:56 +02:00
1060651116
Remove debug mode and move relevant files to zz-build 2018-10-27 21:19:57 +02:00
afe8df823f
Reimplement cert handling, strip useless cli params 2018-10-27 21:13:35 +02:00
6fb1e12ca6
Add uninstall scripts 2018-10-27 15:33:22 +02:00
38524e70af
update repo action + fixes 2018-10-27 12:49:22 +02:00
94048ba2fe
Show percentage as a whole number, clarify strings 2018-10-27 12:21:00 +02:00
960e7a2466
minor fixes 2018-10-27 06:54:54 +02:00
513c0839a5
Show installation progress in percents 2018-10-26 22:42:34 +02:00
848e99b4af
fixes 2018-10-26 22:11:34 +02:00
977b9af923
Add repository login form to frontend template 2018-10-26 22:05:43 +02:00
77965c614a
Split build script 2018-10-26 21:54:34 +02:00
780e469f82
Add uninstallation 2018-10-26 21:52:06 +02:00
65dfff8eb0
simplify pending counters, make werkzeug server threaded 2018-10-26 19:08:14 +02:00
951ae86520
Add VMMgr/PkgMgr install progress 2018-10-26 17:31:40 +02:00
920f01cf45
Change repo configuration structure 2018-10-26 15:38:35 +02:00
8be2bb2083
Fix install path in install.sh 2018-10-26 15:02:11 +02:00
203a70bdbd
Rename setup to install 2018-10-26 14:34:01 +02:00
b1cb57ab48
Uninstall + resiliency test 2018-10-26 14:12:12 +02:00
c6954816be
VMMgr - Install app + consolidate apps table 2018-10-26 11:15:48 +02:00
396653c9a6
eliminate SOURCE_DIR 2018-10-25 22:22:36 +02:00
7df7428acf
Build lxc pacakges to /srv/build/lxc 2018-10-25 22:17:39 +02:00
204318ef44
Use --xattrs in lxc-pack 2018-10-25 22:09:57 +02:00
f9218366fa
Reorganize build process 2018-10-25 22:05:48 +02:00
3abd3cf835
Install apps from custom repo, simplify usage of SOURCE_DIR 2018-10-25 21:48:35 +02:00
a0cf39811c
show all apps in one box 2018-10-22 11:59:46 +02:00
ac69aebf4e
Display online packages in setup-apps 2018-10-21 11:36:32 +02:00
07a195ab05
Simplify method calls in portal templates 2018-10-21 11:05:25 +02:00
867a5d4d69
Don't instantiate vmmgr on every request. Only reload config. 2018-10-21 11:04:48 +02:00
7abe6af068
VMMgr: Unify config, add pkg size 2018-10-21 10:09:02 +02:00
efdd1b1c68
Bump version of Alpine 3.8 rootfs 2018-10-15 20:51:04 +02:00
1817da3ebc
Bump KanBoard to 1.2.6 2018-10-15 20:34:37 +02:00
76616fcab9
Bump ActiveMQ to 5.15.6 2018-10-15 16:21:26 +02:00
2a6d271d2d
Fix solr dependency 2018-10-15 15:41:27 +02:00
66c61e581d
Fix more pkgmgr methods 2018-10-15 15:40:40 +02:00
de0dcc79f4
deps fixes 2018-10-15 14:58:24 +02:00
14984b3199
Distinguish registered apps and packages 2018-10-15 12:15:22 +02:00
1c967a0431
Add package manager prototype 2018-10-02 22:13:39 +02:00
ab78d18491
"fd" is apparently not pythonic 2018-10-02 22:09:34 +02:00
30254eb527
better lxc-pack unlinking 2018-10-02 17:38:58 +02:00
dbce751225
typo 2018-10-02 17:37:27 +02:00
91ebd4193e
Sign using py3-cryptography 2018-10-02 17:35:49 +02:00
48e31ca0f1
Add metadata for all packages 2018-10-02 14:29:17 +02:00
528e676d4d
Add exception handling for lxc-pack 2018-10-02 13:10:24 +02:00
b3cde0cdc8
Add a bunch of package descriptors for testing 2018-10-02 13:00:17 +02:00
88ae8848de
Add packaging script 2018-10-02 12:58:12 +02:00
31f7c408d4
Install tar and xz packages in DEBUG mode 2018-10-02 12:53:44 +02:00
a0dc16535d
Fix sahana demo + sambro install 2018-09-21 18:18:35 +02:00
67caca8171
Move app configuration to pre-start hook 2018-09-21 16:21:55 +02:00
48492bf405
Setup fixes 2018-09-21 15:23:02 +02:00
ed2e1193cb
Better s6 service stop handling 2018-09-21 11:04:12 +02:00
74b7d9478f
Include edge repos in basic alpine image 2018-09-21 09:17:19 +02:00
00eff6fa85
Startup and location fixes 2018-09-20 20:46:25 +02:00
96249760fd
Put config update script installation to the end of setup 2018-09-20 15:45:00 +02:00
011cf4356b
Rewrite confupdater back to individual files, change app start flow 2018-09-20 14:03:23 +02:00
da896c79f2
Stop MariaDB using SIGTERM 2018-09-20 07:21:24 +02:00
33a4c10f7a
Fix Pandora admin hash generator 2018-09-19 17:04:42 +02:00
0a30deb7e2
Have s6-setuidgid look up names from /etc/hosts 2018-09-19 16:52:29 +02:00
e055eb3542
fix copytypo 2018-09-19 10:56:09 +02:00
00154ef899
Implement lxc-build HALT and fix some minor regressions 2018-09-18 16:27:42 +02:00
fc99f7f6ab
Integrate forgotten update-url.sh 2018-09-18 15:18:29 +02:00
b0fe54d034
Fix VMMgr URL compilation 2018-09-17 16:12:17 +02:00
22fa90d785
Use UID/GID for lxc=attach in cron jobs 2018-09-16 19:59:01 +02:00
0240e95621
Use py-bcrypt instead of invoking container 2018-09-16 17:19:13 +02:00
3a2130eb48
Change method for postgres readiness check 2018-09-15 13:43:46 +02:00
4543bbc49f
move clean-ephemeral to lxc pre-start hook 2018-09-14 23:56:02 +02:00
433e23022a
CRLF 2018-09-14 23:12:07 +02:00
d141fff4c1
Start iptables just once 2018-09-14 18:23:16 +02:00
1894893a6f
create=(file|dir), fix setup errors 2018-09-14 18:13:11 +02:00
d957227d40
Fix 2018-09-14 15:58:10 +02:00
725ecc75a6
Move "postfix" host to "host" 2018-09-14 11:24:04 +02:00
30e2232b71
Integrate postfix into basic 2018-09-14 11:21:35 +02:00
b8bb87390f
Make cgroups preexisting hard dependency 2018-09-14 10:41:00 +02:00
ab82ed3fac
LXCize cronjobs 2018-09-14 10:33:07 +02:00
cbaf4d6941
LXCize Ushahidi setup 2018-09-14 09:43:54 +02:00
f74586c94c
LXCize Sigmah setup 2018-09-14 09:09:46 +02:00
d1991ddc7d
LXCize SeedDMS setup 2018-09-14 09:02:16 +02:00
8cc184c7e7
LXCize SAMBRO setup 2018-09-14 08:53:27 +02:00
8ac781bd8b
LXCize Sahana-Demo setup 2018-09-14 08:42:37 +02:00
b47df1d71d
LXCize Sahana setup 2018-09-13 22:09:01 +02:00
f747b89a5d
LXCize Pandora setup 2018-09-13 22:02:25 +02:00
f2a9529e29
LXCize OMK setup 2018-09-13 21:54:36 +02:00
44546c4816
LXCize ODK Build setup 2018-09-13 21:52:38 +02:00
57ecc71ebe
LXCize ODK setup 2018-09-13 21:30:38 +02:00
365f983c2d
LXCize Motech setup 2018-09-13 21:14:53 +02:00
db9458b4ad
LXCize MifosX setup 2018-09-13 21:10:32 +02:00
b7aedad589
start/stop prepreqs 2018-09-13 20:42:11 +02:00
86f4f940c7
LXCize KanBoard setup 2018-09-13 20:38:36 +02:00
986c13f4c7
LXCize GNU Health setup 2018-09-13 20:32:57 +02:00
01fc001990
LXCize FrontlineSMS setup 2018-09-13 19:57:14 +02:00
7dbfe8533c
LXCize CTS setup 2018-09-13 19:27:23 +02:00
4c5568f807
amendments 2018-09-13 19:17:29 +02:00
d3ecfbf4e7
LXCize CC setup 2018-09-13 18:31:19 +02:00
367deb0897
Set PATH in lxc-build 2018-09-13 16:21:16 +02:00
0fda481317
LXCize RabbitMQ setup 2018-09-13 16:05:13 +02:00
677ac1bc4c
LXCize MariaDB setup 2018-09-13 15:50:30 +02:00
7ebdfc1866
Add missing mounts 2018-09-13 14:58:03 +02:00
ea4b883b3f
LXCize Ushahidi build 2018-09-13 14:44:32 +02:00
2b46473cb0
LXCize Sigmah build 2018-09-13 14:39:35 +02:00
2c965f7cfb
LXCize SeedDMS build 2018-09-13 14:35:42 +02:00
79f170ff01
LXCize Sahana build 2018-09-13 14:26:27 +02:00
523765188a
LXCize RabbitMQ build 2018-09-13 14:20:37 +02:00
384f43748b
Reorder pandora build 2018-09-13 14:17:45 +02:00
629e247570
LXCize Pandora build 2018-09-13 14:15:22 +02:00
2f6ba72cea
LXCize OMK build 2018-09-13 14:08:52 +02:00
41b598936f
Fix fix-apk dropping last package 2018-09-13 13:59:56 +02:00
cbd65805f8
LXCize ODK Build build 2018-09-13 13:50:40 +02:00
05bf6da6ce
LXCize ODK build 2018-09-13 13:42:36 +02:00
89b11a6112
LXCize Motech build 2018-09-13 13:39:25 +02:00
444cfb58b1
LXCize MifosX build 2018-09-13 13:34:27 +02:00
cecb8d7dba
LXCize MariaDB build 2018-09-13 13:27:09 +02:00
ce71447928
LXCize KanBoard build 2018-09-13 13:22:15 +02:00
ecf1143524
LXCize GNU Health build 2018-09-13 13:12:46 +02:00
cd6d3815d6
LXCize Frontlinesms build 2018-09-13 13:05:39 +02:00
88008ad40b
LXCize CTS build 2018-09-13 10:38:58 +02:00
6583acc129
Freeze CC version 2018-09-12 19:42:12 +02:00
344b6be624
fixlayer 2018-09-12 19:04:55 +02:00
c7c949eead
cc build 2018-09-12 16:16:38 +02:00
d6447bb437
fix-apk 2018-09-12 16:12:23 +02:00
a25186b5ea
Dockerize the lxc-build a bit more 2018-09-12 16:08:10 +02:00
939d9b0d45
Fix tomcat build 2018-09-12 14:19:36 +02:00
b02d70df38
remove ephemeral layer 2018-09-12 13:59:37 +02:00
5facbb1b35
Modularize proxy registration 2018-09-12 13:19:16 +02:00
9f02c98d1b
ckan service 2018-09-12 11:56:31 +02:00
bc4c073b43
CKAN setup 2018-09-12 11:44:30 +02:00
cff204ca46
Add un/register container IP 2018-09-12 11:12:30 +02:00
fa70f85acb
solr global 2018-09-11 20:28:59 +02:00
e8354e59c9
Add ENV 2018-09-11 19:26:37 +02:00
a9e99a82c5
Create /var/log/lxc 2018-09-11 18:36:08 +02:00
0b56beea89
Add auxiliary script for LXC compilation 2018-09-11 17:08:09 +02:00
9b4be311e6
ckan test 2018-09-07 18:46:30 +02:00
354c98bbf0
typo 2018-09-07 16:03:14 +02:00
89126185eb
Update lxcfiles to LXC 3 2018-09-07 15:47:44 +02:00
bed2d7f5f6
Use compiled LXC 2018-09-07 15:20:07 +02:00
de640bb005
Prepare for LXC3 2018-09-07 14:37:38 +02:00
6ca49d4865
setuid + wget simplification 2018-09-06 21:15:43 +02:00
26bbab959f
bit differently 2018-09-06 14:55:51 +02:00
b56ac216ce
postgres test2 2018-09-06 14:52:46 +02:00
03050dd389
pg 2018-09-06 14:27:40 +02:00
5db1ed2baf
postgres uid tryfix 2018-09-06 14:20:30 +02:00
9a8c2103d4
yeah.. more vars 2018-09-06 10:02:10 +02:00
fd07ec7cb8
guess what? more vars 2018-09-06 09:50:10 +02:00
d0e3be5ce6
more vars 2018-09-06 09:45:13 +02:00
43c8962b0f
fix vars 2018-09-06 09:41:40 +02:00
6427a6ec09
Make lxc-build a bit more presentable 2018-09-06 09:32:20 +02:00
933a75bf57
iptables 2018-09-05 23:12:31 +02:00
eb69ea3cf1
fixes 2018-09-05 23:08:55 +02:00
1b07ef795e
CKAN + deps stup test 2018-09-05 22:20:24 +02:00
402ac5a469
Remove debug messages 2018-09-05 21:54:58 +02:00
8a65b6a0f4
copy_tree 2018-09-05 21:21:07 +02:00
824af776d9
more fixes 2018-09-05 19:44:23 +02:00
dd955c5e59
set -ev 2018-09-05 19:34:21 +02:00
260c8159c7
minor fixes 2018-09-05 19:29:56 +02:00
d21b09d547
minor fixes 2018-09-05 19:26:15 +02:00
1608b7a93f
Some lxc-build fixes 2018-09-05 18:25:27 +02:00
26075bad79
CRLF 2018-09-05 17:46:44 +02:00
deacaa94be
lxc-build + CKAN test 2018-09-05 17:41:38 +02:00
c3255cb00d
+x 2018-09-04 22:52:42 +02:00
1619380fdc
scripts 2018-09-04 22:50:41 +02:00
3a6011aad4
LXCize basic runtimes 2018-09-04 22:45:52 +02:00
b6ac14880b
fix 2018-09-04 22:13:08 +02:00
1c40252112
Initial commit for LXCification 2018-09-04 21:42:26 +02:00
779 changed files with 94173 additions and 11586 deletions

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

6
.gitmodules vendored Normal file

@ -0,0 +1,6 @@
[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

@ -1,40 +0,0 @@
#!/bin/sh
set -e
# 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}/sahana-demo.sh
${SOURCE_DIR}/sambro.sh
${SOURCE_DIR}/seeddms.sh
${SOURCE_DIR}/sigmah.sh
${SOURCE_DIR}/ushahidi.sh
# Perform cleanup only if DEBUG mode is not set
[ ${DEBUG:-0} -eq 1 ] && exit 0
# Clean package cache
rm -rf /var/cache/apk/*
# Remove root settings
find /root -mindepth 1 -maxdepth 1 | xargs rm -rf
# Change root password
passwd

@ -1,90 +0,0 @@
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
In case you're setting up a VMWare virtual machine, select OS type *Other Linux 3.x kernel 64-bit* and after you create the VM, manually edit the `*.vmx` file using a text editor and set there `mem.hotadd = "FALSE"`. Failing to do so will result in system unable to boot. Other hypervizors don't need this adjustment.
## Operating system installation
Download **Alpine Virtual 3.8.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/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 |

@ -1,13 +0,0 @@
#!/bin/sh
set -e
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

@ -1,23 +0,0 @@
FROM java
LABEL maintainer="Disassembler <disassembler@dasm.cz>"
RUN \
# Download and install ActiveMQ
wget http://archive.apache.org/dist/activemq/5.15.5/apache-activemq-5.15.5-bin.tar.gz -O /tmp/activemq.tgz \
&& tar xf /tmp/activemq.tgz -C /srv \
&& mv /srv/apache-activemq-5.15.5 /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"]

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

@ -1,19 +0,0 @@
#!/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

@ -1,100 +0,0 @@
#!/bin/sh
# Based on
# https://wiki.alpinelinux.org/wiki/LVM_on_LUKS
# Prerequisites for this script
# setup-interfaces
# ifup eth0
# Set up repositories
cat <<EOF >/etc/apk/repositories
http://dl-cdn.alpinelinux.org/alpine/v3.8/main
http://dl-cdn.alpinelinux.org/alpine/v3.8/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 100%FREE vg0 -n root
# Format
mkfs.ext4 -m0 /dev/sda1
mkfs.ext4 -m1 /dev/vg0/root
# 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 | cut -d' ' -f2 | 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 (ignore the errors)
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 'spotter.vm' >/mnt/etc/hostname
echo '127.0.0.1 spotter.vm 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
vgchange -a n
cryptsetup luksClose system
poweroff

@ -0,0 +1,28 @@
# 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
apk/spoc Submodule

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

1
apk/vmmgr Submodule

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

@ -1,12 +0,0 @@
#!/bin/sh
set -e
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

@ -1,6 +0,0 @@
FROM alpine
LABEL maintainer="Disassembler <disassembler@dasm.cz>"
RUN \
# Install Java 1.8 JRE
apk --no-cache add openjdk8-jre-base

@ -1,6 +0,0 @@
FROM alpine
LABEL 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

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

@ -1,11 +0,0 @@
FROM alpine
LABEL 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

@ -1,33 +0,0 @@
FROM alpine
LABEL 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

@ -1,15 +0,0 @@
FROM java
LABEL maintainer="Disassembler <disassembler@dasm.cz>"
RUN \
# Install Tomcat 8
wget http://mirror.hosting90.cz/apache/tomcat/tomcat-8/v8.0.53/bin/apache-tomcat-8.0.53.tar.gz -O /tmp/apache-tomcat-8.tgz \
&& tar xf /tmp/apache-tomcat-8.tgz -C /srv \
&& mv /srv/apache-tomcat-8.0.53 /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/ /

@ -1,70 +0,0 @@
#!/bin/sh
set -e
SOURCE_DIR=$(realpath $(dirname "${0}"))/basic
# Install packages
apk --no-cache add curl docker e2fsprogs-extra gettext kbd-misc libressl python3 py3-bcrypt py3-cffi py3-dnspython py3-jinja2 py3-requests py3-six py3-werkzeug nginx util-linux
if [ ${DEBUG:-0} -eq 1 ]; then
# Install some utilities for DEBUG mode
apk --no-cache add git file htop less openssh-server openssh-sftp-server
fi
# Copy root profile files and settings for DEBUG mode
if [ ${DEBUG:-0} -eq 1 ]; then
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
fi
# Copy boot configuration
cp ${SOURCE_DIR}/boot/extlinux.conf /boot/extlinux.conf
cp ${SOURCE_DIR}/boot/vm.txt /boot/vm.txt
cp ${SOURCE_DIR}/etc/inittab /etc/inittab
cp ${SOURCE_DIR}/sbin/extend-disk /sbin/extend-disk
cp ${SOURCE_DIR}/sbin/vmtty /sbin/vmtty
>/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
# 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
chmod +x /usr/bin/acme.sh
# Copy AppMgr resources
cp ${SOURCE_DIR}/etc/init.d/vm-appmgr /etc/init.d/vm-appmgr
rc-update -u
cp -r ${SOURCE_DIR}/srv/vm /srv/vm
ln -s /srv/vm/cli.py /usr/bin/vm-appmgr
# Create a self-signed certificate
vm-appmgr create-selfsigned
# Configure nginx
cp ${SOURCE_DIR}/etc/nginx/nginx.conf /etc/nginx/nginx.conf
# Configure services
for SERVICE in consolefont crond nginx ntpd sshd vm-appmgr swap; 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 -u
rc-update add docker
service docker start
# Create basic images
docker build -t alpine ${SOURCE_DIR}
# Set dummy host and generate related files
vm-appmgr update-host spotter.vm 443

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

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

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

@ -1,40 +0,0 @@
#!/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 cgroups
}
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 10 /var/run/docker.sock
}

@ -1,6 +0,0 @@
#!/sbin/openrc-run
command=/srv/vm/wsgi.py
description="VM application manager"
pidfile=/var/run/vm-appmgr.pid
start_stop_daemon_args="--background --make-pidfile --stderr /dev/null --stdout /dev/null"

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

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILc3Mu7OlKrV7VqDQZ31vT3I3JJxtNNBiemUTRQVOZ3I Disassembler

@ -1,39 +0,0 @@
#!/bin/sh
set -e
# No resizing with less than 10k unused blocks
BLOCKS_FREE=$(/usr/bin/awk '/sda$/ {blocks = $3} /sda\d/ {blocks -= $3} END {print blocks}' /proc/partitions)
[ ${BLOCKS_FREE} -lt 10240 ] && exit 0
# Resize physical partition
# Force busybox fdisk as util-linux fdisk breaks subsequent partx command
cat <<EOF | /bin/busybox fdisk /dev/sda || /bin/true
d
2
n
p
2
t
2
8e
w
EOF
# Re-read partition table
/usr/sbin/partx -u /dev/sda2
# Resize dmcrypt and LVM PV
/sbin/cryptsetup resize system
/sbin/pvresize /dev/mapper/system
# Create swap if it doesn't exist
if [ ! -e /dev/vg0/swap ]; then
/sbin/lvcreate -L 4G vg0 -n swap
/sbin/mkswap /dev/vg0/swap
fi
# Extend LV and underlying filesystem
/sbin/lvextend -l +100%FREE vg0/root
/usr/sbin/resize2fs /dev/vg0/root

@ -1,8 +0,0 @@
#!/bin/sh
# Rebuild /etc/issue
/usr/bin/vm-appmgr rebuild-issue
# Remove double-escaping needed for the real /etc/issue
/bin/sed 's|\\\\|\\|g' /etc/issue
# Wait for key press
read a

@ -1,344 +0,0 @@
# -*- coding: utf-8 -*-
import json
import os
import shutil
import subprocess
from . import confupdater
from . import tools
from . import validator
VERSION = '0.0.1'
CONF_FILE = '/srv/vm/config.json'
ISSUE_FILE = '/etc/issue'
NGINX_DIR = '/etc/nginx/conf.d'
ACME_CRON = '/etc/periodic/daily/acme-sh'
CERT_PUB_FILE = '/etc/ssl/services.pem'
CERT_KEY_FILE = '/etc/ssl/services.key'
CERT_SAN_FILE = '/etc/ssl/san.cnf'
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 /502.html;
location = /502.html {{
root /srv/vm/templates;
}}
location = /vm-ping {{
add_header Content-Type text/plain;
return 200 "vm-pong";
}}
}}
'''
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;
}}
location = /vm-ping {{
add_header Content-Type text/plain;
return 200 "vm-pong";
}}
}}
server {{
listen [::]:{port} ssl http2 default_server ipv6only=off;
location / {{
proxy_pass http://127.0.0.1:8080;
}}
location /static {{
root /srv/vm;
}}
error_page 502 /502.html;
location = /502.html {{
root /srv/vm/templates;
}}
location = /vm-ping {{
add_header Content-Type text/plain;
return 200 "vm-pong";
}}
}}
'''
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[1m{url}\x1b[0m ve Vašem
internetovém prohlížeči.
\x1b[0;30m
'''
ACME_CRON_TEMPLATE = '''#!/bin/sh
[ -x /usr/bin/acme.sh ] && /usr/bin/acme.sh --cron >/dev/null
'''
CERT_SAN = '''[ req ]
distinguished_name = dn
x509_extensions = ext
[ dn ]
[ ext ]
subjectAltName=DNS:{domain},DNS:*.{domain}"
'''
class AppMgr:
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 not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
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 visibility for the app in the configuration
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
self.conf['apps'][app]['visible'] = True
self.save_conf()
def hide_tiles(self, app):
# Update visibility for the app in the configuration
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
self.conf['apps'][app]['visible'] = False
self.save_conf()
def start_app(self, app):
# Start the actual app service
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
tools.start_service(app)
def stop_app(self, app):
# Stop the actual app service
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
tools.stop_service(app)
# 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([tools.is_service_started(d) for d in deps[dep]]):
tools.stop_service(dep)
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.items():
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 enable_autostart(self, app):
# Add the app to OpenRC default runlevel
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
subprocess.run(['/sbin/rc-update', 'add', app])
def disable_autostart(self, app):
# Remove the app from OpenRC default runlevel
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
subprocess.run(['/sbin/rc-update', 'del', app])
def register_proxy(self, app):
# Rebuild nginx configuration using IP of referenced app container and reload nginx
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
self.update_proxy_conf(app, tools.get_container_ip(app))
tools.reload_nginx()
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
if not validator.is_valid_app(app, self.conf):
raise validator.InvalidValueException('app', app)
self.update_proxy_conf(app, tools.NULL_IP)
tools.reload_nginx()
def update_host(self, domain, port, restart_nginx=True):
# Update domain and port and rebuild all configurtion. Defer nginx restart when updating from web interface
if not validator.is_valid_domain(domain):
raise validator.InvalidValueException('domain', domain)
if not validator.is_valid_port(port):
raise validator.InvalidValueException('port', port)
self.domain = self.conf['host']['domain'] = domain
self.port = self.conf['host']['port'] = port
self.save_conf()
self.rebuild_nginx(restart_nginx)
self.update_apps_urls()
def rebuild_nginx(self, restart_nginx):
# 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, tools.NULL_IP)
# Restart nginx to properly bind the new listen port
if restart_nginx:
tools.restart_nginx()
def rebuild_issue(self):
# Compile the HTTPS host displayed in terminal banner
domain = self.domain
# If the dummy host is used, take an IP address of a primary interface instead
if domain == 'spotter.vm':
domain = tools.get_local_ipv4()
if not domain:
domain = tools.get_local_ipv6()
if not domain:
domain = '127.0.0.1'
# Rebuild the terminal banner
with open(ISSUE_FILE, 'w') as f:
f.write(ISSUE_TEMPLATE.format(url=tools.compile_url(domain, self.port)))
def update_apps_urls(self):
# Update configuration for respective applications
confupdater.update_url(tools.compile_url(self.domain, self.port, None))
# Restart currently running apps in order to update config and re-register nginx proxy
for app in self.conf['apps']:
if tools.is_service_started(app):
tools.restart_service(app)
def update_common(self, email, gmaps_api_key):
# Update common configuration values
if email != None:
# Update email
if not validator.is_valid_email(email):
raise validator.InvalidValueException('email', email)
self.conf['common']['email'] = email
confupdater.update_email(email)
if gmaps_api_key != None:
# Update Google Maps API key
self.conf['common']['gmaps-api-key'] = gmaps_api_key
confupdater.update_gmaps_api_key(gmaps_api_key)
# Save config to file
self.save_conf()
# Restart currently running apps in order to update config
for app in self.conf['apps']:
if tools.is_service_started(app):
tools.restart_service(app)
def update_password(self, oldpassword, newpassword):
# Update LUKS password and adminpwd for WSGI application
tools.update_luks_password(oldpassword, newpassword)
self.conf['host']['adminpwd'] = tools.adminpwd_hash(newpassword)
# Save config to file
self.save_conf()
def create_selfsigned(self):
# Create selfsigned certificate with wildcard alternative subject name
with open(os.path.join(CERT_SAN_FILE), 'w') as f:
f.write(CERT_SAN.format(domain=self.domain))
subprocess.run(['openssl', 'req', '-config', CERT_SAN_FILE, '-x509', '-new', '-out', CERT_PUB_FILE, '-keyout', CERT_KEY_FILE, '-nodes', '-days', '7305', '-subj', '/CN={}'.format(self.domain)], check=True)
os.chmod(CERT_KEY_FILE, 0o640)
def request_cert(self):
# Remove all possible conflicting certificates requested in the past
certs = [i for i in os.listdir('/etc/acme.sh.d') if i not in ('account.conf', 'ca', 'http.header')]
for cert in certs:
if cert != self.domain:
subprocess.run(['/usr/bin/acme.sh', '--remove', '-d', cert])
# Compile an acme.sh command for certificate requisition only if the certificate hasn't been requested before
if not os.path.exists(os.path.join('/etc/acme.sh.d', self.domain)):
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']
# Request the certificate
subprocess.run(cmd, check=True)
# Otherwise just try to renew
else:
# Acme.sh returns code 2 on skipped renew
try:
subprocess.run(['/usr/bin/acme.sh', '--renew', '-d', self.domain], check=True)
except subprocess.CalledProcessError as e:
if e.returncode != 2:
raise
# Install the issued certificate
subprocess.run(['/usr/bin/acme.sh', '--install-cert', '-d', self.domain, '--key-file', CERT_KEY_FILE, '--fullchain-file', CERT_PUB_FILE, '--reloadcmd', '/sbin/service nginx reload'], check=True)
# Install acme.sh cronjob
with open(ACME_CRON, 'w') as f:
f.write(ACME_CRON_TEMPLATE)
def install_cert(self, public_file, private_file):
# Remove acme.sh cronjob
if os.path.exists(ACME_CRON):
os.unlink(ACME_CRON)
# Copy certificate files
shutil.copyfile(public_file, CERT_PUB_FILE)
shutil.copyfile(private_file, CERT_KEY_FILE)
os.chmod(CERT_KEY_FILE, 0o640)
# Reload nginx
tools.reload_nginx()

@ -1,138 +0,0 @@
# -*- coding: utf-8 -*-
import os
import shutil
import subprocess
from . import tools
TMP_FILE = '/tmp/confupdater.tmp'
def replace_file_line(filename, oldline, newline):
with open(filename, 'r') as conf, open(TMP_FILE, 'w') as tmp:
for line in conf:
# Find line starting with oldline
if line.startswith(oldline):
# Replace te line with oldline, newline, \n (to not repeat the oldline in newline)
tmp.write(oldline)
tmp.write(newline)
tmp.write('\n')
# Dump the rest of the file and break the loop
tmp.write(conf.read())
break
else:
tmp.write(line)
# Copy the file contents to the original file (preserves permissions of the original file)
shutil.copyfile(TMP_FILE, filename)
os.unlink(TMP_FILE)
def run_mysql_query(query, database):
maria_started = tools.is_service_started('mariadb')
if not maria_started:
tools.start_service('mariadb')
subprocess.run(['docker', 'exec', '-i', 'mariadb', 'mysql', '-e', query, database])
if not maria_started:
tools.stop_service('mariadb')
def app_exists(app):
return os.path.exists(os.path.join('/srv/', app))
def update_gmaps_api_key(api_key):
# CKAN
if app_exists('ckan'):
replace_file_line('/srv/ckan/conf/ckan.ini', 'ckanext.geoview.gapi_key = ', api_key)
# Crisis Cleanup
if app_exists('crisiscleanup'):
replace_file_line('/srv/crisiscleanup/conf/boot.rb', 'ENV[\'GOOGLE_MAPS_API_KEY\'] = ', api_key)
# Pan.do/ra
if app_exists('pandora'):
replace_file_line('/srv/pandora/conf/local_settings.py', 'GOOGLE_API_KEY = ', '\'{}\''.format(api_key))
# Sahana
if app_exists('sahana'):
replace_file_line('/srv/sahana/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
# Sahana Demo
if app_exists('sahana-demo'):
replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
# SAMBRO
if app_exists('sambro'):
replace_file_line('/srv/sambro/conf/000_config.py', 'settings.gis.api_google = ', '"{}"'.format(api_key))
# Sigmah
if app_exists('sigmah'):
replace_file_line('/srv/sigmah/conf/sigmah.properties', 'maps.key=', api_key)
# Ushahidi
if app_exists('ushahidi'):
replace_file_line('/srv/ushahidi/conf/config.json', ' "google_analytics_id": ', '"{}"'.format(api_key))
def update_email(email):
# CKAN
if app_exists('ckan'):
replace_file_line('/srv/ckan/conf/ckan.ini', 'smtp.mail_from = ', email)
replace_file_line('/srv/ckan-datapusher/conf/datapusher_settings.py', 'FROM_EMAIL = ', '\'{}\''.format(email))
# Crisis Cleanup
if app_exists('crisiscleanup'):
replace_file_line('/srv/crisiscleanup/conf/initializers/devise.rb', ' config.mailer_sender = ', '\'{}\''.format(email))
# CTS
if app_exists('cts'):
replace_file_line('/srv/cts/conf/spotter.py', 'SERVER_EMAIL = ', '\'{}\''.format(email))
# GNU Health
if app_exists('gnuhealth'):
replace_file_line('/srv/gnuhealth/conf/trytond.conf', 'from = ', email)
# KanBoard
if app_exists('kanboard'):
replace_file_line('/srv/kanboard/conf/config.php', 'define(\'MAIL_FROM\', ', '\'{}\');'.format(email))
# Mifos X
if app_exists('mifosx'):
query = 'UPDATE `c_external_service_properties` SET `value` = "{}" WHERE `external_service_id` = 2 and `name` LIKE "username";'.format(email)
run_mysql_query(query, 'mifostenant-default')
# Sahana
if app_exists('sahana'):
replace_file_line('/srv/sahana/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
replace_file_line('/srv/sahana/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
# Sahana Demo
if app_exists('sahana-demo'):
replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
# SAMBRO
if app_exists('sambro'):
replace_file_line('/srv/sambro/conf/000_config.py', 'settings.mail.sender = ', '"{}"'.format(email))
replace_file_line('/srv/sambro/conf/000_config.py', 'settings.mail.approver = ', '"{}"'.format(email))
# SeedDMS
if app_exists('seeddms'):
replace_file_line('/srv/seeddms/conf/settings.xml', ' <smtp smtpServer="postfix" smtpPort="25" smtpSendFrom=', '"{}" smtpUser="" smtpPassword=""/>'.format(email))
# Sigmah
if app_exists('sigmah'):
replace_file_line('/srv/sigmah/conf/sigmah.properties', 'mail.from.address=', email)
replace_file_line('/srv/sigmah/conf/sigmah.properties', 'mail.support.to=', email)
# Ushahidi
if app_exists('ushahidi'):
email_json = '{{\\"incoming_type\\":\\"IMAP\\",\\"incoming_server\\":\\"localhost\\",\\"incoming_port\\":143,\\"incoming_security\\":\\"None\\",\\"incoming_username\\":\\"{}\\",\\"incoming_password\\":\\"password\\",\\"outgoing_type\\":\\"SMTP\\",\\"outgoing_server\\":\\"postfix\\",\\"outgoing_port\\":25,\\"outgoing_security\\":\\"None\\",\\"outgoing_username\\":\\"{}\\",\\"outgoing_password\\":\\"password\\",\\"from\\":\\"{}\\",\\"from_name\\":\\"Ushahidi\\"}}'.format(email, email, email)
query = 'UPDATE `config` SET `config_value` = "{}" WHERE `group_name` LIKE "data-provider" AND `config_key` LIKE "email";'.format(email_json)
run_mysql_query(query, 'ushahidi')
query = 'UPDATE `config` SET `config_value` = "\\"{}\\"" WHERE `group_name` LIKE "site" AND `config_key` LIKE "email";'.format(email)
run_mysql_query(query, 'ushahidi')
def update_url(host):
# CKAN
if app_exists('ckan'):
replace_file_line('/srv/ckan/conf/ckan.ini', 'ckan.site_url = ', 'https://ckan.{}'.format(host))
# Motech
if app_exists('motech'):
replace_file_line('/srv/motech/conf/config/motech-settings.properties', 'server.url=', 'https://motech.{}'.format(host))
# Pan.do/ra
if app_exists('pandora'):
replace_file_line('/srv/pandora/conf/config.jsonc', ' "url": ', '"pandora.{}"'.format(host))
# Sahana
if app_exists('sahana'):
replace_file_line('/srv/sahana/conf/000_config.py', 'settings.base.public_url = ', '"https://sahana.{}"'.format(host))
# Sahana Demo
if app_exists('sahana-demo'):
replace_file_line('/srv/sahana-demo/conf/000_config.py', 'settings.base.public_url = ', '"https://sahana-demo.{}"'.format(host))
# SAMBRO
if app_exists('sambro'):
replace_file_line('/srv/sambro/conf/000_config.py', 'settings.base.public_url = ', '"https://sambro.{}"'.format(host))
# Ushahidi
if app_exists('ushahidi'):
replace_file_line('/srv/ushahidi/conf/config.json', ' "backend_url": ', '"https://ush.{}/platform",'.format(host))
api_url = '\\"https:\\\\/\\\\/ush.{}\\\\/platform\\\\/api\\\\/v3\\\\/config\\\\/data-provider\\"'.format(host)
query = 'UPDATE `config` SET `config_value` = "{}" WHERE `group_name` LIKE "data-provider" AND `config_key` LIKE "url";'.format(api_url)
run_mysql_query(query, 'ushahidi')

@ -1,124 +0,0 @@
# -*- coding: utf-8 -*-
import bcrypt
import dns.exception
import dns.resolver
import os
import requests
import socket
import ssl
import subprocess
NULL_IP = '[100::1]'
def compile_url(domain, port, proto='https'):
port = ':{}'.format(port) if (proto == 'https' and port != '443') or (proto == 'http' and port != '80') else ''
host = '{}{}'.format(domain, port)
return '{}://{}'.format(proto, host) if proto is not None else host
def get_container_ip(app):
# Return an IP address of a container. If the container is not running, return address from IPv6 discard prefix instead
try:
return subprocess.run(['/usr/bin/docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}', app], check=True, stdout=subprocess.PIPE).stdout.decode().strip()
except:
return NULL_IP
def get_local_ipv4():
# Return first routable IPv4 address
try:
return subprocess.run(['/sbin/ip', 'route', 'get', '1'], check=True, stdout=subprocess.PIPE).stdout.decode().split()[-1]
except:
return None
def get_local_ipv6():
# Return first routable IPv6 address
try:
return subprocess.run(['/sbin/ip', 'route', 'get', '2003::'], check=True, stdout=subprocess.PIPE).stdout.decode().split()[-3]
except:
return None
def get_external_ip(family):
# Return external IP address of given family via 3rd party service
allowed_gai_family = requests.packages.urllib3.util.connection.allowed_gai_family
try:
requests.packages.urllib3.util.connection.allowed_gai_family = lambda: family
return requests.get('https://tools.dasm.cz/myip.php', timeout=5).text
except:
return None
finally:
requests.packages.urllib3.util.connection.allowed_gai_family = allowed_gai_family
def get_external_ipv4():
# Return external IPv4 address
return get_external_ip(socket.AF_INET)
def get_external_ipv6():
# Return external IPv6 address
return get_external_ip(socket.AF_INET6)
resolver = dns.resolver.Resolver()
resolver.timeout = 3
resolver.lifetime = 3
resolver.nameservers = ['8.8.8.8', '8.8.4.4', '2001:4860:4860::8888', '2001:4860:4860::8844']
def resolve_ip(domain, type):
# Resolve domain name using Google Public DNS
try:
return resolver.query(domain, type)[0].address
except dns.exception.Timeout:
raise
except:
return None
def ping_url(url):
try:
return requests.post('https://tools.dasm.cz/vm-ping.php', data = {'url': url}, timeout=5).text == 'vm-pong'
except requests.exceptions.Timeout:
raise
except:
return False
def is_service_started(app):
# Check OpenRC service status without calling any binary
return os.path.exists(os.path.join('/run/openrc/started', app))
def is_service_autostarted(app):
# Check OpenRC service enablement
return os.path.exists(os.path.join('/etc/runlevels/default', app))
def start_service(service):
subprocess.run(['/sbin/service', service, 'start'], check=True)
def stop_service(service):
subprocess.run(['/sbin/service', service, 'stop'], check=True)
def restart_service(service):
subprocess.run(['/sbin/service', service, 'restart'])
def reload_nginx():
subprocess.run(['/sbin/service', 'nginx', 'reload'])
def restart_nginx():
restart_service('nginx')
def get_cert_info(cert):
data = ssl._ssl._test_decode_cert(cert)
data['subject'] = dict(data['subject'][i][0] for i in range(len(data['subject'])))
data['issuer'] = dict(data['issuer'][i][0] for i in range(len(data['issuer'])))
return data
def adminpwd_hash(password):
return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
def adminpwd_verify(password, hash):
return bcrypt.checkpw(password.encode(), hash.encode())
def update_luks_password(oldpassword, newpassword):
input = '{}\n{}'.format(oldpassword, newpassword).encode()
subprocess.run(['cryptsetup', 'luksChangeKey', '/dev/sda2'], input=input, check=True)
def shutdown_vm():
subprocess.run(['/sbin/poweroff'])
def reboot_vm():
subprocess.run(['/sbin/reboot'])

@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
import re
domain_re = re.compile(r'^(?!-)[a-z0-9-]{1,63}(?<!-)(?:\.(?!-)[a-z0-9-]{1,63}(?<!-)){0,125}\.(?!-)(?![0-9]+$)[a-z0-9-]{1,63}(?<!-)$')
box_re = re.compile(r'^[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*$')
class InvalidValueException(Exception):
pass
def is_valid_domain(domain):
return bool(domain_re.match(domain))
def is_valid_port(port):
try:
port = int(port)
return port > 0 and port < 65536
except:
return False
def is_valid_app(app, conf):
return app in conf['apps']
def is_valid_email(email):
parts = email.split('@')
if len(parts) != 2:
return False
return bool(box_re.match(parts[0])) and bool(domain_re.match(parts[1]))

@ -1,282 +0,0 @@
# -*- coding: utf-8 -*-
import json
import os
from werkzeug.exceptions import BadRequest, HTTPException, NotFound
from werkzeug.routing import Map, Rule
from werkzeug.utils import redirect
from werkzeug.wrappers import Request, Response
from werkzeug.wsgi import ClosingIterator
from jinja2 import Environment, FileSystemLoader
from . import AppMgr, CERT_PUB_FILE
from . import tools
from .validator import InvalidValueException
from .wsgilang import WSGILang
from .wsgisession import WSGISession
SESSION_KEY = os.urandom(26)
class WSGIApp(object):
def __init__(self):
self.jinja_env = Environment(loader=FileSystemLoader('/srv/vm/templates'), autoescape=True, lstrip_blocks=True, trim_blocks=True)
self.jinja_env.globals.update(is_service_autostarted=tools.is_service_autostarted)
self.jinja_env.globals.update(is_service_started=tools.is_service_started)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
request = Request(environ)
# Enhance request
request.mgr = AppMgr()
request.session = WSGISession(request.cookies, SESSION_KEY)
request.session.lang = WSGILang()
# Dispatch request
response = self.dispatch_request(request)
# Save session if changed
request.session.save(response)
return response(environ, start_response)
def dispatch_request(self, request):
adapter = self.get_url_map(request.session).bind_to_environ(request.environ)
try:
endpoint, values = adapter.match()
return getattr(self, endpoint)(request, **values)
except NotFound as e:
# Return custom 404 page
response = self.render_template('404.html', request)
response.status_code = 404
return response
except HTTPException as e:
return e
def get_url_map(self, session):
rules = [
Rule('/', endpoint='portal_view'),
Rule('/login', methods=['GET'], endpoint='login_view'),
Rule('/login', methods=['POST'], endpoint='login_action'),
Rule('/logout', endpoint='logout_action')
]
if session['admin']:
rules += [
Rule('/setup-host', endpoint='setup_host_view'),
Rule('/setup-apps', endpoint='setup_apps_view'),
Rule('/update-host', endpoint='update_host_action'),
Rule('/verify-dns', endpoint='verify_dns_action'),
Rule('/verify-https', endpoint='verify_http_action', defaults={'proto': 'https'}),
Rule('/verify-http', endpoint='verify_http_action', defaults={'proto': 'http'}),
Rule('/update-cert', endpoint='update_cert_action'),
Rule('/update-common', endpoint='update_common_action'),
Rule('/update-app-visibility', endpoint='update_app_visibility_action'),
Rule('/update-app-autostart', endpoint='update_app_autostart_action'),
Rule('/start-app', endpoint='start_app_action'),
Rule('/stop-app', endpoint='stop_app_action'),
Rule('/update-password', endpoint='update_password_action'),
Rule('/shutdown-vm', endpoint='shutdown_vm_action'),
Rule('/reboot-vm', endpoint='reboot_vm_action'),
]
return Map(rules)
def render_template(self, template_name, request, **context):
# Enhance context
context['conf'] = request.mgr.conf
context['session'] = request.session
# Render template
t = self.jinja_env.get_template(template_name)
return Response(t.render(context), mimetype='text/html')
def render_json(self, data):
return Response(json.dumps(data), mimetype='application/json')
def login_view(self, request):
return self.render_template('login.html', request)
def login_action(self, request):
password = request.form['password']
if tools.adminpwd_verify(password, request.mgr.conf['host']['adminpwd']):
request.session['admin'] = True
return redirect('/')
else:
return self.render_template('login.html', request, message=request.session.lang.bad_password())
def logout_action(self, request):
request.session.reset()
return redirect('/')
def portal_view(self, request):
# Default view. If domain is set to the default dummy domain, redirects to first-run setup instead.
if request.session['admin']:
return self.render_template('portal-admin.html', request)
return self.render_template('portal-user.html', request)
def setup_host_view(self, request):
# First-run setup view.
ex_ipv4 = tools.get_external_ipv4()
ex_ipv6 = tools.get_external_ipv6()
in_ipv4 = tools.get_local_ipv4()
in_ipv6 = tools.get_local_ipv6()
is_letsencrypt = os.path.exists('/etc/periodic/daily/acme-sh')
cert_info = tools.get_cert_info(CERT_PUB_FILE)
return self.render_template('setup-host.html', request, ex_ipv4=ex_ipv4, ex_ipv6=ex_ipv6, in_ipv4=in_ipv4, in_ipv6=in_ipv6, is_letsencrypt=is_letsencrypt, cert_info=cert_info)
def setup_apps_view(self, request):
# Application manager view.
return self.render_template('setup-apps.html', request)
def update_host_action(self, request):
# Update domain and port, then restart nginx
try:
domain = request.form['domain']
port = request.form['port']
request.mgr.update_host(domain, port, False)
server_name = request.environ['HTTP_X_FORWARDED_SERVER_NAME']
url = '{}/setup-host'.format(tools.compile_url(server_name, port))
response = self.render_json({'ok': request.session.lang.host_updated(url, url)})
response.call_on_close(tools.restart_nginx)
return response
except BadRequest:
return self.render_json({'error': request.session.lang.malformed_request()})
except InvalidValueException as e:
if e.args[0] == 'domain':
return self.render_json({'error': request.session.lang.invalid_domain(domain)})
if e.args[0] == 'port':
return self.render_json({'error': request.session.lang.invalid_port(port)})
def verify_dns_action(self, request):
# Check if all FQDNs for all applications are resolvable and point to current external IP
mgr = request.mgr
domains = [mgr.domain]+['{}.{}'.format(mgr.conf['apps'][app]['host'], mgr.domain) for app in mgr.conf['apps']]
ipv4 = tools.get_external_ipv4()
ipv6 = tools.get_external_ipv6()
for domain in domains:
try:
a = tools.resolve_ip(domain, 'A')
aaaa = tools.resolve_ip(domain, 'AAAA')
if not a and not aaaa:
return self.render_json({'error': request.session.lang.dns_record_does_not_exist(domain)})
if a and a != ipv4:
return self.render_json({'error': request.session.lang.dns_record_mismatch(domain, a, ipv4)})
if aaaa and aaaa != ipv6:
return self.render_json({'error': request.session.lang.dns_record_mismatch(domain, aaaa, ipv6)})
except:
return self.render_json({'error': request.session.lang.dns_timeout()})
return self.render_json({'ok': request.session.lang.dns_records_ok()})
def verify_http_action(self, request, **kwargs):
# Check if all applications are accessible from the internet using 3rd party ping service
proto = kwargs['proto']
mgr = request.mgr
port = mgr.port if proto == 'https' else '80'
domains = [mgr.domain]+['{}.{}'.format(mgr.conf['apps'][app]['host'], mgr.domain) for app in mgr.conf['apps']]
for domain in domains:
url = tools.compile_url(domain, port, proto)
try:
if not tools.ping_url(url):
return self.render_json({'error': request.session.lang.http_host_not_reachable(url)})
except:
return self.render_json({'error': request.session.lang.http_timeout()})
return self.render_json({'ok': request.session.lang.http_hosts_ok(port)})
def update_cert_action(self, request):
# Update certificate - either request via Let's Encrypt or manually upload files
try:
if request.form['method'] not in ['auto', 'manual']:
raise BadRequest()
if request.form['method'] == 'manual':
if not request.files['public']:
return self.render_json({'error': request.session.lang.cert_file_missing()})
if not request.files['private']:
return self.render_json({'error': request.session.lang.key_file_missing()})
request.files['public'].save('/tmp/public.pem')
request.files['private'].save('/tmp/private.pem')
request.mgr.install_cert('/tmp/public.pem', '/tmp/private.pem')
os.unlink('/tmp/public.pem')
os.unlink('/tmp/private.pem')
else:
request.mgr.request_cert()
except BadRequest:
return self.render_json({'error': request.session.lang.malformed_request()})
except:
return self.render_json({'error': request.session.lang.cert_request_error()})
url = tools.compile_url(request.mgr.domain, request.mgr.port)
return self.render_json({'ok': request.session.lang.cert_installed(url, url)})
def update_common_action(self, request):
# Update common settings shared between apps - admin e-mail address, Google Maps API key
try:
request.mgr.update_common(request.form['email'], request.form['gmaps-api-key'])
except BadRequest:
return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': request.session.lang.common_updated()})
def update_app_visibility_action(self, request):
# Update application visibility on portal page
try:
if request.form['value'] == 'true':
request.mgr.show_tiles(request.form['app'])
else:
request.mgr.hide_tiles(request.form['app'])
except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': 'ok'})
def update_app_autostart_action(self, request):
# Update value determining if the app should be automatically started after VM boot
try:
if request.form['value'] == 'true':
request.mgr.enable_autostart(request.form['app'])
else:
request.mgr.disable_autostart(request.form['app'])
except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()})
return self.render_json({'ok': 'ok'})
def start_app_action(self, request):
# Starts application along with its dependencies
try:
request.mgr.start_app(request.form['app'])
except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()})
except:
return self.render_json({'error': request.session.lang.stop_start_error()})
return self.render_json({'ok': request.session.lang.app_started()})
def stop_app_action(self, request):
# Stops application along with its dependencies
try:
request.mgr.stop_app(request.form['app'])
except (BadRequest, InvalidValueException):
return self.render_json({'error': request.session.lang.malformed_request()})
except:
return self.render_json({'error': request.session.lang.stop_start_error()})
return self.render_json({'ok': request.session.lang.app_stopped()})
def update_password_action(self, request):
# Updates password for both HDD encryption (LUKS-on-LVM) and admin account to vm-appmgr
try:
if request.form['newpassword'] != request.form['newpassword2']:
return self.render_json({'error': request.session.lang.password_mismatch()})
if request.form['newpassword'] == '':
return self.render_json({'error': request.session.lang.password_empty()})
# No need to explicitly validate old password, update_luks_password will raise exception if it's wrong
request.mgr.update_password(request.form['oldpassword'], request.form['newpassword'])
except:
return self.render_json({'error': request.session.lang.bad_password()})
return self.render_json({'ok': request.session.lang.password_changed()})
def reboot_vm_action(self, request):
# Reboots VM
response = self.render_json({'ok': request.session.lang.reboot_initiated()})
response.call_on_close(tools.reboot_vm)
return response
def shutdown_vm_action(self, request):
# Shuts down VM
response = self.render_json({'ok': request.session.lang.shutdown_initiated()})
response.call_on_close(tools.shutdown_vm)
return response
class InvalidRecordException(Exception):
pass

@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
class WSGILang:
lang = {
'malformed_request': 'Byl zaslán chybný požadavek. Obnovte stránku a zkuste akci zopakovat.',
'invalid_domain': 'Zadaný doménový název "{}" není platný.',
'invalid_port': 'Zadaný port "{}" není platný.',
'host_updated': 'Nastavení hostitele bylo úspěšně změněno. Přejděte na URL <a href="{}">{}</a> a pokračujte následujícími kroky.',
'dns_record_does_not_exist': 'DNS záznam pro název "{}" neexistuje.',
'dns_record_mismatch': 'DNS záznam pro název "{}" směřuje na IP {} místo očekávané {}.',
'dns_timeout': 'Nepodařilo se kontaktovat DNS server. Zkontrolujte, zda má virtuální stroj přístup k internetu.',
'dns_records_ok': 'DNS záznamy jsou nastaveny správně.',
'http_host_not_reachable': 'Adresa {} není dostupná z internetu. Zkontrolujte nastavení síťových komponent.',
'http_timeout': 'Nepodařilo se kontaktovat ping server. Zkontrolujte, zda má virtuální stroj přístup k internetu.',
'http_hosts_ok': 'Síť je nastavena správně. Všechny aplikace na portu {} jsou z internetu dostupné.',
'cert_file_missing': 'Nebyl vybrán soubor s certifikátem.',
'key_file_missing': 'Nebyl vybrán soubor se soukromým klíčem.',
'cert_request_error': 'Došlo k chybě při žádosti o certifikát. Zkontrolujte, zda je virtuální stroj dostupný z internetu na portu 80.',
'cert_installed': 'Certifikát byl úspěšně nainstalován. Přejděte na URL <a href="{}">{}</a> nebo restartujte webový prohlížeč pro jeho načtení.',
'common_updated': 'Nastavení aplikací bylo úspěšně změněno.',
'app_started': '<span class="info">Spuštěna</span> (<a href="#" class="app-stop">zastavit</a>)',
'app_stopped': '<span class="error">Zastavena</span> (<a href="#" class="app-start">spustit</a>)',
'stop_start_error': 'Došlo k chybě při spouštění/zastavování. Zkuste akci opakovat nebo restartuje virtuální stroj.',
'bad_password': 'Nesprávné heslo',
'password_mismatch': 'Zadaná hesla se neshodují',
'password_empty': 'Nové heslo nesmí být prázdné',
'password_changed': 'Heslo úspěšně změněno',
'reboot_initiated': 'Příkaz odeslán. Vyčkejte na restartování virtuálního stroje.',
'shutdown_initiated': 'Příkaz odeslán. Vyčkejte na vypnutí virtuálního stroje.',
}
def __getattr__(self, key):
def function(*args):
return self.lang[key].format(*args)
return function

@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
from werkzeug.contrib.securecookie import SecureCookie
class WSGISession:
def __init__(self, cookies, secret_key):
self.secret_key = secret_key
data = cookies.get('session')
if data:
self.sc = SecureCookie.unserialize(data, secret_key)
else:
self.reset()
if 'admin' not in self.sc:
self.reset()
def __getitem__(self, key):
return self.sc.__getitem__(key)
def __setitem__(self, key, value):
return self.sc.__setitem__(key, value)
def __delitem__(self, key):
return self.sc.__delitem__(key)
def __contains__(self, key):
return self.sc.__contains__(key)
def reset(self):
self.sc = SecureCookie(secret_key=self.secret_key)
self.sc['admin'] = False
def save(self, response):
if self.sc.should_save:
data = self.sc.serialize()
response.set_cookie('session', data, httponly=True)

@ -1,114 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import argparse
import getpass
import sys
sys.path.append('/srv/vm')
from appmgr import AppMgr
parser = argparse.ArgumentParser(description='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_rebuild_issue = subparsers.add_parser('rebuild-issue', help='Rebuilds /etc/issue using current settings - used on VM startup')
parser_rebuild_issue.set_defaults(action='rebuild-issue')
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_host = subparsers.add_parser('update-host', help='Rebuilds domain structure of VM with new host name and new HTTPS port')
parser_update_host.set_defaults(action='update-host')
parser_update_host.add_argument('domain', help='Domain name')
parser_update_host.add_argument('port', help='HTTPS port')
parser_update_common = subparsers.add_parser('update-common', help='Updates common configuration properties used by multiple applications')
parser_update_common.set_defaults(action='update-common')
parser_update_common.add_argument('--email', help='Administrative e-mail address')
parser_update_common.add_argument('--gmaps-api-key', help='Google Maps API key')
parser_update_password = subparsers.add_parser('update-password', help='Updates password for HDD encryption and WSGI administration interface')
parser_update_password.set_defaults(action='update-password')
parser_create_selfsigned = subparsers.add_parser('create-selfsigned', help='Creates and installs selfsigned certificate for currently set domain')
parser_create_selfsigned.set_defaults(action='create-selfsigned')
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_install_cert = subparsers.add_parser('install-cert', help='Installs user supplied certificate')
parser_install_cert.set_defaults(action='install-cert')
parser_install_cert.add_argument('certificate', help='Certificate file')
parser_install_cert.add_argument('key', help='Key file')
args = parser.parse_args()
mgr = AppMgr()
if args.action == 'update-login':
mgr.update_login(args.app, args.login, args.password)
elif args.action == 'show-tiles':
mgr.show_tiles(args.app)
elif args.action == 'hide-tiles':
mgr.hide_tiles(args.app)
elif args.action == 'start-app':
mgr.start_app(args.app)
elif args.action == 'stop-app':
mgr.stop_app(args.app)
elif args.action == 'enable-autostart':
mgr.enable_autostart(args.app)
elif args.action == 'disable-autostart':
mgr.disable_autostart(args.app)
elif args.action == 'rebuild-issue':
mgr.rebuild_issue()
elif args.action == 'register-proxy':
mgr.register_proxy(args.app)
elif args.action == 'unregister-proxy':
mgr.unregister_proxy(args.app)
elif args.action == 'update-host':
mgr.update_host(args.domain, args.port)
elif args.action == 'update-common':
mgr.update_common(args.email, args.gmaps_api_key)
elif args.action == 'update-password':
oldpassword = getpass.getpass('Old password: ')
newpassword = getpass.getpass('New password: ')
mgr.update_password(oldpassword, newpassword)
elif args.action == 'create-selfsigned':
mgr.create_selfsigned()
elif args.action == 'request-cert':
mgr.request_cert()
elif args.action == 'install-cert':
mgr.install_cert(args.certificate, args.key)

@ -1,139 +0,0 @@
{
"apps": {
"ckan": {
"host": "ckan",
"login": "N/A",
"password": "N/A",
"title": "CKAN",
"visible": false
},
"crisiscleanup": {
"host": "cc",
"login": "N/A",
"password": "N/A",
"title": "Crisis Cleanup",
"visible": false
},
"cts": {
"host": "cts",
"login": "N/A",
"password": "N/A",
"title": "CTS",
"visible": false
},
"frontlinesms": {
"host": "sms",
"login": "N/A",
"password": "N/A",
"title": "Frontline SMS",
"visible": false
},
"gnuhealth": {
"host": "gh",
"login": "N/A",
"password": "N/A",
"title": "GNU Health",
"visible": false
},
"kanboard": {
"host": "kb",
"login": "N/A",
"password": "N/A",
"title": "KanBoard",
"visible": false
},
"mifosx": {
"host": "mifosx",
"login": "N/A",
"password": "N/A",
"title": "Mifos X",
"visible": false
},
"motech": {
"host": "motech",
"login": "N/A",
"password": "N/A",
"title": "Motech",
"visible": false
},
"opendatakit": {
"host": "odk",
"login": "N/A",
"password": "N/A",
"title": "OpenDataKit Aggregate",
"visible": false
},
"opendatakit-build": {
"host": "odkbuild",
"login": "N/A",
"password": "N/A",
"title": "OpenDataKit Build",
"visible": false
},
"openmapkit": {
"host": "omk",
"login": "N/A",
"password": "N/A",
"title": "OpenMapKit",
"visible": false
},
"pandora": {
"host": "pandora",
"login": "N/A",
"password": "N/A",
"title": "Pan.do/ra",
"visible": false
},
"sahana": {
"host": "sahana",
"login": "N/A",
"password": "N/A",
"title": "Sahana EDEN",
"visible": false
},
"sahana-demo": {
"host": "sahana-demo",
"login": "N/A",
"password": "N/A",
"title": "Sahana EDEN Demo",
"visible": false
},
"sambro": {
"host": "sambro",
"login": "N/A",
"password": "N/A",
"title": "Sahana EDEN SAMBRO",
"visible": false
},
"seeddms": {
"host": "dms",
"login": "N/A",
"password": "N/A",
"title": "SeedDMS",
"visible": false
},
"sigmah": {
"host": "sigmah",
"login": "N/A",
"password": "N/A",
"title": "Sigmah",
"visible": false
},
"ushahidi": {
"host": "ush",
"login": "N/A",
"password": "N/A",
"title": "Ushahidi",
"visible": false
}
},
"common": {
"email": "admin@example.com",
"gmaps-api-key": ""
},
"host": {
"adminpwd": "$2b$12$nLrIefUoWN.pK6j90gsfkO0/tg4EGXDmdjN8HOGB0U.9BcHTFxzWS",
"domain": "spotter.vm",
"port": "443"
}
}

@ -1,196 +0,0 @@
body {
font-family: 'Calibri', 'Verdana', 'Tahoma', sans-serif;
background-color: #bbb;
color: #000;
line-height: 150%;
margin: 25px 30px;
}
a {
color: #06f;
text-decoration: none;
}
img {
border: 0px;
}
nav {
float: right;
}
nav #menu-button {
float: right;
cursor: pointer;
}
nav #menu-button div {
width: 24px;
height: 4px;
background-color: #fff;
border: 1px solid #000;
margin: 2px 0px;
}
nav ul {
display: none;
list-style: none;
border: 1px solid #000;
margin: 26px 0px 0px 0px;
position: absolute;
background-color: #fff;
padding: 10px;
right: 30px;
z-index: 1;
}
nav a {
display: block;
}
h1, h2 {
font-size: 150%;
}
header {
color: #fff;
}
header h1,
header p,
.portal-box p {
padding: 0px;
margin: 0px;
}
.portal-box,
.setup-box {
background-color: #fff;
margin-top: 13px;
border: solid 1px #000;
padding: 10px;
}
.portal-box {
position: relative;
margin-right: 13px;
width: 365px;
float: left;
height: 175px;
}
.portal-box h2 {
margin: 0px;
font-weight: normal;
}
.portal-box h2 a {
color: inherit;
}
.portal-box h2 img {
float: right;
margin-left: 10px;
margin-bottom:10px;
width: 100px;
height: 100px;
}
.portal-box ul {
margin: 0px;
padding-left: 30px;
}
.portal-box:last-child:after {
clear: both;
}
.portal-box-double-width {
width: 765px;
}
.ico {
margin-right: 5px;
width: 20px;
height: 20px;
vertical-align: top;
}
.setup-box h2 {
margin-top: 0px;
}
.setup-box input[type="text"],
.setup-box input[type="password"],
.setup-box input[type="submit"],
.setup-box input[type="button"],
.setup-box input[type="file"],
.setup-box select {
box-sizing: border-box;
width: 180px;
}
.setup-box table {
border-collapse: collapse;
}
.setup-box thead {
font-weight: bold;
}
.setup-box td {
padding: 1px 10px;
vertical-align: top;
}
.setup-box td:first-child {
white-space: nowrap;
}
.setup-box td.remark {
color: #999;
font-size: 80%;
font-style: italic;
line-height: 125%;
padding-top: 5px;
}
.center {
text-align: center;
}
.error {
color: #c00;
font-weight: bold;
}
.info {
color: #090;
font-weight: bold;
}
.loader-wrap {
display: none;
}
.loader-wrap span:after {
clear: both;
content: '';
display: table;
}
.loader {
float: left;
width: 14px;
height: 14px;
border: 5px solid #eee;
border-top: 5px solid #fa3;
border-radius: 50%;
margin-right: 5px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

Binary file not shown.

Before

(image error) Size: 5.4 KiB

Binary file not shown.

Before

(image error) Size: 69 KiB

Binary file not shown.

Before

(image error) Size: 17 KiB

Binary file not shown.

Before

(image error) Size: 33 KiB

Binary file not shown.

Before

(image error) Size: 70 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 15 KiB

Binary file not shown.

Before

(image error) Size: 6.4 KiB

Binary file not shown.

Before

(image error) Size: 40 KiB

Binary file not shown.

Before

(image error) Size: 119 KiB

Binary file not shown.

Before

(image error) Size: 42 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 36 KiB

Binary file not shown.

Before

(image error) Size: 83 KiB

Binary file not shown.

Before

(image error) Size: 101 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

Binary file not shown.

Before

(image error) Size: 7.9 KiB

Binary file not shown.

Before

(image error) Size: 47 KiB

Binary file not shown.

Before

(image error) Size: 6.1 KiB

Binary file not shown.

Before

(image error) Size: 22 KiB

Binary file not shown.

Before

(image error) Size: 21 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

Binary file not shown.

Before

(image error) Size: 13 KiB

Binary file not shown.

Before

(image error) Size: 12 KiB

Binary file not shown.

Before

(image error) Size: 32 KiB

Binary file not shown.

Before

(image error) Size: 23 KiB

Binary file not shown.

Before

(image error) Size: 53 KiB

Binary file not shown.

Before

(image error) Size: 17 KiB

Binary file not shown.

Before

(image error) Size: 16 KiB

Binary file not shown.

Before

(image error) Size: 48 KiB

Binary file not shown.

Before

(image error) Size: 21 KiB

Binary file not shown.

Before

(image error) Size: 9.2 KiB

Binary file not shown.

Before

(image error) Size: 4.3 KiB

@ -1,202 +0,0 @@
$(function() {
$('#update-host').on('submit', update_host);
$('#verify-dns').on('click', verify_dns);
$('#verify-https').on('click', verify_https);
$('#verify-http').on('click', verify_http);
$('#cert-method').on('change', toggle_cert_method);
$('#update-cert').on('submit', update_cert);
$('#update-common').on('submit', update_common);
$('.app-visible').on('click', update_app_visibility);
$('.app-autostart').on('click', update_app_autostart);
$('tr[data-app]').on('click', '.app-start', start_app).on('click', '.app-stop', stop_app);
$('#update-password').on('submit', update_password);
$('#reboot-vm').on('click', reboot_vm);
$('#shutdown-vm').on('click', shutdown_vm);
});
function update_host() {
$('#host-submit').hide();
$('#host-message').hide();
$('#host-wait').show();
$.post('/update-host', {'domain': $('#domain').val(), 'port': $('#port').val()}, function(data) {
$('#host-wait').hide();
if (data.error) {
$('#host-message').attr('class','error').html(data.error).show();
$('#host-submit').show();
} else {
$('#host-message').attr('class','info').html(data.ok).show();
$('input').prop('disabled', true);
$('.setup-box').slice(1).css('opacity', '0.5');
}
});
return false;
}
function verify_dns() {
$('#verify-dns').hide();
$('#dns-message').hide();
$('#dns-wait').show();
$.get('/verify-dns', function(data) {
$('#dns-wait').hide();
if (data.error) {
$('#dns-message').attr('class','error').html(data.error).show();
$('#verify-dns').show();
} else {
$('#dns-message').attr('class','info').html(data.ok).show();
}
});
return false;
}
function _verify_http(proto) {
$('#verify-'+proto).hide();
$('#'+proto+'-message').hide();
$('#'+proto+'-wait').show();
$.get('/verify-' + proto, function(data) {
$('#'+proto+'-wait').hide();
if (data.error) {
$('#'+proto+'-message').attr('class','error').html(data.error).show();
$('#verify-'+proto).show();
} else {
$('#'+proto+'-message').attr('class','info').html(data.ok).show();
}
});
return false;
}
function verify_http() {
return _verify_http('http');
}
function verify_https() {
return _verify_http('https');
}
function toggle_cert_method() {
if ($('#cert-method').val() == 'manual') {
$('.cert-upload').show();
} else {
$('.cert-upload').hide();
}
}
function update_cert() {
$('#cert-submit').hide();
$('#cert-message').hide();
$('#cert-wait').show();
$.ajax({url: '/update-cert', type: 'POST', data: new FormData($('#update-cert')[0]), cache: false, contentType: false, processData: false, success: function(data) {
$('#cert-wait').hide();
if (data.error) {
$('#cert-message').attr('class','error').html(data.error).show();
$('#cert-submit').show();
} else {
$('#cert-message').attr('class','info').html(data.ok).show();
}
}});
return false;
}
function update_common() {
$('#common-submit').hide();
$('#common-message').hide();
$('#common-wait').show();
$.post('/update-common', {'email': $('#email').val(), 'gmaps-api-key': $('#gmaps-api-key').val()}, function(data) {
$('#common-wait').hide();
if (data.error) {
$('#common-message').attr('class','error').html(data.error).show();
$('#common-submit').show();
} else {
$('#common-message').attr('class','info').html(data.ok).show();
$('#common-submit').show();
}
});
return false;
}
function update_app_visibility(ev) {
var el = $(ev.target);
var app = el.closest('tr').data('app');
var value = el.is(':checked') ? 'true' : '';
$.post('/update-app-visibility', {'app': app, 'value': value}, function(data) {
if (data.error) {
el.prop('checked', !value);
alert(data.error);
}
});
}
function update_app_autostart(ev) {
var el = $(ev.target);
var app = el.closest('tr').data('app');
var value = el.is(':checked') ? 'true' : '';
$.post('/update-app-autostart', {'app': app, 'value': value}, function(data) {
if (data.error) {
el.prop('checked', !value);
alert(data.error);
}
});
}
function start_app(ev) {
var el = $(ev.target);
var app = el.closest('tr').data('app');
var td = el.closest('td');
td.html('<div class="loader"></div>');
$.post('/start-app', {'app': app}, function(data) {
if (data.error) {
td.attr('class','error').html(data.error);
} else {
td.removeAttr('class').html(data.ok);
}
});
return false;
}
function stop_app(ev) {
var el = $(ev.target);
var app = el.closest('tr').data('app');
var td = el.closest('td');
td.html('<div class="loader"></div>');
$.post('/stop-app', {'app': app}, function(data) {
if (data.error) {
td.attr('class','error').html(data.error);
} else {
td.removeAttr('class').html(data.ok);
}
});
return false;
}
function update_password() {
$('#password-submit').hide();
$('#password-message').hide();
$('#password-wait').show();
$.post('/update-password', {'oldpassword': $('#oldpassword').val(), 'newpassword': $('#newpassword').val(), 'newpassword2': $('#newpassword2').val()}, function(data) {
$('#password-wait').hide();
if (data.error) {
$('#password-message').attr('class','error').html(data.error).show();
$('#password-submit').show();
} else {
$('#password-message').attr('class','info').html(data.ok).show();
}
});
return false;
}
function reboot_vm() {
if (confirm('Do you really want to reboot VM?')) {
$.get('/reboot-vm', function(data) {
$('#vm-message').attr('class','info').html(data.ok).show();
});
}
return false;
}
function shutdown_vm() {
if (confirm('Do you really want to shutdown VM?')) {
$.get('/shutdown-vm', function(data) {
$('#vm-message').attr('class','info').html(data.ok).show();
});
}
return false;
}

File diff suppressed because one or more lines are too long

@ -1,7 +0,0 @@
$(function() {
$('#menu-button').on('click', toggle_menu);
});
function toggle_menu() {
$('#menu').toggle();
}

@ -1,15 +0,0 @@
<!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 404</title>
</head>
<body>
<h1>Stránka nebyla nalezena</h1>
<p>Stránka, kterou se pokoušíte zobrazit, nebyla na serveru nalezena. Zkontrolujte prosím URL v adresním řádku nebo se vraťte <a href="/">zpět na úvodní stránku</a>.</p>
</body>
</html>

@ -1,15 +0,0 @@
<!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 502</title>
</head>
<body>
<h1>Chyba spojení s aplikací</h1>
<p>Aplikace ke které se pokoušíte připojit není dostupná. Nejspíše byla vypnuta správcem serveru.</p>
</body>
</html>

@ -1,42 +0,0 @@
<!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>{% block title %}{% endblock %}</title>
<link rel="icon" href="static/img/Cluster_Spotter.png" type="image/png">
<link rel="stylesheet" href="static/css/style.css" type="text/css" media="screen">
<script src="static/js/jquery-3.3.1.min.js"></script>
<script src="static/js/script.js"></script>
{% if session.admin %}
<script src="static/js/admin.js"></script>
{% endif %}
</head>
<body>
<nav>
<div id="menu-button">
<div></div>
<div></div>
<div></div>
</div>
<ul id="menu">
<li><a href="/">Portál</a></li>
{% if session.admin %}
<li><a href="/setup-host">Nastavení hostitele</a></li>
<li><a href="/setup-apps">Nastavení aplikací</a></li>
<li><a href="/logout">Odhlášení</a></li>
{% else %}
<li><a href="/login">Přihlášení</a></li>
{% endif %}
</ul>
</nav>
<header>
<h1>CLUSTER NGO</h1>
<p>Sada softwarových nástrojů určená pro krizový management.</p>
</header>
{% block body %}{% endblock %}
</body>
</html>

@ -1,28 +0,0 @@
{% extends 'layout.html' %}
{% block title %}Přihlášení{% endblock %}
{% block body %}
<div class="setup-box">
<h2>Přihlášení</h2>
<form action="/login" method="post">
<table>
<tr>
<td>Jméno:</td>
<td>admin</td>
</tr>
<tr>
<td>Heslo</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<input type="submit" value="Přihlásit">
</td>
</tr>
</table>
{% if message is defined %}
<p class="error">{{ message }}</p>
{% endif %}
</form>
</div>
{% endblock %}

@ -1,352 +0,0 @@
{% extends 'layout.html' %}
{% block title %}Cluster NGO{% endblock %}
{% block body %}
{% set host = '{}:{}'.format(conf['host']['domain'], conf['host']['port']) if conf['host']['port'] != '443' else conf['host']['domain'] %}
{% set app = conf['apps']['sahana'] %}
{% if app['visible'] and is_service_started('sahana') %}
<div class="portal-box portal-box-double-width">
<h2><a href="https://sahana.{{ host }}/eden/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['sahana-demo'] %}
{% if app['visible'] and is_service_started('sahana-demo') %}
<div class="portal-box">
<h2><a href="https://sahana-demo.{{ host }}/eden/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['sambro'] %}
{% if app['visible'] and is_service_started('sambro') %}
<div class="portal-box">
<h2><a href="https://sambro.{{ host }}/eden/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/iOS.png" class="ico" alt="IOS">IOS 6.0 a vyšší</a><br>
<a href="https://apkpure.com/sambro-mobile/io.sahana.sambro.mobile"><img src="static/img/icons/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>
{% endif %}
{% set app = conf['apps']['crisiscleanup'] %}
{% if app['visible'] and is_service_started('crisiscleanup') %}
<div class="portal-box">
<h2><a href="https://cc.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['ckan'] %}
{% if app['visible'] and is_service_started('ckan') %}
<div class="portal-box">
<h2><a href="https://ckan.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['opendatakit-build'] %}
{% if app['visible'] and is_service_started('opendatakit-build') %}
<div class="portal-box">
<h2><a href="https://odkbuild.{{ host }}"><img src="static/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="https://opendatakit.org/xiframe/">XLSForm</a> - online konverter XLS.<br>
<a href="https://opendatakit.org/downloads/download-info/odk-formuploader/"><img src="static/img/icons/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="static/img/icons/Java.png" class="ico" alt="ODK Validate">ODK Validate</a></p>
</div>
{% endif %}
{% set app = conf['apps']['opendatakit'] %}
{% if app['visible'] and is_service_started('opendatakit') %}
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/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="static/img/icons/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="portal-box">
<h2><a href="https://odk.{{ host }}/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['openmapkit'] %}
{% if app['visible'] and is_service_started('openmapkit') %}
<div class="portal-box">
<h2><a href="https://omk.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/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="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/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="static/img/icons/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>
{% endif %}
{% set app = conf['apps']['frontlinesms'] %}
{% if app['visible'] and is_service_started('frontlinesms') %}
<div class="portal-box">
<h2><a href="https://sms.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/img/FrontlineSync.png" alt="FrontlineSync" title="FrontlineSync">FrontlineSync</a></h2>
<p>Mobilní aplikace pro<br>
<a href="https://play.google.com/store/apps/details?id=com.simlab.frontlinesync"><img src="static/img/icons/Android.png" class="ico" alt="Android">Android 2.3 a vyšší</a>
</p>
</div>
{% endif %}
{% set app = conf['apps']['seeddms'] %}
{% if app['visible'] and is_service_started('seeddms') %}
<div class="portal-box">
<h2><a href="https://dms.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['pandora'] %}
{% if app['visible'] and is_service_started('pandora') %}
<div class="portal-box">
<h2><a href="https://pandora.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['ushahidi'] %}
{% if app['visible'] and is_service_started('ushahidi') %}
<div class="portal-box">
<h2><a href="https://ush.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/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="static/img/icons/Android.png" class="ico" alt="Android">Android 4.4 a vyšší</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">ush.{{ host }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/Android.png" class="ico" alt="Android">Android 2.3 a vyšší</a>
</p>
</div>
{% endif %}
{% set app = conf['apps']['kanboard'] %}
{% if app['visible'] and is_service_started('kanboard') %}
<div class="portal-box">
<h2><a href="https://kb.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/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="static/img/icons/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>
{% endif %}
{% set app = conf['apps']['cts'] %}
{% if app['visible'] and is_service_started('cts') %}
<div class="portal-box">
<h2><a href="https://cts.{{ host }}"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['gnuhealth'] %}
{% if app['visible'] and is_service_started('gnuhealth') %}
<div class="portal-box">
<h2><a href="https://gh.{{ host }}/index.html"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
<li><strong>Heslo k demu:</strong> <span class="demopassword">gnusolidario</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/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="static/img/icons/Windows.png" class="ico" alt="Windows">Windows</a><br>
<a href="https://downloads.tryton.org/4.2/tryton-last.dmg"><img src="static/img/icons/MacOS.png" class="ico" alt="MacOS">MacOS</a><br>
<a href="https://downloads.tryton.org/4.2/tryton-last.tar.gz"><img src="static/img/icons/Linux.png" class="ico" alt="Linux">Linux</a>
</p>
<ul>
<li><strong>URL:</strong> <span class="clienturl">gh.{{ host }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['sigmah'] %}
{% if app['visible'] and is_service_started('sigmah') %}
<div class="portal-box">
<h2><a href="https://sigmah.{{ host }}/sigmah/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['motech'] %}
{% if app['visible'] and is_service_started('motech') %}
<div class="portal-box">
<h2><a href="https://motech.{{ host }}/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
{% endif %}
{% set app = conf['apps']['mifosx'] %}
{% if app['visible'] and is_service_started('mifosx') %}
<div class="portal-box">
<h2><a href="https://mifosx.{{ host }}/"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="#"><img src="static/img/MifosX_Mobile.png" alt="Mifos X" title="Mifos X">Mifos X</a></h2>
<p>Mobilní aplikace<br>
<a href="https://github.com/openMF/android-client/releases"><img src="static/img/icons/Android.png" class="ico" alt="Mifos X">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>
{% endif %}
{% if false %}
<div class="portal-box">
<h2><a href="#"><img src="static/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">{{ app['login'] }}</span></li>
<li><strong>Heslo:</strong> <span class="password">{{ app['password'] }}</span></li>
</ul>
</div>
<div class="portal-box">
<h2><a href="https://openid.net"><img src="static/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="portal-box">
<h2><a href="#"><img src="static/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>
{% endif %}
<div class="portal-box">
<h2><a href="http://spotter.ngo"><img src="static/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>
{% endblock %}

@ -1,123 +0,0 @@
{% extends 'layout.html' %}
{% block title %}Cluster NGO{% endblock %}
{% block body %}
{% set host = '{}:{}'.format(conf['host']['domain'], conf['host']['port']) if conf['host']['port'] != '443' else conf['host']['domain'] %}
{% if conf['apps']['sahana-demo']['visible'] and is_service_started('sahana-demo') %}
<div class="portal-box">
<h2><a href="https://sahana-demo.{{ host }}/eden/">Řízení humanítární činnosti</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>
</div>
{% endif %}
{% if conf['apps']['sambro']['visible'] and is_service_started('sambro') %}
<div class="portal-box">
<h2><a href="https://sambro.{{ host }}/eden/">Centrum hlášení a výstrah</a></h2>
<p>Samostatná instance s šablonou pro centrum hlášení a výstrah.</p>
</div>
{% endif %}
{% if conf['apps']['crisiscleanup']['visible'] and is_service_started('crisiscleanup') %}
<div class="portal-box">
<h2><a href="https://cc.{{ host }}">Mapování následků katastrof</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>
</div>
{% endif %}
{% if conf['apps']['ckan']['visible'] and is_service_started('ckan') %}
<div class="portal-box">
<h2><a href="https://ckan.{{ host }}">Datový sklad</a></h2>
<p><strong>Repository</strong> management a datová analýza pro vytváření otevřených dat.</p>
</div>
{% endif %}
{% if conf['apps']['opendatakit-build']['visible'] and is_service_started('opendatakit-build') %}
<div class="portal-box">
<h2><a href="https://odkbuild.{{ host }}">Sběr formulářových dat</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.<br>Aplikace pro návrh formulářů</p>
</div>
{% endif %}
{% if conf['apps']['opendatakit']['visible'] and is_service_started('opendatakit') %}
<div class="portal-box">
<h2><a href="https://odk.{{ host }}/">Sběr formulářových dat</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.</p>
</div>
{% endif %}
{% if conf['apps']['openmapkit']['visible'] and is_service_started('openmapkit') %}
<div class="portal-box">
<h2><a href="https://omk.{{ host }}">Sběr mapových dat</a></h2>
<p><strong>Sběr dat s pomocí smartphone</strong>.<br>
</div>
{% endif %}
{% if conf['apps']['frontlinesms']['visible'] and is_service_started('frontlinesms') %}
<div class="portal-box">
<h2><a href="https://sms.{{ host }}">Hromadné odesílání zpráv</a></h2>
<p><strong>SMS messaging</strong> přes veřejné datové brány</p>
</div>
{% endif %}
{% if conf['apps']['seeddms']['visible'] and is_service_started('seeddms') %}
<div class="portal-box">
<h2><a href="https://dms.{{ host }}">Archiv dokumentace</a></h2>
<p><strong>Dokument management</strong> na dokumentaci a projektovou dokumentaci</p>
</div>
{% endif %}
{% if conf['apps']['pandora']['visible'] and is_service_started('pandora') %}
<div class="portal-box">
<h2><a href="https://pandora.{{ host }}">Archiv medií</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>
</div>
{% endif %}
{% if conf['apps']['ushahidi']['visible'] and is_service_started('ushahidi') %}
<div class="portal-box">
<h2><a href="https://ush.{{ host }}">Skupinová reakce na události</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>
</div>
{% endif %}
{% if conf['apps']['kanboard']['visible'] and is_service_started('kanboard') %}
<div class="portal-box">
<h2><a href="https://kb.{{ host }}">Kanban řízení projektů</a></h2>
<p>Usnadňuje tvorbu a řízení projektů s pomocí Kanban metodiky.</p>
</div>
{% endif %}
{% if conf['apps']['gnuhealth']['visible'] and is_service_started('gnuhealth') %}
<div class="portal-box">
<h2><a href="https://gh.{{ host }}/index.html">Lékařské záznamy pacientů</a></h2>
<p>Zdravotní a nemocniční informační systém.</p>
</div>
{% endif %}
{% if conf['apps']['sigmah']['visible'] and is_service_started('sigmah') %}
<div class="portal-box">
<h2><a href="https://sigmah.{{ host }}/sigmah/">Finanční řízení sbírek</a></h2>
<p>Rozpočtování získávání finančních prostředků.</p>
</div>
{% endif %}
{% if conf['apps']['motech']['visible'] and is_service_started('motech') %}
<div class="portal-box">
<h2><a href="https://motech.{{ host }}/">Automatizace komunikace</a></h2>
<p>Integrace zdravotnických a komunikačních služeb.</p>
</div>
{% endif %}
{% if conf['apps']['mifosx']['visible'] and is_service_started('mifosx') %}
<div class="portal-box">
<h2><a href="https://mifosx.{{ host }}/">Mikrofinancování rozvojových projektů</a></h2>
<p>Nástroj na rozvojovou, humanitární pomoc a mikrofinancování.</p>
</div>
{% endif %}
<div class="portal-box">
<h2><a href="http://spotter.ngo"><img src="static/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>
{% endblock %}

@ -1,94 +0,0 @@
{% extends 'layout.html' %}
{% block title %}Nastavení aplikací{% endblock %}
{% block body %}
<div class="setup-box">
<h2>Nastavení aplikací</h2>
<p>Společné nastavení sdílené některými aplikacemi.</p>
<form id="update-common" action="/update-common" method="post">
<table>
<tr>
<td>E-mail</td>
<td><input type="text" name="email" id="email" value="{{ conf['common']['email'] }}"></td>
<td class="remark">Administrativní e-mail na který budou doručovány zprávy a upozornění z aplikací. Stejná e-mailová adresa bude také využita některými aplikacemi pro odesílání zpráv uživatelům.</td>
</tr>
<tr>
<td>Google Maps API klíč</td>
<td><input type="text" name="gmaps-api-key" id="gmaps-api-key" value="{{ conf['common']['gmaps-api-key'] }}"></td>
<td class="remark">API klíč pro službu Google Maps, která je využita některými aplikacemi.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="2">
<input type="submit" id="common-submit" value="Nastavit hodnoty">
<div id="common-message"></div>
<div id="common-wait" class="loader-wrap">
<div class="loader"></div>
<span>Provádí se změna nastavení, prosím čekejte...</span>
</div>
</td>
</tr>
</table>
</form>
</div>
<div class="setup-box">
<h2>Správce aplikací</h2>
<p>Vyberte které aplikace se mají zobrazovat na hlavní straně portálu a které mají být automaticky spuštěny při startu virtuálního stroje.</p>
<table>
<thead>
<tr>
<td>Aplikace</td>
<td>Zobrazena</td>
<td>Autostart</td>
<td>Stav</td>
</tr>
</thead>
<tbody>
{% for app in conf['apps']|sort %}
<tr data-app="{{ app }}">
<td>{{ conf['apps'][app]['title'] }}</td>
<td class="center"><input type="checkbox" class="app-visible"{% if conf['apps'][app]['visible'] %} checked{% endif %}></td>
<td class="center"><input type="checkbox" class="app-autostart"{% if is_service_autostarted(app) %} checked{% endif %}></td>
<td>{% if is_service_started(app) %}<span class="info">Spuštěna</span> (<a href="#" class="app-stop">zastavit</a>){% else %}<span class="error">Zastavena</span> (<a href="#" class="app-start">spustit</a>){% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="setup-box">
<h2>Správce virtuálního stroje</h2>
<p>Změna hesla k šifrovanému diskovému oddílu a administračnímu rozhraní.</p>
<form id="update-password" action="/update-password" method="post">
<table>
<tr>
<td>Stávající heslo:</td>
<td><input type="password" name="oldpassword" id="oldpassword"></td>
</tr>
<tr>
<td>Nové heslo:</td>
<td><input type="password" name="newpassword" id="newpassword"></td>
</tr>
<tr>
<td>Kontrola nového hesla:</td>
<td><input type="password" name="newpassword2" id="newpassword2"></td>
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="2">
<input type="submit" id="password-submit" value="Změnit heslo">
<div id="password-message"></div>
<div id="password-wait" class="loader-wrap">
<div class="loader"></div>
<span>Provádí se změna hesla, prosím čekejte...</span>
</div>
</td>
</tr>
</table>
</form>
<p>Restartování nebo vypnutí virtuálního stroje.</p>
<input type="button" id="reboot-vm" value="Restartovat VM">
<input type="button" id="shutdown-vm" value="Vypnout VM">
<div id="vm-message"></div>
</div>
{% endblock %}

@ -1,115 +0,0 @@
{% extends 'layout.html' %}
{% block title %}Nastavení hostitele{% endblock %}
{% block body %}
<div class="setup-box">
<h2>HTTPS Hostitel</h2>
<p>Základní doménové jméno a HTTPS port na kterých budou přístupny všechny aplikace.</p>
<form id="update-host" action="/update-host" method="post">
<table>
<tr>
<td>Doména</td>
<td><input type="text" name="domain" id="domain" value="{{ conf['host']['domain'] }}"></td>
<td class="remark">Plně kvalifikovaný doménový název, na kterém bude dostupný aplikační portál. Jednotlivé aplikace budou dostupné na subdoménách této domény.</td>
</tr>
<tr>
<td>Port</td>
<td><input type="text" name="port" id="port" value="{{ conf['host']['port'] }}"></td>
<td class="remark">HTTPS port na kterém budou dostupné aplikace. Výchozí HTTPS port je 443.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="2">
<input type="submit" id="host-submit" value="Nastavit hostitele">
<div id="host-message"></div>
<div id="host-wait" class="loader-wrap">
<div class="loader"></div>
<span>Provádí se změna nastavení, prosím čekejte...</span>
</div>
</td>
</tr>
</table>
</form>
</div>
<div class="setup-box">
<h2>DNS záznamy</h2>
<p>Na jmenném serveru domény nastavené v sekci <em>HTTPS Hostitel</em> nastavte DNS záznamy typu A, případně i AAAA pro následující doménové názvy a nasměrujte je na vnější (tj. dostupnou z internetu) IP adresu tohoto virtuální stroje. Toto nastavení lze obvykle provést skrze webové rozhraní registrátora domény.</p>
<p>Vnější IPv4 {% if ex_ipv4 %}je <strong>{{ ex_ipv4 }}</strong>{% else %}nebyla zjištěna{% endif %} a IPv6 {% if ex_ipv6 %}je <strong>{{ ex_ipv6 }}</strong>{% else %}nebyla zjištěna{% endif %}.</p>
<ul>
<li>{{ conf['host']['domain'] }}</li>
<li>*.{{ conf['host']['domain'] }}</li>
</ul>
<p>Pokud jmenný server nepodporuje wildcard záznamy nebo pokud nemůžete či nechcete dedikovat virtuálnímu stroji všechny subdomény, nastavte místo toho záznamy pro následující doménové názvy</p>
<ul style="column-count:3">
<li>{{ conf['host']['domain'] }}</li>
{% for app in conf['apps']|sort %}
<li>{{ conf['apps'][app]['host'] }}.{{ conf['host']['domain'] }}</li>
{% endfor %}
</ul>
<input type="button" id="verify-dns" value="Ověřit nastavení DNS">
<div id="dns-message"></div>
<div id="dns-wait" class="loader-wrap">
<div class="loader"></div>
<span>Ověřuje se nastavení DNS, prosím čekejte...</span>
</div>
</div>
<div class="setup-box">
<h2>Firewall a NAT</h2>
<p>Pokud je stávající připojení k internetu zprostředkováno routerem s NAT, na hypervizoru je nastaven firewall nebo existují jiné restrikce síťového provozu, je nutno upravit nastavení příslušných komponent, aby byl provoz na portu {{ conf['host']['port'] }} (nastaveném v sekci <em>HTTPS Hostitel</em>) z internetu korektně nasměrován na místní adresu virtuálního stroje.</p>
<p>Pokud bude využit systém automatického vyžádání a obnovy certifikátu (sekce <em>HTTPS certifikát</em>), je nutno aby byl na místní adresu virtuálního stroje nasměrován i port 80, případně byla nastavena HTTP proxy přesměrovávající doménová jména zmíněná v sekci <em>DNS záznamy</em>.</p>
<p>Místní IPv4 {% if in_ipv4 %}je <strong>{{ in_ipv4 }}</strong>{% else %}nebyla zjištěna{% endif %} a IPv6 {% if in_ipv6 %}je <strong>{{ in_ipv6 }}</strong>{% else %}nebyla zjištěna{% endif %}.</p>
<input type="button" id="verify-https" value="Ověřit nastavení portu {{ conf['host']['port'] }}">
<div id="https-message"></div>
<div id="https-wait" class="loader-wrap">
<div class="loader"></div>
<span>Ověřuje se nastavení firewallu a NAT pro port {{ conf['host']['port'] }}, prosím čekejte...</span>
</div>
<input type="button" id="verify-http" value="Ověřit nastavení portu 80">
<div id="http-message"></div>
<div id="http-wait" class="loader-wrap">
<div class="loader"></div>
<span>Ověřuje se nastavení firewallu a NAT pro port 80, prosím čekejte...</span>
</div>
</div>
<div class="setup-box">
<h2>HTTPS certifikát</h2>
<p>Stávající certifikát je vystaven na jméno <strong>{{ cert_info['subject']['commonName'] }}</strong> vystavitelem <strong>{{ cert_info['issuer']['commonName'] }}</strong> a jeho platnost vyprší <strong>{{ cert_info['notAfter'] }}</strong>.</p>
<form id="update-cert" action="/update-cert" method="post">
<table>
<tr>
<td>Způsob správy</td>
<td>
<select name="method" id="cert-method">
<option value="auto"{% if is_letsencrypt %} selected{% endif %}>Automaticky</option>
<option value="manual"{% if not is_letsencrypt %} selected{% endif %}>Ručně</option>
</select>
</td>
<td class="remark">Volba "Automaticky" způsobí, že systém automaticky zažádá o certifikát certifikační autority Let's Encrypt pro všechny plně kvalifikované doménové názvy (tj. nikoliv wildcard) zmíněné v sekci <em>DNS záznamy</em> a nainstaluje úlohu pro jeho automatickou obnovu. Tato akce může trvat několik minut.<br>Volba "Ručně" znamená, že soubory certifikátu a jeho soukromého klíče je nutno nahrát a následně obnovovat ručně skrze formulář na této stránce.</td>
</tr>
<tr class="cert-upload"{% if is_letsencrypt %} style="display:none"{% endif %}>
<td>Soubor certifikátu</td>
<td><input type="file" name="public" accept=".cer, .crt, .der, .pem"></td>
<td class="remark">Soubor s certifikátem ve formátu PEM.<br>Pokud je podepsán certifikační autoritou třetí strany, pak by tento soubor měl mimo koncového certifikátu obsahovat i podpisový certifikát.</td>
</tr>
<tr class="cert-upload"{% if is_letsencrypt %} style="display:none"{% endif %}>
<td>Soubor klíče</td>
<td><input type="file" name="private" accept=".key, .pem"></td>
<td class="remark">Soubor se soukromým klíčem ve formátu PEM pro výše vybraný certifikát.</td>
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="2">
<input type="submit" id="cert-submit" value="Nastavit certifikát">
<div id="cert-message"></div>
<div id="cert-wait" class="loader-wrap">
<div class="loader"></div>
<span>Provádí se změna nastavení, prosím čekejte...</span>
</div>
</td>
</tr>
</table>
</form>
</div>
{% endblock %}

@ -1,16 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
sys.path.append('/srv/vm')
from appmgr.wsgiapp import WSGIApp
application = WSGIApp()
if __name__ == '__main__':
import os
from werkzeug.contrib.fixers import ProxyFix
from werkzeug.serving import run_simple
run_simple('127.0.0.1', 8080, ProxyFix(application))

117
build/build-all.sh Executable file

@ -0,0 +1,117 @@
#!/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

29
build/clean-all.sh Executable file

@ -0,0 +1,29 @@
#!/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

32
build/etc/abuild.conf Normal file

@ -0,0 +1,32 @@
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"

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

36
build/install-toolchain.sh Executable file

@ -0,0 +1,36 @@
#!/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

2
build/root/.profile Normal file

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

@ -1,15 +0,0 @@
#!/bin/sh
set -e
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

@ -1,33 +0,0 @@
FROM python2
LABEL 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
COPY docker/ /
VOLUME ["/etc/ckan-datapusher", "/srv/ckan-datapusher/data"]
EXPOSE 8080
CMD ["s6-svscan", "/etc/services.d"]

@ -1,4 +0,0 @@
#!/bin/sh
/bin/cat /etc/ssl/services.pem >>/usr/lib/python2.7/site-packages/requests/cacert.pem
/bin/cat /etc/ssl/services.pem >>/usr/lib/python2.7/site-packages/certifi/cacert.pem

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

@ -1,6 +0,0 @@
#!/bin/execlineb -P
fdmove -c 2 1
foreground { /bin/add-ca-cert }
s6-setuidgid 8004:8004
/usr/sbin/uwsgi --plugin python --http-socket 0.0.0.0:8080 --wsgi-file /etc/ckan-datapusher/datapusher.wsgi --enable-threads

@ -1,21 +0,0 @@
#!/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 /etc/ssl/services.pem:/etc/ssl/services.pem \
-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
}

67
ckan.sh

@ -1,67 +0,0 @@
#!/bin/sh
set -e
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
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
# 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
chown -R 8003:8003 /srv/ckan/data
# 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
vm-appmgr update-login ckan "${CKAN_ADMIN_USER}" "${CKAN_ADMIN_PWD}"
# Install cron job
cp ${SOURCE_DIR}/etc/periodic/hourly/ckan /etc/periodic/hourly/ckan
# Stop services required for build
service solr stop
service redis stop
service postgres stop

@ -1,46 +0,0 @@
FROM python2
LABEL 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 flask-debugtoolbar \
&& pip install -e 'git+https://github.com/ckan/ckan.git#egg=ckan' \
&& 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"]

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

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