From dea7d7cd0e5b2b29bd0e632e33ca23e5c420f536 Mon Sep 17 00:00:00 2001 From: Konstantin Demin Date: Tue, 13 Aug 2024 09:20:08 +0300 Subject: [PATCH] refactor --- Dockerfile | 172 ++++++++++++- Dockerfile.base | 244 +++++++++++++++++-- Dockerfile.deps | 177 ++++++++++++++ Dockerfile.interim | 201 --------------- apt/preferences.pgdg | 4 - apt/preferences.pgdg-ver.in | 3 + apt/sources.pgdg | 2 +- apt/sources.pgdg-ver.in | 5 + build-scripts/image-base.sh | 51 ++++ build-scripts/image-deps.sh | 16 ++ build-scripts/image.sh | 31 +++ ci/build-image-base.sh | 16 -- ci/build-image-interim.sh | 10 - ci/build-image.sh | 8 - extra-scripts/certifi-extras.sh | 91 +++++++ {scripts => extra-scripts}/gpg-batch.sh | 0 extra-scripts/gpg-export.sh | 28 +++ requirements.txt | 27 ++ scripts/apt-clean.sh | 3 + scripts/apt-install.sh | 44 +++- scripts/apt-remove.sh | 5 + scripts/divert-rm.sh | 7 + scripts/gpg-export.sh | 28 --- scripts/openssl-cert-auto-pem.sh | 50 ++++ scripts/openssl-cert-fingerprint.sh | 52 ++++ scripts/{pip-clean.sh => python-rm-cache.sh} | 0 26 files changed, 965 insertions(+), 310 deletions(-) create mode 100644 Dockerfile.deps delete mode 100644 Dockerfile.interim create mode 100644 apt/preferences.pgdg-ver.in create mode 100644 apt/sources.pgdg-ver.in create mode 100755 build-scripts/image-base.sh create mode 100755 build-scripts/image-deps.sh create mode 100755 build-scripts/image.sh delete mode 100755 ci/build-image-base.sh delete mode 100755 ci/build-image-interim.sh delete mode 100755 ci/build-image.sh create mode 100755 extra-scripts/certifi-extras.sh rename {scripts => extra-scripts}/gpg-batch.sh (100%) create mode 100755 extra-scripts/gpg-export.sh create mode 100644 requirements.txt create mode 100755 scripts/apt-remove.sh create mode 100755 scripts/divert-rm.sh delete mode 100755 scripts/gpg-export.sh create mode 100755 scripts/openssl-cert-auto-pem.sh create mode 100755 scripts/openssl-cert-fingerprint.sh rename scripts/{pip-clean.sh => python-rm-cache.sh} (100%) diff --git a/Dockerfile b/Dockerfile index fe8b13d..a1259f5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,168 @@ -FROM docker.io/rockdrilla/postgresql:16.3-base +ARG UPSTREAM_IMAGE_VERSION +ARG DEPS_IMAGE +FROM docker.io/library/postgres:${UPSTREAM_IMAGE_VERSION}-bookworm AS postgresql-upstream +FROM ${DEPS_IMAGE} AS deps + +## --- + +FROM deps AS pycache SHELL [ "/bin/sh", "-ec" ] -COPY /Dockerfile /usr/local/share/ +COPY /scripts/* /usr/local/sbin/ -COPY /ep.sh /usr/local/sbin/ -COPY /postgres-shim.sh /usr/local/sbin/ +ENV PYTHONDONTWRITEBYTECODE='' + +## Python cache preseed + +RUN libpython="${PYTHON_SITE_PACKAGES%/*}" ; \ + find "${libpython}/" -mindepth 1 -maxdepth 1 -printf '%P\0' \ + | sed -zEn \ + -e '/^(collections|importlib|json|re)$/p' \ + | sort -zV \ + | env -C "${libpython}" xargs -0r \ + python3 -m compileall -q -j 2 ; \ + find "${PYTHON_SITE_PACKAGES}/" -mindepth 1 -maxdepth 1 -printf '%P\0' \ + | sed -zE \ + -e '/\.(dist-info|pth|txt)$/d' \ + -e '/^(pip|pkg_resources|setuptools|wheel)$/d' \ + | sort -zV \ + | env -C "${PYTHON_SITE_PACKAGES}" xargs -0r \ + python3 -m compileall -q -j 2 + +## Python cache warmup +RUN export PYTHONPROFILEIMPORTTIME=1 ; \ + patronictl --help ; \ + patroni --help ; \ + ydiff --help ; \ + cdiff --help + +## Python cache adjustments +RUN d="@$(date '+%s')" ; \ + find /usr/local/lib/ -name '*.pyc' -exec touch -m -d "$d" {} + ; \ + find /usr/local/lib/ -name __pycache__ -exec touch -m -d "$d" {} + + +## --- + +FROM deps AS postgresql +SHELL [ "/bin/sh", "-ec" ] + +COPY /scripts/* /usr/local/sbin/ + +ENV PG_UID=11111 PG_GID=11111 +ENV PGHOME=/var/lib/postgresql +ENV PGDATA=${PGHOME}/data + +RUN echo "postgres:x:${PG_UID}:${PG_GID}:postgres:${PGHOME}:/bin/bash" >> /etc/passwd ; \ + echo "postgres:x:${PG_GID}:" >> /etc/group ; \ + echo 'postgres:!:::::::' >> /etc/shadow ; \ + install -d -o postgres -g postgres -m 0755 "${PGHOME}" + +RUN install -d -o postgres -g postgres -m 3755 /run/postgresql +VOLUME [ "/run/postgresql" ] + +COPY /apt/sources.pgdg-ver.in /tmp/pgdg-ver.sources +COPY /apt/preferences.pgdg-ver.in /tmp/pgdg-ver.prefs +RUN sed "s/%{PG_MAJOR}/${PG_MAJOR}/g" < /tmp/pgdg-ver.sources > "/etc/apt/sources.list.d/pgdg-${PG_MAJOR}.sources" ; \ + sed "s/%{PG_MAJOR}/${PG_MAJOR}/g" < /tmp/pgdg-ver.prefs > "/etc/apt/preferences.d/pgdg-${PG_MAJOR}" ; \ + rm -f /tmp/pgdg-ver.sources /tmp/pgdg-ver.prefs + +COPY --from=postgresql-upstream /etc/postgresql-common/createcluster.conf /etc/postgresql-common/ +RUN apt-install.sh postgresql-common ; \ + apt-install.sh \ + "postgresql-${PG_MAJOR}" \ + ; \ + apt-clean.sh ; \ + f="/usr/share/postgresql/${PG_MAJOR}/postgresql.conf.sample" ; \ + dpkg-divert --add --rename --divert "$f.dpkg" "$f" ; \ + ln -sv ../postgresql.conf.sample "/usr/share/postgresql/${PG_MAJOR}/" +COPY --from=postgresql-upstream /usr/share/postgresql/postgresql.conf.sample /usr/share/postgresql/ + +ENV PATH=${PATH}:/usr/lib/postgresql/${PG_MAJOR}/bin + +COPY --from=postgresql-upstream /docker-entrypoint-initdb.d/ /docker-entrypoint-initdb.d/ +COPY --from=postgresql-upstream /usr/local/bin/*.sh /usr/local/bin/ +## compatibility ;) +RUN ln -sv /usr/local/sbin/dumb-run-as.sh /usr/local/bin/gosu + +## --- + +FROM postgresql AS postgresql-extras +SHELL [ "/bin/sh", "-ec" ] + +RUN apt-install.sh \ + pgbouncer \ + "postgresql-${PG_MAJOR}-cron" \ + "postgresql-${PG_MAJOR}-hll" \ + "postgresql-${PG_MAJOR}-hypopg" \ + "postgresql-${PG_MAJOR}-icu-ext" \ + "postgresql-${PG_MAJOR}-pg-catcheck" \ + "postgresql-${PG_MAJOR}-pg-checksums" \ + "postgresql-${PG_MAJOR}-pg-failover-slots" \ + "postgresql-${PG_MAJOR}-pg-hint-plan" \ + "postgresql-${PG_MAJOR}-pg-qualstats" \ + "postgresql-${PG_MAJOR}-pg-stat-kcache" \ + "postgresql-${PG_MAJOR}-pgextwlist" \ + "postgresql-${PG_MAJOR}-pgfaceting" \ + "postgresql-${PG_MAJOR}-pgfincore" \ + "postgresql-${PG_MAJOR}-pglogical" \ + "postgresql-${PG_MAJOR}-pglogical-ticker" \ + "postgresql-${PG_MAJOR}-pgpcre" \ + "postgresql-${PG_MAJOR}-powa" \ + "postgresql-${PG_MAJOR}-repack" \ + "postgresql-${PG_MAJOR}-roaringbitmap" \ + "postgresql-${PG_MAJOR}-rum" \ + "postgresql-${PG_MAJOR}-semver" \ + "postgresql-${PG_MAJOR}-show-plans" \ + "postgresql-${PG_MAJOR}-similarity" \ + "postgresql-${PG_MAJOR}-squeeze" \ + "postgresql-${PG_MAJOR}-tablelog" \ + "postgresql-${PG_MAJOR}-tdigest" \ + "postgresql-${PG_MAJOR}-timescaledb" \ + "postgresql-${PG_MAJOR}-toastinfo" \ + "postgresql-${PG_MAJOR}-unit" \ + "postgresql-${PG_MAJOR}-wal2json" \ + ; \ + apt-clean.sh + +## --- + +FROM postgresql-extras AS citus +SHELL [ "/bin/sh", "-ec" ] + +COPY /apt/sources.citus /etc/apt/sources.list.d/citus.sources + +RUN apt-install.sh \ + "postgresql-${PG_MAJOR}-citus-12.1" \ + "postgresql-${PG_MAJOR}-topn" \ + ; apt-clean.sh + +VOLUME [ "${PGHOME}" ] + +## --- + +FROM citus +SHELL [ "/bin/sh", "-ec" ] + +COPY /Dockerfile /usr/local/share/ + +## RFC: Python cache +## TODO: reduce load by selecting only __pycache__ directories in either way +COPY --from=pycache /usr/local/lib/ /usr/local/lib/ + +COPY /ep.sh /usr/local/sbin/ +COPY /postgres-shim.sh /usr/local/sbin/ ## quirk RUN ln -sv postgres-shim.sh /usr/local/sbin/postgres -RUN site_packages=$(python3 -c 'import site;print(site.getsitepackages()[0])') ; \ - rm -rf \ - "${site_packages}/etcd/tests" \ - "${site_packages}/psutil/tests" \ - ; \ - find "${site_packages}/" -maxdepth 1 -type f -name '*.py' -exec python3 -m compileall -q -j 2 {} + ; \ - find "${site_packages}/" -mindepth 1 -maxdepth 1 -type d -printf '%P\0' \ - | sed -zE '/\.dist-info$/d;/^(_distutils_hack|pip|pkg_resources|setuptools|wheel)$/d' \ - | env -C "${site_packages}" xargs -0r python3 -m compileall -q -j 2 +WORKDIR "${PGHOME}" + +## "Fast Shutdown mode" in PostgreSQL +## NB: override to SIGTERM in order to switch to "Smart Shutdown mode" +STOPSIGNAL SIGINT + +ENV DUMB_INIT_SETSID=0 \ + MALLOC_ARENA_MAX=4 \ + GOMAXPROCS=4 ENTRYPOINT [ "ep.sh" ] CMD [ "postgres" ] diff --git a/Dockerfile.base b/Dockerfile.base index 992ff1e..e163bb7 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -1,50 +1,240 @@ ARG PYTHONTAG=3.11.9-slim-bookworm -FROM docker.io/library/python:${PYTHONTAG} as base-upstream +FROM docker.io/python:${PYTHONTAG} AS base-upstream -FROM base-upstream as base +FROM base-upstream AS base SHELL [ "/bin/sh", "-ec" ] -COPY /Dockerfile.base /usr/local/share/ +COPY /Dockerfile.base /usr/local/share/ -## - remove duplicate "/usr/local/bin" (fixes upstream image) -## - remove /sbin and /bin (/usr is merged) -ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin +COPY /scripts/* /usr/local/sbin/ +COPY /extra-scripts/* /usr/local/sbin/ -ENV MALLOC_ARENA_MAX=2 \ +## PATH: remove /sbin and /bin (/usr is merged) +ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \ + TMPDIR=/tmp \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + TERM=linux \ + TZ=Etc/UTC \ + MALLOC_ARENA_MAX=2 \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 -COPY /scripts/* /usr/local/sbin/ +## local development +# ENV PIP_INDEX="http://127.0.0.1:8081/repository/proxy_pypi/pypi/" \ +# PIP_INDEX_URL="http://127.0.0.1:8081/repository/proxy_pypi/simple/" \ +# PIP_TRUSTED_HOST="localhost" -COPY /apt/sources.debian /etc/apt/sources.list.d/debian.sources +COPY /apt/sources.debian /etc/apt/sources.list.d/debian.sources + +## prevent services from auto-starting, part 1 +RUN s='/usr/sbin/policy-rc.d' ; b='/usr/bin/policy-rc.d' ; \ + rm -f "$s" "$b" ; \ + echo '#!/bin/sh' > "$b" ; \ + echo 'exit 101' >> "$b" ; \ + chmod 0755 "$b" ; \ + ln -s "$b" "$s" + +RUN divert_true() { divert-rm.sh "$1" ; ln -sv /bin/true "$1" ; } ; \ + ## prevent services from auto-starting, part 2 + divert_true /sbin/start-stop-daemon ; \ + ## always report that we're in chroot + divert_true /usr/bin/ischroot ; \ + ## hide systemd helpers + divert_true /usr/bin/deb-systemd-helper ; \ + divert_true /usr/bin/deb-systemd-invoke RUN apt-env.sh apt-get update ; \ apt-env.sh apt-get upgrade -y ; \ - apt-env.sh dpkg -P \ - e2fsprogs \ - libext2fs2 \ - libss2 \ - logsave \ - ; apt-clean.sh + apt-clean.sh -RUN pip-env.sh pip list --format freeze \ +## perl-base: hardlink->symlink +RUN d=/usr/bin ; \ + find "$d/" -wholename "$d/perl5*" -exec ln -fsv perl {} ';' ; \ + ls -li "$d/perl"* + +## remove unwanted binaries +RUN set -f ; \ + for i in \ + addpart \ + apt-ftparchive \ + agetty \ + badblocks \ + blkdiscard \ + blkid \ + blkzone \ + blockdev \ + bsd-write \ + chage \ + chcpu \ + chfn \ + chgpasswd \ + chmem \ + chpasswd \ + chsh \ + cpgr \ + cppw \ + ctrlaltdel \ + debugfs \ + delpart \ + dmesg \ + dumpe2fs \ + e2freefrag \ + e2fsck \ + e2image \ + e2label \ + e2mmpstatus \ + e2scrub \ + 'e2scrub*' \ + e2undo \ + e4crypt \ + e4defrag \ + expiry \ + faillock \ + fdformat \ + fincore \ + findfs \ + fsck \ + 'fsck.*' \ + fsfreeze \ + fstrim \ + getty \ + gpasswd \ + groupmems \ + grpck \ + grpconv \ + grpunconv \ + hwclock \ + isosize \ + last \ + lastb \ + ldattach \ + losetup \ + lsblk \ + lsirq \ + lslogins \ + mcookie \ + mesg \ + mke2fs \ + mkfs \ + 'mkfs.*' \ + mkhomedir_helper \ + mklost+found \ + mkswap \ + mount \ + newgrp \ + newusers \ + pam-auth-update \ + pam_getenv \ + pam_namespace_helper \ + pam_timestamp_check \ + partx \ + pivot_root \ + pwck \ + pwconv \ + pwhistory_helper \ + pwunconv \ + raw \ + readprofile \ + resize2fs \ + resizepart \ + rtcwake \ + sg \ + shadowconfig \ + sulogin \ + swaplabel \ + swapoff \ + swapon \ + switch_root \ + tune2fs \ + umount \ + unix_chkpwd \ + unix_update \ + utmpdump \ + vigr \ + vipw \ + wall \ + wdctl \ + wipefs \ + write \ + 'write.*' \ + zramctl \ + ; do \ + for d in /usr/sbin /usr/bin /sbin /bin ; do \ + find "$d/" ! -type d -wholename "$d/$i" \ + | while read -r p ; do \ + [ -n "$p" ] || continue ; \ + [ -e "$p" ] || continue ; \ + dpkg -S "$p" >/dev/null 2>&1 || continue ; \ + divert-rm.sh "$p" ; \ + done ; \ + done ; \ + for d in /usr/sbin /usr/bin /sbin /bin ; do \ + find "$d/" ! -type d -wholename "$d/$i" \ + | while read -r p ; do \ + [ -n "$p" ] || continue ; \ + [ -e "$p" ] || continue ; \ + rm -fv "$p" ; \ + done ; \ + done ; \ + done ; \ + ## fixup + rm -f \ + /bin/lastb \ + /bin/sg \ + /sbin/getty \ + ; : + +## remove excessive privileges from binaries +RUN set -f ; \ + for i in \ + passwd \ + su \ + ; do \ + for d in /usr/sbin /usr/bin /sbin /bin ; do \ + find "$d/" ! -type d -wholename "$d/$i" \ + | while read -r p ; do \ + [ -n "$p" ] || continue ; \ + [ -e "$p" ] || continue ; \ + dpkg -S "$p" >/dev/null 2>&1 || continue ; \ + o=$(env stat -c '%U' "$p") ; \ + g=$(env stat -c '%G' "$p") ; \ + ls -l "$p" ; \ + dpkg-statoverride --update --add "$o" "$g" 0755 "$p" ; \ + ls -l "$p" ; \ + done ; \ + done ; \ + done + +RUN apt-remove.sh \ + ca-certificates \ + e2fsprogs \ + ; \ + apt-clean.sh + +## "docker.io/python"-specific cleanup +RUN rm -f /root/.wget-hsts + +RUN python-rm-cache.sh /usr/local ; \ + pip-env.sh pip list --format freeze \ | grep -F '==' | awk -F= '{print $1}' \ | xargs -r pip-env.sh pip install -U ; \ - pip-clean.sh /usr/local + python-rm-cache.sh "${PYTHON_SITE_PACKAGES}" -RUN site_packages=$(python3 -c 'import site;print(site.getsitepackages()[0])') ; \ - libpython=$(dirname "${site_packages}") ; \ - rm -rf \ +RUN python-rm-cache.sh /usr/local ; \ + libpython="${PYTHON_SITE_PACKAGES%/*}" ; \ + rm -rfv \ + /usr/local/bin/idle* \ "${libpython}/ensurepip/_bundled" \ + "${libpython}/idlelib" \ + "${libpython}/tkinter" \ + "${libpython}/turtle.py" \ "${libpython}/turtledemo" \ - ; \ - find "${libpython}/" -maxdepth 1 -type f -name '*.py' -exec python3 -m compileall -q -j 2 {} + ; \ - find "${libpython}/" -mindepth 1 -maxdepth 1 -type d -printf '%P\0' \ - | sed -zE '^(__pycache__|site-packages|__phello__|ensurepip|lib2to3|pydoc.*|tkinter|unittest)$/d' \ - | env -C "${libpython}" xargs -0r python3 -m compileall -q -j 2 + ; : -RUN rm -f /root/.wget-hsts ; \ - find /usr/local/sbin/ ! -type d -name '*.sh' -delete +RUN find /usr/local/sbin/ ! -type d -ls -delete ; \ + find /run/ -mindepth 1 -ls -delete || : ; \ + install -d -m 01777 /run/lock ENTRYPOINT [ ] CMD [ "bash" ] diff --git a/Dockerfile.deps b/Dockerfile.deps new file mode 100644 index 0000000..daeb6b3 --- /dev/null +++ b/Dockerfile.deps @@ -0,0 +1,177 @@ +FROM docker.io/rockdrilla/postgresql:base-v1 AS base + +## --- + +FROM base AS certs +SHELL [ "/bin/sh", "-ec" ] + +COPY /scripts/* /usr/local/sbin/ +COPY /extra-scripts/* /usr/local/sbin/ + +## consult https://github.com/certifi/python-certifi/ +ENV CERTIFI_COMMIT=bd8153872e9c6fc98f4023df9c2deaffea2fa463 + +RUN apt-install.sh ca-certificates curl ; \ + apt-clean.sh ; \ + ## process certifi + ca_file='/etc/ssl/certs/ca-certificates.crt' ; \ + ls -l "${ca_file}" ; \ + certifi-extras.sh ; \ + openssl-cert-fingerprint.sh "${ca_file}" | sort -uV > "${ca_file}.fp" ; \ + chmod 0444 "${ca_file}" "${ca_file}.fp" ; \ + ls -l "${ca_file}" "${ca_file}.fp" + +## --- + +FROM base AS apt-gpg +SHELL [ "/bin/sh", "-ec" ] + +COPY /scripts/* /usr/local/sbin/ +COPY /extra-scripts/* /usr/local/sbin/ + +COPY --from=certs /etc/ssl/certs/ca-certificates.* /etc/ssl/certs/ + +ADD https://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc /tmp/pgdg.gpg.bin +ADD https://packagecloud.io/citusdata/community/gpgkey /tmp/citus.gpg.bin + +## process GPG keyrings +RUN pkg='gnupg' ; \ + apt-install.sh ${pkg} ; \ + gpg-export.sh /tmp/pgdg.gpg.bin /etc/apt/keyrings/pgdg.gpg.asc ; \ + gpg-export.sh /tmp/citus.gpg.bin /etc/apt/keyrings/citus.gpg.asc ; \ + apt-remove.sh ${pkg} + +COPY /apt/sources.pgdg /etc/apt/sources.list.d/pgdg.sources +COPY /apt/sources.citus /etc/apt/sources.list.d/citus.sources + +## verify sources! +RUN apt-env.sh apt-get update ; \ + apt-clean.sh + +## --- + +FROM base AS patroni +SHELL [ "/bin/sh", "-ec" ] + +COPY /scripts/* /usr/local/sbin/ + +COPY --from=certs /etc/ssl/certs/ca-certificates.* /etc/ssl/certs/ + +COPY --from=apt-gpg /etc/apt/keyrings/ /etc/apt/keyrings/ + +COPY /apt/sources.pgdg /etc/apt/sources.list.d/pgdg.sources +COPY /apt/preferences.pgdg /etc/apt/preferences.d/pgdg + +ENV DEV_PACKAGES='libffi-dev libpq-dev libyaml-dev' +# psutil +ENV CIBUILDWHEEL=1 +# pyyaml +ENV PYYAML_FORCE_CYTHON=1 + +COPY /requirements.txt /tmp/ + +RUN w=$(mktemp -d) ; : "${w:?}" ; \ + { apt-mark showauto ; apt-mark showmanual ; } | sort -uV > "$w/t0" ; \ + printf '%s\n' ${DEV_PACKAGES} | sort -uV > "$w/t1" ; \ + apt-install.sh ${DEV_PACKAGES} ; \ + { apt-mark showauto ; apt-mark showmanual ; } | sort -uV > "$w/t2" ; \ + set +e ; \ + grep -Fxv -f "$w/t0" "$w/t2" > "$w/t3" ; \ + grep -Fxv -f "$w/t1" "$w/t3" > "$w/t4" ; \ + grep -Ev -e '-(dev|doc)$' "$w/t4" > "${PYTHON_SITE_PACKAGES}/apt-deps.txt" ; \ + set -e ; \ + rm -rf "$w/" ; unset w ; \ + apt-install.sh build-essential ; \ + pip-env.sh pip install 'cython' ; \ + pip-env.sh pip install \ + --no-binary 'cffi,psutil,pyyaml' \ + -r /tmp/requirements.txt \ + ; \ + pip-env.sh pip uninstall -y 'cython' ; \ + python-rm-cache.sh "${PYTHON_SITE_PACKAGES}" ; \ + rm -rf \ + "${PYTHON_SITE_PACKAGES}/etcd/tests" \ + "${PYTHON_SITE_PACKAGES}/psutil/tests" \ + ; \ + find "${PYTHON_SITE_PACKAGES}/" -type f -name '*.so*' -exec ls -l {} + ; \ + echo ; \ + find "${PYTHON_SITE_PACKAGES}/" -type f -name '*.so*' -printf '%p\0' \ + | sed -zE '/rust/d' \ + | xargs -0r strip --verbose --strip-debug ; \ + echo ; \ + find "${PYTHON_SITE_PACKAGES}/" -type f -name '*.so*' -exec ls -l {} + ; \ + apt-remove.sh build-essential ; \ + apt-clean.sh + +## --- + +FROM base +SHELL [ "/bin/sh", "-ec" ] + +COPY /Dockerfile.deps /usr/local/share/ + +COPY /scripts/* /usr/local/sbin/ + +COPY --from=certs /etc/ssl/certs/ca-certificates.* /etc/ssl/certs/ + +COPY --from=apt-gpg /etc/apt/keyrings/ /etc/apt/keyrings/ + +COPY /apt/sources.pgdg /etc/apt/sources.list.d/pgdg.sources +COPY /apt/preferences.pgdg /etc/apt/preferences.d/pgdg + +COPY --from=patroni /usr/local/bin/ /usr/local/bin/ +COPY --from=patroni /${PYTHON_SITE_PACKAGES}/ /${PYTHON_SITE_PACKAGES}/ + +## install missing dependencies for Python site-packages +RUN f="${PYTHON_SITE_PACKAGES}/apt-deps.txt" ; \ + [ -s "$f" ] || exit 0 ; \ + xargs -a "$f" apt-install.sh ; \ + apt-clean.sh + +RUN apt-install.sh \ + brotli \ + curl \ + dumb-init \ + file \ + gettext-base \ + gnupg \ + iproute2 \ + iputils-ping \ + jq \ + less \ + libnss-wrapper \ + lsof \ + ncurses-base \ + netbase \ + netcat-openbsd \ + openssl \ + procps \ + psmisc \ + tzdata \ + vim \ + xxd \ + xz-utils \ + zstd \ + ; \ + apt-clean.sh + +## set up locales! +RUN _lang=en_US.UTF8 ; \ + { \ + echo "locales locales/default_environment_locale select ${LANG}" ; \ + echo "locales locales/locales_to_be_generated multiselect ${LANG} UTF-8" ; \ + } | debconf-set-selections ; \ + f=/etc/dpkg/dpkg.cfg.d/docker ; \ + if [ -f "$f" ] ; then \ + sed -Ei '/\/usr\/share\/locale/d' "$f" ; \ + fi ; \ + echo "LANG=${_lang}" > /etc/default/locale ; \ + apt-install.sh locales ; apt-clean.sh ; \ + grep -Fixq "${_lang} UTF-8" /etc/locale.gen || { \ + echo "${_lang} UTF-8" >> /etc/locale.gen ; \ + locale-gen ; \ + } ; \ + locale -a | grep -Fixq "${_lang}" +ENV LANG=en_US.UTF8 + +RUN find /usr/local/sbin/ ! -type d -ls -delete diff --git a/Dockerfile.interim b/Dockerfile.interim deleted file mode 100644 index ba01559..0000000 --- a/Dockerfile.interim +++ /dev/null @@ -1,201 +0,0 @@ -ARG PYTHONTAG=3.11.9-slim-bookworm -FROM localhost/local-python:${PYTHONTAG} as base -FROM docker.io/library/postgres:16.3-bookworm as postgresql-upstream - -## --- - -FROM base as postgresql -SHELL [ "/bin/sh", "-ec" ] - -COPY /scripts/* /usr/local/sbin/ - -RUN apt-install.sh \ - ca-certificates \ - curl \ - dumb-init \ - file \ - gnupg \ - iproute2 \ - iputils-ping \ - jq \ - less \ - libnss-wrapper \ - lsof \ - ncurses-base \ - netbase \ - procps \ - psmisc \ - tzdata \ - vim \ - xxd \ - xz-utils \ - zstd \ - ; apt-clean.sh - -ENV PG_MAJOR=16 -ENV PG_UID=11111 PG_GID=11111 -ENV PGHOME=/var/lib/postgresql -ENV PGDATA=${PGHOME}/data - -RUN echo "postgres:x:${PG_UID}:${PG_GID}:postgres:${PGHOME}:/bin/bash" >> /etc/passwd ; \ - echo "postgres:x:${PG_GID}:" >> /etc/group ; \ - echo 'postgres:!:::::::' >> /etc/shadow ; \ - install -d -o postgres -g postgres -m 0755 "${PGHOME}" - -RUN install -d -o postgres -g postgres -m 3755 /run/postgresql -VOLUME [ "/run/postgresql" ] - -## set up locales! -RUN _lang=en_US.UTF8 ; \ - { \ - echo "locales locales/default_environment_locale select ${LANG}" ; \ - echo "locales locales/locales_to_be_generated multiselect ${LANG} UTF-8" ; \ - } | debconf-set-selections ; \ - f=/etc/dpkg/dpkg.cfg.d/docker ; \ - if [ -f "$f" ] ; then \ - sed -Ei '/\/usr\/share\/locale/d' "$f" ; \ - fi ; \ - echo "LANG=${_lang}" > /etc/default/locale ; \ - apt-install.sh locales ; apt-clean.sh ; \ - grep -Fixq "${_lang} UTF-8" /etc/locale.gen || { \ - echo "${_lang} UTF-8" >> /etc/locale.gen ; \ - locale-gen ; \ - } ; \ - locale -a | grep -Fixq "${_lang}" -ENV LANG=en_US.UTF8 - -ADD https://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc /etc/apt/keyrings/pgdg.gpg.bin -COPY /apt/sources.pgdg /etc/apt/sources.list.d/pgdg.sources -COPY /apt/preferences.pgdg /etc/apt/preferences.d/pgdg -RUN env -C /etc/apt/keyrings gpg-export.sh pgdg.gpg.bin pgdg.gpg.asc - -COPY --from=postgresql-upstream /etc/postgresql-common/createcluster.conf /etc/postgresql-common/ -RUN apt-install.sh postgresql-common ; \ - apt-install.sh \ - "postgresql-${PG_MAJOR}" \ - ; \ - apt-clean.sh ; \ - f="/usr/share/postgresql/${PG_MAJOR}/postgresql.conf.sample" ; \ - dpkg-divert --add --rename --divert "$f.dpkg" "$f" ; \ - ln -sv ../postgresql.conf.sample "/usr/share/postgresql/${PG_MAJOR}/" -COPY --from=postgresql-upstream /usr/share/postgresql/postgresql.conf.sample /usr/share/postgresql/ - -ENV PATH=${PATH}:/usr/lib/postgresql/${PG_MAJOR}/bin - -COPY --from=postgresql-upstream /docker-entrypoint-initdb.d/ /docker-entrypoint-initdb.d/ -COPY --from=postgresql-upstream /usr/local/bin/*.sh /usr/local/bin/ -## compatibility ;) -RUN ln -sv /usr/local/sbin/dumb-run-as.sh /usr/local/bin/gosu - -## --- - -FROM postgresql as postgresql-extras -SHELL [ "/bin/sh", "-ec" ] - -RUN apt-install.sh \ - "postgresql-${PG_MAJOR}-cron" \ - "postgresql-${PG_MAJOR}-hll" \ - "postgresql-${PG_MAJOR}-hypopg" \ - "postgresql-${PG_MAJOR}-icu-ext" \ - "postgresql-${PG_MAJOR}-pg-catcheck" \ - "postgresql-${PG_MAJOR}-pg-checksums" \ - "postgresql-${PG_MAJOR}-pg-failover-slots" \ - "postgresql-${PG_MAJOR}-pg-hint-plan" \ - "postgresql-${PG_MAJOR}-pg-qualstats" \ - "postgresql-${PG_MAJOR}-pg-stat-kcache" \ - "postgresql-${PG_MAJOR}-pgextwlist" \ - "postgresql-${PG_MAJOR}-pgfaceting" \ - "postgresql-${PG_MAJOR}-pgfincore" \ - "postgresql-${PG_MAJOR}-pglogical" \ - "postgresql-${PG_MAJOR}-pglogical-ticker" \ - "postgresql-${PG_MAJOR}-pgpcre" \ - "postgresql-${PG_MAJOR}-powa" \ - "postgresql-${PG_MAJOR}-repack" \ - "postgresql-${PG_MAJOR}-roaringbitmap" \ - "postgresql-${PG_MAJOR}-rum" \ - "postgresql-${PG_MAJOR}-semver" \ - "postgresql-${PG_MAJOR}-show-plans" \ - "postgresql-${PG_MAJOR}-similarity" \ - "postgresql-${PG_MAJOR}-squeeze" \ - "postgresql-${PG_MAJOR}-tablelog" \ - "postgresql-${PG_MAJOR}-tdigest" \ - "postgresql-${PG_MAJOR}-timescaledb" \ - "postgresql-${PG_MAJOR}-toastinfo" \ - "postgresql-${PG_MAJOR}-unit" \ - "postgresql-${PG_MAJOR}-wal2json" \ - ; \ - apt-clean.sh - -## --- - -FROM postgresql-extras as citus -SHELL [ "/bin/sh", "-ec" ] - -ADD https://packagecloud.io/citusdata/community/gpgkey /etc/apt/keyrings/citus.gpg.bin -COPY /apt/sources.citus /etc/apt/sources.list.d/citus.sources -RUN env -C /etc/apt/keyrings gpg-export.sh citus.gpg.bin citus.gpg.asc -RUN apt-install.sh \ - "postgresql-${PG_MAJOR}-citus-12.1" \ - "postgresql-${PG_MAJOR}-topn" \ - ; apt-clean.sh - -VOLUME [ "${PGHOME}" ] - -## --- - -FROM postgresql as patroni-build -SHELL [ "/bin/sh", "-ec" ] - -# pyyaml -ENV PYYAML_FORCE_CYTHON=1 -# psutil -ENV CIBUILDWHEEL=1 - -RUN apt-install.sh \ - build-essential \ - libffi-dev \ - libpq-dev \ - libyaml-dev \ - ; \ - apt-clean.sh - -RUN pip-env.sh pip install --no-binary :all: 'psycopg[c,pool]' ; \ - pip-env.sh pip install 'cython' ; \ - pip-env.sh pip install --no-binary 'cffi,psutil,pyyaml' 'patroni[etcd3,kubernetes,raft]' ; \ - pip-env.sh pip uninstall -y 'cython' ; \ - site_packages=$(python3 -c 'import site;print(site.getsitepackages()[0])') ; \ - pip-clean.sh "${site_packages}" ; \ - find "${site_packages}/" -type f -name '*.so*' -exec ls -l {} + ; \ - echo ; \ - find "${site_packages}/" -type f -name '*.so*' -printf '%P\0' \ - | sed -zE '/rust/d' \ - | env -C "${site_packages}" xargs -0r strip --strip-debug ; \ - echo ; \ - find "${site_packages}/" -type f -name '*.so*' -exec ls -l {} + - -## --- - -FROM citus as patroni -SHELL [ "/bin/sh", "-ec" ] - -COPY /Dockerfile.interim /usr/local/share/ - -COPY --from=patroni-build /usr/local/bin/ /usr/local/bin/ -COPY --from=patroni-build /usr/local/lib/python3.11/site-packages/ /usr/local/lib/python3.11/site-packages/ - -RUN apt-install.sh \ - libyaml-0-2 \ - ; apt-clean.sh - -WORKDIR "${PGHOME}" - -## "Fast Shutdown mode" in PostgreSQL -## NB: override to SIGTERM in order to switch to "Smart Shutdown mode" -STOPSIGNAL SIGINT - -ENTRYPOINT [ "docker-entrypoint.sh" ] -CMD [ "postgres" ] - -ENV DUMB_INIT_SETSID=0 \ - MALLOC_ARENA_MAX=4 \ - GOMAXPROCS=4 diff --git a/apt/preferences.pgdg b/apt/preferences.pgdg index 771de59..c111a84 100644 --- a/apt/preferences.pgdg +++ b/apt/preferences.pgdg @@ -1,7 +1,3 @@ Package: * Pin: release a=bookworm-pgdg Pin-Priority: 600 - -Package: src:postgresql-16 -Pin: release a=bookworm-pgdg -Pin-Priority: 700 diff --git a/apt/preferences.pgdg-ver.in b/apt/preferences.pgdg-ver.in new file mode 100644 index 0000000..003eaeb --- /dev/null +++ b/apt/preferences.pgdg-ver.in @@ -0,0 +1,3 @@ +Package: src:postgresql-%{PG_MAJOR} +Pin: release a=bookworm-pgdg +Pin-Priority: 650 diff --git a/apt/sources.pgdg b/apt/sources.pgdg index 1a8d55c..1bfe8f1 100644 --- a/apt/sources.pgdg +++ b/apt/sources.pgdg @@ -1,5 +1,5 @@ Types: deb URIs: http://apt.postgresql.org/pub/repos/apt/ Suites: bookworm-pgdg -Components: main 16 +Components: main Signed-By: /etc/apt/keyrings/pgdg.gpg.asc diff --git a/apt/sources.pgdg-ver.in b/apt/sources.pgdg-ver.in new file mode 100644 index 0000000..e1be7ed --- /dev/null +++ b/apt/sources.pgdg-ver.in @@ -0,0 +1,5 @@ +Types: deb +URIs: http://apt.postgresql.org/pub/repos/apt/ +Suites: bookworm-pgdg +Components: %{PG_MAJOR} +Signed-By: /etc/apt/keyrings/pgdg.gpg.asc diff --git a/build-scripts/image-base.sh b/build-scripts/image-base.sh new file mode 100755 index 0000000..9c1f5db --- /dev/null +++ b/build-scripts/image-base.sh @@ -0,0 +1,51 @@ +#!/bin/sh +set -ef +cd "$(dirname "$0")/.." + +set -a +BUILDAH_FORMAT="${BUILDAH_FORMAT:-docker}" +BUILDAH_ISOLATION="${BUILDAH_ISOLATION:-chroot}" +BUILDAH_NETWORK="${BUILDAH_NETWORK:-host}" +set +a + +PYTHONTAG="${PYTHONTAG:-3.11.9-slim-bookworm}" + +grab_site_packages() { + podman run \ + --pull=always --rm \ + --entrypoint='[]' \ + --user=nobody:nogroup \ + -e LANG=C.UTF-8 \ + -e LC_ALL=C.UTF-8 \ + -e MALLOC_ARENA_MAX=2 \ + -e PYTHONUNBUFFERED=1 \ + -e PYTHONDONTWRITEBYTECODE=1 \ + "$1" \ + python3 -c 'import site;print(site.getsitepackages()[0])' +} + +PYTHON_SITE_PACKAGES=$(grab_site_packages "docker.io/python:${PYTHONTAG}") +[ -n "${PYTHON_SITE_PACKAGES:?}" ] + +img="docker.io/rockdrilla/postgresql:base-v1" + +buildah bud \ + -f ./Dockerfile.base \ + -t "${img}" \ + --pull=missing --no-cache --squash \ + --build-arg "PYTHONTAG=${PYTHONTAG}" \ + --env "PYTHON_SITE_PACKAGES=${PYTHON_SITE_PACKAGES}" \ + --unsetenv GPG_KEY \ + --unsetenv PYTHON_PIP_VERSION \ + --unsetenv PYTHON_SETUPTOOLS_VERSION \ + --unsetenv PYTHON_GET_PIP_SHA256 \ + --unsetenv PYTHON_GET_PIP_URL \ + + +c=$(buildah from --pull=never "${img}") || true +if [ -z "$c" ] ; then + buildah rmi -f "${img}" + exit 1 +fi +buildah config --created-by /usr/local/share/Dockerfile.base "$c" +buildah commit --rm --squash "$c" "${img}" diff --git a/build-scripts/image-deps.sh b/build-scripts/image-deps.sh new file mode 100755 index 0000000..a652720 --- /dev/null +++ b/build-scripts/image-deps.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -ef +cd "$(dirname "$0")/.." + +set -a +BUILDAH_FORMAT="${BUILDAH_FORMAT:-docker}" +BUILDAH_ISOLATION="${BUILDAH_ISOLATION:-chroot}" +BUILDAH_NETWORK="${BUILDAH_NETWORK:-host}" +set +a + +img="docker.io/rockdrilla/postgresql:deps-v1" + +exec buildah bud \ + -f ./Dockerfile.deps \ + -t "${img}" \ + --pull=missing --no-cache diff --git a/build-scripts/image.sh b/build-scripts/image.sh new file mode 100755 index 0000000..c02bcc7 --- /dev/null +++ b/build-scripts/image.sh @@ -0,0 +1,31 @@ +#!/bin/sh +set -ef +cd "$(dirname "$0")/.." + +set -a +BUILDAH_FORMAT="${BUILDAH_FORMAT:-docker}" +BUILDAH_ISOLATION="${BUILDAH_ISOLATION:-chroot}" +BUILDAH_NETWORK="${BUILDAH_NETWORK:-host}" +set +a + +POSTGRESQL_VERSION="${1:-16.4}" +PG_MAJOR="${POSTGRESQL_VERSION%%.*}" + +img="docker.io/rockdrilla/postgresql:${POSTGRESQL_VERSION}" +deps="docker.io/rockdrilla/postgresql:deps-v1" + +c=$(buildah from --pull=missing "${deps}") +[ -n "${c:?}" ] +buildah config --env "POSTGRESQL_VERSION=${POSTGRESQL_VERSION}" "$c" +buildah config --env "PG_MAJOR=${PG_MAJOR}" "$c" +buildah commit --rm "$c" "${img}-env" +unset c + +buildah bud \ + -f ./Dockerfile \ + -t "${img}" \ + --pull=missing --no-cache \ + --build-arg "DEPS_IMAGE=${img}-env" \ + --build-arg "UPSTREAM_IMAGE_VERSION=${POSTGRESQL_VERSION}" \ + +podman image rm "${img}-env" diff --git a/ci/build-image-base.sh b/ci/build-image-base.sh deleted file mode 100755 index e08f85f..0000000 --- a/ci/build-image-base.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -set -ef -cd "$(dirname "$0")/.." - -PYTHONTAG="${1:-3.11.9-slim-bookworm}" -exec buildah bud --isolation chroot --network host --format docker \ - -f ./Dockerfile.base \ - -t "local-python:${PYTHONTAG}" \ - --build-arg "PYTHONTAG=${PYTHONTAG}" \ - --pull=missing --no-cache --omit-history \ - --squash \ - --unsetenv GPG_KEY \ - --unsetenv PYTHON_PIP_VERSION \ - --unsetenv PYTHON_SETUPTOOLS_VERSION \ - --unsetenv PYTHON_GET_PIP_SHA256 \ - --unsetenv PYTHON_GET_PIP_URL \ diff --git a/ci/build-image-interim.sh b/ci/build-image-interim.sh deleted file mode 100755 index 5fbcd2f..0000000 --- a/ci/build-image-interim.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -set -ef -cd "$(dirname "$0")/.." - -PYTHONTAG="${1:-3.11.9-slim-bookworm}" -exec buildah bud --isolation chroot --network host --format docker \ - -f ./Dockerfile.interim \ - -t docker.io/rockdrilla/postgresql:16.3-base \ - --build-arg "PYTHONTAG=${PYTHONTAG}" \ - --pull=missing --no-cache --omit-history \ diff --git a/ci/build-image.sh b/ci/build-image.sh deleted file mode 100755 index 4bbf5a6..0000000 --- a/ci/build-image.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -set -ef -cd "$(dirname "$0")/.." - -exec buildah bud --isolation chroot --network host --format docker \ - -f ./Dockerfile \ - -t docker.io/rockdrilla/postgresql:16.3 \ - --pull=missing --no-cache --omit-history \ diff --git a/extra-scripts/certifi-extras.sh b/extra-scripts/certifi-extras.sh new file mode 100755 index 0000000..2e509f7 --- /dev/null +++ b/extra-scripts/certifi-extras.sh @@ -0,0 +1,91 @@ +#!/bin/sh +set -ef + +certifi_uri="https://raw.githubusercontent.com/certifi/python-certifi/${CERTIFI_COMMIT:?}/certifi/cacert.pem" +dst_dir=/usr/local/share/ca-certificates + +w=$(mktemp -d) ; : "${w:?}" +w_cleanup() { + [ -z "$w" ] || ls -lA "$w/" + [ -z "$w" ] || rm -rf "$w" + unset w + exit "${1:-0}" +} + +curl -sSL "${certifi_uri}" > "$w/certifi.crt" + +def_bundle='/etc/ssl/certs/ca-certificates.crt' + +openssl-cert-auto-pem.sh "${def_bundle}" > "$w/cacert.pem" +openssl-cert-auto-pem.sh "$w/certifi.crt" > "$w/certifi.pem" +[ -s "$w/cacert.pem" ] || w_cleanup 1 +[ -s "$w/certifi.pem" ] || w_cleanup 1 + +bundle_offsets() { + awk ' + BEGIN { + OFS = "," + m_begin="-----BEGIN CERTIFICATE-----" + m_end="-----END CERTIFICATE-----" + i_begin = 0 + } + $0 == m_begin { i_begin = NR ; } + $0 == m_end { + if (i_begin > 0) { + print i_begin,NR + i_begin = 0 + } + } + ' "$1" +} + +bundle_offsets "$w/cacert.pem" > "$w/cacert.off" +bundle_offsets "$w/certifi.pem" > "$w/certifi.off" +[ -s "$w/cacert.off" ] || w_cleanup 1 +[ -s "$w/certifi.off" ] || w_cleanup 1 + +bundle_fingerprints() { + local a + while read -r a ; do + [ -n "$a" ] || continue + + { + sed -ne "${a}p" "$1" | openssl x509 -noout -fingerprint -sha256 \ + || \ + sed -ne "${a}p" "$1" | openssl x509 -noout -fingerprint + } | tr '[:upper:]' '[:lower:]' + done < "$2" +} + +bundle_fingerprints "$w/cacert.pem" "$w/cacert.off" | sort -uV > "$w/cacert.fp" +bundle_fingerprints "$w/certifi.pem" "$w/certifi.off" | sort -uV > "$w/certifi.fp" +[ -s "$w/cacert.fp" ] || w_cleanup 1 +[ -s "$w/certifi.fp" ] || w_cleanup 1 + +set +e +grep -Fxv -f "$w/cacert.fp" "$w/certifi.fp" > "$w/diff.fp" +set -e + +if [ -s "$w/diff.fp" ] ; then + set +e + grep -Fxn -f "$w/diff.fp" "$w/certifi.fp" | cut -d : -f 1 > "$w/records.diff" + set -e + + terse_fingerprint() { + cut -d = -f 2- | tr -cd '[:alnum:]' + } + + mkdir "$w/extras" + + while read -r n ; do + [ -n "$n" ] || continue + + fp=$(sed -ne "${n}p" "$w/certifi.fp" | terse_fingerprint) + off=$(sed -ne "${n}p" "$w/certifi.off") + sed -ne "${off}p" "$w/certifi.pem" | openssl x509 > "${dst_dir}/certifi-${fp}.crt" + done < "$w/records.diff" +fi + +rm -rf "$w" ; unset w + +exec update-ca-certificates --fresh diff --git a/scripts/gpg-batch.sh b/extra-scripts/gpg-batch.sh similarity index 100% rename from scripts/gpg-batch.sh rename to extra-scripts/gpg-batch.sh diff --git a/extra-scripts/gpg-export.sh b/extra-scripts/gpg-export.sh new file mode 100755 index 0000000..dda0678 --- /dev/null +++ b/extra-scripts/gpg-export.sh @@ -0,0 +1,28 @@ +#!/bin/sh +set -ef + +: "${1:?}" "${2:?}" + +w=$(mktemp -d) ; : "${w:?}" + +gpg_on() { gpg-batch.sh start ; } +gpg_off() { + cd / + gpg-batch.sh stop + unset GNUPGHOME + rm -rf "$w" + exit "${1:-0}" +} + +( + export GNUPGHOME="$w/.gnupg" + mkdir -m 0700 "${GNUPGHOME}" + gpg_on + + gpg --import "$1" + gpg --armor --export > "$w/export" + cat < "$w/export" > "$2" + gpg --show-keys "$2" + + gpg_off +) || gpg_off 1 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..90bd9a4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,27 @@ +## psycopg[c,pool] + +psycopg-c==3.2.1 +typing_extensions==4.12.2 +psycopg-pool==3.2.2 +psycopg[c,pool]==3.2.1 + +## patroni[etcd3,kubernetes] + +click==8.1.7 +wcwidth==0.2.13 +prettytable==3.11.0 +psutil==6.0.0 +six==1.16.0 +python-dateutil==2.9.0.post0 +PyYAML==6.0.2 +urllib3==2.2.2 +ydiff==1.3 +dnspython==2.6.1 +python-etcd==0.4.5 +patroni[etcd3,kubernetes]==3.3.2 + +## misc +cdiff==1.0 +pycparser==2.22 +cffi==1.17.0 +cryptography==43.0.0 diff --git a/scripts/apt-clean.sh b/scripts/apt-clean.sh index 819debe..4365a7c 100755 --- a/scripts/apt-clean.sh +++ b/scripts/apt-clean.sh @@ -15,6 +15,9 @@ find "${DPKG_ADMINDIR}/" ! -type d -wholename "${DPKG_ADMINDIR}/*-old" -delete find /var/log/ ! -type d -wholename '/var/log/alternatives.log' -delete find /var/log/ ! -type d -wholename '/var/log/dpkg.log' -delete +## DONT DO THIS AT HOME! +find "${DPKG_ADMINDIR}/" ! -type d -wholename "${DPKG_ADMINDIR}/info/*.symbols" -delete + ## debconf find /var/cache/debconf/ ! -type d -wholename '/var/cache/debconf/*-old' -delete diff --git a/scripts/apt-install.sh b/scripts/apt-install.sh index 9fd77b0..7859e80 100755 --- a/scripts/apt-install.sh +++ b/scripts/apt-install.sh @@ -1,4 +1,44 @@ #!/bin/sh set -ef -apt-env.sh apt-get update -exec apt-env.sh apt-get install -y --no-install-recommends "$@" + +find_fresh_ts() { + { + find "$@" -exec stat -c '%Y' '{}' '+' 2>/dev/null || : + # duck and cover! + echo 1 + } | sort -rn | head -n 1 +} + +_apt_update() { + # update package lists; may fail sometimes, + # e.g. soon-to-release channels like Debian "bullseye" @ 22.04.2021 + + # (wannabe) smart package list update + ts_sources=$(find_fresh_ts /etc/apt/ -follow -regextype egrep -regex '.+\.(list|sources)$' -type f) + ts_lists=$(find_fresh_ts /var/lib/apt/lists/ -maxdepth 1 -regextype egrep -regex '.+_Packages(\.(bz2|gz|lz[4o]|xz|zstd?))?$' -type f) + if [ ${ts_sources} -gt ${ts_lists} ] ; then + apt-env.sh apt-get update + fi +} + +_dpkg_avail_hack() { + VERSION_CODENAME=$(. /etc/os-release ; printf '%s' "${VERSION_CODENAME}") || : + f="${DPKG_ADMINDIR:-/var/lib/dpkg}/available" + # if ${VERSION_CODENAME} is empty then we're on Debian sid or so :) + case "${VERSION_CODENAME}" in + stretch | buster | bionic | focal ) + # ref: https://unix.stackexchange.com/a/271387/49297 + if [ -s "$f" ] ; then + return + fi + /usr/lib/dpkg/methods/apt/update "${DPKG_ADMINDIR:-/var/lib/dpkg}" apt apt + ;; + * ) + touch "$f" + ;; + esac +} + +_apt_update +_dpkg_avail_hack +exec apt-env.sh apt-get install -y --no-install-recommends --no-install-suggests "$@" diff --git a/scripts/apt-remove.sh b/scripts/apt-remove.sh new file mode 100755 index 0000000..dc032b6 --- /dev/null +++ b/scripts/apt-remove.sh @@ -0,0 +1,5 @@ +#!/bin/sh +set -ef + +apt-env.sh apt-get purge -y --allow-remove-essential "$@" +exec apt-env.sh apt-get autopurge -y diff --git a/scripts/divert-rm.sh b/scripts/divert-rm.sh new file mode 100755 index 0000000..0740eef --- /dev/null +++ b/scripts/divert-rm.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -ef +: "${1:?}" +d=$(printf '%s' "/run/postgresql/divert/$1" | tr -s '/') +mkdir -p "${d%/*}" +dpkg-divert --divert "$d" --rename "$1" 2>/dev/null +rm -f "$d" diff --git a/scripts/gpg-export.sh b/scripts/gpg-export.sh deleted file mode 100755 index b38072a..0000000 --- a/scripts/gpg-export.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -set -ef - -: "${1:?}" "${2:?}" - -w=$(mktemp -d) ; : "${w:?}" - -gpg_on() { gpg-batch.sh start ; } -gpg_off() { - cd / - gpg-batch.sh stop - unset GNUPGHOME - rm -rf "$w" - exit "${1:-0}" -} - -( - export GNUPGHOME="$w/.gnupg" - mkdir -m 0700 "${GNUPGHOME}" - gpg_on - - gpg --import "$1" - gpg --armor --export > "$w/export" - cat < "$w/export" > "$2" - gpg --show-keys "$2" - - gpg_off -) || gpg_off 1 diff --git a/scripts/openssl-cert-auto-pem.sh b/scripts/openssl-cert-auto-pem.sh new file mode 100755 index 0000000..2ffff27 --- /dev/null +++ b/scripts/openssl-cert-auto-pem.sh @@ -0,0 +1,50 @@ +#!/bin/sh +set -f + +[ $# -gt 0 ] || exit 0 +me=${0##*/} + +[ -n "$1" ] || exit 1 +[ -f "$1" ] || { + env printf '%s: not a file or does not exist: %q\n' "${me}" "$1" >&2 + exit 1 +} +[ -s "$1" ] || exit 0 + +w=$(mktemp -d) || exit 1 +w_cleanup() { + [ -z "$w" ] || ls -lA "$w/" + [ -z "$w" ] || rm -rf "$w" + unset w + exit "${1:-0}" +} + +openssl storeutl -certs "$1" > "$w/cert.pem" || w_cleanup 1 +[ -s "$w/cert.pem" ] || w_cleanup 1 +tr -s '\r\n' '\n' < "$w/cert.pem" > "$w/cert.txt" +[ -s "$w/cert.txt" ] || w_cleanup 1 + +awk ' +BEGIN { + OFS = "," + m_begin="-----BEGIN CERTIFICATE-----" + m_end="-----END CERTIFICATE-----" + i_begin = 0 +} +$0 == m_begin { i_begin = NR ; } +$0 == m_end { + if (i_begin > 0) { + print i_begin,NR + i_begin = 0 + } +} +' "$w/cert.txt" > "$w/cert.offsets" +[ -s "$w/cert.offsets" ] || w_cleanup 1 + +while read -r a ; do + [ -n "$a" ] || continue + + sed -ne "${a}p" "$w/cert.txt" +done < "$w/cert.offsets" + +rm -rf "$w" ; unset w diff --git a/scripts/openssl-cert-fingerprint.sh b/scripts/openssl-cert-fingerprint.sh new file mode 100755 index 0000000..f41ad1d --- /dev/null +++ b/scripts/openssl-cert-fingerprint.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -f + +[ $# -gt 0 ] || exit 0 +me=${0##*/} + +[ -n "$1" ] || exit 1 +[ -f "$1" ] || { + env printf '%s: not a file or does not exist: %q\n' "${me}" "$1" >&2 + exit 1 +} +[ -s "$1" ] || exit 0 + +w=$(mktemp -d) || exit 1 +w_cleanup() { + [ -z "$w" ] || ls -lA "$w/" + [ -z "$w" ] || rm -rf "$w" + unset w + exit "${1:-0}" +} + +openssl-cert-auto-pem.sh "$1" > "$w/cert.pem" || w_cleanup 1 +[ -s "$w/cert.pem" ] || w_cleanup 1 + +awk ' +BEGIN { + OFS = "," + m_begin="-----BEGIN CERTIFICATE-----" + m_end="-----END CERTIFICATE-----" + i_begin = 0 +} +$0 == m_begin { i_begin = NR ; } +$0 == m_end { + if (i_begin > 0) { + print i_begin,NR + i_begin = 0 + } +} +' "$w/cert.pem" > "$w/cert.off" +[ -s "$w/cert.off" ] || w_cleanup 1 + +while read -r a ; do + [ -n "$a" ] || continue + + { + sed -ne "${a}p" "$w/cert.pem" | openssl x509 -noout -fingerprint -sha256 \ + || \ + sed -ne "${a}p" "$w/cert.pem" | openssl x509 -noout -fingerprint + } | tr '[:upper:]' '[:lower:]' +done < "$w/cert.off" + +w_cleanup 0 diff --git a/scripts/pip-clean.sh b/scripts/python-rm-cache.sh similarity index 100% rename from scripts/pip-clean.sh rename to scripts/python-rm-cache.sh