Showing posts with label MySQL. Show all posts
Showing posts with label MySQL. Show all posts

Saturday, November 20, 2010

Asterisk queue_log on MySQL

History
Backlinks...Asterisk cdr mysqlMysqlQueueMetricsThe table format and behavior of realtime queue_log storage has changed for Asterisk 1.8.

More details: https://issues.asterisk.org/view.php?id=17082


Current SVN trunk (Revision 94782 from 12-26-07 09:54), supports storage of queue_log in your RT engine.

More details: http://bugs.digium.com/view.php?id=11625


PLEASE NOTE: The table structure referenced in the above link is no longer accurate (use the structure below). The time column must be char(10), or you will receive an error like this: WARNING[25801] res_config_mysql.c: Realtime table general@queue_log: column 'time' cannot be type 'int(10) unsigned' (need char)
Sample queue_log table for MySQL: CREATE TABLE `queue_log` ( `id` int(10) unsigned NOT NULL auto_increment, `time` char(10) unsigned default NULL, `callid` varchar(32) NOT NULL default '', `queuename` varchar(32) NOT NULL default '', `agent` varchar(32) NOT NULL default '', `event` varchar(32) NOT NULL default '', `data` varchar(255) NOT NULL default '', PRIMARY KEY (`id`));
queue_log message consists of 2 parts: constant and variable. Constant part is split among corresponding fields (time, callid, queuename, agent, event). Variable data is stored in `data` field as is, so you'll meet '|' there. Example: mysql> select * from queue_log;+----+------------+--------------+------------------+-------+------------+-------+| id | time | callid | queuename | agent | event | data |+----+------------+--------------+------------------+-------+------------+-------+| 1 | 1198356717 | 1198356717.0 | voipsolutions.ru | NONE | ENTERQUEUE | |serg || 2 | 1198356719 | 1198356717.0 | voipsolutions.ru | NONE | ABANDON | 1|1|2 |+----+------------+--------------+------------------+-------+------------+-------+

to activate RT logging add a line like


to your extconfig.conf

PLEASE NOTE: Asterisk 1.6 changed the way that the extconfig.conf file references the MySQL database. You now specify the context name in extconfig.conf, NOT the database name.

So, you've got queue_log created from realtime, but it doesn't make easy parsing. Here's a new table definition and some SQL code to pretty it up for you. Note that locking etc. aren't done - we run this job at night when we know there aren't any calls anyway, but your situation may differ. CREATE TABLE IF NOT EXISTS `queue_log_processed` (
`recid` int(10) unsigned NOT NULL auto_increment,
`origid` int(10) unsigned NOT NULL,
`callid` varchar(32) NOT NULL default '',
`queuename` varchar(32) NOT NULL default '',
`agentdev` varchar(32) NOT NULL,
`event` varchar(32) NOT NULL default '',
`data1` varchar(128) NOT NULL,
`data2` varchar(128) NOT NULL,
`data3` varchar(128) NOT NULL,
`datetime` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY  (`recid`),
KEY `data1` (`data1`),
KEY `data2` (`data2`),
KEY `data3` (`data3`),
KEY `event` (`event`),
KEY `queuename` (`queuename`),
KEY `callid` (`callid`),
KEY `datetime` (`datetime`),
KEY `agentdev` (`agentdev`),
KEY `origid` (`origid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
And then we run the following SQL:
INSERT INTO queue_log_processed (origid,callid,queuename,agentdev,event,data1,data2,data3,datetime)
SELECT id,callid,queue_log.queuename,agent,event,
   replace(substring(substring_index(`data`, '|', 1), length(substring_index(`data`, '|', 1 - 1)) + 1), '|', ''),
   replace(substring(substring_index(`data`, '|', 2), length(substring_index(`data`, '|', 2 - 1)) + 1), '|', ''),
   replace(substring(substring_index(`data`, '|', 3), length(substring_index(`data`, '|', 3 - 1)) + 1), '|', ''),
   FROM_UNIXTIME(time) FROM queue_log;
DELETE FROM queue_log;
I put the above example into a MYSQL trigger to allow an 2 realtime stats tables to be generated. If you are utilizing a version of MYSQL that supports triggers, I would suggest utilizing this for creating realtime tables. I then created web pages to monitor the queues.
CREATE TABLE IF NOT EXISTS `queue_log` (
 `id` int(10) unsigned NOT NULL auto_increment,
 `time` varchar(40) default NULL,
 `callid` varchar(32) NOT NULL default '',
 `queuename` varchar(32) NOT NULL default '',
 `agent` varchar(32) NOT NULL default '',
 `event` varchar(32) NOT NULL default '',
 `data` varchar(255) NOT NULL default '',
 PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- Triggers `queue_log`
--
DROP TRIGGER IF EXISTS `aasterisk`.`bi_queueEvents`;
DELIMITER //
CREATE TRIGGER `aasterisk`.`bi_queueEvents` BEFORE INSERT ON `aasterisk`.`queue_log`
FOR EACH ROW BEGIN
 IF NEW.event = 'ADDMEMBER' THEN
   INSERT INTO agent_status (agentId,agentStatus,timestamp,callid) VALUES (NEW.agent,'READY',FROM_UNIXTIME(NEW.time),NULL) ON DUPLICATE KEY UPDATE agentStatus = "READY", timestamp = FROM_UNIXTIME(NEW.time), callid = NULL; 
 ELSEIF NEW.event = 'REMOVEMEMBER' THEN
   INSERT INTO `agent_status` (agentId,agentStatus,timestamp,callid) VALUES (NEW.agent,'LOGGEDOUT',FROM_UNIXTIME(NEW.time),NULL) ON DUPLICATE KEY UPDATE agentStatus = "LOGGEDOUT", timestamp = FROM_UNIXTIME(NEW.time), callid = NULL;
 ELSEIF NEW.event = 'PAUSE' THEN
   INSERT INTO agent_status (agentId,agentStatus,timestamp,callid) VALUES (NEW.agent,'PAUSE',FROM_UNIXTIME(NEW.time),NULL) ON DUPLICATE KEY UPDATE agentStatus = "PAUSE", timestamp = FROM_UNIXTIME(NEW.time), callid = NULL; 
 ELSEIF NEW.event = 'UNPAUSE' THEN
   INSERT INTO `agent_status` (agentId,agentStatus,timestamp,callid) VALUES (NEW.agent,'READY',FROM_UNIXTIME(NEW.time),NULL) ON DUPLICATE KEY UPDATE agentStatus = "READY", timestamp = FROM_UNIXTIME(NEW.time), callid = NULL;
 ELSEIF NEW.event = 'ENTERQUEUE' THEN
   REPLACE INTO `call_status` VALUES 
(NEW.callid,
replace(replace(substring(substring_index(NEW.data, '|', 2), length(substring_index(New.data, '|', 2 - 1)) + 1), '|', '')
, '|', ''),
'inQue',
FROM_UNIXTIME(NEW.time),
NEW.queuename,
'',
'',
'',
'',
0);
 ELSEIF NEW.event = 'CONNECT' THEN
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
holdtime = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', '')
where callid = NEW.callid;
INSERT INTO agent_status (agentId,agentStatus,timestamp,callid) VALUES
(NEW.agent,NEW.event,
FROM_UNIXTIME(NEW.time),
NEW.callid)
ON DUPLICATE KEY UPDATE
agentStatus = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
callid = NEW.callid;
 ELSEIF NEW.event in ('COMPLETECALLER','COMPLETEAGENT') THEN
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
originalPosition = replace(substring(substring_index(NEW.data, '|', 3), length(substring_index(NEW.data, '|', 3 - 1)) + 1), '|', ''),
holdtime = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', ''),
callduration = replace(substring(substring_index(NEW.data, '|', 2), length(substring_index(NEW.data, '|', 2 - 1)) + 1), '|', '')
where callid = NEW.callid;
INSERT INTO agent_status (agentId,agentStatus,timestamp,callid) VALUES (NEW.agent,NEW.event,FROM_UNIXTIME(NEW.time),NULL) ON DUPLICATE KEY UPDATE agentStatus = "READY", timestamp = FROM_UNIXTIME(NEW.time), callid = NULL;
 ELSEIF NEW.event in ('TRANSFER') THEN
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
holdtime = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', ''),
callduration = replace(substring(substring_index(NEW.data, '|', 3), length(substring_index(NEW.data, '|', 3 - 1)) + 1), '|', '')
where callid = NEW.callid;
INSERT INTO agent_status (agentId,agentStatus,timestamp,callid) VALUES
(NEW.agent,'READY',FROM_UNIXTIME(NEW.time),NULL)
ON DUPLICATE KEY UPDATE
agentStatus = "READY",
timestamp = FROM_UNIXTIME(NEW.time),
callid = NULL;
 ELSEIF NEW.event in ('ABANDON','EXITEMPTY') THEN 
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
position = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', ''),
originalPosition = replace(substring(substring_index(NEW.data, '|', 2), length(substring_index(NEW.data, '|', 2 - 1)) + 1), '|', ''),
holdtime = replace(substring(substring_index(NEW.data, '|', 3), length(substring_index(NEW.data, '|', 3 - 1)) + 1), '|', '')
where callid = NEW.callid;
 ELSEIF NEW.event = 'EXITWITHKEY'THEN 
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
position = replace(substring(substring_index(NEW.data, '|', 2), length(substring_index(NEW.data, '|', 2 - 1)) + 1), '|', ''),
keyPressed = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', '')
where callid = NEW.callid;
 ELSEIF NEW.event = 'EXITWITHTIMEOUT' THEN 
   UPDATE `call_status` SET 
callid = NEW.callid,
status = NEW.event,
timestamp = FROM_UNIXTIME(NEW.time),
queue = NEW.queuename,
position = replace(substring(substring_index(NEW.data, '|', 1), length(substring_index(NEW.data, '|', 1 - 1)) + 1), '|', '')
where callid = NEW.callid;
END IF;
 END
//
DELIMITER ;


And adding the 2 realtime tables 'call_status' and 'agent_status'

CREATE TABLE IF NOT EXISTS `agent_status` (
 `agentId` varchar(40) NOT NULL default '',
 `agentName` varchar(40) default NULL,
 `agentStatus` varchar(30) default NULL,
 `timestamp` timestamp NULL default NULL,
 `callid` double(18,6) unsigned default '0.000000',
 `queue` varchar(20) default NULL,
 PRIMARY KEY  (`agentId`),
 KEY `agentName` (`agentName`),
 KEY `agentStatus` (`agentStatus`,`timestamp`,`callid`),
 KEY `queue` (`queue`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `call_status` (
 `callId` double(18,6) NOT NULL,
 `callerId` varchar(13) NOT NULL,
 `status` varchar(30) NOT NULL,
 `timestamp` timestamp NULL default NULL,
 `queue` varchar(25) NOT NULL,
 `position` varchar(11) NOT NULL,
 `originalPosition` varchar(11) NOT NULL,
 `holdtime` varchar(11) NOT NULL,
 `keyPressed` varchar(11) NOT NULL,
 `callduration` int(11) NOT NULL,
 PRIMARY KEY  (`callId`),
 KEY `callerId` (`callerId`),
 KEY `status` (`status`),
 KEY `timestamp` (`timestamp`),
 KEY `queue` (`queue`),
 KEY `position` (`position`,`originalPosition`,`holdtime`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;



Asterisk does not currently support dumping queue_log data straight to a MySQL table.

There is the alternative of changing ast_queue_log function in logger.c to log via mysql. The following link describes a patch that does exactly this: http://forums.digium.com/viewtopic.php?t=4073


An alternative is to use the commercial QueueMetrics version:
Within the package QueueMetrics there is a script called queueLoader.pl that can upload queueu_log data to MySQL.


There are a number of ways for data to be uploaded into MySQL. If we plan to use the real-time monitoring features, we must upload data to MySQL as events happen; if we don't, uploading data in batches will suffice.


The script can be found under WEB-INF/mysql-utils and is called queueLoader.pl (a working installation of Perl5 with MySQL DBI is required to run this script).


To use the script, edit it with a text editor in order to set the MySQL server, database, user and password, like in the following example:


my $mysql_host = "10.10.3.5";
my $mysql_db = "log_code";
my $mysql_user = "queuemetrics";
my $mysql_pass = "javadude";


After the database is set, you can upload a whole file (in this case, /my/queue_log) to a partition named “P01� by running:
perl queueLoader.pl /my/queue_log P01

You can also upload your queue_log file to partition “P02� as it is being written by issuing:
tail -n 0 -f /var/log/asterisk/queue_log | queueLoader.pl - P02
(do not forget the minus sign, separated by spaces, before the partition name!).

A number of other techniques are available to upload a queue_log file as it is being written to a MySQL table, you may also want to consider the Unix named pipe method reported here: http://lists.digium.com/pipermail/asterisk-users/2005-July/109892.html


In the future, we expect Asterisk to be able to write queue_log data straight to a database via ODBC, so these tricks will not be necessary anymore.

Sunday, November 7, 2010

Asterisk cmd MYSQL

History
Backlinks...Asterisk - documentation of...MysqlAsterisk Queue CallbackAsterisk PGSQL Basic MYSQL Database Functionality This is part of the asterisk-addons package available via the Digium Subversion asterisk-addons repository, or as a tarball from the Asterisk website. This is an ADD-ON of asterisk, is not installed by default and must be downloaded and installed with the asterisk-addons package. However, in Asterisk 1.8 the addons have been integrated back into Asterisk. MYSQL(): Basic MYSQL Database Functionality (note that the help information returned from 'show application MYSQL' is a little misleading - what's shown below is easier to understand!)

MYSQL(Connect connid dhhost dbuser dbpass dbname)

Connects to a database. Arguments contain standard MySQL parameters passed to function mysql_real_connect. Connection identifer returned in ${connid}. If the connection wasn't possible, then ${connid} == "".

MYSQL(Query resultid ${connid} query-string)

Executes standard MySQL query contained in query-string using established connection identified by ${connid}. Result of query is stored in ${resultid}.

MYSQL(Fetch fetchid ${resultid} var1\ var2\ ...\ varN)

If any rows are available to select, ${fetchid} is set to 1 and a single row is fetched from a result set contained in ${resultid}. The return fields are assigned to ${var1}, ${var2} ... ${varN} respectively. If no rows are left to select, ${fetchid} is set to 0 and ${var1}, ${var2} ... ${varN} remain unchanged.

MYSQL(Nextresult resultid ${connid}) (New in Asterisk 1.8)
If last query returned more than one result set, it stores the next result set in ${resultid}. It's useful with stored procedures.

MYSQL(Clear ${resultid})

Frees memory and data structures associated with result set.

MYSQL(Disconnect ${connid})

Disconnects from named connection to MySQL.

exten => _X.,1,MYSQL(Connect connid localhost dbuser dbpass dbname)
exten => _X.,2,MYSQL(Query resultid ${connid} SELECT\ scriptname\ from\ mac2pin\ where\ userid=${CALLERIDNAME})
exten => _X.,3,MYSQL(Fetch fetchid ${resultid} AGIScript)
exten => _X.,4,GotoIf($[${AGIScript} = NULL]?5:7)
exten => _X.,5,AGI(${DefaultAGIScript},${EXTEN})
exten => _X.,6,Goto(_X.,8)
exten => _X.,7,AGI(${AGIScript},${EXTEN})
exten => _X.,8,MYSQL(Clear ${resultid})
exten => _X.,9,MYSQL(Disconnect ${connid})
exten => _X.,10,Hangup

In the above example, if the user hangs up at either priority 5 or priority 7, MYSQL(Clear...) and MYSQL(Disconnect....) will never be executed. This will constantly create connections over and over again as calls progressively increase. Eventually, MySQL will not allow anymore connections. (Depending on the limit set in the mysql conf file). Therefore, in this case the following will work: exten => _X.,1,MYSQL(Connect connid localhost asterisk dbpass asterisk)
exten => _X.,2,MYSQL(Query resultid ${connid} SELECT\ scriptname\ from\ mac2pin\ where\ userid=${CALLERIDNAME})
exten => _X.,3,MYSQL(Fetch fetchid ${resultid} AGIScript)
exten => _X.,4,MYSQL(Clear ${resultid})
exten => _X.,5,MYSQL(Disconnect ${connid})
exten => _X.,6,GotoIf($[${fetchid}]?7:9)
exten => _X.,7,AGI(${DefaultAGIScript},${EXTEN})
exten => _X.,8,Hangup
exten => _X.,9,AGI(${AGIScript},${EXTEN})
exten => _X.,10,Hangup

Notice in this case, I am clearing and disconnecting after the Fetch. This ensures that before we even reach the AGI script to do a task, we ensure that Clearing and Disconnecting takes place unless the call is hungup after the connection and before the disconnect. The best way to handle this situation is to clear connections in the 'h' or hangup extension. Escape spaces with \ in the query string. If you use quotes they are passed to the application as part of the string Other characters that need to be escaped are quotes (\' and \"), commas (\,), backtick (\`), and backslash (\\). Note: This is apparently no longer necessary as of Asterisk 1.8. After upgrading two development servers, I discovered that I could define my querystring and return variables without the escape character The fields returned are assigned to the variables in the same order that they are returned by MySQL. It is not recommended to "SELECT *" because you cannot guarantee in which order the fields will be returned. You do not need to give them pretty names "SELECT (long ass query field) as shortfieldname" because the field name is irrelevant to the order. The asterisk online command description states that ${fetchid} is set to TRUE if more rows are available. This is incorrect. It is set to 1 if a row was found in the last fetch and 0 if no row was found. There appears to be a buglet in 'app_addon_sql_mysql.c' - change the line "#ifdef EXTRA_LOG" to "#if EXTRA_LOG" (save and 'make install') and you'll stop seeing warning messages like "May 21 15:51:53 WARNING[5309]: app_addon_sql_mysql.c:318 aMYSQL_fetch: ast_MYSQL_fetch: numFields=4". As of Asterisk 1.6.x.y.z escaping spaces with a backslash (\) generates an SQL error, same is likely true for quotes (\' & \"), comma (,) & backtick (\`). Asterisk 1.4.xyz does need to have these characters escaped.
exten => 888,1,MYSQL(Connect connid localhost dbuser dbpass dbname)
exten => 888,n,GotoIf($["${connid}" = ""]?error,1)
exten => 888,n,MYSQL(Query resultid ${connid} SELECT\ `number`\ FROM\ `phones`\ WHERE\ `channel`=\'${chan}\')
exten => 888,n(fetchrow),MYSQL(Fetch foundRow ${resultid} number) ; fetch row
exten => 888,n,GotoIf($["${foundRow}" = "1"]?done) ; leave loop if no row found
exten => 888,n,NoOp(${number})
exten => 888,n,Goto(fetchrow) ; continue loop if row found
exten => 888,n(done),MYSQL(Clear ${resultid})
exten => 888,n,MYSQL(Disconnect ${connid})

exten => error,1,NoOp(Connection error - do whatever we have to do to crash nicely!)
exten => error,n,Hangup


Please note the corrections to MYSQL(Fetch). ${fetchid} does not necessarily return 1 if there are more available rows, it returns 1 if there was a row available during that call to MYSQL(Fetch). This appears to have been inaccurately explained since the creation of this page. I have corrected this above and in the example below. - Flobi.
If you do not properly Clear and Disconnect from MySQL, connections will persist and overload MySQL. The only way to undo this is to shutdown Asterisk and restart it, or use mytop and kill the processes that are hung. To avoid this, clean up connections in the 'h' extension. - R. Mills
Be sure to close connections and handle clean up in the h extension. This will ensure that on hangup connections do not persist. - R.Mills
Just to clear up the issue. There should be no problem selecting multiple fields. Be sure your syntax is correct. - R.Mills
Using the escape sequences as of 1.6.2X causes syntax errors. Using ` around column names and ' around values without escapes works fine. -D.Hansen
In asterisk 1.6.1.11 omitting ` around column names does not cause an error. Use ' around string values, not needed for numbers. Eg. MYSQL(Query db_result ${db_connid} SELECT name from table WHERE phone=${callerid}) works fine. -Baji
autoclear: Configuration file for app_addon_sql_mysql If set, autoclear will destroy allocated statement and connection resources when the channel ends. For most usage of the MYSQL app, this is what you want, but it's conceivable that somebody is sharing MYSQL connections across multiple channels, in which case, this should be set to 'no'. Defaults to 'no', as this was the original behavior.

 autoclear=yes

Check this page and Asterisk Queue Callback for background. These two sets of statements accomplish the same thing:
exten => 1,n,MYSQL(Query resultid ${connid} INSERT\ INTO\ callers\ SET\ uniqueid=${UNIQUEID}\, callback=1\, callbacknum=${CALLERID:-11:11})
exten => 2,n,MYSQL(Query resultid ${connid} INSERT\ INTO\ callers\ SET\ uniqueid=${UNIQUEID}) exten => 2,n,MYSQL(Query resultid ${connid} UPDATE\ callers\ SET\ callback=1\, callbacknum=${CALLERID:-11:11}\ WHERE\ uniqueid=${UNIQUEID})
Notice that in extension 2 the resultid value didn't need to be cleared.
These two sets of statements accomplish the same thing:
exten => 1,n,MYSQL(Query resultid ${connid} DELETE\ FROM\ callers\ WHERE\ callbacknum=${cbn})
exten => 2,n,System(mysql -u acd -h 127.0.0.1 -e "DELETE FROM callers WHERE callbacknum=${cbn}" --password=acdpass acd)
Now, in order to use the MYSQL() delete in stead of the System delete you'll have to clear the resultid value between queries:
exten => 2,n,MYSQL(Query resultid ${connid} SELECT\ callbacknum\ FROM\ callers\ WHERE\ callbacknum=${CALLERID:-11:11}) exten => 2,n,MYSQL(Fetch fetchid ${resultid} cbn) exten => 2,n,MYSQL(Clear ${resultid}) exten => 2,n,MYSQL(Query resultid ${connid} DELETE\ FROM\ callers\ WHERE\ callbacknum=${cbn})
Moreover, if you are working with a TimeStamp column, you can retrieve values without the delimiters by appending a '+0' to the column name:
exten => 1,n,MYSQL(Query resultid ${connid} SELECT\ called+0\ FROM\ callers\ WHERE\ callbacknum=${CALLERID(num):-11:11}) This returns datetime yyyymmddhhmmss. I find it easier to just disconnect and clear in the h extension, no problems. Q: What is a better way to do it then in terms of performance, security, and flexibility? Using exec and a shell script, or agi or something else?

A: Setup extconfig to have realtime access to the database/table you want to pull info from, then in the dialplan use the app Realtime.
Use the RealTime config handler system to read data into channel variables:

 RealTime(||[|])

All unique column names will be set as channel variables with optional prefix to the name. e.g. prefix of 'var_' would make the column 'name' become the variable ${var_name}
This will not show any auth info in the asterisk cli and automatically clears connect and fetch id's, works great and decreases the number of priority routines within an extension.

There is alternative solution to easily work with almost all databases in Asterisk using drag-and-drop environment but you will need Visual Dialplan and Apstel Integration Server, both free to download and use. There is some fee to keep it but you do not need to keep it, you can simply download, install and use to develop your dial plan and then uninstall it, like I did. Here is how it looks like.
Image
To download it go here or read more here. 154846 views strong. Asterisk | Applications | Functions | Variables | Expressions | Asterisk FAQ

Monday, August 30, 2010

How To Set Up MySQL Database Replication With SSL Encryption On Debian Lenny

Follow me on Twitter
Last edited 08/18/2010

This tutorial describes how to set up database replication in MySQL using an SSL connection for encryption (to make it impossible for hackers to sniff out passwords and data transferred between the master and slave). MySQL replication allows you to have an exact copy of a database from a master server on another server (slave), and all updates to the database on the master server are immediately replicated to the database on the slave server so that both databases are in sync. This is not a backup policy because an accidentally issued DELETE command will also be carried out on the slave; but replication can help protect against hardware failures though.

I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

In this tutorial I will show how to replicate the database exampledb from the server server1.example.com (master) with the IP address 192.168.0.100 to the server server2.example.com (slave) with the IP address 192.168.0.101. Both systems are running Debian Lenny; however, the configuration should apply to almost all distributions with little or no modifications. The database exampledb with tables and data is already existing on the master, but not on the slave.

I'm running all the steps in this tutorial with root privileges, so make sure you're logged in as root.

 

2 Installing MySQL 5 And Enabling SSL Support

If MySQL 5 isn't already installed on server1 and server2, install it now:

server1/server2:

aptitude install mysql-server mysql-client

You will be asked to provide a password for the MySQL root user - this password is valid for the user root

Wednesday, August 25, 2010

Installing Nginx With PHP5 And MySQL Support On OpenSUSE 11.3

Follow me on Twitter
Last edited 08/05/2010

Nginx (pronounced "engine x") is a free, open-source, high-performance HTTP server. Nginx is known for its stability, rich feature set, simple configuration, and low resource consumption. This tutorial shows how you can install Nginx on an OpenSUSE 11.3 server with PHP5 support (through FastCGI) and MySQL support.

I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

In this tutorial I use the hostname server1.example.com with the IP address 192.168.0.100. These settings might differ for you, so you have to replace them where appropriate.

 

2 Installing MySQL 5

First we install MySQL 5 like this:

yast2 -i mysql mysql-client mysql-community-server

Then we create the system startup links for MySQL (so that MySQL starts automatically whenever the system boots) and start the MySQL server:

chkconfig --add mysql
/etc/init.d/mysql start

Now check that networking is enabled. Run

netstat -tap

Installing A Web, Email And MySQL Database Cluster (Mirror) On Debian 5.0 With ISPConfig 3

com>
Last edited 08/04/2010

This tutorial describes the installation of a clustered Web, Email, Database and DNS server to be used for redundancy, high availability and load balancing on Debian 5 with the ISPConfig 3 control panel. GlusterFS will be used to mirror the data between the servers and ISPConfig for mirroring the configuration files. I will use a setup of two servers here for demonstration purposes but the setup can scale to a higher number of servers with only minor modifications in the GlusterFS configuration files.

There is currently one limitation in the MySQL cluster setup. The MySQL daemon has locking problems during the initial innodb check when the second server gets started. The current workaround that I use here is to start MySQL with myisam only. I've found several reports of successfully running MySQL servers with innodb on GlusterFS, so it must be possible with some finetuning of the GlusterFS and / or MySQL configuration file to use innodb as well. I will try to find a solution for the locking issues and update this tutorial. If someone knows a solution for innodb on GlusterFS, please contact me. If you want to use the second server only as hot standby system, then you should be able to use innodb as long as you start MySQL on the second server only when the first server is disconnected.

This is currently a proof of concept setup, so there is no experience how this setup scales in production systems yet. The only part that might cause problems is the shared MySQL data directory. Another solution for accessing MySQL databases from several servers simultaneously is to use a MySQL-cluster setup (http://www.mysql.com/products/database/cluster/) or MySQL master / master replication (http://www.howtoforge.com/mysql_master_master_replication).

 

1 Setting Up The Two Base Systems

In this setup there will be one master server (which runs the ISPConfig control panel interface) and one slave server which mirrors the web (apache), email (postfix and dovecot) and database (MySQL) services of the master server.

To install the clustered setup, we need two servers with a Debian 5.0 minimal install. The base setup is described in the following tutorial in the steps 1 - 6:

http://www.howtoforge.com/perfect-server-debian-lenny-ispconfig3

Install only steps 1 - 6 of the perfect server tutorial and not the other steps as they differ for a clustered setup!

In my example I use the following hostnames and IP addresses for the two servers:

Master Server

Hostname: server1.example.tld
IP address: 192.168.0.105

Slave server

Hostname: server2.example.tld
IP address: 192.168.0.106

Whereever these hostnames or IP addresses occur in the next installation steps you will have to change them to match the IPs and hostnames of your servers.

 

2 Installing The Two Servers

The following steps have to be executed on the master and on the slave server. If a specific step is only for the master or slave, then I've added a note in the description in red.

vi /etc/hosts

127.0.0.1 localhost192.168.0.105 server1.example.tld192.168.0.106 server2.example.tld# The following lines are desirable for IPv6 capable hosts::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allroutersff02::3 ip6-allhosts

Set the hostname of the server:

echo server1.example.tld > /etc/hostname
/etc/init.d/hostname.sh start

User server1.example.tld on the first server and server2.example.tld on the second server.

Edit the sources.list file...

vi /etc/apt/sources.list

... and ensure that it contains the following two lines. The first one is for the debian volatile repository to get updated pacakges for the ClamAV antivirus software and SpamAssassin and the second one is for the backports repository which contains current GlusterFS packages.

deb http://volatile.debian.org/debian-volatile lenny/volatile main contrib non-freedeb http://www.backports.org/debian/ lenny-backports main contrib non-free

Run...

apt-get install debian-backports-keyring
apt-get update

... to install the backports repository key and update the apt package database; then run ...

apt-get upgrade

... to install the latest updates (if there are any).

It is a good idea to synchronize the system clock with an NTP (network time protocol) server over the Internet. Simply run...

apt-get -y install ntp ntpdate

... and your system time will always be in sync.

Install postfix, dovecot and mysql with one single command:

apt-get -y install postfix postfix-mysql postfix-doc mysql-client mysql-server openssl getmail4 rkhunter binutils dovecot-imapd dovecot-pop3d sudo

Enter the new password for mysql when requested by the installer and answer the next questions as decsribed below:

Create directories for web-based administration ? <-- No
General type of configuration? <-- Internet site
Mail name? <-- server1.mydomain.tld
SSL certificate required <-- Ok

We want MySQL to listen on all interfaces, not just localhost, therefore we edit /etc/mysql/my.cnf and comment out the line bind-address

Tuesday, August 24, 2010

Installing A Multiserver Setup With Dedicated Web, Email, DNS And MySQL Database Servers On Debian 5.0 With ISPConfig 3

com>
Last edited 08/10/2010

This tutorial describes the installation of an ISPConfig 3 multiserver setup with dedicated web, email, database and two DNS servers all managed trough a single ISPConfig 3 control panel. The setup described below uses five servers and can be extended easily to to a higher number of servers by just adding more servers. E.g. if you want to have two mailservers, do the setup steps from chapter 2 on both of these servers. If you want to set up more web servers, then install ISPConfig on all other web servers in expert mode except of the first one.

 

1 Installing The Five Debian Base Systems

In this setup there will be one master server (which runs the web server and ISPConfig control panel interface) and four slave servers for database, email and DNS.

To install the clustered setup, we need five servers (or virtual servers) with a Debian 5.0 minimal install. The base setup is described in the following tutorial in the steps 1 - 6:

http://www.howtoforge.com/perfect-server-debian-lenny-ispconfig3

Install only steps 1 - 6 of the perfect server tutorial and not the other steps as they differ for a clustered setup!

In my example I use the following hostnames and IP addresses for the five servers:

Web Server

Hostname: web.example.tld
IP address: 192.168.0.105

Mail Server

Hostname: mail.example.tld
IP address: 192.168.0.106

DB Server

Hostname: db.example.tld
IP address: 192.168.0.107

DNS Server (primary)

Hostname: ns1.example.tld
IP address: 192.168.0.108

DNS Server (secondary)

Hostname: ns2.example.tld
IP address: 192.168.0.109

Whereever these hostnames or IP addresses occur in the next installation steps you will have to change them to match the IP's and hostnames of your servers.

 

2 Installing The Web Server

Edit the hosts file and add the IP addresses and hostnames for all servers. The hostnames and IP addresses have to be adjusted to match your setup.

vi /etc/hosts

127.0.0.1 localhost192.168.0.105 web.example.tld192.168.0.106 mail.example.tld192.168.0.107 db.example.tld192.168.0.108 ns1.example.tld192.168.0.109 ns2.example.tld # The following lines are desirable for IPv6 capable hosts::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allroutersff02::3 ip6-allhosts

Set the hostname of the server:

echo web.example.tld > /etc/hostname
/etc/init.d/hostname.sh start

Edit the sources.list file...

vi /etc/apt/sources.list

... and ensure that it contains the following line to enable the volatile repository.

deb http://volatile.debian.org/debian-volatile lenny/volatile main contrib non-free

Run...

apt-get update

... to update the apt package database; then run...

apt-get upgrade

... to install the latest updates (if there are any).

It is a good idea to synchronize the system clock with an NTP (network time protocol) server over the Internet. Simply run...

apt-get -y install ntp ntpdate

... and your system time will always be in sync.

Install the MySQL server. A MySQL server instance is necessary on every server as ISPConfig uses it to sync the configuration between the servers.

apt-get -y install mysql-client mysql-server

Enter the new password for MySQL when requested by the installer.

We want MySQL to listen on all interfaces on the master server, not just localhost, therefore we edit /etc/mysql/my.cnf and comment out the line bind-address