Compare commits
668 Commits
last-docke
...
master
Author | SHA1 | Date | |
---|---|---|---|
440317c552 | |||
fd23d27bba | |||
c9af05aeb0 | |||
5bd1f5e97c | |||
215ffb81ae | |||
7052ea8859 | |||
dd922b7775 | |||
2877cd2748 | |||
1d688ad1ff | |||
723a6a494f | |||
db26467d0b | |||
8d15e2806d | |||
f4700bef17 | |||
abf763683d | |||
0ad56ac087 | |||
81226d3bcc | |||
358281816f | |||
98327336ac | |||
89c4e2e88f | |||
521f3f2ab6 | |||
b17f6a3279 | |||
08313f07db | |||
01d19fe5fb | |||
093f306ec7 | |||
667354a158 | |||
53141556f7 | |||
88893abc50 | |||
082a9fb50d | |||
917c15420c | |||
ef116c12ef | |||
03d56ac0c9 | |||
86c97de908 | |||
967ccc0d44 | |||
6f52ea0f1a | |||
c50e67dbc0 | |||
31876f3776 | |||
4fd2de3935 | |||
b53f8b0a24 | |||
1c2e59e64b | |||
c757630f7a | |||
1c140bb593 | |||
5c1130eafe | |||
b189f3c9a2 | |||
783fd3c094 | |||
8bc038ea02 | |||
8428373178 | |||
ddcca22498 | |||
0f89b0ae4b | |||
9a83b97d33 | |||
a993e2f4ce | |||
fe9928443f | |||
d2082a896b | |||
a763665f32 | |||
2b09ee23c8 | |||
40a46cd675 | |||
9e2075a4af | |||
7355cdb888 | |||
a4c52f9b3b | |||
013f0d110e | |||
4ba0069a8a | |||
99099e03bb | |||
6ec890aa30 | |||
e39aa41c7c | |||
a7202756ab | |||
596955f6b4 | |||
14e07c9b56 | |||
3f9accced2 | |||
1cd9fb1485 | |||
9b517ceebb | |||
97a5c63d48 | |||
f79cddbf44 | |||
c3d5542bee | |||
a28b29f953 | |||
4cc79de59c | |||
af7be5c1be | |||
09b7ce481f | |||
3839eddb60 | |||
ebe3828b5e | |||
d532d087fe | |||
bbc669d2a7 | |||
74df7b6a59 | |||
624693bb22 | |||
5218d4d094 | |||
c9978e21c9 | |||
547c3cf84f | |||
c41a007870 | |||
60c0e25c49 | |||
0d1b4942c3 | |||
cba47bc0b2 | |||
e1e4f706ee | |||
603bd923e1 | |||
c2064220d0 | |||
1fb67a69f9 | |||
e0a071e9e5 | |||
a90cb7679b | |||
d307a559c0 | |||
3659f3d1ed | |||
87429cda34 | |||
b2db2816fa | |||
d5aca4ad52 | |||
57cef0f4cf | |||
ea2ba79f96 | |||
f5416a4501 | |||
553930da0d | |||
40e98ff42a | |||
615b847cf9 | |||
8e4b38ef18 | |||
004f35c186 | |||
a2ffc2ab63 | |||
837466742e | |||
b1ff00e36b | |||
04c9795586 | |||
001faa160e | |||
eb5b8365c3 | |||
29f1b52dee | |||
93f94e16ac | |||
16c9a6c862 | |||
92b61944dd | |||
1620028382 | |||
df2eb81928 | |||
52016223ab | |||
50e6ec1c3a | |||
b3b1daf989 | |||
2163506a8e | |||
21f695d7ba | |||
5107631271 | |||
676a9d24b7 | |||
e8e01417b2 | |||
1885b9e18e | |||
780f44246f | |||
1eea6c8e99 | |||
9417ad24a2 | |||
7331ab6d96 | |||
cc1ea7fa25 | |||
e5574db63c | |||
8771ac9828 | |||
6047cbcd0a | |||
ad437292ab | |||
bd946bf564 | |||
867997b588 | |||
6bab2bda8d | |||
de5e7da26d | |||
c287b1ea6e | |||
a12b0f101e | |||
0028a3ba5b | |||
09a146b54c | |||
5f6a7a2517 | |||
1a0c641df3 | |||
d16fcb8a9d | |||
391859ded4 | |||
e7e255488d | |||
cb4ff53efd | |||
087ad65518 | |||
15be9aad67 | |||
c04cf033a8 | |||
0bae44985c | |||
e788060456 | |||
d93c739d38 | |||
4c0fcc5535 | |||
268dc6447c | |||
6cb0440d4a | |||
bd70f07f8b | |||
ecfafd0c4a | |||
236c15dbac | |||
e0e49ec31a | |||
746713eb9f | |||
102761efac | |||
caf30e9958 | |||
9f8571f622 | |||
b804987254 | |||
2b9d73c847 | |||
cab95d15f3 | |||
b79323b4b7 | |||
3e8032d867 | |||
ef52c066d2 | |||
c32365d671 | |||
7a45daf853 | |||
fea0a7911a | |||
f63e78a800 | |||
0790a9243b | |||
590dde8206 | |||
40e26e4407 | |||
35345dc529 | |||
36181e3593 | |||
dadda1c175 | |||
719b4e04b6 | |||
692571a7f8 | |||
ff3d37517f | |||
d8d9f5431e | |||
8f27ee6afe | |||
797e900268 | |||
74ff517e09 | |||
0455738fa8 | |||
5782083921 | |||
be4042d7e4 | |||
f32b719630 | |||
512895a6f2 | |||
f6328158ed | |||
042a82c463 | |||
853c3852fd | |||
b55a5dfdbd | |||
4e0cbe0dcb | |||
58960e5e01 | |||
84d43f51ff | |||
e02fc0f97d | |||
157a0b8660 | |||
202aa1e8ca | |||
72a4ea9e5c | |||
243c8a4542 | |||
c7b0ea28b2 | |||
0b46076ae7 | |||
3632568e29 | |||
361bb2dc7b | |||
61ab0b0b48 | |||
734a9611e5 | |||
368a060a5e | |||
923b794cc6 | |||
f45e25ea2c | |||
81b9e8d0af | |||
07163889a3 | |||
04804d8883 | |||
bedbbb0c3a | |||
4c47c49eab | |||
29cad671dc | |||
705ac8104a | |||
d73b0c381f | |||
fe0777eaf2 | |||
f16d2cde9b | |||
7a19274211 | |||
36d0b9156c | |||
6aa4eb7778 | |||
76bef22633 | |||
7cb420dc4c | |||
99c39d5ee9 | |||
2ee9b97020 | |||
29d791afe1 | |||
7b1298d7d0 | |||
f948c885bc | |||
473dd4af61 | |||
f5fee5afa1 | |||
5e7846b519 | |||
e5c6203412 | |||
bba8f06422 | |||
076786f482 | |||
28a70e878e | |||
d7d89b9db6 | |||
44209ddfb3 | |||
e355510575 | |||
3713365950 | |||
1801fcdc3d | |||
18698ef5d4 | |||
d08848a4d0 | |||
48510beb28 | |||
751afa6cf2 | |||
64dced3dc8 | |||
b2b2c12cdf | |||
91c413ecbf | |||
2bd45fea0d | |||
c73c5f1eef | |||
7426ff6f9c | |||
0e465b0820 | |||
19b62a4370 | |||
ed997ab417 | |||
376a0f87ef | |||
c2a30bc4c1 | |||
9532bc7405 | |||
0351abcb92 | |||
a2605594d3 | |||
f2176428bc | |||
91a5a24b1b | |||
d94db19410 | |||
515672c170 | |||
8a23276748 | |||
a7a4004f53 | |||
22d10b5a69 | |||
7809cc8a5e | |||
bdf4a01b3b | |||
c71817c2e8 | |||
c22d2c7393 | |||
e794ced82a | |||
e1b7ba1204 | |||
f82ad15689 | |||
f8403c5f42 | |||
4d579ef8c1 | |||
b6c3949d41 | |||
c10b1a7920 | |||
9c3cee22a6 | |||
a41d270743 | |||
ebbbab71fb | |||
a9a930b37b | |||
b5eabcb311 | |||
7ed4628597 | |||
827991d7ac | |||
56af4a0b66 | |||
3d8154d87f | |||
d56afb17c2 | |||
5084dc1579 | |||
d3129d81ab | |||
e8138099cb | |||
fe9fb27679 | |||
692897c9bf | |||
85e8b631a1 | |||
9c50b29d22 | |||
de80024445 | |||
5a43c23b83 | |||
4458be2763 | |||
0f5c1d6433 | |||
4e9c63d8aa | |||
7e3431a4c0 | |||
79efa46226 | |||
f9507ae4b7 | |||
8434f192c9 | |||
d476a36f24 | |||
3a3552f154 | |||
466a83e407 | |||
93cc9f435b | |||
62a6612a79 | |||
f2016d1b71 | |||
715ad22409 | |||
1aaf16e8b7 | |||
3a554e1c84 | |||
cf99826386 | |||
9b18c94ddd | |||
985dd2998a | |||
f46fafa4ed | |||
4ba938d17f | |||
0f093a1087 | |||
4ac414c691 | |||
4391b33fbc | |||
826b244bae | |||
eac6129fb3 | |||
ed3aeb60d8 | |||
6c16aedadd | |||
d1fc5b7796 | |||
4e107840a1 | |||
8c7890fcbc | |||
15e7600ae4 | |||
57cd65115d | |||
990a9dcb71 | |||
a8bca6727b | |||
8b6f09c7d5 | |||
1ec7dfcc95 | |||
0bc2daf4ad | |||
ed0c6c90a7 | |||
2e674aa2d0 | |||
c9ceaff648 | |||
dfdd1de8e8 | |||
77196fdcca | |||
99d31eb0b5 | |||
8171f20309 | |||
8d42eac029 | |||
9d1e3f2d60 | |||
f9cc283477 | |||
89d3dd7d0c | |||
7f0d9572e3 | |||
69f67649f3 | |||
b1d705487a | |||
bbfe11f557 | |||
7116566519 | |||
2ea88cabce | |||
846a85e939 | |||
9f1f247484 | |||
1efc713ae3 | |||
ec7e843024 | |||
afbd4a0f60 | |||
446b855d03 | |||
7186daeb1c | |||
4fbeae6f7e | |||
b96aae6780 | |||
d3d8e3b766 | |||
f1fb7607b5 | |||
048c0053f5 | |||
a7c85af7cc | |||
6822f605d1 | |||
64aced5d8d | |||
bdc0d0a2a6 | |||
8e57996b9c | |||
9d0e30f728 | |||
b556ee3c30 | |||
cd4591501f | |||
1989b886f5 | |||
6e9e0dffe1 | |||
8f07df8c43 | |||
f35efa4a05 | |||
79442aa60e | |||
bc587252b4 | |||
1824e05393 | |||
e0637ce2a2 | |||
7e1e54a63e | |||
42ec6eeb95 | |||
5c48a83547 | |||
e165e9d8f7 | |||
f97d06873e | |||
959da1a423 | |||
081c517e21 | |||
dc41cd5f4a | |||
893c3028a1 | |||
13153d341b | |||
71fb5a7ca3 | |||
387a7072f9 | |||
65adfe8e16 | |||
efff62d21e | |||
4e36b2fb9e | |||
fda64ee225 | |||
b4b03d3505 | |||
ca3fd66ad3 | |||
1bb3a4330e | |||
0c9c54f481 | |||
db81cd38b8 | |||
4f72107c98 | |||
dfd0273a2c | |||
508cb47c1e | |||
f155f0bc22 | |||
8ddbc72644 | |||
91b1cfb08c | |||
cd6ea369d7 | |||
95665357f5 | |||
8cc7553acd | |||
938c47f950 | |||
eb079b9699 | |||
98e87aa772 | |||
d0751b1f2c | |||
4f81baf02f | |||
3e51996286 | |||
bf1c8b3fbf | |||
e051ad1e06 | |||
6977e1e7bd | |||
aaf2611b82 | |||
4129eb85c3 | |||
180997be4a | |||
6af3888fda | |||
cb4b17e1d5 | |||
3a424c5726 | |||
3f6a74b5bd | |||
ce325cf3d0 | |||
b4f5979354 | |||
bbf8219504 | |||
e58fc05a7d | |||
e17da9f060 | |||
b134f3c935 | |||
1ce6abc6e4 | |||
64dda6172e | |||
f623ce13ba | |||
ea289aff48 | |||
2dbefce8db | |||
1dce7601cf | |||
aecf3eede2 | |||
3dfd71eb03 | |||
8d6b2bdee6 | |||
afb121c72e | |||
e09669fb73 | |||
96490c6c3e | |||
2a75965449 | |||
8adf762acc | |||
a13c44d2d6 | |||
718a3b7a3f | |||
5992629869 | |||
43922d8192 | |||
49dffce0d0 | |||
e4d2422974 | |||
0ffbe9bb58 | |||
12869d5dca | |||
5de59917cd | |||
89a430fe5a | |||
e4bf6effe1 | |||
d833b439c7 | |||
af6f90f9cb | |||
6e182a9414 | |||
6822269c84 | |||
1812e27e1e | |||
b7d9cec76a | |||
e225af87fb | |||
58dc418e87 | |||
ab62d9bafc | |||
35a70fd5c1 | |||
072b529c9c | |||
979060da69 | |||
410958a2a7 | |||
76220d811d | |||
5919719f3e | |||
20a6d670ca | |||
b76a350d7b | |||
cdb74d9677 | |||
905f2c62c1 | |||
61fab326c3 | |||
237342254f | |||
a339c8e8ff | |||
f98edaff58 | |||
d5a5962ee2 | |||
5ba5461a80 | |||
0f4c2756ec | |||
6111325402 | |||
b772f92c22 | |||
eb27d92383 | |||
f6c44f3d0c | |||
7bca441acd | |||
25689d6345 | |||
f675996e60 | |||
cb0d0012c9 | |||
1400bab1e1 | |||
cb2a3d65d8 | |||
6bafd28e3e | |||
5e4dbd6adf | |||
0a32d9ed9d | |||
6b38073372 | |||
d2b410efe8 | |||
7c5b482392 | |||
874700ecb4 | |||
1060651116 | |||
afe8df823f | |||
6fb1e12ca6 | |||
38524e70af | |||
94048ba2fe | |||
960e7a2466 | |||
513c0839a5 | |||
848e99b4af | |||
977b9af923 | |||
77965c614a | |||
780e469f82 | |||
65dfff8eb0 | |||
951ae86520 | |||
920f01cf45 | |||
8be2bb2083 | |||
203a70bdbd | |||
b1cb57ab48 | |||
c6954816be | |||
396653c9a6 | |||
7df7428acf | |||
204318ef44 | |||
f9218366fa | |||
3abd3cf835 | |||
a0cf39811c | |||
ac69aebf4e | |||
07a195ab05 | |||
867a5d4d69 | |||
7abe6af068 | |||
efdd1b1c68 | |||
1817da3ebc | |||
76616fcab9 | |||
2a6d271d2d | |||
66c61e581d | |||
de0dcc79f4 | |||
14984b3199 | |||
1c967a0431 | |||
ab78d18491 | |||
30254eb527 | |||
dbce751225 | |||
91ebd4193e | |||
48e31ca0f1 | |||
528e676d4d | |||
b3cde0cdc8 | |||
88ae8848de | |||
31f7c408d4 | |||
a0dc16535d | |||
67caca8171 | |||
48492bf405 | |||
ed2e1193cb | |||
74b7d9478f | |||
00eff6fa85 | |||
96249760fd | |||
011cf4356b | |||
da896c79f2 | |||
33a4c10f7a | |||
0a30deb7e2 | |||
e055eb3542 | |||
00154ef899 | |||
fc99f7f6ab | |||
b0fe54d034 | |||
22fa90d785 | |||
0240e95621 | |||
3a2130eb48 | |||
4543bbc49f | |||
433e23022a | |||
d141fff4c1 | |||
1894893a6f | |||
d957227d40 | |||
725ecc75a6 | |||
30e2232b71 | |||
b8bb87390f | |||
ab82ed3fac | |||
cbaf4d6941 | |||
f74586c94c | |||
d1991ddc7d | |||
8cc184c7e7 | |||
8ac781bd8b | |||
b47df1d71d | |||
f747b89a5d | |||
f2a9529e29 | |||
44546c4816 | |||
57ecc71ebe | |||
365f983c2d | |||
db9458b4ad | |||
b7aedad589 | |||
86f4f940c7 | |||
986c13f4c7 | |||
01fc001990 | |||
7dbfe8533c | |||
4c5568f807 | |||
d3ecfbf4e7 | |||
367deb0897 | |||
0fda481317 | |||
677ac1bc4c | |||
7ebdfc1866 | |||
ea4b883b3f | |||
2b46473cb0 | |||
2c965f7cfb | |||
79f170ff01 | |||
523765188a | |||
384f43748b | |||
629e247570 | |||
2f6ba72cea | |||
41b598936f | |||
cbd65805f8 | |||
05bf6da6ce | |||
89b11a6112 | |||
444cfb58b1 | |||
cecb8d7dba | |||
ce71447928 | |||
ecf1143524 | |||
cd6d3815d6 | |||
88008ad40b | |||
6583acc129 | |||
344b6be624 | |||
c7c949eead | |||
d6447bb437 | |||
a25186b5ea | |||
939d9b0d45 | |||
b02d70df38 | |||
5facbb1b35 | |||
9f02c98d1b | |||
bc4c073b43 | |||
cff204ca46 | |||
fa70f85acb | |||
e8354e59c9 | |||
a9e99a82c5 | |||
0b56beea89 | |||
9b4be311e6 | |||
354c98bbf0 | |||
89126185eb | |||
bed2d7f5f6 | |||
de640bb005 | |||
6ca49d4865 | |||
26bbab959f | |||
b56ac216ce | |||
03050dd389 | |||
5db1ed2baf | |||
9a8c2103d4 | |||
fd07ec7cb8 | |||
d0e3be5ce6 | |||
43c8962b0f | |||
6427a6ec09 | |||
933a75bf57 | |||
eb69ea3cf1 | |||
1b07ef795e | |||
402ac5a469 | |||
8a65b6a0f4 | |||
824af776d9 | |||
dd955c5e59 | |||
260c8159c7 | |||
d21b09d547 | |||
1608b7a93f | |||
26075bad79 | |||
deacaa94be | |||
c3255cb00d | |||
1619380fdc | |||
3a6011aad4 | |||
b6ac14880b | |||
1c40252112 |
@ -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
|
90
README.md
@ -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 |
|
13
activemq.sh
@ -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
|
28
apk/py3-secure-cookie/APKBUILD
Normal file
@ -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/ /
|
70
basic.sh
@ -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); }
|
||||
}
|
Before ![]() (image error) Size: 5.4 KiB |
Before ![]() (image error) Size: 69 KiB |
Before ![]() (image error) Size: 17 KiB |
Before ![]() (image error) Size: 33 KiB |
Before ![]() (image error) Size: 70 KiB |
Before ![]() (image error) Size: 12 KiB |
Before ![]() (image error) Size: 15 KiB |
Before ![]() (image error) Size: 6.4 KiB |
Before ![]() (image error) Size: 40 KiB |
Before ![]() (image error) Size: 119 KiB |
Before ![]() (image error) Size: 42 KiB |
Before ![]() (image error) Size: 12 KiB |
Before ![]() (image error) Size: 36 KiB |
Before ![]() (image error) Size: 83 KiB |
Before ![]() (image error) Size: 101 KiB |
Before ![]() (image error) Size: 16 KiB |
Before ![]() (image error) Size: 7.9 KiB |
Before ![]() (image error) Size: 47 KiB |
Before ![]() (image error) Size: 6.1 KiB |
Before ![]() (image error) Size: 22 KiB |
Before ![]() (image error) Size: 21 KiB |
Before ![]() (image error) Size: 16 KiB |
Before ![]() (image error) Size: 13 KiB |
Before ![]() (image error) Size: 12 KiB |
Before ![]() (image error) Size: 32 KiB |
Before ![]() (image error) Size: 23 KiB |
Before ![]() (image error) Size: 53 KiB |
Before ![]() (image error) Size: 17 KiB |
Before ![]() (image error) Size: 16 KiB |
Before ![]() (image error) Size: 48 KiB |
Before ![]() (image error) Size: 21 KiB |
Before ![]() (image error) Size: 9.2 KiB |
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;
|
||||
}
|
2
basic/srv/vm/static/js/jquery-3.3.1.min.js
vendored
@ -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> </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> </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> </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> </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> </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"
|
8
build/etc/nginx/conf.d/repo.conf
Normal file
@ -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
|