From 7f58c064b491d5dad152551f509dd159da747868 Mon Sep 17 00:00:00 2001 From: William Brown Date: Jul 11 2019 00:41:59 +0000 Subject: Ticket 50484 - Add a release build dockerfile and dscontainer improvements Bug Description: In testing a production deployment of 389-ds-base from the source tree, a new dockerfile was added to handle the release build and proper image cleanups. Additionally, some issues with sigchld handling were noted. Fix Description: * Add a .release dockerfile for the suse base image which cleans up after itself correctly. * Catch extra arguments to the sigchld handler * Create directories in /data with more open permissions to account for id changes. https://pagure.io/389-ds-base/pull-request/50484 Author: William Brown Review by: mhonek (Thank you!) --- diff --git a/docker/389-ds-suse/Dockerfile b/docker/389-ds-suse/Dockerfile index a286912..2e0b5f4 100644 --- a/docker/389-ds-suse/Dockerfile +++ b/docker/389-ds-suse/Dockerfile @@ -12,7 +12,7 @@ RUN zypper ar http://download.opensuse.org/update/leap/15.1/oss/ u && \ zypper --gpg-auto-import-keys ref RUN zypper --non-interactive si --build-deps-only 389-ds && \ - zypper in -y 389-ds rust cargo rust-std && \ + zypper in -y 389-ds rust cargo rust-std libevent && \ zypper rm -y 389-ds # Install build dependencies @@ -33,7 +33,8 @@ WORKDIR /usr/local/src/389-ds-base # Build and install # Derived from rpm --eval '%configure' on opensuse. -RUN ./configure --host=x86_64-suse-linux-gnu --build=x86_64-suse-linux-gnu \ +RUN autoreconf -fiv && \ + ./configure --host=x86_64-suse-linux-gnu --build=x86_64-suse-linux-gnu \ --program-prefix= \ --disable-dependency-tracking \ --prefix=/usr \ diff --git a/docker/389-ds-suse/Dockerfile.release b/docker/389-ds-suse/Dockerfile.release new file mode 100644 index 0000000..c934eda --- /dev/null +++ b/docker/389-ds-suse/Dockerfile.release @@ -0,0 +1,72 @@ +#!BuildTag: 389-ds-container +FROM opensuse/leap:15.1 +MAINTAINER wbrown@suse.de + +EXPOSE 3389 3636 + +# RUN zypper ar -G obs://network:ldap network:ldap && \ +RUN zypper ar http://download.opensuse.org/update/leap/15.1/oss/ u && \ + zypper ar http://download.opensuse.org/distribution/leap/15.1/repo/oss/ m && \ + zypper ar http://download.opensuse.org/repositories/network:ldap/openSUSE_Leap_15.1/ "network:ldap" && \ + zypper mr -p 97 "network:ldap" && \ + zypper --gpg-auto-import-keys ref + +# Push source code to the container - we do this early because we want the zypper and +# build instructions in a single RUN stanza to minimise the container final size. +ADD ./ /usr/local/src/389-ds-base +WORKDIR /usr/local/src/389-ds-base + + +# Build and install +# Derived from rpm --eval '%configure' on opensuse. + +RUN zypper --non-interactive si --build-deps-only 389-ds && \ + zypper in -y 389-ds rust cargo rust-std && \ + zypper rm -y 389-ds lib389 && \ + autoreconf -fiv && \ + ./configure --host=x86_64-suse-linux-gnu --build=x86_64-suse-linux-gnu \ + --program-prefix= \ + --disable-dependency-tracking \ + --prefix=/usr \ + --exec-prefix=/usr \ + --bindir=/usr/bin \ + --sbindir=/usr/sbin \ + --sysconfdir=/etc \ + --datadir=/usr/share \ + --includedir=/usr/include \ + --libdir=/usr/lib64 \ + --libexecdir=/usr/lib \ + --localstatedir=/var \ + --sharedstatedir=/var/lib \ + --mandir=/usr/share/man \ + --infodir=/usr/share/info \ + --disable-dependency-tracking \ + --enable-gcc-security --enable-autobind --enable-auto-dn-suffix --with-openldap \ + --enable-rust --disable-perl --with-pythonexec="python3" --without-systemd \ + --libexecdir=/usr/lib/dirsrv/ --prefix=/ && \ + make -j 12 && \ + make install && \ + make lib389 && \ + make lib389-install && \ + make clean && \ + zypper rm -y -u rust cargo rust-std gcc gcc-c++ automake autoconf + +# Link some known static locations to point to /data +RUN mkdir -p /data/config && \ + mkdir -p /data/ssca && \ + mkdir -p /data/run && \ + mkdir -p /var/run/dirsrv && \ + ln -s /data/config /etc/dirsrv/slapd-localhost && \ + ln -s /data/ssca /etc/dirsrv/ssca && \ + ln -s /data/run /var/run/dirsrv + +# Temporal volumes for each instance + +VOLUME /data + +# Set the userup correctly. This was created as part of the 389ds in above. +# For k8s we'll need 389 to not drop privs? I think we don't specify a user +# here and ds should do the right thing if a non root user runs the server. +# USER dirsrv + +CMD [ "/usr/sbin/dscontainer", "-r" ] diff --git a/src/lib389/cli/dscontainer b/src/lib389/cli/dscontainer index 83a1f79..e4bb073 100755 --- a/src/lib389/cli/dscontainer +++ b/src/lib389/cli/dscontainer @@ -40,6 +40,7 @@ from lib389.instance.setup import SetupDs from lib389.instance.options import General2Base, Slapd2Base from lib389.passwd import password_generate from lib389.paths import Paths +from lib389._constants import DSRC_CONTAINER # We setup the logger in verbose mode to make sure debug info # is always available! @@ -47,7 +48,10 @@ log = setup_script_logger("container-init", True) # Handle any dead child process signals we receive. Wait for them to terminate, or # if they are not found, move on. -def _sigchild_handler(): +# +# We take *args and **kwargs here to handle the fact that this signal gets args, but +# we don't need or care about them. +def _sigchild_handler(*args, **kwargs): log.debug("Received SIGCHLD ...") os.waitpid(-1, os.WNOHANG) @@ -103,14 +107,15 @@ def begin_magic(): '/data/logs' ]: if not os.path.exists(d): - os.makedirs(d, mode=0o770) + # Yolo, container security is from ns isolation, not unix perms. When we drop + # privs we'll need this to support future writes. + os.makedirs(d, mode=0o777) # Do we have correct permissions to our volumes? With the power of thoughts and # prayers, we continue blindy and ... well hope. - # Do we have an instance? We can only tell by the /data/config/container.inf - # marker file - if not os.path.exists('/data/config/container.inf'): + # Do we have an instance? We can only tell by the DSRC_CONTAINER marker file + if not os.path.exists(DSRC_CONTAINER): # Nope? Make one ... log.info("Initialising 389-ds-container due to empty volume ...") rpw = password_generate() @@ -162,10 +167,19 @@ def begin_magic(): log.info("IMPORTANT: Set cn=Directory Manager password to \"%s\"" % rpw) - # Create the marker to say we exist. This is also a good writable permissions - # test for the volume. - with open('/data/config/container.inf', 'w') as f: - f.write('allocated') + # Create the marker to say we exist. This is also a good writable permissions + # test for the volume. + with open(DSRC_CONTAINER, 'w') as f: + f.write(""" +[localhost] +# Note that '/' is replaced to '%%2f' for ldapi url format. +# So this is pointing to /data/run/slapd-localhost.socket +uri = ldapi://%%2fdata%%2frun%%2fslapd-localhost.socket +binddn = cn=Directory Manager +# Set your basedn here +# basedn = dc=example,dc=com + """) + os.chmod(DSRC_CONTAINER, 0o755) # TODO: All of this is contingent on the server starting *and* # ldapi working ... Perhaps these are better inside ns-slapd core diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl index ed8fc8f..e76f3e5 100755 --- a/src/lib389/cli/dsctl +++ b/src/lib389/cli/dsctl @@ -22,6 +22,7 @@ from lib389.cli_ctl import instance as cli_instance from lib389.cli_ctl import dbtasks as cli_dbtasks from lib389.cli_base import disconnect_instance, setup_script_logger from lib389.cli_ctl.instance import instance_remove_all +from lib389._constants import DSRC_CONTAINER parser = argparse.ArgumentParser() parser.add_argument('-v', '--verbose', @@ -47,7 +48,7 @@ parser.add_argument('--remove-all', nargs="?", default=False, const=None, subparsers = parser.add_subparsers(help="action") # We can only use the instance tools like start/stop etc in a non-container # environment. If we are in a container, we only allow the tasks. -if not os.path.exists('/data/config/container.inf'): +if not os.path.exists(DSRC_CONTAINER): cli_instance.create_parser(subparsers) cli_dbtasks.create_parser(subparsers) diff --git a/src/lib389/lib389/_constants.py b/src/lib389/lib389/_constants.py index e656131..a1fa6ee 100644 --- a/src/lib389/lib389/_constants.py +++ b/src/lib389/lib389/_constants.py @@ -345,3 +345,5 @@ args_instance = {SER_DEPLOYED_DIR: os.environ.get('PREFIX', None), # Helper for linking dse.ldif values to the parse_config function args_dse_keys = SER_PROPNAME_TO_ATTRNAME + +DSRC_CONTAINER = '/data/config/container.inf' diff --git a/src/lib389/lib389/cli_base/dsrc.py b/src/lib389/lib389/cli_base/dsrc.py index 8fd8364..5056514 100644 --- a/src/lib389/lib389/cli_base/dsrc.py +++ b/src/lib389/lib389/cli_base/dsrc.py @@ -10,6 +10,7 @@ import sys import os import ldap from lib389.properties import * +from lib389._constants import DSRC_CONTAINER MAJOR, MINOR, _, _, _ = sys.version_info @@ -85,10 +86,11 @@ def dsrc_to_ldap(path, instance_name, log): """ path = os.path.expanduser(path) log.debug("dsrc path: %s" % path) - # First read our config - # No such file? + log.debug("dsrc container path: %s" % DSRC_CONTAINER) config = configparser.ConfigParser() - config.read([path]) + # First read our container config if it exists + # Then overlap the user config. + config.read([DSRC_CONTAINER, path]) log.debug("dsrc instances: %s" % config.sections())