From 09d423171a0b71514c5f2802e3c46373c55abbd7 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Fri, 21 Jun 2024 13:09:50 +0200 Subject: [PATCH] feat(modules): run bash module --- .../opt/jboss/container/java/run/run-java.sh | 250 ++++++++++++++++++ .../org.eclipse.jkube.run.bash/configure.sh | 31 +++ .../org.eclipse.jkube.run.bash/module.yaml | 66 +++++ 3 files changed, 347 insertions(+) create mode 100644 modules/org.eclipse.jkube.run.bash/artifacts/opt/jboss/container/java/run/run-java.sh create mode 100644 modules/org.eclipse.jkube.run.bash/configure.sh create mode 100644 modules/org.eclipse.jkube.run.bash/module.yaml diff --git a/modules/org.eclipse.jkube.run.bash/artifacts/opt/jboss/container/java/run/run-java.sh b/modules/org.eclipse.jkube.run.bash/artifacts/opt/jboss/container/java/run/run-java.sh new file mode 100644 index 0000000..f359438 --- /dev/null +++ b/modules/org.eclipse.jkube.run.bash/artifacts/opt/jboss/container/java/run/run-java.sh @@ -0,0 +1,250 @@ +#!/bin/bash + +# Fail on a single failed command +set -eo pipefail + +export JBOSS_CONTAINER_UTIL_LOGGING_MODULE="${JBOSS_CONTAINER_UTIL_LOGGING_MODULE-/opt/jboss/container/util/logging}" +export JBOSS_CONTAINER_JAVA_RUN_MODULE="${JBOSS_CONTAINER_JAVA_RUN_MODULE-/opt/jboss/container/java/run}" + +# Default the application dir to the S2I deployment dir +if [ -z "$JAVA_APP_DIR" ] + then JAVA_APP_DIR=/deployments +fi + +source "$JBOSS_CONTAINER_UTIL_LOGGING_MODULE/logging.sh" + +# ========================================================== +# Generic run script for running arbitrary Java applications +# +# This has forked (and diverged) from: +# at https://github.com/fabric8io/run-java-sh +# +# ========================================================== + +# Error is indicated with a prefix in the return value +check_error() { + local msg=$1 + if echo ${msg} | grep -q "^ERROR:"; then + log_error ${msg} + exit 1 + fi +} + +# detect Quarkus fast-jar package type (OPENJDK-631) +is_quarkus_fast_jar() { + if test -f quarkus-app/quarkus-run.jar; then + log_info "quarkus fast-jar package type detected" + echo quarkus-app/quarkus-run.jar + return 0 + else + return 1 + fi +} + +# Try hard to find a sane default jar-file +auto_detect_jar_file() { + local dir=$1 + + # Filter out temporary jars from the shade plugin which start with 'original-' + local old_dir=$(pwd) + cd ${dir} + if [ $? = 0 ]; then + + if quarkus="$(is_quarkus_fast_jar)"; then + echo "$quarkus" + return + fi + + local nr_jars=`ls *.jar 2>/dev/null | grep -v '^original-' | wc -l | tr -d '[[:space:]]'` + if [ ${nr_jars} = 1 ]; then + ls *.jar | grep -v '^original-' + exit 0 + fi + + log_error "Neither \$JAVA_MAIN_CLASS nor \$JAVA_APP_JAR is set and ${nr_jars} JARs found in ${dir} (1 expected)" + cd ${old_dir} + else + log_error "No directory ${dir} found for auto detection" + fi +} + +# Check directories (arg 2...n) for a jar file (arg 1) +get_jar_file() { + local jar=$1 + shift; + + if [ "${jar:0:1}" = "/" ]; then + if [ -f "${jar}" ]; then + echo "${jar}" + else + log_error "No such file ${jar}" + fi + else + for dir in $*; do + if [ -f "${dir}/$jar" ]; then + echo "${dir}/$jar" + return + fi + done + log_error "No ${jar} found in $*" + fi +} + +load_env() { + # Configuration stuff is read from this file + local run_env_sh="run-env.sh" + + # Load default default config + if [ -f "${JBOSS_CONTAINER_JAVA_RUN_MODULE}/${run_env_sh}" ]; then + source "${JBOSS_CONTAINER_JAVA_RUN_MODULE}/${run_env_sh}" + fi + + # Check also $JAVA_APP_DIR. Overrides other defaults + # It's valid to set the app dir in the default script + if [ -f "${JAVA_APP_DIR}/${run_env_sh}" ]; then + source "${JAVA_APP_DIR}/${run_env_sh}" + fi + + export JAVA_APP_DIR + + # JAVA_LIB_DIR defaults to JAVA_APP_DIR + export JAVA_LIB_DIR="${JAVA_LIB_DIR:-${JAVA_APP_DIR}}" + if [ -z "${JAVA_MAIN_CLASS}" ] && [ -z "${JAVA_APP_JAR}" ]; then + JAVA_APP_JAR="$(auto_detect_jar_file ${JAVA_APP_DIR})" + check_error "${JAVA_APP_JAR}" + fi + + if [ "x${JAVA_APP_JAR}" != x ]; then + local jar="$(get_jar_file ${JAVA_APP_JAR} ${JAVA_APP_DIR} ${JAVA_LIB_DIR})" + check_error "${jar}" + export JAVA_APP_JAR=${jar} + else + export JAVA_MAIN_CLASS + fi +} + +# Combine all java options +get_java_options() { + local jvm_opts + local debug_opts + local proxy_opts + local opts + if [ -f "${JBOSS_CONTAINER_JAVA_JVM_MODULE}/java-default-options" ]; then + jvm_opts=$(${JBOSS_CONTAINER_JAVA_JVM_MODULE}/java-default-options) + fi + if [ -f "${JBOSS_CONTAINER_JAVA_JVM_MODULE}/debug-options" ]; then + debug_opts=$(${JBOSS_CONTAINER_JAVA_JVM_MODULE}/debug-options) + fi + if [ -f "${JBOSS_CONTAINER_JAVA_PROXY_MODULE}/proxy-options" ]; then + source "${JBOSS_CONTAINER_JAVA_PROXY_MODULE}/proxy-options" + proxy_opts="$(proxy_options)" + fi + + opts="${JAVA_OPTS} ${debug_opts} ${proxy_opts} ${jvm_opts} ${JAVA_OPTS_APPEND}" + # Normalize spaces with awk (i.e. trim and eliminate double spaces) + echo "${opts}" | awk '$1=$1' +} + +# Read in a classpath either from a file with a single line, colon separated +# or given line-by-line in separate lines +# Arg 1: path to claspath (must exist), optional arg2: application jar, which is stripped from the classpath in +# multi line arrangements +format_classpath() { + local cp_file="$1" + local app_jar="$2" + + local wc_out=`wc -l $1 2>&1` + if [ $? -ne 0 ]; then + log_error "Cannot read lines in ${cp_file}: $wc_out" + exit 1 + fi + + local nr_lines=`echo $wc_out | awk '{ print $1 }'` + if [ ${nr_lines} -gt 1 ]; then + local sep="" + local classpath="" + while read file; do + local full_path="${JAVA_LIB_DIR}/${file}" + # Don't include app jar if include in list + if [ x"${app_jar}" != x"${full_path}" ]; then + classpath="${classpath}${sep}${full_path}" + fi + sep=":" + done < "${cp_file}" + echo "${classpath}" + else + # Supposed to be a single line, colon separated classpath file + cat "${cp_file}" + fi +} + +# Fetch classpath from env or from a local "run-classpath" file +get_classpath() { + local cp_path="." + if [ "x${JAVA_LIB_DIR}" != "x${JAVA_APP_DIR}" ]; then + cp_path="${cp_path}:${JAVA_LIB_DIR}" + fi + if [ -z "${JAVA_CLASSPATH}" ] && [ "x${JAVA_MAIN_CLASS}" != x ]; then + if [ "x${JAVA_APP_JAR}" != x ]; then + cp_path="${cp_path}:${JAVA_APP_JAR}" + fi + if [ -f "${JAVA_LIB_DIR}/classpath" ]; then + # Classpath is pre-created and stored in a 'run-classpath' file + cp_path="${cp_path}:`format_classpath ${JAVA_LIB_DIR}/classpath ${JAVA_APP_JAR}`" + else + # No order implied + cp_path="${cp_path}:${JAVA_APP_DIR}/*" + fi + elif [ "x${JAVA_CLASSPATH}" != x ]; then + # Given from the outside + cp_path="${JAVA_CLASSPATH}" + fi + echo "${cp_path}" +} + +# Mask secrets before printing +mask_passwords() { + local content="$1" + local result="" + + IFS=' ' read -r -a key_value_pairs <<< "$content" + + for pair in "${key_value_pairs[@]}"; do + key=$(echo "$pair" | cut -d '=' -f 1) + value=$(echo "$pair" | cut -d '=' -f 2-) + + if [[ $key =~ [Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd] ]]; then + result+="$key=***** " + else + result+="$pair " + fi + done + + echo "${result% }" +} + +# Start JVM +startup() { + # Initialize environment + load_env + + local args + cd ${JAVA_APP_DIR} + if [ "x${JAVA_MAIN_CLASS}" != x ] ; then + args="${JAVA_MAIN_CLASS}" + else + args="-jar ${JAVA_APP_JAR}" + fi + + local procname="${JAVA_APP_NAME-java}" + + local masked_opts=$(mask_passwords "$(get_java_options)") + + log_info "exec -a \"${procname}\" java ${masked_opts} -cp \"$(get_classpath)\" ${args} $*" + log_info "running in $PWD" + exec -a "${procname}" java $(get_java_options) -cp "$(get_classpath)" ${args} $* +} + +# ============================================================================= +# Fire up +startup $* diff --git a/modules/org.eclipse.jkube.run.bash/configure.sh b/modules/org.eclipse.jkube.run.bash/configure.sh new file mode 100644 index 0000000..218e0d0 --- /dev/null +++ b/modules/org.eclipse.jkube.run.bash/configure.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# Configure module +set -e + +SCRIPT_DIR=$(dirname $0) +ARTIFACTS_DIR=${SCRIPT_DIR}/artifacts + +chown -R $USER:root $SCRIPT_DIR +chmod -R ug+rwX $SCRIPT_DIR +chmod ug+x ${ARTIFACTS_DIR}/opt/jboss/container/java/run/* + +pushd ${ARTIFACTS_DIR} +cp -pr * / +popd + +mkdir -p /deployments/data \ + && chmod -R "ug+rwX" /deployments/data \ + && chown -R $USER:root /deployments/data + +# OPENJDK-100: turn off negative DNS caching +if [ -w ${JAVA_HOME}/jre/lib/security/java.security ]; then + # JDK8 location + javasecurity="${JAVA_HOME}/jre/lib/security/java.security" +elif [ -w ${JAVA_HOME}/lib/security/java.security ]; then + # JDK8 JRE location + javasecurity="${JAVA_HOME}/lib/security/java.security" +else + # JDK11 location + javasecurity="${JAVA_HOME}/conf/security/java.security" +fi +sed -i 's/\(networkaddress.cache.negative.ttl\)=[0-9]\+$/\1=0/' "$javasecurity" diff --git a/modules/org.eclipse.jkube.run.bash/module.yaml b/modules/org.eclipse.jkube.run.bash/module.yaml new file mode 100644 index 0000000..f0bf71e --- /dev/null +++ b/modules/org.eclipse.jkube.run.bash/module.yaml @@ -0,0 +1,66 @@ +schema_version: 1 +name: org.eclipse.jkube.run.bash +version: 1.0.0 +description: > + Provides support for running Java applications. Basic usage is + $JBOSS_CONTAINER_JAVA_RUN_MODULE/run-java.sh. + + Adapted from: + - https://github.com/jboss-container-images/openjdk/blob/d14ec7f363956b73684409c8b6bd9c766507013b/modules/run/ + - https://github.com/jboss-openshift/cct_module/blob/f91fb2f80dd880ed7498d4dfc3afb35dfcef60bd/jboss/container/java/run/bash/ + +envs: +- name: JBOSS_CONTAINER_JAVA_RUN_MODULE + value: /opt/jboss/container/java/run + +- name: JAVA_APP_DIR + description: ^ + The directory where the application resides. All paths in your application + are relative to this directory. + example: "myapplication/" + +- name: JAVA_MAIN_CLASS + description: ^ + A main class to use as argument for `java`. When this environment variable + is given, all jar files in **JAVA_APP_DIR** are added to the classpath as + well as **JAVA_LIB_DIR**. + example: "com.example.MainClass" + +- name: JAVA_LIB_DIR + description: ^ + Directory holding the Java jar files as well an optional `classpath` file + which holds the classpath. Either as a single line classpath (colon + separated) or with jar files listed line-by-line. If not set + **JAVA_LIB_DIR** is the same as **JAVA_APP_DIR**. + +- name: JAVA_DATA_DIR + description: ^ + The location of the directory which should be used by the application for + reading/writing application data. Users should override the default if + their application should use a different directory, e.g. if a persistent + volume is used to persist data across restarts. + value: "/deployments/data" + example: "/var/cache/application" + +- name: JAVA_CLASSPATH + description: ^ + The classpath to use. If not given, the startup script checks for a file + `**JAVA_APP_DIR/classpath**` and use its content literally as classpath. If + this file doesn't exists all jars in the app dir are added + (`classes:**JAVA_APP_DIR/***`). + +- name: JAVA_ARGS + description: Arguments passed to the `java` application. + +- name: JAVA_APP_NAME + description: To set the process or application name by the user. + +execute: +- script: configure.sh + +modules: + install: + - name: org.eclipse.jkube.user + - name: org.eclipse.jkube.jvm.bash + - name: jboss.container.util.logging.bash + - name: jboss.container.openjdk.jdk