Different trunks on cluster nodes

Configuring synchronization, sensors, and optimizations
Post Reply
User avatar
CRM User
Posts: 138
Joined: Sun Nov 27, 2016 3:41 pm

Different trunks on cluster nodes

Post by CRM User » Sun Oct 14, 2018 1:05 pm

The nodes which makeup my cluster are on different continents, and have different SIP trunks. Yet, I want all aspects of the configuration (dialplan, extensions, routes, etc) to be the same. (And I'm using FreePBX).

My setup is as follows:

MASTER node: Located in New York, USA. I have 2 trunks: NY1 and NY2
SLAVE node: Located in London England. I have 1 trunk: LON1

The configuration of NY1 and LON1 are similar, just the host IP and secrets are different.

How can I set this up?
Account for questions transferred from CRM system
User avatar
Telium Support
Posts: 184
Joined: Sun Nov 27, 2016 3:27 pm

Re: Different trunks on cluster nodes

Post by Telium Support » Sun Oct 14, 2018 1:18 pm

HAAst can handle that easily using the event handler system. There are 2 aspects to your cluster that must be handled separately: the FreePBX configuration, and the Asterisk configuration. Remember that FreePBX is a pretty GUI with it's own configuration database (in MySQL), and it regenerates the Asterisk configuration files (flat files) when you click apply changes. So we have to handle each a bit differently.

I should also point out that because FreePBX creates a relationship between DIALPLAN->ROUTES->TRUNKS, you cannot simply delete a trunk on one node but have it present on the other. To effectively remove the second trunk from London we modify one trunk configuration to ensure it cannot be activated by Asterisk (so it will be ignored in the dialplan). We do so by setting the SIP port to an invalid number.

FreePBX Configuration
To make your life simpler (and setup less confusing), on your New York FreePBX name your NY1 and NY2 trunks:
MASTER_TRUNK1 (for the trunk)
MASTER_TRUNK1_IN (for inbound)
MASTER_TRUNK1_OUT (for outbound)
MASTER_TRUNK2
MASTER_TRUNK2_IN
MASTER_TRUNK2_OUT
Next, add to your New York FreePBX your LON trunk named exactly as follows:
SLAVE_TRUNK1 (for the trunk)
SLAVE_TRUNK1_IN (for inbound)
SLAVE_TRUNK1_OUT (for outbound)
Finally, add to your New York FreePBX a duplicate the above SLAVE_TRUNK1 to be named SLAVE_TRUNK2:
SLAVE_TRUNK2
SLAVE_TRUNK2_IN
SLAVE_TRUNK2_OUT
In FreePBX (on Master) edit your routes to use:
  1. MASTER_TRUNK1
  2. SLAVE_TRUNK1
  3. MASTER_TRUNK2
  4. SLAVE_TRUNK2
in that order. Don't worry about NY using SLAVE trunks, or London using MASTER trunks. HAAst will disable them to ensure only the right trunks are used in the right location.

HAAst FreePBX MySQL event handler
HAAst will be responsible for enabling all master trunks in New York (and disabling all slave trunks), and enabling all slave trunks in London (and disabling master trunks there), and changing the external IP address (for SIP config). HAAst will also disable SLAVE_TRUNK2 in London so it won't be used (contents ignored). HAAst will also change the external IP address in SIP settings. Assuming that you are using the sample HAAst configuration file for Sangoma FreePBX, you will have a sync job named 'freepbx-mysql'. You need to create a post-sync event handler (file) called sync.stop.post.freepbx-mysql in the /usr/local/haast/events folder. That event handler will be responsible for enabling/disabling trunks:

Code: Select all

#!/bin/bash

# Determine if this is the SLAVE PBX
ISSLAVE=$(hostname | grep london | wc -l)

# Determine value of 'disabled' setting in FreePBX
if [ ${ISSLAVE} -eq 0 ] ; then
  NODENAME="NewYork"
  LOCALIP="1.2.3.4"
  REMOTEIP="5.6.7.8"
  MASTERDISABLED="off"
  SLAVEDISABLED="on"
else
  NODENAME="London"
  REMOTEIP="1.2.3.4"
  LOCALIP="5.6.7.8"
  MASTERDISABLED="on"
  SLAVEDISABLED="off"
fi

#----------------------------------------------------------------------------

HVERBOSE=0
if [ -f "/usr/local/haast/internal/helperfunctions.sh" ] ; then
  . /usr/local/haast/internal/helperfunctions.sh
elif [ -f "../internal/helperfunctions.sh" ] ; then
  . ../internal/helperfunctions.sh
else
  echo "ERROR: Cannot find helperfunctions.sh"
  exit 10
fi

# Update the trunks table for MASTER_XXX trunks
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="update trunks set disabled='${MASTERDISABLED}' where name like 'MASTER_%'"

# Update the trunks table for SLAVE_XXX trunks
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="update trunks set disabled='${SLAVEDISABLED}' where name like 'SLAVE_%'"

# Update the kvblob table for the SIP settings > externip value
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="UPDATE kvblobstore SET content = REPLACE(content, '${REMOTEIP}', '${LOCALIP}')"
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="UPDATE kvstore_FreePBX_modules_Sysadmin SET val = REPLACE(val, '${REMOTEIP}', '${LOCALIP}')"
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="UPDATE kvstore_Sipsettings SET val = REPLACE(val, '${REMOTEIP}', '${LOCALIP}')"
  mysql \
    -u ${MYSQL_SYNCUSERNAME} \
    -p${MYSQL_SYNCPASSWORD} \
    -h ${MYSQL_SYNCLOCALHOST} \
    -D asterisk \
    -P ${MYSQL_SYNCPORT} \
    -N \
    -B \
    --execute="UPDATE sysadmin_options SET value = REPLACE(value, '${REMOTEIP}', '${LOCALIP}')"

# Tell HAAst all exitted ok
exit 0

HAAst Asterisk file event handler
HAAst will be responsible for ensuring the trunk information (in sip.conf) has the contents appropriate for the node it is running on. There are also 2 distinct use cases we must consider. First use case: if SLAVE becomes active and the admin edits the configuration in FreePBX then Asterisk must accept that configuration and run normally (even if no event handlers have run). In this case there is nothing to be done since the disabled trunks will not generate any config data for Asterisk since they have been disabled in FreePBX. (Nothing to do). Second use case: The Asterisk configuration files from MASTER has been sent to SLAVE, and the SLAVE trunks contain information relevant for New York. To handler this situation we replace trunk content (in the Asterisk config files), and we also remove the MASTER_ prefix from any Asterisk config files (for clarity). Assuming that you are using the sample HAAst configuration file for Sangoma FreePBX, you will have a sync job named 'freepbx-conf'. You need to create a post-sync event handler (file) called sync.stop.post.freepbx-conf in the /usr/local/haast/events folder. That event handler will be responsible for modify the Asterisk config files:

Code: Select all

#!/bin/bash

# Determine if this is the SLAVE PBX
ISSLAVE=$(hostname | grep london | wc -l)

# Determine value of 'disabled' setting in FreePBX
if [ ${ISSLAVE} -eq 0 ] ; then
  NODENAME="NewYork"
  SECRET="NySeCrEt"
  HOST="12.23.34.45"
  EXTERNIP="1.2.3.4"
else
  NODENAME="London"
  SECRET="LoNSeCrEt"
  HOST="98.87.76.65"
  EXTERNIP="9.8.7.6"
fi


#----------------------------------------------------------------------------

HVERBOSE=0
if [ -f "/usr/local/haast/internal/helperfunctions.sh" ] ; then
  . /usr/local/haast/internal/helperfunctions.sh
elif [ -f "../internal/helperfunctions.sh" ] ; then
  . ../internal/helperfunctions.sh
else
  echo "ERROR: Cannot find helperfunctions.sh"
  exit 10
fi

# Remove MASTER_ and SLAVE_ prefixes from sip config files and dialplan config files,
# to allow for shared files between MASTER and SLAVE (with shared trunk names)
sed -i 's/MASTER_//g' /etc/asterisk/sip_additional.conf
sed -i 's/MASTER_//g' /etc/asterisk/extensions_additional.conf
sed -i 's/SLAVE_//g' /etc/asterisk/sip_additional.conf
sed -i 's/SLAVE_//g' /etc/asterisk/extensions_additional.conf

# Enable / disable trunks in Asterisk config files, and alter settings for common
if [ ${ISSLAVE} -eq 0 ] ; then
  # THIS IS MASTER
  # Enable trunk2 by removing port to a value that will never accept SIP
  # TRUNK2
  crudini --del --inplace /etc/asterisk/sip_additional.conf "TRUNK2_OUT" port
else
  # THIS IS SLAVE
  # Disable trunk2 by setting port to a value that will never accept SIP
  crudini --set --inplace /etc/asterisk/sip_additional.conf "TRUNK2_OUT" port "9999"
fi

# Change values to match required local node settings
# TRUNK1
echo secret="${HOST}" | crudini --merge --inplace /etc/asterisk/sip_additional.conf "TRUNK1_OUT"
echo secret="${SECRET}" | crudini --merge --inplace /etc/asterisk/sip_additional.Tconf "TRUNK1_OUT"
# External IP address
echo external_media_address="${EXTERNIP}" | crudini --merge --inplace /etc/asterisk/pjsip.transports.conf "0.0.0.0-udp"
echo external_signaling_address="${EXTERNIP}" | crudini --merge --inplace /etc/asterisk/pjsip.transports.conf "0.0.0.0-udp"
echo externip="${EXTERNIP}" | crudini --merge --inplace /etc/asterisk/sip_general_additional.conf ""

# Notify HAAst of success
exit 0
Notice that the above event handler also disables TRUNK2 by adding an incorrect sip port number (9999), and uses the open source 'crudini' package to accomplish this. This will cause the trunk connection to fail, and Asterisk will ignore the trunk. The result is that the ROUTES as setup in FreePBX will skip this trunk.

Notice as well that we hard coded a bit of information at the start of the event handlers; this is for simplicity. If you want to get really fancy, you can extract the relevant trunk data from the MySQL database and use that to update the Asterisk files. But the above explains the concept in the simplest way possible.
Post Reply