- [docker](src/docker) Use the native envvar `SVDIR` instead of `DOCKER_RUNSV_DIR`.

- [docker](src/docker) Update docker-entrypoint.sh.
- [docker](src/docker) Update docker-service.sh.
- [docker](src/docker) Now use docker-config.sh.
- [docker](src/docker) Now use DOCKER_ENTRY_DIR=/etc/docker/entry.d and DOCKER_EXIT_DIR=/etc/docker/exit.d.
- [kopano](src/kopano) 50-kopano-apply-envvars.
master v1.2.0
mlan 2020-06-22 22:39:33 +02:00
parent cbf0fdb5e2
commit 9e1906db58
18 changed files with 565 additions and 395 deletions

View File

@ -1,3 +1,12 @@
# 1.2.0
- [docker](src/docker) Use the native envvar `SVDIR` instead of `DOCKER_RUNSV_DIR`.
- [docker](src/docker) Update docker-entrypoint.sh.
- [docker](src/docker) Update docker-service.sh.
- [docker](src/docker) Now use docker-config.sh.
- [docker](src/docker) Now use DOCKER_ENTRY_DIR=/etc/docker/entry.d and DOCKER_EXIT_DIR=/etc/docker/exit.d.
- [kopano](src/kopano) 50-kopano-apply-envvars.
# 1.1.8
- [docker](Dockerfile) Configure z-push to use HTTP_X_FORWARDED_FOR.
@ -24,13 +33,13 @@
# 1.1.4
- Use `LDAP_URI` now that the historic directives `LDAP_HOST`, `LDAP_PORT`, `LDAP_PROTOCOL` are no longer supported (8.7.85).
- Split up initialization functions and process supervision. Process supervision stays in entrypoint.sh, whereas the initialization functions are moved to individual files in /etc/entrypoint.d.
- Apache runit script also needs `setup-runit.sh` option; force.
- Split up initialization functions and process supervision. Process supervision stays in docker-entrypoint.sh, whereas the initialization functions are moved to individual files in /etc/docker/entry.d.
- Apache runit script also needs `docker-service.sh` option; force.
# 1.1.3
- The `setup-runit.sh` script now have options: down, force, log, name, source, quiet.
- Fixed the Apache runit script, using the new `setup-runit.sh` script. Stopping the parent process now also stops all child processes. Using the quiet option, Apache does not flood the logs anymore.
- The `docker-service.sh` script now have options: down, force, log, name, source, quiet.
- Fixed the Apache runit script, using the new `docker-service.sh` script. Stopping the parent process now also stops all child processes. Using the quiet option, Apache does not flood the logs anymore.
- Added support of the environment variable `LMTP_LISTEN=*:2003`, due to misconfiguration of `kopano-dagent` in recent releases (8.7.84).
- Simplified the health check.
- Changed repository directory structure to a more general one.

View File

@ -9,26 +9,28 @@ FROM ${ARCH:+$ARCH/}$DIST:$REL AS base
LABEL maintainer=mlan
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONDONTWRITEBYTECODE=PleaseNoPyCache \
SVDIR=/etc/service \
DOCKER_BIN_DIR=/usr/local/bin \
DOCKER_RUNSV_DIR=/etc/service \
DOCKER_ENTRY_DIR=/etc/entrypoint.d \
DOCKER_EXIT_DIR=/etc/exitpoint.d \
DOCKER_ENTRY_DIR=/etc/docker/entry.d \
DOCKER_EXIT_DIR=/etc/docker/exit.d \
DOCKER_CONF_DIR1=/etc/kopano \
DOCKER_CONF_DIR2=/usr/share/z-push \
DOCKER_USER=kopano \
DOCKER_APPL_LIB=/var/lib/kopano \
KOPANO_SPAMD_LIB=/var/lib/kopano/spamd \
DOCKER_RUNAS=kopano \
DOCKER_BUILD_DEB_DIR=/tmp/deb \
DOCKER_BUILD_PASSES=1 \
SYSLOG_OPTIONS='-S' \
SYSLOG_LEVEL=5
#
# Copy utility scripts including entrypoint.sh to image
# Copy utility scripts including docker-entrypoint.sh to image
#
COPY src/*/bin $DOCKER_BIN_DIR/
COPY src/*/entrypoint.d $DOCKER_ENTRY_DIR/
COPY src/*/exitpoint.d $DOCKER_EXIT_DIR/
COPY src/*/entry.d $DOCKER_ENTRY_DIR/
COPY src/*/exit.d $DOCKER_EXIT_DIR/
#
# Install helpers
# Install helpers. Set bash as default shell. Setup syslogs service.
#
RUN apt-get update && apt-get install --yes --no-install-recommends \
apt-utils \
@ -39,7 +41,7 @@ RUN apt-get update && apt-get install --yes --no-install-recommends \
ca-certificates \
tar \
gnupg \
&& setup-runit.sh "syslogd -nO- -l$SYSLOG_LEVEL $SYSLOG_OPTIONS"
&& docker-service.sh "syslogd -nO- -l$SYSLOG_LEVEL $SYSLOG_OPTIONS"
@ -51,7 +53,7 @@ FROM base AS base-man
# Do not exclude man pages & other documentation
# Reinstall all currently installed packages in order to get the man pages back
#
ENV DEBIAN_FRONTEND=noninteractive
#ENV DEBIAN_FRONTEND=noninteractive
RUN rm -f /etc/dpkg/dpkg.cfg.d/excludes \
&& apt-get update \
&& dpkg -l | grep ^ii | cut -d' ' -f3 | xargs apt-get install -y --reinstall \
@ -77,7 +79,7 @@ ARG ARCH=amd64
# variables
#
ENV DEBIAN_FRONTEND=noninteractive \
DOCKER_RUNSV_DIR=/etc/service \
SVDIR=/etc/service \
DOCKER_BIN_DIR=/usr/local/bin \
LMTP_LISTEN=*:2003 \
SA_GROUP=kopano \
@ -96,9 +98,10 @@ RUN mkdir -p $DOCKER_BUILD_DEB_DIR \
&& for i in $(seq ${DOCKER_BUILD_PASSES}); do echo "\033[1;36mKOPANO CORE INSTALL PASS: $i\033[0m" \
&& dpkg --install --force-depends --skip-same-version --recursive $DOCKER_BUILD_DEB_DIR \
&& apt-get install --yes --no-install-recommends --fix-broken; done \
&& mkdir -p /var/lib/kopano/attachments && chown kopano: /var/lib/kopano/attachments \
&& mkdir -p /var/lib/kopano/attachments && chown $DOCKER_RUNAS: /var/lib/kopano/attachments \
&& mkdir -p $KOPANO_SPAMD_LIB/ham && chown $DOCKER_RUNAS: $KOPANO_SPAMD_LIB/ham \
&& rm -rf $DOCKER_BUILD_DEB_DIR \
&& setup-runit.sh \
&& docker-service.sh \
"kopano-dagent -l" \
"kopano-gateway -F" \
"kopano-ical -F" \
@ -114,15 +117,15 @@ RUN mkdir -p $DOCKER_BUILD_DEB_DIR \
#
# Have runit's runsvdir start all services
#
CMD runsvdir -P ${DOCKER_RUNSV_DIR}
CMD runsvdir -P ${SVDIR}
#
# Entrypoint, how container is run
#
ENTRYPOINT ["entrypoint.sh"]
ENTRYPOINT ["docker-entrypoint.sh"]
#
# Check if all services are running
#
HEALTHCHECK CMD sv status ${DOCKER_RUNSV_DIR}/*
HEALTHCHECK CMD sv status ${SVDIR}/*
@ -139,7 +142,7 @@ ARG REL
# variables
#
ENV DEBIAN_FRONTEND=noninteractive \
DOCKER_RUNSV_DIR=/etc/service \
SVDIR=/etc/service \
DOCKER_BUILD_DEB_DIR=/tmp/deb \
DOCKER_BUILD_PASSES=1
#
@ -156,21 +159,23 @@ RUN apt-get install --yes --no-install-recommends apache2 libapache2-mod-php \
&& dpkg --install --force-depends --skip-same-version --recursive $DOCKER_BUILD_DEB_DIR \
&& apt-get install --yes --no-install-recommends --fix-broken; done \
&& dpkg-reconfigure php7-mapi \
&& conf replace /etc/kopano/webapp/config.php 'define("INSECURE_COOKIES", false);' 'define("INSECURE_COOKIES", true);' \
# && conf fixmissing /etc/php/7.?/apache2/conf.d/kopano.ini /etc/php/7.?/mods-available/kopano.ini /etc/php5/conf.d/kopano.ini \
&& conf replace /etc/apache2/sites-available/kopano-webapp.conf 'Alias /webapp /usr/share/kopano-webapp' '<VirtualHost *:80>\\nDocumentRoot /usr/share/kopano-webapp' \
&& . docker-common.sh \
&& . docker-config.sh \
&& dc_replace /etc/kopano/webapp/config.php 'define("INSECURE_COOKIES", false);' 'define("INSECURE_COOKIES", true);' \
# && dc_fixmissing /etc/php/7.?/apache2/conf.d/kopano.ini /etc/php/7.?/mods-available/kopano.ini /etc/php5/conf.d/kopano.ini \
&& dc_replace /etc/apache2/sites-available/kopano-webapp.conf 'Alias /webapp /usr/share/kopano-webapp' '<VirtualHost *:80>\\nDocumentRoot /usr/share/kopano-webapp' \
&& echo '</VirtualHost>' >> /etc/apache2/sites-available/kopano-webapp.conf \
&& conf modify /etc/apache2/apache2.conf '^ErrorLog' syslog:user \
&& dc_modify /etc/apache2/apache2.conf '^ErrorLog' syslog:user \
&& echo 'CustomLog "||/usr/bin/logger -t apache -i -p user.debug" common' >> /etc/apache2/apache2.conf \
&& echo 'ServerName localhost' >> /etc/apache2/apache2.conf \
&& mkdir -p /etc/kopano/theme/Custom \
&& ln -sf /etc/kopano/theme/Custom /usr/share/kopano-webapp/plugins/. \
# && conf modify /etc/apache2/apache2.conf '^LogLevel' crit \
# && dc_modify /etc/apache2/apache2.conf '^LogLevel' crit \
&& a2disconf other-vhosts-access-log \
&& a2dissite 000-default.conf \
&& a2ensite kopano-webapp \
&& rm -rf $DOCKER_BUILD_DEB_DIR \
&& setup-runit.sh "-f -s /etc/apache2/envvars -q apache2 -DFOREGROUND -DNO_DETACH -k start"
&& docker-service.sh "-f -s /etc/apache2/envvars -q apache2 -DFOREGROUND -DNO_DETACH -k start"
#
# Ports
#
@ -191,7 +196,7 @@ ARG REL
# variables
#
ENV DEBIAN_FRONTEND=noninteractive \
DOCKER_RUNSV_DIR=/etc/service \
SVDIR=/etc/service \
DOCKER_BUILD_DEB_DIR=/tmp/deb \
DOCKER_BUILD_PASSES=1
#
@ -208,9 +213,11 @@ RUN debaddr="$(kopano-webaddr.sh --deb final http://repo.z-hub.io/z-push: ${DIST
z-push-config-apache \
z-push-autodiscover \
z-push-state-sql \
&& conf addafter /etc/apache2/conf-available/z-push.conf 'Alias /Microsoft-Server-ActiveSync' 'AliasMatch (?i)/Autodiscover/Autodiscover.xml "/usr/share/z-push/autodiscover/autodiscover.php"' '</IfModule>' \
&& conf replace /usr/share/z-push/config.php 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, false);' 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, \x27HTTP_X_FORWARDED_FOR\x27);' \
&& conf replace /usr/share/z-push/config.php 'define(\x27LOGBACKEND\x27, \x27filelog\x27);' 'define(\x27LOGBACKEND\x27, \x27syslog\x27);'
&& . docker-common.sh \
&& . docker-config.sh \
&& dc_addafter /etc/apache2/conf-available/z-push.conf 'Alias /Microsoft-Server-ActiveSync' 'AliasMatch (?i)/Autodiscover/Autodiscover.xml "/usr/share/z-push/autodiscover/autodiscover.php"' '</IfModule>' \
&& dc_replace /usr/share/z-push/config.php 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, false);' 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, \x27HTTP_X_FORWARDED_FOR\x27);' \
&& dc_replace /usr/share/z-push/config.php 'define(\x27LOGBACKEND\x27, \x27filelog\x27);' 'define(\x27LOGBACKEND\x27, \x27syslog\x27);'

View File

@ -172,7 +172,7 @@ To see all available configuration variables you can run `man` within the contai
make mail-app-man_server
```
If you do, you will notice that configuration variable names are all lower case, but they will be matched with all uppercase environment variables by the container `entrypoint.sh` script.
If you do, you will notice that configuration variable names are all lower case, but they will be matched with all uppercase environment variables by the container `docker-entrypoint.sh` script.
## SQL database configuration
@ -279,7 +279,7 @@ You can easily customize the Kopano WebApp see [New! JSON themes in Kopano WebAp
```bash
docker cp mytheme/. mail-app:/etc/kopano/theme/Custom
docker exec -it mail-app chown -R root: /etc/kopano/theme
docker exec -it mail-app conf replace /etc/kopano/webapp/config.php 'define("THEME", \x27\x27);' 'define("THEME", \x27Custom\x27);'
docker exec -it mail-app run dc_replace /etc/kopano/webapp/config.php 'define("THEME", \x27\x27);' 'define("THEME", \x27Custom\x27);'
```
Please note that it is not possible to rename the directory `/etc/kopano/theme/Custom` within the container without further modifications.

View File

@ -57,8 +57,11 @@ $(addsuffix -logs,$(srv_list)):
$(addsuffix -sh,$(srv_list)):
docker-compose exec $(patsubst %-sh,%,$@) sh
$(addsuffix -env,$(srv_list)):
docker-compose exec $(patsubst %-env,%,$@) env
$(addsuffix -sv,$(srv_list)):
docker-compose exec $(patsubst %-sv,%,$@) sh -c 'sv status $$DOCKER_RUNSV_DIR/*'
docker-compose exec $(patsubst %-sv,%,$@) sh -c 'sv status $$SVDIR/*'
$(addsuffix -diff,$(srv_list)):
docker container diff $(COMPOSE_PROJECT_NAME)_$(patsubst %-diff,%,$@)_1
@ -91,7 +94,7 @@ mta-test:
| nc -C localhost 25
mta-razor:
docker-compose exec mta conf cntcfg_razor_register
docker-compose exec mta run amavis_register_razor
mta-apk_list:
docker-compose exec mta /bin/sh -c 'for pkg in $$(apk info 2>/dev/null); do printf "%9s %s\n" $$(apk info -s $$pkg 2>/dev/null | sed -n "2{p;q}") $$pkg; done | sort'
@ -112,6 +115,10 @@ mta-debugtools:
mta-htop: mta-debugtools
docker-compose exec mta htop
mta-encrypt:
$(eval secret := $(shell whiptail --backtitle "doveadm pw" --title "encrypt password" --inputbox "password" 8 78 secret 3>&1 1>&2 2>&3))
docker-compose exec mta doveadm pw -p $(secret)
db-test:
docker-compose exec db mysqlshow -u $(MYSQL_USER) $(MYSQL_DATABASE) -p$(MYSQL_PASSWORD)

View File

@ -1,147 +0,0 @@
#!/bin/sh
#
# config
#
#
# usage
#
usage() { echo "
USAGE
conf COMMAND FILE [command-options]
COMMAND
modify <file> <parameter statement>
if parameter is found modify its value
uncomment parameter if needed
Examples:
conf modify /etc/clamav/clamd.conf Foreground yes
conf modify /etc/amavisd.conf \$sa_tag_level_deflt = -999;
replace <file> <old-string> <new-string>
match <old-string> and relpace it with <new-string>
Examples:
conf replace /etc/amavisd.conf /var/run/clamav/clamd.sock /run/clamav/clamd.sock
uncommentsection <file> <string>
Remove all leading '#' starting with a line that matches <string> and
ending with an empty line
Examples:
conf uncommentsection /etc/amavisd.conf '# ### http://www.clamav.net/'
comment <file> <string>
Add leading '#' to line matching <string>
Examples:
conf comment /etc/clamav/freshclam.conf UpdateLogFile
addafter <file> <start-string> <add-string> [<stop-string>]
Add <add-string> after line matching <start-string> folowed by an empty line or a line matching <stop-string>
Examples:
conf addafter /etc/amavisd.conf '@local_domains_maps' '$inet_socket_bind = '\''127.0.0.1'\'';'
fixmissing <file> <source> [<source>]
If <file> is missing create it using the first found <source>
Examples:
conf fixmissing /etc/php/7.?/apache2/conf.d/kopano.ini /etc/php/7.?/mods-available/kopano.ini /etc/php5/conf.d/kopano.ini
FILE
full path to file which will be edited in place
"
}
#
# commands
#
_escape() { echo "$@" | sed 's|/|\\\/|g' | sed 's|\$|\\\$|g' | sed "s/""'""/\\\x27/g" ;}
_exglob() { echo $(ls -d $(dirname $1))/$(basename $1) ;}
modify() {
local cfg_file=$1
shift
local lhs="$1"
shift
local eq=
local rhs=
if [ "$1" = "=" ]; then
eq="$1"
shift
rhs="$(_escape $@)"
else
rhs="$(_escape $@)"
fi
echo 's/.*('"$lhs"'\s*'"$eq"'\s*)[^ ]+(.*)/\1'"$rhs"'\2/g' $cfg_file
sed -ri 's/.*('"$lhs"'\s*'"$eq"'\s*)[^ ]+(.*)/\1'"$rhs"'\2/g' $cfg_file
}
replace() {
local cfg_file=$1
local old="$(_escape $2)"
local new="$(_escape $3)"
echo 's/'"$old"'/'"$new"'/g' $cfg_file
sed -i 's/'"$old"'/'"$new"'/g' $cfg_file
}
addafter() {
local cfg_file=$1
local start="$(_escape $2)"
local new="$(_escape $3)"
local stop="$(_escape $4)"
if [ -z "$stop" ]; then
echo '/'"$start"'/!{p;d;}; $!N;s/\n\s*$/\n'"$new"'\n/g' $cfg_file
sed -i '/'"$start"'/!{p;d;}; $!N;s/\n\s*$/\n'"$new"'\n/g' $cfg_file
else
echo '/'"$start"'/!{p;d;}; $!N;s/\n(.*'"$stop"'.*)/\n'"$new"'\n\1/g' $cfg_file
sed -ri '/'"$start"'/!{p;d;}; $!N;s/\n(.*'"$stop"'.*)/\n'"$new"'\n\1/g' $cfg_file
fi
}
comment() {
local cfg_file=$1
local string="$2"
sed -i 's/^'"$string"'/s/^/#/g' $cfg_file
}
uncommentsection() {
local cfg_file=$1
local startline="$(_escape $2)"
echo '/^'"$startline"'$/,/^\s*$/s/^#*//g' $cfg_file
sed -i '/^'"$startline"'$/,/^\s*$/s/^#*//g' $cfg_file
}
fixmissing() {
local cfg_file=$(_exglob $1)
shift
if [ ! -e $cfg_file ]; then
for src_file in $@; do
echo "CHECKING:$src_file"
if [ -e $(_exglob $src_file) ]; then
echo "FOUND:$(_exglob $src_file)"
ln -s $(_exglob $src_file) $cfg_file
break
fi
done
fi
}
cli_and_exit() {
if [ "$(basename $0)" = conf ]; then
local cmd=$1
if [ -n "$cmd" ]; then
shift
echo CMD:$cmd ARG:"$@"
$cmd "$@"
else
usage
fi
exit 0
fi
}
#
# allow command line interface
#
cli_and_exit "$@"

View File

@ -0,0 +1,102 @@
#!/bin/sh
#
# docker-common.sh
#
# Defines common functions. Source this file from other scripts.
#
DOCKER_LOGLEVEL=${DOCKER_LOGLEVEL-5}
DOCKER_LOGENTRY=${DOCKER_LOGENTRY-docker-entrypoint.sh}
DOCKER_LOGUSAGE=${DOCKER_LOGUSAGE-usage}
#
# Write messages to console if interactive or syslog if not.
# Usage: inform priority message
# The priority may be specified numerically or as a facility.level pair.
# Example user.notice, or 1.6 level is one of:
# 0|emerg|1|alert|2|crit|3|err|4|warning|5|notice|6|info|7|debug
#
dc_log() {
local script=$(basename $0)
local stamp="$(dc_log_stamp)"
local prio=$1
local level=${prio#*.}
local logtag="${script}[${$}]"
local ttytag="$(dc_log_stamp)$(dc_log_tag $level $logtag):"
shift
# Assume interactive if we have stdout open and print usage message if needed.
if [ -t 1 ]; then
echo "$@"
case "$level" in
0|emerg|1|alert|2|crit|3|err) $DOCKER_LOGUSAGE 2>/dev/null ;;
esac
else
# If we have /dev/log socket send message to logger otherwise to stdout.
if [ -S /dev/log ]; then
logger -t "$logtag" -p "$prio" "$@"
else
if dc_log_level "$level"; then
echo "$ttytag $@"
fi
fi
fi
}
#
# Color log output. Used if the syslogd daemon is not running.
#
dc_log_tag() {
local level=$1
local string=$2
local c l
case $level in
0|emerg) c=91; l=EMERG ;;
1|alert) c=91; l=ALERT ;;
2|crit) c=91; l=CRIT ;;
3|err) c=91; l=ERROR ;;
4|warning) c=93; l=WARN ;;
5|notice) c=92; l=NOTE ;;
6|info) c=92; l=INFO ;;
7|debug) c=92; l=DEBUG ;;
esac
printf "\e[%sm%s %s\e[0m\n" $c $string $l
}
#
# Use $DOCKER_LOGLEVEL during image build phase. Assume we are in build phase if
# $DOCKER_LOGENTRY is not running.
#
dc_log_level() {
local level=$1
if pidof $DOCKER_LOGENTRY >/dev/null; then
[ "$level" -le "$SYSLOG_LEVEL" ]
else
[ "$level" -le "$DOCKER_LOGLEVEL" ]
fi
}
#
# Don't add time stamp during image build phase. Assume we are in build phase if
# $DOCKER_LOGENTRY is not running.
#
dc_log_stamp() {
if grep -q $DOCKER_LOGENTRY /proc/1/cmdline; then
date +'%b %e %X '
fi
}
#
# Tests
#
dc_is_installed() { apk -e info $1 &>/dev/null ;} # true if pkg is installed
#
# Update loglevel
#
dc_update_loglevel() {
loglevel=${1-$SYSLOG_LEVEL}
if [ -n "$loglevel" ]; then
dc_log 5 "Setting syslogd level=$loglevel."
docker-service.sh "syslogd -nO- -l$loglevel $SYSLOG_OPTIONS"
[ -n "$DOCKER_RUNFUNC" ] && sv restart syslogd
fi
}

View File

@ -0,0 +1,244 @@
#!/bin/sh
#
# docker-config.sh
#
# Defines common functions. Source this file from other scripts.
#
# Defined in Dockerfile:
# DOCKER_UNLOCK_FILE
#
HOSTNAME=${HOSTNAME-$(hostname)}
DOMAIN=${HOSTNAME#*.}
TLS_KEYBITS=${TLS_KEYBITS-2048}
TLS_CERTDAYS=${TLS_CERTDAYS-30}
#
# general file manipulation commands, used both during build and run time
#
_escape() { echo "$@" | sed 's|/|\\\/|g' | sed 's|;|\\\;|g' | sed 's|\$|\\\$|g' | sed "s/""'""/\\\x27/g" ;}
dc_modify() {
local cfg_file=$1
shift
local lhs="$1"
shift
local eq=
local rhs=
if [ "$1" = "=" ]; then
eq="$1"
shift
rhs="$(_escape $@)"
else
rhs="$(_escape $@)"
fi
dc_log 7 's/.*('"$lhs"'\s*'"$eq"'\s*)[^#]+(.*)/\1'"$rhs"' \2/g' $cfg_file
sed -ri 's/.*('"$lhs"'\s*'"$eq"'\s*)[^#]+(.*)/\1'"$rhs"' \2/g' $cfg_file
}
dc_replace() {
local cfg_file=$1
local old="$(_escape $2)"
local new="$(_escape $3)"
dc_log 7 's/'"$old"'/'"$new"'/g' $cfg_file
sed -i 's/'"$old"'/'"$new"'/g' $cfg_file
}
dc_addafter() {
local cfg_file=$1
local startline="$(_escape $2)"
local new="$(_escape $3)"
dc_log 7 '/'"$startline"'/!{p;d;}; $!N;s/\n\s*$/\n'"$new"'\n/g' $cfg_file
sed -i '/'"$startline"'/!{p;d;}; $!N;s/\n\s*$/\n'"$new"'\n/g' $cfg_file
}
dc_comment() {
local cfg_file=$1
local string="$2"
dc_log 7 '/^'"$string"'/s/^/#/g' $cfg_file
sed -i '/^'"$string"'/s/^/#/g' $cfg_file
}
dc_uncommentsection() {
local cfg_file=$1
local startline="$(_escape $2)"
dc_log 7 '/^'"$startline"'$/,/^\s*$/s/^#*//g' $cfg_file
sed -i '/^'"$startline"'$/,/^\s*$/s/^#*//g' $cfg_file
}
dc_removeline() {
local cfg_file=$1
local string="$2"
dc_log 7 '/'"$string"'.*/d' $cfg_file
sed -i '/'"$string"'.*/d' $cfg_file
}
dc_uniquelines() {
local cfg_file=$1
dc_log 7 '$!N; /^(.*)\n\1$/!P; D' $cfg_file
sed -ri '$!N; /^(.*)\n\1$/!P; D' $cfg_file
}
#
# Persist dirs
#
#
# Make sure that we have the required directory structure in place under
# DOCKER_PERSIST_DIR.
#
dc_persist_mkdirs() {
local dirs=$@
for dir in $dirs; do
mkdir -p ${DOCKER_PERSIST_DIR}${dir}
done
}
#
# Make sure that we have the required directory structure in place under
# DOCKER_PERSIST_DIR.
#
dc_persist_dirs() {
local srcdirs="$@"
local dstdir
if [ -n "$DOCKER_PERSIST_DIR" ]; then
for srcdir in $srcdirs; do
mkdir -p "$srcdir"
dstdir="${DOCKER_PERSIST_DIR}${srcdir}"
mkdir -p "$(dirname $dstdir)"
mv -f "$srcdir" "$(dirname $dstdir)"
ln -sf "$dstdir" "$srcdir"
dc_log 5 "Moving $srcdir to $dstdir"
done
fi
}
#
# mv dir to persist location and leave a link to it
#
dc_persist_mvdirs() {
local srcdirs="$@"
if [ -n "$DOCKER_PERSIST_DIR" ]; then
for srcdir in $srcdirs; do
if [ -e "$srcdir" ]; then
local dstdir="${DOCKER_PERSIST_DIR}${srcdir}"
local dsthome="$(dirname $dstdir)"
if [ ! -d "$dstdir" ]; then
dc_log 5 "Moving $srcdir to $dstdir"
mkdir -p "$dsthome"
mv "$srcdir" "$dsthome"
ln -sf "$dstdir" "$srcdir"
else
dc_log 4 "$srcdir already moved to $dstdir"
fi
else
dc_log 4 "Cannot find $srcdir"
fi
done
fi
}
#
# Conditionally change owner of files.
#
dc_chowncond() {
local user=$1
local dir=$2
if id $user > /dev/null 2>&1; then
if [ -n "$(find $dir ! -user $user -print -exec chown -h $user: {} \;)" ]; then
dc_log 5 "Changed owner to $user for some files in $dir"
fi
fi
}
#
# Append entry if it is not already there. If mode is -i then append before last line.
#
dc_cond_append() {
local mode filename lineraw lineesc
case $1 in
-i) mode=i; shift;;
-a) mode=a; shift;;
*) mode=a;;
esac
filename=$1
shift
lineraw=$@
lineesc="$(echo $lineraw | sed 's/[\";/*]/\\&/g')"
if [ -e "$filename" ]; then
if [ -z "$(sed -n '/'"$lineesc"'/p' $filename)" ]; then
dc_log 7 "dc_cond_append append: $mode $filename $lineraw"
case $mode in
a) echo "$lineraw" >> $filename;;
i) sed -i "$ i\\$lineesc" $filename;;
esac
else
dc_log 4 "Avoiding duplication: $filename $lineraw"
fi
else
dc_log 7 "dc_cond_append create: $mode $filename $lineraw"
echo "$lineraw" >> $filename
fi
}
dc_cpfile() {
local suffix=$1
shift
local cfs=$@
for cf in $cfs; do
cp "$cf" "$cf.$suffix"
done
}
dc_mvfile() {
local suffix=$1
shift
local cfs=$@
for cf in $cfs; do
mv "$cf" "$cf.$suffix"
done
}
#
# Prune PID files
#
dc_prune_pidfiles() {
local dirs=$@
for dir in $dirs; do
if [ -n "$(find -H $dir -type f -name "*.pid" -exec rm {} \; 2>/dev/null)" ]; then
dc_log 5 "Removed orphan pid files in $dir"
fi
done
}
#
# TLS/SSL Certificates [openssl]
#
dc_tls_setup_selfsigned_cert() {
local cert=$1
local key=$2
if ([ ! -s $cert ] || [ ! -s $key ]); then
dc_log 5 "Setup self-signed TLS certificate for host $HOSTNAME"
openssl genrsa -out $key $TLS_KEYBITS
openssl req -x509 -utf8 -new -batch -subj "/CN=$HOSTNAME" \
-days $TLS_CERTDAYS -key $key -out $cert
fi
}
#
# Configuration Lock
#
dc_lock_config() {
if dc_is_unlocked; then
rm $DOCKER_UNLOCK_FILE
dc_log 5 "Removing unlock file, locking the configuration."
else
dc_log 5 "No unlock file found, so not touching configuration."
fi
}
#
# true if there is no lock file or FORCE_CONFIG is not empty
#
dc_is_unlocked() { [ -f "$DOCKER_UNLOCK_FILE" ] || [ -n "$FORCE_CONFIG" ] ;}

View File

@ -0,0 +1,84 @@
#!/bin/bash
# set -x
#
# This script need to run as PID 1 allowing it to receive signals from docker
#
# Usage: add the folowing lines in Dockerfile
# ENTRYPOINT ["docker-entrypoint.sh"]
# CMD runsvdir -P ${SVDIR}
#
#
# Variables
#
DOCKER_ENTRY_DIR=${DOCKER_ENTRY_DIR-/etc/docker/entry.d}
DOCKER_EXIT_DIR=${DOCKER_EXIT_DIR-/etc/docker/exit.d}
SVDIR=${SVDIR-/etc/service}
#
# Source common functions.
#
. docker-common.sh
. docker-config.sh
#
# Functions
#
#
# run_parts dir
# Read and execute commands from files in the _current_ shell environment
#
run_parts() {
for file in $(find $1 -type f -executable 2>/dev/null|sort); do
dc_log 7 run_parts: executing $file
. $file
done
}
#
# If the service is running, send it the TERM signal, and the CONT signal.
# If both files ./run and ./finish exits, execute ./finish.
# After it stops, do not restart the service.
#
sv_down() { sv down ${SVDIR}/* ;}
#
# SIGTERM handler
# docker stop first sends SIGTERM, and after a grace period, SIGKILL.
# use exit code 143 = 128 + 15 -- SIGTERM
#
term_trap() {
dc_log 4 "Got SIGTERM, so shutting down."
run_parts "$DOCKER_EXIT_DIR"
sv_down
exit 143
}
#
# Stage 0) Register signal handlers and redirect stderr
#
exec 2>&1
trap 'kill $!; term_trap' TERM
#
# Stage 1) run all entry scripts in $DOCKER_ENTRY_DIR
#
run_parts "$DOCKER_ENTRY_DIR"
#
# Stage 2) run provided arguments in the background
# Start services with: runsvdir -P ${SVDIR}
#
"$@" &
#
# Stage 3) wait forever so we can catch the SIGTERM
#
while true; do
tail -f /dev/null & wait $!
done

View File

@ -0,0 +1,44 @@
#!/bin/sh
#
# docker-runfunc.sh
#
# Allow functions to be accessed from the commandline.
#
#
# Source common functions.
#
. docker-common.sh
#
# dr_docker_call_func "$@"
#
dr_docker_call_func() {
export DOCKER_RUNFUNC="$@"
local cmd=$1
shift
dc_log 7 "CMD:$cmd ARG:$@"
$cmd "$@"
exit 0
}
#
# dr_docker_run_parts dir name
# Read and execute commands from files in the _current_ shell environment.
#
dr_docker_run_parts() {
for file in $(find $1 -type f -name "$2" -executable 2>/dev/null|sort); do
dc_log 7 run_parts: executing $file
. $file
done
}
#
# Source files with function definitions.
#
dr_docker_run_parts "$DOCKER_ENTRY_DIR" "1*"
#
# Call function.
#
dr_docker_call_func "$@"

View File

@ -1,10 +1,11 @@
#!/bin/sh
#
# setup-runit.sh
# docker-service.sh
#
. docker-common.sh
# use /etc/service if $DOCKER_RUNSV_DIR not already defined
DOCKER_RUNSV_DIR=${DOCKER_RUNSV_DIR-/etc/service}
# use /etc/service if $SVDIR not already defined
SVDIR=${SVDIR-/etc/service}
DOCKER_SVLOG_DIR=${DOCKER_SVLOG_DIR-/var/log/sv}
DOCKER_RUN_DIR=${DOCKER_RUN_DIR-/var/run}
@ -14,10 +15,10 @@ DOCKER_RUN_DIR=${DOCKER_RUN_DIR-/var/run}
usage() {
cat <<-!cat
NAME
setup-runit.sh
docker-service.sh
SYNOPSIS
setup-runit.sh [-d] [-f] [-h] [-l] [-n name] [-s file] [-q] command [args]
docker-service.sh [-d] [-f] [-h] [-l] [-n name] [-s file] [-q] command [args]
OPTIONS
-d default down
@ -29,7 +30,7 @@ usage() {
-q send stdout and stderr to /dev/null
EXAMPLES
setup-runit.sh "kopano-dagent -l" "-d kopano-grapi serve"
docker-service.sh "kopano-dagent -l" "-d kopano-grapi serve"
"-q -s /etc/apache2/envvars apache2 -DFOREGROUND -DNO_DETACH -k start"
!cat
@ -43,17 +44,6 @@ pid_name() {
echo "${DOCKER_RUN_DIR}/${dir_name}/${pid_name}.pid"
}
inform() {
name=$(basename $0)
case "$1" in
0) pre_string="\e[1m\e[92mINFO ($name)\e[0m";;
1) pre_string="\e[1m\e[93mWARN ($name)\e[0m";;
2) pre_string="\e[1m\e[91mERROR ($name)\e[0m";;
esac
shift
printf "$pre_string %s\n" "$*"
}
add_opt() {
if [ -z "$options" ]; then
options=$1
@ -85,14 +75,14 @@ init_service() {
shift $((OPTIND -1))
cmd=$(which "$1")
sv_name=${sv_name-$(base_name $1)}
runsv_dir=$DOCKER_RUNSV_DIR/$sv_name
runsv_dir=$SVDIR/$sv_name
svlog_dir=$DOCKER_SVLOG_DIR/$sv_name
if [ -n "$sv_force" ]; then
forcepid="$(echo rm -f $(pid_name $sv_name)*)"
fi
shift
if [ ! -z "$cmd" ]; then
inform 0 "Setting up ($sv_name) options ($options) args ($@)"
dc_log 5 "Setting up ($sv_name) options ($options) args ($@)"
mkdir -p $runsv_dir
cat <<-!cat > $runsv_dir/run
#!/bin/sh -e
@ -117,7 +107,6 @@ init_service() {
fi
}
#
# run
#

View File

@ -1,77 +0,0 @@
#!/usr/bin/env bash
# set -x
#
# This script need to run as PID 1 allowing it to receive signals from docker
#
# Usage: add the folowing lines in Dockerfile
# ENTRYPOINT ["entrypoint.sh"]
# CMD runsvdir -P ${DOCKER_RUNSV_DIR}
#
#
# Variables
#
DOCKER_ENTRY_DIR=${DOCKER_ENTRY_DIR-/etc/entrypoint.d}
DOCKER_EXIT_DIR=${DOCKER_EXIT_DIR-/etc/exitpoint.d}
DOCKER_RUNSV_DIR=${DOCKER_RUNSV_DIR-/etc/service}
#
# Functions
#
#
# Run all executable scipts in entry direcory
#
run_dir() {
local rundir=${1}
if [ -d "$rundir" ]; then
run-parts "$rundir"
fi
}
#
# If the service is running, send it the TERM signal, and the CONT signal.
# If ./run exits, start ./finish if it exists.
# After it stops, do not restart service.
#
sv_down() { sv down ${DOCKER_RUNSV_DIR}/* ;}
#
# SIGTERM handler
# docker stop first sends SIGTERM, and after a grace period, SIGKILL.
# use exit code 143 = 128 + 15 -- SIGTERM
#
term_trap() {
run_dir "$DOCKER_EXIT_DIR"
sv_down
exit 143
}
#
# Stage 0) Register signal hanglers and redirect stderr
#
exec 2>&1
trap 'kill ${!}; term_trap' SIGTERM
#
# Stage 1) run all entry scripts in $DOCKER_ENTRY_DIR
#
run_dir "$DOCKER_ENTRY_DIR"
#
# Stage 2) run provided arguments in the background
# Start services with: runsvdir -P ${DOCKER_RUNSV_DIR}
#
"$@" &
#
# Stage 3) wait forever so we can catch the SIGTERM
#
while true; do
tail -f /dev/null & wait ${!}
done

1
src/docker/bin/run Symbolic link
View File

@ -0,0 +1 @@
docker-runfunc.sh

View File

@ -0,0 +1,7 @@
#!/bin/sh
#
# 50-docker-update-loglevel
#
# If SYSLOG_LEVEL is not empty update syslog level
#
dc_update_loglevel

View File

@ -1,17 +0,0 @@
#!/bin/sh
#
# 50_update-loglevel
#
# If SYSLOG_LEVEL is not empty update syslog level
#
inform() { printf "entrypoint[$$]: INFO:$(basename $0): $*.\n" ;}
#
# run
#
if [ -n "$SYSLOG_LEVEL" ]; then
inform "Setting syslogd level=$SYSLOG_LEVEL"
setup-runit.sh "syslogd -nO- -l$SYSLOG_LEVEL $SYSLOG_OPTIONS"
fi

View File

@ -1,6 +1,6 @@
#!/bin/bash
#
# 50_update_config
# 50-kopano-apply-envvars
#
# Kopano now installs without any cfg files, so we just write custom values
# into their target cfg file.
@ -39,9 +39,7 @@ sqlstate_env_vars="STATE_SQL_ENGINE STATE_SQL_SERVER STATE_SQL_PORT STATE_SQL_DA
# Define helpers
#
inform() { printf "entrypoint[$$]: INFO:$(basename $0): $*.\n" ;}
_kopano_cfg_gen() {
_kopano_apply_envvars_gen() {
# do not touch existing cfg files
local cfg_file=$1
shift
@ -49,43 +47,43 @@ _kopano_cfg_gen() {
if [ ! -e $cfg_file ]; then
for env_var in $env_vars; do
if [ -n "${!env_var}" ]; then
inform "Setting ${env_var,,} = ${!env_var} in $cfg_file"
dc_log 5 "Setting ${env_var,,} = ${!env_var} in $cfg_file"
echo ${env_var,,} = ${!env_var} >> $cfg_file
fi
done
fi
}
_php_cfg_gen() {
_kopano_apply_phpenvvars_gen() {
local cfg_file=$1
shift
local env_vars=$@
if [ -e $cfg_file ]; then
for env_var in $env_vars; do
if [ -n "${!env_var}" ]; then
inform "Setting ${env_var} = ${!env_var} in $cfg_file"
dc_log 5 "Setting ${env_var} = ${!env_var} in $cfg_file"
sed -ri "s/(\s*define).+${env_var}.+/\1\(\x27${env_var}\x27, \x27${!env_var}\x27\);/g" $cfg_file
fi
done
fi
}
kopano_cfg() {
_kopano_cfg_gen $server_cfg_file $server_env_vars
_kopano_cfg_gen $ldap_cfg_file $ldap_env_vars
_kopano_cfg_gen $spooler_cfg_file $spooler_env_vars
_kopano_cfg_gen $dagent_cfg_file $dagent_env_vars
_kopano_cfg_gen $spamd_cfg_file $spamd_env_vars
kopano_apply_envvars() {
_kopano_apply_envvars_gen $server_cfg_file $server_env_vars
_kopano_apply_envvars_gen $ldap_cfg_file $ldap_env_vars
_kopano_apply_envvars_gen $spooler_cfg_file $spooler_env_vars
_kopano_apply_envvars_gen $dagent_cfg_file $dagent_env_vars
_kopano_apply_envvars_gen $spamd_cfg_file $spamd_env_vars
}
php_cfg() {
_php_cfg_gen $zpush_cfg_file $zpush_env_vars
_php_cfg_gen $sqlstate_cfg_file $sqlstate_env_vars
kopano_apply_phpenvvars() {
_kopano_apply_phpenvvars_gen $zpush_cfg_file $zpush_env_vars
_kopano_apply_phpenvvars_gen $sqlstate_cfg_file $sqlstate_env_vars
}
#
# run
#
kopano_cfg
php_cfg
kopano_apply_envvars
kopano_apply_phpenvvars

View File

@ -1,41 +0,0 @@
#!/bin/sh
#
# 10_fix_spamd_ham
#
# kopano-spamd creates /var/lib/kopano/spamd/ham with root ownership,
# but needs to be kopano
#
#
# config
#
DOCKER_USER=${DOCKER_USER-kopano}
DOCKER_SPAMD_DIR=${DOCKER_SPAMD_DIR-/var/lib/kopano/spamd}
#
# define helpers
#
inform() { printf "entrypoint[$$]: INFO:$(basename $0): $*.\n" ;}
fixattr() {
for dir in $@; do
if [ -n "$(find $dir ! -user $DOCKER_USER -print -exec chown -h $DOCKER_USER: {} \;)" ]; then
inform "Changed owner to $DOCKER_USER for some files in $dir"
fi
if [ -n "$(find -L $dir ! -user $DOCKER_USER -print -exec chown $DOCKER_USER: {} \;)" ]; then
inform "Changed owner to $DOCKER_USER for some files in $dir"
fi
if [ -n "$(find -H $dir ! -perm -u+rw -print -exec chmod u+rw {} \;)" ]; then
inform "Changed permission to rw for some files in $dir"
fi
done
}
#
# run
#
mkdir -p $DOCKER_SPAMD_DIR/ham
fixattr $DOCKER_SPAMD_DIR/ham

View File

@ -1,40 +0,0 @@
#!/bin/sh
#
# 20_fix_attr
#
# Make sure all files in named directories are RW by user $DOCKER_USER.
#
#
# config
#
DOCKER_USER=${DOCKER_USER-kopano}
DOCKER_ATCH_DIR=${DOCKER_ATCH_DIR-/var/lib/kopano/attachments}
DOCKER_SPAMD_DIR=${DOCKER_SPAMD_DIR-/var/lib/kopano/spamd}
#
# define helpers
#
inform() { printf "entrypoint[$$]: INFO:$(basename $0): $*.\n" ;}
fixattr() {
for dir in $@; do
if [ -n "$(find $dir ! -user $DOCKER_USER -print -exec chown -h $DOCKER_USER: {} \;)" ]; then
inform "Changed owner to $DOCKER_USER for some files in $dir"
fi
if [ -n "$(find -L $dir ! -user $DOCKER_USER -print -exec chown $DOCKER_USER: {} \;)" ]; then
inform "Changed owner to $DOCKER_USER for some files in $dir"
fi
if [ -n "$(find -H $dir ! -perm -u+rw -print -exec chmod u+rw {} \;)" ]; then
inform "Changed permission to rw for some files in $dir"
fi
done
}
#
# run
#
fixattr $DOCKER_ATCH_DIR $DOCKER_SPAM_DIR