diff --git a/Vagrantfile b/Vagrantfile index 23cc06cb2..eb3abc9b9 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -40,35 +40,35 @@ Vagrant.configure("2") do |config| # define all the OS boxes we support config.vm.define "ubuntu-xenial" do |os| os.vm.box = "bento/ubuntu-16.04" - provision_libretime(os, "ubuntu.sh", installer_args + "--distribution=ubuntu --release=xenial") + provision_libretime(os, "ubuntu.sh", installer_args) end config.vm.define "ubuntu-trusty" do |os| os.vm.box = "bento/ubuntu-14.04" - provision_libretime(os, "ubuntu.sh", installer_args + "--distribution=ubuntu --release=trusty") + provision_libretime(os, "ubuntu.sh", installer_args) end config.vm.define "ubuntu" do |os| STDERR.puts 'WARNING: The "ubuntu" option is deprecated. Please migrate to "ubuntu-trusty".' STDERR.puts os.vm.box = "ubuntu/trusty64" - provision_libretime(os, "ubuntu.sh", installer_args + "--distribution=ubuntu --release=trusty") + provision_libretime(os, "ubuntu.sh", installer_args) end config.vm.define "debian-jessie" do |os| os.vm.box = "bento/debian-8.7" - provision_libretime(os, "debian.sh", installer_args + "--distribution=debian --release=jessie") + provision_libretime(os, "debian.sh", installer_args) end config.vm.define "debian-wheezy" do |os| os.vm.box = "bento/debian-7.11" - provision_libretime(os, "debian.sh", installer_args + "--distribution=debian --release=wheezy") + provision_libretime(os, "debian.sh", installer_args) end config.vm.define "debian" do |os| STDERR.puts 'WARNING: The "debian" option is deprecated. Please migrate to "debian-jessie".' STDERR.puts os.vm.box = "debian/jessie64" - provision_libretime(os, "debian.sh", installer_args + "--distribution=debian --release=jessie") + provision_libretime(os, "debian.sh", installer_args) end config.vm.define "centos" do |os| os.vm.box = 'centos/7' - provision_libretime(os, "centos.sh", installer_args + "--ignore-dependencies --distribution=centos --web-user=apache --selinux") + provision_libretime(os, "centos.sh", installer_args + "--selinux") end def provision_libretime(config, prepare_script, installer_args) diff --git a/install b/install index 48f27270b..339bf6325 100755 --- a/install +++ b/install @@ -62,7 +62,7 @@ showversion () { exit 0 } -web_user="www-data" +web_user="" web_root="" web_port="80" in_place="f" @@ -80,7 +80,7 @@ _q=0 upgrade="f" dist="" code="" -apache_bin="apache2" +apache_bin="" function verbose() { @@ -95,9 +95,11 @@ function loud() { fi } -# Evaluate commands silently if quiet +# Evaluate commands silently if quiet. +# If not quiet, output command if verbose. function loudCmd() { if [[ ${_q} -eq 0 ]]; then + verbose "$@" eval $@ else eval $@ > /dev/null @@ -116,6 +118,225 @@ function checkCommandExists() { 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 '/sbin/init' (Debian Wheezy & Ubuntu Trusty) + # returns '(/usr)?/lib/systemd/systemd' (Debian Jessie, Ubuntu Xenial, CentOS 7) + verbose "Detected path to PID=1 process: $pid_1_path" + # Get package of PID=1 path as it identifies the init system + pid_1_package=$(dpkg -S $pid_1_path 2>/dev/null || + rpm --qf '%{name}\n' -qf $pid_1_path 2>/dev/null) + 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" + local source_base_path="" + local source_path="" + local target_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 + # TODO: move .service files under python_apps/.../install/systemd + source_path="${SCRIPT_DIR-$PWD}/installer/systemd/${service_name}.service" + target_path="/etc/systemd/system/${service_name}.service" + if [[ ! -e $source_path ]]; then + echo "$0:${FUNCNAME}(): 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 + # 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 + 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" + loudCmd "systemctl start ${service_name}.service" + verbose "Service ${service_name} enabled and started" + elif $has_upstart_init; then + case "$service_name" in + airtime_analyzer) + source_path="${python_source_path}/${service_name}/install/upstart/${service_name}.conf" + target_path="/etc/init/${service_name}.conf" + user=${user:-$web_user} + ;; + airtime-celery) + source_path="${python_source_path}/${service_name}/install/upstart/${service_name}.conf" + target_path="/etc/init/${service_name}.conf" + user="" + ;; + airtime-liquidsoap|airtime-playout) + source_path="${python_source_path}/pypo/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}(): 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" + # Start the service + loudCmd "service ${service_name} start" + verbose "Service ${service_name} started" + elif $has_systemv_init; then + case "$service_name" in + airtime_analyzer) + source_path="${python_source_path}/${service_name}/install/sysvinit/${service_name}" + target_path="/etc/init.d/${service_name}" + user=${user:-$web_user} + ;; + airtime-celery) + source_path="${python_source_path}/${service_name}/install/initd/${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="" + ;; + airtime-liquidsoap|airtime-playout) + source_path="${python_source_path}/pypo/install/sysvinit/${service_name}" + target_path="/etc/init.d/${service_name}" + user=${user:-$web_user} + ;; + esac + if [[ ! -e $source_path ]]; then + echo "$0:${FUNCNAME}(): 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" + # Start the service + loudCmd "invoke-rc.d $service_name start" + verbose "Service ${service_name} enabled and started" + 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}(): ERROR: command \"$command\" is not supported!" >&2 + exit 1 + ;; + esac + return 0 +} + while :; do case "$1" in --help) @@ -309,35 +530,137 @@ echo "| |___| || \_\ \ | \/\ ___/| | | | Y Y \ ___/ " echo "|_______ \__||___ /__| \___ >____| |__|__|_| /\___ >" echo -e " \/ \/ \/ \/ \/\n" -if [ "$dist" = "centos" ]; then +echo -e "Detecting distribution and release ..." +if [ -e /etc/os-release ]; then + # Access $ID, $VERSION_ID and $PRETTY_NAME + 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" -o -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_jessie=false +is_debian_wheezy=false +is_ubuntu_dist=false +is_ubuntu_xenial=false +is_ubuntu_trusty=false +is_centos_dist=false +is_centos_7=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-16.04|ubuntu-xenial) + code="xenial" + is_ubuntu_dist=true + is_ubuntu_xenial=true + ;; + ubuntu-14.04|ubuntu-trusty) + code="trusty" + is_ubuntu_dist=true + is_ubuntu_trusty=true + ;; + debian-8|debian-jessie) + code="jessie" + is_debian_dist=true + is_debian_jessie=true + ;; + debian-7|debian-wheezy) + code="wheezy" + is_debian_dist=true + is_debian_wheezy=true + ;; + centos-7) + is_centos_dist=true + is_centos_7=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 + +if $is_centos_dist; then apache_bin="httpd" + apache_service="httpd" + web_user="${web_user:-apache}" +else + apache_bin="apache2ctl" + apache_service="apache2" + web_user="${web_user:-www-data}" fi if [ "$ignore_dependencies" = "f" ]; then set +e - if [ -z "${dist}" ]; then - loudCmd "apt-get -y --force-yes install lsb-release" - dist=`lsb_release -ds | awk '{print tolower($1);}'` - code=`lsb_release -cs` - fi - loud "\n-----------------------------------------------------" loud " * Installing External Dependencies * " loud "-----------------------------------------------------" - verbose "\n * Reading requirements-${dist,,}-${code,,}.apt..." - loudCmd "apt-get update" - if [ -f ${SCRIPT_DIR}/installer/lib/requirements-${dist,,}-${code,,}.apt ]; then - if [ ${dist,,} == "ubuntu" ] && [ ${code,,} == "xenial" ]; then - loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --allow-downgrades --allow-remove-essential --allow-change-held-packages install $(grep -vE '^\s*#' ${SCRIPT_DIR}/installer/lib/requirements-${dist,,}-${code,,}.apt | tr '\n' ' ')" - else - loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --force-yes install $(grep -vE '^\s*#' ${SCRIPT_DIR}/installer/lib/requirements-${dist,,}-${code,,}.apt | tr '\n' ' ')" + if [ -x /usr/bin/apt-get ]; then + verbose "\n * Reading requirements-${dist}-${code}.apt..." + loudCmd "apt-get update" + package_list_file="${SCRIPT_DIR}/installer/lib/requirements-${dist}-${code}.apt" + if [ ! -f "$package_list_file" ]; then + echo "ERROR: package file does not exist: $package_list_file" >&2 + exit 1 + fi + # For apt-get version 1.1 or higher, --force-yes is deprecated so use new options. + apt_force_options="--allow-downgrades --allow-remove-essential --allow-change-held-packages" + # Get apt-get version by returning the 2nd parameter from the 1st line of output + apt_version=$(apt-get --version |awk 'NR == 1 { print $2 }') + # returns: 0.9.7.9 (Debian Wheezy) + # returns: 1.0.1ubuntu2 (Ubuntu Trusty) + # returns: 1.0.9.8.4 (Debian Jessie) + # returns: 1.2.9 (Ubuntu Xenial) + verbose "Detected apt-get version as: $apt_version" + apt_version_formatted=$(awk 'BEGIN {FS = "."} {printf "%03d.%03d\n", $1,$2}' <<< $apt_version) + [[ "$apt_version_formatted" < "001.001" ]] && apt_force_options="--force-yes" + verbose "Using apt-get force options: $apt_force_options" + loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m ${apt_force_options} install $(grep -vE '^\s*#' $package_list_file | tr '\n' ' ')" + if [ "$in_place" = "t" ]; then + loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m install git" fi else - loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --force-yes install $(grep -vE '^\s*#' ${SCRIPT_DIR}/installer/lib/requirements-ubuntu-trusty.apt | tr '\n' ' ')" - fi - if [ "$in_place" = "t" ]; then - loudCmd "DEBIAN_FRONTEND=noninteractive apt-get -y -m --force-yes install git" + echo "WARNING: installing dependencies is not supported for this distribution" >&2 fi set -e else @@ -371,10 +694,7 @@ if [ -f /etc/airtime/airtime.conf ]; then set +e verbose "Stopping airtime services..." - loudCmd "service airtime-playout stop" - loudCmd "service airtime-celery stop" - loudCmd "service airtime_analyzer stop" - loudCmd "service airtime-liquidsoap stop" + systemInitCommand stop airtime_analyzer airtime-celery airtime-playout airtime-liquidsoap verbose "...Done" echo "Looks like you have an old version of Airtime. Your current /etc/airtime/airtime.conf \ @@ -385,12 +705,15 @@ will be moved to /etc/airtime/airtime.conf.tmp" rm -rf /usr/lib/airtime/ fi - rm /etc/init.d/airtime-* - + rm -f /etc/init.d/airtime* + rm -f /etc/init/airtime* + rm -f /etc/default/airtime-celery + rm -f /etc/systemd/system/airtime* + 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 /etc/apache2/sites-available/airtime.conf + rm /etc/apache2/sites-available/airtime.conf /etc/apache2/sites-enabled/airtime.conf fi if [ -d /usr/share/airtime -a web_root = /usr/share/airtime ]; then @@ -432,17 +755,31 @@ if [ "$apache" = "t" ]; then loud "\n-----------------------------------------------------" loud " * Configuring Apache * " loud "-----------------------------------------------------" - apache_sitedir="/etc/apache2/sites-available/" - if [ "$dist" = "centos" ]; then - apache_sitedir="/etc/httpd/conf.d/" + # 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 - $apache_bin -v | grep "2\.4" > /dev/null - apacheversion=$? + # Parse: Server version: Apache/2.2.22 (Ubuntu) -> 2 + apache_major_version=$($apache_bin -v |awk -F'[ /.]+' 'NR == 1 { print $4 }') set -e - if [ "$apacheversion" != "1" ]; then + if [[ "$apache_major_version" -ge 2 ]]; then airtimeconfigfile="airtime.conf" oldconfigfile="airtime-vhost.conf" else @@ -460,9 +797,9 @@ if [ "$apache" = "t" ]; then if [ "$web_port" != "80" ]; then listen_port="Listen ${web_port}" fi - + apache_template_file=${SCRIPT_DIR}/installer/apache/airtime-vhost-2.4 - if [ "$apacheversion" = "1" ]; then + if [[ "$apache_major_version" -eq 1 ]]; then # fall back to apache 1 config apache_template_file=${SCRIPT_DIR}/installer/apache/airtime-vhost fi @@ -472,15 +809,14 @@ if [ "$apache" = "t" ]; then -e "s@WEB_ROOT@${web_root}@g" \ ${apache_template_file} > ${apache_sitedir}${airtimeconfigfile} - if [ "$dist" != "centos" ]; then + # The a2ensite/a2dissite utilities are not available on CentOS + if [[ -x /usr/sbin/a2ensite ]]; then loudCmd "a2dissite 000-default" - fi - # 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 - if [ "$dist" != "centos" ]; then + # 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 @@ -508,10 +844,8 @@ if [ "$icecast" = "t" ]; then else icecast_unit_name="icecast" fi - set +e # restart in case icecast was already started (like is the case on debian) - loudCmd "service ${icecast_unit_name} restart" - set -e + systemInitCommand restart ${icecast_unit_name} verbose "...Done" fi @@ -523,13 +857,13 @@ verbose "\n * Installing necessary python services..." loudCmd "pip install setuptools --upgrade" verbose "...Done" -# Ubuntu trusty needs a workaround for python version SSL downloads +# Ubuntu Trusty and Debian Wheezy needs a workaround for python version SSL downloads # This affects all python installs where python < 2.7.9 -use_pyopenssl="" -if [ "$dist" != "debian" ] || [ "$code" = "wheezy" ]; then - use_pyopenssl="t" -fi -if [ "$use_pyopenssl" = "t" ]; then +python_version=$(python --version 2>&1 | awk '{ print $2 }') +verbose "Detected Python version: $python_version" +# Convert version so each segment is zero padded for easy comparison +python_version_formatted=$(awk 'BEGIN {FS = "."} {printf "%03d.%03d.%03d\n", $1,$2,$3}' <<< $python_version) +if [[ "$python_version_formatted" < "002.007.009" ]]; then verbose "\n * Installing pyOpenSSL and ca db for SNI support..." loudCmd "pip install pyOpenSSL cryptography idna certifi --upgrade" verbose "...Done" @@ -550,76 +884,34 @@ loudCmd "python ${AIRTIMEROOT}/python_apps/api_clients/setup.py install --instal verbose "...Done" verbose "\n * Installing pypo and liquidsoap..." -loudCmd "python ${AIRTIMEROOT}/python_apps/pypo/setup.py install --install-scripts=/usr/bin" +loudCmd "python ${AIRTIMEROOT}/python_apps/pypo/setup.py install --install-scripts=/usr/bin --no-init-script" +systemInitInstall airtime-liquidsoap $web_user +systemInitInstall airtime-playout $web_user verbose "...Done" verbose "\n * Installing airtime-celery..." -loudCmd "python ${AIRTIMEROOT}/python_apps/airtime-celery/setup.py install" +loudCmd "python ${AIRTIMEROOT}/python_apps/airtime-celery/setup.py install --no-init-script" # Make the airtime log directory group-writable loudCmd "chmod 775 /var/log/airtime" # Create the Celery user -if [ "$dist" = "centos" ]; then - loudCmd "id celery || adduser --no-create-home -c 'LibreTime Celery' -r celery || true" - loudCmd "systemctl enable airtime-celery" +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 || adduser --no-create-home --gecos 'LibreTime Celery' --disabled-login --firstuid 1 --lastuid 999 celery" - loudCmd "update-rc.d airtime-celery defaults" + 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" - -if [ "$dist" = "ubuntu" ] && [ "$code" != "xenial" ]; then - loudCmd "initctl reload-configuration" -elif [ "$dist" = "ubuntu" ] && [ "$code" = "xenial" ]; then - loudCmd "systemctl daemon-reload" -fi +# 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 airtime-celery verbose "...Done" verbose "\n * Installing airtime_analyzer..." -loudCmd "python ${AIRTIMEROOT}/python_apps/airtime_analyzer/setup.py install --install-scripts=/usr/bin" -if [ "$dist" = "ubuntu" ] && [ "$code" != "xenial" ]; then - loudCmd "initctl reload-configuration" -elif [ "$dist" = "ubuntu" ] && [ "$code" = "xenial" ]; then - loudCmd "systemctl daemon-reload" -fi +loudCmd "python ${AIRTIMEROOT}/python_apps/airtime_analyzer/setup.py install --install-scripts=/usr/bin --no-init-script" +systemInitInstall airtime_analyzer $web_user verbose "...Done" -for i in /etc/init/airtime*.template; do - chmod 644 $i - sed -i "s/WEB_USER/${web_user}/g" $i - mv $i ${i%.template} -done - -set +e -if [ "$dist" = "ubuntu" ] && [ "$code" != "xenial" ] ; then - loudCmd "initctl reload-configuration" -elif [ "$dist" = "ubuntu" ] && [ "$code" = "xenial" ]; then - loudCmd "systemctl daemon-reload" -fi - -# airtime-celery only has an init.d startup script -if [ "$dist" = "centos" ]; then - loudCmd "systemctl enable airtime-celery" -else - loudCmd "update-rc.d airtime-celery defaults" # Start at bootup, on Debian -fi - -# On Ubuntu, we already have the upstart configs, so this is redundant -# and causes multiple processes to spawn on startup -if [ "$dist" = "debian" ]; then - loudCmd "systemctl daemon-reload" #systemd hipsters - - loudCmd "update-rc.d airtime-playout defaults" # Start at bootup, on Debian - loudCmd "update-rc.d airtime-liquidsoap defaults" # Start at bootup, on Debian - loudCmd "update-rc.d airtime_analyzer defaults" # Start at bootup, on Debian -fi -if [ "$dist" = "centos" ]; then - loudCmd "systemctl enable airtime-playout" - loudCmd "systemctl enable airtime-liquidsoap" - loudCmd "systemctl enable airtime_analyzer" -fi -set -e - if [ ! -d /var/log/airtime ]; then loud "\n-----------------------------------------------------" loud " * Installing Log Files * " @@ -641,16 +933,25 @@ verbose "\n * Setting permissions on /var/tmp/airtime..." chmod -R a+x /var/tmp/airtime chown -R ${web_user}:${web_user} /var/tmp/airtime/ -# PHP Config File for Apache -if [ ${dist,,} == "ubuntu" ] && [ ${code,,} == "xenial" ]; then - libretime_phpini="/etc/php/7.0/apache2/conf.d/airtime.ini" +loud "\n-----------------------------------------------------" +loud " * Configuring PHP in Apache * " +loud "-----------------------------------------------------" +# Test common locations for php conf directory +php_conf_dirs=( + "/etc/php/7.0/apache2/conf.d" # Ubuntu Xenial + "/etc/php5/apache2/conf.d" # 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 - libretime_phpini="/etc/php5/apache2/conf.d/airtime.ini" -fi - -if [ "$dist" = "centos" ]; then - libretime_phpini="/etc/php.d/airtime.ini" + 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} @@ -659,24 +960,34 @@ else fi # Enable Apache modules -if [ "$dist" != "centos" ] && [ "$code" != "xenial" ]; then +if $is_ubuntu_xenial; then + loudCmd "a2enmod rewrite php7.0" +elif $is_centos_dist; then + verbose "TODO: enable Apache modules mod_rewrite and mod_php manually" +else loudCmd "a2enmod rewrite php5" -elif [ "$dist" = "ubuntu" ] && [ "$code" = "xenial" ]; then - loudCmd "a2enmod rewrite" - loudCmd "a2enmod php7.0" fi + loud "\n-----------------------------------------------------" loud " * Configuring PostgreSQL * " loud "-----------------------------------------------------" # Ensure postgres is running - It isn't after you install the postgres package on Ubuntu 15.04 -loudCmd "service postgresql start" +systemInitCommand start postgresql setupAirtimePostgresUser() { # here-doc to execute this block as postgres user su postgres <<'EOF' set +e - psql -d postgres -tAc "CREATE USER airtime WITH ENCRYPTED PASSWORD 'airtime'; ALTER USER airtime CREATEDB;" + 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 @@ -751,19 +1062,23 @@ if [ "$ignore_dependencies" = "f" ]; then loud " * Installing Locales * " loud "-----------------------------------------------------" - set +e - verbose "\n * Generating locales" - for i in `ls ${web_root}/../locale | grep ".._.."`; do - if [ "$dist" = "debian" ]; then - grep -qi "^$i" /etc/locale.gen - if [ $? -ne 0 ]; then - verbose "$i.UTF-8 UTF-8" >> /etc/locale.gen + if $is_centos_dist; then + loud "\n not required on $dist" + else + set +e + verbose "\n * Generating locales" + for i in `ls ${web_root}/../locale | grep ".._.."`; do + if [ "$dist" = "debian" ]; then + grep -qi "^$i" /etc/locale.gen + if [ $? -ne 0 ]; then + verbose "$i.UTF-8 UTF-8" >> /etc/locale.gen + fi + else + loudCmd "locale-gen \"$i.utf8\"" fi - else - loudCmd "locale-gen \"$i.utf8\"" - fi - done - set -e + done + set -e + fi if [ "$dist" = "debian" ]; then loudCmd "/usr/sbin/locale-gen" @@ -783,18 +1098,17 @@ if [ "$selinux" = "t" ]; then fi verbose "\n * Reloading apache..." -if [ "$dist" != "centos" ]; then - loudCmd "service ${apache_bin} reload 2>/dev/null" - verbose "...Done" - - IP=$(ifconfig eth0 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://') -else - verbose "systemctl restart ${apache_bin} 2>/dev/null" - loudCmd "systemctl restart ${apache_bin} 2>/dev/null" - verbose "...Done" - +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" + $is_ubuntu_xenial && ip_device="enp0s8" + IP=$(ifconfig ${ip_device} 2>/dev/null |awk -F'[ :]+' '/inet addr:/ {print $4}') fi +verbose "...Done" echo -e "\n-----------------------------------------------------" echo " * Basic Setup DONE! * " diff --git a/installer/systemd/airtime-celery.service b/installer/systemd/airtime-celery.service index 54e2e36cc..51254e1d7 100644 --- a/installer/systemd/airtime-celery.service +++ b/installer/systemd/airtime-celery.service @@ -7,7 +7,7 @@ User=celery Group=celery Environment=RMQ_CONFIG_FILE=/etc/airtime/airtime.conf WorkingDirectory=/srv/airtime -ExecStart=/bin/celery worker -A airtime-celery.tasks:celery --time-limit=300 --concurrency=1 --config=celeryconfig -l INFO +ExecStart=/usr/local/bin/celery worker -A airtime-celery.tasks:celery --time-limit=300 --concurrency=1 --config=celeryconfig -l INFO Restart=always [Install] diff --git a/installer/vagrant/centos.sh b/installer/vagrant/centos.sh index 48136e706..23237668f 100644 --- a/installer/vagrant/centos.sh +++ b/installer/vagrant/centos.sh @@ -124,27 +124,6 @@ restorecon -Rv /vagrant /etc/airtime /srv/airtime # Disable default apache page sed -i -e 's/^/#/' /etc/httpd/conf.d/welcome.conf -# Quick and dirty systemd unit install (will be in package later) -unit_dir="/etc/systemd/system" -unit_src_dir="/vagrant/installer/systemd" -cp -rp ${unit_src_dir}/*.service ${unit_dir} - -# Overrides to use apache user for now (final packaging will have dedicated users) -for service in `ls ${unit_src_dir}/*.service`; do - unit_name=`basename ${service}` - if [ "$unit_name" = "airtime-celery.service" ]; then - continue - fi - sed -i \ - -e 's/User=.*/User=apache/' \ - -e 's/Group=.*/Group=apache/' \ - ${unit_dir}/${unit_name} -done - - -# for good measure, lets reload em -systemctl daemon-reload - # celery will not run unless we install a specific version (https://github.com/pypa/setuptools/issues/942) # this will need to be figured out later on and will get overriden by the docs installer anyhow :( pip install setuptools==33.1.1 diff --git a/python_apps/airtime-celery/install/upstart/airtime-celery.conf b/python_apps/airtime-celery/install/upstart/airtime-celery.conf new file mode 100644 index 000000000..93b34efbd --- /dev/null +++ b/python_apps/airtime-celery/install/upstart/airtime-celery.conf @@ -0,0 +1,18 @@ +description "LibreTime Celery Service" +author "help@libretime.org" + +start on runlevel [2345] +stop on runlevel [!2345] + +respawn + +setuid celery +setgid celery + +env LANG='en_US.UTF-8' +env LC_ALL='en_US.UTF-8' +env RMQ_CONFIG_FILE=/etc/airtime/airtime.conf + +chdir /srv/airtime + +exec celery worker -A airtime-celery.tasks:celery --time-limit=300 --concurrency=1 --config=celeryconfig -l INFO