Refactored platydock and platyvenv

This commit is contained in:
Fabio Manganiello 2019-12-01 22:27:54 +01:00
parent f27e1efdd6
commit f8d3ea5197
3 changed files with 95 additions and 92 deletions

View file

@ -1,18 +1,22 @@
FROM python:alpine3.7
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN apk add --update --no-cache --virtual build-base \
&& apk add --update --no-cache libffi-dev \
&& apk add --update --no-cache zlib-dev \
&& apk add --update --no-cache libjpeg-turbo-dev \
&& pip install -r requirements.txt \
&& apk del build-base \
&& apk del libffi-dev \
&& apk del libjpeg-turbo-dev \
&& apk del zlib-dev
RUN cd /app && python setup.py build install
CMD python -m platypush
# Sample Dockerfile. Use platydock -c /path/to/custom/config.yamlr
# to generate your custom Dockerfile.
FROM python:alpine3.7
RUN mkdir /app
COPY . /app
WORKDIR /app
RUN apk add --update --no-cache --virtual build-base \
&& apk add --update --no-cache libffi-dev \
&& apk add --update --no-cache zlib-dev \
&& apk add --update --no-cache libjpeg-turbo-dev \
&& pip install -r requirements.txt \
&& apk del build-base \
&& apk del libffi-dev \
&& apk del libjpeg-turbo-dev \
&& apk del zlib-dev
RUN cd /app && python setup.py build install
CMD python -m platypush

View file

@ -17,7 +17,7 @@ function build {
cfgfile=
while getopts ':c:' opt; do
case $opt in
case ${opt} in
c)
cfgfile=$OPTARG;;
\?)
@ -29,7 +29,7 @@ function build {
esac
done
if [ -z "$cfgfile" ]; then
if [[ -z "$cfgfile" ]]; then
echo "Usage: $0 build -c <path-to-platypush-config-file>" >&2
exit 1
fi
@ -39,18 +39,18 @@ function build {
includes=()
while read -r line; do
echo $line | egrep '``pip install .+?``' > /dev/null 2>&1
echo ${line} | egrep '``pip install .+?``' > /dev/null 2>&1
if (( $? != 0 )); then
continue
fi
dep=$(echo $line | sed -r -e 's/.*``pip install (.+?)``.*/\1/')
dep=$(echo ${line} | sed -r -e 's/.*``pip install (.+?)``.*/\1/')
deps+=("$dep")
done <<< $(python <<EOF
from platypush.config import Config
from platypush.context import get_plugin, get_backend, register_backends
Config.init('`realpath $cfgfile`')
Config.init('`realpath ${cfgfile}`')
register_backends()
backend_config = Config.get_backends()
@ -68,12 +68,12 @@ EOF
)
while read -r include; do
includes+=($include)
includes+=(${include})
done <<< $(python <<EOF
from platypush.config import Config
from platypush.context import get_plugin, get_backend, register_backends
Config.init('`realpath $cfgfile`')
Config.init('`realpath ${cfgfile}`')
for include in Config._included_files:
print(include)
@ -83,13 +83,13 @@ EOF
device_id=$(python <<EOF
from platypush.config import Config
Config.init('`realpath $cfgfile`')
Config.init('`realpath ${cfgfile}`')
print(Config.get('device_id'))
EOF
)
envdir=$workdir/$device_id
etcdir=$envdir/etc/platypush
envdir=${workdir}/${device_id}
etcdir=${envdir}/etc/platypush
echo "Preparing virtual environment for device $device_id"
mkdir -p "$envdir"
@ -105,18 +105,18 @@ EOF
done
cp "$cfgfile" "$etcdir/config.yaml"
cfgfile=$etcdir/config.yaml
cfgfile=${etcdir}/config.yaml
python3 -m venv $envdir
cd $envdir
source $envdir/bin/activate
python3 -m venv ${envdir}
cd ${envdir}
source ${envdir}/bin/activate
echo "Installing required dependencies"
for ((i=0; $i < ${#deps[@]}; i++)); do
echo ${deps[$i]}
done | sort -u | while read dep; do
pip install $dep
pip install ${dep}
done
pip install --upgrade git+https://github.com/BlackLight/platypush.git
@ -124,29 +124,29 @@ EOF
}
function start {
if [ -z "$1" ]; then
if [[ -z "$1" ]]; then
echo "Usage: $0 start <env-name>" >&2
exit 1
fi
env=$1
envdir=$workdir/$env
logsdir=$envdir/var/log/platypush
rundir=$envdir/var/run
pidfile=$rundir/platypush.pid
cfgfile=$envdir/etc/platypush/config.yaml
envdir=${workdir}/${env}
logsdir=${envdir}/var/log/platypush
rundir=${envdir}/var/run
pidfile=${rundir}/platypush.pid
cfgfile=${envdir}/etc/platypush/config.yaml
if [ ! -d "$envdir" ]; then
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
mkdir -p $logsdir
mkdir -p $rundir
mkdir -p ${logsdir}
mkdir -p ${rundir}
if [[ -f "$pidfile" ]]; then
pid=`cat "$pidfile"`
if ps -p $pid | grep platypush; then
if ps -p ${pid} | grep platypush; then
echo "Another instance (PID $pid) is running, please stop that instance first"
exit 1
fi
@ -155,10 +155,10 @@ function start {
rm -f "$pidfile"
fi
python3 -m venv $envdir
cd $envdir
python3 -m venv ${envdir}
cd ${envdir}
source bin/activate
bin/platypush -c "$cfgfile" -P "$pidfile" > $logsdir/stdout.log 2> $logsdir/stderr.log &
bin/platypush -c "$cfgfile" -P "$pidfile" > ${logsdir}/stdout.log 2> ${logsdir}/stderr.log &
start_time=`date +'%s'`
timeout=30
@ -166,7 +166,7 @@ function start {
[[ -f "$pidfile" ]] && break
now=`date +'%s'`
let elapsed=$now-$start_time
if (( $elapsed >= $timeout )); then
if (( ${elapsed} >= ${timeout} )); then
echo "Platypush instance '$env' didn't start within $timeout seconds" >&2
exit 1
fi
@ -181,44 +181,44 @@ function start {
}
function stop {
if [ -z "$1" ]; then
if [[ -z "$1" ]]; then
echo "Usage: $0 stop <env-name>" >&2
exit 1
fi
env=$1
envdir=$workdir/$env
rundir=$envdir/var/run
pidfile=$rundir/platypush.pid
envdir=${workdir}/${env}
rundir=${envdir}/var/run
pidfile=${rundir}/platypush.pid
if [ ! -d "$envdir" ]; then
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
if [[ ! -f "$pidfile" ]]; then
echo "No pidfile found for instance "$env""
echo "No pidfile found for instance "${env}""
exit 1
fi
pid=`cat "$pidfile"`
pids="$pid `ps --no-headers -o pid= --ppid $pid`"
kill -9 $pids
kill -9 ${pids}
rm -f "$pidfile"
echo "Instance '$env' with PID $pid stopped"
}
function rme {
if [ -z "$1" ]; then
if [[ -z "$1" ]]; then
echo "Usage: $0 rm <env-name>" >&2
exit 1
fi
envdir=$workdir/$1
rundir=$envdir/var/run
pidfile=$rundir/platypush.pid
envdir=${workdir}/$1
rundir=${envdir}/var/run
pidfile=${rundir}/platypush.pid
if [ ! -d "$envdir" ]; then
if [[ ! -d "$envdir" ]]; then
echo "No such directory: $envdir" >&2
exit 1
fi
@ -247,10 +247,10 @@ fi
action=$1
shift
mkdir -p $workdir
mkdir -p ${workdir}
case $action in
'build') build $*;;
case ${action} in
'build') build;;
'start') start $*;;
'stop') stop $*;;
'rm') rme $*;;

View file

@ -17,21 +17,19 @@ import sys
import textwrap
import traceback as tb
import platypush
from platypush.config import Config
from platypush.context import register_backends, get_plugin, get_backend
workdir = os.path.join(os.path.expanduser('~'), '.local', 'share',
'platypush', 'platydock')
'platypush', 'platydock')
class Action(enum.Enum):
build = 'build'
start = 'start'
stop = 'stop'
rm = 'rm'
ls = 'ls'
stop = 'stop'
rm = 'rm'
ls = 'ls'
def __str__(self):
return self.value
@ -47,30 +45,28 @@ def _parse_deps(cls):
return deps
def generate_dockerfile(deps, ports, cfgfile, devdir):
def generate_dockerfile(deps, ports, cfgfile, devdir, python_version):
device_id = Config.get('device_id')
if not device_id:
raise RuntimeError(('You need to specify a device_id in {} - Docker ' +
'containers cannot rely on hostname').format(cfgfile))
try:
os.makedirs(devdir)
except FileExistsError:
pass
'containers cannot rely on hostname').format(cfgfile))
os.makedirs(devdir, exist_ok=True)
content = textwrap.dedent(
'''
FROM python:alpine3.7
FROM python:alpine{python_version}
RUN mkdir -p /etc/platypush
RUN mkdir -p /usr/local/share/platypush\n
''').lstrip()
'''.format(python_version=python_version)).lstrip()
srcdir = os.path.dirname(cfgfile)
cfgfile_copy = os.path.join(devdir, 'config.yaml')
subprocess.call(['cp', cfgfile, cfgfile_copy])
content += 'COPY config.yaml /etc/platypush/\n'
# noinspection PyProtectedMember
for include in Config._included_files:
incdir = os.path.relpath(os.path.dirname(include), srcdir)
destdir = os.path.join(devdir, incdir)
@ -83,8 +79,7 @@ def generate_dockerfile(deps, ports, cfgfile, devdir):
subprocess.call(['cp', include, destdir])
content += 'RUN mkdir -p /etc/platypush/' + incdir + '\n'
content += 'COPY ' + os.path.relpath(include, srcdir) + \
' /etc/platypush/' + incdir + '\n'
' /etc/platypush/' + incdir + '\n'
content += textwrap.dedent(
'''
@ -96,7 +91,7 @@ def generate_dockerfile(deps, ports, cfgfile, devdir):
content += '\t&& pip install {} \\\n'.format(dep)
content += '\t&& pip install ' + \
'git+https://github.com/BlackLight/platypush.git \\\n'
'git+https://github.com/BlackLight/platypush.git \\\n'
content += '\t&& apk del git \\\n'
content += '\t&& apk del build-base\n\n'
@ -120,14 +115,17 @@ def build(args):
parser = argparse.ArgumentParser(prog='platydock build',
description='Build a Platypush image ' +
'from a config.yaml')
'from a config.yaml')
parser.add_argument('-c', '--config', type=str, required=True,
help='Path to the platypush configuration file')
parser.add_argument('-p', '--python-version', type=str, default='3.8',
help='Python version to be used')
opts, args = parser.parse_known_args(args)
cfgfile = os.path.abspath(os.path.expanduser(opts.config))
python_version = opts.python_version
Config.init(cfgfile)
register_backends()
backend_config = Config.get_backends()
@ -150,11 +148,11 @@ def build(args):
for name in Config.get_plugins().keys():
try:
deps.update(_parse_deps(get_plugin(name)))
except:
pass
except Exception as ex:
print('Dependencies parsing error for {}: {}'.format(name, str(ex)))
devdir = os.path.join(workdir, Config.get('device_id'))
generate_dockerfile(deps=deps, ports=ports, cfgfile=cfgfile, devdir=devdir)
generate_dockerfile(deps=deps, ports=ports, cfgfile=cfgfile, devdir=devdir, python_version=python_version)
subprocess.call(['docker', 'build', '-t', 'platypush-{}'.format(
Config.get('device_id')), devdir])
@ -164,8 +162,8 @@ def start(args):
global workdir
parser = argparse.ArgumentParser(prog='platydock start',
description='Start a Platypush container',
epilog=textwrap.dedent('''
description='Start a Platypush container',
epilog=textwrap.dedent('''
You can append additional options that
will be passed to the docker container.
Example:
@ -239,9 +237,9 @@ def rm(args):
parser = argparse.ArgumentParser(prog='platydock rm',
description='Remove a Platypush image. ' +
'NOTE: make sure that no container is ' +
'running nor linked to the image before ' +
'removing it')
'NOTE: make sure that no container is ' +
'running nor linked to the image before ' +
'removing it')
parser.add_argument('image', type=str, help='Platypush image to remove')
opts, args = parser.parse_known_args(args)
@ -274,12 +272,14 @@ def ls(args):
for image in images:
print(image)
def main():
parser = argparse.ArgumentParser(prog='platydock', add_help=False,
description='Manage Platypush docker containers',
epilog='Use platydock <action> --help to ' +
'get additional help')
'get additional help')
# noinspection PyTypeChecker
parser.add_argument('action', nargs='?', type=Action, choices=list(Action),
help='Action to execute')
parser.add_argument('-h', '--help', action='store_true', help='Show usage')
@ -302,5 +302,4 @@ if __name__ == '__main__':
tb.print_exc(file=sys.stdout)
print(ERR_PREFIX + str(e) + ERR_SUFFIX, file=sys.stderr)
# vim:sw=4:ts=4:et: