Added docker container for 1.3.4

This commit is contained in:
Ramon Bartl 2020-10-13 23:53:16 +02:00
parent 07259cb50a
commit 421423906c
No known key found for this signature in database
GPG key ID: 359669D35BDDF79B
7 changed files with 670 additions and 0 deletions

70
1.3.4/Dockerfile Normal file
View file

@ -0,0 +1,70 @@
# Use an official Python runtime as a parent image
FROM python:2.7-stretch
# Set one or more individual labels
LABEL maintainer="Ramon Bartl"
LABEL email="rb@ridingbytes.com"
LABEL senaite.core.version="1.3.4"
# Set environment variables
ENV PLONE_MAJOR=4.3 \
PLONE_VERSION=4.3.19 \
PLONE_MD5=04ed5beac7fb8504f06a36d44e407b06 \
SENAITE_HOME=/home/senaite \
SENAITE_USER=senaite \
SENAITE_INSTANCE_HOME=/home/senaite/senaitelims \
SENAITE_DATA=/data \
SENAITE_FILESTORAGE=/data/filestorage \
SENAITE_BLOBSTORAGE=/data/blobstorage
# Create the senaite user
RUN useradd --system -m -d $SENAITE_HOME -U -u 500 $SENAITE_USER
# Create direcotries
RUN mkdir -p $SENAITE_INSTANCE_HOME $SENAITE_FILESTORAGE $SENAITE_BLOBSTORAGE
# Copy the package config
COPY packages.txt /
# Install package dependencies
RUN apt-get update && apt-get install -y --no-install-recommends $(grep -vE "^\s*#" /packages.txt | tr "\n" " ")
# Fetch unified installer
RUN wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/Plone-$PLONE_VERSION-UnifiedInstaller.tgz \
&& echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \
&& tar -xzf Plone.tgz \
&& cp -rv /Plone-$PLONE_VERSION-UnifiedInstaller/base_skeleton/* $SENAITE_INSTANCE_HOME \
&& cp -v /Plone-$PLONE_VERSION-UnifiedInstaller/buildout_templates/buildout.cfg $SENAITE_INSTANCE_HOME/buildout-base.cfg \
&& cd $SENAITE_HOME \
&& tar -xjf /Plone-$PLONE_VERSION-UnifiedInstaller/packages/buildout-cache.tar.bz2 \
&& rm -rf /Plone-$PLONE_VERSION-UnifiedInstaller /Plone.tgz
# Change working directory
WORKDIR $SENAITE_INSTANCE_HOME
# Copy Buildout
COPY bootstrap.py buildout.cfg ./
# Bootstrap and buildout
RUN python bootstrap.py \
&& bin/buildout \
&& ln -s $SENAITE_FILESTORAGE/ var/filestorage \
&& ln -s $SENAITE_BLOBSTORAGE/ var/blobstorage \
&& chown -R senaite:senaite $SENAITE_HOME $SENAITE_DATA \
&& rm -rf $SENAITE_HOME/buildout-cache/downloads/dist
# Mount external volume
VOLUME /data
# Copy startup scripts
COPY docker-initialize.py docker-entrypoint.sh /
# Expose instance port
EXPOSE 8080
# Add instance healthcheck
HEALTHCHECK --interval=1m --timeout=5s --start-period=1m \
CMD nc -z -w5 127.0.0.1 8080 || exit 1
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["start"]

210
1.3.4/bootstrap.py Normal file
View file

@ -0,0 +1,210 @@
##############################################################################
#
# Copyright (c) 2006 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Bootstrap a buildout-based project
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
import os
import shutil
import sys
import tempfile
from optparse import OptionParser
__version__ = '2015-07-01'
# See zc.buildout's changelog if this version is up to date.
tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.
Note that by using --find-links to point to local resources, you can keep
this script from going over the network.
'''
parser = OptionParser(usage=usage)
parser.add_option("--version",
action="store_true", default=False,
help=("Return bootstrap.py version."))
parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases',
action="store_true", default=False,
help=("Normally, if you do not specify a --version, the "
"bootstrap script and buildout gets the newest "
"*final* versions of zc.buildout and its recipes and "
"extensions for you. If you use this flag, "
"bootstrap and buildout will get the newest releases "
"even if they are alphas or betas."))
parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
parser.add_option("-f", "--find-links",
help=("Specify a URL to search for buildout releases"))
parser.add_option("--allow-site-packages",
action="store_true", default=False,
help=("Let bootstrap.py use existing site packages"))
parser.add_option("--buildout-version",
help="Use a specific zc.buildout version")
parser.add_option("--setuptools-version",
help="Use a specific setuptools version")
parser.add_option("--setuptools-to-dir",
help=("Allow for re-use of existing directory of "
"setuptools versions"))
options, args = parser.parse_args()
if options.version:
print("bootstrap.py version %s" % __version__)
sys.exit(0)
######################################################################
# load/install setuptools
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
ez = {}
if os.path.exists('ez_setup.py'):
exec(open('ez_setup.py').read(), ez)
else:
exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_site_packages:
# ez_setup imports site, which adds site packages
# this will remove them from the path to ensure that incompatible versions
# of setuptools are not in the path
import site
# inside a virtualenv, there is no 'getsitepackages'.
# We can't remove these reliably
if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages():
# Strip all site-packages directories from sys.path that
# are not sys.prefix; this is because on Windows
# sys.prefix is a site-package directory.
if sitepackage_path != sys.prefix:
sys.path[:] = [x for x in sys.path
if sitepackage_path not in x]
setup_args = dict(to_dir=tmpeggs, download_delay=0)
if options.setuptools_version is not None:
setup_args['version'] = options.setuptools_version
if options.setuptools_to_dir is not None:
setup_args['to_dir'] = options.setuptools_to_dir
ez['use_setuptools'](**setup_args)
import setuptools
import pkg_resources
# This does not (always?) update the default working set. We will
# do it.
for path in sys.path:
if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path)
######################################################################
# Install buildout
ws = pkg_resources.working_set
setuptools_path = ws.find(
pkg_resources.Requirement.parse('setuptools')).location
# Fix sys.path here as easy_install.pth added before PYTHONPATH
cmd = [sys.executable, '-c',
'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
find_links = os.environ.get(
'bootstrap-testing-find-links',
options.find_links or
('http://downloads.buildout.org/'
if options.accept_buildout_test_releases else None)
)
if find_links:
cmd.extend(['-f', find_links])
requirement = 'zc.buildout'
version = options.buildout_version
if version is None and not options.accept_buildout_test_releases:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
_final_parts = '*final-', '*final'
def _final_version(parsed_version):
try:
return not parsed_version.is_prerelease
except AttributeError:
# Older setuptools
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex(
search_path=[setuptools_path])
if find_links:
index.add_find_links((find_links,))
req = pkg_resources.Requirement.parse(requirement)
if index.obtain(req) is not None:
best = []
bestv = None
for dist in index[req.project_name]:
distv = dist.parsed_version
if _final_version(distv):
if bestv is None or distv > bestv:
best = [dist]
bestv = distv
elif distv == bestv:
best.append(dist)
if best:
best.sort()
version = best[-1].version
if version:
requirement = '=='.join((requirement, version))
cmd.append(requirement)
import subprocess
if subprocess.call(cmd) != 0:
raise Exception(
"Failed to execute command:\n%s" % repr(cmd)[1:-1])
######################################################################
# Import and run buildout
ws.add_entry(tmpeggs)
ws.require(requirement)
import zc.buildout.buildout
if not [a for a in args if '=' not in a]:
args.append('bootstrap')
# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
args[0:0] = ['-c', options.config_file]
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)

111
1.3.4/buildout.cfg Normal file
View file

@ -0,0 +1,111 @@
[buildout]
extends =
buildout-base.cfg
extensions =
index = https://pypi.python.org/simple/
var-dir=/data
user=admin:admin
effective-user = senaite
buildout-user = senaite
eggs-directory=../buildout-cache/eggs
download-cache=../buildout-cache/downloads
parts +=
zeo
eggs +=
senaite.lims
[client1]
recipe =
[zeo]
<= zeoserver_base
recipe = plone.recipe.zeoserver
zeo-address = 8080
[versions]
setuptools=
zc.buildout=
senaite.lims=1.3.4
soupsieve = 1.9.4
# The following part definition lists the versions picked:
Chameleon = 3.6.2
Products.ATExtensions = 1.1
Pyphen = 0.9.5
Werkzeug = 1.0.0
backports.functools-lru-cache = 1.6.1
cairocffi = 0.9.0
cffi = 1.14.0
cssselect2 = 0.2.2
html5lib = 1.0.1
more-itertools = 5.0.0
pdfrw = 0.4
plone.recipe.command = 1.1
plone.recipe.precompiler = 0.6
senaite.core.supermodel = 1.2.3
sourcecodegen = 0.6.14
tinycss2 = 0.6.1
webencodings = 0.5.1
z3c.pt = 3.2.0
# Required by:
# senaite.core==1.3.3
Products.DataGridField = 1.9.6
# Required by:
# senaite.core==1.3.3
Products.TextIndexNG3 = 3.4.14
# Required by:
# senaite.impress==1.2.3
beautifulsoup4 = 4.8.2
# Required by:
# senaite.core==1.3.3
collective.indexing = 2.1
# Required by:
# senaite.core==1.3.3
collective.progressbar = 0.5
# Required by:
# plone.jsonapi.core==0.6
dicttoxml = 1.7.4
# Required by:
# senaite.core==1.3.3
jarn.jsi18n = 1.1
# Required by:
# senaite.core==1.3.3
magnitude = 0.9.4
# Required by:
# senaite.core==1.3.3
plone.jsonapi.core = 0.6
# Required by:
# cffi==1.14.0
pycparser = 2.19
# Required by:
# senaite.core==1.3.3
z3c.jbot = 0.8
# Required by:
# plone.recipe.unifiedinstaller==4.3.2
# plone.recipe.zeoserver==1.3.1
# plone.recipe.zope2instance==4.4.1
# z3c.autoinclude==0.3.9
zc.buildout = 2.13.3
# Required by:
# Products.TextIndexNG3==3.4.14
zopyx.txng3.core = 3.6.2

11
1.3.4/docker-compose.yml Normal file
View file

@ -0,0 +1,11 @@
version: "2"
services:
senaite:
image: senaite
volumes:
- data:/data
ports:
- "8080:8080"
volumes:
data:

56
1.3.4/docker-entrypoint.sh Executable file
View file

@ -0,0 +1,56 @@
#!/bin/bash
set -e
COMMANDS="debug help logtail show stop adduser fg kill quit run wait console foreground logreopen reload shell status"
START="start restart zeoserver"
CMD="bin/instance"
gosu senaite python /docker-initialize.py
if [ -e "custom.cfg" ]; then
if [ ! -e "bin/develop" ]; then
gosu senaite /home/senaite/senaitelims/bin/buildout -c custom.cfg
gosu senaite python /docker-initialize.py
fi
fi
if [[ "$1" == "zeo"* ]]; then
CMD="bin/$1"
fi
if [ -z "$HEALTH_CHECK_TIMEOUT" ]; then
HEALTH_CHECK_TIMEOUT=1
fi
if [ -z "$HEALTH_CHECK_INTERVAL" ]; then
HEALTH_CHECK_INTERVAL=1
fi
if [[ $START == *"$1"* ]]; then
_stop() {
gosu senaite $CMD stop
kill -TERM $child 2>/dev/null
}
trap _stop SIGTERM SIGINT
gosu senaite $CMD start
gosu senaite $CMD logtail &
child=$!
pid=`$CMD status | sed 's/[^0-9]*//g'`
if [ ! -z "$pid" ]; then
echo "Application running on pid=$pid"
sleep "$HEALTH_CHECK_TIMEOUT"
while kill -0 "$pid" 2> /dev/null; do
sleep "$HEALTH_CHECK_INTERVAL"
done
else
echo "Application didn't start normally. Shutting down!"
_stop
fi
else
if [[ $COMMANDS == *"$1"* ]]; then
exec gosu senaite bin/instance "$@"
fi
exec "$@"
fi

184
1.3.4/docker-initialize.py Executable file
View file

@ -0,0 +1,184 @@
#!/usr/local/bin/python
import re
import os
import warnings
warnings.simplefilter('always', DeprecationWarning)
class Environment(object):
""" Configure container via environment variables
"""
def __init__(
self,
env=os.environ,
zope_conf="/home/senaite/senaitelims/parts/instance/etc/zope.conf",
custom_conf="/home/senaite/senaitelims/custom.cfg",
zeopack_conf="/home/senaite/senaitelims/bin/zeopack",
zeoserver_conf="/home/senaite/senaitelims/parts/zeoserver/etc/zeo.conf"):
self.env = env
self.zope_conf = zope_conf
self.custom_conf = custom_conf
self.zeopack_conf = zeopack_conf
self.zeoserver_conf = zeoserver_conf
def zeoclient(self):
""" ZEO Client
"""
server = self.env.get("ZEO_ADDRESS", None)
if not server:
return
config = ""
with open(self.zope_conf, "r") as cfile:
config = cfile.read()
# Already initialized
if "<blobstorage>" not in config:
return
read_only = self.env.get("ZEO_READ_ONLY", "false")
zeo_ro_fallback = self.env.get("ZEO_CLIENT_READ_ONLY_FALLBACK", "false")
shared_blob_dir = self.env.get("ZEO_SHARED_BLOB_DIR", "off")
zeo_storage = self.env.get("ZEO_STORAGE", "1")
zeo_client_cache_size = self.env.get("ZEO_CLIENT_CACHE_SIZE", "128MB")
zeo_conf = ZEO_TEMPLATE.format(
zeo_address=server,
read_only=read_only,
zeo_client_read_only_fallback=zeo_ro_fallback,
shared_blob_dir=shared_blob_dir,
zeo_storage=zeo_storage,
zeo_client_cache_size=zeo_client_cache_size
)
pattern = re.compile(r"<blobstorage>.+</blobstorage>", re.DOTALL)
config = re.sub(pattern, zeo_conf, config)
with open(self.zope_conf, "w") as cfile:
cfile.write(config)
def zeopack(self):
""" ZEO Pack
"""
server = self.env.get("ZEO_ADDRESS", None)
if not server:
return
if ":" in server:
host, port = server.split(":")
else:
host, port = (server, "8100")
with open(self.zeopack_conf, 'r') as cfile:
text = cfile.read()
text = text.replace('address = "8100"', 'address = "%s"' % server)
text = text.replace('host = "127.0.0.1"', 'host = "%s"' % host)
text = text.replace('port = "8100"', 'port = "%s"' % port)
with open(self.zeopack_conf, 'w') as cfile:
cfile.write(text)
def zeoserver(self):
""" ZEO Server
"""
pack_keep_old = self.env.get("ZEO_PACK_KEEP_OLD", '')
if pack_keep_old.lower() in ("false", "no", "0", "n", "f"):
with open(self.zeoserver_conf, 'r') as cfile:
text = cfile.read()
if 'pack-keep-old' not in text:
text = text.replace(
'</filestorage>',
' pack-keep-old false\n</filestorage>'
)
with open(self.zeoserver_conf, 'w') as cfile:
cfile.write(text)
def buildout(self):
""" Buildout from environment variables
"""
# Already configured
if os.path.exists(self.custom_conf):
return
eggs = self.env.get("PLONE_ADDONS",
self.env.get("ADDONS", "")).strip().split()
if not eggs:
eggs = self.env.get("BUILDOUT_EGGS", "").strip().split()
if eggs:
warnings.warn(
"BUILDOUT_EGGS is deprecated. Please use "
"PLONE_ADDONS instead !!!", DeprecationWarning)
zcml = self.env.get("PLONE_ZCML",
self.env.get("ZCML", "")).strip().split()
if not zcml:
zcml = self.env.get("BUILDOUT_ZCML", "").strip().split()
if zcml:
warnings.warn(
"BUILDOUT_ZCML is deprecated. Please use "
"PLONE_ZCML instead !!!", DeprecationWarning)
develop = self.env.get("PLONE_DEVELOP",
self.env.get("DEVELOP", "")).strip().split()
if not develop:
develop = self.env.get("BUILDOUT_DEVELOP", "").strip().split()
if develop:
warnings.warn(
"BUILDOUT_DEVELOP is deprecated. Please use "
"PLONE_DEVELOP instead !!!", DeprecationWarning)
if not (eggs or zcml or develop):
return
buildout = BUILDOUT_TEMPLATE.format(
eggs="\n\t".join(eggs),
zcml="\n\t".join(zcml),
develop="\n\t".join(develop)
)
with open(self.custom_conf, 'w') as cfile:
cfile.write(buildout)
def setup(self, **kwargs):
self.buildout()
self.zeoclient()
self.zeopack()
self.zeoserver()
__call__ = setup
ZEO_TEMPLATE = """
<zeoclient>
read-only {read_only}
read-only-fallback {zeo_client_read_only_fallback}
blob-dir /data/blobstorage
shared-blob-dir {shared_blob_dir}
server {zeo_address}
storage {zeo_storage}
name zeostorage
var /home/senaite/senaitelims/parts/instance/var
cache-size {zeo_client_cache_size}
</zeoclient>
""".strip()
BUILDOUT_TEMPLATE = """
[buildout]
extends = develop.cfg
develop += {develop}
eggs += {eggs}
zcml += {zcml}
"""
def initialize():
""" Configure Plone instance as ZEO Client
"""
environment = Environment()
environment.setup()
if __name__ == "__main__":
initialize()

28
1.3.4/packages.txt Normal file
View file

@ -0,0 +1,28 @@
dpkg-dev
gcc
gosu
libbz2-dev
libc6-dev
libcairo2
libffi-dev
libgdk-pixbuf2.0-0
libjpeg62
libjpeg62-turbo-dev
libopenjp2-7
libopenjp2-7-dev
libpango-1.0-0
libpangocairo-1.0-0
libpcre3-dev
libssl-dev
libtiff5
libtiff5-dev
libxml2
libxml2-dev
libxslt1-dev
libxslt1.1
lynx
netcat
rsync
wget
wv
zlib1g-dev