Skip to content

Commit

Permalink
feat(modules): run bash module
Browse files Browse the repository at this point in the history
  • Loading branch information
manusa committed Jun 21, 2024
1 parent 6de4070 commit 09d4231
Show file tree
Hide file tree
Showing 3 changed files with 347 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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 $*
31 changes: 31 additions & 0 deletions modules/org.eclipse.jkube.run.bash/configure.sh
Original file line number Diff line number Diff line change
@@ -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"
66 changes: 66 additions & 0 deletions modules/org.eclipse.jkube.run.bash/module.yaml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 09d4231

Please sign in to comment.