#!/usr/local/bin/bash
#
# Copyright (C) 2006 SIPfoundry Inc.
# Licensed by SIPfoundry under the LGPL license.
#
# Copyright (C) 2006 Pingtel Corp.
# Licensed to SIPfoundry under a Contributor Agreement.
Action=RUN
Status=1
Args=""
Today=`date`
resolverArgs=""
# Declare script variables in a manner that unit test
# (or end user I suppose) can override
: ${SslDir:=@SIPX_CONFDIR@/ssl}
: ${AuthoritiesDir:=$SslDir/authorities}
: ${ConfigDefs:=@SIPX_CONFDIR@/config.defs}
: ${Configpp:=@bindir@/configpp}
: ${ConfigFiles:=@SIPX_CONFDIR@/authproxy-config @SIPX_CONFDIR@/proxy-config}
: ${PidFile:=@SIPX_RUNDIR@/sipxconfig.pid}
: ${LibDir:=@SIPX_LIBDIR@}
: ${Psql:=psql}
: ${ServiceDir:=/etc/init.d}
: ${SubstituteUser:=su}
: ${Chown:=chown}
: ${LogDir:=@SIPX_LOGDIR@}
: ${TmpDir:=@SIPX_TMPDIR@}
: ${RunningUser:=@SIPXPBXUSER@}
: ${PgUser:=pgsql}
: ${PgSchema:=@SIPX_CONFDIR@/cdr/schema.sql}
: ${DbVersion:=2}
: ${DbPatchDir:=@SIPX_CONFDIR@/cdr}
: ${DbPatchLog:=@SIPX_LOGDIR@/sipcdrpatch.log}
Database=SIPXCDR
Today=`date`
# This function determines the correct service name for Postgres.
postgresService() {
# If the user has already specified $Service, do not modify it.
if test -n "$POSTGRES_SERVICE"
then
echo -e "$POSTGRES_SERVICE"
fi
if [ -f /etc/init.d/rhdb ]
then
# Red Hat Enterprise uses the name rhdb.
echo -e rhdb
fi
# Most other distributions use the name postgresql.
echo -e postgresql
}
# Search/replace variables used in config.defs into config files
runConfigpp() {
# If the "config.defs" file exists and the <name>.in file exists for a
# configuration file, then run the config preprocessor to generate the
# fully resolved configuration file.
if [ -f "$ConfigDefs" ]
then
for i in $ConfigFiles ; do
if [ -f "${i}.in" ]
then
${Configpp} --defs "${ConfigDefs}" --in "${i}.in" --out "$i"
fi
done
fi
}
# How to add a database patch:
#
# Add a file containing SQL statements in the sipXproxy/etc/database directory.
# Be sure to add the file to the sql_schemas list in Makefile.am and to the %files
# section in sipxproxy.spec.in
#
# Define an upgrade path - put the file name (without extension .sql) in one or
# more of the upgrade lists below. If we currently have database version 3 then
# add the file to UpgradePatches1 (upgrading a version 1 database) and UpgradePatches2
# (upgrading a version 2 database).
UpgradePatches1="refer_uri"
# Apply database patches
databasePatch() {
versionString=`${Psql} -U ${PgUser} -d ${Database} -c "select max(version) from version_history"`
version=`echo $versionString | cut -d ' ' -f 3`
case ${version} in
1)
UpgradePatches=$UpgradePatches1
;;
*)
UpgradePatches="view_cdrs"
;;
esac
if [ -f ${DbPatchLog} ]; then
echo "${Today}" >> ${DbPatchLog}
else
echo "${Today}" > ${DbPatchLog}
fi
echo "Patch list: ${UpgradePatches}" >> ${DbPatchLog}
if [ -n "${UpgradePatches}" ]; then
for patch in $UpgradePatches; do
if [ -f ${DbPatchDir}/${patch}.sql ]; then
# Apply patch only if not found in the patch list
if ! ${Psql} -U ${PgUser} -d ${Database} -c "select name from patch where name = '${patch}'" | grep ${patch} >>${DbPatchLog} 2>&1; then
echo "Applying patch ${DbPatchDir}/${patch}.sql" >> ${DbPatchLog}
${Psql} --quiet -U ${PgUser} -d ${Database} -f ${DbPatchDir}/${patch}.sql >>${DbPatchLog} 2>&1
${Psql} --quiet -U ${PgUser} -d ${Database} -c "insert into patch values ('${patch}')"
fi
else
echo "Error: Database patch file ${patch}.sql not found."
fi
done
fi
}
# Setup database
databaseCommand() {
runConfigpp
databaseCheck Silent
case ${1} in
create)
createdb --quiet -U ${PgUser} --encoding=UNICODE ${Database}
${Psql} --quiet -U ${PgUser} -d ${Database} -f ${PgSchema}
;;
drop)
dropdb --quiet -U ${PgUser} ${Database}
;;
esac
}
runningUserCheck() {
CurrentUser=`id -un`
if [ "$CurrentUser" != "$RunningUser" ]; then
echo "Only user @sipxpbx.user@ can run this command." 1>&2
return 1
fi
return 0
}
# Check if call resolver is configured for HA
HAcheck() {
# Quietly check if we're setup for HA - we have to do database tests differently
resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_CSE_HOSTS`
host_list=`expr match "$resolveConfig" '.*CSE_HOSTS\s*:\s*\(.*\)'`
ha_with_localhost=0
if [ -z "$host_list" ]; then
# Normal setup
return 1
else
if expr match "$host_list" '.*localhost.*' >/dev/null; then
# HA setup with localhost
ha_with_localhost=1
else
# HA setup without localhost
ha_with_localhost=0
fi
return 0
fi
}
# Return false if postgres is
# 1. not running
# 2. running but not setup to communicate w/java or ${Psql} command
# 3. Database is not created
databaseCheck() {
if ! ${Psql} -l -U pgsql | grep "${Database}" >/dev/null 2>&1
then
procs=`ps -C postmaster`
if ! expr match "$procs" '.*postmaster.*' >/dev/null; then
if [ "$1" != "Silent" ]; then
echo " failed"
echo
echo " Error: PostgreSQL is not running."
echo
fi
else
# Check postgres configuration
Service=postgresql
if test -z $PGDATA; then
PGDATA=/usr/local/pgsql/data
fi
# Check for conf file
if [ -f $PGDATA/pg_hba.conf ]; then
if ! grep '^local *all *all *trust.*' $PGDATA/pg_hba.conf >/dev/null; then
if [ "$1" != "Silent" ]; then
echo
echo " Error: $PGDATA/pg_hba.conf is not set up for local connections."
echo " Run the sipxcallresolver.sh script with the --setup"
echo " parameter:"
echo " sipxcallresolver.sh --setup"
echo
fi
else
# Check if psql command works at all
if ${Psql} -l -U pgsql >/dev/null 2>&1; then
if [ "$1" != "Silent" ]; then
echo
echo " Error: The SIPXCDR database does not exist. Run the sipxcallresolver.sh"
echo " script with the --setup parameter:"
echo " sipxcallresolver.sh --setup"
echo
fi
else
echo
echo " Unknown database error."
echo
fi
fi
fi
fi
return 1
else
return 0
fi
}
# Check if there are multiple proxy processes running at the same time.
# This can be a scenario for logging failures.
proxyCheck() {
ok=0
echo -n "Checking for running sipproxy..."
procs=`ps -C sipproxy`
if expr match "$procs" '.*sipproxy.*' >/dev/null; then
# At least one sipproxy is running, check for another one
if expr match "$procs" '.*sipproxy.*sipproxy.*' >/dev/null; then
echo " failed"
echo
echo " Found at least two sipproxy processes. This is a potential"
echo " cause of CSE logging failures!"
echo
ps -C sipproxy
echo
ok=1
else
echo " ok"
fi
else
echo " not running (ok)"
fi
echo -n "Checking for running sipauthproxy..."
procs=`ps -C sipauthproxy`
if expr match "$procs" '.*sipauthproxy.*' >/dev/null; then
# At least one sipauthproxy is running, check for another one
if expr match "$procs" '.*sipauthproxy.*sipauthproxy.*' >/dev/null; then
echo "failed"
echo
echo " Found at least two sipauthproxy processes. This is a potential"
echo " cause of CSE logging failures! "
echo
ps -C sipauthproxy
echo
ok=1
else
echo " ok"
fi
else
echo " not running (ok)"
fi
return $ok
}
configCheck() {
Status=1
db_check=1
if ! proxyCheck; then
Status=0
fi
if [ $db_check = 1 ]; then
echo "Checking database..."
if ! databaseCheck; then
Status=0
else
if databaseVersionCheck; then
echo " ok"
fi
fi
else
echo "Machine is configured for HA without a database on localhost - skip database check"
fi
echo "Checking configuration..."
proxyConfig=`cat @SIPX_CONFDIR@/proxy-config.in | grep SIP_PROXY_CALL_STATE_DB`
if ! expr match "$proxyConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
echo
echo " Error: proxy is not configured to log call state events to a database."
echo " Add the line"
echo
echo " SIP_PROXY_CALL_STATE_DB : ENABLE"
echo
echo " to @SIPX_CONFDIR@/proxy-config.in"
echo
Status=0
else
echo " proxy configured for logging"
fi
authConfig=`cat @SIPX_CONFDIR@/authproxy-config.in | grep SIP_AUTHPROXY_CALL_STATE_DB`
if ! expr match "$authConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
echo
echo " Error: authproxy is not configured to log call state events to a database."
echo " Add the line"
echo
echo " SIP_AUTHPROXY_CALL_STATE_DB : ENABLE"
echo
echo " to @SIPX_CONFDIR@/authproxy-config.in"
echo
Status=0
else
echo " authproxy configured for logging"
fi
# Don't check configuration of call resolver for distributed machines
if [ ${Action} = CONFIGTEST ]; then
resolveOk=1
resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_DAILY_RUN`
if ! expr match "$resolveConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
echo
echo " Warning: call resolver is not configured for daily runs. This"
echo " will prevent the call resolver from automatically"
echo " resolving calls and purging old database records"
echo " on a regular basis. Add the line"
echo
echo " SIP_CALLRESOLVER_DAILY_RUN : ENABLE"
echo
echo " to @SIPX_CONFDIR@/callresolver-config.in"
echo
resolveOk=0
Status=0
fi
resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_PURGE`
if ! expr match "$resolveConfig" '.*:\s*[eE][nN][aA][bB][lL][eE]\s*$' >/dev/null; then
echo
echo " Warning: call resolver is not configured for purging old records."
echo " This will prevent the call resolver from automatically"
echo " purging old database records on a regular basis. Add"
echo " the line"
echo
echo " SIP_CALLRESOLVER_PURGE : ENABLE"
echo
echo " to @SIPX_CONFDIR@/callresolver-config.in"
echo
resolveOk=0
Status=0
fi
# In HA setup test for the CA field entry
if HAcheck; then
resolveConfig=`cat @SIPX_CONFDIR@/callresolver-config.in | grep SIP_CALLRESOLVER_CSE_CA`
if [ -z resolvConfig ]; then
echo
echo " Error: In a HA setup the SIP_CALLRESOLVER_CSE_CA parameter must"
echo " be set. Add the line"
echo
echo " SIP_CALLRESOLVER_CSE_CA : <name of CA file>"
echo
echo " to @SIPX_CONFDIR@/callresolver-config.in"
resolveOk=0
Status=0
else
cfile=`expr match "$resolveConfig" '.*:\s*\(.*\)\s*$'`
if [ ! -f @SIPX_CONFDIR@/ssl/authorities/${cfile} ]; then
echo
echo "Error: The value for SIP_CALLRESOLVER_CSE_CA is:"
echo " ${cfile}"
echo
echo " A file of that name does not exist in"
echo " @SIPX_CONFDIR@/ssl/authorities"
echo
resolveOk=0
Status=0
fi
fi
fi
if [ $resolveOk = 1 ]; then
echo " call resolver configuration ok"
fi
echo -n "Checking for @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb..."
if [ -f @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb ]; then
echo " ok"
else
echo
echo " Error: @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb not found."
echo
Status=0
fi
fi
}
# Check the database version. If it is wrong, then exit, because it's dangerous to
# run call resolver on top of the wrong database version.
databaseVersionCheck() {
dbver=`${Psql} -c "select max(vh.version) from version_history vh;" ${Database} pgsql | sed -n 's/^\s*\([0-9][0-9]*\)\s*$/\1/p'`
if [ "$dbver" = "" ]
then
echo " Error: could not get the database version."
return 1
fi
if [ "$dbver" != $DbVersion ]
then
if [ "$dbver" == 0 ]
then
echo
echo " Error: bad ${Database} database version. This database was"
echo " created by a prerelease version of sipxcallresolver. You should"
echo " drop and recreate the database via"
echo " \"sipxcallresolver.sh --database drop create\"."
echo
else
echo
echo " Error: bad ${Database} database version. Expected version $DbVersion,"
echo " got version $dbver. This database was created or modified by a different"
echo " version of sipxcallresolver."
echo
fi
return 1
fi
return 0
}
# Called after installation or upgrade by distro's package infrastructure
# but can be called manually and is harmless if called multiple times.
onSetup() {
if ! databaseCheck Silent
then
@bindir@/pgpatch.sh
databaseCommand create
fi
databasePatch
# Make a call resolver entry in the crontab file
if [ -f @SIPX_SYSCONFDIR@/crontab ]; then
if ! grep sipxcallresolver @SIPX_SYSCONFDIR@/crontab >/dev/null; then
echo "05 01 * * * root @bindir@/sipxcallresolver.sh --daily" >> @SIPX_SYSCONFDIR@/crontab
fi
else
echo "05 01 * * * root @bindir@/sipxcallresolver.sh --daily" > @SIPX_SYSCONFDIR@/crontab
fi
}
onUninstall()
{
# Remove crontab entry for sipxcallresolver if there is one
if [ -f @SIPX_SYSCONFDIR@/crontab ]; then
if grep sipxcallresolver @SIPX_SYSCONFDIR@/crontab >/dev/null; then
sed -e 's/^.*sipxcallresolver.*$//' @SIPX_SYSCONFDIR@/crontab > @SIPX_SYSCONFDIR@/crontab.tmp
mv @SIPX_SYSCONFDIR@/crontab.tmp @SIPX_SYSCONFDIR@/crontab
fi
fi
}
# Start CDR call resolver
onStartup() {
# Check database version - don't run if it's wrong
if ! databaseVersionCheck; then
exit 1
fi
databasePatch
ruby @GEM_LIB_DIR@/sipxcallresolver-1.0.0/main.rb ${resolverArgs}
}
# simple diagnostics
configtest() {
configCheck
# Print out a success message if everything is OK, to give the user some feedback.
# If there is an error then the test will yield an error message.
if [ $Status = 1 ]
then
echo "The config test succeeded."
echo
else
echo "The config test found problems."
echo
fi
}
CONFIG_DEFS="@SIPX_CONFDIR@/config.defs"
CONFIG_FILES="\
@SIPX_CONFDIR@/callresolver-config
"
# If the "config.defs" file exists and the <name>.in file exists for a
# configuration file, then run the config preprocessor to generate the
# fully resolved configuration file.
if [ -f "$CONFIG_DEFS" ]
then
for i in $CONFIG_FILES ; do
if [ -f "${i}.in" ]
then
@bindir@/configpp --defs "${CONFIG_DEFS}" --in "${i}.in" --out "$i"
fi
done
fi
user=`whoami`
if [ "${user}" != "root" ]; then
echo "Error: Must be root to run sipxcallresolver.sh script."
exit 1
fi
while [ $# -ne 0 ]
do
case ${1} in
-c|--configtest)
Action=CONFIGTEST
;;
-s|--setup)
Action=SETUP
;;
-u|--uninstall)
Action=UNINSTALL
;;
-d|--database)
Action=DATABASE
shift
Args="${@}"
break 2
;;
--patch)
Action=PATCH
;;
--distrib-configtest)
Action=DISTRIBTEST
;;
--nop)
Action=NOP
;;
-h|--help)
Action=HELP
;;
*)
if [ "${1}" = --start ]; then
resolverArgs="${resolverArgs} ${1} "
elif [ "${1}" = --end ]; then
resolverArgs="${resolverArgs} ${1} "
elif [ "${1}" = --redo ]; then
resolverArgs="${resolverArgs} ${1} "
elif [ "${1}" = --daily ]; then
resolverArgs="${resolverArgs} ${1} "
else
resolverArgs="${resolverArgs} \"${1}\" "
fi
;;
esac
shift # always consume 1
done
if [ ${Action} = CONFIGTEST ]
then
configtest
exit $Status
elif [ ${Action} = DISTRIBTEST ]
then
configtest
exit $Status
elif [ ${Action} = DATABASE ]
then
databaseCommand $Args
elif [ ${Action} = RUN ]
then
if [ "${user}" != "root" ]; then
echo "Error: Must be root to run call resolver"
exit 1
fi
onStartup
elif [ ${Action} = SETUP ]
then
onSetup
elif [ ${Action} = UNINSTALL ]
then
onUninstall
elif [ ${Action} = PATCH ]
then
databasePatch
elif [ ${Action} = HELP ]
then
cat <<USAGE
Usage: sipxcdr.sh [-d|--database commands ...]
[-c|--configtest]
[-s|--setup]
[-h|--help]
Set up CDR database and processing for sipXpbx.
Options include:
none Starts CDR call resolver
--database commands Runs an operation on the database. Database commands
are detailed below
--configtest Run diagnostics
--setup Initialize postgresql for communicating with sipxconfig
and create initial database. Will most likely need
root permissions.
--uninstall Uninstall sipxcallresolver changes and settings.
Common Database commands include:
drop Drops ${Database} database
create Create new ${Database} database
-p Full list all available commands
Notable environment variables:
POSTGRES_SERVICE a guess is made to determine the name for the
Postgres service.
If the guess is incorrect, then set this to the name of
the script in /etc/init.d that starts/stops
the Postgres database. The possibilities that
we are aware of are "postgresql" and "rhdb".
USAGE
fi
syntax highlighted by Code2HTML, v. 0.9.1