You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
14 KiB
497 lines
14 KiB
4 months ago
|
#!/bin/bash
|
||
|
# Copyright Broadcom, Inc. All Rights Reserved.
|
||
|
# SPDX-License-Identifier: APACHE-2.0
|
||
|
#
|
||
|
# Library for managing services
|
||
|
|
||
|
# shellcheck disable=SC1091
|
||
|
|
||
|
# Load Generic Libraries
|
||
|
. /opt/bitnami/scripts/libvalidations.sh
|
||
|
. /opt/bitnami/scripts/liblog.sh
|
||
|
|
||
|
# Functions
|
||
|
|
||
|
########################
|
||
|
# Read the provided pid file and returns a PID
|
||
|
# Arguments:
|
||
|
# $1 - Pid file
|
||
|
# Returns:
|
||
|
# PID
|
||
|
#########################
|
||
|
get_pid_from_file() {
|
||
|
local pid_file="${1:?pid file is missing}"
|
||
|
|
||
|
if [[ -f "$pid_file" ]]; then
|
||
|
if [[ -n "$(< "$pid_file")" ]] && [[ "$(< "$pid_file")" -gt 0 ]]; then
|
||
|
echo "$(< "$pid_file")"
|
||
|
fi
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Check if a provided PID corresponds to a running service
|
||
|
# Arguments:
|
||
|
# $1 - PID
|
||
|
# Returns:
|
||
|
# Boolean
|
||
|
#########################
|
||
|
is_service_running() {
|
||
|
local pid="${1:?pid is missing}"
|
||
|
|
||
|
kill -0 "$pid" 2>/dev/null
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Stop a service by sending a termination signal to its pid
|
||
|
# Arguments:
|
||
|
# $1 - Pid file
|
||
|
# $2 - Signal number (optional)
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
stop_service_using_pid() {
|
||
|
local pid_file="${1:?pid file is missing}"
|
||
|
local signal="${2:-}"
|
||
|
local pid
|
||
|
|
||
|
pid="$(get_pid_from_file "$pid_file")"
|
||
|
[[ -z "$pid" ]] || ! is_service_running "$pid" && return
|
||
|
|
||
|
if [[ -n "$signal" ]]; then
|
||
|
kill "-${signal}" "$pid"
|
||
|
else
|
||
|
kill "$pid"
|
||
|
fi
|
||
|
|
||
|
local counter=10
|
||
|
while [[ "$counter" -ne 0 ]] && is_service_running "$pid"; do
|
||
|
sleep 1
|
||
|
counter=$((counter - 1))
|
||
|
done
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Start cron daemon
|
||
|
# Arguments:
|
||
|
# None
|
||
|
# Returns:
|
||
|
# true if started correctly, false otherwise
|
||
|
#########################
|
||
|
cron_start() {
|
||
|
if [[ -x "/usr/sbin/cron" ]]; then
|
||
|
/usr/sbin/cron
|
||
|
elif [[ -x "/usr/sbin/crond" ]]; then
|
||
|
/usr/sbin/crond
|
||
|
else
|
||
|
false
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Generate a cron configuration file for a given service
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# $2 - Command
|
||
|
# Flags:
|
||
|
# --run-as - User to run as (default: root)
|
||
|
# --schedule - Cron schedule configuration (default: * * * * *)
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
generate_cron_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local cmd="${2:?command is missing}"
|
||
|
local run_as="root"
|
||
|
local schedule="* * * * *"
|
||
|
local clean="true"
|
||
|
|
||
|
# Parse optional CLI flags
|
||
|
shift 2
|
||
|
while [[ "$#" -gt 0 ]]; do
|
||
|
case "$1" in
|
||
|
--run-as)
|
||
|
shift
|
||
|
run_as="$1"
|
||
|
;;
|
||
|
--schedule)
|
||
|
shift
|
||
|
schedule="$1"
|
||
|
;;
|
||
|
--no-clean)
|
||
|
clean="false"
|
||
|
;;
|
||
|
*)
|
||
|
echo "Invalid command line flag ${1}" >&2
|
||
|
return 1
|
||
|
;;
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
mkdir -p /etc/cron.d
|
||
|
if "$clean"; then
|
||
|
cat > "/etc/cron.d/${service_name}" <<EOF
|
||
|
# Copyright Broadcom, Inc. All Rights Reserved.
|
||
|
# SPDX-License-Identifier: APACHE-2.0
|
||
|
|
||
|
${schedule} ${run_as} ${cmd}
|
||
|
EOF
|
||
|
else
|
||
|
echo "${schedule} ${run_as} ${cmd}" >> /etc/cron.d/"$service_name"
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Remove a cron configuration file for a given service
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
remove_cron_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local cron_conf_dir="/etc/monit/conf.d"
|
||
|
rm -f "${cron_conf_dir}/${service_name}"
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Generate a monit configuration file for a given service
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# $2 - Pid file
|
||
|
# $3 - Start command
|
||
|
# $4 - Stop command
|
||
|
# Flags:
|
||
|
# --disable - Whether to disable the monit configuration
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
generate_monit_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local pid_file="${2:?pid file is missing}"
|
||
|
local start_command="${3:?start command is missing}"
|
||
|
local stop_command="${4:?stop command is missing}"
|
||
|
local monit_conf_dir="/etc/monit/conf.d"
|
||
|
local disabled="no"
|
||
|
|
||
|
# Parse optional CLI flags
|
||
|
shift 4
|
||
|
while [[ "$#" -gt 0 ]]; do
|
||
|
case "$1" in
|
||
|
--disable)
|
||
|
disabled="yes"
|
||
|
;;
|
||
|
*)
|
||
|
echo "Invalid command line flag ${1}" >&2
|
||
|
return 1
|
||
|
;;
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
is_boolean_yes "$disabled" && conf_suffix=".disabled"
|
||
|
mkdir -p "$monit_conf_dir"
|
||
|
cat > "${monit_conf_dir}/${service_name}.conf${conf_suffix:-}" <<EOF
|
||
|
# Copyright Broadcom, Inc. All Rights Reserved.
|
||
|
# SPDX-License-Identifier: APACHE-2.0
|
||
|
|
||
|
check process ${service_name}
|
||
|
with pidfile "${pid_file}"
|
||
|
start program = "${start_command}" with timeout 90 seconds
|
||
|
stop program = "${stop_command}" with timeout 90 seconds
|
||
|
EOF
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Remove a monit configuration file for a given service
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
remove_monit_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local monit_conf_dir="/etc/monit/conf.d"
|
||
|
rm -f "${monit_conf_dir}/${service_name}.conf"
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Generate a logrotate configuration file
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# $2 - Log files pattern
|
||
|
# Flags:
|
||
|
# --period - Period
|
||
|
# --rotations - Number of rotations to store
|
||
|
# --extra - Extra options (Optional)
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
generate_logrotate_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local log_path="${2:?log path is missing}"
|
||
|
local period="weekly"
|
||
|
local rotations="150"
|
||
|
local extra=""
|
||
|
local logrotate_conf_dir="/etc/logrotate.d"
|
||
|
local var_name
|
||
|
# Parse optional CLI flags
|
||
|
shift 2
|
||
|
while [[ "$#" -gt 0 ]]; do
|
||
|
case "$1" in
|
||
|
--period|--rotations|--extra)
|
||
|
var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")"
|
||
|
shift
|
||
|
declare "$var_name"="${1:?"$var_name" is missing}"
|
||
|
;;
|
||
|
*)
|
||
|
echo "Invalid command line flag ${1}" >&2
|
||
|
return 1
|
||
|
;;
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
mkdir -p "$logrotate_conf_dir"
|
||
|
cat <<EOF | sed '/^\s*$/d' > "${logrotate_conf_dir}/${service_name}"
|
||
|
# Copyright Broadcom, Inc. All Rights Reserved.
|
||
|
# SPDX-License-Identifier: APACHE-2.0
|
||
|
|
||
|
${log_path} {
|
||
|
${period}
|
||
|
rotate ${rotations}
|
||
|
dateext
|
||
|
compress
|
||
|
copytruncate
|
||
|
missingok
|
||
|
$(indent "$extra" 2)
|
||
|
}
|
||
|
EOF
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Remove a logrotate configuration file
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
remove_logrotate_conf() {
|
||
|
local service_name="${1:?service name is missing}"
|
||
|
local logrotate_conf_dir="/etc/logrotate.d"
|
||
|
rm -f "${logrotate_conf_dir}/${service_name}"
|
||
|
}
|
||
|
|
||
|
########################
|
||
|
# Generate a Systemd configuration file
|
||
|
# Arguments:
|
||
|
# $1 - Service name
|
||
|
# Flags:
|
||
|
# --custom-service-content - Custom content to add to the [service] block
|
||
|
# --environment - Environment variable to define (multiple --environment options may be passed)
|
||
|
# --environment-file - Text file with environment variables (multiple --environment-file options may be passed)
|
||
|
# --exec-start - Start command (required)
|
||
|
# --exec-start-pre - Pre-start command (optional)
|
||
|
# --exec-start-post - Post-start command (optional)
|
||
|
# --exec-stop - Stop command (optional)
|
||
|
# --exec-reload - Reload command (optional)
|
||
|
# --group - System group to start the service with
|
||
|
# --name - Service full name (e.g. Apache HTTP Server, defaults to $1)
|
||
|
# --restart - When to restart the Systemd service after being stopped (defaults to always)
|
||
|
# --pid-file - Service PID file
|
||
|
# --standard-output - File where to print stdout output
|
||
|
# --standard-error - File where to print stderr output
|
||
|
# --success-exit-status - Exit code that indicates a successful shutdown
|
||
|
# --type - Systemd unit type (defaults to forking)
|
||
|
# --user - System user to start the service with
|
||
|
# --working-directory - Working directory at which to start the service
|
||
|
# Returns:
|
||
|
# None
|
||
|
#########################
|
||
|
generate_systemd_conf() {
|
||
|
local -r service_name="${1:?service name is missing}"
|
||
|
local -r systemd_units_dir="/etc/systemd/system"
|
||
|
local -r service_file="${systemd_units_dir}/bitnami.${service_name}.service"
|
||
|
# Default values
|
||
|
local name="$service_name"
|
||
|
local type="forking"
|
||
|
local user=""
|
||
|
local group=""
|
||
|
local environment=""
|
||
|
local environment_file=""
|
||
|
local exec_start=""
|
||
|
local exec_start_pre=""
|
||
|
local exec_start_post=""
|
||
|
local exec_stop=""
|
||
|
local exec_reload=""
|
||
|
local restart="always"
|
||
|
local pid_file=""
|
||
|
local standard_output="journal"
|
||
|
local standard_error=""
|
||
|
local limits_content=""
|
||
|
local success_exit_status=""
|
||
|
local custom_service_content=""
|
||
|
local working_directory=""
|
||
|
# Parse CLI flags
|
||
|
shift
|
||
|
while [[ "$#" -gt 0 ]]; do
|
||
|
case "$1" in
|
||
|
--name \
|
||
|
| --type \
|
||
|
| --user \
|
||
|
| --group \
|
||
|
| --exec-start \
|
||
|
| --exec-stop \
|
||
|
| --exec-reload \
|
||
|
| --restart \
|
||
|
| --pid-file \
|
||
|
| --standard-output \
|
||
|
| --standard-error \
|
||
|
| --success-exit-status \
|
||
|
| --custom-service-content \
|
||
|
| --working-directory \
|
||
|
)
|
||
|
var_name="$(echo "$1" | sed -e "s/^--//" -e "s/-/_/g")"
|
||
|
shift
|
||
|
declare "$var_name"="${1:?"${var_name} value is missing"}"
|
||
|
;;
|
||
|
--limit-*)
|
||
|
[[ -n "$limits_content" ]] && limits_content+=$'\n'
|
||
|
var_name="${1//--limit-}"
|
||
|
shift
|
||
|
limits_content+="Limit${var_name^^}=${1:?"--limit-${var_name} value is missing"}"
|
||
|
;;
|
||
|
--exec-start-pre)
|
||
|
shift
|
||
|
[[ -n "$exec_start_pre" ]] && exec_start_pre+=$'\n'
|
||
|
exec_start_pre+="ExecStartPre=${1:?"--exec-start-pre value is missing"}"
|
||
|
;;
|
||
|
--exec-start-post)
|
||
|
shift
|
||
|
[[ -n "$exec_start_post" ]] && exec_start_post+=$'\n'
|
||
|
exec_start_post+="ExecStartPost=${1:?"--exec-start-post value is missing"}"
|
||
|
;;
|
||
|
--environment)
|
||
|
shift
|
||
|
# It is possible to add multiple environment lines
|
||
|
[[ -n "$environment" ]] && environment+=$'\n'
|
||
|
environment+="Environment=${1:?"--environment value is missing"}"
|
||
|
;;
|
||
|
--environment-file)
|
||
|
shift
|
||
|
# It is possible to add multiple environment-file lines
|
||
|
[[ -n "$environment_file" ]] && environment_file+=$'\n'
|
||
|
environment_file+="EnvironmentFile=${1:?"--environment-file value is missing"}"
|
||
|
;;
|
||
|
*)
|
||
|
echo "Invalid command line flag ${1}" >&2
|
||
|
return 1
|
||
|
;;
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
# Validate inputs
|
||
|
local error="no"
|
||
|
if [[ -z "$exec_start" ]]; then
|
||
|
error "The --exec-start option is required"
|
||
|
error="yes"
|
||
|
fi
|
||
|
if [[ "$error" != "no" ]]; then
|
||
|
return 1
|
||
|
fi
|
||
|
# Generate the Systemd unit
|
||
|
cat > "$service_file" <<EOF
|
||
|
# Copyright Broadcom, Inc. All Rights Reserved.
|
||
|
# SPDX-License-Identifier: APACHE-2.0
|
||
|
|
||
|
[Unit]
|
||
|
Description=Bitnami service for ${name}
|
||
|
# Starting/stopping the main bitnami service should cause the same effect for this service
|
||
|
PartOf=bitnami.service
|
||
|
|
||
|
[Service]
|
||
|
Type=${type}
|
||
|
EOF
|
||
|
if [[ -n "$working_directory" ]]; then
|
||
|
cat >> "$service_file" <<< "WorkingDirectory=${working_directory}"
|
||
|
fi
|
||
|
if [[ -n "$exec_start_pre" ]]; then
|
||
|
# This variable may contain multiple ExecStartPre= directives
|
||
|
cat >> "$service_file" <<< "$exec_start_pre"
|
||
|
fi
|
||
|
if [[ -n "$exec_start" ]]; then
|
||
|
cat >> "$service_file" <<< "ExecStart=${exec_start}"
|
||
|
fi
|
||
|
if [[ -n "$exec_start_post" ]]; then
|
||
|
# This variable may contain multiple ExecStartPost= directives
|
||
|
cat >> "$service_file" <<< "$exec_start_post"
|
||
|
fi
|
||
|
# Optional stop and reload commands
|
||
|
if [[ -n "$exec_stop" ]]; then
|
||
|
cat >> "$service_file" <<< "ExecStop=${exec_stop}"
|
||
|
fi
|
||
|
if [[ -n "$exec_reload" ]]; then
|
||
|
cat >> "$service_file" <<< "ExecReload=${exec_reload}"
|
||
|
fi
|
||
|
# User and group
|
||
|
if [[ -n "$user" ]]; then
|
||
|
cat >> "$service_file" <<< "User=${user}"
|
||
|
fi
|
||
|
if [[ -n "$group" ]]; then
|
||
|
cat >> "$service_file" <<< "Group=${group}"
|
||
|
fi
|
||
|
# PID file allows to determine if the main process is running properly (for Restart=always)
|
||
|
if [[ -n "$pid_file" ]]; then
|
||
|
cat >> "$service_file" <<< "PIDFile=${pid_file}"
|
||
|
fi
|
||
|
if [[ -n "$restart" ]]; then
|
||
|
cat >> "$service_file" <<< "Restart=${restart}"
|
||
|
fi
|
||
|
# Environment flags
|
||
|
if [[ -n "$environment" ]]; then
|
||
|
# This variable may contain multiple Environment= directives
|
||
|
cat >> "$service_file" <<< "$environment"
|
||
|
fi
|
||
|
if [[ -n "$environment_file" ]]; then
|
||
|
# This variable may contain multiple EnvironmentFile= directives
|
||
|
cat >> "$service_file" <<< "$environment_file"
|
||
|
fi
|
||
|
# Logging
|
||
|
if [[ -n "$standard_output" ]]; then
|
||
|
cat >> "$service_file" <<< "StandardOutput=${standard_output}"
|
||
|
fi
|
||
|
if [[ -n "$standard_error" ]]; then
|
||
|
cat >> "$service_file" <<< "StandardError=${standard_error}"
|
||
|
fi
|
||
|
if [[ -n "$custom_service_content" ]]; then
|
||
|
# This variable may contain multiple miscellaneous directives
|
||
|
cat >> "$service_file" <<< "$custom_service_content"
|
||
|
fi
|
||
|
if [[ -n "$success_exit_status" ]]; then
|
||
|
cat >> "$service_file" <<EOF
|
||
|
# When the process receives a SIGTERM signal, it exits with code ${success_exit_status}
|
||
|
SuccessExitStatus=${success_exit_status}
|
||
|
EOF
|
||
|
fi
|
||
|
cat >> "$service_file" <<EOF
|
||
|
# Optimizations
|
||
|
TimeoutStartSec=2min
|
||
|
TimeoutStopSec=30s
|
||
|
IgnoreSIGPIPE=no
|
||
|
KillMode=mixed
|
||
|
EOF
|
||
|
if [[ -n "$limits_content" ]]; then
|
||
|
cat >> "$service_file" <<EOF
|
||
|
# Limits
|
||
|
${limits_content}
|
||
|
EOF
|
||
|
fi
|
||
|
cat >> "$service_file" <<EOF
|
||
|
|
||
|
[Install]
|
||
|
# Enabling/disabling the main bitnami service should cause the same effect for this service
|
||
|
WantedBy=bitnami.service
|
||
|
EOF
|
||
|
}
|