1#!/usr/bin/perl -w
2
3#######################################################################
4# Processus d'interrogation de l'ensemble des equipements Osiris
5# - Interrogation SNMP + generation de graphes rrdtools
6# - Mise a jour de la base d'association Postgres pour les AP WiFi
7# - Mise a jour des fichiers d'etat du spanning tree pour l'ensemble
8#   des commutateurs du parc Osiris
9#
10# Ce processus travaille avec des sondes qui interrogent les
11# equipements.
12#
13# parametres :
14# option :  indique si le processus travaille sur l'ensemble des sondes, sur
15#           une liste de type de sonde executer ou a ignorer
16#
17# Les 2 parametres suivants determinent la maniere dont les processus
18# vont se partager l'execution des sondes
19# num_process   : donne le numero du process
20# nb_process    : donne le nombre total de processus
21
22use strict;
23use warnings;
24use Sys::Syslog;                          # Misses setlogsock.
25use Sys::Syslog qw(:DEFAULT setlogsock);  # Also gets setlogsock
26use Net::SNMP;
27use SNMP_util;
28use Socket;
29use RRDs;
30use DBI;
31use POSIX;
32
33our $group = $ARGV[0];
34our $num_process = $ARGV[1];
35our $nb_process = $ARGV[2];
36
37require "%NMLIBDIR%/libmetro.pl";
38
39# lecture du fichier de configuration general
40our $conf_file = "%CONFFILE%";
41our %global_conf = read_global_conf_file($conf_file);
42
43# check parameters, if one of them emty, set it to default value
44check_params();
45
46our %config = ();
47
48$config{dir_lock}		= $global_conf{metrodatadir} . "/lock" ;
49$config{defaultdomain} 		= $global_conf{defaultdomain};
50$config{syslog_facility} 	= $global_conf{"pollerlogfacility"};
51$config{path_probes} 		= "%NMLIBDIR%/probes";
52$config{path_poll} 		= $global_conf{metrodatadir} . "/poller";
53$config{path_rrd_db} 		= $global_conf{metrodatadir} . "/db";
54$config{path_cache_probes} 	= $global_conf{metrodatadir} . "/cache";
55$config{dir_plugins}		= "%NMLIBDIR%/plugins";
56$config{dir_report}		= $global_conf{metrodatadir} . "/report";
57# recuperation du groupe de pollers
58$config{options} 		= $global_conf{"gpopt_$group"};
59# arguments de connexion a la base PSQL
60$config{PGHOST} 		= $global_conf{macdbhost};
61$config{PGDATABASE} 		= $global_conf{macdbname};
62$config{PGUSER} 		= $global_conf{macdbuser};
63$config{PGPASSWORD} 		= $global_conf{macdbpassword};
64$config{fichier_etat} 		= $global_conf{metrodatadir} . "/wifi/ap_state.txt";
65
66# timeout snmp
67$config{snmp_timeout} 		= $global_conf{snmptimeout};
68
69# liste des sondes
70our %function_probes = (
71		'ifNom-ap'		=> \&ifNom_ap,
72                'ifNom-snmp64'		=> \&ifNom_counter64,
73		'ifNom-broadcast64'	=> \&ifNom_broadcast64,
74		'broadcast'     	=> \&ifNom_broadcast64,
75		'ifNom-multicast64'	=> \&ifNom_multicast64,
76		'multicast'     	=> \&ifNom_multicast64,
77		'ifNom_error'		=> \&ifNom_error,
78                'ifNom-snmp32'		=> \&ifNom_counter32,
79                'ifIP-snmp'		=> \&get_if_by_ip,
80		'get_value_generic'	=> \&get_generic,
81		'plugin'		=> \&get_plugins,
82		'ipmac'			=> \&get_arp_table,
83		'portmac.cisco'		=> \&get_portmac_cisco,
84		'portmac.hp'		=> \&get_portmac_hp,
85		'portmac.juniper'	=> \&get_portmac_juniper
86);
87
88# load all probes
89require $config{path_probes} . "/sensor-if-snmp-ap.pl";
90require $config{path_probes} . "/sensor-if-snmp64.pl";
91require $config{path_probes} . "/sensor-if-snmp32.pl";
92require $config{path_probes} . "/sensor-if-by-ip.pl";
93require $config{path_probes} . "/sensor-generic-gauge.pl";
94require $config{path_probes} . "/sensor-plugins.pl";
95require $config{path_probes} . "/sensor-if-broadcast.pl";
96require $config{path_probes} . "/sensor-if-multicast.pl";
97require $config{path_probes} . "/sensor-if-error.pl";
98require $config{path_probes} . "/sensor-arp-table.pl";
99require $config{path_probes} . "/sensor-portmac.pl";
100
101our $lock_cache_file = 0;
102our $maj_cache_file = 0;
103
104our %collsess;
105our %liste_ap;
106our %liste_ap_state;
107our %ApSnmpHashref = ();
108our %APSupSSID = ();
109our @total_activesess = ();
110our @total_authsess = ();
111our %mac_auth;
112
113our %ok_sondes = ();
114our %nok_sondes = ();
115
116init_test_sondes();
117
118# recuperation de la date et heure de lancement du script
119our %time = get_time("NOW");
120
121# lectures des options passees en parametres
122$ok_sondes{'all'} = 1;
123
124my @liste_options = split(/,/,$config{'options'});
125foreach my $elem (@liste_options)
126{
127    if($elem=~m/^!(.*)/)
128    {
129	$nok_sondes{$1} = 1;
130    }
131    else
132    {
133	$ok_sondes{$elem} = 1;
134	$ok_sondes{'all'} = 0;
135    }
136}
137
138# multiprocessus calcul du resultat du modulo pour matcher une sonde
139our $modulo_match = $num_process % $nb_process;
140
141# Creation d'une socket syslog unix
142setlogsock("unix");
143
144# Message des logs demarrage du d�mon ####################
145writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
146	"\t -> START. Demarrage du polling ########");
147
148
149##################################################################
150# gestion specifique pour les AP WiFi
151# recuperation de la liste des authentifies sur le WiFi
152if($ok_sondes{'assoc_ap'} == 1 && check_periodicity("*/5 * * * *"))
153{
154    writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
155        "\t -> INFO : Recuperation des authentifies du reseau sans fil ...");
156
157    get_authaccess();
158}
159
160#################################################################
161# Traitement des sondes
162#
163opendir(MAJDIR, $config{'path_poll'});
164our @FICHIERS=grep(/(\.sensor|\.plugin)$/, readdir MAJDIR);
165closedir(MAJDIR);
166
167# lecture des fichiers en cache
168our %idxcache;
169
170if(open(CACHE,"$config{path_cache_probes}/idx.cache"))
171{
172	while(my $l=<CACHE>)
173	{
174		chomp $l;
175		if($l =~ /(.+);(.+);(.+)/)
176		{
177			$idxcache{$1}{$2} = $3;
178		}
179	}
180	close(CACHE);
181}
182else
183{
184	writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
185        	"\t -> ERROR : fichier de cache : $!");
186}
187
188read_tab_asso(%idxcache);
189
190
191my $elem;
192my $compteur = 0;
193foreach $elem (@FICHIERS)
194{
195	$compteur += ouvre_fichier_conf($elem);
196}
197
198writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
199        "\t -> $compteur sondes");
200
201Net::SNMP->snmp_dispatcher();
202
203# ecriture des fichiers qui stockent les index snmp des interfaces
204maj_if_files();
205
206########
207
208##################################################################
209# gestion specifique pour les AP WiFi
210if($ok_sondes{'assoc_ap'} == 1 && check_periodicity("*/5 * * * *"))
211{
212    ###################################
213    # cr�ation du tableau d'�tat des AP
214    writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
215        "\t -> Ecriture du fichier de supervision des AP");
216
217    maj_liste_ap_state();
218
219    ################################################################
220    ## mise � jour de la base des associations WiFi
221    writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
222        "\t -> MAJ de la base des associations WIFI");
223
224    set_assoc_ap_base();
225}
226########
227
228
229writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
230                "\t -> STOP. Fin du polling ###############");
231########
232
233
234
235##################################################################
236# FONCTIONS
237##################################################################
238
239##################################################################
240# mise � jour des fichiers contenant les index SNMP des interfaces
241# des �quipements connus
242sub maj_if_files
243{
244	my $i;
245	my @fichier;
246
247	if($maj_cache_file == 1)
248	{
249		if(check_lock_file($config{'dir_lock'},"metropollercache.lock","metropoller") == 0)
250		{
251        		# on locke tant que l'appli tourne
252        		create_lock_file($config{'dir_lock'},"metropollercache.lock","metropoller");
253
254			writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
255                        "\t -> INFO : Mise a jour du fichier de cache");
256
257			open(BD,">$config{path_cache_probes}/idx.cache");
258
259			foreach my $key (keys %idxcache)
260        		{
261                		foreach my $kkey (keys %{$idxcache{$key}})
262                		{
263					my $string = "$key;$kkey;$idxcache{$key}{$kkey}";
264					if($string =~ /(.+);(.+);(.+)/)
265					{
266						print BD "$string\n";
267					}
268                		}
269        		}
270
271			close(BD);
272
273			# suppression du verrou
274        		delete_lock_file("$config{'dir_lock'}/metropollercache.lock");
275        	}
276		else
277		{
278			writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
279                                "\t WARNING fichier de cache locke");
280		}
281	}
282}
283
284
285###############################################################
286# lecture des fichiers contenant les ordres de polling
287sub ouvre_fichier_conf
288{
289	my ($file) = @_;
290	my ($sonde,$base,$host,$community,$l_param,$periodicity);
291	my $ok = 0;
292	my $num_ligne = 0;
293
294	open(FILE, "$config{'path_poll'}/$file");
295
296	#print LOG "fichier : $config{'path_poll'}/$file\n";
297
298	while(<FILE>)
299	{
300		if(! /^#/ && ! /^\s+/)
301		{
302		    chomp;
303		    # detection d'un parametre de periodicite facon cron pour savoir si la sonde doit etre executee
304		    if(/(.*);(.*)/)
305		    {
306			$periodicity = $1;
307			($sonde,$base,$host,$community,$l_param) = (split(/\s+/,$2))[0,1,2,3,4];
308		    }
309		    # aucun parametre de periodicite, la sonde est execute par defaut
310		    else
311		    {
312			$periodicity = "*/5 * * * *";
313		     	($sonde,$base,$host,$community,$l_param) = (split(/\s+/,$_))[0,1,2,3,4];
314		    }
315
316		    $num_ligne ++;
317
318        #print LOG "ligne : $periodicity;$sonde,$base,$host,$community,$l_param\n";
319
320		    # multiprocessus : ce processus doit-il traiter cette ligne?
321		    my $test_modulo = $num_ligne % $nb_process;
322
323		    if($test_modulo == $modulo_match)
324		    {
325			if(check_periodicity($periodicity))
326			{
327				$ok ++;
328				# nettoyage du nom de la sonde
329				$sonde = clean_probe($sonde);
330
331				# parametres a appliquer dans l'appel de chaque fonction
332				# $base,$host,$community,$l_param,$sonde
333				if(defined($function_probes{$sonde}))
334				{
335			    		if(($ok_sondes{'all'} == 1 || $ok_sondes{$sonde} == 1) && $nok_sondes{$sonde} != 1)
336			    		{
337						$function_probes{$sonde}->($base,$host,$community,$l_param,$sonde,$periodicity);
338			    		}
339			    		else
340			    		{
341						$ok --;
342			    		}
343				}
344				else
345				{
346			    		if(($ok_sondes{'all'} == 1 || $ok_sondes{$sonde} == 1) && $nok_sondes{$sonde} != 1)
347                            		{
348						writelog("poller_$group$num_process",$config{'syslog_facility'},"info",
349				    			"\t -> WARNING: Sonde $sonde inexistante");
350						# aucune sonde trouvee, n'a rien fait
351						$ok --;
352			    		}
353				}
354			}
355		    }
356		}
357	}
358	close(FILE);
359
360	return $ok;
361}
362
363
364######################################
365# Nettoie le nom des sondes dans update_rrd qui disposent encore
366# du chemin /local/obj999 ....
367sub clean_probe
368{
369    my ($sonde) = @_;
370
371    my @decomp_rep = split(/\//,$sonde);
372    my $t_decomp_rep = @decomp_rep;
373    ($sonde) = (split(/\.pl/,$decomp_rep[$t_decomp_rep - 1]))[0];
374
375    return $sonde;
376}
377
378
379##########################################################
380# fonction de mise � jour du fichier de supervision des AP
381sub maj_liste_ap_state
382{
383    my $key;
384
385    open(STATE,">$config{'fichier_etat'}");
386    foreach $key (keys %liste_ap_state)
387    {
388	    print STATE "$key=$liste_ap_state{$key}\n";
389    }
390    close(STATE);
391}
392
393
394############################################################
395# initialisation des booleens qui indiquent au programme
396# les types de sondes a executer
397sub init_test_sondes
398{
399    foreach my $key (keys %function_probes)
400    {
401        $ok_sondes{$key} = 0;
402        $nok_sondes{$key} = 0;
403    }
404}
405
406############################################################
407# cree un tableau nominatif avec les index sql des tous les
408# ssid du reseau wifi
409sub init_list_ssid
410{
411    my ($l) = @_;
412
413    my %l_ssid;
414
415    chomp $l;
416    my @ll = split(/,/,$l);
417
418    foreach my $s (@ll)
419    {
420        $l_ssid{$s} = read_conf_file("$conf_file","ID_SQL_$s");
421    }
422
423    return %l_ssid;
424}
425
426############################################################
427# controle le parametre de periodicite du lancement d'une sonde
428# exemple :
429#   */5 * * * * : toutes les 5 minutes
430#   * */1 * * * : toute les heures
431#   sinon renseigner a la maniere de cron :
432#           minute hour    mday    month   wday (1 = lundi)
433# exemple : *      *       *       *       1 : tous les lundi
434#
435# renvoie 1 si la sonde doit etre lancee
436sub check_periodicity
437{
438        my($periodicity) = @_;
439
440	my($mwday,$mmonth,$mmday);
441        #print LOG "$periodicity, time = $time{WDAY}, $time{MON}, $time{MDAY}, $time{HOUR}:$time{MIN}\n";
442
443	my($min,$hour,$mday,$month,$wday) = (split(/\s+/,$periodicity))[0,1,2,3,4];
444
445        if($wday eq "*" || $wday !~/[1-7]/)
446        {
447		$mwday = $wday;
448                $wday = "0,1,2,3,4,5,6";
449        }
450        if($month eq "*" || $month !~/[1-12]/)
451        {
452		$mmonth = $month;
453                $month = "1,2,3,4,5,6,7,8,9,10,11,12";
454        }
455        if($mday eq "*" || $mday !~/[1-31]/)
456        {
457		$mmday = $mday;
458                $mday = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31";
459        }
460        if($min eq "*")
461        {
462		if($mwday =~/[0-6]/ || $mmonth =~/[1-12]/ || $mmday =~/[1-31]/)
463		{
464			$min = 0;
465		}
466		else
467		{
468                	$min = "0-59";
469		}
470        }
471        elsif($min =~/\*\/([0-9]+)/)
472        {
473                my $temp_min ="";
474
475                for(my $i=0;$i<60;$i++)
476                {
477                        my $modulo = $i % $1;
478                        if($modulo == 0)
479                        {
480                                $temp_min = "$temp_min" . "$i,";
481                        }
482                }
483                $min = $temp_min;
484        }
485        if($hour eq "*")
486        {
487		if($mwday =~/[0-6]/ || $mmonth =~/[1-12]/ || $mmday =~/[1-31]/)
488                {
489                        $hour = 0;
490                }
491                else
492                {
493                        $hour = "0-23";
494                }
495        }
496        elsif($hour  =~/\*\/([0-9]+)/)
497        {
498                my $temp = "";
499
500                for(my $i=0;$i<23;$i++)
501                {
502                        my $modulo = $i % $1;
503                        if($modulo == 0)
504                        {
505                                $temp = "$temp" . "$i,";
506                        }
507                }
508                $hour = $temp;
509        }
510
511
512        my $etap_check = 0;
513
514        my @l_wday = split(/,/,$wday);
515        for (my $i=0;$i<@l_wday;$i++)
516        {
517        #	print LOG "WDAY : $l_wday[$i] == $time{WDAY}";
518
519		if($l_wday[$i] == $time{WDAY})
520                {
521                # on est dans le bon jour de la semaine pour executer la sonde
522                        $i = @l_wday;
523                        $etap_check =1;
524                }
525        }
526        if($etap_check == 1)
527        {
528                #print LOG "=> OK\n";
529
530		my @l_month = split(/,/,$month);
531                for (my $i=0;$i<@l_month;$i++)
532                {
533	#	 	print LOG "MON : $l_month[$i] == $time{MON}";
534
535                        if($l_month[$i] == $time{MON})
536                        {
537                        # on est dans le bon mois pour executer la sonde
538                                $i = @l_month;
539                                $etap_check =2;
540                        }
541                }
542        }
543        if($etap_check == 2)
544        {
545		#print LOG "=> OK\n";
546
547                my @l_mday = split(/,/,$mday);
548                for (my $i=0;$i<@l_mday;$i++)
549                {
550			#print LOG "MDAY : $l_mday[$i] == $time{MDAY}";
551
552                        if($l_mday[$i] == $time{MDAY})
553                        {
554                        # on est dans le bon mois pour executer la sonde
555                                $i = @l_mday;
556                                $etap_check =3;
557                        }
558                }
559        }
560        if($etap_check == 3)
561        {
562		#print LOG "=> OK\n";
563
564		if($hour eq "0-23")
565		{
566			$etap_check =4;
567
568			#print LOG "HOUR : $hour == $time{HOUR}";
569		}
570		else
571		{
572               	 	my @l_hour = split(/,/,$hour);
573                	for (my $i=0;$i<@l_hour;$i++)
574                	{
575		#	print LOG "HOUR : $l_hour[$i] == $time{HOUR}";
576
577                        	if($l_hour[$i] == $time{HOUR})
578                        	{
579                        	# on est dans le bon mois pour executer la sonde
580                                	$i = @l_hour;
581                                	$etap_check =4;
582                        	}
583                	}
584		}
585        }
586        if($etap_check == 4)
587        {
588		if($min eq "0-59")
589                {
590			return 1;
591
592			#print LOG "=> OK\n";
593                }
594                else
595                {
596                	my @l_min= split(/,/,$min);
597                	for (my $i=0;$i<@l_min;$i++)
598                	{
599                        	if($l_min[$i] == $time{MIN})
600                        	{
601                        	# on est dans le bon mois pour executer la sonde
602                                	$i = @l_min;
603                                	return 1;
604
605					#print LOG "=> OK\n";
606                        	}
607                	}
608        	}
609	}
610        return 0;
611}
612
613
614# check parameters
615sub check_params
616{
617	if(not defined $group)
618	{
619		$group = "default";
620		print "WARNING : process group not defined, set to default\n";
621	}
622	if(defined $num_process and defined $nb_process and $num_process > $nb_process)
623	{
624		print "ERROR : $num_process > $nb_process. Exit.\n";
625		usage();
626		exit();
627	}
628	if(not defined $num_process)
629	{
630		print "WARNING : process number not defined, set to 1, set number of processes to 1\n";
631		usage();
632		$num_process = 1;
633		$nb_process = 1;
634	}
635	if(not defined $nb_process)
636	{
637		print "WARNING : number of processes not defined, set to 1, set process number to 1\n";
638		usage();
639		$num_process = 1;
640                $nb_process = 1;
641	}
642}
643
644# print usage
645sub usage
646{
647	print "Metropoller
648	###
649	./metropoller <group> <process number> <total number of processes>
650
651	- group : group of sensors. Default value 'default',
652	- process number : process number between 1 and <total number of processes>,
653	- total number of processes : total number of processes.
654	\n";
655}
656