From 0e9573290c09f95693c51d510cb53e90def5ce13 Mon Sep 17 00:00:00 2001 From: Kaur Palang Date: Wed, 25 Jun 2025 21:09:58 +0300 Subject: [PATCH 1/3] #40 Add initial Dockerfile Signed-off-by: Kaur Palang --- docker/.dockerignore | 2 + docker/Dockerfile | 129 ++++++++++++++++++++++ docker/build-images.sh | 13 +++ docker/entrypoint.sh | 244 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 docker/.dockerignore create mode 100644 docker/Dockerfile create mode 100755 docker/build-images.sh create mode 100755 docker/entrypoint.sh diff --git a/docker/.dockerignore b/docker/.dockerignore new file mode 100644 index 000000000..ad5c94e26 --- /dev/null +++ b/docker/.dockerignore @@ -0,0 +1,2 @@ +* +!entrypoint.sh \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..4a95c29f9 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,129 @@ +# syntax=docker/dockerfile:1 + +ARG ALPINE_JRE_TAG=17.0.15_6-jre-alpine +ARG ALPINE_JDK_TAG=17.0.15_6-jdk-alpine +ARG UBUNTU_JRE_TAG=17.0.15_6-jre-noble +ARG UBUNTU_JDK_TAG=17.0.15_6-jdk-noble + +ARG UID=14285 +ARG GID=14285 + +FROM alpine:3.21.3 AS downloader + +ARG UID +ARG GID + +WORKDIR /opt + +# Download Open Integration Engine release +RUN apk add --no-cache curl \ + && curl -L \ + -o /opt/engine.tar.gz \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://github.com/OpenIntegrationEngine/engine/releases/download/v4.5.2-tp.1/oie_unix_4_5_2.tar.gz \ + && tar xzf engine.tar.gz \ + && mv /opt/oie /opt/engine \ + && mkdir -p /opt/engine/appdata + +WORKDIR /opt/engine +COPY --chmod=755 ./entrypoint.sh /opt/engine/entrypoint + +RUN rm -rf cli-lib manager-lib \ + && rm mirth-cli-launcher.jar oiecommand + +RUN (cat oieserver.vmoptions docs/oieservice-java9+.vmoptions ; echo "") > oieserver_base.vmoptions + +RUN chown -R ${UID}:${GID} /opt/engine + +########################################## +# +# Alpine Images +# +########################################## + +FROM eclipse-temurin:$ALPINE_JRE_TAG AS alpine-jre + +ARG UID +ARG GID + +COPY --from=downloader /opt/engine /opt/engine + +RUN adduser -D -H -u $UID engine \ + && apk add --no-cache bash + +VOLUME /opt/engine/appdata +VOLUME /opt/engine/custom-extensions +WORKDIR /opt/engine + +EXPOSE 8443 + +USER engine +ENTRYPOINT ["./entrypoint"] +CMD ["./oieserver"] + +FROM eclipse-temurin:$ALPINE_JDK_TAG AS alpine-jdk + +ARG UID +ARG GID + +COPY --from=downloader /opt/engine /opt/engine + +RUN adduser -D -H -u $UID engine \ + && apk add --no-cache bash + +VOLUME /opt/engine/appdata +VOLUME /opt/engine/custom-extensions +WORKDIR /opt/engine + +EXPOSE 8443 + +USER engine +ENTRYPOINT ["./entrypoint"] +CMD ["./oieserver"] + +########################################## +# +# Ubuntu Images +# +########################################## + +FROM eclipse-temurin:$UBUNTU_JRE_TAG AS ubuntu-jre + +ARG UID +ARG GID + +COPY --from=downloader /opt/engine /opt/engine + +RUN groupadd --gid ${GID} engine \ + && useradd -u ${UID} -g ${GID} -M engine + +VOLUME /opt/engine/appdata +VOLUME /opt/engine/custom-extensions +WORKDIR /opt/engine + +EXPOSE 8443 + +USER engine +ENTRYPOINT ["./entrypoint"] +CMD ["./oieserver"] + +FROM eclipse-temurin:$UBUNTU_JDK_TAG AS ubuntu-jdk + +ARG UID +ARG GID + +COPY --from=downloader /opt/engine /opt/engine + +RUN groupadd --gid ${GID} engine \ + && useradd -u ${UID} -g ${GID} -M engine + +VOLUME /opt/engine/appdata +VOLUME /opt/engine/custom-extensions +WORKDIR /opt/engine + +EXPOSE 8443 + +USER engine +ENTRYPOINT ["./entrypoint"] +CMD ["./oieserver"] \ No newline at end of file diff --git a/docker/build-images.sh b/docker/build-images.sh new file mode 100755 index 000000000..71f4c4a25 --- /dev/null +++ b/docker/build-images.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +# Build alpine-jre image +docker build -f Dockerfile --target alpine-jre -t openintegrationengine/engine:latest-alpine-jre . +# Build ubuntu-jre image +docker build -f Dockerfile --target ubuntu-jre -t openintegrationengine/engine:latest-ubuntu-jre . + +# Build alpine-jdk image +docker build -f Dockerfile --target alpine-jdk -t openintegrationengine/engine:latest-alpine-jdk . +# Build ubuntu-jdk image +docker build -f Dockerfile --target ubuntu-jdk -t openintegrationengine/engine:latest-alpine-jdk . \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 000000000..d7a4cb891 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,244 @@ +#!/bin/bash +set -e + +APP_DIR=/opt/engine + +custom_extension_count=`ls -1 "$APP_DIR"/custom-extensions/*.zip 2>/dev/null | wc -l` +if [ $custom_extension_count != 0 ]; then + echo "Found ${custom_extension_count} custom extensions." + for extension in $(ls -1 "$APP_DIR"/custom-extensions/*.zip); do + unzip -o -q $extension -d "$APP_DIR/extensions" + done +fi + +# set storepass and keypass to 'changeme' so they aren't overwritten later +KEYSTORE_PASS=changeme +sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_PASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" +sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_PASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" + +# merge the environment variables into /opt/engine/conf/mirth.properties +# db type +if ! [ -z "${DATABASE+x}" ]; then + sed -i "s/^database\s*=\s*.*\$/database = ${DATABASE//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# db username +if ! [ -z "${DATABASE_USERNAME+x}" ]; then + sed -i "s/^database\.username\s*=\s*.*\$/database.username = ${DATABASE_USERNAME//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# db password +if ! [ -z "${DATABASE_PASSWORD+x}" ]; then + sed -i "s/^database\.password\s*=\s*.*\$/database.password = ${DATABASE_PASSWORD//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# db url +if ! [ -z "${DATABASE_URL+x}" ]; then + sed -i "s/^database\.url\s*=\s*.*\$/database.url = ${DATABASE_URL//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# database max connections +if ! [ -z "${DATABASE_MAX_CONNECTIONS+x}" ]; then + sed -i "s/^database\.max-connections\s*=\s*.*\$/database.max-connections = ${DATABASE_MAX_CONNECTIONS//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# database max retries +if ! [ -z "${DATABASE_MAX_RETRY+x}" ]; then + sed -i "s/^database\.connection\.maxretry\s*=\s*.*\$/database.connection.maxretry = ${DATABASE_MAX_RETRY//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# database retry wait time +if ! [ -z "${DATABASE_RETRY_WAIT+x}" ]; then + sed -i "s/^database\.connection\.retrywaitinmilliseconds\s*=\s*.*\$/database.connection.retrywaitinmilliseconds = ${DATABASE_RETRY_WAIT//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# keystore storepass +if ! [ -z "${KEYSTORE_STOREPASS+x}" ]; then + sed -i "s/^keystore\.storepass\s*=\s*.*\$/keystore.storepass = ${KEYSTORE_STOREPASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# keystore keypass +if ! [ -z "${KEYSTORE_KEYPASS+x}" ]; then + sed -i "s/^keystore\.keypass\s*=\s*.*\$/keystore.keypass = ${KEYSTORE_KEYPASS//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +if ! [ -z "${KEYSTORE_TYPE+x}" ]; then + sed -i "s/^keystore\.type\s*=\s*.*\$/keystore.type = ${KEYSTORE_TYPE//\//\\/}/" "$APP_DIR/conf/mirth.properties" +fi + +# session store +if ! [ -z "${SESSION_STORE+x}" ]; then + LINE_COUNT=`grep "server.api.sessionstore" "$APP_DIR/conf/mirth.properties" | wc -l` + if [ $LINE_COUNT -lt 1 ]; then + echo -e "\nserver.api.sessionstore = ${SESSION_STORE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" + else + sed -i "s/^server\.api\.sessionstore\s*=\s*.*\$/server.api.sessionstore = ${SESSION_STORE//\//\\/}/" "$APP_DIR/conf/mirth.properties" + fi +fi + +#server ID +if ! [ -z "${SERVER_ID+x}" ]; then + echo -e "server.id = ${SERVER_ID//\//\\/}" > "$APP_DIR/appdata/server.id" +fi + +# merge extra environment variables starting with _MP_ into mirth.properties +while read -r keyvalue; do + KEY="${keyvalue%%=*}" + VALUE="${keyvalue#*=}" + VALUE=$(tr -dc '\40-\176' <<< "$VALUE") + + if ! [ -z "${KEY}" ] && ! [ -z "${VALUE}" ] && ! [[ ${VALUE} =~ ^\ +$ ]]; then + + # filter for variables starting with "_MP_" + if [[ ${KEY} == _MP_* ]]; then + + # echo "found property ${KEY}=${VALUE}" + + # example: _MP_DATABASE_MAX__CONNECTIONS -> database.max-connections + + # remove _MP_ + # example: DATABASE_MAX__CONNECTIONS + ACTUAL_KEY=${KEY:4} + + # switch '__' to '-' + # example: DATABASE_MAX-CONNECTIONS + ACTUAL_KEY="${ACTUAL_KEY//__/-}" + + # switch '_' to '.' + # example: DATABASE.MAX-CONNECTIONS + ACTUAL_KEY="${ACTUAL_KEY//_/.}" + + # lower case + # example: database.max-connections + ACTUAL_KEY="${ACTUAL_KEY,,}" + + # if key does not exist in mirth.properties append it at bottom + LINE_COUNT=`grep "^${ACTUAL_KEY}" "$APP_DIR/conf/mirth.properties" | wc -l` + if [ $LINE_COUNT -lt 1 ]; then + # echo "key ${ACTUAL_KEY} not found in mirth.properties, appending. Value = ${VALUE}" + echo -e "\n${ACTUAL_KEY} = ${VALUE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" + else # otherwise key exists, overwrite it + # echo "key ${ACTUAL_KEY} exists, overwriting. Value = ${VALUE}" + ESCAPED_KEY="${ACTUAL_KEY//./\\.}" + sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${ACTUAL_KEY} = ${VALUE//\//\\/}/" "$APP_DIR/conf/mirth.properties" + fi + fi + fi +done <<< "`printenv`" + +cp oieserver_base.vmoptions oieserver.vmoptions + +# Address reflective access by Jackson +echo "--add-opens=java.desktop/java.awt.color=ALL-UNNAMED" >> oieserver.vmoptions + +# merge vmoptions into /opt/engine/oieserver.vmoptions +if ! [ -z "${VMOPTIONS+x}" ]; then + PREV_IFS="$IFS" + IFS="," + read -ra vmoptions <<< "$VMOPTIONS" + IFS="$PREV_IFS" + + for vmoption in "${vmoptions[@]}" + do + echo "${vmoption}" >> "$APP_DIR/oieserver.vmoptions" + done +fi + +# merge the user's secret mirth.properties +# takes a whole mirth.properties file and merges line by line with /opt/engine/conf/mirth.properties +if [ -f /run/secrets/mirth_properties ]; then + + # add new line in case /opt/engine/conf/mirth.properties doesn't end with one + echo "" >> "$APP_DIR/conf/mirth.properties" + + while read -r keyvalue; do + KEY="${keyvalue%%=*}" + VALUE="${keyvalue#*=}" + + # remove leading and trailing white space + KEY="$(echo -e "${KEY}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + VALUE="$(echo -e "${VALUE}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + + if ! [ -z "${KEY}" ] && ! [ -z "${VALUE}" ] && ! [[ ${VALUE} =~ ^\ +$ ]]; then + # if key does not exist in mirth.properties append it at bottom + LINE_COUNT=`grep "^${KEY}" "$APP_DIR/conf/mirth.properties" | wc -l` + if [ $LINE_COUNT -lt 1 ]; then + # echo "key ${KEY} not found in mirth.properties, appending. Value = ${VALUE}" + echo -e "${KEY} = ${VALUE//\//\\/}" >> "$APP_DIR/conf/mirth.properties" + else # otherwise key exists, overwrite it + # echo "key ${KEY} exists, overwriting. Value = ${VALUE}" + ESCAPED_KEY="${KEY//./\\.}" + sed -i "s/^${ESCAPED_KEY}\s*=\s*.*\$/${KEY} = ${VALUE//\//\\/}/" "$APP_DIR/conf/mirth.properties" + fi + fi + done <<< "`cat /run/secrets/mirth_properties`" +fi + +# merge the user's secret vmoptions +# takes a whole oieserver.vmoptions file and merges line by line with /opt/engine/oieserver.vmoptions +if [ -f /run/secrets/oieserver_vmoptions ]; then + (cat /run/secrets/oieserver_vmoptions ; echo "") >> "$APP_DIR/oieserver.vmoptions" +fi + +# download jars from this url "$CUSTOM_JARS_DOWNLOAD", set by user +if ! [ -z "${CUSTOM_JARS_DOWNLOAD+x}" ]; then + echo "Downloading Jars at ${CUSTOM_JARS_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" + else + curl -sSLf "${CUSTOM_JARS_DOWNLOAD}" -o userJars.zip || echo "problem with custom jars download" + fi + + # Unzipping contents of userJars.zip into /opt/engine/server-launcher-lib folder + if [ -e "userJars.zip" ]; then + echo "Unzipping contents of userJars.zip into $APP_DIR/server-launcher-lib" + unzip userJars.zip -d "$APP_DIR/server-launcher-lib" + # removing the downloaded zip file + rm userJars.zip + fi +fi + +# download extensions from this url "$EXTENSIONS_DOWNLOAD", set by user +if ! [ -z "${EXTENSIONS_DOWNLOAD+x}" ]; then + echo "Downloading extensions at ${EXTENSIONS_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" + else + curl -sSLf "${EXTENSIONS_DOWNLOAD}" -o userExtensions.zip || echo "problem with extensions download" + fi + + # Unzipping contents of userExtensions.zip + if [ -e "userExtensions.zip" ]; then + echo "Unzipping contents of userExtensions.zip" + mkdir /tmp/userextensions + unzip userExtensions.zip -d /tmp/userextensions + # removing the downloaded zip file + rm userExtensions.zip + + # Unzipping contents of individual extension zip files into /opt/engine/extensions folder + zipFileCount=`ls -1 /tmp/userextensions/*.zip 2>/dev/null | wc -l` + if [ $zipFileCount != 0 ]; then + echo "Unzipping contents of /tmp/userextensions/ zips into $APP_DIR/extensions" + for f in /tmp/userextensions/*.zip; do unzip "$f" -d "$APP_DIR/extensions"; done + fi + # removing the tmp folder + rm -rf /tmp/userextensions + fi +fi + +# download keystore +if ! [ -z "${KEYSTORE_DOWNLOAD+x}" ]; then + echo "Downloading keystore at ${KEYSTORE_DOWNLOAD}" + if ! [ -z "${ALLOW_INSECURE}" ] && [ "${ALLOW_INSECURE}" == "true" ]; then + curl -ksSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" + else + curl -sSLf "${KEYSTORE_DOWNLOAD}" -o "$APP_DIR/appdata/keystore.jks" || echo "problem with keystore download" + fi +fi + +# if delay is set as an environment variable then wait that long in seconds +if ! [ -z "${DELAY+x}" ]; then + sleep $DELAY +fi + +exec "$@" \ No newline at end of file From 1babeff4c3ab32c56d0560b91494c1d41d626fad Mon Sep 17 00:00:00 2001 From: Kaur Palang Date: Wed, 25 Jun 2025 21:46:30 +0300 Subject: [PATCH 2/3] #40 Add license header to entrypoint.sh Signed-off-by: Kaur Palang --- docker/entrypoint.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index d7a4cb891..84b57adef 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,4 +1,9 @@ -#!/bin/bash +#!/usr/bin/env bash +# +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2023 NextGen Healthcare +# + set -e APP_DIR=/opt/engine From d892f835f7ac553207c26915dd274f999788505e Mon Sep 17 00:00:00 2001 From: Kaur Palang Date: Wed, 25 Jun 2025 21:54:19 +0300 Subject: [PATCH 3/3] #40 Add github actions workflow Signed-off-by: Kaur Palang --- .github/workflows/build-container.yaml | 26 ++++++++++++++++++++++++++ .github/workflows/build.yaml | 4 ++++ 2 files changed, 30 insertions(+) create mode 100644 .github/workflows/build-container.yaml diff --git a/.github/workflows/build-container.yaml b/.github/workflows/build-container.yaml new file mode 100644 index 000000000..a5164808b --- /dev/null +++ b/.github/workflows/build-container.yaml @@ -0,0 +1,26 @@ +name: Build OpenIntegrationEngine Container + +on: + push: + branches: + - main + paths: + - docker + pull_request: + branches: + - main + paths: + - docker + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Build Container + working-directory: docker/ + run: ./build-images.sh + + - run: docker image ls \ No newline at end of file diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 486e29f11..ceb301b03 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,9 +4,13 @@ on: push: branches: - main + paths-ignore: + - docker pull_request: branches: - main + paths-ignore: + - docker jobs: build: