diff --git a/5.2/5.2.14/alpine/Dockerfile b/5.2/5.2.14/alpine/Dockerfile new file mode 100644 index 0000000..21babe5 --- /dev/null +++ b/5.2/5.2.14/alpine/Dockerfile @@ -0,0 +1,71 @@ +FROM python:3.8-alpine + +ENV PIP=22.2.2 \ + ZC_BUILDOUT=3.0.1 \ + SETUPTOOLS=65.7.0 \ + WHEEL=0.38.4 \ + PLONE_MAJOR=5.2 \ + PLONE_VERSION=5.2.13 \ + PLONE_VERSION_RELEASE=Plone-5.2.13-UnifiedInstaller-1.0 \ + PLONE_MD5=12c037fae9413385149e8677f8457b84 + +RUN addgroup -g 500 plone \ + && adduser -S -D -G plone -u 500 plone \ + && mkdir -p /plone/instance /data/filestorage /data/blobstorage + +COPY buildout.cfg /plone/instance/ + +RUN apk add --no-cache --virtual .build-deps \ + build-base \ + libc-dev \ + zlib-dev \ + libjpeg-turbo-dev \ + libpng-dev \ + libxml2-dev \ + libxslt-dev \ + mariadb-dev \ + openldap-dev \ + pcre-dev \ + postgresql-dev \ + libffi-dev \ +&& wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/$PLONE_VERSION_RELEASE.tgz \ +&& echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \ +&& tar -zxvf Plone.tgz \ +&& cp -rv ./$PLONE_VERSION_RELEASE/base_skeleton/* /plone/instance/ \ +&& cp -v ./$PLONE_VERSION_RELEASE/buildout_templates/buildout.cfg /plone/instance/buildout-base.cfg \ +&& pip install pip==$PIP setuptools==$SETUPTOOLS zc.buildout==$ZC_BUILDOUT wheel==$WHEEL \ +# some package needs PyYAML 5.4.1, and this can only be built with cython<3.0.0 +&& pip install "cython<3.0.0" && pip install --no-build-isolation pyyaml==5.4.1 \ +&& cd /plone/instance \ +&& buildout \ +&& ln -s /data/filestorage/ /plone/instance/var/filestorage \ +&& ln -s /data/blobstorage /plone/instance//var/blobstorage \ +&& find /data -not -user plone -exec chown plone:plone {} \+ \ +&& find /plone -not -user plone -exec chown plone:plone {} \+ \ +&& rm -rf /Plone* \ +&& apk del .build-deps \ +&& apk add --no-cache --virtual .run-deps \ + su-exec \ + bash \ + git \ + rsync \ + libldap \ + libxml2 \ + libxslt \ + libjpeg-turbo \ + mariadb-connector-c \ + postgresql-client \ +&& rm -rf /plone/buildout-cache/downloads/* + +VOLUME /data + +COPY docker-initialize.py docker-entrypoint.sh / + +EXPOSE 8080 +WORKDIR /plone/instance + +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"] diff --git a/5.2/5.2.14/alpine/buildout.cfg b/5.2/5.2.14/alpine/buildout.cfg new file mode 100644 index 0000000..02ca654 --- /dev/null +++ b/5.2/5.2.14/alpine/buildout.cfg @@ -0,0 +1,106 @@ +[buildout] +extends = + buildout-base.cfg + +index = https://pypi.org/simple/ + +extensions = +effective-user = plone +buildout-user = plone +var-dir=/data +user=admin:admin +parts += + zeo + mrbob + plonesite + +eggs += + RelStorage[mysql,postgresql,oracle] + pas.plugins.ldap + +[client1] +recipe = + +[instance_base] +resources = ${buildout:directory}/resources + +[zeo] +<= zeoserver_base +recipe = plone.recipe.zeoserver +zeo-address = 8080 + +[instance] +zcml-additional = + + + +event-log-handler = StreamHandler +event-log-args = (sys.stderr,) +access-log-handler = StreamHandler +access-log-args = (sys.stdout,) + +# Requires gcc, thus install it on image build +[mrbob] +recipe = zc.recipe.egg +eggs = + mr.bob + bobtemplates.plone + +[plonesite] +recipe = collective.recipe.plonesite +instance = instance +site-id = Plone +profiles-initial = Products.CMFPlone:dependencies +profiles = + plonetheme.barceloneta:default + plone.app.caching:default + plone.app.contenttypes:plone-content + plone.restapi:default +upgrade-portal = False +upgrade-all-profiles = False +enabled = False + +[versions] +setuptools = +zc.buildout = + +plone.restapi = 8.43.1 +plone.rest = 3.0.0 + +RelStorage = 3.4.5 +argparse = 1.4.0 +bda.cache = 1.3.0 +bobtemplates.plone = 5.2.2 +case-conversion = 2.1.0 +collective.checkdocs = 0.2 +collective.recipe.plonesite = 1.12.0 +cx-Oracle = 8.3.0 +isort = 5.11.5 +mr.bob = 1.0.0 +mysqlclient = 2.1.1 +node = 1.2.1 +node.ext.ldap = 1.2 +node.ext.ugm = 1.1 +odict = 1.9.0 +pas.plugins.ldap = 1.8.2 +passlib = 1.7.4 +perfmetrics = 3.3.0 +plumber = 1.7 +psycopg2 = 2.9.3 +pyasn1 = 0.5.0 +pyasn1-modules = 0.3.0 +python-ldap = 3.4.2 +python-memcached = 1.59 +regex = 2023.6.3 +yafowil = 3.1.0 +yafowil.plone = 4.0.0a5 +yafowil.widget.array = 1.7 +yafowil.widget.dict = 1.8 +yafowil.yaml = 2.0 diff --git a/5.2/5.2.14/alpine/docker-entrypoint.sh b/5.2/5.2.14/alpine/docker-entrypoint.sh new file mode 100755 index 0000000..dcfd834 --- /dev/null +++ b/5.2/5.2.14/alpine/docker-entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e + +COMMANDS="adduser debug fg foreground help kill logreopen logtail reopen_transcript run show status stop wait" +START="console start restart" + +# Fixing permissions for external /data volumes +mkdir -p /data/blobstorage /data/cache /data/filestorage /data/instance /data/log /data/zeoserver +mkdir -p /plone/instance/src +find /data -not -user plone -exec chown plone:plone {} \+ +find /plone -not -user plone -exec chown plone:plone {} \+ + +# Initializing from environment variables +su-exec plone python /docker-initialize.py + +if [ -e "custom.cfg" ]; then + if [ ! -e "bin/develop" ]; then + buildout -c custom.cfg + find /data -not -user plone -exec chown plone:plone {} \+ + find /plone -not -user plone -exec chown plone:plone {} \+ + su-exec plone python /docker-initialize.py + fi +fi + +# ZEO Server +if [[ "$1" == "zeo"* ]]; then + exec su-exec plone bin/$1 fg +fi + +# Plone instance start +if [[ $START == *"$1"* ]]; then + exec su-exec plone bin/instance console +fi + +# Plone instance helpers +if [[ $COMMANDS == *"$1"* ]]; then + exec su-exec plone bin/instance "$@" +fi + +# Custom +exec "$@" diff --git a/5.2/5.2.14/alpine/docker-initialize.py b/5.2/5.2.14/alpine/docker-initialize.py new file mode 100755 index 0000000..cfbf6d2 --- /dev/null +++ b/5.2/5.2.14/alpine/docker-initialize.py @@ -0,0 +1,382 @@ +#!/usr/local/bin/python + +import re +import os + +class Environment(object): + """ Configure container via environment variables + """ + def __init__(self, env=os.environ, + zope_conf="/plone/instance/parts/instance/etc/zope.conf", + custom_conf="/plone/instance/custom.cfg", + zeopack_conf="/plone/instance/bin/zeopack", + zeoserver_conf="/plone/instance/parts/zeoserver/etc/zeo.conf", + cors_conf="/plone/instance/parts/instance/etc/package-includes/999-additional-overrides.zcml" + ): + self.env = env + self.zope_conf = zope_conf + self.custom_conf = custom_conf + self.zeopack_conf = zeopack_conf + self.zeoserver_conf = zeoserver_conf + self.cors_conf = cors_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 "" 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".+", 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( + '', + ' pack-keep-old false\n' + ) + + with open(self.zeoserver_conf, 'w') as cfile: + cfile.write(text) + + def cors(self): + """ Configure CORS Policies + """ + if not [e for e in self.env if e.startswith("CORS_")]: + return + + allow_origin = self.env.get("CORS_ALLOW_ORIGIN", + "http://localhost:3000,http://127.0.0.1:3000") + allow_methods = self.env.get("CORS_ALLOW_METHODS", + "DELETE,GET,OPTIONS,PATCH,POST,PUT") + allow_credentials = self.env.get("CORS_ALLOW_CREDENTIALS", "true") + expose_headers = self.env.get("CORS_EXPOSE_HEADERS", + "Content-Length,X-My-Header") + allow_headers = self.env.get("CORS_ALLOW_HEADERS", + "Accept,Authorization,Content-Type,X-Custom-Header,Lock-Token") + max_age = self.env.get("CORS_MAX_AGE", "3600") + cors_conf = CORS_TEMPLATE.format( + allow_origin=allow_origin, + allow_methods=allow_methods, + allow_credentials=allow_credentials, + expose_headers=expose_headers, + allow_headers=allow_headers, + max_age=max_age + ) + with open(self.cors_conf, "w") as cfile: + cfile.write(cors_conf) + + def relstorage_conf(self): + """ RelStorage configuration from environment variables + """ + if not [e for e in self.env if e.startswith("RELSTORAGE_")]: + return "" + + # Database specific adapter options + # https://relstorage.readthedocs.io/en/latest/supported-databases.html + adapter_options = self.env.get( + "RELSTORAGE_ADAPTER_OPTIONS", + "", + ).strip().split(",") + + settings = { + # General Settings + "name": self.env.get("RELSTORAGE_NAME"), + "read-only": self.env.get("RELSTORAGE_READ_ONLY"), + "keep-history": self.env.get("RELSTORAGE_KEEP_HISTORY"), + "commit-lock-timeout": self.env.get( + "RELSTORAGE_COMMIT_LOCK_TIMEOUT", + ), + "commit-lock-id": self.env.get("RELSTORAGE_COMMIT_LOCK_ID"), + "create-schema": self.env.get("RELSTORAGE_CREATE_SCHEMA"), + + # Blobs + "blob-dir": self.env.get("RELSTORAGE_BLOB_DIR", + "/plone/instance/var/blobstorage"), + "shared-blob-dir": self.env.get("RELSTORAGE_SHARED_BLOB_DIR"), + "blob-cache-size": self.env.get("RELSTORAGE_BLOB_CACHE_SIZE"), + "blob-cache-size-check": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK", + ), + "blob-cache-size-check-external": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK_EXTERNAL", + ), + "blob-chunk-size": self.env.get("RELSTORAGE_BLOB_CHUNK_SIZE"), + + # Replication + "replica-conf": self.env.get("RELSTORAGE_REPLICA_CONF"), + "ro-replica-conf": self.env.get("RELSTORAGE_RO_REPLICA_CONF"), + "replica-timeout": self.env.get("RELSTORAGE_REPLICA_TIMEOUT"), + "revert-when-stale": self.env.get("RELSTORAGE_REVERT_WHEN_STALE"), + + # GC and Packing + "pack-gc": self.env.get("RELSTORAGE_PACK_GC"), + "pack-prepack-only": self.env.get("RELSTORAGE_PACK_PREPACK_ONLY"), + "pack-skip-prepack": self.env.get("RELSTORAGE_PACK_SKIP_PREPACK"), + "pack-batch-timeout": self.env.get("RELSTORAGE_PACK_BATCH_TIMEOUT"), + "pack-commit-busy-delay": self.env.get( + "RELSTORAGE_PACK_COMMIT_BUSY_DELAY", + ), + + # Database Caching + "cache-prefix": self.env.get("RELSTORAGE_CACHE_PREFIX"), + + # Local Caching + "cache-local-mb": self.env.get("RELSTORAGE_CACHE_LOCAL_MB"), + "cache-local-object-max": self.env.get( + "RELSTORAGE_CACHE_LOCAL_OBJECT_MAX", + ), + "cache-local-compression": self.env.get( + "RELSTORAGE_CACHE_LOCAL_COMPRESSION", + ), + "cache-delta-size-limit": self.env.get( + "RELSTORAGE_CACHE_DELTA_SIZE_LIMIT", + ), + + # Persistent Local Caching + "cache-local-dir": self.env.get("RELSTORAGE_CACHE_LOCAL_DIR"), + + # Deprecated Options + # ... + } + + return "\n ".join(adapter_options + [ + "{} {}".format(x[0], x[1].strip()) for x in settings.items() if x[1] + ]) + + def buildout(self): + """ Buildout from environment variables + """ + # Already configured + if os.path.exists(self.custom_conf): + return + + findlinks = self.env.get("FIND_LINKS", "").strip().split() + + eggs = self.env.get("PLONE_ADDONS", + self.env.get("ADDONS", "")).strip().split() + + zcml = self.env.get("PLONE_ZCML", + self.env.get("ZCML", "")).strip().split() + + develop = self.env.get("PLONE_DEVELOP", + self.env.get("DEVELOP", "")).strip().split() + + site = self.env.get("PLONE_SITE", + self.env.get("SITE", "")).strip() + + profiles = self.env.get("PLONE_PROFILES", + self.env.get("PROFILES", "")).strip().split() + + versions = self.env.get("PLONE_VERSIONS", + self.env.get("VERSIONS", "")).strip().split() + + file_logging = self.env.get("FILE_LOGGING") + + sources = self.env.get("SOURCES", "").strip() + sources = sources and [x.strip() for x in sources.split(",")] + + relstorage = self.relstorage_conf() + + buildout_extends = ((develop or sources) + and ["develop.cfg"] or ["buildout.cfg"]) + extra_extends = self.env.get("BUILDOUT_EXTENDS", "").strip().split() + buildout_extends.extend(extra_extends) + + # If profiles not provided. Install ADDONS :default profiles + if not profiles: + for egg in eggs: + base = egg.split("=")[0] + profiles.append("%s:default" % base) + + enabled = bool(site) + if not ( + eggs or zcml or relstorage or develop or enabled or extra_extends or file_logging + ): + return + + buildout = BUILDOUT_TEMPLATE.format( + buildout_extends="\n\t".join(buildout_extends), + findlinks="\n\t".join(findlinks), + eggs="\n\t".join(eggs), + zcml="\n\t".join(zcml), + develop="\n\t".join(develop), + profiles="\n\t".join(profiles), + versions="\n".join(versions), + site=site or "Plone", + enabled=enabled, + ) + + # If we need to create a plonesite and we have a zeo setup + # configure collective.recipe.plonesite properly + server = self.env.get("ZEO_ADDRESS", None) + shared_blob_dir=self.env.get("ZEO_SHARED_BLOB_DIR", "off") + + if server: + buildout += ZEO_INSTANCE_TEMPLATE.format(zeoaddress=server, + shared_blob_dir=shared_blob_dir) + + # Add RelStorage configuration if needed + if relstorage: + buildout += RELSTORAGE_TEMPLATE.format(relstorage=relstorage) + + # Add file logging configuration if needed + if file_logging: + buildout += FILE_LOGGING_INSTANCE + + # Add sources configuration if needed + if sources: + buildout += SOURCES_TEMPLATE.format(sources="\n".join(sources)) + + with open(self.custom_conf, 'w') as cfile: + cfile.write(buildout) + + def setup(self, **kwargs): + self.buildout() + self.cors() + self.zeoclient() + self.zeopack() + self.zeoserver() + + __call__ = setup + +ZEO_TEMPLATE = """ + + 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 /plone/instance/parts/instance/var + cache-size {zeo_client_cache_size} + +""".strip() + +CORS_TEMPLATE = """ + + + + +""" + +BUILDOUT_TEMPLATE = """ +[buildout] +extends = {buildout_extends} +find-links += {findlinks} +develop += {develop} +eggs += {eggs} +zcml += {zcml} + +[plonesite] +enabled = {enabled} +site-id = {site} +profiles += {profiles} + +[versions] +{versions} +""" + +ZEO_INSTANCE_TEMPLATE = """ + +[instance] +zeo-client = true +zeo-address = {zeoaddress} +shared-blob = {shared_blob_dir} +http-fast-listen = off +""" + +RELSTORAGE_TEMPLATE = """ + +[instance] +rel-storage = + {relstorage} +""" + +SOURCES_TEMPLATE = """ + +[sources] +{sources} +""" + +FILE_LOGGING_INSTANCE = """ + +[instance] +event-log-handler = FileHandler +event-log-args = ('${buildout:var-dir}/log/instance.log', 'a') +access-log-handler = FileHandler +access-log-args = ('${buildout:var-dir}/log/instance-access.log', 'a') +""" + +def initialize(): + """ Configure Plone instance as ZEO Client + """ + environment = Environment() + environment.setup() + +if __name__ == "__main__": + initialize() diff --git a/5.2/5.2.14/debian/Dockerfile b/5.2/5.2.14/debian/Dockerfile new file mode 100644 index 0000000..41f437e --- /dev/null +++ b/5.2/5.2.14/debian/Dockerfile @@ -0,0 +1,50 @@ +FROM python:3.8-slim-bullseye + +ENV PIP=22.2.2 \ + ZC_BUILDOUT=3.0.1 \ + SETUPTOOLS=65.7.0 \ + WHEEL=0.38.4 \ + PLONE_MAJOR=5.2 \ + PLONE_VERSION=5.2.13 \ + PLONE_VERSION_RELEASE=Plone-5.2.13-UnifiedInstaller-1.0 \ + PLONE_MD5=12c037fae9413385149e8677f8457b84 + +RUN useradd --system -m -d /plone -U -u 500 plone \ + && mkdir -p /plone/instance/ /data/filestorage /data/blobstorage + +COPY buildout.cfg /plone/instance/ + +RUN buildDeps="default-libmysqlclient-dev dpkg-dev gcc libbz2-dev libc6-dev libffi-dev libjpeg62-turbo-dev libldap2-dev libopenjp2-7-dev libpcre3-dev libpq-dev libsasl2-dev libssl-dev libtiff5-dev libxml2-dev libxslt1-dev wget zlib1g-dev" \ + && runDeps="default-libmysqlclient-dev git gosu libjpeg62 libopenjp2-7 libpq5 libtiff5 libxml2 libxslt1.1 lynx netcat poppler-utils rsync wv" \ + && apt-get update \ + && apt-get install -y --no-install-recommends $buildDeps \ + && wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/$PLONE_VERSION_RELEASE.tgz \ + && echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \ + && tar -xzf Plone.tgz \ + && cp -rv ./$PLONE_VERSION_RELEASE/base_skeleton/* /plone/instance/ \ + && cp -v ./$PLONE_VERSION_RELEASE/buildout_templates/buildout.cfg /plone/instance/buildout-base.cfg \ + && pip install pip==$PIP setuptools==$SETUPTOOLS zc.buildout==$ZC_BUILDOUT wheel==$WHEEL \ + && cd /plone/instance \ + && buildout \ + && ln -s /data/filestorage/ /plone/instance/var/filestorage \ + && ln -s /data/blobstorage /plone/instance/var/blobstorage \ + && find /data -not -user plone -exec chown plone:plone {} \+ \ + && find /plone -not -user plone -exec chown plone:plone {} \+ \ + && rm -rf /Plone* \ + && apt-get purge -y --auto-remove $buildDeps \ + && apt-get install -y --no-install-recommends $runDeps \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /plone/buildout-cache/downloads/* + +VOLUME /data + +COPY docker-initialize.py docker-entrypoint.sh / + +EXPOSE 8080 +WORKDIR /plone/instance + +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"] diff --git a/5.2/5.2.14/debian/buildout.cfg b/5.2/5.2.14/debian/buildout.cfg new file mode 100644 index 0000000..02ca654 --- /dev/null +++ b/5.2/5.2.14/debian/buildout.cfg @@ -0,0 +1,106 @@ +[buildout] +extends = + buildout-base.cfg + +index = https://pypi.org/simple/ + +extensions = +effective-user = plone +buildout-user = plone +var-dir=/data +user=admin:admin +parts += + zeo + mrbob + plonesite + +eggs += + RelStorage[mysql,postgresql,oracle] + pas.plugins.ldap + +[client1] +recipe = + +[instance_base] +resources = ${buildout:directory}/resources + +[zeo] +<= zeoserver_base +recipe = plone.recipe.zeoserver +zeo-address = 8080 + +[instance] +zcml-additional = + + + +event-log-handler = StreamHandler +event-log-args = (sys.stderr,) +access-log-handler = StreamHandler +access-log-args = (sys.stdout,) + +# Requires gcc, thus install it on image build +[mrbob] +recipe = zc.recipe.egg +eggs = + mr.bob + bobtemplates.plone + +[plonesite] +recipe = collective.recipe.plonesite +instance = instance +site-id = Plone +profiles-initial = Products.CMFPlone:dependencies +profiles = + plonetheme.barceloneta:default + plone.app.caching:default + plone.app.contenttypes:plone-content + plone.restapi:default +upgrade-portal = False +upgrade-all-profiles = False +enabled = False + +[versions] +setuptools = +zc.buildout = + +plone.restapi = 8.43.1 +plone.rest = 3.0.0 + +RelStorage = 3.4.5 +argparse = 1.4.0 +bda.cache = 1.3.0 +bobtemplates.plone = 5.2.2 +case-conversion = 2.1.0 +collective.checkdocs = 0.2 +collective.recipe.plonesite = 1.12.0 +cx-Oracle = 8.3.0 +isort = 5.11.5 +mr.bob = 1.0.0 +mysqlclient = 2.1.1 +node = 1.2.1 +node.ext.ldap = 1.2 +node.ext.ugm = 1.1 +odict = 1.9.0 +pas.plugins.ldap = 1.8.2 +passlib = 1.7.4 +perfmetrics = 3.3.0 +plumber = 1.7 +psycopg2 = 2.9.3 +pyasn1 = 0.5.0 +pyasn1-modules = 0.3.0 +python-ldap = 3.4.2 +python-memcached = 1.59 +regex = 2023.6.3 +yafowil = 3.1.0 +yafowil.plone = 4.0.0a5 +yafowil.widget.array = 1.7 +yafowil.widget.dict = 1.8 +yafowil.yaml = 2.0 diff --git a/5.2/5.2.14/debian/docker-entrypoint.sh b/5.2/5.2.14/debian/docker-entrypoint.sh new file mode 100755 index 0000000..ecf7f76 --- /dev/null +++ b/5.2/5.2.14/debian/docker-entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e + +COMMANDS="adduser debug fg foreground help kill logreopen logtail reopen_transcript run show status stop wait" +START="console start restart" + +# Fixing permissions for external /data volumes +mkdir -p /data/blobstorage /data/cache /data/filestorage /data/instance /data/log /data/zeoserver +mkdir -p /plone/instance/src +find /data -not -user plone -exec chown plone:plone {} \+ +find /plone -not -user plone -exec chown plone:plone {} \+ + +# Initializing from environment variables +gosu plone python /docker-initialize.py + +if [ -e "custom.cfg" ]; then + if [ ! -e "bin/develop" ]; then + buildout -c custom.cfg + find /data -not -user plone -exec chown plone:plone {} \+ + find /plone -not -user plone -exec chown plone:plone {} \+ + gosu plone python /docker-initialize.py + fi +fi + +# ZEO Server +if [[ "$1" == "zeo"* ]]; then + exec gosu plone bin/$1 fg +fi + +# Plone instance start +if [[ $START == *"$1"* ]]; then + exec gosu plone bin/instance console +fi + +# Plone instance helpers +if [[ $COMMANDS == *"$1"* ]]; then + exec gosu plone bin/instance "$@" +fi + +# Custom +exec "$@" diff --git a/5.2/5.2.14/debian/docker-initialize.py b/5.2/5.2.14/debian/docker-initialize.py new file mode 100755 index 0000000..cfbf6d2 --- /dev/null +++ b/5.2/5.2.14/debian/docker-initialize.py @@ -0,0 +1,382 @@ +#!/usr/local/bin/python + +import re +import os + +class Environment(object): + """ Configure container via environment variables + """ + def __init__(self, env=os.environ, + zope_conf="/plone/instance/parts/instance/etc/zope.conf", + custom_conf="/plone/instance/custom.cfg", + zeopack_conf="/plone/instance/bin/zeopack", + zeoserver_conf="/plone/instance/parts/zeoserver/etc/zeo.conf", + cors_conf="/plone/instance/parts/instance/etc/package-includes/999-additional-overrides.zcml" + ): + self.env = env + self.zope_conf = zope_conf + self.custom_conf = custom_conf + self.zeopack_conf = zeopack_conf + self.zeoserver_conf = zeoserver_conf + self.cors_conf = cors_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 "" 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".+", 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( + '', + ' pack-keep-old false\n' + ) + + with open(self.zeoserver_conf, 'w') as cfile: + cfile.write(text) + + def cors(self): + """ Configure CORS Policies + """ + if not [e for e in self.env if e.startswith("CORS_")]: + return + + allow_origin = self.env.get("CORS_ALLOW_ORIGIN", + "http://localhost:3000,http://127.0.0.1:3000") + allow_methods = self.env.get("CORS_ALLOW_METHODS", + "DELETE,GET,OPTIONS,PATCH,POST,PUT") + allow_credentials = self.env.get("CORS_ALLOW_CREDENTIALS", "true") + expose_headers = self.env.get("CORS_EXPOSE_HEADERS", + "Content-Length,X-My-Header") + allow_headers = self.env.get("CORS_ALLOW_HEADERS", + "Accept,Authorization,Content-Type,X-Custom-Header,Lock-Token") + max_age = self.env.get("CORS_MAX_AGE", "3600") + cors_conf = CORS_TEMPLATE.format( + allow_origin=allow_origin, + allow_methods=allow_methods, + allow_credentials=allow_credentials, + expose_headers=expose_headers, + allow_headers=allow_headers, + max_age=max_age + ) + with open(self.cors_conf, "w") as cfile: + cfile.write(cors_conf) + + def relstorage_conf(self): + """ RelStorage configuration from environment variables + """ + if not [e for e in self.env if e.startswith("RELSTORAGE_")]: + return "" + + # Database specific adapter options + # https://relstorage.readthedocs.io/en/latest/supported-databases.html + adapter_options = self.env.get( + "RELSTORAGE_ADAPTER_OPTIONS", + "", + ).strip().split(",") + + settings = { + # General Settings + "name": self.env.get("RELSTORAGE_NAME"), + "read-only": self.env.get("RELSTORAGE_READ_ONLY"), + "keep-history": self.env.get("RELSTORAGE_KEEP_HISTORY"), + "commit-lock-timeout": self.env.get( + "RELSTORAGE_COMMIT_LOCK_TIMEOUT", + ), + "commit-lock-id": self.env.get("RELSTORAGE_COMMIT_LOCK_ID"), + "create-schema": self.env.get("RELSTORAGE_CREATE_SCHEMA"), + + # Blobs + "blob-dir": self.env.get("RELSTORAGE_BLOB_DIR", + "/plone/instance/var/blobstorage"), + "shared-blob-dir": self.env.get("RELSTORAGE_SHARED_BLOB_DIR"), + "blob-cache-size": self.env.get("RELSTORAGE_BLOB_CACHE_SIZE"), + "blob-cache-size-check": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK", + ), + "blob-cache-size-check-external": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK_EXTERNAL", + ), + "blob-chunk-size": self.env.get("RELSTORAGE_BLOB_CHUNK_SIZE"), + + # Replication + "replica-conf": self.env.get("RELSTORAGE_REPLICA_CONF"), + "ro-replica-conf": self.env.get("RELSTORAGE_RO_REPLICA_CONF"), + "replica-timeout": self.env.get("RELSTORAGE_REPLICA_TIMEOUT"), + "revert-when-stale": self.env.get("RELSTORAGE_REVERT_WHEN_STALE"), + + # GC and Packing + "pack-gc": self.env.get("RELSTORAGE_PACK_GC"), + "pack-prepack-only": self.env.get("RELSTORAGE_PACK_PREPACK_ONLY"), + "pack-skip-prepack": self.env.get("RELSTORAGE_PACK_SKIP_PREPACK"), + "pack-batch-timeout": self.env.get("RELSTORAGE_PACK_BATCH_TIMEOUT"), + "pack-commit-busy-delay": self.env.get( + "RELSTORAGE_PACK_COMMIT_BUSY_DELAY", + ), + + # Database Caching + "cache-prefix": self.env.get("RELSTORAGE_CACHE_PREFIX"), + + # Local Caching + "cache-local-mb": self.env.get("RELSTORAGE_CACHE_LOCAL_MB"), + "cache-local-object-max": self.env.get( + "RELSTORAGE_CACHE_LOCAL_OBJECT_MAX", + ), + "cache-local-compression": self.env.get( + "RELSTORAGE_CACHE_LOCAL_COMPRESSION", + ), + "cache-delta-size-limit": self.env.get( + "RELSTORAGE_CACHE_DELTA_SIZE_LIMIT", + ), + + # Persistent Local Caching + "cache-local-dir": self.env.get("RELSTORAGE_CACHE_LOCAL_DIR"), + + # Deprecated Options + # ... + } + + return "\n ".join(adapter_options + [ + "{} {}".format(x[0], x[1].strip()) for x in settings.items() if x[1] + ]) + + def buildout(self): + """ Buildout from environment variables + """ + # Already configured + if os.path.exists(self.custom_conf): + return + + findlinks = self.env.get("FIND_LINKS", "").strip().split() + + eggs = self.env.get("PLONE_ADDONS", + self.env.get("ADDONS", "")).strip().split() + + zcml = self.env.get("PLONE_ZCML", + self.env.get("ZCML", "")).strip().split() + + develop = self.env.get("PLONE_DEVELOP", + self.env.get("DEVELOP", "")).strip().split() + + site = self.env.get("PLONE_SITE", + self.env.get("SITE", "")).strip() + + profiles = self.env.get("PLONE_PROFILES", + self.env.get("PROFILES", "")).strip().split() + + versions = self.env.get("PLONE_VERSIONS", + self.env.get("VERSIONS", "")).strip().split() + + file_logging = self.env.get("FILE_LOGGING") + + sources = self.env.get("SOURCES", "").strip() + sources = sources and [x.strip() for x in sources.split(",")] + + relstorage = self.relstorage_conf() + + buildout_extends = ((develop or sources) + and ["develop.cfg"] or ["buildout.cfg"]) + extra_extends = self.env.get("BUILDOUT_EXTENDS", "").strip().split() + buildout_extends.extend(extra_extends) + + # If profiles not provided. Install ADDONS :default profiles + if not profiles: + for egg in eggs: + base = egg.split("=")[0] + profiles.append("%s:default" % base) + + enabled = bool(site) + if not ( + eggs or zcml or relstorage or develop or enabled or extra_extends or file_logging + ): + return + + buildout = BUILDOUT_TEMPLATE.format( + buildout_extends="\n\t".join(buildout_extends), + findlinks="\n\t".join(findlinks), + eggs="\n\t".join(eggs), + zcml="\n\t".join(zcml), + develop="\n\t".join(develop), + profiles="\n\t".join(profiles), + versions="\n".join(versions), + site=site or "Plone", + enabled=enabled, + ) + + # If we need to create a plonesite and we have a zeo setup + # configure collective.recipe.plonesite properly + server = self.env.get("ZEO_ADDRESS", None) + shared_blob_dir=self.env.get("ZEO_SHARED_BLOB_DIR", "off") + + if server: + buildout += ZEO_INSTANCE_TEMPLATE.format(zeoaddress=server, + shared_blob_dir=shared_blob_dir) + + # Add RelStorage configuration if needed + if relstorage: + buildout += RELSTORAGE_TEMPLATE.format(relstorage=relstorage) + + # Add file logging configuration if needed + if file_logging: + buildout += FILE_LOGGING_INSTANCE + + # Add sources configuration if needed + if sources: + buildout += SOURCES_TEMPLATE.format(sources="\n".join(sources)) + + with open(self.custom_conf, 'w') as cfile: + cfile.write(buildout) + + def setup(self, **kwargs): + self.buildout() + self.cors() + self.zeoclient() + self.zeopack() + self.zeoserver() + + __call__ = setup + +ZEO_TEMPLATE = """ + + 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 /plone/instance/parts/instance/var + cache-size {zeo_client_cache_size} + +""".strip() + +CORS_TEMPLATE = """ + + + + +""" + +BUILDOUT_TEMPLATE = """ +[buildout] +extends = {buildout_extends} +find-links += {findlinks} +develop += {develop} +eggs += {eggs} +zcml += {zcml} + +[plonesite] +enabled = {enabled} +site-id = {site} +profiles += {profiles} + +[versions] +{versions} +""" + +ZEO_INSTANCE_TEMPLATE = """ + +[instance] +zeo-client = true +zeo-address = {zeoaddress} +shared-blob = {shared_blob_dir} +http-fast-listen = off +""" + +RELSTORAGE_TEMPLATE = """ + +[instance] +rel-storage = + {relstorage} +""" + +SOURCES_TEMPLATE = """ + +[sources] +{sources} +""" + +FILE_LOGGING_INSTANCE = """ + +[instance] +event-log-handler = FileHandler +event-log-args = ('${buildout:var-dir}/log/instance.log', 'a') +access-log-handler = FileHandler +access-log-args = ('${buildout:var-dir}/log/instance-access.log', 'a') +""" + +def initialize(): + """ Configure Plone instance as ZEO Client + """ + environment = Environment() + environment.setup() + +if __name__ == "__main__": + initialize() diff --git a/5.2/5.2.14/python2/Dockerfile b/5.2/5.2.14/python2/Dockerfile new file mode 100644 index 0000000..0f87b18 --- /dev/null +++ b/5.2/5.2.14/python2/Dockerfile @@ -0,0 +1,50 @@ +FROM python:2.7-slim-buster + +ENV PIP=20.3.4 \ + ZC_BUILDOUT=2.13.8 \ + SETUPTOOLS=44.1.1 \ + WHEEL=0.37.1 \ + PLONE_MAJOR=5.2 \ + PLONE_VERSION=5.2.13 \ + PLONE_VERSION_RELEASE=Plone-5.2.13-UnifiedInstaller-1.0 \ + PLONE_MD5=12c037fae9413385149e8677f8457b84 + +RUN useradd --system -m -d /plone -U -u 500 plone \ + && mkdir -p /plone/instance/ /data/filestorage /data/blobstorage + +COPY buildout.cfg /plone/instance/ + +RUN buildDeps="default-libmysqlclient-dev dpkg-dev gcc libbz2-dev libc6-dev libffi-dev libjpeg62-turbo-dev libldap2-dev libopenjp2-7-dev libpcre3-dev libpq-dev libsasl2-dev libssl-dev libtiff5-dev libxml2-dev libxslt1-dev wget zlib1g-dev" \ + && runDeps="default-libmysqlclient-dev git gosu libjpeg62 libopenjp2-7 libpq5 libtiff5 libxml2 libxslt1.1 lynx netcat poppler-utils rsync wv" \ + && apt-get update \ + && apt-get install -y --no-install-recommends $buildDeps \ + && wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/$PLONE_VERSION_RELEASE.tgz \ + && echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \ + && tar -xzf Plone.tgz \ + && cp -rv ./$PLONE_VERSION_RELEASE/base_skeleton/* /plone/instance/ \ + && cp -v ./$PLONE_VERSION_RELEASE/buildout_templates/buildout.cfg /plone/instance/buildout-base.cfg \ + && pip install pip==$PIP setuptools==$SETUPTOOLS zc.buildout==$ZC_BUILDOUT wheel==$WHEEL \ + && cd /plone/instance \ + && buildout \ + && ln -s /data/filestorage/ /plone/instance/var/filestorage \ + && ln -s /data/blobstorage /plone/instance/var/blobstorage \ + && find /data -not -user plone -exec chown plone:plone {} \+ \ + && find /plone -not -user plone -exec chown plone:plone {} \+ \ + && rm -rf /Plone* \ + && apt-get purge -y --auto-remove $buildDeps \ + && apt-get install -y --no-install-recommends $runDeps \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /plone/buildout-cache/downloads/* + +VOLUME /data + +COPY docker-initialize.py docker-entrypoint.sh / + +EXPOSE 8080 +WORKDIR /plone/instance + +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"] diff --git a/5.2/5.2.14/python2/buildout.cfg b/5.2/5.2.14/python2/buildout.cfg new file mode 100644 index 0000000..6f0312d --- /dev/null +++ b/5.2/5.2.14/python2/buildout.cfg @@ -0,0 +1,104 @@ +[buildout] +extends = + buildout-base.cfg + +extensions = +effective-user = plone +buildout-user = plone +var-dir=/data +user=admin:admin +parts += + zeo + mrbob + plonesite + +eggs += + RelStorage[mysql,postgresql,oracle] + pas.plugins.ldap + +[client1] +recipe = + +[instance_base] +resources = ${buildout:directory}/resources + +[zeo] +<= zeoserver_base +recipe = plone.recipe.zeoserver +zeo-address = 8080 + +[instance] +zcml-additional = + + + +event-log-handler = StreamHandler +event-log-args = (sys.stderr,) +access-log-handler = StreamHandler +access-log-args = (sys.stdout,) + +# Requires gcc, thus install it on image build +[mrbob] +recipe = zc.recipe.egg +eggs = + mr.bob + bobtemplates.plone + +[plonesite] +recipe = collective.recipe.plonesite +instance = instance +site-id = Plone +profiles-initial = Products.CMFPlone:dependencies +profiles = + plonetheme.barceloneta:default + plone.app.caching:default + plone.app.contenttypes:plone-content + plone.restapi:default +upgrade-portal = False +upgrade-all-profiles = False +enabled = False + +[versions] +setuptools = +zc.buildout = + +plone.restapi = 7.8.2 + +RelStorage = 3.4.0 +argparse = 1.4.0 +bda.cache = 1.3.0 +bobtemplates.plone = 5.2.0 +case-conversion = 2.1.0 +collective.checkdocs = 0.2 +collective.recipe.plonesite = 1.12.0 +cx-Oracle = 7.3.0 +importlib-resources = 3.3.1 +isort = 5.7.0 +mr.bob = 0.1.2 +mysqlclient = 1.4.6 +node = 1.2.1 +node.ext.ldap = 1.2 +node.ext.ugm = 1.1 +odict = 1.9.0 +pas.plugins.ldap = 1.8.2 +passlib = 1.7.4 +perfmetrics = 3.3.0 +plumber = 1.6 +psycopg2 = 2.8.6 +pyasn1 = 0.5.0 +pyasn1-modules = 0.3.0 +python-ldap = 3.3.1 +python-memcached = 1.59 +regex = 2020.7.14 +yafowil = 2.3.3 +yafowil.plone = 4.0.0a5 +yafowil.widget.array = 1.7 +yafowil.widget.dict = 1.8 +yafowil.yaml = 1.3.1 diff --git a/5.2/5.2.14/python2/docker-entrypoint.sh b/5.2/5.2.14/python2/docker-entrypoint.sh new file mode 100755 index 0000000..ecf7f76 --- /dev/null +++ b/5.2/5.2.14/python2/docker-entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e + +COMMANDS="adduser debug fg foreground help kill logreopen logtail reopen_transcript run show status stop wait" +START="console start restart" + +# Fixing permissions for external /data volumes +mkdir -p /data/blobstorage /data/cache /data/filestorage /data/instance /data/log /data/zeoserver +mkdir -p /plone/instance/src +find /data -not -user plone -exec chown plone:plone {} \+ +find /plone -not -user plone -exec chown plone:plone {} \+ + +# Initializing from environment variables +gosu plone python /docker-initialize.py + +if [ -e "custom.cfg" ]; then + if [ ! -e "bin/develop" ]; then + buildout -c custom.cfg + find /data -not -user plone -exec chown plone:plone {} \+ + find /plone -not -user plone -exec chown plone:plone {} \+ + gosu plone python /docker-initialize.py + fi +fi + +# ZEO Server +if [[ "$1" == "zeo"* ]]; then + exec gosu plone bin/$1 fg +fi + +# Plone instance start +if [[ $START == *"$1"* ]]; then + exec gosu plone bin/instance console +fi + +# Plone instance helpers +if [[ $COMMANDS == *"$1"* ]]; then + exec gosu plone bin/instance "$@" +fi + +# Custom +exec "$@" diff --git a/5.2/5.2.14/python2/docker-initialize.py b/5.2/5.2.14/python2/docker-initialize.py new file mode 100755 index 0000000..cfbf6d2 --- /dev/null +++ b/5.2/5.2.14/python2/docker-initialize.py @@ -0,0 +1,382 @@ +#!/usr/local/bin/python + +import re +import os + +class Environment(object): + """ Configure container via environment variables + """ + def __init__(self, env=os.environ, + zope_conf="/plone/instance/parts/instance/etc/zope.conf", + custom_conf="/plone/instance/custom.cfg", + zeopack_conf="/plone/instance/bin/zeopack", + zeoserver_conf="/plone/instance/parts/zeoserver/etc/zeo.conf", + cors_conf="/plone/instance/parts/instance/etc/package-includes/999-additional-overrides.zcml" + ): + self.env = env + self.zope_conf = zope_conf + self.custom_conf = custom_conf + self.zeopack_conf = zeopack_conf + self.zeoserver_conf = zeoserver_conf + self.cors_conf = cors_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 "" 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".+", 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( + '', + ' pack-keep-old false\n' + ) + + with open(self.zeoserver_conf, 'w') as cfile: + cfile.write(text) + + def cors(self): + """ Configure CORS Policies + """ + if not [e for e in self.env if e.startswith("CORS_")]: + return + + allow_origin = self.env.get("CORS_ALLOW_ORIGIN", + "http://localhost:3000,http://127.0.0.1:3000") + allow_methods = self.env.get("CORS_ALLOW_METHODS", + "DELETE,GET,OPTIONS,PATCH,POST,PUT") + allow_credentials = self.env.get("CORS_ALLOW_CREDENTIALS", "true") + expose_headers = self.env.get("CORS_EXPOSE_HEADERS", + "Content-Length,X-My-Header") + allow_headers = self.env.get("CORS_ALLOW_HEADERS", + "Accept,Authorization,Content-Type,X-Custom-Header,Lock-Token") + max_age = self.env.get("CORS_MAX_AGE", "3600") + cors_conf = CORS_TEMPLATE.format( + allow_origin=allow_origin, + allow_methods=allow_methods, + allow_credentials=allow_credentials, + expose_headers=expose_headers, + allow_headers=allow_headers, + max_age=max_age + ) + with open(self.cors_conf, "w") as cfile: + cfile.write(cors_conf) + + def relstorage_conf(self): + """ RelStorage configuration from environment variables + """ + if not [e for e in self.env if e.startswith("RELSTORAGE_")]: + return "" + + # Database specific adapter options + # https://relstorage.readthedocs.io/en/latest/supported-databases.html + adapter_options = self.env.get( + "RELSTORAGE_ADAPTER_OPTIONS", + "", + ).strip().split(",") + + settings = { + # General Settings + "name": self.env.get("RELSTORAGE_NAME"), + "read-only": self.env.get("RELSTORAGE_READ_ONLY"), + "keep-history": self.env.get("RELSTORAGE_KEEP_HISTORY"), + "commit-lock-timeout": self.env.get( + "RELSTORAGE_COMMIT_LOCK_TIMEOUT", + ), + "commit-lock-id": self.env.get("RELSTORAGE_COMMIT_LOCK_ID"), + "create-schema": self.env.get("RELSTORAGE_CREATE_SCHEMA"), + + # Blobs + "blob-dir": self.env.get("RELSTORAGE_BLOB_DIR", + "/plone/instance/var/blobstorage"), + "shared-blob-dir": self.env.get("RELSTORAGE_SHARED_BLOB_DIR"), + "blob-cache-size": self.env.get("RELSTORAGE_BLOB_CACHE_SIZE"), + "blob-cache-size-check": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK", + ), + "blob-cache-size-check-external": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK_EXTERNAL", + ), + "blob-chunk-size": self.env.get("RELSTORAGE_BLOB_CHUNK_SIZE"), + + # Replication + "replica-conf": self.env.get("RELSTORAGE_REPLICA_CONF"), + "ro-replica-conf": self.env.get("RELSTORAGE_RO_REPLICA_CONF"), + "replica-timeout": self.env.get("RELSTORAGE_REPLICA_TIMEOUT"), + "revert-when-stale": self.env.get("RELSTORAGE_REVERT_WHEN_STALE"), + + # GC and Packing + "pack-gc": self.env.get("RELSTORAGE_PACK_GC"), + "pack-prepack-only": self.env.get("RELSTORAGE_PACK_PREPACK_ONLY"), + "pack-skip-prepack": self.env.get("RELSTORAGE_PACK_SKIP_PREPACK"), + "pack-batch-timeout": self.env.get("RELSTORAGE_PACK_BATCH_TIMEOUT"), + "pack-commit-busy-delay": self.env.get( + "RELSTORAGE_PACK_COMMIT_BUSY_DELAY", + ), + + # Database Caching + "cache-prefix": self.env.get("RELSTORAGE_CACHE_PREFIX"), + + # Local Caching + "cache-local-mb": self.env.get("RELSTORAGE_CACHE_LOCAL_MB"), + "cache-local-object-max": self.env.get( + "RELSTORAGE_CACHE_LOCAL_OBJECT_MAX", + ), + "cache-local-compression": self.env.get( + "RELSTORAGE_CACHE_LOCAL_COMPRESSION", + ), + "cache-delta-size-limit": self.env.get( + "RELSTORAGE_CACHE_DELTA_SIZE_LIMIT", + ), + + # Persistent Local Caching + "cache-local-dir": self.env.get("RELSTORAGE_CACHE_LOCAL_DIR"), + + # Deprecated Options + # ... + } + + return "\n ".join(adapter_options + [ + "{} {}".format(x[0], x[1].strip()) for x in settings.items() if x[1] + ]) + + def buildout(self): + """ Buildout from environment variables + """ + # Already configured + if os.path.exists(self.custom_conf): + return + + findlinks = self.env.get("FIND_LINKS", "").strip().split() + + eggs = self.env.get("PLONE_ADDONS", + self.env.get("ADDONS", "")).strip().split() + + zcml = self.env.get("PLONE_ZCML", + self.env.get("ZCML", "")).strip().split() + + develop = self.env.get("PLONE_DEVELOP", + self.env.get("DEVELOP", "")).strip().split() + + site = self.env.get("PLONE_SITE", + self.env.get("SITE", "")).strip() + + profiles = self.env.get("PLONE_PROFILES", + self.env.get("PROFILES", "")).strip().split() + + versions = self.env.get("PLONE_VERSIONS", + self.env.get("VERSIONS", "")).strip().split() + + file_logging = self.env.get("FILE_LOGGING") + + sources = self.env.get("SOURCES", "").strip() + sources = sources and [x.strip() for x in sources.split(",")] + + relstorage = self.relstorage_conf() + + buildout_extends = ((develop or sources) + and ["develop.cfg"] or ["buildout.cfg"]) + extra_extends = self.env.get("BUILDOUT_EXTENDS", "").strip().split() + buildout_extends.extend(extra_extends) + + # If profiles not provided. Install ADDONS :default profiles + if not profiles: + for egg in eggs: + base = egg.split("=")[0] + profiles.append("%s:default" % base) + + enabled = bool(site) + if not ( + eggs or zcml or relstorage or develop or enabled or extra_extends or file_logging + ): + return + + buildout = BUILDOUT_TEMPLATE.format( + buildout_extends="\n\t".join(buildout_extends), + findlinks="\n\t".join(findlinks), + eggs="\n\t".join(eggs), + zcml="\n\t".join(zcml), + develop="\n\t".join(develop), + profiles="\n\t".join(profiles), + versions="\n".join(versions), + site=site or "Plone", + enabled=enabled, + ) + + # If we need to create a plonesite and we have a zeo setup + # configure collective.recipe.plonesite properly + server = self.env.get("ZEO_ADDRESS", None) + shared_blob_dir=self.env.get("ZEO_SHARED_BLOB_DIR", "off") + + if server: + buildout += ZEO_INSTANCE_TEMPLATE.format(zeoaddress=server, + shared_blob_dir=shared_blob_dir) + + # Add RelStorage configuration if needed + if relstorage: + buildout += RELSTORAGE_TEMPLATE.format(relstorage=relstorage) + + # Add file logging configuration if needed + if file_logging: + buildout += FILE_LOGGING_INSTANCE + + # Add sources configuration if needed + if sources: + buildout += SOURCES_TEMPLATE.format(sources="\n".join(sources)) + + with open(self.custom_conf, 'w') as cfile: + cfile.write(buildout) + + def setup(self, **kwargs): + self.buildout() + self.cors() + self.zeoclient() + self.zeopack() + self.zeoserver() + + __call__ = setup + +ZEO_TEMPLATE = """ + + 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 /plone/instance/parts/instance/var + cache-size {zeo_client_cache_size} + +""".strip() + +CORS_TEMPLATE = """ + + + + +""" + +BUILDOUT_TEMPLATE = """ +[buildout] +extends = {buildout_extends} +find-links += {findlinks} +develop += {develop} +eggs += {eggs} +zcml += {zcml} + +[plonesite] +enabled = {enabled} +site-id = {site} +profiles += {profiles} + +[versions] +{versions} +""" + +ZEO_INSTANCE_TEMPLATE = """ + +[instance] +zeo-client = true +zeo-address = {zeoaddress} +shared-blob = {shared_blob_dir} +http-fast-listen = off +""" + +RELSTORAGE_TEMPLATE = """ + +[instance] +rel-storage = + {relstorage} +""" + +SOURCES_TEMPLATE = """ + +[sources] +{sources} +""" + +FILE_LOGGING_INSTANCE = """ + +[instance] +event-log-handler = FileHandler +event-log-args = ('${buildout:var-dir}/log/instance.log', 'a') +access-log-handler = FileHandler +access-log-args = ('${buildout:var-dir}/log/instance-access.log', 'a') +""" + +def initialize(): + """ Configure Plone instance as ZEO Client + """ + environment = Environment() + environment.setup() + +if __name__ == "__main__": + initialize() diff --git a/5.2/5.2.14/python37/Dockerfile b/5.2/5.2.14/python37/Dockerfile new file mode 100644 index 0000000..eebe0f9 --- /dev/null +++ b/5.2/5.2.14/python37/Dockerfile @@ -0,0 +1,50 @@ +FROM python:3.7-slim-buster + +ENV PIP=22.2.2 \ + ZC_BUILDOUT=3.0.1 \ + SETUPTOOLS=65.7.0 \ + WHEEL=0.38.4 \ + PLONE_MAJOR=5.2 \ + PLONE_VERSION=5.2.13 \ + PLONE_VERSION_RELEASE=Plone-5.2.13-UnifiedInstaller-1.0 \ + PLONE_MD5=12c037fae9413385149e8677f8457b84 + +RUN useradd --system -m -d /plone -U -u 500 plone \ + && mkdir -p /plone/instance/ /data/filestorage /data/blobstorage + +COPY buildout.cfg /plone/instance/ + +RUN buildDeps="default-libmysqlclient-dev dpkg-dev gcc libbz2-dev libc6-dev libffi-dev libjpeg62-turbo-dev libldap2-dev libopenjp2-7-dev libpcre3-dev libpq-dev libsasl2-dev libssl-dev libtiff5-dev libxml2-dev libxslt1-dev wget zlib1g-dev" \ + && runDeps="default-libmysqlclient-dev git gosu libjpeg62 libopenjp2-7 libpq5 libtiff5 libxml2 libxslt1.1 lynx netcat poppler-utils rsync wv" \ + && apt-get update \ + && apt-get install -y --no-install-recommends $buildDeps \ + && wget -O Plone.tgz https://launchpad.net/plone/$PLONE_MAJOR/$PLONE_VERSION/+download/$PLONE_VERSION_RELEASE.tgz \ + && echo "$PLONE_MD5 Plone.tgz" | md5sum -c - \ + && tar -xzf Plone.tgz \ + && cp -rv ./$PLONE_VERSION_RELEASE/base_skeleton/* /plone/instance/ \ + && cp -v ./$PLONE_VERSION_RELEASE/buildout_templates/buildout.cfg /plone/instance/buildout-base.cfg \ + && pip install pip==$PIP setuptools==$SETUPTOOLS zc.buildout==$ZC_BUILDOUT wheel==$WHEEL \ + && cd /plone/instance \ + && buildout \ + && ln -s /data/filestorage/ /plone/instance/var/filestorage \ + && ln -s /data/blobstorage /plone/instance/var/blobstorage \ + && find /data -not -user plone -exec chown plone:plone {} \+ \ + && find /plone -not -user plone -exec chown plone:plone {} \+ \ + && rm -rf /Plone* \ + && apt-get purge -y --auto-remove $buildDeps \ + && apt-get install -y --no-install-recommends $runDeps \ + && rm -rf /var/lib/apt/lists/* \ + && rm -rf /plone/buildout-cache/downloads/* + +VOLUME /data + +COPY docker-initialize.py docker-entrypoint.sh / + +EXPOSE 8080 +WORKDIR /plone/instance + +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"] diff --git a/5.2/5.2.14/python37/buildout.cfg b/5.2/5.2.14/python37/buildout.cfg new file mode 100644 index 0000000..02ca654 --- /dev/null +++ b/5.2/5.2.14/python37/buildout.cfg @@ -0,0 +1,106 @@ +[buildout] +extends = + buildout-base.cfg + +index = https://pypi.org/simple/ + +extensions = +effective-user = plone +buildout-user = plone +var-dir=/data +user=admin:admin +parts += + zeo + mrbob + plonesite + +eggs += + RelStorage[mysql,postgresql,oracle] + pas.plugins.ldap + +[client1] +recipe = + +[instance_base] +resources = ${buildout:directory}/resources + +[zeo] +<= zeoserver_base +recipe = plone.recipe.zeoserver +zeo-address = 8080 + +[instance] +zcml-additional = + + + +event-log-handler = StreamHandler +event-log-args = (sys.stderr,) +access-log-handler = StreamHandler +access-log-args = (sys.stdout,) + +# Requires gcc, thus install it on image build +[mrbob] +recipe = zc.recipe.egg +eggs = + mr.bob + bobtemplates.plone + +[plonesite] +recipe = collective.recipe.plonesite +instance = instance +site-id = Plone +profiles-initial = Products.CMFPlone:dependencies +profiles = + plonetheme.barceloneta:default + plone.app.caching:default + plone.app.contenttypes:plone-content + plone.restapi:default +upgrade-portal = False +upgrade-all-profiles = False +enabled = False + +[versions] +setuptools = +zc.buildout = + +plone.restapi = 8.43.1 +plone.rest = 3.0.0 + +RelStorage = 3.4.5 +argparse = 1.4.0 +bda.cache = 1.3.0 +bobtemplates.plone = 5.2.2 +case-conversion = 2.1.0 +collective.checkdocs = 0.2 +collective.recipe.plonesite = 1.12.0 +cx-Oracle = 8.3.0 +isort = 5.11.5 +mr.bob = 1.0.0 +mysqlclient = 2.1.1 +node = 1.2.1 +node.ext.ldap = 1.2 +node.ext.ugm = 1.1 +odict = 1.9.0 +pas.plugins.ldap = 1.8.2 +passlib = 1.7.4 +perfmetrics = 3.3.0 +plumber = 1.7 +psycopg2 = 2.9.3 +pyasn1 = 0.5.0 +pyasn1-modules = 0.3.0 +python-ldap = 3.4.2 +python-memcached = 1.59 +regex = 2023.6.3 +yafowil = 3.1.0 +yafowil.plone = 4.0.0a5 +yafowil.widget.array = 1.7 +yafowil.widget.dict = 1.8 +yafowil.yaml = 2.0 diff --git a/5.2/5.2.14/python37/docker-entrypoint.sh b/5.2/5.2.14/python37/docker-entrypoint.sh new file mode 100755 index 0000000..ecf7f76 --- /dev/null +++ b/5.2/5.2.14/python37/docker-entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash +set -e + +COMMANDS="adduser debug fg foreground help kill logreopen logtail reopen_transcript run show status stop wait" +START="console start restart" + +# Fixing permissions for external /data volumes +mkdir -p /data/blobstorage /data/cache /data/filestorage /data/instance /data/log /data/zeoserver +mkdir -p /plone/instance/src +find /data -not -user plone -exec chown plone:plone {} \+ +find /plone -not -user plone -exec chown plone:plone {} \+ + +# Initializing from environment variables +gosu plone python /docker-initialize.py + +if [ -e "custom.cfg" ]; then + if [ ! -e "bin/develop" ]; then + buildout -c custom.cfg + find /data -not -user plone -exec chown plone:plone {} \+ + find /plone -not -user plone -exec chown plone:plone {} \+ + gosu plone python /docker-initialize.py + fi +fi + +# ZEO Server +if [[ "$1" == "zeo"* ]]; then + exec gosu plone bin/$1 fg +fi + +# Plone instance start +if [[ $START == *"$1"* ]]; then + exec gosu plone bin/instance console +fi + +# Plone instance helpers +if [[ $COMMANDS == *"$1"* ]]; then + exec gosu plone bin/instance "$@" +fi + +# Custom +exec "$@" diff --git a/5.2/5.2.14/python37/docker-initialize.py b/5.2/5.2.14/python37/docker-initialize.py new file mode 100755 index 0000000..99ec331 --- /dev/null +++ b/5.2/5.2.14/python37/docker-initialize.py @@ -0,0 +1,381 @@ +#!/usr/local/bin/python + +import re +import os + +class Environment(object): + """ Configure container via environment variables + """ + def __init__(self, env=os.environ, + zope_conf="/plone/instance/parts/instance/etc/zope.conf", + custom_conf="/plone/instance/custom.cfg", + zeopack_conf="/plone/instance/bin/zeopack", + zeoserver_conf="/plone/instance/parts/zeoserver/etc/zeo.conf", + cors_conf="/plone/instance/parts/instance/etc/package-includes/999-additional-overrides.zcml" + ): + self.env = env + self.zope_conf = zope_conf + self.custom_conf = custom_conf + self.zeopack_conf = zeopack_conf + self.zeoserver_conf = zeoserver_conf + self.cors_conf = cors_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 "" 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".+", 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( + '', + ' pack-keep-old false\n' + ) + + with open(self.zeoserver_conf, 'w') as cfile: + cfile.write(text) + + def cors(self): + """ Configure CORS Policies + """ + if not [e for e in self.env if e.startswith("CORS_")]: + return + + allow_origin = self.env.get("CORS_ALLOW_ORIGIN", + "http://localhost:3000,http://127.0.0.1:3000") + allow_methods = self.env.get("CORS_ALLOW_METHODS", + "DELETE,GET,OPTIONS,PATCH,POST,PUT") + allow_credentials = self.env.get("CORS_ALLOW_CREDENTIALS", "true") + expose_headers = self.env.get("CORS_EXPOSE_HEADERS", + "Content-Length,X-My-Header") + allow_headers = self.env.get("CORS_ALLOW_HEADERS", + "Accept,Authorization,Content-Type,X-Custom-Header,Lock-Token") + max_age = self.env.get("CORS_MAX_AGE", "3600") + cors_conf = CORS_TEMPLATE.format( + allow_origin=allow_origin, + allow_methods=allow_methods, + allow_credentials=allow_credentials, + expose_headers=expose_headers, + allow_headers=allow_headers, + max_age=max_age + ) + with open(self.cors_conf, "w") as cfile: + cfile.write(cors_conf) + + def relstorage_conf(self): + """ RelStorage configuration from environment variables + """ + if not [e for e in self.env if e.startswith("RELSTORAGE_")]: + return "" + + # Database specific adapter options + # https://relstorage.readthedocs.io/en/latest/supported-databases.html + adapter_options = self.env.get( + "RELSTORAGE_ADAPTER_OPTIONS", + "", + ).strip().split(",") + + settings = { + # General Settings + "name": self.env.get("RELSTORAGE_NAME"), + "read-only": self.env.get("RELSTORAGE_READ_ONLY"), + "keep-history": self.env.get("RELSTORAGE_KEEP_HISTORY"), + "commit-lock-timeout": self.env.get( + "RELSTORAGE_COMMIT_LOCK_TIMEOUT", + ), + "commit-lock-id": self.env.get("RELSTORAGE_COMMIT_LOCK_ID"), + "create-schema": self.env.get("RELSTORAGE_CREATE_SCHEMA"), + + # Blobs + "blob-dir": self.env.get("RELSTORAGE_BLOB_DIR", + "/plone/instance/var/blobstorage"), + "shared-blob-dir": self.env.get("RELSTORAGE_SHARED_BLOB_DIR"), + "blob-cache-size": self.env.get("RELSTORAGE_BLOB_CACHE_SIZE"), + "blob-cache-size-check": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK", + ), + "blob-cache-size-check-external": self.env.get( + "RELSTORAGE_BLOB_CACHE_SIZE_CHECK_EXTERNAL", + ), + "blob-chunk-size": self.env.get("RELSTORAGE_BLOB_CHUNK_SIZE"), + + # Replication + "replica-conf": self.env.get("RELSTORAGE_REPLICA_CONF"), + "ro-replica-conf": self.env.get("RELSTORAGE_RO_REPLICA_CONF"), + "replica-timeout": self.env.get("RELSTORAGE_REPLICA_TIMEOUT"), + "revert-when-stale": self.env.get("RELSTORAGE_REVERT_WHEN_STALE"), + + # GC and Packing + "pack-gc": self.env.get("RELSTORAGE_PACK_GC"), + "pack-prepack-only": self.env.get("RELSTORAGE_PACK_PREPACK_ONLY"), + "pack-skip-prepack": self.env.get("RELSTORAGE_PACK_SKIP_PREPACK"), + "pack-batch-timeout": self.env.get("RELSTORAGE_PACK_BATCH_TIMEOUT"), + "pack-commit-busy-delay": self.env.get( + "RELSTORAGE_PACK_COMMIT_BUSY_DELAY", + ), + + # Database Caching + "cache-prefix": self.env.get("RELSTORAGE_CACHE_PREFIX"), + + # Local Caching + "cache-local-mb": self.env.get("RELSTORAGE_CACHE_LOCAL_MB"), + "cache-local-object-max": self.env.get( + "RELSTORAGE_CACHE_LOCAL_OBJECT_MAX", + ), + "cache-local-compression": self.env.get( + "RELSTORAGE_CACHE_LOCAL_COMPRESSION", + ), + "cache-delta-size-limit": self.env.get( + "RELSTORAGE_CACHE_DELTA_SIZE_LIMIT", + ), + + # Persistent Local Caching + "cache-local-dir": self.env.get("RELSTORAGE_CACHE_LOCAL_DIR"), + + # Deprecated Options + # ... + } + + return "\n ".join(adapter_options + [ + "{} {}".format(x[0], x[1].strip()) for x in settings.items() if x[1] + ]) + + def buildout(self): + """ Buildout from environment variables + """ + # Already configured + if os.path.exists(self.custom_conf): + return + + findlinks = self.env.get("FIND_LINKS", "").strip().split() + + eggs = self.env.get("PLONE_ADDONS", + self.env.get("ADDONS", "")).strip().split() + + zcml = self.env.get("PLONE_ZCML", + self.env.get("ZCML", "")).strip().split() + + develop = self.env.get("PLONE_DEVELOP", + self.env.get("DEVELOP", "")).strip().split() + + site = self.env.get("PLONE_SITE", + self.env.get("SITE", "")).strip() + + profiles = self.env.get("PLONE_PROFILES", + self.env.get("PROFILES", "")).strip().split() + + versions = self.env.get("PLONE_VERSIONS", + self.env.get("VERSIONS", "")).strip().split() + + file_logging = self.env.get("FILE_LOGGING") + + sources = self.env.get("SOURCES", "").strip() + sources = sources and [x.strip() for x in sources.split(",")] + + relstorage = self.relstorage_conf() + + buildout_extends = ((develop or sources) + and ["develop.cfg"] or ["buildout.cfg"]) + extra_extends = self.env.get("BUILDOUT_EXTENDS", "").strip().split() + buildout_extends.extend(extra_extends) + + # If profiles not provided. Install ADDONS :default profiles + if not profiles: + for egg in eggs: + base = egg.split("=")[0] + profiles.append("%s:default" % base) + + enabled = bool(site) + if not ( + eggs or zcml or relstorage or develop or enabled or extra_extends or file_logging + ): + return + + buildout = BUILDOUT_TEMPLATE.format( + buildout_extends="\n\t".join(buildout_extends), + findlinks="\n\t".join(findlinks), + eggs="\n\t".join(eggs), + zcml="\n\t".join(zcml), + develop="\n\t".join(develop), + profiles="\n\t".join(profiles), + versions="\n".join(versions), + site=site or "Plone", + enabled=enabled, + ) + + # If we need to create a plonesite and we have a zeo setup + # configure collective.recipe.plonesite properly + server = self.env.get("ZEO_ADDRESS", None) + shared_blob_dir=self.env.get("ZEO_SHARED_BLOB_DIR", "off") + if server: + buildout += ZEO_INSTANCE_TEMPLATE.format(zeoaddress=server, + shared_blob_dir=shared_blob_dir) + + # Add RelStorage configuration if needed + if relstorage: + buildout += RELSTORAGE_TEMPLATE.format(relstorage=relstorage) + + # Add file logging configuration if needed + if file_logging: + buildout += FILE_LOGGING_INSTANCE + + # Add sources configuration if needed + if sources: + buildout += SOURCES_TEMPLATE.format(sources="\n".join(sources)) + + with open(self.custom_conf, 'w') as cfile: + cfile.write(buildout) + + def setup(self, **kwargs): + self.buildout() + self.cors() + self.zeoclient() + self.zeopack() + self.zeoserver() + + __call__ = setup + +ZEO_TEMPLATE = """ + + 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 /plone/instance/parts/instance/var + cache-size {zeo_client_cache_size} + +""".strip() + +CORS_TEMPLATE = """ + + + + +""" + +BUILDOUT_TEMPLATE = """ +[buildout] +extends = {buildout_extends} +find-links += {findlinks} +develop += {develop} +eggs += {eggs} +zcml += {zcml} + +[plonesite] +enabled = {enabled} +site-id = {site} +profiles += {profiles} + +[versions] +{versions} +""" + +ZEO_INSTANCE_TEMPLATE = """ + +[instance] +zeo-client = true +zeo-address = {zeoaddress} +shared-blob = {shared_blob_dir} +http-fast-listen = off +""" + +RELSTORAGE_TEMPLATE = """ + +[instance] +rel-storage = + {relstorage} +""" + +SOURCES_TEMPLATE = """ + +[sources] +{sources} +""" + +FILE_LOGGING_INSTANCE = """ + +[instance] +event-log-handler = FileHandler +event-log-args = ('${buildout:var-dir}/log/instance.log', 'a') +access-log-handler = FileHandler +access-log-args = ('${buildout:var-dir}/log/instance-access.log', 'a') +""" + +def initialize(): + """ Configure Plone instance as ZEO Client + """ + environment = Environment() + environment.setup() + +if __name__ == "__main__": + initialize()