Skip to content

Instantly share code, notes, and snippets.

@ryanlfoster
Forked from FredIde/aem-control.sh
Created March 20, 2017 17:36
Show Gist options
  • Save ryanlfoster/8a33d358fefbd0cb7d90f0dd294a8d3f to your computer and use it in GitHub Desktop.
Save ryanlfoster/8a33d358fefbd0cb7d90f0dd294a8d3f to your computer and use it in GitHub Desktop.
#!/bin/bash
#set -x
#==========================================================================
# NAME
# aem-control - start, stop, restart or check the status of
# an AEM instance (>= 5.5.0)
#
# SYNOPSIS
# aem-control [start|stop|restart|status|activate|sweep|help|version]
#
# DESCRIPTION
# Starts, stops, restartes or checks the status of a AEM instance.
#
# Mandatory command line arguments are
#
# start Start the Adobe AEM service
# stop Stop the Adobe AEM service
# restart Restart the Adobe AEM service
# status Check the status of the Adobe AEM service
# activate Activate all resolved Apache Felix bundles
# sweep Run memory garbage collection
# help Display usage information
# version Display version information
#
# FILES
# A configuration file "../etc/aem-control.conf" is required to provide
# the following configuration variables:
#
# USERNAME
# Operating system user to run this script as
#
# JAVA_HOME
# Home directory of Java JDK
#
# JAVA_LANG
# Value of LANG environment variable to be passed to Java
# (e.g. 'en_US.UTF-8')
#
# JAVA_TZ
# Value of TZ environment variable to be passed to Java
# (e.g. 'UTC')
#
# JAVA_EXTRA_OPT_ARRAY
# JVM extra options to use (garbage collector etc.)
#
# AEM_HOME
# AEM home directory (the directory in which the 'crx-quickstart'
# directory resides)
#
# AEM_ADDRESS
# AEM listen address (usually '0.0.0.0' for all interfaces, otherwise
# IP address of specific interface)
#
# AEM_PORT
# AEM port number (usually 4502 for author and 4503 for publish
# instances)
#
# AEM_USERNAME
# Username of the administrative AEM user (usually 'admin')
#
# AEM_PASSWORD
# Password of the administrative AEM user
#
# AEM_RUN_MODES
# Comma-delimited list of AEM run modes (must either contain 'author' or 'publish')
#
# LOG_HOME
# Home directory for AEM log directories
#
# LOG_HISTORY
# Maximum number of log directories to keep
#
# CONNECT_TIMEOUT
# Maximum number of seconds to wait for network connection
# to be established (default is 5 seconds)
#
# SOCKET_TIMEOUT
# Maximum number of seconds to wait for a complete response
# from a host after a request was sent (default is 120 seconds)
#
# START_TIMEOUT
# Timeout for AEM service to start in seconds (default is 600 seconds)
#
# STOP_TIMEOUT
# Timeout for AEM service to stop in seconds (default is 1800 seconds)
#
# CHECK_DELAY
# Delay in between successive functional checks in seconds
# (default is 10 seconds)
#
# SYSLOG_FACILITY
# Syslog facility to use (default is 'local0')
#
# COPYRIGHT
# Apache License V2
# All rights reserved.
#
# AUTHORS
# Fred Ide
#
# CHANGE HISTORY
# 2013-04-26 mk@dvu.eu
# Initial release
# 2015-10-12 FAI
# Bug fixing
#==========================================================================
#--------------------------------------------------------------------------
# NAME
# whence - search for a command and return its absolute file name
#
# SYNOPSIS
# whence [command]
#
# DESCRIPTION
# Searches for a command and returns its absolute file name
#--------------------------------------------------------------------------
declare -r PATH='/sbin:/bin:/usr/sbin:/usr/bin'
whence() {
local -r COMMAND_NAME="$1"
local COMMAND_FILE
# Search PATH for command
COMMAND_FILE="$(type -p "$COMMAND_NAME" 2>/dev/null)"
if [[ -x "$COMMAND_FILE" ]]; then
# Found
echo "$COMMAND_FILE"
else
# Not found
echo -n "Error: \"$COMMAND_NAME\" - command not found" >/dev/tty
kill -2 $$
fi
}
# Declare absolute file names of all external commands used by this script
declare -r CAT="$(whence cat)"
declare -r CURL="$(whence curl)"
declare -r DATE="$(whence date)"
declare -r ENV="$(whence env)"
declare -r FIND="$(whence find)"
declare -r GREP="$(whence grep)"
declare -r HOSTNAME="$(whence hostname)"
declare -r ID="$(whence id)"
declare -r IFCONFIG="$(whence ifconfig)"
declare -r LN="$(whence ln)"
declare -r LOGGER="$(whence logger)"
declare -r MKDIR="$(whence mkdir)"
declare -r MV="$(whence mv)"
declare -r NOHUP="$(whence nohup)"
declare -r PGREP="$(whence pgrep)"
declare -r READLINK="$(whence readlink)"
declare -r RM="$(whence rm)"
declare -r RMDIR="$(whence rmdir)"
declare -r SLEEP="$(whence sleep)"
declare -r SORT="$(whence sort)"
declare -r SU="$(whence su)"
declare -r TAIL="$(whence tail)"
#--------------------------------------------------------------------------
# NAME
# real_path - return the canonicalized absolute pathname of a given
# pathname
#
# SYNOPSIS
# real_path [pathname]
#
# DESCRIPTION
# Expands all symbolic links and resolves references to /./, /../ and
# extra '/' characters in the specified pathname to produce a
# canonicalized absolute pathname. If the specified pathname is invalid,
# the function will set the return code to 1.
#--------------------------------------------------------------------------
real_path() {
local -r REL_PATH="$1"
local ABS_PATH
ABS_PATH="$("$READLINK" -f "$REL_PATH" 2>/dev/null)"
if [[ -z "$ABS_PATH" ]]; then
echo "$REL_PATH"
return 1
fi
echo "$ABS_PATH"
return 0
}
#--------------------------------------------------------------------------
# Global Variables
#--------------------------------------------------------------------------
# General constants
declare -r LF=$'\n'
# Declare and initialize script-releated variables
declare -r MY_VERSION='1.3.0'
declare -r MY_SCRIPT_FILE="$(real_path "$0")"
declare -r MY_SCRIPT_NAME="${MY_SCRIPT_FILE##*/}"
declare -r MY_SCRIPT_DIR="${MY_SCRIPT_FILE%/*}"
declare -r MY_SCRIPT_ARGS="$@"
declare -r MY_FQDN="$("$HOSTNAME" -f 2>/dev/null)"
declare -ri MY_PID=$$
declare -r MY_CWD="$PWD"
declare -r MY_IFS="$IFS"
declare -r MY_TIMESTAMP="$("$DATE" -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null)"
declare MY_LOCK_FILE="/tmp/.${MY_SCRIPT_NAME}.lock"
# Declare configuration file variables
declare USERNAME
declare JAVA_HOME
declare JAVA_LANG='en_US.UTF-8'
declare JAVA_TZ='UTC'
declare JAVA_HEAP_SIZE
declare JAVA_PERM_SIZE
declare -a JAVA_EXTRA_OPT_ARRAY
declare AEM_HOME
declare AEM_ADDRESS='0.0.0.0' # default to all interfaces
declare AEM_PORT=4502 # default to port 4502
declare AEM_USERNAME='admin' # default to 'admin'
declare AEM_PASSWORD='admin' # default to 'admin'
declare AEM_RUN_MODES='author' # default to 'author'
declare AEM_UMASK='0022'
declare -a AEM_EXTRA_OPT_ARRAY
declare LOG_HOME
declare LOG_HISTORY=7 # default to 7 days
declare CONNECT_TIMEOUT=5 # default to 5 seconds
declare SOCKET_TIMEOUT=120 # default to 2 minutes
declare START_TIMEOUT=1800 # default to 30 minutes
declare -a SKIP_BUNDLE_ARRAY
declare SKIP_BUNDLE_REGEX
declare STOP_TIMEOUT=1800 # default to 30 minutes
declare CHECK_DELAY=10 # Default to 10 seconds
declare SYSLOG_FACILITY='local0' # default to 'local0'
# Declare internal variables
declare CONF_FILE
declare JAVA
declare AEM_BASE_DIR
declare AEM_JAR_FILE
declare AEM_INSTANCE_NAME
declare AEM_AUTHORITY
declare AEM_CREDENTIALS
declare AEM_PID
#--------------------------------------------------------------------------
# NAME
# version - print version information and exit
#
# SYNOPSIS
# version
#
# DESCRIPTION
# Writes version information to standard output and terminates the script
# with error code 0.
#--------------------------------------------------------------------------
version() {
echo ''
echo "$MY_SCRIPT_NAME version $MY_VERSION"
echo ''
echo 'Copyright (c) 2013-2015 Digital Venture Unternehmensberatung GmbH'
echo 'All rights reserved.'
echo ''
exit 0
}
#--------------------------------------------------------------------------
# NAME
# usage - print usage information and exit
#
# SYNOPSIS
# usage [exit_code]
#
# DESCRIPTION
# Writes usage information to standard output and terminates the script
# with the specified error code or the default exit code 2.
#--------------------------------------------------------------------------
usage() {
local -ri EXIT_CODE=${1:-2}
echo ''
echo "Usage: $MY_SCRIPT_NAME [start|stop|restart|status|help|version] (first)"
echo ''
echo 'Mandatory Arguments:'
echo 'start Start the Adobe AEM service'
echo 'stop Stop the Adobe AEM service'
echo 'restart Restart the Adobe AEM service'
echo 'status Check the status of the Adobe AEM service'
echo 'activate Activate all installed/resolved Apache Felix bundles'
echo 'sweep Run memory garbage collection'
echo 'help Display this message'
echo 'version Display version information'
echo ''
exit $EXIT_CODE
}
#--------------------------------------------------------------------------
# NAME
# log - print and log messages
#
# SYNOPSIS
# log [severity] [message...]
#
# DESCRIPTION
# Writes the specified message to the respecitve log.
#--------------------------------------------------------------------------
log() {
local SYSLOG_SEVERITY="$1"
local SEVERITY
local LINE
case "$SYSLOG_SEVERITY" in
'emerg')
# Emergency: system is unusable
SEVERITY='Emergency'
;;
'alert')
# Alert: action must be taken immediately
SEVERITY='Alert'
;;
'crit')
# Critical: critical condition
SEVERITY='Critical'
;;
'err')
# Error: error condition
SEVERITY='Error'
;;
'warning')
# Warning: warning condition
SEVERITY='Warning'
;;
'notice')
# Notice: normal but significant condition
SEVERITY='Notice'
;;
'info')
# Informational: informational message
SEVERITY='Info'
;;
'debug')
# Debug: debug-level message
SEVERITY='Debug'
;;
*)
# Invalid severity
SYSLOG_SEVERITY='err'
SEVERITY='Unknown severity'
;;
esac
shift
echo "$SEVERITY: $1"
"$LOGGER" \
-p $SYSLOG_FACILITY.$SYSLOG_SEVERITY \
-t "$MY_SCRIPT_NAME" \
-i "$SEVERITY: $1" \
&>/dev/null
shift
while (( $# > 0 )); do
IFS="$LF"
for LINE in $1; do
if [[ -n "$LINE" ]]; then
echo "Details: $LINE"
"$LOGGER" \
-p $SYSLOG_FACILITY.$SYSLOG_SEVERITY \
-t "$MY_SCRIPT_NAME" \
-i "Details: $LINE" \
&>/dev/null
fi
done
IFS="$MY_IFS"
shift
done
}
#--------------------------------------------------------------------------
# NAME
# crit - print critical error message and exit
#
# SYNOPSIS
# crit [message...]
#
# DESCRIPTION
# Writes the specified error message to standard error and
# terminates the script with the specified error code.
#--------------------------------------------------------------------------
crit() {
log 'crit' "$@" 1>&2
exit 1
}
#--------------------------------------------------------------------------
# NAME
# err - print error message
#
# SYNOPSIS
# err [message...]
#
# DESCRIPTION
# Writes the specified error message to standard error.
#--------------------------------------------------------------------------
err() {
log 'err' "$@" 1>&2
}
#--------------------------------------------------------------------------
# NAME
# warning - print warning message
#
# SYNOPSIS
# warning [message...]
#
# DESCRIPTION
# Writes the specified warning message to standard error.
#--------------------------------------------------------------------------
warning() {
log 'warning' "$@" 1>&2
}
#--------------------------------------------------------------------------
# NAME
# notice - print notification message
#
# SYNOPSIS
# notice [message...]
#
# DESCRIPTION
# Writes the specified notification message to standard output.
#--------------------------------------------------------------------------
notice() {
log 'notice' "$@"
}
#--------------------------------------------------------------------------
# NAME
# info - print informational message
#
# SYNOPSIS
# info [message...]
#
# DESCRIPTION
# Writes the specified informational message to standard output.
#--------------------------------------------------------------------------
info() {
log 'info' "$@"
}
#--------------------------------------------------------------------------
# NAME
# lock - exit if there is an existing lock file or create a lock file
#
# SYNOPSIS
# lock
#
# DESCRIPTION
# Checks if there is an existing lock file and exits if the PID of the
# locking process is still alive. Otherwise, a lock file is created.
#--------------------------------------------------------------------------
lock() {
local PID
# Check if there is an existing lock file
if [[ -f "$MY_LOCK_FILE" ]]; then
if [[ -r "$MY_LOCK_FILE" ]]; then
# Check if process is still running
PID=$("$CAT" "$MY_LOCK_FILE")
if [[ "$PID" =~ ^[1-9][0-9]*$ ]]; then
kill -0 "$PID" &>/dev/null
if (( $? == 0 )); then
# Process is still running
crit "\"$MY_SCRIPT_NAME\" is locked by PID $PID"
fi
fi
else
# Process is bein run by someone else
crit "\"$MY_SCRIPT_NAME\" is being run by another user"
fi
fi
# Create new lock file
echo -n "$MY_PID" 1>"$MY_LOCK_FILE"
}
#--------------------------------------------------------------------------
# NAME
# unlock - delete lock file
#
# SYNOPSIS
# unlock
#
# DESCRIPTION
# Deletes the lock file.
#--------------------------------------------------------------------------
unlock() {
"$RM" -f "$MY_LOCK_FILE" &>/dev/null
}
#--------------------------------------------------------------------------
# NAME
# check_mode - check the permissions of a file or directory
#
# SYNOPSIS
# check_mode [item] [f][d][r][w][x]
#
# DESCRIPTION
# Checks if the specified file or directory possesses the specified
# permissions
#--------------------------------------------------------------------------
check_mode() {
local ITEM="$1"
local FLAGS="$2"
if [[ "$FLAGS" == *f* ]]; then
if [[ ! -f "$ITEM" ]]; then
crit "File \"$ITEM\" not found"
fi
fi
if [[ "$FLAGS" == *d* ]]; then
if [[ ! -d "$ITEM" ]]; then
crit "Directory \"$ITEM\" not found"
fi
fi
if [[ "$FLAGS" == *r* ]]; then
if [[ ! -r "$ITEM" ]]; then
crit "No read permission for \"$ITEM\""
fi
fi
if [[ "$FLAGS" == *w* ]]; then
if [[ ! -w "$ITEM" ]]; then
crit "No write permission for \"$ITEM\""
fi
fi
if [[ "$FLAGS" == *x* ]]; then
if [[ ! -x "$ITEM" ]]; then
crit "No execute permission for \"$ITEM\""
fi
fi
}
#--------------------------------------------------------------------------
# NAME
# check_if_addr - check interface address
#
# SYNOPSIS
# check_if_addr [if_addr]
#
# DESCRIPTION
# Checks whether or not the specified interface address belongs to this
# host.
#--------------------------------------------------------------------------
check_if_addr() {
local -r IF_ADDR="$1"
local REGEX
local -a LINE_ARRAY
local LINE
local ADDR
# Check if the specified address references all interfaces
if [[ "$IF_ADDR" == '0.0.0.0' ]]; then
return
fi
# Check if the specified address references an existing interface
IFS="$LF"
LINE_ARRAY=( $("$IFCONFIG" -a 2>/dev/null) )
IFS="$MY_IFS"
REGEX='inet[[:blank:]]+(addr:)?([[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})'
for LINE in "${LINE_ARRAY[@]}"; do
if [[ "$LINE" =~ $REGEX ]]; then
ADDR="${BASH_REMATCH[2]}"
if [[ "$IF_ADDR" == "$ADDR" ]]; then
return
fi
fi
done
crit "The interface address \"$IF_ADDR\" does not belong to this host"
}
#--------------------------------------------------------------------------
# NAME
# load_config - load configuration file
#
# SYNOPSIS
# load_config
#
# DESCRIPTION
# Sources configuration variables from a configuration file.
#--------------------------------------------------------------------------
load_config() {
# Assemble absolute pathname of configuration directory
local -r CONF_DIR="$(real_path "$MY_SCRIPT_DIR/../etc")"
# Assemble name of configuration file
local -r CONF_NAME="${MY_SCRIPT_NAME%.*}.conf"
# Assemble absolute pathname of configuration file
CONF_FILE="$(real_path "$CONF_DIR/$CONF_NAME")"
# Make sure that configuration file exists and is readable
check_mode "$CONF_FILE" fr
# Change to configuration directory to allow configuration file to
# source other configuration files by their relative pathname
cd "$CONF_DIR"
# Source configuration file
source "$CONF_FILE"
}
#--------------------------------------------------------------------------
# NAME
# check_config - check configuration variables
#
# SYNOPSIS
# check_config
#
# DESCRIPTION
# Check if the configuration variables contain valid values.
#--------------------------------------------------------------------------
check_config() {
local NOFILE
local -i REQUIRED_EUID
local REGEX
local LINE
local ADDRESS
local -a ADDRESS_ARRAY
local -i MAX_CHECK_DELAY
local -a JAR_ARRAY
local -i JAR_COUNT
local -i SKIP_BUNDLE_COUNT
# Check if syslog facility is defined
if [[ -z "$SYSLOG_FACILITY" ]]; then
crit "SYSLOG_FACILITY is not defined in configuration file \"$CONF_FILE\""
fi
# Check if username is defined
if [[ -z "$USERNAME" ]]; then
crit "USERNAME is not defined in configuration file \"$CONF_FILE\""
fi
# Check if username exists
REQUIRED_EUID=$("$ID" -u $USERNAME 2>/dev/null)
if (( $? != 0 )); then
crit "Username \"$USERNAME\" does not exist"
elif (( EUID != REQUIRED_EUID )); then
# Check if effective user is root
if (( EUID == 0 )); then
# Switch to required user
"$SU" - $USERNAME -c "cd \"$MY_CWD\"; \"$MY_SCRIPT_FILE\" $MY_SCRIPT_ARGS"
# Note: su returns the exit code of the executed program
exit $?
else
crit "Must be run as user \"$USERNAME\""
fi
fi
# Check if Java home directory is defined
if [[ -z "$JAVA_HOME" ]]; then
crit "JAVA_HOME is not defined in configuration file \"$CONF_FILE\""
fi
# Check if Java home directory exists and is accessible
JAVA_HOME="$(real_path "$JAVA_HOME")"
check_mode "$JAVA_HOME" drx
check_mode "$JAVA_HOME/bin" drx
# Check if "java" program exists and is executable
JAVA="$JAVA_HOME/bin/java"
check_mode "$JAVA" fx
# Check if Java heap size is defined and valid
if [[ -z "$JAVA_HEAP_SIZE" ]]; then
crit "JAVA_HEAP_SIZE is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$JAVA_HEAP_SIZE" =~ ^[0-9]{4,}$ ]]; then
crit "JAVA_HEAP_SIZE must be an integer value greater or equal 1024"
elif (( JAVA_HEAP_SIZE < 1024 )); then
crit "JAVA_HEAP_SIZE must be an integer value greater or equal 1024"
fi
# Check if Java permanent generation size is defined and valid
if [[ -z "$JAVA_PERM_SIZE" ]]; then
crit "JAVA_PERM_SIZE is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$JAVA_PERM_SIZE" =~ ^[0-9]{3,}$ ]]; then
crit "JAVA_PERM_SIZE must be an integer value greater or equal 256"
elif (( JAVA_PERM_SIZE < 256 )); then
crit "JAVA_PERM_SIZE must be an integer value greater or equal 256"
fi
# Check if AEM directory is defined
if [[ -z "$AEM_HOME" ]]; then
crit "AEM_HOME is not defined in configuration file \"$CONF_FILE\""
fi
# Check if AEM directory exists and is accessible
AEM_HOME="$(real_path "$AEM_HOME")"
if [[ "$AEM_HOME" =~ ^/*$ ]]; then
crit "Cowardly refusing to accept \"$AEM_HOME\" as AEM instance directory"
fi
check_mode "$AEM_HOME/" drwx
# Check if AEM crx-quickstart directoy exists and is accessible
AEM_BASE_DIR="$AEM_HOME/crx-quickstart"
check_mode "$AEM_BASE_DIR/" drx
# Check if AEM crx-quickstart/app directroy exists and is accessible
check_mode "$AEM_BASE_DIR/app/" drx
# Check if AEM crx-quickstart/logs directroy exists and is accessible
if [[ ! -L "$AEM_BASE_DIR/logs" && -d "$AEM_BASE_DIR/logs/" ]]; then
check_mode "$AEM_BASE_DIR/logs/" drwx
fi
# Check if AEM address is defined and valid
if [[ -z "$AEM_ADDRESS" ]]; then
crit "AEM_ADDRESS is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$AEM_ADDRESS" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
crit "AEM_ADDRESS does not contain a valid IP address"
else
check_if_addr "$AEM_ADDRESS"
fi
# Check if AEM port is defined and valid
if [[ -z "$AEM_PORT" ]]; then
crit "AEM_PORT is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$AEM_PORT" =~ ^[0-9]{4,5}$ ]]; then
crit "AEM_PORT must be an integer value in the interval [1024; 65535]"
elif (( AEM_PORT < 1024 || AEM_PORT > 65535 )); then
crit "AEM_PORT must be an integer value in the interval [1024; 65535]"
fi
# Assemble authority part of AEM URL
if [[ "$AEM_ADDRESS" == '0.0.0.0' ]]; then
AEM_AUTHORITY="127.0.0.1:$AEM_PORT"
else
AEM_AUTHORITY="$AEM_ADDRESS:$AEM_PORT"
fi
# Check if AEM username is defined and valid
if [[ -z "$AEM_USERNAME" ]]; then
crit "AEM_USERNAME is not defined in configuration file \"$CONF_FILE\""
elif [[ "$AEM_USERNAME" =~ [:] ]]; then
crit "AEM_USERNAME must not contain a colon character (\":\")"
fi
# Check if AEM password is defined and valid
if [[ -z "$AEM_PASSWORD" ]]; then
crit "AEM_PASSWORD is not defined in configuration file \"$CONF_FILE\""
elif [[ "$AEM_PASSWORD" =~ [:] ]]; then
crit "AEM_PASSWORD must not contain a colon character (\":\")"
fi
# Assemble credentials for AEM
AEM_CREDENTIALS="$AEM_USERNAME:$AEM_PASSWORD"
# Check if AEM run mode is defined and valid
if [[ -z "$AEM_RUN_MODES" ]]; then
crit "AEM_RUN_MODES is not defined in configuration file \"$CONF_FILE\""
fi
REGEX='(^|,)(author|publish)(,|$)'
if [[ ! "$AEM_RUN_MODES" =~ $REGEX ]]; then
crit "AEM_RUN_MODES must either contain \"author\" or \"publish\""
fi
# Check if log directory home is defined, exists and is accessible
if [[ -z "$LOG_HOME" ]]; then
crit "LOG_HOME is not defined in configuration file \"$CONF_FILE\""
fi
# Check if log directory home exists and is accessible
LOG_HOME="$(real_path "$LOG_HOME")"
check_mode "$LOG_HOME" drwx
# Check if log directory is valid
REGEX="^$AEM_BASE_DIR/logs(/|\$)"
if [[ "$LOG_HOME" =~ $REGEX ]]; then
crit "LOG_HOME must not equal or be a subdirectory of \"$AEM_BASE_DIR/logs\""
fi
# Check if log history is defined and valid
if [[ -z "$LOG_HISTORY" ]]; then
crit "LOG_HISTORY is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$LOG_HISTORY" =~ ^[0-9]+$ ]]; then
crit "LOG_HISTORY must be an integer value greater than 0"
elif (( LOG_HISTORY == 0 )); then
crit "LOG_HISTORY must be an integer value greater than 0"
fi
# Check if connection timeout is defined and valid
if [[ -z "$CONNECT_TIMEOUT" ]]; then
crit "CONNECT_TIMEOUT is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$CONNECT_TIMEOUT" =~ ^[0-9]+$ ]]; then
crit "CONNECT_TIMEOUT must be an integer value greater or equal 5"
elif (( CONNECT_TIMEOUT < 5 )); then
crit "CONNECT_TIMEOUT must be an integer value greater or equal 5"
fi
# Check if socket timeout is defined and valid
if [[ -z "$SOCKET_TIMEOUT" ]]; then
crit "SOCKET_TIMEOUT is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$SOCKET_TIMEOUT" =~ ^[0-9]+$ ]]; then
crit "SOCKET_TIMEOUT must be an integer value greater or equal 15"
elif (( SOCKET_TIMEOUT < 15 )); then
crit "SOCKET_TIMEOUT must be an integer value greater or equal 15"
fi
# Check if start timeout is valid
if [[ ! "$START_TIMEOUT" =~ ^[0-9]{2,}$ ]]; then
crit "START_TIMEOUT must be an integer value greater or equal 60"
elif (( START_TIMEOUT < 60 )); then
crit "START_TIMEOUT must be an integer value greater or equal 60"
fi
# Check if stop timeout is valid
if [[ ! "$STOP_TIMEOUT" =~ ^[0-9]{2,}$ ]]; then
crit "STOP_TIMEOUT must be an integer value greater or equal 60"
elif (( STOP_TIMEOUT < 60 )); then
crit "STOP_TIMEOUT must be an integer value greater or equal 60"
fi
# Compute maximum value for delay
if (( START_TIMEOUT < STOP_TIMEOUT )); then
(( MAX_CHECK_DELAY = START_TIMEOUT / 4 ))
else
(( MAX_CHECK_DELAY = STOP_TIMEOUT / 4 ))
fi
# Check if check delay is valid
if [[ -z "$CHECK_DELAY" ]]; then
crit "CHECK_DELAY is not defined in configuration file \"$CONF_FILE\""
elif [[ ! "$CHECK_DELAY" =~ ^[0-9]+$ ]]; then
crit "CHECK_DELAY must be an integer value in the interval [1; $MAX_CHECK_DELAY]"
elif (( CHECK_DELAY < 1 || CHECK_DELAY > MAX_CHECK_DELAY )); then
crit "CHECK_DELAY must be an integer value in the interval [1; $MAX_CHECK_DELAY]"
fi
# Assemble regular expression for bundle exclusion
SKIP_BUNDLE_COUNT=${#SKIP_BUNDLE_ARRAY[*]}
while (( SKIP_BUNDLE_COUNT > 1 )); do
(( SKIP_BUNDLE_COUNT-- ))
SKIP_BUNDLE_REGEX="|${SKIP_BUNDLE_ARRAY[SKIP_BUNDLE_COUNT]}$SKIP_BUNDLE_REGEX"
done
if (( SKIP_BUNDLE_COUNT > 0 )); then
SKIP_BUNDLE_REGEX="\"name\":\"(${SKIP_BUNDLE_ARRAY[0]}$SKIP_BUNDLE_REGEX)\""
else
SKIP_BUNDLE_REGEX='^$'
fi
# Search for Adobe AEM jar file
JAR_ARRAY=( $( \
"$FIND" \
"$AEM_BASE_DIR/app" \
-maxdepth 1 \
-name "*.jar" \
) )
JAR_COUNT=${#JAR_ARRAY[*]}
# Check if Adobe AEM jar file exists and is accessible
if (( JAR_COUNT < 1 )); then
crit "Cannot find any Adobe AEM jar file that matches \"$AEM_BASE_DIR/app/*.jar\""
elif (( JAR_COUNT > 1)); then
crit "Found multiple Adobe AEM jar files that match \"$AEM_BASE_DIR/app/*.jar\": ${JAR_ARRAY[*]}"
fi
AEM_JAR_FILE="${JAR_ARRAY[0]}"
check_mode "$AEM_JAR_FILE" fr
# Initialize instance name
AEM_INSTANCE_NAME="${MY_FQDN}_${AEM_ADDRESS}_${AEM_PORT}"
# Initialize lock file name
MY_LOCK_FILE="/tmp/.aem_${AEM_INSTANCE_NAME}.lock"
# Change back to original directory
cd "$MY_CWD"
}
#--------------------------------------------------------------------------
# NAME
# configure_shell - configure shell limits
#
# SYNOPSIS
# configure_shell
#
# DESCRIPTION
# Checks the maximum number of open file descriptors and the maximum
# amount of virtual memory available to the shell and sets these
# built-in shell limits to their highest possible values.
#--------------------------------------------------------------------------
configure_shell() {
local -r REGEX='[[:digit:]]+'
local VALUE
local -i EXIT_STATUS
# Check maximum number of open file descriptors
VALUE="$(ulimit -n)"
if [[ "$VALUE" =~ $REGEX ]]; then
if (( VALUE < 65535 )); then
# Set maximum number of open file descriptors
for VALUE in 65535 63999 32768 16384 8192; do
ulimit -n $VALUE &>/dev/null
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
break
fi
done
if (( EXIT_STATUS != 0 )); then
crit "The maximum number of open file descriptors must be at least 8192"
fi
fi
elif [[ "$VALUE" != 'unlimited' ]]; then
crit "\"ulimit -n\" returned unknown value \"$VALUE\""
fi
# Check maximum amount of virtual memory available to the shell
VALUE="$(ulimit -v)"
if [[ "$VALUE" != 'unlimited' ]]; then
# Set maximum amount of virtual memory available to the shell
ulimit -v unlimited &>/dev/null
EXIT_STATUS=$?
if (( EXIT_STATUS != 0 )); then
crit "The maximum amount of virtual memory available to the shell must be unlimited"
fi
fi
# Set file mode mask
umask "$AEM_UMASK"
}
#--------------------------------------------------------------------------
# NAME
# rotate_log_dirs - rotate log directories
#
# SYNOPSIS
# rotate_log_dirs
#
# DESCRIPTION
# Deletes old log directory structures, creates a new log directoy
# structure and replaces all AEM log directories with symbolic links
# to this new log directory structure.
#--------------------------------------------------------------------------
rotate_log_dirs() {
local -r CURRENT_LOG_DIR='current'
local -r LOG_BASE_DIR="$LOG_HOME/$AEM_INSTANCE_NAME"
local REGEX
local -a LOG_DIR_ARRAY
local -i INDEX
local LOG_DIR
# Create log base directory
"$MKDIR" -p "$LOG_BASE_DIR/" &>/dev/null
# Get array of all existing log directories sorted alphabetically in reverse order
REGEX="^.*/[0-9]+-[0-9]+-[0-9]+T[0-9]+:[0-9]+:[0-9]+Z\$"
LOG_DIR_ARRAY=( $( \
"$FIND" \
"$LOG_BASE_DIR" \
-maxdepth 1 \
-regex "$REGEX" \
2>/dev/null | \
"$SORT" -r \
2>/dev/null \
) )
# Delete old log directories
INDEX=${#LOG_DIR_ARRAY[*]}
while (( INDEX >= LOG_HISTORY )); do
(( INDEX-- ))
LOG_DIR="${LOG_DIR_ARRAY[INDEX]}"
"$RM" -rf "$LOG_DIR" &>/dev/null
done
# Check if "logs" is a real directory
if [[ ! -L "$AEM_BASE_DIR/logs" && -d "$AEM_BASE_DIR/logs/" ]]; then
# Move "logs" directory to new log directory
"$MV" "$AEM_BASE_DIR/logs" "$LOG_BASE_DIR/$MY_TIMESTAMP" &>/dev/null
else
# Create new log directory
"$MKDIR" -p "$LOG_BASE_DIR/$MY_TIMESTAMP" &>/dev/null
fi
# Make "current" symbolic link point to new log directoy
cd "$LOG_BASE_DIR"
"$RM" -f "$CURRENT_LOG_DIR" &>/dev/null
"$LN" -s "$MY_TIMESTAMP" "$CURRENT_LOG_DIR" &>/dev/null
# Make "logs" symbolic link point to "current" symbolic link
"$RM" -f "$AEM_BASE_DIR/logs" &>/dev/null
"$LN" -s "$LOG_BASE_DIR/$CURRENT_LOG_DIR" "$AEM_BASE_DIR/logs" &>/dev/null
}
#--------------------------------------------------------------------------
# NAME
# get_aem_pid - get Adobe AEM process ID
#
# SYNOPSIS
# get_aem_pid
#
# DESCRIPTION
# Sets the global AEM_PID variable to the process ID of the
# Adobe AEM process.
#--------------------------------------------------------------------------
get_aem_pid() {
#set -x
local -r REGEX="-Daem\\.instance\\.name=${AEM_INSTANCE_NAME//./\\.}"
# Get process ID of Adobe AEM process
AEM_PID=$("$PGREP" -u $EUID -f -- "$REGEX" 2>/dev/null)
# Check if process ID is empty
if [[ -z "$AEM_PID" ]]; then
# info "Java-process is NOT running for $REGEX "
# Check if there is a PID file (maybe AEM was started
# with the vanilla start script)
if [[ -r "$AEM_BASE_DIR/conf/cq.pid" ]]; then
# Get process ID from PID file
AEM_PID="$("$CAT" "$AEM_BASE_DIR/conf/cq.pid" 2>/dev/null)"
if [[ -n "$AEM_PID" ]]; then
# Check if AEM process is still running
kill -0 "$AEM_PID" &>/dev/null
if (( $? != 0 )); then
# AEM process is no longer running
AEM_PID=''
info "Java-process is NO LONGER running for $REGEX "
fi
fi
fi
fi
# set +x
}
#--------------------------------------------------------------------------
# NAME
# activate - activate all installed/resolved Apache Felix bundles
#
# SYNOPSIS
# activate
#
# DESCRIPTION
# Activates all resolved Apache Felix bundles.
#--------------------------------------------------------------------------
activate() {
local URL
local OUTPUT
local -i EXIT_STATUS
local REGEX
local -a BUNDLE_ARRAY
local -i BUNDLE_COUNT
local BUNDLE
local -i BUNDLE_ID
info "Retrieving all installed or resolved Apache Felix bundles"
# Get bundle information from Apache Felix
URL="http://$AEM_AUTHORITY/system/console/bundles.json"
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS != 0 )); then
crit "\"$CURL\" returned error code $EXIT_STATUS" "$OUTPUT"
fi
# Extract all installed or resolved bundles from JSON output
REGEX='\{[^\}]*"state"[[:space:]]*:[[:space:]]*"(Installed|Resolved)"[^\}]+\}'
IFS="$LF"
BUNDLE_ARRAY=( $( \
echo "$OUTPUT" | \
"$GREP" -Eio "$REGEX" 2>/dev/null | \
"$GREP" -Eiv "$SKIP_BUNDLE_REGEX" 2>/dev/null \
) )
IFS="$MY_IFS"
BUNDLE_COUNT=${#BUNDLE_ARRAY[@]}
info "Apache Felix reports that there are $BUNDLE_COUNT installed or resolved bundles"
if (( BUNDLE_COUNT == 0 )); then
return
fi
# Start all installed or resolved bundles
REGEX='"id"[[:space:]]*:[[:space:]]*([[:digit:]]+)'
for BUNDLE in "${BUNDLE_ARRAY[@]}"; do
if [[ "$BUNDLE" =~ $REGEX ]]; then
BUNDLE_ID=${BASH_REMATCH[1]}
info "Starting bundle with ID $BUNDLE_ID"
URL="http://$AEM_AUTHORITY/system/console/bundles/$BUNDLE_ID"
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request POST \
--url "$URL" \
--data 'action=start' \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS != 0 )); then
crit "\"$CURL\" returned error code $EXIT_STATUS" "$OUTPUT"
fi
fi
done
}
#--------------------------------------------------------------------------
# NAME
# start - start AEM service
#
# SYNOPSIS
# start
#
# DESCRIPTION
# Starts the AEM service.
#--------------------------------------------------------------------------
start() {
local -a JAVA_OPT_ARRAY
local -a AEM_OPT_ARRAY
local URL
local OUTPUT
local REGEX
local REGEX2
local -i EXIT_STATUS
local -i START_TIME
local -i DURATION
local -i REMAINING_TIME
local -a BUNDLE_ARRAY
local -i BUNDLE_COUNT
# Make sure there is no stale PID file
"$RM" -f "$AEM_BASE_DIR/conf/cq.pid" &>/dev/null
# Start Adobe AEM
info "Starting Adobe AEM process"
# Assemble Java options
JAVA_OPT_ARRAY=( \
'-server' \
"-Xms${JAVA_HEAP_SIZE}m" \
"-Xmx${JAVA_HEAP_SIZE}m" \
"-XX:PermSize=${JAVA_PERM_SIZE}m" \
"-XX:MaxPermSize=${JAVA_PERM_SIZE}m" \
'-Djava.awt.headless=true' \
'-Dfile.encoding=UTF8' \
"-Daem.instance.name=$AEM_INSTANCE_NAME" \
"-Dsling.run.modes=$AEM_RUN_MODES" \
)
# Assemble Adobe AEM options
AEM_OPT_ARRAY=( \
'start' \
'-a' "$AEM_ADDRESS" \
'-p' "$AEM_PORT" \
'-c' "$AEM_BASE_DIR" \
'-i' "$AEM_BASE_DIR/launchpad" \
)
# Start Adobe AEM process
configure_shell
"$ENV" \
-i \
"LANG=$JAVA_LANG" \
"TZ=$JAVA_TZ" \
"JAVA_HOME=$JAVA_HOME" \
"$NOHUP" \
"$JAVA" \
"${JAVA_OPT_ARRAY[@]}" \
"${JAVA_EXTRA_OPT_ARRAY[@]}" \
-jar "$AEM_JAR_FILE" \
"${AEM_OPT_ARRAY[@]}" \
"${AEM_EXTRA_OPT_ARRAY[@]}" \
0</dev/null \
1>"$AEM_BASE_DIR/logs/startup.log" \
2>&1 \
&
# Check for error code
EXIT_STATUS=$?
if (( EXIT_STATUS != 0 )); then
crit \
"Adobe AEM returned error $EXIT_STATUS" \
"$("$TAIL" "$AEM_BASE_DIR/logs/startup.log" 2>/dev/null)"
fi
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
# Check if Adobe AEM process is running
get_aem_pid
if [[ -n "$AEM_PID" ]]; then
break
else
info "Adobe AEM process NOT running yet. PLEASE CHECK startup.log"
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
info "$REMAINING_TIME seconds remaining"
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
# Check if Adobe AEM process is running
get_aem_pid
if [[ -n "$AEM_PID" ]]; then
crit \
"Adobe AEM process failed to start within $START_TIMEOUT seconds"
"$("$TAIL" "$AEM_BASE_DIR/logs/startup.log" 2>/dev/null)"
else
crit \
"Adobe AEM process NOT started within $START_TIMEOUT seconds. PLEASE CHECK startup.log"
"$("$TAIL" "$AEM_BASE_DIR/logs/startup.log" 2>/dev/null)"
fi
else
# Adjust start timeout
(( START_TIMEOUT -= DURATION ))
fi
# Adobe AEM process is running
echo "$AEM_PID" > "$AEM_BASE_DIR/conf/cq.pid" 2>/dev/null
info "Adobe AEM process is running with PID $AEM_PID"
# Wait for Apache Sling to respond
info "Waiting for Apache Sling to become available"
REGEX='[[:blank:]]OK$'
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
OUTPUT="$(\
"$JAVA" \
-jar "$AEM_JAR_FILE" \
status \
-c "$AEM_BASE_DIR" \
0</dev/null \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Check for regular expression in output
if [[ "$OUTPUT" =~ $REGEX ]]; then
# Apache Sling responded properly
break
fi
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
if [[ -z "$OUTPUT" ]]; then
info "$REMAINING_TIME seconds remaining - Apache Sling does not respond"
else
get_aem_pid
if [[ -z "$AEM_PID" ]]; then
crit \
"Adobe AEM process is no longer running. PLEASE CHECK startup.log or error.log"
"$("$TAIL" "$AEM_BASE_DIR/logs/startup.log" 2>/dev/null)"
else
info "$REMAINING_TIME seconds remaining - Apache Sling responds, but not as expected"
fi
fi
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
if (( EXIT_STATUS != 0 )); then
crit "Apache Sling failed to respond within $START_TIMEOUT seconds" "$OUTPUT"
else
crit "Apache Sling failed to start within $START_TIMEOUT seconds" "$OUTPUT"
fi
else
# Adjust start timeout
(( START_TIMEOUT -= DURATION ))
fi
info "Apache Sling is available"
# Wait for Apache Felix to start
info "Waiting for Apache Felix to become available"
URL="http://$AEM_AUTHORITY/system/console/vmstat"
REGEX='System is up and running!'
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
# Check if Apache Felix is up and running
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
# Extract status line from output
if [[ "$OUTPUT" =~ $REGEX ]]; then
break
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
if [[ -z "$OUTPUT" ]]; then
info "$REMAINING_TIME seconds remaining - Apache Felix does not respond"
else
info "$REMAINING_TIME seconds remaining - Apache Felix responds, but not as expected"
fi
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
# Check for connection timeout
if (( EXIT_STATUS != 0 )); then
crit "Apache Felix failed to respond within $START_TIMEOUT seconds" "$OUTPUT"
else
crit "Apache Felix failed to start within $START_TIMEOUT seconds" "$OUTPUT"
fi
else
# Adjust start timeout
(( START_TIMEOUT -= DURATION ))
fi
URL="http://$AEM_AUTHORITY/system/console/bundles.json"
# Filter "Installed", "Resolved" or "Starting" bundles
REGEX='\{[^\}]*"state"[[:space:]]*:[[:space:]]*"(Installed|Resolved|Starting)"[^\}]+\}'
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
# Get bundle information from Apache Felix
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Extract all installed or resolved bundles from JSON output
IFS="$LF"
BUNDLE_ARRAY=( $( \
echo "$OUTPUT" | \
"$GREP" -Eio "$REGEX" 2>/dev/null | \
"$GREP" -Eiv "$SKIP_BUNDLE_REGEX" 2>/dev/null \
) )
IFS="$MY_IFS"
# Get number of installed or resolved bundles
BUNDLE_COUNT=${#BUNDLE_ARRAY[@]}
if (( BUNDLE_COUNT == 0 )); then
# No more installed or resolved bundles
break
fi
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
if (( EXIT_STATUS != 0 || BUNDLE_COUNT < 0 )); then
info "$REMAINING_TIME seconds remaining - Apache Felix does not respond"
else
info "$REMAINING_TIME seconds remaining - Apache Felix reports that $BUNDLE_COUNT bundle(s) are not started yet"
fi
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
# Check for connection timeout
if (( EXIT_STATUS != 0 )); then
crit "Apache Felix failed to respond within $START_TIMEOUT seconds" "$OUTPUT"
else
crit "Apache Felix failed to start $BUNDLE_COUNT bundle(s) within $START_TIMEOUT seconds"
fi
else
# Adjust start timeout
(( START_TIMEOUT -= DURATION ))
fi
info "Apache Felix is available"
# Wait for Adobe CRX to start
info "Waiting for Adobe CRX to become available"
URL="http://$AEM_AUTHORITY/crx/packmgr/service.jsp?cmd=ls"
REGEX='<status[[:space:]]+code="200"'
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
# Check if Adobe CRX is responsive
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Check for regular expression in output
if [[ "$OUTPUT" =~ $REGEX ]]; then
# Adobe CRX responded properly
break
fi
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
info "$REMAINING_TIME seconds remaining"
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
if (( EXIT_STATUS != 0 )); then
crit "Adobe CRX failed to respond within $START_TIMEOUT seconds" "$OUTPUT"
else
crit "Adobe CRX failed to start within $START_TIMEOUT seconds" "$OUTPUT"
fi
else
# Adjust start timeout
(( START_TIMEOUT -= DURATION ))
fi
info "Adobe CRX is available"
# Wait for Adobe WCM to start
info "Waiting for Adobe WCM to become available"
URL="http://$AEM_AUTHORITY/libs/cq/core/content/welcome.html"
REGEX='Welcome,[[:space:]]+Administrator\.'
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < START_TIMEOUT )); do
# Check if Adobe WCM is responsive
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Check for regular expression in output
if [[ "$OUTPUT" =~ $REGEX ]]; then
# Adobe WCM responded properly
break;
fi
fi
# Compute remaining time
(( REMAINING_TIME = START_TIMEOUT - DURATION ))
info "$REMAINING_TIME seconds remaining"
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
# Check for timeout
if (( DURATION >= START_TIMEOUT )); then
if (( EXIT_STATUS != 0 )); then
crit "Adobe WCM failed to respond within $START_TIMEOUT seconds" "$OUTPUT"
else
crit "Adobe WCM failed to start within $START_TIMEOUT seconds" "$OUTPUT"
fi
fi
info "Adobe WCM is available"
}
#--------------------------------------------------------------------------
# NAME
# stop - stop service
# SYNOPSIS
# stop
#
# DESCRIPTION
# Stops the AEM service
#--------------------------------------------------------------------------
stop() {
local -i START_TIME
local -i DURATION
local -i REMAINING_TIME
# Stop Adobe AEM
info "Stopping Adobe AEM process"
cd "$AEM_HOME"
(
"$ENV" \
-i \
"LANG=$JAVA_LANG" \
"TZ=$JAVA_TZ" \
"JAVA_HOME=$JAVA_HOME" \
"$JAVA" \
-Djava.awt.headless=true \
-Dfile.encoding=UTF8 \
-jar "$AEM_JAR_FILE" \
stop \
-c "$AEM_BASE_DIR" \
0</dev/null \
1>"$AEM_BASE_DIR/logs/shutdown.log" \
2>&1
) &
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < STOP_TIMEOUT )); do
# Check if Adobe AEM process stopped
kill -0 $AEM_PID &>/dev/null
if (( $? != 0 )); then
# Adobe AEM stopped
break
fi
# Compute remaining time
(( REMAINING_TIME = STOP_TIMEOUT - DURATION ))
info "$REMAINING_TIME seconds remaining"
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
if (( DURATION >= STOP_TIMEOUT )); then
err "Adobe AEM process failed to stop"
# Stop Adobe AEM process with SIGTERM
info "Sending TERM signal to Adobe AEM process running with PID $AEM_PID"
kill -15 $AEM_PID &>/dev/null
# Wait for Adobe AEM to stop
info "Waiting for Adobe AEM process to stop"
START_TIME=$("$DATE" -u '+%s' 2>/dev/null)
DURATION=0
while (( DURATION < STOP_TIMEOUT )); do
# Check if Adobe AEM process stopped
kill -0 $AEM_PID &>/dev/null
if (( $? != 0 )); then
# Adobe AEM stopped
break
fi
# Compute remaining time
(( REMAINING_TIME = STOP_TIMEOUT - DURATION ))
info "$REMAINING_TIME seconds remaining"
# Wait ...
"$SLEEP" $CHECK_DELAY &>/dev/null
# Update duration
(( DURATION = $("$DATE" -u '+%s' 2>/dev/null) - START_TIME ))
done
if (( DURATION >= STOP_TIMEOUT )); then
err "Adobe AEM process failed to stop"
# Stop Adobe AEM process with SIGKILL
info "Sending KILL signal to Adobe AEM process running with PID $AEM_PID"
kill -9 $AEM_PID &>/dev/null
fi
fi
# Adobe AEM process stopped
"$RM" -f "$AEM_BASE_DIR/conf/cq.pid" &>/dev/null
}
#--------------------------------------------------------------------------
# NAME
# status - get service status
#
# SYNOPSIS
# service
#
# DESCRIPTION
# Performs elementary functional test.
#--------------------------------------------------------------------------
status() {
local URL
local REGEX
local OUTPUT
local -a BUNDLE_ARRAY
local -i BUNDLE_COUNT
local -i RESULT=0
# Get status information from Apache Sling
cd "$AEM_HOME"
OUTPUT="$( \
"$JAVA" \
-jar "$AEM_JAR_FILE" \
status \
-c "$AEM_BASE_DIR" \
2>&1 \
)"
if (( $? == 0 )); then
# Check for regular expression in output
REGEX='[[:blank:]]OK$'
if [[ "$OUTPUT" =~ $REGEX ]]; then
info "Apache Sling is available"
else
err "Apache Sling did not respond as expected" "$OUTPUT"
RESULT=1
fi
else
err "Apache Sling failed to respond" "$OUTPUT"
RESULT=1
fi
# Check if Apache Felix is up and running
URL="http://$AEM_AUTHORITY/system/console/vmstat"
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
# Extract status line from output
REGEX='System is up and running!'
if [[ "$OUTPUT" =~ $REGEX ]]; then
# Get bundle information from Apache Felix
URL="http://$AEM_AUTHORITY/system/console/bundles.json"
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Extract all installed or resolved bundles from JSON output
REGEX='\{[^\}]*"state"[[:space:]]*:[[:space:]]*"(Installed|Resolved|Starting)"[^\}]+\}'
IFS="$LF"
BUNDLE_ARRAY=( $( \
echo "$OUTPUT" | \
"$GREP" -Eio "$REGEX" 2>/dev/null | \
"$GREP" -Eiv "$SKIP_BUNDLE_REGEX" 2>/dev/null \
) )
IFS="$MY_IFS"
# Get number of installed or resolved bundles
BUNDLE_COUNT=${#BUNDLE_ARRAY[@]}
if (( BUNDLE_COUNT == 0 )); then
info "Apache Felix is available"
else
err "Apache Felix failed to start $BUNDLE_COUNT bundles"
RESULT=1
fi
else
err "Apache Felix failed to respond" "$OUTPUT"
RESULT=1
fi
else
err "Apache Felix failed to start" "$OUTPUT"
RESULT=1
fi
# Check if Adobe CRX is responsive
URL="http://$AEM_AUTHORITY/crx/packmgr/service.jsp?cmd=ls"
REGEX='<status[[:space:]]+code="200"'
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Check for regular expression in output
if [[ "$OUTPUT" =~ $REGEX ]]; then
info "Adobe CRX is available"
else
err "Adobe CRX did not respond as expected" "$OUTPUT"
RESULT=1
fi
else
err "Adobe CRX failed to respond" "$OUTPUT"
RESULT=1
fi
# Check if Adobe WCM is responsive
URL="http://$AEM_AUTHORITY/libs/cq/core/content/welcome.html"
REGEX='Welcome,[[:space:]]+Administrator\.'
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request GET \
--url "$URL" \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS == 0 )); then
# Check for regular expression in output
if [[ "$OUTPUT" =~ $REGEX ]]; then
info "Adobe WCM is available"
else
err "Adobe WCM did not respond as expected" "$OUTPUT"
RESULT=1
fi
else
err "Adobe WCM failed to respond" "$OUTPUT"
RESULT=1
fi
return $RESULT
}
#--------------------------------------------------------------------------
# NAME
# sweep - Run memory garbage collection
#
# SYNOPSIS
# sweep
#
# DESCRIPTION
# Runs a memory garbage collection.
#--------------------------------------------------------------------------
sweep() {
local URL
local OUTPUT
local -i EXIT_STATUS
# Run memory garbage collection
URL="http://$AEM_AUTHORITY/system/console/memoryusage"
OUTPUT="$( \
"$CURL" \
--silent \
--show-error \
--connect-timeout $CONNECT_TIMEOUT \
--max-time $SOCKET_TIMEOUT \
--location \
--user "$AEM_CREDENTIALS" \
--request POST \
--url "$URL" \
--data 'command=gc' \
2>&1 \
)"
EXIT_STATUS=$?
if (( EXIT_STATUS != 0 )); then
crit "\"$CURL\" returned error code $EXIT_STATUS" "$OUTPUT"
fi
}
#--------------------------------------------------------------------------
# Main program
#--------------------------------------------------------------------------
# Source configuration
load_config
# Check configuration
check_config
if [ "$2" = "first" ];then
(( START_TIMEOUT = START_TIMEOUT * 10 ))
info "Set START_TIMEOUT to $START_TIMEOUT due to first start"
fi
# Analyze command-line argument
case "$1" in
'start')
# Lock this script
lock
info "Starting Adobe AEM service"
# Check if Adobe AEM process is already running
get_aem_pid
if [[ -z "$AEM_PID" ]]; then
# Rotate log directories
rotate_log_dirs
# Start Adobe AEM service
start
fi
info "Adobe AEM service started successfully"
# Unlock this script
unlock
;;
'stop')
# Lock this script
lock
info "Stopping Adobe AEM service"
# Check if Adobe AEM process is running
get_aem_pid
if [[ -n "$AEM_PID" ]]; then
# Stop Adobe AEM service
stop
fi
info "Adobe AEM service stopped successfully"
# Unlock this script
unlock
;;
'restart')
# Lock this script
lock
info "Restarting Adobe AEM service"
# Check if Adobe AEM process is already running
get_aem_pid
if [[ -n "$AEM_PID" ]]; then
# Stop Adobe AEM service
stop
fi
# Rotate log directories
rotate_log_dirs
# Start Adobe AEM service
start
info "Adobe AEM service restarted successfully"
# Unlock this script
unlock
;;
'status')
info "Checking status of Adobe AEM service"
# Check if Adobe AEM process is running
get_aem_pid
if [[ -z "$AEM_PID" ]]; then
err "Adobe AEM service is not available"
exit 3
else
info "Adobe AEM is running with PID $AEM_PID"
# Check if Adobe AEM service is available
status
if (( $? == 0 )); then
info "Adobe AEM service is available"
else
err "Adobe AEM service is not available"
exit 3
fi
fi
;;
'activate')
# Lock this script
lock
# Check if Adobe AEM process is running
get_aem_pid
if [[ -z "$AEM_PID" ]]; then
crit "Adobe AEM service is not running"
fi
info "Activating all installed or resolved Apache Felix bundles"
activate
# Unlock this script
unlock
;;
'sweep')
# Lock this script
lock
# Check if Adobe AEM process is running
get_aem_pid
if [[ -z "$AEM_PID" ]]; then
crit "Adobe AEM service is not running"
fi
info "Running memory garbage collection"
# Run memory garbage collection
sweep
info "Memory garbage collection complete"
# Unlock this script
unlock
;;
'help')
usage 0
;;
'version')
version
;;
*)
usage
;;
esac
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment