content: # syntax=docker/dockerfile:1.9
  
  # This is the build file for the OTOBO web docker image.
  # The services OTOBO web and OTOBO daemon use the same image.
  # There is also an extra build target otobo-web-kerberos that adds support for Kerberos.
  
  # See also bin/docker/build_docker_images.sh
  # See also https://docs.docker.com/docker-hub/builds/advanced/
  # See also https://doc.otobo.org/manual/installation/10.1/en/content/installation-docker.html
  
  # As of OTOBO 10.0.26 the Debian version is explicitly set to Debian 12 (bookworm).
  # This avoids a surprising change of the version of Debian when the image
  # is rebuilt, especially when the image for a new release of OTOBO is built.
  # Note that the minor version of Debian may change between builds.
  #
  # The version of Perl is set to 5.40. The idea is that all release branches,
  # rel-10_0, rel-10_1, rel-11.0, and rel-11_1, use the same version of Perl 5.
  #
  # The individual build targets may add additional Debian or CPAN packages.
  FROM perl:5.40-bookworm AS base
  
  # First there is some initial setup that needs to be done by root.
  USER root
  
  # Install some required and optional Debian packages.
  #
  # For ODBC see https://blog.devart.com/installing-and-configuring-odbc-driver-on-linux.html
  # For ODBC for SQLIte, for testing ODBC, see http://www.ch-werner.de/sqliteodbc/html/index.html
  #
  # The webserver needs to connect to MariaDB service using DBD::mysql. For that purpose
  # 'default-mysql-client' is installed. This allows the building
  # of the Perl module DBD::mysql. It also installs the command line program 'mysql'.
  #
  # Create /opt/otobo_install already here, in order to reduce the number of build layers.
  # hadolint ignore=DL3008
  #
  # create the otobo user
  #   --user-group            create group 'otobo' and add the user to the created group
  #   --home-dir /opt/otobo   set $HOME of the user
  #   --create-home           create /opt/otobo
  #   --shell /bin/bash       set the login shell, not used here because otobo is system user
  #   --comment 'OTOBO user'  complete name of the user
  #
  # Also create /opt/otobo_install and /opt/otobo
  ENV OTOBO_USER=otobo
  ENV OTOBO_GROUP=otobo
  ENV OTOBO_HOME=/opt/otobo
  RUN apt-get update\
   && DEBIAN_FRONTEND=noninteractive apt-get -y --no-install-recommends install\
   "ack"\
   "cron"\
   "default-mysql-client"\
   "graphviz"\
   "git"\
   "ldap-utils"\
   "less"\
   "nano"\
   "odbcinst1debian2" "libodbc1" "odbcinst" "unixodbc-dev" "unixodbc"\
   "freetds-bin" "freetds-common" "tdsodbc"\
   "postgresql-client"\
   "redis-tools"\
   "sqlite3" "libsqliteodbc"\
   "rsync"\
   "screen"\
   "telnet"\
   "tree"\
   "vim"\
   "chromium"\
   "chromium-sandbox"\
   "fonts-indic"\
   "fonts-noto"\
   "fonts-noto-cjk"\
   "fonts-noto-color-emoji"\
   "libqrencode-dev"\
   && useradd --user-group --home-dir $OTOBO_HOME --create-home --shell /bin/bash --comment 'OTOBO user' $OTOBO_USER\
   && install -d /opt/otobo_install\
   && install --group $OTOBO_GROUP --owner $OTOBO_USER -d $OTOBO_HOME
  
  # We want an UTF-8 console
  ENV LC_ALL=C.UTF-8
  ENV LANG=C.UTF-8
  
  # Install CPAN distributions that are required by OTOBO into the local lib /opt/otobo_install/local.
  # Installation can be triggerd by making any modification of the file cpanfile.docker.
  #
  # Only local::lib is installed with ghe Perl module installer 'cpanm'. 'cpanm' is already available
  # via the Docker base image for perl.
  #
  # Note that the modules in /opt/otobo/Kernel/cpan-lib are not considered by cpanm.
  # This hopefully reduces potential conflicts.
  #
  # The modules are installed with the command `carton` as it allows to install fixed
  # version from a previous snapshot. The idea is that the snapshot is updated when
  # performing local builds. The automatic build on Github use the saved snapshot.
  #
  # 'carton install' installs the newest version of CPAN modules when the cpanfile.snapsho does not exist.
  # The file cpanfile.snapshot is created, documenting which versions were installed.
  # 'carton install --deployment' will install the exact versions from cpanfile.snapshot.
  # and it will complain if modules that are not in the snapshot should be installed.
  #
  # A fatpacked script `carton` is used for building the image. This has the advantage
  # that the requirements for `carton` are not included in the generated Docker image.
  #
  # Creating the fatpacked carton script is a bit tedious. See
  # https://github.com/perl-carton/carton/issues/237 and https://github.com/miyagawa/cpanminus/pull/577.
  # The recommendation is to create the fatpack in an running container:
  #   cd /opt/otobo
  #   cpanm --local-lib local Carton
  #   cpanm --local-lib local App::FatPacker
  #   sed -e '/version::vpp/s/^/# version:vpp is not in core Perl 5.40:/' -i.bak local/lib/perl5/Menlo/CLI/Compat.pm
  #   touch cpanfile
  #   carton fatpack
  #   rm cpanfile
  # On the Docker host the fatpacked /opt/otobo_install/vendor/bin/carton can be copied to bin/docker/carton
  # in the Git sandbox.
  #   docker cp otoelfeins-web-1:/opt/otobo/vendor/bin/carton bin/docker/carton
  #   git add bin/docker/carton
  #
  # Note that the variable $DOCKER_TAG is already substituted by Docker.
  #
  # Clean up the .cpanm dir after the installation tasks as that dir is no longer needed
  # and the unpacked Perl distributions sometimes have weird user and group IDs.
  WORKDIR /opt/otobo_install
  COPY bin/docker/carton carton
  COPY cpanfile.docker cpanfile
  COPY cpanfile.docker.snapshot cpanfile.snapshot
  ENV PERL5LIB="/opt/otobo_install/local/lib/perl5"
  ENV PATH="/opt/otobo_install/local/bin:${PATH}"
  ARG DOCKER_TAG=unspecified
  RUN <<END_BASH bash
      set -eux
  
      cpanm --local-lib local local::lib
  
      if [[ $DOCKER_TAG == local-* ]]
      then
          rm cpanfile.snapshot
          /opt/otobo_install/carton install
      else
          /opt/otobo_install/carton install --deployment
      fi
  
      rm -rf "/root/.cpanm"
  END_BASH
  
  # Add some additional meta info to the image.
  # This done at the end of the Dockerfile as changed labels and changed args invalidate the layer cache.
  # The labels are compliant with https://github.com/opencontainers/image-spec/blob/master/annotations.md .
  # For the standard build args passed by hub.docker.com see https://docs.docker.com/docker-hub/builds/advanced/.
  # Titel is specific for the individual targets.
  LABEL maintainer='Team OTOBO <dev@otobo.org>'
  LABEL org.opencontainers.image.authors='Team OTOBO <dev@otobo.org>'
  LABEL org.opencontainers.image.description='OTOBO is the new open source ticket system with strong functionality AND a great look'
  LABEL org.opencontainers.image.documentation='https://otobo.org'
  LABEL org.opencontainers.image.licenses='GNU General Public License v3.0 or later'
  LABEL org.opencontainers.image.url='https://github.com/RotherOSS/otobo'
  LABEL org.opencontainers.image.vendor='Rother OSS GmbH'
  
  # Tell the web application and bin/otobo.SetPermissions.pl that it runs in a container.
  # Note that this setting is essential for a correct migration from OTRS 6.
  ENV OTOBO_RUNS_UNDER_DOCKER=1
  
  # the entrypoint is not in the volume
  ENTRYPOINT ["/opt/otobo_install/entrypoint.sh"]
  
  # The regular build target, without Kerberos
  FROM base AS otobo-web
  
  # First there is some initial setup that needs to be done by root.
  USER root
  
  # No further Debian or CPAN packages are needed,
  # so we only need to do the cleanup
  RUN rm -rf /var/lib/apt/lists/*
  
  # Copy the OTOBO installation to /opt/otobo_install/otobo_next and use it as the working dir.
  # The files that are set up in .dockerignore. This means that a potentially existing Kernel/Config.pm
  # won't be copied. Instead Kernel/Config.pm.docker.dist will be copied to Kernel/Config.pm in entrypoint.sh.
  COPY --chown=$OTOBO_USER:$OTOBO_GROUP . /opt/otobo_install/otobo_next
  WORKDIR /opt/otobo_install/otobo_next
  
  # In a running installation additional Perl modules from CPAN might be needed. These be installed
  # in the directory /opt/otobo/local. This directory is located in the volume /opt/otobo and therefore
  # survives updates of the Docker image.
  # /opt/otobo/local must be prepolulated with architecture and version dependent subdirs. These subdirs
  # are added to @INC when a Perl process starts up.
  RUN perl -Mlocal::lib=local
  ENV PERL5LIB="/opt/otobo/local/lib/perl5:${PERL5LIB}"
  ENV PATH="/opt/otobo/local/bin:${PATH}"
  
  # Make sure that /opt/otobo exists and is writable by $OTOBO_USER.
  # set up entrypoint.sh and docker_firsttime
  # Finally set permissions. Explicitly pass --runs-under-docker as
  # $ENV{OTOBO_RUNS_UNDER_DOCKER} is not yet set.
  RUN install --owner $OTOBO_USER --group $OTOBO_GROUP -D bin/docker/entrypoint.sh /opt/otobo_install/entrypoint.sh\
   && install --owner $OTOBO_USER --group $OTOBO_GROUP /dev/null docker_firsttime\
   && perl bin/otobo.SetPermissions.pl --runs-under-docker
  
  # perform build steps that can be done as the user otobo.
  USER $OTOBO_USER
  
  # More setup that can be done by the user otobo
  
  # Under Docker the Elasticsearch Daemon is running on the host 'elastic' instead of '127.0.0.1'.
  # The webservice configuration is in a YAML file and it is not obvious how
  # to change settings for webservices.
  # So we take the easy was out and do the change directly in the XML file,
  # before installer.pl has run.
  # Doing this already in the initial database insert allows installer.pl
  # to pick up the changed host and to check whether Elasticsearch is available.
  RUN perl -p -i.orig -e "s{Host: http://localhost:9200}{Host: http://elastic:9200}" scripts/database/otobo-initial_insert.xml
  
  # Activate SysConfig settings that should override that defaults when running in Docker.
  RUN cp Kernel/Config/Files/XML/DockerConfig.xml.dist Kernel/Config/Files/XML/DockerConfig.xml
  
  # Create dirs.
  # Enable bash completion.
  # Add a .vimrc.
  # make Docker image identifyable via the files git-(repo|branch|commit).txt
  # Create ARCHIVE with hashes of the files in the workdir
  ARG GIT_REPO=unspecified
  ARG GIT_BRANCH=unspecified
  ARG GIT_COMMIT=unspecified
  RUN <<END_BASH bash
      set -eux
  
      install -d var/stats var/packages var/article var/tmp
      (
          echo "# File created by Dockerfile"
          echo ""
          echo "# set up bash completion"
          echo ". ~/.bash_completion"
          echo ""
          echo "# use Page-Up and Page-Down for cycling thru autocomplet suggestions"
          echo "bind '\"\\e[6~\": menu-complete'"
          echo "bind '\"\\e[5~\": menu-complete-backward'"
          echo ""
          echo "# helpers"
          echo "alias ..='cd ..'"
          echo "alias ...='cd ../..'"
      ) >> .bash_aliases
      install -m u=rw,g=r,o=r scripts/vim/.vimrc .vimrc
      (echo $GIT_REPO   > git-repo.txt)
      (echo $GIT_BRANCH > git-branch.txt)
      (echo $GIT_COMMIT > git-commit.txt)
      bin/otobo.CheckSum.pl -a create
  END_BASH
  
  # Up to now we have prepared /opt/otobo_install/otobo_next.
  # Merging /opt/otobo_install/otobo_next and /opt/otobo is left to /opt/otobo_install/entrypoint.sh.
  # Note that for supporting the command 'cron' we need to start as root.
  # For all other commands entrypoint.sh switches to the user otobo.
  WORKDIR $OTOBO_HOME
  
  # Titel is specific for the build target
  LABEL org.opencontainers.image.title='OTOBO'
  
  # These labels change with every build
  ARG BUILD_DATE=unspecified
  LABEL org.opencontainers.image.created=$BUILD_DATE
  LABEL org.opencontainers.image.revision=$GIT_COMMIT
  LABEL org.opencontainers.image.source=$GIT_REPO
  ARG DOCKER_TAG=unspecified
  LABEL org.opencontainers.image.version=$DOCKER_TAG
  
  # This Dockerfile also provides for building images with additional support for Kerberos.
  # This image will be built when --target=otobo-web-kerberos is specified in the 'docker build' command.
  FROM base AS otobo-web-kerberos
  
  # First there is some initial setup that needs to be done by root.
  USER root
  
  # install Kerberos related Debian packages
  RUN apt-get update\
   && DEBIAN_FRONTEND=noninteractive apt-get -y --no-install-recommends install\
   "krb5-user"\
   "libpam-krb5"\
   "libpam-ccreds"\
   "krb5-multidev"\
   "libkrb5-dev"\
   && rm -rf /var/lib/apt/lists/*
  
  # append extra modules needed for Kerberos
  # Clean up the .cpanm dir after the installation tasks as that dir is no longer needed
  # and the unpacked Perl distributions sometimes have weird user and group IDs.
  WORKDIR /opt/otobo_install
  RUN <<END_BASH bash
      set -eux
  
      (
          echo "requires 'Authen::Krb5::Simple';"
          echo "requires 'LWP::Authen::Negotiate';"
      ) >> cpanfile
  
      PERL_CPANM_OPT="--local-lib /opt/otobo_install/local"
      /opt/otobo_install/carton install
  
      rm -rf "/root/.cpanm"
  END_BASH
  
  # perform build steps that can be done as the user otobo.
  USER $OTOBO_USER
  
  # skipping /opt/otobo_install/local
  COPY --from=otobo-web\
   /opt/otobo_install/entrypoint.sh\
   /opt/otobo_install
  COPY --from=otobo-web --chown=$OTOBO_USER:$OTOBO_GROUP\
   /opt/otobo_install/otobo_next\
   /opt/otobo_install/otobo_next
  
  WORKDIR $OTOBO_HOME
  
  # Titel is specific for the build target
  LABEL org.opencontainers.image.title='OTOBO Kerberos'
  
  # These labels change with every build
  ARG BUILD_DATE=unspecified
  LABEL org.opencontainers.image.created=$BUILD_DATE
  LABEL org.opencontainers.image.revision=$GIT_COMMIT
  LABEL org.opencontainers.image.source=$GIT_REPO
  ARG DOCKER_TAG=unspecified
  LABEL org.opencontainers.image.version=$DOCKER_TAG
  