CACTI

It is supposed that you are rather familiar with: Linux, Apache2, DNS (Bind), MySQL and SNMP.


ONE IMPORTANT MOMENT: DO NOT TRY TO POPULATE FINALLY DEVICE/GRAPHICS UNTIL YOU DON'T RESOLVE ALL ISSUES WITH INSTALLATION AND SETTING UP OF CACTI ITSELF!


Installation

Setup procedure

  1. First we install the program.
     apt-get install cacti cacti-spine

    Some comments:

    • cacti - Monitoring system itself
    • cacti-spine - it is a “poller” program. It's a binary code as opposed to embedded script, which is interpreted by BASH or SHELL. Accordingly, Spine works much more faster what undoubtedly is advantage when it is needed to inquire large mass of devices one time pre minute. Spine automatically indicate itself as poller in Cacti's configs during installation.

  2. We copy Cacti site's content to our prepared directory which will be registered in Apache later.
    ~# mkdir /var/www/cacti.united-networks.ru
    ~# cp -Lr /usr/share/cacti/site/* /var/www/cacti.united-networks.ru/
    ~#

    Some comments:

    • -L in cp command means “dereference” symbolyc links. It's because Cacti's site catalogue has symlinks to outside locations.
    • We do this because Cacti installation places all HTML/PHP pages to its own location!

  3. Then we need to ”pull on” some “skin” allowing to use different plugins for Cacti, for example: Monitor, Weathermaps, THold, Settings and so on. It is called “Plugin Architecture” (or PIA). It is very important to track versions of Cacti and PIA to match. If Cacti has version 0.8.7i then PIA distribution must have the same one (cacti-0.8.7i-pia-3.1.tar.gz):
    ~# dpkg -l  | grep cacti
    ii  cacti                            0.8.7i-2ubuntu1            Frontend to rrdtool for monitoring systems and services
    ii  cacti-spine                      0.8.7i-1ubuntu1            Multi-Threading poller for cacti
    ~# ll /usr/local/src | grep PIA
    -rw-r--r--  1 root          root          2270714 дек.  12 06:32 cacti-0.8.7i-PIA-3.1.tar.gz
    ~# tar zxvf /usr/local/src/cacti-0.8.7i-pia-3.1.tar.gz
    ...
    ~# cp -r cacti-0.8.7i-pia-3.1/* /var/www/cacti.united-networks.ru/
    ~# rm -rf cacti-0.8.7i-pia-3.1 

    I was forced to download PIA-package manually. And after being “untarred” it was simply copied over fresh Cacti installation. Also I uploaded SQL-script from this distribution into MySQL Database named CACTI:

    ~# mysql -u root -p<strong_password> cacti < /usr/local/src/cacti-0.8.7i-PIA-3.1/cacti.sql

    It modified/created tables in database for plugins support. Pay attention that the <strong_password> is written together with ”-p”.

    Important! MySQL database Cacti must be created before runinng this script (the sequence of commands: mysql -u root -p<strong_password> - without pointing of certain database name and inside MySQL yet: create database cacti; - semi-colon is obligatory)!

    Addtionally I created separate MySQL User Account with unlimited rights to Cacti-database. This is the only database where it has access but with no restrictions. Also I changed manually administrative Cacti Username/Password in table “user_auth”:

    ~# mysql -u root -p<strong_password> cacti
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 4658
    Server version: 5.5.22-0ubuntu1 (Ubuntu)
    
    Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql> grant all on cacti.* to cacti_admin identified by 'some_strongest_password';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> flush privileges;
    Query OK, 0 rows affected (0.05 sec)
    
    mysql> select id,username,password from user_auth;
    +----+----------+------------------+
    | id | username | password         |
    +----+----------+------------------+
    |  1 | admin    | b46ebd31bcdf2fe7 |
    |  3 | guest    | 43e9a4ab75570f5b |
    +----+----------+------------------+
    2 rows in set (0.00 sec)
    
    mysql> update user_auth set password=md5('another_strongest_password') where id=1;
    Query OK, 0 rows affected (0.00 sec)
    Rows matched: 1  Changed: 0  Warnings: 0
    
    mysql> exit
    Bye
    ~# 

    Username “cacti_admin” is used to access MySQL whereas “admin” is used to enter the Cacti's Web-interface. The first is included in <Cacti site's directory>/include/config.php and used by Cacti when reading and writing data from/to MySQL database and the latter is virtual entity which is used by Cacti itself to assign these or those rights to some persons for access to some parts of Cacti's Web-interface.

  4. Then I changed some Apache2 settings to change the way to access Cacti's Web interface. Initially it is supposed that Cacti will be placed in catalogue on existing “Default” site that is like “http://192.168.0.1/cacti/” but I allocated separate HTTP-site with name “http://cacti.united-networks.ru” what is more pragmatic in my opinion. This is achieved by the following:
    ~# vi /etc/apache2/sites-available/cacti.united-networks.ru
    <VirtualHost *:80>
        ServerAdmin eyatsko@united-networks.ru
        ServerName cacti.united-networks.ru
        DocumentRoot /var/www/cacti.united-networks.ru
        <Directory /var/www/cacti.united-networks.ru>
            Options Indexes FollowSymlinks MultiViews +ExecCGI
            . . .
            DirectoryIndex index.php
            AddType application/x-httpd-php .php
        </Directory>
        ErrorLog  /var/log/apache2/cacti.united-networks.ru/error_log
        CustomLog /var/log/apache2/cacti.united-networks.ru/access_log common
    </VirtualHost>
    :wq
    ~# /etc/init.d/apache2 restart
     * Restarting web server apache2
    ... waiting                        [ OK ]
    ~# 

    Of course cacti.united-networks.ru must be returned by DNS as address pointing to Apache-server where Cacti is located!
    Then I eliminated references to external (relative to Cacti site's - if they are. The trick is that after copying PIA (plugin architecture) file “include/global.php” is overwritten!) directory particularly to /etc/cacti in <Cacti site's directory>/include/global.php - I commented out line like this:

    . . .
    require("/etc/cacti/debian.php");
    . . .

    If you take attention the second line overwrites results of the previous one. The above actions avoid to store password information somethings elsewhere except of Cacti's home.

  5. At the next step we must indicate MySQL account information in <Cacti site's directory>/include/config.php (file is not large so you easily find out the following block of the lines):
    . . .
    $database_type = "mysql";
    $database_default = "cacti";
    $database_hostname = "localhost";
    $database_username = "cacti_admin";
    $database_password = "some_strongest_password";
    $database_port = "3306";
    $database_ssl = false;
    . . .

    Also you will possibly need to correct the similar lines in global.php which includes config.php.

  6. Next we access to Cacti's Web-interface through a Web-browser. It asks some stupid questions - just pass them. When it asks for credentials to access the Web interface - enter “admin”/“another_strongest_password” - rememer, we changed it in MySQL's table “user_auth”. It is administrative account. We will do all modifications under it. When Cacti asks to change the password for “admin” then re-enter the same password twice. As for others - just agree! :-) And hit on “Next”, “Next”, “Next”…

  7. Most settings are already done by installation procedure, but we need to allow use of plugins. If you downloaded correct PIA, correctly created database and tables by mysql-script, you will see the following Cacti's Web-interface (most right (large) drawind). First, go to “User Management”, enter to the admin user account's properties and select checkbox Plugin Management on the Tab “Realm Permissions” (it is selected by default, we mention about it “just in case”). Then Save user's properties pressing corresponding Button at bottom right of the screen. Plugin Management item in the right-side menu will appear immediately.
    There are two signs that all is done right: the mentioned item “Plugin Management” of Main Menu (on the right of the screen) and the presence of the directory <Cacti site's directory>/plugins. This is important directory - plugins are extracted into it when they are installed (this process will be described later in detail).

Let's consider Cacti's installation completed!

CACTI Customization

We need to do some post-install actions.

Some comments:

  • General Tab
    • Enable Polling warning not only errors. It helps to understand why some things do not work.
    • Set SNMP version and SNMP Community to 2 and public accordingly. These will appear in Device properties during creation by default.
  • Paths Tab
    • Input path-to-spine (it can be retrieved from `which spine` command output) in Spine Poller File Path.
  • Poller Tab
    • Poller Type must be spine, not “cmd.php”.
    • Poller Interval and Cron Interval correspond between each other in the following way: Cron queries hardware, Poller updates RRDs and graphs. So, Poller Interval could not be greater than Cron one. You can poll your devices Every minute, and build graphics rarer. So you save on some processor resources on Cacti's Server.
    • Maximum Threads per Process - this parameter regulates how many concurrent sub-processes will be started when spine starts its work within Cron programmed chronology. To facilitate you to understand what happens we demonstrate you how Cacti polls remote network devices. Cacti's poller Spine consists of the number if separate procedures called sub-routines. Each subroutine starts in isolated area of memory and represents small program code running as parallel process. Cacti can start the same sub-routine (which for example asks for SNMP data some given IP addres) several times giving it each time different IPs. So we have some pseudo-parallel executed codes which poll some remote devices at the same time (simultaneousely). Well.. It would increase performance of Cacti when it processes a numerous remote devices. This option is much like similar to “Maximum concurrent Poller Processes” which is the same for another type of poller - CMD.PHP. CMD.PHP is text-based script - a program which is parsed and performed by PHP interpreter. This is rather slowly in comparision to Spine poller. And there is big complexity to make PHP to run threads. We can run some copies of script passing them to PHP interpreter each time with different parameters instead. This is “like” Spine's threads, but some copies of whole program are executed in parallel. not a part of code of the same program.
    • Downed Host detection defines default value of the same field during device creation. Use Ping of SNMP Uptime and it will apear at device creation page.
    • Ping Type - ICMP Ping which is more preferred from Firewall view point.


SNMP installation on monitored hosts

It's rather simple.

~# apt-get install snmp snmpd
. . .

Some comments:

  • snmp - a package with utilities like snmpwalk (to do SNMP Object Tree traversal), snmpget or snmpset (to read and set particular SNMP-enabled host parameters) and others;
  • snmpd - Daemon which listens network and answers on requests of snmpwalk and other SNMP-utilities.

After that all we need is reform configuration file of a daemon SNMPD (snmpwalk and others don't need configuration files because they get all its parameters through Ubuntu's CLI). In the last versions of SNMPD its config was greatly simplified. By default it has the most of parameters being correctly configured. But we must define access rules. By default they are grouped in structured architecture (we don't touch SNMPv3). First of all Agent is defined, then the View for community is configured, then Community itself. We must redefine above for our local conditions, because default configureation supposes local use (on this host - that is on 127.0.0.1) only, with no access from any LAN. This is default “head” of /etc/snmp/snmpd.conf:

. . .
agentAddress  udp:127.0.0.1:161
. . .
view   systemonly  included   .1.3.6.1.2.1.1
view   systemonly  included   .1.3.6.1.2.1.25.1
. . .
rocommunity public  default    -V systemonly
. . .

These options limit usage of SNMPD on localhost only and only a half of SNMP Tree including .1.3.6.1.2.1.1 and .1.3.6.1.2.1.25.1 leaves only of the whole SNMP tree.

Let's modify configuration in /etc/snmp/snmpd.conf in the following way:

. . .
agentAddress  udp:161
. . .
view   systemonly  included   .1.3.6.1.2.1.1
view   systemonly  included   .1.3.6.1.2.1.25.1
. . .
rocommunity public 172.16.0.0/12
. . .

Could you see the difference?.. :-) I will explain. Doing so we remove restriction where requests can arrive from. And at the same time we leave private addresses of United Networks (172.16.0.0/12) which are allowed to read the only defined rocommunity public. Additionally we remove any view restrictions from this community (-V systemonly) telling SNMPD to return whole SNMP Tree for requests. Then we need to restart the daemon:

~# /etc/init.d/snmpd restart
 * Restarting network management services:
~#

Let's check it out from another host:

~# snmpwalk -v2c -c public 172.16.0.1
iso.3.6.1.2.1.1.1.0 = STRING: "Linux srvgate.msk.united-networks.ru 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (15605200) 1 day, 19:20:52.00
iso.3.6.1.2.1.1.4.0 = STRING: "Me <me@example.org>"
iso.3.6.1.2.1.1.5.0 = STRING: "srvgate.msk.united-networks.ru"
iso.3.6.1.2.1.1.6.0 = STRING: "Sitting on the Dock of the Bay"
iso.3.6.1.2.1.1.7.0 = INTEGER: 72
iso.3.6.1.2.1.1.8.0 = Timeticks: (0) 0:00:00.00
iso.3.6.1.2.1.1.9.1.2.1 = OID: iso.3.6.1.6.3.10.3.1.1
iso.3.6.1.2.1.1.9.1.2.2 = OID: iso.3.6.1.6.3.11.3.1.1
iso.3.6.1.2.1.1.9.1.2.3 = OID: iso.3.6.1.6.3.15.2.1.1
iso.3.6.1.2.1.1.9.1.2.4 = OID: iso.3.6.1.6.3.1
iso.3.6.1.2.1.1.9.1.2.5 = OID: iso.3.6.1.2.1.49
iso.3.6.1.2.1.1.9.1.2.6 = OID: iso.3.6.1.2.1.4
iso.3.6.1.2.1.1.9.1.2.7 = OID: iso.3.6.1.2.1.50
iso.3.6.1.2.1.1.9.1.2.8 = OID: iso.3.6.1.6.3.16.2.2.1
iso.3.6.1.2.1.1.9.1.3.1 = STRING: "The SNMP Management Architecture MIB."
iso.3.6.1.2.1.1.9.1.3.2 = STRING: "The MIB for Message Processing and Dispatching."
. . .
~#

… and so on. An enormous quantities of lines. :-)

Plugin installation

Prerequisites: Cacti and its PIA have been already installed, Plugin Management is enabled in the properties of administrative user under which plugin installation will be performed.

  1. First, we need download plugin archive. Usually this is made from site like this: http://docs.cacti.net/plugins.
  2. Then we need to store and extract it in directory <Cacti's home directory>/plugins/. As a rule plugins are delivered as tar-gzip archive (.tgz) so exact command to unpack “tarball” can be as follows. Usually I “pick” the link address right clicking on HTTP-link on the Plugin's download Web-page, then I switch to PuTTY window, type “wget ” and insert link right clicking again. Here is example of THold instalation:
    /var/www/cacti.united-networks.ru/plugins# wget http://docs.cacti.net/_media/plugin:thold-v0.4.9-3.tgz
    --2012-05-30 13:33:37--  http://docs.cacti.net/_media/plugin:thold-v0.4.9-3.tgz
    Преобразование адреса docs.cacti.net (docs.cacti.net)... 173.225.179.10
    Подключение к docs.cacti.net (docs.cacti.net)|173.225.179.10|:80... соединились.
    Запрос HTTP послан, ожидание ответа... 200 OK
    Длина: 120190 (117K) [application/octet-stream]
    Сохранение в каталог: ««plugin:thold-v0.4.9-3.tgz»».
    
    100%[=================================================================================>] 120 190      151K/s   за 0,8s
    
    2012-05-30 13:33:39 (151 KB/s) - «plugin:thold-v0.4.9-3.tgz» сохранен [120190/120190]
    
    /var/www/cacti.united-networks.ru/plugins# ll
    итого 132
    -rw-r--r-- 1 www-data www-data     44 мая   28 15:00 index.php
    drwxr-xr-x 4 www-data www-data   4096 мая   28 14:26 monitor
    -rw-r--r-- 1 root     root     120190 нояб. 12  2011 plugin:thold-v0.4.9-3.tgz
    drwxr-xr-x 9 www-data www-data   4096 мая   30 11:44 weathermap
    /var/www/cacti.united-networks.ru/plugins# mv plugin\:thold-v0.4.9-3.tgz thold-v0.4.9-3.tgz
    /var/www/cacti.united-networks.ru/plugins# tar zxvf thold-v0.4.9-3.tgz
    thold/
    thold/setup.php
    thold/thold_functions.php
    . . .
    thold/images/view_log.gif
    thold/listthold.php
    /var/www/cacti.united-networks.ru/plugins#

    P.s. I renamed tar archive before extracting because tar does not understand “plugin\: …” in a filename and swears on it.

  3. At the next step we go on “Plugin Management” page of Cacti's Web Interface and activate plugin clicking on blue “arrow” on the left from plugin name.

    It will become red. That means that plugin successfully installed.
    But it is not all. Being activated some plugins need to be enabled. This is made by pressing on green square with right arrow:

    It will also become red. As at Monitor plugin..

  4. But this is still not all. We have installed plugin and activated one but we still have no “handles” and “levers” to control it. The latter will apear in Web interface of those users who have corresponding options checked in their properties in “User Management

  5. Oh! Miracle! Just look at that! Now we have Tab named “thold” where we can see thresholds and Menu Item “Thresholds” where we can define thresholds itself. After we have defined thresholds and added them into devices Cacti begin to raise alarms when thresholds are violated. For example if we monitor used disk space on some host and if this space exhausted over the defined for this host threshold Cacti generates an e-mail or another predefined action.

Plugin Weathermap

It has some tricks for installation process. If you don't know them Weathermap does not tell you what's wrong. It will be silent. To deliver you from reading the numerous Internet articles let's talk about them.

The first thing you should know - being installed plugin does not create own databases. Just copy-paste the following in mysql console (preliminarily enter it by issuing mysql -u cacti_admin -p<some_strongest_password> at the Bash prompt):

CREATE TABLE weathermap_maps (
  id int(11) NOT NULL auto_increment,
  sortorder int(11) NOT NULL default 0,
  group_id int(11) NOT NULL default 1,
  active set('on','off') NOT NULL default 'on',
  configfile text NOT NULL,
  imagefile text NOT NULL,
  htmlfile text NOT NULL,
  titlecache text NOT NULL,
  filehash varchar (40) NOT NULL default '',
  warncount int(11) NOT NULL default 0,
  debug set('on','off','once') NOT NULL default 'off',
  runtime double NOT NULL default 0,
  lastrun datetime,
  config text NOT NULL default '',
  thumb_width int(11) NOT NULL default 0,
  thumb_height int(11) NOT NULL default 0,
  schedule varchar(32) NOT NULL default '*',
  archiving set('on','off') NOT NULL default 'off',
  PRIMARY KEY  (id)
) ENGINE=MyISAM;
         
CREATE TABLE weathermap_auth (
  userid mediumint(9) NOT NULL default '0',
  mapid int(11) NOT NULL default '0'
) ENGINE=MyISAM;
                  
CREATE TABLE  weathermap_groups (
  `id` INT(11) NOT NULL auto_increment,
  `name` VARCHAR( 128 ) NOT NULL default '',
  `sortorder` INT(11) NOT NULL default 0,
  PRIMARY KEY (id)
) ENGINE=MyISAM;
                              
                              
INSERT INTO weathermap_groups (id,name,sortorder) VALUES (1,'Weathermaps',1);

CREATE TABLE IF NOT EXISTS weathermap_data (
  id int(11) NOT NULL auto_increment,
  rrdfile varchar(255) NOT NULL,
  data_source_name varchar(19) NOT NULL,
  last_time int(11) NOT NULL,
  last_value varchar(255) NOT NULL,
  last_calc varchar(255) NOT NULL, 
  sequence int(11) NOT NULL, 
  local_data_id int(11) NOT NULL DEFAULT 0,
  PRIMARY KEY  (id), 
  KEY rrdfile (rrdfile),
  KEY local_data_id (local_data_id), 
  KEY data_source_name (data_source_name) 
) ENGINE=MyISAM;

Another thing is in Weathermap plugin's dependency on php5-gd. The latter is graphical extension for PHP. That is it allows to draw from PHP-code. Without it installed on the system Weathermap opens typical PHP diagnostic page. You need to install it manually by the following:

~# apt-get install php5-gd
Чтение списков пакетов… Готово
Построение дерева зависимостей
Чтение информации о состоянии… Готово
НОВЫЕ пакеты, которые будут установлены:
  php5-gd
. . . 

After that you can open editor through menus: Console → MANAGEMENT:Weathermaps → Weathermap Editor. You can find “Weathermap Editor” in the middle of the bottom dark blue status line (with bright white letters on it). If all is fine Editor will be opened in separate Tab/Window depending on settings of your browser and you will be suggested three alternatives:

  • create new map;
  • crate new map as a copy of existing one;
  • pick one of existing for editing.

With no errors on a page. In that case you may be quiet, all is ok.

Populating Cacti by Graphs

Important Warning! If you change standard template for either Data Source or Graph then you need to delete all existing graphics with their associated data sources for that template and rebuild them for the second time! Without that graphics will continue to draw in the previous way.

Objects Architecture

If you look at frightful diagram on the right you can see the objects subordination in Cacti. You should know for what purposes serves one or the other object to get final load graphic. Real data flow is shown by “reds”.

At the bottom of hierarchy data is located, at the top graphs are. Data can be retrieved from remote device via SNMP by locally run command like:

/var/www/cacti.united-networks.ru# snmpwalk -v2c -c public 172.16.16.6 .1.3.6.1.4.1.9.2.1.3.0
iso.3.6.1.4.1.9.2.1.3.0 = STRING: "sr-2821.eyatsko.msk"
/var/www/cacti.united-networks.ru#

This is actual for simple, single returned value. As in above example. But sometimes SNMP data is returned as an array of values. In that case Cacti must process it and lay each portion of data on its “shelf”. For that case Cacti has a number of XML-structured files which describe those arrays structures and define algorithm for processing. Another way to collect data - locally run a script which gets data somewhere by a way known only to it and this script returns data in a form which is understood for Cacti.

Data (SNMP or not) are collected in Cacti in such entities as “Data Sources”. Simply saying Data Sources describe for Cacti how and from where to get data for graphics. Data Sources are then used by other Cacti entities called “Graphs” to draw a graphic. Graphs contain information about how graphis should look, how axes must be signed, and, of course, data source where data for graphic are got from. These two are key “figures” in this concern: Data Sources and Graphs. All others are auxillary things.

To simplify (speed up) process of Graphs creation some helpers were developed. They are called in general “Templates”. Templates can be as for data sources as for graphs. And even for devices teplates are. To understand what is exactly happening when we are creating a Graph let's consider general steps what we make usually working with Cacti.

  1. First of all we drop into “Management/Devices” menu to create a device object which reflects (represents) real server or router. We indicate its IP (where Cacti will “knock”) and general SNMP-parameters. Also we can choose a type of this certain device - we can select so called Host Template. The only thing which use of Host Template gives is we need or not manually add inherent Graph Template. For example if we choose “Cisco Router” as a Host Template “Cisco - CPU Usage” and “SNMP - Interface Statictics” will apear automatically in the device's properties in “Graph Templates” and “Data Query” sections accordingly.
  2. Then we save created device pressing button “Save” at the bottom of the page, then we go to the top of the same Web-page and click link “Create Graphs for this Host”. At that moment real Graphs and and their Data Sources are created!
  3. Created Graphs are placed into menu “Management/Graph Management”. They are already active but we still can not see them anywhere on the Graphs Tab (remember that we still are on the “Console Tab”). To make them “visible” we should place (embed) them into Graph Tree which must be created preliminarily.
  4. Graph Tree is created, evidently, in menu “Management/Graph Trees”. It is necessary to notice, that Cacti can hold many Graph Trees - just look at imperseptibleAdd” link on the top dark blue status line. At the its outermost right end. Click it, type the name for new Graph Tree and click “Create” button at the right bottom corner of the page where we are currently located. Look of the page will change. Additional sections and fields will appear. “Add” link will migrate down on the page - onto dark blue line of “Tree Items”. There you can add “leaves”. Take in account that addition of new leaves will occur inside currently choosen leaf! At the top of the process first leaves will be added into root element - into the tree itself. So you are able to build rather branched tree structure! I am sure you will examine this process and become familiar with trees quickly! :-) Just take a look at created Tree. We use capitals for separate sites (MSK,EYATSKO, DOMAIN) and lowercases for hardware (srvgate, sw-2940, etc). Entering into hardware leads to sweep opening related Graphs in the left part of Web-page.
  5. Let's come back to “Console/Management/Graph Management” and place created graphs on a tree. By deafult list of graphs is whole, that is for absolutely all devices wit no difference placed graphs somewhere or not. You can filter it on hostname (device name indicated earlier) - to limit output, then set checks on required graphs, select in drop-down combo an action “Place on a Tree (…)” and click on button Go. It will ask you further for certain place in a Tree where Graphs should be placed. After choosing right place and clickng Continue on the next page all will be done. Now you can visit Graphs Tab.

The above procedure pursure two goals: the first is introduce you to Cacti, the second is to demonstrate the very first diagram of Cacti's objects. Now we have notion about how Devices, Graphs and its Data Sources and Graph Trees are related. Let's take a look at remaining (unfamiliar) part of that diagram.

Let's talk about templates and their subordination. As we know now when we create device we should add some Graph Templates (a template for a graphic) into Device's properties. Device itself can be created using Host Template. Somebody earlier entered menu “Templates/Host Templates”, picked some Graph Templates and Data Queries from corresponding drop-down combos and saved all this as a certain Host Template - it's not so interesting - just visit “Templates/Host Templates” and you will makesure that it is not more then a part of Device configuration. It just allows to save some set of those options as preset which then is added into device by selecting “Host Template” during one's configuration.

So let's return back to Graph Templates. The latter is not Graphs theyself - they are only “patterns” on which real Graph is built. Since Graph can contain several graphics (for example one curve is for Ingress Bits-per-second and another is for Egress ones) Graph Template contains so-called Items. Items directly linked to corresponding Data Source Templates. When you click “Create Graphs for this Host” Graph is created from Graph Template and Data Sources are made from these Item's Data Source Templates. Is it clear? :-)

Data Template is more difficult for understanding. Data Template is a prototype for Data Source. It defines a method by which data will be collected. And depending on choosen way how statistical data is retreived from real hardware it can be:

  • snmpget which gets required data directly;
  • SNMP-array which need XML-file with description how these data must be processed, this is called “Data Query”. It is setup separately in corresponding menu.
  • Some script data which generated by locally run script (on a programming language of Perl) which returns data to Cacti in predefined form, this is called “Data Input Method”. It is setup separately in corresponding menu too.

Some of these things we will do later.

There is a main thing to remember in relation to Data Sources and Data Template (Graphs and Graphs Templates, Devices and Host Templates): you MAY THINK that the first is OBJECT, the second one (TEMPLATE) is a SET of PREDEFINED OPTIONS and PROPERTIES which migrate to real object upon creation stage. That is fields of corresponding dialog are set to these predefined values when you click “create”. You need to remember this when you try to “correct” OID in template thinking that this will be reflected in Graphics. I may be confused if it will not. Cacti does not guarantee that changing templates will lead to changing objects. To see changes finally on Graphics you need to delete them and re-create! Only during creation changes in templates migrate to object properties!

Now we have covered whole the very first diagram of Cacti's objects! :-) The last unmentioned thing: don't forget Save created devices clicking that button in the right-bottom corner of Web-page. But, probably you guessed by yourself.. :-)

Creating own Graphs/Data Templates

Get SNMP Data

Let's consider the procedure basing on “Get SNMP Data” method of data aquisition. We need to create all “chain” of subordinate objects from above hierarchy. That is Data Template, Graph Template. After that we are able to create objects for real hardware on the basis of these templates. We will create Graph to control Wireless Associations for Cisco AIR-AP1131AG-E-K9 access point - to know how many wireless users fumble in our Wi-Fi Network.

  1. First of all create Data Template. It describes how to we will get SNMP information from AP.
    • On the left-side menu click Data Templates in section Templates. 7
    • Then find out and click “Add” in the top-right corner of right-side part of the window. The Dialog for new Data Template will open (it is the same as for existing object, but empty).
    • Fill out the following fields with the following values:
      • in the section Data Templates: field Name - fill in something like “Cisco Wireless AP - Associations”. This will appear in the list of available Data Sources when clicking on Data Templates→Data Templates.
      • in the section Data Source: field Name - fill in with “|host_description| - Cisco AP Associations”. This will be shown in Management→Data Sources. Take a glance on the difference between “this” and “that” - the above is list of templates (!), from which real object are created, and the current is the list of already created mentioned objects. Exactly because of this Cacti's internal macro “host_description” is present in the Name of real data source. It will be expanded to the name of a device (also real - not a template name) where this Data Source will be choosen when this device will be created. The whole list of Cacti variables can be found in Cacti documentation: http://www.cacti.net/downloads/docs/html/variables.html. If we don't use “|host_description|” all our Data Sources for all Cisco Access Points using this Data Source Template for creation will have the same Name in list. In that case how do we differ Data Source of one AP from Data Source of another? You will see in list of Data Source only: Cisco AP Associations, Cisco AP Associations, Cisco AP Associations… Who is who here? This is the QUESTION! :-)
      • in the section Data Source: field Data Input Method - select “Get SNMP Data” in drop-down combo.
      • in the section Data Source Item []: field Internal Data Source Name enter the name which will represent this Data Source in Graph Template. Use lower-case letters for the name and make this name rather short but intelligible.
      • in the same section take a look at Data Source Type field with selected value “GAUGE”. If you try SNMPWALK with some SNMP-enabled host it shows OIDs with associated values. Somewhere between numbers of OID and its value you can see types - something like: Counter32, Gauge32, Integer, String, Timeticks and so on. Trick is that values returned by SNMP protocol have form of TLV=Type-Length-Value. And on the receiving side this type is needed to be interpreted in the same way as it was coded on the transmitted side. Here we tell to poller that it should wait Gauge32 when poll this OID.
    • After you have pressed “Create” the screen extends by additional section: Custom Data. Its staffing depends on value of “Data Input Method” which you have selected before. In our case the content of this section is determined by “Get SNMP Data”.
    • All we need to do there is to fill in field OID - insert “.1.3.6.1.4.1.9.9.273.1.1.2.1.1.1”. This is an OID for AP's radio interface dot11Radio0, for interface dot11Radio1 OID will change to ”.1.3.6.1.4.1.9.9.273.1.1.2.1.1.2”.
  2. The next step is making of Graph Template. It's used when Graph creating from Device Screen. When you press “Create Graphs for this Host” being in device configuration screen Graphs are created from Graph Templates you have choosen in sections Associated Graph Templates and Associated Data Quieries. Graphs automatically create Data Sources from which they will get the data for their graphics. Data Sources in order are created from corresponding Data Templates which are referenced from Graph Templates. This is the “chain” of events.
    • Let's move to Templates→Graph Templates, then click Add, now you already know where it can be found: the top-right corner of Graph Templates list, dark-blue header.
    • Fill in the following fields before clicking “Create” (all other fields do not matter):
      • in the section Template: field Name - input something like “Cisco Wireless AP - Associations”. This is the name of Graph Template of its own. It will appear in the list of graph templates.
      • in the section Graph Template: field Title - indicate something similar to Data Template |host_description| - Cisco AP Associations. This is the name of Graph which will appear at the top of the graphic.
    • Create.
    • The screen will be altered. New sections Graph Template Items and Graph Item Inputs will appear. The first one will contain items which represent graphic line or under-graphic statistical data or some another data. The second one will contain items which serve to ask for user to input some parameters during graphic creation. For example, you can “program” with these items to ask for user color of graphic curve (the most frequent use). Or an OID of interface dot11Radio1. Or an IP address of a host. Or something else. Let's consider content of the sections separately.

  3. Being “inside” Graph Template add Graph Item as usual clicking Add on the top-right of the screen. We consider the most common way used in the most of Graph Templates in Cacti.
    • Item # 1 will be graphic itself.
      • in the drop-down combo Data Source select previously created Data Source Template “Cisco Wireless AP - Associations - (cisco_ap_assocs)”. In the brackets once mentioned “internal name” is shown This is just that which were written “in short and in lower-case”. Do you remeber? In the drop-down combo Data Template and internal name are shown combined.
      • in the drop-down Color select a color. In the example color equal to “Host MIB - Logged in Users” Graph Template color is shown.
      • in the Graph Item Type type of graphic is indicated. We have choosen AREA by analogy to mentioned “Host MIB - Logged in Users” Graph Template. Actually this is solid-filled graphic-area, not just line.
      • in Consolidation Function we indicate what type of statistical function to apply to incoming from hardware data till building and drawing graphic. AVERAGE is the most suitable. There is a temptation to choose “LAST” but it doesn't work.
      • Text Format is a subscription on axis OY. Just enter something like “Associations”.
    • Item # 2 will be the first subscription (under-graphic text and statistic) - Last numeric value (not a graphic line). Let's look through fields in short.
      • field Data Source - Cisco Wireless AP - Associations - (cisco_ap_assocs) (it will be the same for all Items because all of them work with the same data but represent one in different ways).
      • field Color - None.
      • field Graph Item Type - GRPINT (numeric value).
      • field Consolidation Function - LAST.
      • field GPRINT Type - Exact Numbers.
      • field Text Format - Last: - it will appear under the bottom of graphic and will server as axplanation to digits what the latter means.
    • Item # 3 will be the second subscription - Average numeric value.
      • field Data Source - Cisco Wireless AP - Associations - (cisco_ap_assocs).
      • field Color - None.
      • field Graph Item Type - GRPINT.
      • field Consolidation Function - AVERAGE.
      • field GPRINT Type - Exact Numbers.
      • field Text Format - Avg: text.
    • Item # 4 will be the third subscription - Maximum numeric value.
      • field Data Source - Cisco Wireless AP - Associations - (cisco_ap_assocs).
      • field Color - None.
      • field Graph Item Type - GRPINT.
      • field Consolidation Function - MAX.
      • field GPRINT Type - Exact Numbers.
      • field Text Format - Max: text.
      • Select checkbox Insert Hard Return. We have just created statistical subscription to graphic. Last, Average, Maximum and so on - these are all statistical data which is calculated and output by Cacti under the graphic. Separate statistical units are output one-by-obe in the same line of text. Insertion of Hard Return leads to breaking output for this line and beginning to output with new line. You can see this on graphics for network interfaces. Input and Output Traffic statistical data is output into two separate lines.

  4. If you look at Graph Item Inputs section after you have finished to create Grap Items you may notice that there Data Source [cisco_ap_assoc] has appeared. It is created automatically. Don't touch it. But you may add for example color for “Item # 1”. Add new Graph Item Input.
    • field Name - enter text. For example “Legend Color”.
    • field Field Type - Data Source.
    • select checkbox Item # 1: AREA (AVERAGE) in section Associated Graph Items (it's combined automatically from Graph Item data which we entered previously). It means that when creating graphs user is prompted to pick up a color for graph. When he do that the color is applied to selected graph.

  5. Next you can go to Management→Devices and Add (the top right corner of devices list, dark-blue header) a device. Since speech is about Cisco device and exactly about Cisco Wireless Access Point you need to indicate the following (take in account that this is the real device now, not a template, that is object itself):
    • section Devices, field “Description”: something like msk.ap-1131. Look at it attentively. Site name is carried to the beginning of the name. It is made to order devices in their list. If we do on the contrary list will be sorted by the name: ap-1131. ap-1131.eyatsko.msk, ap-1131.msk, then srvgate. srvgate.eyatsko.msk, srvgate.msk. and so on. That will be more difficult to find certain device on the certain site. Let's think: when trouble arises we usually keep in mind where it has arised (in the first place) and just after that we think what type of device causes it. And key criteria for searching becomes Site-name, not a device name.
    • section Devices, field Hostname: “ap-1131.msk.united-networks.ru” - this is the FQDN of the device.
    • section Devices, drop-down combo Host Tamplate - select “Cisco Router”. This is the case when we select a template of a host and the Device will be supplied with certain graphs after creation just according to this Host Template. For example in this certain case we will find “Cisco - CPU Usage” in “Associated grph Templates” and “SNMP Interface Statistics” in “Associated Data Quieries”.
    • section Devices, checkbox Monitor Host - checked.
    • Click Create button. Device screen will be supplemented with to additional sections.
    • In the section Associated Graph Templates remove “Cisco - CPU Usage” graph template by clicking red cross on the right of the corresponding line and add “Cisco - CPU Usage (newer IOS)” instead by selecting in corresponding drop-down combo and then clicking button Add.
    • Next, create graphics clicking “Create Graphs for this Host”.
    • You will find yourself on Grpahs creation Web-page. You need to select certain graphs clicking corresponding checkbox opposite the graph name. Not all graphs are needed to be created. For exapmle interface “Null” or base interface for subinterfaces. Just look at Dot11Radio0 interface and its associated subinterfaces Dot11Radio0.13 and Dot11Radio0.19. Sometimes it's necessary to create parent interface's graph - to view total statistic on all subinterfaces and sometimes not. Overall policy consists in creation of the minimal nubert of graphs but they must be very useful ones.
    • After clicking Create you probably will be asked for some graph parameters just in case - about “Legend Color” - this is the very parameter which we have discussed during Graph Template configuration. Well, just agree.. Click Create.
  6. Go to Management→Graph Management. You can filter records in the list typing “msk.ap-1131” in the field “Search” and clicking the button “Go”.
    • Select checkbox opposite to msk.ap-1131 - CPU Usage. Notice this is real Graph, not a template. Look at the name attentively - previous |host_description| is expanded and the graph name contains “conditional hostname” and actually Graph name “CPU Usage”. Remember how we have composed Title in the corresponding Graph Template.
    • Select in drop-down combo “Choose an action” on the bottom-right of the page with Graphs the value “Place on a tree (Default Tree)”. And click “Go” button near the drop-down combo.
    • On the next screen select “—— ap-1131” immediately under “— MSK” in the drop-down combo Destination Branch. And click Continue button. We just have selected destination place in the graph tree for the graph.
    • select checkboxes opposite to graphs “msk.ap-1131 - Traffic - Do0.13” through “msk.ap-1131 - Traffic - Fa0.19”, then place them the at the same place in the Grap Tree as previously - that is at “—— ap-1131” under “— MSK”.
    • in the same way place subsequently there the graphs “msk.ap-1131 - Traffic - BV1” and “msk.ap-1131 - Cisco AP Associations”. Such sequental procedure determines the order in which graphs will apear when you navigate to graphs Tab and then to Default Tree→MSK→ap-1131.
    • Voila! There it is! Strictly speaking you can place graphs on the Graph Tree as they are in the graph list (one step) and then re-arrange them in menu: Management→Graph Trees. Here you can see prototype of Graph Tree which you met on “graphs” Tab. We can expand or collapse Headings using signs of “plus” or “minus” on the left from corrsponding Heading. This helps to navigate through the tree of objects and localize the object which we need.



Get Script Server Data Indexed

“But…” You can say… We just have made Graphic of Associations for the only Radio Interface of an Access Point. What can we do if we need to view both interfaces at a time? One way we can use is to build to Data Sources, two Graph Templates and finally to Graphs for each Radio Interfaces. One Data Souce will use OID ”.1.3.6.1.4.1.9.9.273.1.1.2.1.1.1” for interface dot11Radio0, and another Data Source will use OID ”.1.3.6.1.4.1.9.9.273.1.1.2.1.1.2” for interface dot11Radio1. There will be two separate graphics (Graph, Graph Template and finally Data Source), for the accosiations of two interfaces. That is we go through above procedure one more time and get in the result additional graphic below the shown one above.

Another way is to make two Data sources for each OID and combine them in one Graph Template as two lines (areas) - one below the other on one graphic. Let's take a glance on differences between the above procedure and the suggested method.

  • There are two Data Sources with the names:
Interface Data Templates - Name Data Source - Name Data Source Item - internal Data Source Name OID
dot11Radio0 Cisco Wireless AP - Associations (do0) |host_description| - Cisco AP Associations (do0) cisco_ap_assocs_do0 .1.3.6.1.4.1.9.9.273.1.1.2.1.1.1
dot11Radio1 Cisco Wireless AP - Associations (do1) |host_description| - Cisco AP Associations (do1) cisco_ap_assocs_do1 .1.3.6.1.4.1.9.9.273.1.1.2.1.1.2
  • Graph Template is modified too:

Other settings of the Graph Template are left intact.

Look at the above illustrations attentively. Here we have introduced the first time use of the CDEF (mathematic) function. Actually this is “Total All Data Sources”. You can find it choosen in “Item # 3” … “Item # 5” and in “Consolidation [do0+do1]” in corresponding drop-down combos. Here we have two Data Sources: the first is for dot11Radio0 (which represents IEEE802.11b/g Wireless standard) associations and the second is for dot11Radio1 (IEEE802.11a standard) ones and mentioned CDEF function sums instant values of data sources and the result is used later in statistical subscriptions under the graphic.

You can notice that Items #3, #4 and #5 use Data Source “Cisco Wireless AP - Associations (do0) - (cisco_ap_assocs_do0)”. But how to make it to sum two data sources? As you choose “Total All Data Sources” as this Item begins to show the Sum instead of single value of choosen Data Source. We have made Graph Item Input “Consolidation [do0+do1]” but it has not been necessary. It was for debugging purposes - to allow us change CDEF function “on the fly” without changing Graph Template.

Also notice that in those items used different value for GPRINT Type for the first two “Exact Numbers” is used and for the last one this is “Load average”. It is rathe clearly. When we find look for “Last” value or when we searching for “Maximum” we deal with instant, momentary values. But just we begin to concern “Average” we have to do with statistical function. Therefore “Load Average” value is used for AVERAGE GPRINT Type.

Next. Look at Graph Item Type of the first two Items: #1 and #2 (these are actually graphics). To get one graphic is raised over another we have used “STACK” Graph Item Type. Be careful to avoid ineffective time expense! It is used ONLY in the second graph. The first is usual AREA. STACK is built on previous regular graph (or another STACK), but not vice-versa!


But.. Is there simplier way (you're asking)? “Two data sources… Graphs with STACK… CDEF functions…” No, there is not. All other cases are more complex, cumbersome and difficult for understanding. There is “more right” one from Cacti's viewpoint. The next case consists in the use of “Get Server Script Data (Indexed)” (“Unix Script”) and “Data Queries” with corresponding Graph Templates and their Data Sources. Data Queries are suitable for processing of so called SNMP Tables. Let's consider an example. There is a table “Host Resources Storage Table” (“hrStorageTable”) in the Host-MIB (Standard SNMP MIB which is inherent in nearly all devices).

hrStorageTable  1.3.6.1.2.1.25.2.3
   hrStorageTableEntry  1.3.6.1.2.1.25.2.3.1
      hrStorageIndex  1.3.6.1.2.1.25.2.3.1.1
      hrStorageType  1.3.6.1.2.1.25.2.3.1.2
      hrStorageDescr  1.3.6.1.2.1.25.2.3.1.3
      hrStorageAllocationUnits  1.3.6.1.2.1.25.2.3.1.4
      hrStorageSize  1.3.6.1.2.1.25.2.3.1.5
      hrStorageUsed  1.3.6.1.2.1.25.2.3.1.6
      hrStorageAllocationFailures   1.3.6.1.2.1.25.2.3.1.7 

In practice this looks like the following:

~# snmpwalk -v2c -c public 172.16.16.2 1.3.6.1.2.1.25.2.3
iso.3.6.1.2.1.25.2.3.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.25.2.3.1.1.2 = INTEGER: 2
iso.3.6.1.2.1.25.2.3.1.1.3 = INTEGER: 3
iso.3.6.1.2.1.25.2.3.1.1.4 = INTEGER: 4
iso.3.6.1.2.1.25.2.3.1.1.5 = INTEGER: 5
iso.3.6.1.2.1.25.2.3.1.1.6 = INTEGER: 6
iso.3.6.1.2.1.25.2.3.1.2.1 = OID: iso.3.6.1.2.1.25.2.1.5
iso.3.6.1.2.1.25.2.3.1.2.2 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.3 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.4 = OID: iso.3.6.1.2.1.25.2.1.7
iso.3.6.1.2.1.25.2.3.1.2.5 = OID: iso.3.6.1.2.1.25.2.1.3
iso.3.6.1.2.1.25.2.3.1.2.6 = OID: iso.3.6.1.2.1.25.2.1.2
iso.3.6.1.2.1.25.2.3.1.3.1 = STRING: "A:\\"
iso.3.6.1.2.1.25.2.3.1.3.2 = STRING: "C:\\ Label:SYSTEM  Serial Number b80c5f5f"
iso.3.6.1.2.1.25.2.3.1.3.3 = STRING: "D:\\ Label:DATA  Serial Number ea57acb4"
iso.3.6.1.2.1.25.2.3.1.3.4 = STRING: "R:\\"
iso.3.6.1.2.1.25.2.3.1.3.5 = STRING: "Virtual Memory"
iso.3.6.1.2.1.25.2.3.1.3.6 = STRING: "Physical Memory"
iso.3.6.1.2.1.25.2.3.1.4.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.4.2 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.3 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.4.5 = INTEGER: 65536
iso.3.6.1.2.1.25.2.3.1.4.6 = INTEGER: 65536
iso.3.6.1.2.1.25.2.3.1.5.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.5.2 = INTEGER: 7861801
iso.3.6.1.2.1.25.2.3.1.5.3 = INTEGER: 487324927
iso.3.6.1.2.1.25.2.3.1.5.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.5.5 = INTEGER: 53472
iso.3.6.1.2.1.25.2.3.1.5.6 = INTEGER: 32757
iso.3.6.1.2.1.25.2.3.1.6.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.2 = INTEGER: 2967423
iso.3.6.1.2.1.25.2.3.1.6.3 = INTEGER: 324440738
iso.3.6.1.2.1.25.2.3.1.6.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.5 = INTEGER: 7324
iso.3.6.1.2.1.25.2.3.1.6.6 = INTEGER: 13140
iso.3.6.1.2.1.25.2.3.1.7.1 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.2 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.3 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.4 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.5 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.6 = Counter32: 0

Which can easily be “converted” to “real” table (in above output data follows column-by-column in linear manner):

hrStorageIndex        hrStorageType        hrStorageDescr  hrStorageAllocationUnits  hrStorageSize  hrStorageUsed  hrStorageAllocationFailures
1 iso.3.6.1.2.1.25.2.1.5 (hrStorageRemovableDisk) “A:\\” 0 0 0 0
2 iso.3.6.1.2.1.25.2.1.4 (hrStorageFixedDisk) “C:\\ Label:SYSTEM Serial Number b80c5f5f” 4096 7861801 2967423 0
3 iso.3.6.1.2.1.25.2.1.4 (hrStorageFixedDisk) “D:\\ Label:DATA Serial Number ea57acb4” 4096 487324927 324440738 0
4 iso.3.6.1.2.1.25.2.1.7 (hrStorageCompactDisc) “R:\\” 0 0 0 0
5 iso.3.6.1.2.1.25.2.1.3 (hrStorageVirtualMemory) “Virtual Memory” 65535 53472 7324 0
6 iso.3.6.1.2.1.25.2.1.2 (hrStorageRam) “Physical Memory” 65535 32757 13140 0

hrStorageType-s” could be retrieved by snmpwalk on corresponding OID (1.3.6.1.2.1.25.2.1) just “near” the considered hrStorageTable (in the same SNMP-Tree). Real size of a device is got by multiplication of hrStorageSize and hrStorageAllocationUnits or hrStorageUsed and hrStorageAllocationUnits. For example Disk C: has 7'861'801 x 4'096 = 32'201'936'896 bytes (that is about ~30 GigaBytes) and there is used 2'967'423 x 4'096 = 12'154'564'608 (that is about ~11 GigaBytes).

What's the further?

We need to “explain” to Cacti how to work with the above data. How it should interpret them into table, what is the structure of the latter. This is made by XML-script. Depending on content of XML-script CACTI either does some actions on retrievement of some data from a device or call some PHP-script which is indicated in the XML file. The first method has got the name “Get SNMP Data (Indexed)”. In that case Cacti gets a notion about table structure directly from XML and processes SNMP Tables on its own. This method works only for good structured tables which have strictly determined layout. For example table must have a column with Indexes - with line numbers. For all other cases Cacti calls a script (Perl or PHP) and by now it must retrieve data from a device and represent one into format which Cacti understands. It is just because we cannot use “Get SNMP Data (Indexed)”. There are not Indexes in our table. What is not “Get SNMP Data (Indexed)” it has “Script” in their names: “Get Script Data (Indexed)” or “Get Script Server Data (Indexed)”. In our case we will use the last. Our Script will artifically make Indexes for Cacti. Look at the below examples, they demonstrate two mentioned approaches:

Get SNMP Data Indexed (SNMP Interface Statistics) Get Script Server Data Indexed (SNMP - Get Mounted Partitions)
<interface>
        <name>Get SNMP Interfaces</name>
        <description>Queries a host for a list of monitorable interfaces</description>
        <oid_index>.1.3.6.1.2.1.2.2.1.1</oid_index>
        <oid_num_indexes>.1.3.6.1.2.1.2.1.0</oid_num_indexes>
        <index_order>ifDescr:ifName:ifHwAddr:ifIndex</index_order>
        <index_order_type>numeric</index_order_type>
        <index_title_format>|chosen_order_field|</index_title_format>

        <fields>
                <ifIndex>
                        <name>Index</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.2.2.1.1</oid>
                </ifIndex>
                <ifOperStatus>
                        <name>Status</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.2.2.1.8</oid>
                </ifOperStatus>
                <ifDescr>
                        <name>Description</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.2.2.1.2</oid>
                </ifDescr>
                <ifName>
                        <name>Name (IF-MIB)</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.31.1.1.1.1</oid>
                </ifName>
. . .

                <ifIP>
                        <name>IP Address</name>
                        <method>walk</method>
                        <source>OID/REGEXP:.*\.([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.4.20.1.2</oid>
                </ifIP>
        </fields>
</interface>


<interface>
        <name>Get Host MIB Partitions</name>
        <script_path>|path_cacti|/scripts/ss_host_disk.php</script_path>
        <script_function>ss_host_disk</script_function>
        <script_server>php</script_server>
        <arg_prepend>|host_hostname| |host_id| |host_snmp_version|:|host_snmp_port|:|host_snmp_timeout|:
|host_ping_retries|:|host_max_oids|:|host_snmp_community|:|host_snmp_username|:|host_snmp_password|:
|host_snmp_auth_protocol|:|host_snmp_priv_passphrase|:|host_snmp_priv_protocol|:|host_snmp_context|</arg_prepend>
        <arg_index>index</arg_index>
        <arg_query>query</arg_query>
        <arg_get>get</arg_get>
        <arg_num_indexes>num_indexes</arg_num_indexes>
        <output_delimeter>!</output_delimeter>
        <index_order>hrStorageDescr:hrStorageIndex</index_order>
        <index_order_type>numeric</index_order_type>
        <index_title_format>|chosen_order_field|</index_title_format>

        <fields>
                <hrStorageIndex>
                        <name>Index</name>
                        <direction>input</direction>
                        <query_name>index</query_name>
                </hrStorageIndex>
                <hrStorageDescr>
                        <name>Description</name>
                        <direction>input</direction>
                        <query_name>description</query_name>
                </hrStorageDescr>
                <hrStorageAllocationUnits>
                        <name>Storage Allocation Units</name>
                        <direction>input</direction>
                        <query_name>sau</query_name>
                </hrStorageAllocationUnits>

                <hrStorageSize>
                        <name>Total Size</name>
                        <direction>output</direction>
                        <query_name>total</query_name>
                </hrStorageSize>
                <hrStorageUsed>
                        <name>Total Used</name>
                        <direction>output</direction>
                        <query_name>used</query_name>
                </hrStorageUsed>
                <hrStorageAllocationFailures>
                        <name>Allocation Failures</name>
                        <direction>output</direction>
                        <query_name>failures</query_name>
                </hrStorageAllocationFailures>
        </fields>
</interface>

On the left you can see “Get SNMP Data (Indexed)” typical example. You can notice that each field contains two very important things: an OID and an SNMP Method to acquire the data from OID. You can understand from the seen that for example to get ifIndex's data Cacti should make “snmpwalk” on ”.1.3.6.1.2.1.2.2.1.1”. At the same time let's tell few words about “input” and “output” “directions”: “output” data is directly used for building graphic while “input” fields are auxillary and needed for reference to the graph somewhere in Cacti's Web interface. For example, if you enter some device (Management→Devices) and click “Create Graphs for this Host” you will appear on the page where you are prompted to select graphs for creations. Here you can see “input” Index, Description and so on. Field name tag (such as ”<ifOperStatus>”) and “name” are also used for representation fields in Cacti's Web interface. The talk will turn to them later.

In opposite to the spoken the right part has no OIDs in field defenition. OIDs are used directly in Script the name of which you can see in the header of XML file. Just look at the “<script_path>” clause (and related ones): “|path_cacti|/scripts/ss_host_disk.php” - this is full path to the script which will retrieve required data from the real device and return this data back to Cacti. Path is composed from two parts: base Cacti's catalogue (“|path_cacti|”) and relative offset with the final Script's filename (“ss_host_disk.php”). The other clauses describe a function inside the script that should be called (“<script_function>”) and script “engine” - that is interpreter which will parse and perform operators from the script (it is called “<script_server>”). Here is PHP.

“Script section” of XML is followed by “arg_*” related clauses. They describe what internal variables will be passed by Cacti into the script (“<arg_prepend>”) as command-line arguments and what commands for script are allowed from Cacti: “<arg_index>”, “<arg_query>”, “<arg_get>”, “<arg_num_indexes>”. The latter makes script to determine how many indexes are returned from real device. It is print a number, for example: “6” - that is six indexes. “Get” is something like “snmpget”, “query” is like “snmpwalk”, and “index” prints all indexes: “1, 2, 3, 4, 5, 6”.

Then various index related information follows. Then filed descriptions follow. Fileds represent the values which Cacti queries from devices with the help of the script. You can see examples of these queries if you enter device again (Management→Devices) and click on “Verbose Query”. You will see something like the following, but in small font:

+ Running data query [12].
+ Found type = '6' [Script Query - Script Server].
+ Found data query XML file at '/var/www/cacti.united-networks.ru/resource/script_server/cisco_ap_assocs.xml'
+ XML file parsed ok.
+ Executing script for num of indexes '"/usr/bin/php" -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: num_indexes'
+ Found number of indexes: 1
+ Executing script for list of indexes '"/usr/bin/php" -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: index' Index Count: 1
+ Found index: 1
+ Executing script query '"/usr/bin/php" -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: query index'
+ Found item [Index='1'] index: 1
+ Executing script query '"/usr/bin/php" -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: query description'
+ Found item [Descr='Radio Associations'] index: 1

Attentively look at line(s) like:
+ Executing script for num of indexes '”/usr/bin/php” -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: num_indexes'
Here “/usr/bin/php” is mentioned above “engine”, “/var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php” performed script which retrieves data, “ap-1131.msk.united-networks.ru” and others are command-line parameters passed into script. The first one is FQDN (or just an IP address) of a device. Than ID of a device (this is the Cacti internal ID - some scripts can work directly with Cacti's database using this ID, for example to snmpwalk device one time, to cache retrieved data and then ask for cache multiple times). In our case this is “6”. Then the SNMP Parameters combined in special fashion using colons follows: SNMP Version, UDP Port, Request Timeout, Ping Retries, Maximum of returned OIDs, Community, SNMPv3 Authentication Data and so on. This is made to represent all of these as one command-line argument. You can look at the script's line:
<arg_prepend>|host_hostname| |host_id| |host_snmp_version| : |host_snmp_port| : |host_snmp_timeout| : |host_ping_retries| : |host_max_oids| : |host_snmp_community| : |host_snmp_username| : |host_snmp_password| : |host_snmp_auth_protocol| : |host_snmp_priv_passphrase| : |host_snmp_priv_protocol| : |host_snmp_context|</arg_prepend>
It results in: “2:161:500:1:10:public::::::”. Because we don't use SNMPv3 with its authentication and encryption there are many “empty” colons (with missed parameters). What is the next? The last parameter is actually command to script what to do: “num_indexes”. This certain command makes script to calculate the number of indexes returned by snmpwalk. If you look at other the same lines in above output you will find various “queries”: query index, query description. These are right “input” fields defined in XML:

                <Index>
                        <name>Index</name>
                        <direction>input</direction>
                        <query_name>index</query_name>
                </Index>
                <Descr>
                        <name>Description</name>
                        <direction>input</direction>
                        <query_name>description</query_name>
                </Descr>

The Query Name is passed as additional parameter in query to the script.

Now let's look at the script:

~# cd /var/www/cacti.united-networks.ru
/var/www/cacti.united-networks.ru# vi scripts/ss_host_disk.php
<?php

/* do NOT run this script through a web browser */
if (!isset($_SERVER["argv"][0]) || isset($_SERVER['REQUEST_METHOD'])  || isset($_SERVER['REMOTE_ADDR'])) {
        die("<br><strong>This script is only meant to run at the command line.</strong>");
}

$no_http_headers = true;

/* display No errors */
error_reporting(0);

if (isset($config)) {
        include_once(dirname(__FILE__) . "/../lib/snmp.php");
}

if (!isset($called_by_script_server)) {
        include_once(dirname(__FILE__) . "/../include/global.php");
        include_once(dirname(__FILE__) . "/../lib/snmp.php");

        array_shift($_SERVER["argv"]);

        print call_user_func_array("ss_host_disk", $_SERVER["argv"]);
}

function ss_host_disk($hostname, $host_id, $snmp_auth, $cmd, $arg1 = "", $arg2 = "") {
        $snmp = explode(":", $snmp_auth);
        $snmp_version   = $snmp[0];
        $snmp_port      = $snmp[1];
        $snmp_timeout   = $snmp[2];
        $ping_retries   = $snmp[3];
        $max_oids               = $snmp[4];

        $snmp_auth_username     = "";
        $snmp_auth_password     = "";
        $snmp_auth_protocol     = "";
        $snmp_priv_passphrase   = "";
        $snmp_priv_protocol     = "";
        $snmp_context           = "";
        $snmp_community                 = "";

        if ($snmp_version == 3) {
                $snmp_auth_username   = $snmp[6];
                $snmp_auth_password   = $snmp[7];
                $snmp_auth_protocol   = $snmp[8];
                $snmp_priv_passphrase = $snmp[9];
                $snmp_priv_protocol   = $snmp[10];
                $snmp_context         = $snmp[11];
        }else{
                $snmp_community = $snmp[5];
        }

        $oids = array(
                "total"                 => ".1.3.6.1.2.1.25.2.3.1.5",
                "used"                  => ".1.3.6.1.2.1.25.2.3.1.6",
                "failures"              => ".1.3.6.1.2.1.25.2.3.1.7",
                "index"                 => ".1.3.6.1.2.1.25.2.3.1.1",
                "description"           => ".1.3.6.1.2.1.25.2.3.1.3",
                "sau"                   => ".1.3.6.1.2.1.25.2.3.1.4"
                );
 . . . 

At the heading of the code some cheks are performed (whether this script is run under Apache or not, for example). Interesting things start from the line: “print call_user_func_array(“ss_host_disk”, $_SERVER[“argv”]);”. Here main function (see XML's <script_function>… </script_function> clause) is called. Call is performed by PHP function “call_user_func_array()”, and function name (“ss_host_disk”, see its declaration below) and array of its parameters (array “$_SERVER[“argv”]”) are passed as parameters into call_user_func_array(). Notice that call_user_func_array() returns a value returned in order by ss_host_disk(). And it is printed in Standard Output of the Script (to STDOUT). Generally speaking Script must print ALL its results into STDOUT, and Cacti aquires then them from STDOUT which becomes STDIN for Cacti. This is main principle.

Look at ss_host_disk function declaration:
function ss_host_disk($hostname, $host_id, $snmp_auth, $cmd, $arg1 = ””, $arg2 = ””) Remember the call of Script with PHP engine: “ap-1131.msk.united-networks.ru” “6” “2:161:500:1:10:public::::::” “num_indexes” - these all turn out at $hostname, $host_id, $snmp_auth, $cmd (and maybe at $arg1, $arg2 if there were more parameters) places. That is in result of substitution wil become: $hostname=“ap-1131.msk.united-networks.ru”, $host_id=“6”, $snmp_auth=“2:161:500:1:10:public::::::” and $cmd=“num_indexes”. There are no additional parameters therefore $arg1 and $arg2 will remain empty (that is ”” as in function declaration).

Immediately after beginning of ss_host_disk() function “snmp_auth” variables value (string “2:161:500:1:10:public::::::”) is parsed into array named “snmp” by function “explode” using colon as delimiter. And depending on snmp_version value “snmp_auth_*” set of variables whether gets values (for SNMPv3) or not.

Oh! Look at that! Here OIDs are found! It is rather simple, isn't it? Wel, let's begin to write our own script! Below there is a sample of real, working script. But before we begin we should become aware of “originative” XML file for the script:

<interface>
        <name>Get Cisco AP Associations</name>
        <script_path>|path_cacti|/scripts/cisco_ap_assocs.php</script_path>
        <script_function>cisco_ap_assocs</script_function>
        <script_server>php</script_server>
        <arg_prepend>|host_hostname| |host_id| |host_snmp_version|:|host_snmp_port|:
|host_snmp_timeout|:|host_ping_retries|:|host_max_oids|:|host_snmp_community|:
|host_snmp_username|:|host_snmp_password|:|host_snmp_auth_protocol|:|host_snmp_priv_passphrase|:
|host_snmp_priv_protocol|:|host_snmp_context|</arg_prepend>
        <arg_index>index</arg_index>
        <arg_query>query</arg_query>
        <arg_get>get</arg_get>
        <arg_num_indexes>num_indexes</arg_num_indexes>
        <output_delimeter>!</output_delimeter>
        <index_order>Descr:Index</index_order>
        <index_order_type>numeric</index_order_type>
        <index_title_format>|chosen_order_field|</index_title_format>

        <fields>
                <Index>
                        <name>Index</name>
                        <direction>input</direction>
                        <query_name>index</query_name>
                </Index>
                <Descr>
                        <name>Description</name>
                        <direction>input</direction>
                        <query_name>description</query_name>
                </Descr>

                <Radio0>
                        <name>interface dot11Radio0</name>
                        <direction>output</direction>
                        <query_name>radio0</query_name>
                </Radio0>
                <Radio1>
                        <name>interface dot11Radio1</name>
                        <direction>output</direction>
                        <query_name>radio1</query_name>
                </Radio1>
        </fields>
</interface>





























<?php

/* do NOT run this script through a web browser */
if (!isset($_SERVER["argv"][0]) || isset($_SERVER['REQUEST_METHOD'])  || isset($_SERVER['REMOTE_ADDR'])) {
        die("<br><strong>This script is only meant to run at the command line.</strong>");
}

$no_http_headers = true;

/* display No errors */
error_reporting(0);

if (isset($config))
 {
  include_once(dirname(__FILE__) . "/../lib/snmp.php");
 }

if (!isset($called_by_script_server))
 {
  include_once(dirname(__FILE__) . "/../include/global.php");
  include_once(dirname(__FILE__) . "/../lib/snmp.php");
  array_shift($_SERVER["argv"]);
  print call_user_func_array("cisco_ap_assocs", $_SERVER["argv"]);
 }

function cisco_ap_assocs($hostname, $host_id, $snmp_auth, $cmd, $arg1 = "", $arg2 = "")
 {
  if ($cmd == "index")
   {
    for ($i=1;$i<=1;$i++)
     {
      print $i."\n";
     }
   }
  elseif($cmd == "num_indexes")
   {
    print "1";
   }
  elseif($cmd == "query")
   {
    $arg = $arg1;
    if($arg == "radio0")
     {
      $dot11Radio0=`/usr/bin/snmpget -v2c -Ov -c public $hostname 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1 | /usr/bin/awk '{printf $2}'`;
      print "1!".$dot11Radio0."\n";
     }
    elseif($arg == "radio1")
     {
      $dot11Radio1=`/usr/bin/snmpget -v2c -Ov -c public $hostname 1.3.6.1.4.1.9.9.273.1.1.2.1.1.2 | /usr/bin/awk '{printf $2}'`;
      print "1!".$dot11Radio1."\n";
     }
    elseif($arg == "index")
     {
      print "1!1\n";
     }
    elseif($arg=="description")
     {
      print "1!Radio Associations\n";
     }
   }
  elseif($cmd == "get")
   {
    $arg = $arg1;
    $index = $arg2;
    if($index==1 && $arg=="radio0")
     return `/usr/bin/snmpget -v2c -Ov -c public $hostname 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1 | /usr/bin/awk '{printf $2}'`;
    if($index==1 && $arg=="radio1")
     return `/usr/bin/snmpget -v2c -Ov -c public $hostname 1.3.6.1.4.1.9.9.273.1.1.2.1.1.2 | /usr/bin/awk '{printf $2}'`;
   }
 }
?>

If all is rather clear with XML the script can look quite complex. A couple of words about SNMP structure which is represented by XML. It describes an SNMP table with one row and four columns. There is temptation to make two rows for two Radios, but.. It will lead to TWO different Graphs instead of two graphics on the same single Graph. Do you understand? So Radios must be in the same line for being on the same Graph. Thereby line in SNMP table is the only. Columns are the folowing: index (mandatory), description (at the end of the day it is bogus. It is needed during graphic creation) and two radios: radio0 and radio1 (it is real working data source columns).

In the script I omit SNMP related commands because I exactly know what SNMP version will be. And I begin immediately with commands which can be got by script from Cacti: you can observe the following commands (query names): “index”, “description”, “radio0” and “radio1”.

As reaction on query “index”:
/usr/bin/php -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:500:1:10:public:::::: index
Script should return all indexes line by line. For example if there would be 3 indexes script must print:

~# /usr/bin/php -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:::::: index
1
2
3
~#

Including CRs. Take a note about: 'print $i.”\n”;' operator. But in our certain case the task is deterministic and we print just “1”, the first and the single index.

Go further. As reaction on “num_indexes” we print “1” - the number of indexes. We have the only index. One line per mentioned above SNMP table.

As a reaction on “query” $arg1 is brought into play. We must supply script with additional parameter, for example:

~# /usr/bin/php -q /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 6 2:161:::::: query radio0
1!2
~#

Notice that the first one is index then actually queried value follows (it is delimited by ”!” from index). If you look at XML you will find ”<output_delimeter>!</output_delimeter>”. Is it clear? :-) It is very important to accomplish output of each line by “\n”. Otherwise Cacti might not understand the returned by script values! Related to “query” block of the code in the script “considers” the following cases: “query index”, “query description” and accordingly “query radio0” and “query radio1”. Index and Description are constant values we just print them, but in the case of Radio0 and Radio1 we ask device by SNMP. SNMPGET's ”-Ov” argument supresses odd snmpget output leaving just an OID and its corresponding value. AWK filters actual value and assigns it to Script's internal variable which is printed a few moments later.

And the last command if “get”. As opposed to “query” which returns whole column of data, get returns certain value which is located on the intersection of certain column and row in SNMP Table. Therefore “get” command gets TWO arguments: column name ($arg1) and index value ($arg2). As a rule “get” command to script is used for data aquisition during graphic building. So it actually supplies only “output” fields of XML. Another difference between “get” and “query” is in that the result of “get” is not printed immediately after getting. Result is returned back to called code (look at the beginning of the script) and printed there: ”print call_user_func_array(“cisco_ap_assocs”, $_SERVER[“argv”]);”.

In conclusion of script analysis let's summarize all script output in general table:

Cacti request Scritpt Action
num_indexes should print a number of SNMP rows with no tailing '\n'!
index should print indexes (one per a row) with '\n' at the end. Be careful it is not the number in order, it is index! Indexes could follow inconsistently: 1 6 10 115 116 120…
query should print indexes with values of certain SNMP-column delimited by '!' (or by another symbol declared in XML). Each row must be complemented with '\n'
get should return in calling routine requested (single) value located on crossing column and row of SNMP-table. Without '\n'! Calling routine print it itself.

ATTENTION! Be careful writing a script! Once I do mistake in Get. My indexes anywhere else except “Get” procedure began at “1”, and in “Get” it began at “0”. This difference led to situation when “get something n” (where 'n' was maximum of index) gave an “Index is out of range” error in script, what in order prevented corresponding graph from being built. That is there was no Graph at all. And no errors in Cacti. Just graphic absence! No any diagnosis. Nothing! So.. Check the work of your script in detail through Linux command line. For all situations for all combinations of query/get/index it should return correct values whithout errors. I mean command: 'php -q ../../scripts/cisco_ap_assocs.php ap-1131.msk.united-networks.ru 2 2:161:1500:1:10:public:::::: query radio0' and so on. And here is that ill-starred script and its XML: operators.tar.gz :-)

Next step is to create Data Query in Cacti. Go to “Collection methods→Data Query” and “Add” new Data Query. Take a look on sample drawing on the right. Please, enter Query name in Name field (it will appear in the list of Quieries), also enter some Description, select “Get Script Server Data (Indexed)” in drop-down combo, and the most important thing you need to do is to complement XML Path with actual XML file directory and filename. The value <path_cacti> (it's is expanded in my case into /var/www/cacti/united-networks.ru/) and /resource/ subdirectory are suggested by default. As you fill in fileds of the form and click “Create”, form is extended with additional section: “Associated Graph Templates”. To begin work with it you need to do some prior actions. Actually we need create two things: Data Template and Graph Template. Being created they might be confronted with fields from XML file and corresponding Script. Let's do that.

First of all, create Data Template. As you add new Data Template at “Template→Data Templates” (clicking unremarkable “Add” at the top-right of the screen) as you will encounter yourself at a page of Data Template which you are already familiar with. Fill-in the fields:

  • Name” in section “Data Templates” - with the name for this template;
  • Name” in section “Data Source” - this name will appear in the “Management→Data Sources”. The name for real Data Source (not a template) is got from |host_description| and some “explanation text” (“Cisco - AP- Associations” in this case). It becomes rather “personalized”.
  • Choose “Get Script Server Data Indexed” in the drop-down combo “Data Input Method”;
  • Internal Data Source Name” in section “Data Source Item” - this is name for an actual data source. They might be several per Data Source. And they corellate with XML file's fields!

After clicking “Create” new section “Custom Data” will appear. It is specific for choosen “Get Script Server Data Indexed”. Here we need to complete Data Sorce creation:

  • Notice, that at the top right of the section “Data Source Item” hyperlink “New” has appeared. Click it and fill in “Internal Data Source Name” field with “radio1”. That is add additional Internal Data Source. The names “radio0” and “radio1” will be used later when you will link XML fields with newly created data sources in the mentioned earlier section of the Query. They should be understandable for you. Notice, that two additional headings have appeared above the “Data Source Item” section's heading. The text on Tabs is equal to entered names of the data sources. It changes immediately after you Save this Data Template.
  • Mark all checkboxes in the section “Custom Data”. It is important! It's because Cacti will be made to get “personal” “Index Type”, “Index Value” and “Output Type ID” for both “radio0” and and “radio1” internal data sources.

All other values might be left intact.

Next, we create Graph Template. Go to “Templates→Graph Templates”. Enter text from sample into fields and click “Create”:

  • Field “Name” in the section “Template” - Name for the Template itself.
  • Field “Title (–title)” in the section “Graph Template” - Graph Title.
  • Field “Vertical Label” in the section “Graph Template” - subscription for Y-axis on the graphic picture.

Appearance of Graph Template Dialog will change immediately after creatin, several sections are added: “Graph Template Items”, “Graph Item Inputs”. Let's add Grap Items in the way which is already familiar to us:

Data Source Color Graph Item Type Consolidation Function GPRINT Type Text Format Insert Hard Return
Item # 1 Cisco Wireless - AP - Associations (radio0) 4668E4 AREA AVERAGE Normal Assoc.do0
Item # 2 Cisco Wireless - AP - Associations (radio0) None GRPINT LAST Exact Numbers Last:
Item # 3 Cisco Wireless - AP - Associations (radio0) None GRPINT MAX Exact Numbers Max:
Item # 4 Cisco Wireless - AP - Associations (radio0) None GRPINT AVERAGE Exact Numbers Avg: Yes
Item # 5 Cisco Wireless - AP - Associations (radio1) 8d00BA AREA AVERAGE Normal Assoc.do1
Item # 6 Cisco Wireless - AP - Associations (radio1) None GRPINT LAST Exact Numbers Last:
Item # 7 Cisco Wireless - AP - Associations (radio1) None GRPINT MAX Exact Numbers Max:
Item # 8 Cisco Wireless - AP - Associations (radio1) None GRPINT AVERAGE Exact Numbers Avg: Yes

Also you may add “Graph Item Inputs” (there are sample values below):

Name Field Type Associated Grapth Items
Data Source [radio0] Data Source [radio0] Data Source Item #1: AREA (AVERAGE), Item #2: GPRINT (LAST), Item #3: GPRINT (MAX), Item #4: GPRINT (AVERAGE)
Data Source [radio1] Data Source [radio1] Data Source Item #5: AREA (AVERAGE), Item #6: GPRINT (LAST), Item #7: GPRINT (MAX), Item #8: GPRINT (AVERAGE)


Once you create Graph Template, you can get back to Quiery and complete its configuration. When you enter your previously created Data Query you need to “Add” Graph Template. Why do this? When you pick up this Data Query from a device Cacti needs to know what Graph use to visualize data returned by this Data Query. And Graph needs Data Sources. It's because we spent some time creating them. :-) Now we need to associate Graph Template which will be used later for Graph Creation.

In opened dialog enter an arbitrary name and select formely created graph template “Cisco Wireless - AP - Associations” in drop-down combo. The name you have entered means nothing, it serves to distinguish one associated graph template from another when there are several ones. As you “Create” the dialog will be extended by several additional sections.

You will find two rows “Data Sources” in “Associated Data Templates”. These data templates have been choosen by you in due time during creation of Graph Template. What did happen? Cacti seeing selected on the preceeding step Graph Template looks into latter and detects Data Template with two Data Sources in it. Recall: “radio0” and “radio1”. So here Cacti shows you these ones: “radio0” and “radio1”. And there two combo-boxes are opposite to them. There are two items in combo-boxes: “Radio0 (interface dot11Radio0)” and “Radio1 (interface dot11Radio1)”. Don't you get it yet? ;-) These are output fields from you XML! Look at that here they are:

<Radio0>
  <name>interface dot11Radio0</name>
  <direction>output</direction>
  <query_name>radio0</query_name>
</Radio0>
<Radio1>
  <name>interface dot11Radio1</name>
  <direction>output</direction>
  <query_name>radio1</query_name>
</Radio1>

Items' names are combined from XML's section name and the “name” option! It is the most important moment of all “this fairytale”. Here and only here you associate data template with you script!

Let's be attentive! Both drop-down combos initially contain the same value: “Radio0 (interface dot11Radio0)”, and for second Data Source you should select “Radio1 (interface dot11Radio1)” in the second one! :-) And don't forget to select checkboxes on the right. This activates data sources.

The last thing you should do is to fill blank fields in section “Suggested Values”. I don't know why exactly them are needed, but it seems these values are used as name for Data Source and as title for Graph created from these Data and Graph Templates (perhaps this replaces corresponding fields in Data and Graph Templates which were created by us several minutes ago). I always use the following “naming schema”:

  • something like “|host_description| - Cisco Wireless - AP - Associations” in the first field and “name” in “Field Name” - for Data Template;
  • something like “|host_description| - Cisco Wireless - AP - Associations” in the first field and “title” in “Field Name” - for Graph Template;


After doing that you may go to Management→Devices and create device as usually. While being in device's dialog choose “Cisco Wireless - AP - Associations” in corresponding drop-down combo in the section “Associated Data Quieries”. Then “Create Graphs for this Host” and so on, and so on in usual way. As result you should get the following.



Script/Command

Other alternative to stated methods is Scripts. It is simplier than Queries but still requires certain accuracy. This method is suitable when SNMP is not a case. In short sceanrio can be described as follows:

  • We write a script which gathers some information from (network) devices;
  • Script should get some parameters as command-line arguments. The most important (and mandatory) is IP address of a device. This parameters are called as “input fields” in Cacti's terms.
  • Script should print data for graphics in special format: <field1>:<value1> <field2>:<value2> … <fieldN>:<valueN> - as many fields (another term for graphic calling), as many graphics. These fields are called in Cacti's terms as “output fields”.
  • Next, we create in Cacti “Data Input Method” (Collection Methods→Data Input Method) with “Input Type” = “Script/Command”.
  • Then we define what Cacti should pass into script (so called “Input Fields”) and what out Script will return back to Cacti (“Output Fields”). Input Field(s) is an IP of a device as a rule. Output Field(s) is mentioned <field1>:<value1>…
  • Next we create in Cacti Data Source in the same way as described above indicating our Script as Data Input Method.
  • Then we create Graph Template indicating fresh created Data Source as “Data Source” for Graphics (Item # 1, Item # 2, …).
  • Then we can create a Device and and choose that Graph. Then “Create Graphics for this Host” and so on, and so on…

Well.. Let's begin to describe in detail.

First of all we need script. I wrote small Perl-based program to repeat the sample with Wireless Access Point. Here it is:

~# vi /var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.pl
#!/usr/bin/perl

if($#ARGV>=0)
 {
  $IP=$ARGV[0];
  $dot11Radio0=`/usr/bin/snmpget -v2c -Ov -c public $IP 1.3.6.1.4.1.9.9.273.1.1.2.1.1.1 | /usr/bin/awk '{printf \$2}'`;
  $dot11Radio1=`/usr/bin/snmpget -v2c -Ov -c public $IP 1.3.6.1.4.1.9.9.273.1.1.2.1.1.2 | /usr/bin/awk '{printf \$2}'`;
  print "dot11Radio0:".$dot11Radio0." dot11Radio1:".$dot11Radio1."";
 }

As you can see it executes two snmpget-commands to Host's IP which is passed as command-line argument into this Perl-script. Results are stored into script variables. Variables are printed in certain format: “dot11Radio0:1 dot11Radio1:0” Here “dot11Radio0” and “dot11Radio1” some arbitrary names. Main idea Cacti must know about these ones. Fields in Cacti must be the same! After fieldnames real values delimited by colon (”:”) follow. That is what returned by “snmpget”. Be carefull using '$' (dollar sign) in the shell command execution by `` apostrophes requires backslash '\' because '$' is internal Perl symbol!

The other important moment is in absence of '\n' at the end of output string. Take a look at the 'printf' operator. Well, now we can follow into Cacti: add new object in Collection MethodsData Input Methods. Fill in the following fields by the following values:

  • Section Data Input Methods, field Name - arbitrary name which will be used elsewehere in Cacti as reference to this Input Method: “Cisco Wireless - AP - Script
  • Section Data Input Methods, drop-down combo Input Type - “Script/Command”.
  • Section Data Input Methods, large field Input String - exact command with all parameters enclosed into triangle brackets - to execute script. Cacti will issue this command replacing triangle brackets with real data. For example: “/var/www/cacti.united-networks.ru/scripts/cisco_ap_assocs.pl <ip>”. Here <ip> is the one example of “triangle” parameters. :-) Brackets are mandatory! And “ip” is the (arbitrary) name of input field. It's just the name. And what Cacti should imply is described a little bit later. Triangle brackets signalize to Cacti that this is Input Field.
  • Section Input Fields, click “Add
    • Screen will change and you will be suggested to choose from drop-down combo Input Field name (which is in triangle brackets in command-line). In our case that will be “ip”.
    • Friendly Name is internal Cacti's name, this parameter will be presented anywhere by this “Friendly Name” in Cacti's interface.
    • Special Type Code should contain “hostname” in our case. It means that under string “ip” Cacti will mean IP-address of a device where this Input Method is used.
  • Section Output Fields, click Add
    • Screen will change and you will see a set of fields. The first is Field [Output]. It must contain EXACTLY THE SAME as output field printed by script. That is we should create two such fields: “dot11Radio0” and “dot11Radio1” one-by-one. Now let's create “dot11Radio0”. Put this in “Field [Output]”. Notice, that it is case sensitive!
    • Next field is already familiar to us “Friendly Name”. In the sample I entered the same as previous: “dot11Radio0”.
    • Update RRD File is checked - so leave it checked.
  • Create “dot11Radio1” by yourself.


We have just created and object which represents work of our script and wich is named “Data Input Method”. Now let's create corresponding Data Source Template which will get results from that script and “impersonate” them for Cacti. To do that go to “Templates”→“Data Templates” and “Add”. From now the rest of procedure will strongly remind the same one from “Data Queries”.

  • Section Data Templates, field Name - enter the name for this template: “Cisco Wireless - AP - Script”.
  • Section Data Source, field Name - here fill-in template through which the real name of real Data Source will be formed. When you click “Create Graphs fot this Host” during “Device” creation. Enter something like: “|host_description| - Cisco Wireless - AP - Script”. When Device will be created internal Cacti's variable “|host_description|” will be replaced with content of the Device's field “Description”.
  • Section Data Source, drop-down combo Data Input Method - select “Cisco Wireless - AP - Script”.
  • Section Data Source, checkbox Data Source Active - should be checked.
  • Section Data Source Item, field Internal Data Source Name - the name of Data Source Item. I used “radio0”. To distinguish it from Script's Output Field “dot11Radio0”.
  • Section Data Source Item, field “Maximum Value (…” - “0” (unlimited).
  • Click “Create”. “Data Source Item” section will be extended in accordance to choosen “Data Input Method” and new section “Custom Data” will appear.
  • Notice that now drop-down combo “Output Field” is present. Choose “dot11Radio0 - dot11Radio0” (it's composed from “Name” and “Friendly Name”).
  • Now add New Data Source Item - look at the right end of dark-blue heading of this section.
  • New tab will appear. There will be default name “ds” for it. Change it on “radio1” and repeat all steps as for “fadio0” choosing Output Fielddot11Radio1 - dot11Radio1”.
  • IP field in section Custom Data - leave intact (checkbox should be unchecked and text field should be blank).
  • Save the Data Template.


Well.. Now right time for Graph Template Creation. We have just created “Data Template” and linked its internal “Data Source Items” with the “Data Fields” returned by the Script. Now let's create usual “Graph Template” and associate it with that “Data Template”. Move to “Templates”→“Graph Templates” and Add new template (in the top-right corner of Graph Templates list, on the dark-blue heading). Fill-in the following fields:

  • Section Template, field Name - enter here the name of the template. For example: “Cisco Wireless - AP - Script”.
  • Section Graph Template, field Title (–title), enter here template for name of Graphs' which are built basing on this template. Here is something like: “|host_description| - Cisco Wireless - AP - Script”. When the real Graph will be built basing on this Graph Template the hostname will be in its name in place of “|host_description|” (latter will be replaced by Host Name where you clicked “Create Graphs for this host” link).
  • Section Graph Template, field Vertical Label (–vertical-Label) - here the name of ordinate axis should be entered. For example: “wifi users”.
  • Click Create, appearance of the form will change.
  • Add Graph Items with the following parameteres:
Data Source Color Graph Item Type Consolidation Function GPRINT Type Text Format Insert Hard Return
Item # 1 Cisco Wireless - AP - Script - (radio0) 4668E4 AREA AVERAGE Normal Assoc.do0
Item # 2 Cisco Wireless - AP - Script - (radio0) None GRPINT LAST Exact Numbers Last:
Item # 3 Cisco Wireless - AP - Script - (radio0) None GRPINT MAX Exact Numbers Max:
Item # 4 Cisco Wireless - AP - Script - (radio0) None GRPINT AVERAGE Exact Numbers Avg: Yes
Item # 5 Cisco Wireless - AP - Script - (radio1) 8d00BA STACK AVERAGE Normal Assoc.do1
Item # 6 Cisco Wireless - AP - Script - (radio1) None GRPINT LAST Exact Numbers Last:
Item # 7 Cisco Wireless - AP - Script - (radio1) None GRPINT MAX Exact Numbers Max:
Item # 8 Cisco Wireless - AP - Script - (radio1) None GRPINT AVERAGE Exact Numbers Avg: Yes


Next, you go to “Management”→“Devices” and create device which reflects real Access Point. Select in section Associated Graph Templates fresh created “Cisco Wireless - AP - Script” and click “Create Graphs for this Host”. Place created Graphs on the Graph Tree and wait for 5-10 minumtes - to allow Cacti to gather information, to make averageing and to update Graphics. If you have done all right you will see a graphic much like shown one.

Miscellaneous Problems

Fix "Host MIB" issue

Using Host MIB may cause lack some (or even all) information on some graphics when monitoring Windows Hosts. It is appeared on Graphics as something like this:

As you probably mentioned Disk Space cannot change unevenly. That is now nothing is used on Disk C: and few momments ago there were 60% used. This is speaks about one thing - Cacti hasn't time to aquire all needed data to build graphics correctly.

To be more accurate - the cause in that the Windows SNMP Agent responds to Cacti's requests too slowly. The performance of Cacti is enough to poll the numerous devices. But Windows brakes as usual.. :-)

One approach to avoid described situation is to increase SNMP Timeout. Just look at: Devices on the right-side menu → then pick up your Windows device (in my case there was SRVMAIN) → and increase SNMP Timeout in the section SNMP Options. 1500 milliseconds must be enough (instead 500 millsecond by default). Save changes in corresponding device. All is done, but you should realize that this will work until the number of controlled devices (and Windows hosts in particular) is not large. After some threshold there are no warranties!


ATTENTION: It will not be enough just to save changes in device! You need to delete all graphs and associated Data Sources in Graph Management and re-create them from Device in usual way! Probably RRD creates its Graph-data initially with complete set of parameters and subsequent editions of a device will not affect on existing RRD-graphs! This is applicable for all cases with Cacti. Later modification of parameters which are used during object creation is not accounted in existing objects in any way!


The second approach is in using of another SNMP object different from “Host MIB”. The speech is about “hrStorageTable”. This object is not embedded in Cacti out-of-box. In needs to be installed. You may ask me why do we need to install sometheng else if we can simply increase device timeout? Somebody is helped by increasing timeout but sombody may have a lots of devices where this method may not work.

First of all hrStorageTable implements Data Query wich made polling via XML-template and returns SNMP Data Indexed. Take a look at the Objects Architecture. SNMP Data Indexed is an SNMP Array which returns all needed information to build a set of graphs including their axes and titles! What the mentioned “Host MIB” does? It snmp-walks on the following SNMP-OID:

/usr/local/src# snmpwalk -v2c -c public 172.16.16.2 .1.3.6.1.2.1.25.2.3.1
iso.3.6.1.2.1.25.2.3.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.25.2.3.1.1.2 = INTEGER: 2
iso.3.6.1.2.1.25.2.3.1.1.3 = INTEGER: 3
iso.3.6.1.2.1.25.2.3.1.1.4 = INTEGER: 4
iso.3.6.1.2.1.25.2.3.1.1.5 = INTEGER: 5
iso.3.6.1.2.1.25.2.3.1.1.6 = INTEGER: 6
iso.3.6.1.2.1.25.2.3.1.2.1 = OID: iso.3.6.1.2.1.25.2.1.5
iso.3.6.1.2.1.25.2.3.1.2.2 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.3 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.4 = OID: iso.3.6.1.2.1.25.2.1.7
iso.3.6.1.2.1.25.2.3.1.2.5 = OID: iso.3.6.1.2.1.25.2.1.3
iso.3.6.1.2.1.25.2.3.1.2.6 = OID: iso.3.6.1.2.1.25.2.1.2
iso.3.6.1.2.1.25.2.3.1.3.1 = STRING: "A:\\"
iso.3.6.1.2.1.25.2.3.1.3.2 = STRING: "C:\\ Label:SYSTEM  Serial Number b80c5f5f"
iso.3.6.1.2.1.25.2.3.1.3.3 = STRING: "D:\\ Label:DATA  Serial Number ea57acb4"
iso.3.6.1.2.1.25.2.3.1.3.4 = STRING: "R:\\"
iso.3.6.1.2.1.25.2.3.1.3.5 = STRING: "Virtual Memory"
iso.3.6.1.2.1.25.2.3.1.3.6 = STRING: "Physical Memory"
iso.3.6.1.2.1.25.2.3.1.4.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.4.2 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.3 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.4.5 = INTEGER: 65536
iso.3.6.1.2.1.25.2.3.1.4.6 = INTEGER: 65536
iso.3.6.1.2.1.25.2.3.1.5.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.5.2 = INTEGER: 7861801
iso.3.6.1.2.1.25.2.3.1.5.3 = INTEGER: 487324927
iso.3.6.1.2.1.25.2.3.1.5.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.5.5 = INTEGER: 53472
iso.3.6.1.2.1.25.2.3.1.5.6 = INTEGER: 32757
iso.3.6.1.2.1.25.2.3.1.6.1 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.2 = INTEGER: 2967753
iso.3.6.1.2.1.25.2.3.1.6.3 = INTEGER: 324440737
iso.3.6.1.2.1.25.2.3.1.6.4 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.5 = INTEGER: 8677
iso.3.6.1.2.1.25.2.3.1.6.6 = INTEGER: 14084
iso.3.6.1.2.1.25.2.3.1.7.1 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.2 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.3 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.4 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.5 = Counter32: 0
iso.3.6.1.2.1.25.2.3.1.7.6 = Counter32: 0
/usr/local/src#

The series of OIDs beginning with iso.3.6.1.2.1.25.2.3.1.1.x none other than “possible indexes in array”. And iso.3.6.1.2.1.25.2.3.1.3.x are the names for storages. And iso.3.6.1.2.1.25.2.3.1.4.x are the measurement units for returned sizes of storages which in order are returned in iso.3.6.1.2.1.25.2.3.1.5.x (total space) and iso.3.6.1.2.1.25.2.3.1.6.x (used space). For example, C: and D: are measured in 4096 bytes chunks, and memory is measured in 64K ones (65535 bytes).

Standard host_disk.xml hrStorageTable.xml
<interface>
        <name>Get Host Partition Information</name>
        <index_order_type>numeric</index_order_type>
        <oid_index>.1.3.6.1.2.1.25.2.3.1.1</oid_index>

        <fields>
                <hrStorageIndex>
                        <name>Index</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.1</oid>
                </hrStorageIndex>
                <hrStorageDescr>
                        <name>Description</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.3</oid>
                </hrStorageDescr>
                <hrStorageAllocationUnits>
                        <name>Storage Allocation Units</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>input</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.4</oid>
                </hrStorageAllocationUnits>

                <hrStorageSize>
                        <name>Total Size</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>output</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.5</oid>
                </hrStorageSize>
                <hrStorageUsed>
                        <name>Total Used</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>output</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.6</oid>
                </hrStorageUsed>
                <hrStorageAllocationFailures>
                        <name>Allocation Failures</name>
                        <method>walk</method>
                        <source>value</source>
                        <direction>output</direction>
                        <oid>.1.3.6.1.2.1.25.2.3.1.7</oid>
                </hrStorageAllocationFailures>
        </fields>
</interface>
<interface>
   <name>Get hrStoragedTable Information</name>
   <description>Get SNMP based Partition Information out of hrStorageTable</description>
   <index_order>hrStorageDescr:hrStorageIndex</index_order>
   <index_order_type>numeric</index_order_type>
   <oid_index>.1.3.6.1.2.1.25.2.3.1.1</oid_index>

   <fields>
      <hrStorageIndex>
         <name>Index</name>
         <method>walk</method>
         <source>value</source>
         <direction>input</direction>
         <oid>.1.3.6.1.2.1.25.2.3.1.1</oid>
      </hrStorageIndex>
      <hrStorageDescr>
         <name>Description</name>
         <method>walk</method>
         <source>value</source>
         <direction>input</direction>
         <oid>.1.3.6.1.2.1.25.2.3.1.3</oid>
      </hrStorageDescr>
      <hrStorageAllocationUnits>
         <name>Allocation Units (Bytes)</name>
         <method>walk</method>
         <source>VALUE/REGEXP:([0-9]*) Bytes</source>
         <direction>input</direction>
         <oid>.1.3.6.1.2.1.25.2.3.1.4</oid>
       </hrStorageAllocationUnits>
      <hrStorageSize>
         <name>Total Size (Units)</name>
         <method>walk</method>
         <source>value</source>
         <direction>output</direction>
         <oid>.1.3.6.1.2.1.25.2.3.1.5</oid>
      </hrStorageSize>
      <hrStorageUsed>
         <name>Used Space (Units)</name>
         <method>walk</method>
         <source>value</source>
         <direction>output</direction>
         <oid>.1.3.6.1.2.1.25.2.3.1.6</oid>
      </hrStorageUsed>
   </fields>
</interface>






If you compare these two samples of XML-code you can observe that they much the same, but in standard host_disk.xml description and index_order are omitted. If “description” has no any effect, “index_order” has a key value!

It is not enough to insert missed lines from right code to left one. We need to modify all templates (data and graph) to account this change. The guaranteed way to avoid mistakes which can lead to Cacti re-installation is to get correct templates for hrStorageTable.xml pull it on Cacti installation and put hrStorageTable.xml to correct path in Cacti's directory structure. So make below simple steps:

  1. Download hrstoragetable087d.tar.gz Tar-ball from http://docs.cacti.net/_media/usertemplate:data:host_mib:hrstoragetable087d.tar.gz. It is not a matter that it has different version, it works. Don't worry! :-)
  2. Untar archive into some local directory on your PC from where you access Cacti-site and import cacti087d_data_query_snmp_-_hrstoragetable.xml through Import/ExportImport Templates in the right-side (main) Cacti's Menu.
  3. Then put hrStorageTable.xml into <Cacti sites's directory>/resources/snmp_quieries/ (original host_disk.xml is located in the same place).
  4. From here you can find “SNMP hrStorageTable” in corresponding menu (Data Quiery) within Device.
  5. Now you must delete old Host MIB graphs and you can create new ones.

Fix "Cisco CPU Usage" issue

Depending on IOS version Cisco Systems changed its OIDs for CPU Utilization. Therefore Cacti does not build corrsponding graphics. You can get to know with the subject in detail on page (Google keywords were: “cisco cpu usage OID IOS”, the first relevant result): http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a0080094a94.shtml. Here we only cite a table with OIDs:

Version IOS 12.2(3.5) or later IOS later to 12.0(3)T and prior to 12.2(3.5) IOS prior to 12.0(3)T
MIB CISCO-PROCESS-MIB CISCO-PROCESS-MIB OLD-CISCO-CPI-MIB
Objects cpmCPUTotal5minRev
(.1.3.6.1.4.1.9.9.109.1.1.1.1.8)
cpmCPUTotal5min
(.1.3.6.1.4.1.9.9.109.1.1.1.1.5)
avgBusy5
(.1.3.6.1.4.1.9.2.1.58)
cpmCPUTotal1minRev
(.1.3.6.1.4.1.9.9.109.1.1.1.1.7)
cpmCPUTotal1min
(.1.3.6.1.4.1.9.9.109.1.1.1.1.4)
avgBusy1
(.1.3.6.1.4.1.9.2.1.57)
cpmCPUTotal5secRev
(.1.3.6.1.4.1.9.9.109.1.1.1.1.6)
cpmCPUTotal5sec
(.1.3.6.1.4.1.9.9.109.1.1.1.1.3)
avgBusyPer
(.1.3.6.1.4.1.9.2.1.56)

Notice: OID above may require to add some digit in its tail, for example, you may need to indicate not exactly .1.3.6.1.4.1.9.2.1.58 but .1.3.6.1.4.1.9.2.1.58.0. To clearly know what a digit required just snmpwalk on value(s) of OIDs above (snmpwalk -v2c -c public <IP> <OID>). SNMPWALK shows real OID which you can than copy and paste to Data Template.

The first way is to simply change one (obsolete) OID .1.3.6.1.4.1.9.2.1.58.0 to another (newer, for example .1.3.6.1.4.1.9.9.109.1.1.1.1.5) in Templates→Data Templates then, on the right side of the screen: Cisco Router - 5 Minute CPU. This will work in a case when your devices all have rather “fresh” IOS version. For example this helped me, but I have the following IOSes in production:
c2800nm-adventerprisek9-mz.124-24.T3
c2960-lanbasek9-mz.122-50.SE
c2960-lanbasek9-mz.122-58.SE2
c2960-lanbasek9-mz.122-50.SE4
c1130-k9w7-mx.124-10b.JDA3
c2940-i6k2l2q4-mz.121-22.EA10a
c3550-ipservicesk9-mz.122-44.SE6

As you can observe all of them “younger” then 12.0(3)T. Using this way you doom yourself to track IOS versions to avoid meeting 12.0 or “elder”. Perhaps.. this will bring a use - your “iron bars” will always be up-to-date! :-)


The second way is to create own analogs of data template Cisco Router - 5 Minute CPU with associated graph templates.

  • First, create Data Template. Click barely noticable link Add on page Templates → Data Templates. It's located on the right of dark blue heading at the top of the page. Fields are (they mostly repeat existing object “Cisco Router - 5 Minute CPU” fields with some additions which allow differ both of these objects):
    • section Data Templates, field Name - Cisco Router - 5 Minute CPU (newer IOS);
    • section Data Source, field Name - |host_description| - 5 Minute CPU New;
    • section Data Source, drop-down combo Data Input Method - Get SNMP Data;
    • section Data Source Item, field Internal Name - 5min_cpu_new;
    • section Custom Data, field OID - .1.3.6.1.4.1.9.9.109.1.1.1.1.3.1 (this is most dynamic value - 5 seconds, without averaging on Cisco - in this case 5-mins-averaging is met on Cacti's side only).
    • Save and exit the device.
  • Then create Graph Template. Again, click barely noticable link Add on page Templates → Graph Templates. It's located on the right of dark blue heading at the top of the page.
    • section Template, field Name - Cisco - CPU Usage (newer IOS);
    • section Graph Template, field Title - |host_description| - CPU Usage;
    • Create.
  • After creation look of Graph Template will transformed. Graph Template Items will appear. We need to Add (dark blue heading) some of them - by analogy to original “Cisco CPU Usage” graph template:
    • Item # 1 (its name will appear after creation):
      • field Data Source - Cisco Router - 5 Minute CPU (newer IOS) - (5min_cpu_new);
      • field Color - FF0000 (light-red);
      • field Graph Item Type - AREA (just in case Consolidation Function must remain AVERAGE!);
      • field Text Format - CPU Usage text.
    • Item # 2:
      • field Data Source - Cisco Router - 5 Minute CPU (newer IOS) - (5min_cpu_new);
      • field Color - None;
      • field Graph Item Type - GRPINT;
      • field Consolidation Function - LAST;
      • field GPRINT Type - Extracrt Numbers;
      • field Text Format - Current: text.
    • Item # 3:
      • field Data Source - Cisco Router - 5 Minute CPU (newer IOS) - (5min_cpu_new);
      • field Color - None;
      • field Graph Item Type - GRPINT;
      • field Consolidation Function - AVERAGE;
      • field GPRINT Type - Extracrt Numbers;
      • field Text Format - Average: text.
    • Item # 4:
      • field Data Source - Cisco Router - 5 Minute CPU (newer IOS) - (5min_cpu_new);
      • field Color - None;
      • field Graph Item Type - GRPINT;
      • field Consolidation Function - MAX;
      • field GPRINT Type - Extracrt Numbers;
      • field Text Format - Maximum: text;
      • field Insert Hard Return - checked.
    • The last we must “reproduct” is Graph Item Inputs. This items will be asked when you create Graphs from a Device. We may not create this items, in that case all parameters will be used from graph template automatically (without ny questions), but I guess User must be given an opportunity to change for example color of some graphic. To distinguish one from another.
      • One of them will be added automatically while we create Graph Items - this is Data Source [5min_cpu_new] (analogue of CPU Usage Data Source in original “Cisco Router - 5 Minutes CPU”).
      • The second one we should create - just “Add” again and type on opened Properties Page “Legend Color” in field Name, choose Field Type in drop-down combo Color and select “Item #1:AREA(AVERAGE)” checkbox (this is the only graph item where color matters).
    • Save the Graph Template and exit.

Now you can use newly created Graph Templates in Devices.

Graphics Parameters

Common Settings for all devices

→ Devices, before clicking “Create”

  • Description → meaningful Server's name (including Site name), for inner use in Cacti. Devices will be referenced by this Description further during creation and setup.
  • Hostname → FQDN or IP Address of Server.
  • Monitor Host → checked.
  • Downed Device Detection → “Ping or SNMP Uptime. That is if it is ping-ed then result of ping is used, if no but SNMP data is accessible - UpTime changes will be used
    /var/www/cacti.united-networks.ru# snmpwalk -v2c -c public 172.16.16.6 .1.3.6.1.2.1.1.3.0
    iso.3.6.1.2.1.1.3.0 = Timeticks: (250796909) 29 days, 0:39:29.09
    /var/www/cacti.united-networks.ru#
  • Ping method - “ICMP Ping”, not UDP which can be filtered somewhere on the way to this device!
  • SNMP Version - “Version 2” of SNMP Protocol.
  • SNMP Community - “Public” - as a rule Community Public is present on every networked device.

→ Graph Trees:

  • Associated Data Queries:
    • SNMP - Interface Statistics.

Creating Unix Server

→ During creation

  • Generic SNMP-enabled Host

→ Devices

  • Associated Graph Templates:
    • ucd/net - CPU Usage;
    • ucd/net - Load Average;
    • ucd/net - Memory Usage;
    • Unix - Logged in Users;
  • Associated Data Queries:
    • SNMP - Get Mounted Partitions;

→ Graph Trees, Graph order:

  • Traffic - ethXX.
  • CPU Usage.
  • Load Average.
  • Used Space - / .
  • Used Space - Swap space.
  • Memory Usage.
  • Used Space - Physical Memory.
  • Used Space - Virtual Memory.
  • Logged in Users.

Creating Windows 2003 Server

→ During creation

  • Generic SNMP-enabled Host
  • SNMP Timeout = 1500 (instead of standard “500” value, it's for Windows Hosts only)

→ Devices

  • Associated Graph Templates:
    • Host MIB - Logged in Users;
    • Host MIB - Processes;
    • Unix - Load Average;
  • Associated Data Queries:
    • SNMP - Get Mounted Partitions;

→ Graph Trees, Graph Order:

  • Traffic - ethXX.
  • Load Average.
  • Used Space - C: Label:SYSTEM.
  • Used Space - D: Label:DATA.
  • Used Space - Physical Memory.
  • Used Space - Virtual Memory.
  • Logged in Users.
  • Processes.

Creating Cisco Generic Switch/Router

→ During creation

  • Cisco Router

→ Devices

  • Associated Graph Templates:
    • Cisco - CPU Usage (with corrected OID in “Templates” → “Data Templates” → “Cisco Router - 5 Minute CPU” → “Custom Data” → “OID” =.1.3.6.1.4.1.9.9.109.1.1.1.1.3.1 instead of .1.3.6.1.4.1.9.2.1.58.0);
      or
    • Cisco - CPU Usage (New IOS) which is created similarly to original “Cisco - CPU Usage” but with the other OID.

→ Graph Trees, Graph Order:

  • CPU Usage.
  • Traffic - ethXX.
  • Traffic - vlanXX (if applicable).

Creating Cisco 1130 Series Access Point

→ During creation

  • Cisco Router

→ Devices

  • Associated Graph Templates:
    • Cisco - CPU Usage (with corrected OID in “Templates” → “Data Templates” → “Cisco Router - 5 Minute CPU” → “Custom Data” → “OID” =.1.3.6.1.4.1.9.9.109.1.1.1.1.3.1 instead of .1.3.6.1.4.1.9.2.1.58.0);
      or
    • Cisco - CPU Usage (New IOS) which is created similarly to original “Cisco - CPU Usage” but with the other OID.
    • Cisco - AP1130 Associations (especially created Script/Command (see above) with multiple DS Data Template and Standard Graph Template).

→ Graph Trees, Graph Order:

  • CPU Usage.
  • Traffic - do0XX.
  • Traffic - do1XX.
  • Traffic - ethXX.
  • Traffic - bviXX.
  • AP1130 Associations.
monitoring.txt · Last modified: 2016/01/31 11:14 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki