libretime/install

1264 lines
41 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e # Exit if any of the steps fails.
if [[ $EUID -ne 0 ]]; then
echo "Please run as root user."
exit 1
fi
SCRIPT_DIR="$( cd "$( dirname "$0")" && pwd)"
AIRTIMEROOT=${SCRIPT_DIR}
showhelp() {
echo "Usage: sudo bash install [options]
-h, --help, -?
Display usage information
-V, --version
Display version information
-v, --verbose
More output
-q, --quiet, --silent
No output except errors
-f, --force
Turn off interactive prompts
--distribution=DISTRIBUTION
Linux distribution the installation is being run on
--release=RELEASE
Distribution release
-d, --ignore-dependencies
Don't install binary dependencies
-w, --web-user=WEB_USER
Set the apache web user. Defaults to www-data. Only change
this setting if you've changed the default apache web user
-r, --web-root=WEB_ROOT
Set the web root for Airtime files
This will copy the Airtime application files, but you will need
to give your web user access to the given directory if it is
not accessible
--web-port=WEB_PORT
Set what port the LibreTime interface should run on.
-I, --in-place
Set the current Airtime directory as the web root
Note that you will need to give your web user permission to
access this directory if it is not accessible
-p, --postgres
Create a default postgres user named 'airtime' with password
'airtime'
-a, --apache
Install apache and deploy a basic configuration for Airtime
-i, --icecast
Install Icecast 2 and deploy a basic configuration for Airtime
--selinux
Run restorecon on directories and files that need tagging to
allow the WEB_USER access
--no-postgres
Skips all postgres related install tasks (Useful if you configure
postgresql as part of another script / docker builds)
--no-rabbitmq
Skips all rabbitmq related install tasks."
exit 0
}
showversion() {
if [ ! -f "$SCRIPT_DIR/VERSION" ]; then
echo "Please initialize LibreTime by running ./build.sh"
exit 1
fi
version=$(cat "$SCRIPT_DIR/VERSION")
echo "LibreTime Version ${version}"
exit 0
}
web_user=""
web_root=""
web_port="80"
in_place="f"
postgres="f"
apache="f"
icecast="f"
ignore_dependencies="f"
selinux="f"
# Interactive
_i=1
# Verbose
_v=0
# Quiet
_q=0
upgrade="f"
dist=""
code=""
apache_bin=""
skip_postgres=0
skip_rabbitmq=0
default_value="Y"
# <user:group> <path>
mkdir_and_chown() {
mkdir -p "$2"
chown -R "$1" "$2"
}
function verbose() {
if [[ ${_v} -eq 1 ]]; then
echo -e "$@"
fi
}
function loud() {
if [[ ${_q} -eq 0 ]]; then
echo -e "$@"
fi
}
# Evaluate commands silently if quiet.
# If not quiet, output command if verbose.
function loudCmd() {
if [[ ${_q} -eq 0 ]]; then
verbose "$@"
# Disable the shellcheck until quoting can be corrected
# shellcheck disable=2294
eval "$@"
else
# shellcheck disable=2294
eval "$@" > /dev/null
fi
}
function checkCommandExists() {
set +e
command="$1"
eval hash "${command}" 2> /dev/null
commandFound=$?
if [[ ! ${commandFound} -eq 0 ]]; then
echo -e "Error: ${command} not found. Please ensure you have the corresponding dependency installed."
exit
fi
set -e
}
# Function to determine if systemd, Upstart or System V Init is the active
# init system. All the newer supported distros use systemd out-of-the-box but
# a sysadmin could have installed an alternative init compatibility package.
# As a result, making assumptions based on the distribution and release is
# not a good idea. The detection works as follows:
# 1. Get the process name where PID=1 and follow any symlinks.
# 2. Look up that path in the appropriate package manager to get the name
# of the package that process is part of.
# See https://unix.stackexchange.com/questions/196166/how-to-find-out-if-a-system-uses-sysv-upstart-or-systemd-initsystem
has_systemd_init=false
has_upstart_init=false
has_systemv_init=false
function systemInitDetect() {
verbose "\nDetecting init system type ..."
# Get the path of the command where pid=1 following any symlinks
pid_1_path=$(readlink --canonicalize -n /proc/1/exe)
# returns '(/usr)?/lib/systemd/systemd' (Debian Buster, CentOS 7)
verbose "Detected path to PID=1 process: $pid_1_path"
# Get package of PID=1 path as it identifies the init system.
# Allow this to fail, at least then the init system can be guessed from the
# PID 1 executable alone
pid_1_package=$(dpkg -S "$pid_1_path" 2> /dev/null ||
rpm --qf '%{name}\n' -qf "$pid_1_path" 2> /dev/null ||
echo "unknown")
verbose "Detected package name for PID=1 process: $pid_1_package"
case "${pid_1_package}:${pid_1_path}" in
*systemd*)
has_systemd_init=true
verbose "Detected init system type: systemd"
;;
*upstart*)
has_upstart_init=true
verbose "Detected init system type: Upstart"
;;
*sysvinit*)
has_systemv_init=true
verbose "Detected init system type: System V"
;;
*)
echo "ERROR: Unable to detect init system using package or path of PID=1 process!" >&2
exit 1
;;
esac
return 0
}
# Function to wrap installation of services for systemd, Upstart and System V
# depending on which one was detected by the systemInitDetect() function.
# Service file is copied from a known location and installed into the system.
# In the process, filtering is performed for the userid if appropriate.
# If required, the service is enabled; then it is started.
# Usage:
# systemInitInstall service-name [user]
function systemInitInstall() {
local service_name="$1"
local user="$2"
# shellcheck disable=SC2034
local source_base_path=""
local source_path=""
local target_path=""
local alt_path=""
local source_config_path=""
local target_config_path=""
local python_source_path="${SCRIPT_DIR-$PWD}/python_apps"
verbose "\n * Installing service $service_name ..."
if $has_systemd_init; then
case "$service_name" in
libretime-analyzer)
source_path="${SCRIPT_DIR}/analyzer/install/systemd/${service_name}.service"
target_path="/etc/systemd/system/${service_name}.service"
alt_path="${target_path//libretime-/airtime_}"
;;
libretime-celery)
source_path="${SCRIPT_DIR}/worker/install/systemd/${service_name}.service"
target_path="/etc/systemd/system/${service_name}.service"
alt_path="${target_path//libretime-/airtime-}"
;;
libretime-liquidsoap | libretime-playout)
source_path="${SCRIPT_DIR}/playout/install/systemd/${service_name}.service"
target_path="/etc/systemd/system/${service_name}.service"
alt_path="${target_path//libretime-/airtime-}"
;;
libretime-api)
source_path="${SCRIPT_DIR-$PWD}/api/install/systemd/${service_name}.service"
target_path="/etc/systemd/system/${service_name}.service"
alt_path="${target_path//libretime-/airtime-}"
;;
esac
if [[ ! -e $source_path ]]; then
echo "$0:${FUNCNAME[0]}(): ERROR: service \"$service_name\" with source path \"$source_path\" does not exist!" >&2
exit 1
fi
# Stop and disable the service if it already exists
if [[ -e $target_path ]]; then
verbose "Service $service_name already exists - stopping and disabling."
loudCmd "systemctl disable ${service_name}.service"
loudCmd "systemctl stop ${service_name}.service"
fi
local old_style_unit_exists="f"
# Migrate old style airtime unit exist if it exists
if [[ -e $alt_path && ! -L $alt_path ]]; then
local old_service
old_service=$(echo "$service_name" | sed 's/libretime/airtime/' | sed 's/-analyzer/_analyzer/')
verbose "Old service $old_service already exists - migrating."
loudCmd "systemctl disable ${old_service}.service"
loudCmd "systemctl stop ${old_service}.service"
loudCmd "rm $alt_path"
old_style_unit_exists="t"
fi
# If no user defined, then just copy, otherwise filter
if [[ -z $user ]]; then
loudCmd "cp $source_path $target_path"
else
sed -e "s/User=.*/User=${user}/" \
-e "s/Group=.*/Group=${user}/" "$source_path" > "$target_path"
fi
if [[ $old_style_unit_exists == "t" ]]; then
verbose "Maintaining compatibility with old systemd unit names"
# Alias to old Airtime names
loudCmd "ln -s $source_path $alt_path"
fi
chmod 0644 "$target_path"
chown root:root "$target_path"
verbose "Service ${service_name} installed into ${target_path}"
# Enable and start the service
loudCmd "systemctl enable ${service_name}.service"
verbose "Service ${service_name} enabled and started"
elif $has_upstart_init; then
case "$service_name" in
libretime-analyzer)
source_path="${SCRIPT_DIR}/analyzer/install/upstart/${service_name}.conf"
target_path="/etc/init/${service_name}.conf"
user=${user:-$web_user}
;;
libretime-celery)
source_path="${SCRIPT_DIR}/worker/install/upstart/${service_name}.conf"
target_path="/etc/init/${service_name}.conf"
user=""
;;
libretime-liquidsoap | libretime-playout)
source_path="${SCRIPT_DIR}/playout/install/upstart/${service_name}.conf.template"
target_path="/etc/init/${service_name}.conf"
user=${user:-$web_user}
;;
esac
if [[ ! -e $source_path ]]; then
echo "$0:${FUNCNAME[0]}(): ERROR: service \"$service_name\" with source path \"$source_path\" does not exist!" >&2
exit 1
fi
# Stop the service if it already exists
if [[ -e $target_path ]]; then
verbose "Service $service_name already exists - stopping."
loudCmd "service ${service_name} stop"
fi
# If no user defined, then just copy, otherwise filter
if [[ -z $user ]]; then
loudCmd "cp $source_path $target_path"
else
sed -e "s/WEB_USER/${user}/g" \
-e "/^set[gu]id/{s/www-data/${user}/}" "$source_path" > "$target_path"
fi
chmod 0644 "$target_path"
chown root:root "$target_path"
verbose "Service ${service_name} installed into ${target_path}"
loudCmd "initctl check-config $service_name"
elif $has_systemv_init; then
case "$service_name" in
libretime-analyzer)
source_path="${SCRIPT_DIR}/analyzer/install/sysvinit/${service_name}"
target_path="/etc/init.d/${service_name}"
user=${user:-$web_user}
;;
libretime-celery)
source_path="${SCRIPT_DIR}/worker/install/sysvinit/${service_name}"
target_path="/etc/init.d/${service_name}"
source_config_path="${python_source_path}/${service_name}/install/conf/${service_name}"
target_config_path="/etc/default/${service_name}"
user=""
;;
libretime-liquidsoap | libretime-playout)
source_path="${SCRIPT_DIR}/playout/install/sysvinit/${service_name}"
target_path="/etc/init.d/${service_name}"
user=${user:-$web_user}
;;
esac
if [[ ! -e $source_path ]]; then
echo "$0:${FUNCNAME[0]}(): ERROR: service \"$service_name\" with source path \"$source_path\" does not exist!" >&2
exit 1
fi
# Stop the service if it already exists
if [[ -e $target_path ]]; then
verbose "Service $service_name already exists - stopping."
loudCmd "invoke-rc.d $service_name stop"
fi
# If no user defined, then just copy, otherwise filter
if [[ -z $user ]]; then
loudCmd "cp $source_path $target_path"
[[ -n $source_config_path ]] &&
loudCmd "cp $source_config_path $target_config_path"
else
sed -e "/^USERID/{s/www-data/${user}/}" \
-e "/^GROUPID/{s/www-data/${user}/}" "$source_path" > "$target_path"
fi
chmod 0644 "$target_path"
chown root:root "$target_path"
if [[ -n $target_config_path ]]; then
chmod 0644 "$target_config_path"
chown root:root "$target_config_path"
fi
verbose "Service ${service_name} installed into ${target_path}"
# Create symlinks for the appropriate runlevels
loudCmd "update-rc.d $service_name defaults"
verbose "Service ${service_name} enabled"
fi
return 0
}
# Function to wrap different systemd vs. Upstart init commands depending
# on which init system has been detected. Syntax is similar to systemctl.
# Usage:
# systemInitCommand _command_ [service-name ...]
# Where _command_ is one of: start, stop, status, reload, restart
# enable, disable and either daemon-reload or reload-configuration.
function systemInitCommand() {
local command=$1
shift
case "$command" in
start | stop | status | reload | restart)
if $has_systemd_init; then
loudCmd "systemctl $command $*"
elif $has_upstart_init; then
for svc_name in "$@"; do
loudCmd "service $svc_name $command"
done
elif $has_systemv_init; then
for svc_name in "$@"; do
loudCmd "invoke-rc.d $svc_name $command"
done
fi
;;
enable | disable) # TODO: REMOVE
$has_systemd_init &&
loudCmd "systemctl $command $1.service"
if $has_systemv_init; then
if [[ "$command" == "enable" ]]; then
loudCmd "update-rc.d $1 defaults"
else
loudCmd "update-rc.d $1 enable"
fi
fi
;;
daemon-reload | reload-configuration)
$has_systemd_init &&
loudCmd "systemctl daemon-reload"
$has_upstart_init &&
loudCmd "initctl reload-configuration"
;;
*)
echo -e "$0:${FUNCNAME[0]}(): ERROR: command \"$command\" is not supported!" >&2
exit 1
;;
esac
return 0
}
while :; do
case "$1" in
--help)
showhelp
;;
--version)
showversion
;;
--verbose)
_v=1
;;
--quiet | --silent)
_q=1
;;
--force)
_i=0
;;
--distribution)
if [ "$2" ]; then
dist=$2
shift 2
continue
else
echo 'ERROR: Must specify a non-empty "--distribution DISTRIBUTION" argument.' >&2
exit 1
fi
;;
--distribution=?*)
dist=${1#*=} # Delete everything up to "=" and assign the remainder.
;;
--distribution=)
echo 'ERROR: Must specify a non-empty "--distribution DISTRIBUTION" argument.' >&2
exit 1
;;
--release)
if [ "$2" ]; then
code=$2
shift 2
continue
else
echo 'ERROR: Must specify a non-empty "--release RELEASE" argument.' >&2
exit 1
fi
;;
--release=?*)
code=${1#*=} # Delete everything up to "=" and assign the remainder.
;;
--release=)
echo 'ERROR: Must specify a non-empty "--release RELEASE" argument.' >&2
exit 1
;;
--ignore-dependencies)
ignore_dependencies="t"
;;
--apache)
apache="t"
;;
--icecast)
icecast="t"
;;
--postgres)
postgres="t"
;;
--in-place)
in_place="t"
;;
--web-user)
if [ "$2" ]; then
web_user=$2
shift 2
continue
else
echo 'ERROR: Must specify a non-empty "--web-user WEB_USER" argument.' >&2
exit 1
fi
;;
--web-user=?*)
web_user=${1#*=} # Delete everything up to "=" and assign the remainder.
;;
--web-user=)
echo 'ERROR: Must specify a non-empty "--web-user=WEB_USER" argument.' >&2
exit 1
;;
--web-root)
if [ "$2" ]; then
web_root=$(readlink -f "$2")
shift 2
continue
else
echo 'ERROR: Must specify a non-empty "--web-root WEB_ROOT" argument.' >&2
exit 1
fi
;;
--web-root=?*)
web_root=${1#*=} # Delete everything up to "=" and assign the remainder.
;;
--web-root=)
echo 'ERROR: Must specify a non-empty "--web-root=WEB_ROOT" argument.' >&2
exit 1
;;
--web-port)
echo 'ERROR: Please specify a port number.' >&2
exit 1
;;
--web-port=)
echo 'ERROR: Please specify a port number.' >&2
exit 1
;;
--web-port=?*)
web_port=${1#*=}
;;
--selinux)
selinux="t"
;;
--no-postgres)
skip_postgres=1
;;
--no-rabbitmq)
skip_rabbitmq=1
;;
--)
shift
break
;;
-?*)
for ((i = 1; i < ${#1}; i++)); do
case "${1:$i:1}" in
h | \?)
showhelp
;;
V)
showversion
;;
v)
_v=1
;;
q)
_q=1
;;
f)
_i=0
;;
d)
ignore_dependencies="t"
;;
a)
apache="t"
;;
i)
icecast="t"
;;
p)
postgres="t"
;;
I)
in_place="t"
;;
w)
if [ "$2" ]; then
web_user=$2
continue
else
echo 'ERROR: Must specify a non-empty "-w WEB_USER" argument.' >&2
exit 1
fi
;;
r)
if [ "$2" ]; then
web_root=$(readlink -f $2)
continue
else
echo 'ERROR: Must specify a non-empty "-d WEB_ROOT" argument.' >&2
exit 1
fi
;;
*)
echo "$0: error - unrecognized option '${1:i:1}'" >&2
echo "Try 'install --help' for more information."
exit 1
;;
esac
done
;;
*)
break
;;
esac
shift
done
# If web_root is given, check that it exists
if [[ -n $web_root && ! -d $web_root ]]; then
echo "$web_root directory not found!"
exit 1
fi
echo -e "\n.____ ._____. ___________.__ "
echo "| | |__\_ |_________ ___\__ ___/|__| _____ ____ "
echo "| | | || __ \_ __ \_/ __ \| | | |/ \_/ __ \ "
echo "| |___| || \_\ \ | \/\ ___/| | | | Y Y \ ___/ "
echo "|_______ \__||___ /__| \___ >____| |__|__|_| /\___ >"
echo -e " \/ \/ \/ \/ \/\n"
echo -e "Detecting distribution and release ..."
if [ -e /etc/os-release ]; then
# Access $ID, $VERSION_ID and $PRETTY_NAME
# shellcheck disable=SC1091
source /etc/os-release
echo "Detected distribution id: $ID"
echo "Detected distribution release id: $VERSION_ID"
echo "Detected distribution description: $PRETTY_NAME"
else
ID=unknown
VERSION_ID=unknown
PRETTY_NAME="Unknown distribution and release"
echo "WARNING: /etc/os-release configuration not found. Unable to detect distribution." >&2
if [[ -z $dist || -z $code ]]; then
echo "ERROR: One or both of --distribution and --release options were not specified." >&2
echo "This is an unsupported distribution and/or version!" >&2
exit 1
fi
fi
# Validate --distribution parameter has a sane value for this OS.
if [ -n "$dist" ]; then
dist=${dist,,}
verbose "Checking --distribution \"$dist\" to ensure it has a sane value."
# If $ID detected above does not match parameter, then do some checking
if [ "$dist" != "$ID" ]; then
verbose "Detected distribution \"$ID\" does not match specified one of \"$dist\". Checking ..."
case "$dist" in
centos | rhel)
pkg_installer=/usr/bin/yum
verbose "Detected yum package installer"
;;
debian | ubuntu)
pkg_installer=/usr/bin/apt-get
verbose "Detected apt-get package installer"
;;
*)
echo "ERROR: the value \"$dist\" specified for --distribution is unsupported." >&2
exit 1
;;
esac
if [ ! -x "$pkg_installer" ]; then
echo "ERROR: The value \"$dist\" specified for --distribution does not appear compatible!" >&2
exit 1
fi
fi
fi
# Validate the distribution and release is a supported one; set boolean flags.
is_debian_dist=false
is_debian_buster=false
is_debian_bullseye=false
is_ubuntu_dist=false
is_ubuntu_focal=false
is_ubuntu_bionic=false
is_centos_dist=false
# shellcheck disable=SC2034
is_centos_7=false
is_centos_8=false
# Use specified distribution and release or detected otherwise.
dist="${dist:-$ID}"
code="${code:-$VERSION_ID}"
code="${code,,}"
verbose "Validating dist-code: ${dist}-${code}"
case "${dist}-${code}" in
ubuntu-20.04)
code="focal"
is_ubuntu_dist=true
is_ubuntu_focal=true
;;
ubuntu-18.04)
code="bionic"
# shellcheck disable=SC2034
is_ubuntu_dist=true
is_ubuntu_bionic=true
;;
ubuntu-16.04 | ubuntu-xenial | ubuntu-xenial_docker_minimal)
echo -e "ERROR: Ubuntu Xenial is archived and does not receive any security or other updates since 2021-04-01." >&2
echo -e "The LibreTime installer dropped support for installing LibreTime on Xenial in 3.0.0-alpha.10." >&2
exit 1
;;
debian-9 | debian-stretch)
echo -e "ERROR: Debian Stretch is archived and does not receive any security or other updates since 2020-06-06." >&2
echo -e "The LibreTime installer dropped support for installing LibreTime on Stretch in 3.0.0-alpha.10." >&2
exit 1
;;
debian-10 | debian-buster)
code="buster"
is_debian_dist=true
is_debian_buster=true
;;
debian-11 | debian-bullseye)
code="bullseye"
is_debian_dist=true
is_debian_bullseye=true
;;
#Fix for Raspbian 9 (stretch)
raspbian-9)
echo -e "ERROR: Raspbian Stretch is archived and does not receive any security or other updates since 2020-06-06." >&2
echo -e "The LibreTime installer dropped support for installing LibreTime on Stretch in 3.0.0-alpha.10." >&2
exit 1
;;
#End of fix
#Fix for Raspbian 10 (buster)
raspbian-10)
code="buster"
dist="debian"
# shellcheck disable=SC2034
is_debian_dist=true
is_debian_buster=true
;;
#End of fix
debian-8 | debian-jessie)
echo -e "ERROR: Debian Jessie is archived and does not receive any security or other updates since 2018-05-17." >&2
echo -e "The LibreTime installer dropped support for installing LibreTime on Jessie in 3.0.0-alpha.8." >&2
exit 1
;;
centos-8)
is_centos_dist=true
# shellcheck disable=SC2034
is_centos_8=true
;;
*)
echo -e "ERROR: Distribution \"$PRETTY_NAME\" is not supported with \"${dist}-${code}\"!" >&2
exit 1
;;
esac
verbose "Using distribution id \"$dist\", release code \"$code\""
# Detect init system type
systemInitDetect
# SysV is not supported, fail fast instead of cleaning the whole script
# from sysv related entries.
if $has_systemv_init; then
echo "ERROR: Installation on SysV init system is not supported!" >&2
exit 1
fi
# Upstart is not supported, fail fast instead of cleaning the whole script
# from Upstart related entries.
if $has_upstart_init; then
echo "ERROR: Installation on Upstart init system is not supported!" >&2
exit 1
fi
if $is_centos_dist; then
python_bin="python3.8"
apache_bin="httpd"
apache_service="httpd"
web_user="${web_user:-apache}"
else
python_bin="python3"
apache_bin="apache2ctl"
apache_service="apache2"
web_user="${web_user:-www-data}"
fi
if [ "$ignore_dependencies" = "f" ]; then
set +e
loud "\n-----------------------------------------------------"
loud " * Installing External Dependencies * "
loud "-----------------------------------------------------"
if [ -x /usr/bin/apt-get ]; then
verbose "\n * Reading packages.ini files..."
packages_files=(
"${SCRIPT_DIR}/"
"${SCRIPT_DIR}/legacy"
"${SCRIPT_DIR}/api"
"${SCRIPT_DIR}/analyzer"
"${SCRIPT_DIR}/playout"
)
set -e
package_list=$(
"${SCRIPT_DIR}/tools/packages.py" --format=line "${code}" "${packages_files[@]}" ||
(echo "ERROR: could not generate packages list" >&2 && exit 1)
)
set +e
loudCmd "apt-get -q update"
loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y install $package_list"
[[ "$in_place" == "t" ]] && loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y install git"
else
echo "WARNING: installing dependencies is not supported for this distribution" >&2
fi
set -e
else
checkCommandExists "${apache_bin}"
checkCommandExists "rabbitmqctl"
checkCommandExists "psql"
if [ "$in_place" = "t" ]; then
checkCommandExists "git"
fi
fi
# Check if composer exists and install if it doesn't
set +e
eval hash "composer" 2> /dev/null
commandFound=$?
set -e
if [[ ! ${commandFound} -eq 0 ]]; then
curl -sS https://getcomposer.org/installer > get-composer.php
php ./get-composer.php --install-dir=/usr/local/bin --filename=composer
rm get-composer.php
PATH="${PATH}:/usr/local/bin"
fi
make VERSION # Create a VERSION file
make -C legacy build # Install php dependencies with composer
if [ -f /etc/airtime/airtime.conf ]; then
# TODO use VERSION or some other way to check for updates and handle
# media-monitor case on it's own
OLD_CONF=$(grep -F "[media-monitor]" /etc/airtime/airtime.conf || true)
if [ -n "${OLD_CONF}" ]; then
upgrade="t"
set +e
verbose "Stopping airtime services..."
systemInitCommand stop airtime_analyzer airtime-celery airtime-playout airtime-liquidsoap airtime-media-monitor
verbose "...Done"
verbose "Disabling obsolete services..."
systemInitCommand disable airtime-media-monitor
verbose "...Done"
echo "Looks like you have an old version of Airtime. Your current /etc/airtime/airtime.conf \
will be moved to /etc/airtime/airtime.conf.tmp"
# If we don't remove the existing python files in /usr/lib and the
# /etc/init.d startup scripts, services won't work properly
if [ -d /usr/lib/airtime/ ]; then
rm -rf /usr/lib/airtime/
fi
rm -f /etc/init.d/airtime*
rm -f /etc/init/airtime*
rm -f /etc/default/airtime-celery
if [ "$apache" = "t" ]; then
# If the user selects an "in-place" install or passes in a web root,
# we need to replace the old apache airtime.conf
rm -f /etc/apache2/sites-available/airtime.conf /etc/apache2/sites-enabled/airtime.conf
fi
if [[ -d "/usr/share/airtime" && $web_root == "/usr/share/airtime" ]]; then
rm -rf "/usr/share/airtime"
fi
mv /etc/airtime/airtime.conf /etc/airtime/airtime.conf.tmp
set -e
fi
fi
API2_APACHE_CONF=$(grep -F "ProxyPass" /etc/apache2/sites-available/airtime.conf || true)
if [[ -z "${API2_APACHE_CONF}" && "$apache" == "t" ]]; then
# Remove Apache configuration so that the ProxyPass configuration for API 2.0
# is installed
rm -f /etc/apache2/sites-available/airtime.conf /etc/apache2/sites-enabled/airtime.conf
fi
if [[ "$apache" = "f" && ${_i} -eq 1 ]]; then
echo -e "Install default Airtime apache configuration? (Y/n): \c"
read IN
IN=${IN:-$default_value}
if [[ "$IN" = "y" || "$IN" = "Y" ]]; then
apache="t"
fi
fi
if [ "$in_place" = "t" ]; then
verbose "\n * Setting current Airtime directory as web root..."
web_root=${AIRTIMEROOT}/legacy/public
elif [ -n "$web_root" ]; then
verbose "\n * Creating Apache web root directory..."
cp -R ${AIRTIMEROOT}/legacy ${web_root}
cp ${AIRTIMEROOT}/VERSION ${web_root}
web_root=${web_root}/legacy/public/
else
verbose "\n * Creating default Apache web root directory /usr/share/airtime/php..."
web_root="/usr/share/airtime/php"
mkdir -p ${web_root}
cp -R ${AIRTIMEROOT}/legacy ${web_root}
cp ${AIRTIMEROOT}/VERSION ${web_root}
web_root=${web_root}/legacy/public/
fi
verbose "...Done"
if [ "$apache" = "t" ]; then
loud "\n-----------------------------------------------------"
loud " * Configuring Apache * "
loud "-----------------------------------------------------"
# Detect Apache root folder, e.g. /etc/apache2 or /etc/httpd
eval "$($apache_bin -V | awk '/HTTPD_ROOT|SERVER_CONFIG_FILE/ { print $2 }')"
apache_conf="${HTTPD_ROOT}/${SERVER_CONFIG_FILE}"
verbose "Detected Apache root folder is: ${HTTPD_ROOT}"
if [[ ! -e $apache_conf ]]; then
echo -e "ERROR: Apache binary \"$apache_bin\" points to a non-existent file \"$apache_conf\""
exit 1
fi
verbose "Detected Apache primary .conf file is: ${apache_conf}"
if [[ -d ${HTTPD_ROOT}/sites-available ]]; then # debian & ubuntu
apache_sitedir="${HTTPD_ROOT}/sites-available/"
elif [[ -d ${HTTPD_ROOT}/conf.d ]]; then # centos
apache_sitedir="${HTTPD_ROOT}/conf.d/"
else
echo -e "ERROR: unknown location of Apache sites-available or virtual host directory!" >&2
exit 1
fi
verbose "Detected Apache sites configuration folder: ${apache_sitedir}"
set +e
# Parse: Server version: Apache/2.2.22 (Ubuntu) -> 2
apache_major_version=$($apache_bin -v | awk -F'[ /.]+' 'NR == 1 { print $4 }')
set -e
if [[ "$apache_major_version" -ge 2 ]]; then
airtimeconfigfile="airtime.conf"
oldconfigfile="airtime-vhost.conf"
else
airtimeconfigfile="airtime"
oldconfigfile="airtime-vhost"
fi
# If we're upgrading (installing over an existing Airtime install) and we've been told to
# install apache, we should overwrite any existing configuration. If we don't do this, doing
# an in-place installation over an old Airtime install (which installs to /usr/share by default)
# will fail
if [[ "$upgrade" == "t" || ! -f "${apache_sitedir}${airtimeconfigfile}" ]]; then
verbose "\n * Creating Apache config for Airtime..."
listen_port=""
if [ "$web_port" != "80" ]; then
listen_port="Listen ${web_port}"
fi
apache_template_file=${SCRIPT_DIR}/installer/apache/airtime-vhost-2.4
if [[ "$apache_major_version" -eq 1 ]]; then
# fall back to apache 1 config
apache_template_file=${SCRIPT_DIR}/installer/apache/airtime-vhost
fi
sed \
-e "s@WEB_PORT_LISTEN@${listen_port}@g" \
-e "s@WEB_PORT@${web_port}@g" \
-e "s@WEB_ROOT@${web_root}@g" \
${apache_template_file} > ${apache_sitedir}${airtimeconfigfile}
# The a2ensite/a2dissite utilities are not available on CentOS
if [[ -x /usr/sbin/a2ensite ]]; then
loudCmd "a2dissite 000-default"
# If Airtime was previously installed with apt, the vhost file name is different,
# so we need to specifically disable it.
if [ -f "/etc/apache2/sites-available/${oldconfigfile}" ]; then
loudCmd "a2dissite airtime-vhost"
fi
loudCmd "a2ensite airtime"
fi
else
verbose "\nApache config for Airtime already exists, skipping"
fi
fi
if [[ "$icecast" == "f" && ${_i} -eq 1 ]]; then
echo -e "Install default Airtime Icecast configuration? (Y/n): \c"
read -r IN
IN=${IN:-$default_value}
if [[ $IN == "y" || $IN == "Y" ]]; then
icecast="t"
fi
fi
if [ "$icecast" = "t" ]; then
loud "\n-----------------------------------------------------"
loud " * Configuring Icecast * "
loud "-----------------------------------------------------"
verbose "\n * Enabling Icecast 2..."
icecast_unit_name="icecast2"
if [ "$dist" != "centos" ]; then
sed -i 's/ENABLE=false/ENABLE=true/g' /etc/default/icecast2
icecast_config="/etc/icecast2/icecast.xml"
else
icecast_unit_name="icecast"
icecast_config="/etc/icecast.xml"
fi
systemInitCommand enable "${icecast_unit_name}"
# only update icecast password if
if [ ! -e "/etc/airtime/airtime.conf" ] && [ ! -e "/etc/airtime/airtime.conf.tmp" ]; then
icecast_pass=$(tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c"${1:-12}")
echo "$icecast_pass" > /tmp/icecast_pass
loud "\n New install detected setting icecast password to random value."
xmlstarlet ed --inplace -u /icecast/authentication/source-password -v "$icecast_pass" "$icecast_config"
xmlstarlet ed --inplace -u /icecast/authentication/relay-password -v "$icecast_pass" "$icecast_config"
xmlstarlet ed --inplace -u /icecast/authentication/admin-password -v "$icecast_pass" "$icecast_config"
fi
# restart in case icecast was already started (like is the case on debian)
systemInitCommand restart ${icecast_unit_name}
verbose "...Done"
fi
loud "\n-----------------------------------------------------"
loud " * Installing Airtime Services * "
loud "-----------------------------------------------------"
LIBRETIME_WORKING_DIR="/var/lib/libretime"
python_version=$($python_bin --version 2>&1 | awk '{ print $2 }')
verbose "Detected Python version: $python_version"
pip_cmd="$python_bin -m pip"
verbose "\n * Installing necessary python services..."
loudCmd "$pip_cmd install --upgrade setuptools~=58.0"
verbose "...Done"
if [ ! -d /var/log/airtime ]; then
loud "\n-----------------------------------------------------"
loud " * Installing Log Files * "
loud "-----------------------------------------------------"
verbose "\n * Creating /var/log/airtime"
loudCmd "mkdir -p /var/log/airtime"
mkdir_and_chown "$web_user:$web_user" "/var/log/libretime"
verbose "\n * Copying logrotate files..."
loudCmd "cp ${AIRTIMEROOT}/legacy/build/airtime-php.logrotate /etc/logrotate.d/airtime-php"
loudCmd "cp ${AIRTIMEROOT}/playout/install/logrotate/libretime-liquidsoap.conf /etc/logrotate.d/libretime-liquidsoap"
fi
verbose "\n * Installing Shared..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/shared"
verbose "...Done"
verbose "\n * Installing API client..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/api_client"
verbose "...Done"
verbose "\n * Installing playout and liquidsoap..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/playout"
mkdir_and_chown "${web_user}:${web_user}" "${LIBRETIME_WORKING_DIR}/playout"
loudCmd "mkdir -p /var/log/airtime/{pypo,pypo-liquidsoap} /var/tmp/airtime/pypo/{cache,files,tmp} /var/tmp/airtime/show-recorder/"
loudCmd "chown -R ${web_user}:${web_user} /var/log/airtime/{pypo,pypo-liquidsoap} /var/tmp/airtime/pypo/{cache,files,tmp} /var/tmp/airtime/show-recorder/"
systemInitInstall libretime-liquidsoap "$web_user"
systemInitInstall libretime-playout "$web_user"
verbose "...Done"
verbose "\n * Installing celery..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/worker"
# Create the Celery user
if $is_centos_dist; then
loudCmd "id celery 2>/dev/null || adduser --no-create-home -c 'LibreTime Celery' -r celery || true"
else
loudCmd "id celery 2>/dev/null || adduser --no-create-home --gecos 'LibreTime Celery' --disabled-login --firstuid 1 --lastuid 999 celery"
fi
# Add celery to the www-data group
loudCmd "usermod -G ${web_user} -a celery"
# CentOS installs celery in /usr/bin which differs from other distros. Make
# available in /usr/local/bin as systemd requires an absolute path.
[[ ! -e /usr/local/bin/celery ]] && ln -s /usr/bin/celery /usr/local/bin/celery
systemInitInstall libretime-celery
verbose "...Done"
verbose "\n * Installing libretime-analyzer..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/analyzer"
mkdir_and_chown "${web_user}:${web_user}" "${LIBRETIME_WORKING_DIR}/analyzer"
systemInitInstall libretime-analyzer "$web_user"
verbose "...Done"
verbose "\n * Installing API..."
loudCmd "$pip_cmd install ${AIRTIMEROOT}/api[prod]"
systemInitInstall libretime-api "$web_user"
mkdir -p /etc/airtime
sed -e "s@WEB_USER@${web_user}@g" \
-e "s@WEB_ROOT@${web_root}@g" \
"${AIRTIMEROOT}/installer/uwsgi/libretime-api.ini" > /etc/airtime/libretime-api.ini
loudCmd "libretime-api collectstatic --clear --noinput"
verbose "...Done"
verbose "\n * Setting permissions on /var/log/airtime..."
# Make the airtime log directory group-writable
loudCmd "chmod -R 775 /var/log/airtime"
loudCmd "chown -R ${web_user}:${web_user} /var/log/airtime/"
verbose "\n * Setting permissions on /var/tmp/airtime..."
loudCmd "chmod -R a+x /var/tmp/airtime"
loudCmd "chown -R ${web_user}:${web_user} /var/tmp/airtime/"
loud "\n-----------------------------------------------------"
loud " * Configuring PHP in Apache * "
loud "-----------------------------------------------------"
# Test common locations for php conf directory
php_conf_dirs=(
"/etc/php/7.4/apache2/conf.d" # Debian Bullseye, Ubuntu Focal
"/etc/php/7.3/apache2/conf.d" # Debian Buster
"/etc/php/7.2/apache2/conf.d" # Ubuntu Bionic
"/etc/php/7.0/apache2/conf.d" # Ubuntu Xenial
"/etc/php5/apache2/conf.d" # Debian Stretch, Debian Jessie, Ubuntu Trusty
"/etc/php.d" # CentOS 7
)
for php_conf in "${php_conf_dirs[@]}"; do
[[ -d $php_conf ]] && break
done
if [[ -d $php_conf ]]; then
libretime_phpini="${php_conf}/airtime.ini"
else
echo -e "ERROR: PHP Apache configuration folder does not exist or is in an unknown location!" >&2
exit 1
fi
verbose "Detected php conf directory at: $php_conf"
if [ ! -f "${libretime_phpini}" ]; then
verbose "\n * Creating LibreTime PHP config for Apache..."
cp ${SCRIPT_DIR}/installer/php/airtime.ini ${libretime_phpini}
else
verbose "\nAirtime PHP config for Apache already exists, skipping"
fi
# Enable Apache modules
if $is_debian_bullseye || $is_ubuntu_focal; then
loudCmd "a2enmod rewrite php7.4 proxy proxy_http"
elif $is_debian_buster; then
loudCmd "a2enmod rewrite php7.3 proxy proxy_http"
elif $is_ubuntu_bionic; then
loudCmd "a2enmod rewrite php7.2 proxy proxy_http"
elif $is_centos_dist; then
verbose "TODO: enable Apache modules mod_rewrite, mod_php, mod_proxy and mod_proxy_http manually"
else
loudCmd "a2enmod rewrite php5 proxy proxy_http"
fi
if [ $skip_postgres -eq 0 ]; then
loud "\n-----------------------------------------------------"
loud " * Configuring PostgreSQL * "
loud "-----------------------------------------------------"
# Ensure postgres is running - It isn't after you install the postgres package on Ubuntu 15.04
systemInitCommand start postgresql
setupAirtimePostgresUser() {
# here-doc to execute this block as postgres user
su postgres << 'EOF'
set +e
count=$(psql -d postgres -tAc "SELECT count(*) FROM pg_roles WHERE rolname='airtime';")
if [[ $count -eq 0 ]]; then
psql -d postgres -tAc "CREATE USER airtime WITH ENCRYPTED PASSWORD 'airtime'; ALTER USER airtime CREATEDB;"
[[ $? -eq 0 ]] &&
echo "Created airtime user in PostgreSQL" ||
echo "$0:${FUNCNAME}(): ERROR: Can't create airtime user in PostgreSQL!"
else
echo "airtime user already exists in PostgreSQL"
fi
set -e
# don't indent this!
EOF
}
if [ "$postgres" = "t" ]; then
setupAirtimePostgresUser
elif [ ${_i} -eq 1 ]; then
echo -e "Create default airtime postgres user? (Y/n): \c"
read IN
IN=${IN:-$default_value}
if [[ "$IN" = "y" || "$IN" = "Y" ]]; then
setupAirtimePostgresUser
fi
fi
fi
if [ $skip_rabbitmq -eq 0 ]; then
loud "\n-----------------------------------------------------"
loud " * Configuring RabbitMQ * "
loud "-----------------------------------------------------"
RABBITMQ_VHOST=/airtime
RABBITMQ_USER=airtime
RABBITMQ_PASSWORD=airtime
# EXCHANGES="airtime-pypo|pypo-fetch|airtime-analyzer|media-monitor"
# Ignore errors in this check to avoid dying when vhost isn't found
set +e
rabbitmqctl list_vhosts | grep -w "^${RABBITMQ_VHOST}$" > /dev/null
RESULT="$?"
set -e
# Only run these if the vhost doesn't exist
if [ "$RESULT" != "0" ]; then
verbose "\n * Creating RabbitMQ user ${RABBITMQ_USER}..."
rabbitmqctl add_vhost ${RABBITMQ_VHOST}
rabbitmqctl add_user ${RABBITMQ_USER} ${RABBITMQ_PASSWORD}
else
verbose "\nRabbitMQ user already exists, skipping creation"
fi
verbose "\n * Setting RabbitMQ user permissions..."
#loudCmd "rabbitmqctl set_permissions -p ${RABBITMQ_VHOST} ${RABBITMQ_USER} \"$EXCHANGES\" \"$EXCHANGES\" \"$EXCHANGES\""
loudCmd "rabbitmqctl set_permissions -p ${RABBITMQ_VHOST} ${RABBITMQ_USER} .\* .\* .\*"
fi
if [ ! -d "/etc/airtime" ]; then
loud "\n-----------------------------------------------------"
loud " * Installing Libretime * "
loud "-----------------------------------------------------"
verbose "\n * Creating /etc/airtime/ directory..."
mkdir /etc/airtime
fi
if [ "$icecast" = "t" ]; then
if [ ! -e "/etc/airtime/airtime.conf" ] && [ ! -e "/etc/airtime/airtime.conf.tmp" ]; then
# need to copy the icecast_pass from temp to /etc/airtime so web-based installer can read it
cp /tmp/icecast_pass /etc/airtime/icecast_pass
fi
fi
chown -R ${web_user}:${web_user} /etc/airtime
if [ ! -d "/srv/airtime" ]; then
mkdir -p /srv/airtime
fi
chown -R ${web_user}:${web_user} /srv/airtime
# If the user requested it we run restorecon on files that need
# tagging for selinux.
if [ "$selinux" = "t" ]; then
loud "\n-----------------------------------------------------"
loud " * Restoring SELinux Tags * "
loud "-----------------------------------------------------"
verbose "\n * Running restorecon..."
loudCmd "restorecon -Rv /etc/airtime /srv/airtime > /dev/null 2>&1"
verbose "...Done"
fi
verbose "\n * Reloading apache..."
systemInitCommand restart ${apache_service}
# NOTE: ip command works on all supported platforms
if $is_centos_dist; then
IP=$(ip -o -4 address show dev eth0 | grep -Po 'inet \K[\d.]+')
else
# not on centos
ip_device="eth0"
IP=$(ifconfig ${ip_device} 2> /dev/null | awk -F'[ :]+' '/inet addr:/ {print $4}')
fi
verbose "...Done"
echo -e "\n-----------------------------------------------------"
echo " * Basic Setup DONE! * "
echo " "
echo " To get started with Libretime, visit ${IP} "
echo " or, if you've set up your own web configuration, "
echo " the Libretime webroot on your webserver "
echo "-----------------------------------------------------"