get ("${cacti_url}/data_templates.php?action=template_edit");
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Templates -> \(Edit\)#) {
verbose 0, "Cacti: Failed to go to the data template addition page. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Accessed the page to add a data template:\n" . $mech->response()->decoded_content . "\n\n######################";
###############################################################
my @@dsnames;
@@dsnames = keys %{$data->{perf}}; # Our pefdata labels, which are also internal data source names for Cacti
my $inids = shift @@dsnames;
my @@create_item_regexs;
my $create_item_spec_match;
my %typemap = ( GAUGE => 1, COUNTER => 2, DERIVE => 3, ABSOLUTE => 4 );
{ lock $data->{spec}; lock %{$data->{spec}}; lock %{$data->{spec}->{create_items}};
@@create_item_regexs = keys %{$data->{spec}->{create_items}};
$create_item_spec_match = join "", grep { $inids =~ /^$_$/i } @@create_item_regexs;
lock %{$data->{spec}->{create_items}->{$create_item_spec_match}};
#print "data_source_name => $inids,
#t_rrd_minimum => $data->{spec}->{create_items}->{$create_item_spec_match}->{min},
#t_rrd_maximum => $data->{spec}->{create_items}->{$create_item_spec_match}->{max},
#data_source_type_id => $typemap{$data->{spec}->{create_items}->{$create_item_spec_match}->{type}},\n";
#exit 1;
# In Cacti, we first create an initial data template, with an initial data source name, and then we can add more
$mech->submit_form(
fields => {
template_name => "$cactiserv",
name => "|host_description| - $cactiserv",
active => 'unchecked',
data_source_name => $inids,
rrd_minimum => $data->{spec}->{create_items}->{$create_item_spec_match}->{min},
rrd_maximum => $data->{spec}->{create_items}->{$create_item_spec_match}->{max},
data_source_type_id => $typemap{$data->{spec}->{create_items}->{$create_item_spec_match}->{type}},
},
);
}
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save the new data template \"$serv\" -- \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved the new data template \"$serv\" to ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
#################################################################
# Now we can add additional items to the data template (perfdata labels), if needed
my $dsprev = $inids;
foreach my $nextds (@@dsnames) {
$create_item_spec_match = join "", grep { $nextds =~ /^$_$/i } @@create_item_regexs;
# First we ask to create a new component
$mech -> follow_link (text => 'New');
unless ($mech -> success() && $mech->response()->decoded_content =~ m#\d+: $dsprev#) {
verbose 0, "Cacti: Failed to create new item in the new data template \"$serv\" -- \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Created new component for new data template \"$serv\", ds component \"$nextds\" in ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
##################################################
# Then we save it with necessary parameters
{ lock $data->{spec}; lock %{$data->{spec}}; lock %{$data->{spec}->{create_items}}; lock %{$data->{spec}->{create_items}->{$create_item_spec_match}};
$mech->submit_form(
fields => {
data_source_name => $nextds,
rrd_minimum => $data->{spec}->{create_items}->{$create_item_spec_match}->{min},
rrd_maximum => $data->{spec}->{create_items}->{$create_item_spec_match}->{max},
data_source_type_id => $typemap{$data->{spec}->{create_items}->{$create_item_spec_match}->{type}},
},
);
}
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save the new data template \"$serv\" with new item \"$nextds\" - \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved new component for new data template \"$serv\", ds component \"$nextds\" in ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
$dsprev = $nextds;
}
#push @@data_templates_created, $cactiserv;
my $dt_tmp = get_cacti_data_templates;
%data_templates = %$dt_tmp;
verbose (1, "Cacti: Successfully created a new data template for service \"$cactiserv\"");
return 0; # Successful creation of all components
}
# Check if the graph template exists, and if not, create
sub gt_check_create {
my $data = shift;
my $serv = shift;
my $host = shift;
my ($cactiserv, $uniqname);
$uniqname = unpack ("L", md5(join "", sort keys %{$data->{perf}}));
$cactiserv = "${serv}_${uniqname}";
{ lock $data->{spec}; lock %{$data->{spec}};
# Does the template exist?
#return 0 if grep /^$data->{spec}->{graph_template_name}_${cactiserv}$/i, @@graph_templates;
return 0 if exists $graph_templates{"$data->{spec}->{graph_template_name}_${cactiserv}"};
}
verbose 1, "Cacti: Graph template not found. Will create";
# Access initial page containing the graph templates
$mech->get ("${cacti_url}/graph_templates.php");
unless ($mech -> success() && $mech->title() =~ m#Console -> Graph Templates#) {
verbose 0, "Cacti: Failed to fetch \"${cacti_url}/graph_templates.php\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Query of ${cacti_url}/graph_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
#######################################################
# Add a new one
$mech -> follow_link (text => 'Add');
unless ($mech -> success() && $mech->title() =~ m#Console -> Graph Templates -> \(Edit\)#) {
verbose 0, "Cacti: Failed to follow the \"Add\" link. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Followed the \"Add\" link:\n" . $mech->response()->decoded_content . "\n\n######################";
########################################################
# Next we need to save the new graph template with global graph template data
my ($title, $hgt, $wdt, $t_upper, $t_lower, $t_base, $g_templ_name, $g_templ_label);
{ lock $data->{spec}; lock %{$data->{spec}};
$title = "|host_description| - " . (exists $data->{spec}->{graph_title} ? $data->{spec}->{graph_title} : $serv) . "($uniqname)";
$hgt = exists $data->{spec}->{graph_height} ? $data->{spec}->{graph_height} : 120;
$wdt = exists $data->{spec}->{graph_width} ? $data->{spec}->{graph_width} : 500;
$t_upper = exists $data->{spec}->{graph_upper_limit} ? $data->{spec}->{graph_upper_limit} : 100;
$t_lower = exists $data->{spec}->{graph_lower_limit} ? $data->{spec}->{graph_lower_limit} : 0;
$t_base = exists $data->{spec}->{graph_base} ? $data->{spec}->{graph_base} : 1000;
$g_templ_name = $data->{spec}->{graph_template_name};
# If the desired graph label is the same as the data source item name (for a single DS, we need to get it out)
my ($firstlbl) = keys %{$data->{perf}};
$g_templ_label = $data->{spec}->{graph_label} =~ m#\^item\^#i ? $data->{perf}->{$firstlbl}->[5] : $data->{spec}->{graph_label};
}
#print "$title###$data->{spec}->{graph_label}###\n";
#return 1;
$mech -> submit_form (
fields => {
name => "${g_templ_name}_${cactiserv}",
title => $title,
height => $hgt,
width => $wdt,
upper_limit => $t_upper,
lower_limit => $t_lower,
base_value => $t_base,
vertical_label => $g_templ_label,
},
);
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save the new graph template \"${g_templ_name}_${cactiserv}\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved new graph template \"${g_templ_name}_${cactiserv}\":\n" . $mech->response()->decoded_content . "\n\n######################";
############################################################
# Now we need to add graph components, and associate them with items in the relevant data template
my (@@dsnames, @@graph_item_regexs);
@@dsnames = keys %{$data->{perf}};
{ lock $data->{spec}; lock %{$data->{spec}}; lock %{$data->{spec}->{graph_items}};
@@graph_item_regexs = keys %{$data->{spec}->{graph_items}};
}
my (%data_template_sel, %colors_sel, %function_type_sel, %graph_type_sel, %cdef_sel, %gprint_sel);
my ($data_template_sel_items, $colors_sel_items, $function_type_sel_items, $graph_type_sel_items, $cdef_sel_items, $gprint_sel_items);
# For each data source item
foreach my $curds (@@dsnames) {
my $graph_item_spec_match = join "", grep { $curds =~ /^$_$/i } @@graph_item_regexs;
my @@gr_items;
{ lock $data->{spec}; lock %{$data->{spec}}; lock %{$data->{spec}->{graph_items}}; lock %{$data->{spec}->{graph_items}->{$graph_item_spec_match}};
@@gr_items = @@{$data->{spec}->{graph_items}->{$graph_item_spec_match}};
}
# For each graph component of relevant ds item (line, area, etc)
foreach my $curgritem (@@gr_items) {
$mech -> follow_link (text => 'Add', n => 1);
my $curcont = $mech->response()->decoded_content;
unless ($mech -> success() && $mech->title() =~ m#Console -> Graph Templates -> \(Edit\) -> Graph Template Items#) {
verbose 0, "Cacti: Failed to add a new graph component by following the \"Add\" link. Answer: " . $mech->status();
verbose 2, "Response:\n" . $curcont;
return 1;
}
verbose 2, "Cacti: Followed the \"Add\" link to add a new graph component:\n" . $curcont . "\n\n######################";
# Load a list of data templates
($data_template_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^task_item_id$/,
);
# We only need to determine the list of data templates once
# @@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values if keys %data_template_sel == 0;
#print Dumper (\%data_template_sel);
# We need to determine the relevant data template id to select each time
# We do this, in case the key matched case-insensitive
# my $keytemp = join "", grep m#^${cactiserv}\s+\-\s+\(${curds}\)$#i, keys %data_template_sel;
my $keytemp = get_cacti_data_template_component_id ($cactiserv, $curds);
#verbose 0, Dumper ($keytemp);
unless ($keytemp && @@$keytemp == 1) {
verbose 0, "Cacti: Could not locate the data_template ID for \"$cactiserv\"";
return 1;
}
$keytemp = $keytemp->[0];
#verbose 0, "\n###$keytemp###\n";
#print $data_template_sel{$keytemp}, "\n";
# Select the right data template
# $data_template_sel_items -> value ($data_template_sel{$keytemp});
$data_template_sel_items -> value ($keytemp);
# Load a list of colors
($colors_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^color_id$/,
);
@@colors_sel{$colors_sel_items->value_names} = $colors_sel_items->possible_values if keys %colors_sel == 0;
# Load a list of graph types (AREA, GRPINT, etc)
($graph_type_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^graph_type_id$/,
);
@@graph_type_sel{$graph_type_sel_items->value_names} = $graph_type_sel_items->possible_values if keys %graph_type_sel == 0;
# Load a list of functions (AVERAGE, MIN, MAX)
($function_type_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^consolidation_function_id$/,
);
@@function_type_sel{$function_type_sel_items->value_names} = $function_type_sel_items->possible_values if keys %function_type_sel == 0;
# Load a list of CDEF's
($cdef_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^cdef_id$/,
);
@@cdef_sel{$cdef_sel_items->value_names} = $cdef_sel_items->possible_values if keys %cdef_sel == 0;
# Load a list of GPRINT types
($gprint_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^gprint_id$/,
);
@@gprint_sel{$gprint_sel_items->value_names} = $gprint_sel_items->possible_values if keys %gprint_sel == 0;
my $gritem = join "", keys %{$curgritem}; # AREA, LINE1, GRPINT, etc
# Select the right graph type
$keytemp = join "", grep m#^$gritem$#i, keys %graph_type_sel;
$graph_type_sel_items -> value ($graph_type_sel{$keytemp});
# Function is average for graphical items, and whatever is specified for everything else
my $func = $gritem =~ m#area|stack|line\d+#i ? 'AVERAGE' : $curgritem -> {$gritem} -> {function};
# Select the right function type
$keytemp = join "", grep m#^$func$#i, keys %function_type_sel;
$function_type_sel_items -> value ($function_type_sel{$keytemp});
# Select the right CDEF if necessary
if (exists $curgritem->{$gritem}->{cdef}) {
$keytemp = join "", grep m#^$curgritem->{$gritem}->{cdef}$#i, keys %cdef_sel;
$cdef_sel_items -> value ($cdef_sel{$keytemp});
}
# Select the right GPRINT type if necessary
if (exists $curgritem->{$gritem}->{type}) {
$keytemp = join "", grep m#^$curgritem->{$gritem}->{type}$#i, keys %gprint_sel;
$gprint_sel_items -> value ($gprint_sel{$keytemp});
}
my $text;
$text = $curgritem -> {$gritem} -> {text} =~ m#\^item\^# ? $data->{perf}->{$curds}->[5] : $curgritem -> {$gritem} -> {text};
# Select the right color, or if missing/random - select a random color
exists $curgritem -> {$gritem} -> {color} and do {
$keytemp = join "", grep m#^$curgritem->{$gritem}->{color}$#i, keys %colors_sel;
# Color not found or random color
my @@colorkeys = keys %colors_sel;
while ($keytemp eq 'FFFFFF' || $keytemp eq '') { # White color is ignored
$keytemp = $colorkeys[int (rand (scalar (@@colorkeys)))];
}
$colors_sel_items -> value ($colors_sel{$keytemp});
};
# Hard return checked if this is the last item
#my $hard_return = $gr_items[@@gr_items-1] eq $curgritem ? 'checked' : 'unchecked';
$mech -> field (hard_return => 'on') if ($gr_items[@@gr_items-1] eq $curgritem || exists $curgritem -> {$gritem} -> {eol});
$mech -> submit_form (
fields => {
text_format => $text,
# hard_return => $hard_return,
},
);
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save a new graph item $curds -> $func for new graph template \"$g_templ_name\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved new graph item $curds -> $func for new graph template \"$g_templ_name\":\n" . $mech->response()->decoded_content . "\n\n######################";
}
}
verbose 1, "Cacti: Graph template \"${g_templ_name}_${cactiserv}\" successfully created";
my $gt_tmp = get_cacti_graph_templates;
%graph_templates = %$gt_tmp;
#@@graph_templates = `$php -q ${cacti_path}/cli/add_graphs.php --list-graph-templates`;
#shift @@graph_templates;
#map { chomp; s/^\d+\s+//; } @@graph_templates;
return 0; # Successful creation of all components
}
# Check if the data source exists, and if not, create
sub ds_check_create {
my $data = shift;
my $serv = shift;
my $host = shift;
my $cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
return 0 if (get_cacti_host_template_ds ($host, $cactiserv));
#if (get_cacti_host_template_ds ($host, $cactiserv)) {
#verbose 1, "Data source already exists for host \"$host\" and service \"$cactiserv\"";
#return 0;
#}
# If we have the data source on record, don't waste time
# return 0 if exists $data_source_created{$cactiserv} && grep m#^$host$#i, @@{$data_source_created{$cactiserv}};
# First see if the data sources already exist
# Get the page with data sources
# $mech -> get ("${cacti_url}/data_sources.php");
# unless ($mech -> success() && $mech->title() =~ m#Console -> Data Sources#) {
# verbose 0, "Cacti: Failed to fetch \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
# verbose 2, "Response:\n" . $mech->response()->decoded_content;
# return 1;
# }
# verbose 2, "Cacti: Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
##################################################
my (%data_template_sel, %host_sel);
my ($data_template_sel_items, $host_sel_items);
# Load a list of data templates
# ($data_template_sel_items) = $mech -> find_all_inputs (
# type => 'option',
# name_regex => qr/^template_id$/,
# );
# @@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values;
# Locate the needed data template in the list, and select it
# my $servkey = join "", grep m#^$cactiserv$#i, keys %data_template_sel;
# my $hostkey;
# if (exists $data_template_sel{$servkey}) { # No hosts with the template???
# $data_template_sel_items -> value ($data_template_sel{$servkey});
####################
# Load a list of hosts
# ($host_sel_items) = $mech -> find_all_inputs (
# type => 'option',
# name_regex => qr/^host_id$/,
# );
# @@host_sel{$host_sel_items->value_names} = $host_sel_items->possible_values;
# Locate the needed host in the list, and select it
# $hostkey = join "", grep m#^$host #i, keys %host_sel;
# $hostkey = join "", grep m# \(${host}\.#i, keys %host_sel if $hostkey eq '';
# if (exists $host_sel{$hostkey}) {
# $host_sel_items -> value ($host_sel{$hostkey});
###################
# Now search for it
# $mech -> submit_form (
# form_name => 'form_data_sources',
# );
# unless ($mech -> success() && $mech->title() =~ m#Console -> Data Sources#) {
# verbose 0, "Cacti: Failed to search \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
# verbose 2, "Response:\n" . $mech->response()->decoded_content;
# return 1;
# }
# verbose 2, "Cacti: Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
# Data source exists?
# return 0 if $mech->response()->decoded_content !~ m#No Data Sources#;
# }
# }
########################################################
verbose 1, "Cacti: Data source not found for host \"$host\" and service \"$cactiserv\". Will create";
# Add a new data source
# $mech->follow_link (text => 'Add');
$mech -> get ("${cacti_url}/data_sources.php?action=ds_edit&host_id=-1");
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Sources -> \(Edit\)#) {
verbose 0, "Cacti: Failed to add a new data source by following the \"Add\" link. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Followed the \"Add\" link to add a new data source:\n" . $mech->response()->decoded_content . "\n\n######################";
########################################################
### We reload the lists because these are OBJECTS specific to the current page of $mech
# Load a list of data templates
($data_template_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^data_template_id$/,
);
# @@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values;
# Locate the needed data template in the list, and select it
# $servkey = join "", grep m#^$cactiserv$#i, keys %data_template_sel;
# $data_template_sel_items -> value ($data_template_sel{$servkey});
$data_template_sel_items -> value ($data_templates{$cactiserv});
# Load a list of hosts
($host_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^host_id$/,
);
@@host_sel{$host_sel_items->value_names} = $host_sel_items->possible_values;
# Locate the needed host in the list, and select it
my $hostkey = join "", grep m#^$host #i, keys %host_sel;
$hostkey = join "", grep m# \(${host}\.#i, keys %host_sel if $hostkey eq '';
$host_sel_items -> value ($host_sel{$hostkey});
# Save the new data source with selected host and data template
$mech -> submit_form;
unless ($mech -> success()) {
verbose 0, "Cacti: Failed to create a new data source by associating a host with data template. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Created a new data source:\n" . $mech->response()->decoded_content . "\n\n######################";
#####################################################################
# Need to save another page having a path to the RRD file
$mech -> submit_form (
fields => {
data_source_path => "${rrapath}/${host}_${serv}.rrd",
},
);
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save a new data source for template \"$cactiserv\" and host \"$host\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
# $data_source_created{$cactiserv} = [] unless exists $data_source_created{$cactiserv};
# push @@{$data_source_created{$cactiserv}}, $host;
verbose 2, "Cacti: Saved a new data source for template \"$cactiserv\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
verbose 1, "Cacti: Successfully created a new data source for host \"$host\" and service \"$cactiserv\"";
return 0; # Successful creation of a new data source
}
# Check if the graph exists, and if not, create
sub g_check_create {
my $data = shift;
my $serv = shift;
my $host = shift;
my ($cactiserv, $uniqname);
$uniqname = unpack ("L", md5(join "", sort keys %{$data->{perf}}));
$cactiserv = "${serv}_${uniqname}";
my (%graph_template_sel, %host_sel);
my ($graph_template_sel_items, $host_sel_items, $g_templ_title);
my $hst = join "", grep m#^${host}(|\.princeton\.edu)$#i, keys %cacti_hosts; # look up hostname
#$hst = grep m#^${host}$#i, keys %cacti_hosts if $hst eq ''; # look up description (might be different)
#return 1 unless exists $cacti_hosts{$hst}; # Host could not be located in Cacti for some reason (unprobable since this was already checked)
return 1 unless $hst; # Host could not be located in Cacti for some reason (unprobable since this was already checked)
my $host_ds_comp = get_cacti_host_ds_components $host;
#my @@host_graphs = `$php ${cacti_path}/cli/add_tree.php --list-graphs --host-id=$cacti_hosts{$hst}`;
my $hst_grphs = get_cacti_graph $host;
# Does the graph exist for the host?
{ lock %{$data->{spec}};
$g_templ_title = exists $data->{spec}->{graph_title} ? $data->{spec}->{graph_title} : $serv;
#if (grep m#^\d+\s+\S+\s+\-\s+$g_templ_title\($uniqname\)\s+#i, @@host_graphs) {
if (exists $hst_grphs->{"${host} - ${g_templ_title}(${uniqname})"}) {
verbose 1, "Cacti: Graph exists for host \"$host\" and service \"$serv\"";
return 0;
}
}
verbose 1, "Cacti: Graph for host \"$host\" and service \"$serv\" could not be located. Will create";
$mech -> get ("${cacti_url}/graphs.php?action=graph_edit&host_id=-1");
unless ($mech -> success() && $mech->title() =~ m#Console -> Graph Management -> \(Edit\)#) {
verbose 0, "Cacti: Failed to add a new graph for template \"$cactiserv\" and host \"$host\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Created a new graph for template \"$cactiserv\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
##################################################
# Load a list of graph templates
($graph_template_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^graph_template_id$/,
);
# @@graph_template_sel{$graph_template_sel_items->value_names} = $graph_template_sel_items->possible_values;
# Locate the needed graph template in the list, and select it
my ($graphkey, $g_templ_name);
{ lock %{$data->{spec}};
$g_templ_name = $data->{spec}->{graph_template_name} . "_$cactiserv";
$graphkey = $graph_templates{$g_templ_name};
#$graphkey = join "", grep m#^${g_templ_name}$#i, keys %graph_template_sel;
}
#$graph_template_sel_items -> value ($graph_template_sel{$graphkey});
$graph_template_sel_items -> value ($graphkey);
####################
# Load a list of hosts
($host_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^host_id$/,
);
# @@host_sel{$host_sel_items->value_names} = $host_sel_items->possible_values;
# Locate the needed host in the list, and select it
# my $hostkey = join "", grep m#^$host #i, keys %host_sel;
# $hostkey = join "", grep m# \(${host}\.princeton\.edu\)#i, keys %host_sel if $hostkey eq '';
# $host_sel_items -> value ($host_sel{$hostkey});
$host_sel_items -> value ($cacti_hosts{$host});
# This is done solely to get the name of the host if the description differs from the hostname
# $hostkey =~ m#^(\S+)#;
# my $hostkey_temp = $1;
###################
# Save
$mech -> submit_form;
#unless ($mech -> success() && $mech->response()->decoded_content =~ m#${hostkey_temp} \- ${g_templ_title}\(${uniqname}\)#) {
unless ($mech -> success() && $mech->response()->decoded_content =~ m#${host} \- ${g_templ_title}\(${uniqname}\)#) {
verbose 0, "Cacti: Failed to save the new graph for graph template \"${g_templ_title}(${uniqname})\" and host \"$host\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved the new graph for graph template \"${g_templ_title}(${uniqname})\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
##########################################################
# Now let's select (map) the relevant data sources to data template items of the graph
my $curcont = join "", $mech -> response() -> decoded_content;
my $ds_sel_items;
my %ds_sel;
#
#
#Data Source [home]
while ($curcont =~ m# |
]+>Data Source \[([^\]]+)\]
#mg) {
my ($item_id, $found_ds_name) = ($1, $2);
($ds_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^task_item_id_${item_id}$/,
);
#@@ds_sel{$ds_sel_items->value_names} = $ds_sel_items->possible_values;
#my $dskey = join "", grep m#^${host} \- ${cactiserv} \($found_ds_name\)$#i, keys %ds_sel;
#$ds_sel_items -> value ($ds_sel{$dskey});
$ds_sel_items -> value ($host_ds_comp->{"${host} - ${cactiserv}(${found_ds_name})"});
}
$mech -> submit_form;
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Save Successful#) {
verbose 0, "Cacti: Failed to save the components of the new graph for graph template \"${g_templ_name}_${cactiserv}\" and host \"$host\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Saved the components of the new graph for graph template \"${g_templ_name}_${cactiserv}\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
verbose 1, "Cacti: Successfully created a graph for host \"$host\"";
return 0; # Graph creation successful
}
sub begin {
# If we are not outputting to STDOUT, then we daemonize
if ($outtype eq 'log') {
my $pid;
use POSIX qw(setsid);
chdir '/';
open STDIN, '/dev/null' or die "Cannot read \"/dev/null\"";
open STDOUT, '>> /dev/null' or die "Cannot write to \"/dev/null\"";
open STDERR, '>> /dev/null' or die "Cannot write to \"/dev/null\"";
defined ($pid = fork) or die "Cannot fork: $!";
exit 0 if $pid;
POSIX::setsid or die "Cannot start a new session";
$SIG{PIPE} = 'ignore';
$pidfile = File::Pid -> new ({file => $pidpath,});
$pidfile -> write or die "Cannot write PID file: $!";
}
$SIG{HUP} = \&reload; # SIGHUP causes configuration re-read
$SIG{TERM} = \&end_program; # SIGTERM causes graceful termination
$SIG{INT} = \&end_program; # CTRL+C causes graceful termination
my $descr = load;
# Nagios pipe read
read_perfdata $descr->[0], $descr->[1];
$pidfile -> remove if $outtype eq 'log';
}
# This routine does things that might later be reloaded on request
sub load {
$pnag = Thread::Queue -> new;
$pnagcac = Thread::Queue -> new;
if ($outtype eq 'log') {
open LOG, ">> $log_file" or die "Cannot open logfile \"$log_file\"";
}
verbose 0, "###### Program Started ###########\n";
# Load performance history
open PERS, "< $persistence_file" and do {
foreach () {
chomp;
my ($hst, $svc) = split /::::/;
$perfhist{$hst} = &share ({}) unless exists $perfhist{$hst};
$perfhist{$hst}->{$svc} = 2;
}
close PERS;
};
read_config;
my $rrd_thr = threads -> new (\&update_rrd);
$rrd_thr -> detach;
my $cac_thr = threads -> new (\&cacti_update);
$cac_thr -> detach;
return [ $rrd_thr, $cac_thr ];
}
# This routine terminates things that might then be reloaded, or the program can be terminated
sub unload {
lock $waiton and $waiton = 0;
# Clear performance history
foreach (keys %perfhist) {
delete $perfhist{$_};
}
%perfhist = ();
verbose 0, "########## Program terminated ##########";
close LOG;
# This is a way to execute various external tasks before final termination, or reload
# Things such as cleanup, and log rotation should go in this file
open POSTTASKS, "< $close_file" and do {
foreach () {
chomp;
`$_`;
}
close POSTTASKS;
};
}
sub read_config {
#sleep 20;
lock %spec;
%spec = ();
#@@graph_templates = `$php -q ${cacti_path}/cli/add_graphs.php --list-graph-templates`;
#shift @@graph_templates;
#map { chomp; s/^\d+\s+//; } @@graph_templates;
#my @@cac_hosts = `$php -q ${cacti_path}/cli/add_graphs.php --list-hosts`;
#foreach (@@cac_hosts) { /^(\d+)\s+(\S+)\s+(.*)/ and do { $cacti_hosts{$2} = $1; $cacti_hosts{$3} = $1; }; }
open SPECFILE, "< $spec_file" or graceful_die (1, 1, "Unable to open the service spec file!!!\n");
my @@speclines = ;
close SPECFILE;
verbose 1, "---- Reading RRD specification ----";
my ($curservreg, $curhostreg, $graphspec, $itemspec, $itemspec2, $createitem, $createitemspec);
foreach (@@speclines) {
chomp;
next if /^\s*(#|$)/;
# Beginning of a new spec definition, along with a unique service regex
/^\s*service_regex\s+(\S+)\s+{\s*$/ and do {
undef $curservreg;
undef $curhostreg;
undef $graphspec;
($curservreg, $curhostreg) = ($1, '^self^'); # By default we assume that there's a graph for each individual host
$spec{$curservreg} = &share ({});
$spec{$curservreg} -> {$curhostreg} = &share ({});
next;
};
next unless defined $curservreg;
# Line that defines a host regex to match for hosts. If this occurs, we remove the previously assumed ^self^
/^\s*host_regex:\s+(.*)$/ and do {
delete $spec{$curservreg} -> {$curhostreg};
$curhostreg = $1;
$spec{$curservreg} -> {$curhostreg} = {};
next;
};
# Beginning of a block defining RRD creation
/^\s*create_items\s*{/ and do {
$createitem = 1;
$spec{$curservreg} -> {$curhostreg} -> {create_items} = &share ({});
next;
};
# Beginning of a block defining Cacti graph template creation
/^\s*graph_items\s*{/ and do {
$graphspec = 1;
$spec{$curservreg} -> {$curhostreg} -> {graph_items} = &share ({});
next;
};
# Item related to the general Cacti graph template definition
/^\s*graph_([^:]+):\s+(.*)/ and do {
my $grphprop = "graph_$1";
$spec{$curservreg} -> {$curhostreg} -> {$grphprop} = $2;
next;
};
# Data source item names that need mapping (illegal chars?)
/^\s*map_items:\s*(.*)/ and do {
my $itmap = $1;
$spec{$curservreg} -> {$curhostreg} -> {map_items} = &share ({});
%{$spec{$curservreg} -> {$curhostreg} -> {map_items}} = split /\s*=>\s*/, $itmap;
};
# Data source items to be ignored (not graphs)
/^\s*ignore_items:\s*(.*)/ and do {
$spec{$curservreg} -> {$curhostreg} -> {ignore_items} = &share ([]);
@@{$spec{$curservreg} -> {$curhostreg} -> {ignore_items}} = split /\s*,\s*/, $1;
};
# Item defining an RRD label to match
$createitem && /^\s*(\S+)\s+{/ and do {
$createitemspec = $1;
$spec{$curservreg} -> {$curhostreg} -> {create_items} -> {$1} = &share ({});
next;
};
# Item defining a data source to match
$graphspec && /^\s*(\S+)\s+{/ and do {
# Different graph items using the matched data source, such as AREA or GPRINT
$itemspec and do {
$itemspec2 = $1;
push @@{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}}, &share ({});
$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}[@@{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}} - 1] -> {$itemspec2} = &share ({});
#print "def itemspec2 => $itemspec2\n";
next;
};
$itemspec = $1;
$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec} = &share ([]);
#print "def itemspec => $itemspec\n";
next;
};
# Record current RRD label property
$createitemspec && /^\s*([^:]+):\s*(.*)/ and do {
$spec{$curservreg} -> {$curhostreg} -> {create_items} -> {$createitemspec} -> {$1} = $2;
};
# Record current Graph item property
$itemspec2 && /^\s*([^:]+):\s*(.*)/ and do {
$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}[@@{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}} - 1] -> {$itemspec2} -> {$1} = $2;
};
# End of some block
/^\s*}/ and do {
$createitem and do {
$createitemspec and do {
undef $createitemspec;
next;
};
undef $createitem;
};
$graphspec and do {
$itemspec and do {
$itemspec2 and do {
#print "undef itemspec2 => $itemspec2\n";
undef $itemspec2;
next;
};
#print "undef itemspec => $itemspec\n";
undef $itemspec;
next;
};
#print "undef graphspec\n";
undef $graphspec;
};
next;
};
}
#print Dumper (\%spec);
#exit 1;
}
# The following will continuously read the perfdata Nagios pipe
sub read_perfdata {
my ($rrd_thr, $cac_thr) = @@_;
#$LASTSERVICECHECK$\t$HOSTNAME$\t$SERVICEDESC$\t$SERVICEOUTPUT$\t$SERVICEPERFDATA$
open PERFDATA, "< $perf_file" or graceful_die (0, 1, "Unable to open the perfdata file \"$perf_file\"!!!");
verbose (1, "Performance data pipe \"$perf_file\" successfully opened for reading");
# The following should loop forever, since we're reading from a pipe
# Termination should be done by a signal, such as SIGTERM
# Each line contains perfdata info for a host/service
while () {
chomp;
verbose (4, "Perfdata line read: #$_#\n");
$pnag -> enqueue ("$_");
# If we've been commanded to finish
last if (lock $terminate && $terminate);
if (lock $waiton && $waiton) {
if ($waiton == 1) {
#$pnag -> insert (0, "Reload");
#$pnagcac -> insert (0, "Reload");
$pnag -> enqueue ("Reload");
$pnagcac -> enqueue ("Reload");
$waiton = 2;
}
if ($rrd_thr -> is_running || $cac_thr -> is_running) { verbose 1, "Waiting for the threads to complete..."; next; }
unload;
my $descr = load;
($rrd_thr, $cac_thr) = @@$descr;
}
}
close PERFDATA;
verbose (1, "Performance data pipe \"$perf_file\" closed");
#sleep 60;
#$pnag -> insert (0, "Terminate");
#$pnagcac -> insert (0, "Terminate");
$pnag -> enqueue ("Terminate");
$pnagcac -> enqueue ("Terminate");
# If one of the threads is still running, just display a message
while ($rrd_thr -> is_running || $cac_thr -> is_running) { verbose 1, "Waiting for the threads to complete..."; sleep 3; }
unload;
}
sub update_rrd {
my %perfdata;
my $rrd_thr_wait = 0;
verbose (1, "------ Update RRD thread started ------");
while ( $_ = $pnag -> dequeue ) {
verbose (4, "Update RRD dequeued: ##$_##");
last if /^(Terminate|Reload)$/;
my ($tm, $hst, $svc, $svcout, $svcperf) = split /\t/;
next unless defined $tm && defined $hst && defined $svc && defined $svcout && defined $svcperf;
#$svcperf = $svcout if not defined $svcperf || $svcperf eq ''; ##### need to put in possibility of regex parsing the output if needed. This will require some regex matching in create_ spec
verbose (3, "Perfdata line parsed: ####$_#####$tm###$svc###$hst###$svcout###$svcperf###");
# This skips perfdata lines not matching the spec - don't care about these
lock %spec;
next if $svcperf =~ /^\s*$/
|| ! grep ($svc =~ m#$_#i, keys %spec)
|| ! grep { my $svtmp = $_; lock %{$spec{$svtmp}}; $svc =~ m#$svtmp#i and do {
grep { $hst =~ m#$_#i || $_ eq '^self^' } keys %{$spec{$svtmp}}
};
} keys %spec;
$svc =~ s/\s+/_/g;
# change to 2 later!!!
verbose (1, "Perfdata line matching spec: ###$svc###$hst###$svcout###$svcperf###; Queue size: " . $pnag->pending);
$perfdata{$hst} = {} unless exists $perfdata{$hst};
$perfdata{$hst}->{$svc} = {} unless exists $perfdata{$hst}->{$svc};
my $curperf = $perfdata{$hst}->{$svc};
$curperf->{perf} = {};
$curperf->{time} = $tm;
# Each perfdata line might carry perf output (separated by space) for several items that we need to parse
# 'label'=value[UOM];[warn];[crit];[min];[max] -- per rrdtool docs, label should be [a-zA-Z0-9_]+, 1-19chars long
foreach my $nextperf (split /\s+/, $svcperf) {
#print "#####$nextperf####\n";
my ($lbl, $rest) = split /=/, $nextperf;
next unless defined $rest;
$lbl =~ s/'//g; # We don't need the single quotes anyhow
my $graphlabel = $lbl;
$lbl =~ s/[^a-zA-Z0-9_]//g;
$lbl = substr $lbl, 0, 19;
my ($val, $wrn, $crt, $min, $max) = split /;/, $rest;
$val =~ s/[^0-9\.\-]//g;
$curperf->{perf}->{$lbl} = [];
push @@{$curperf->{perf}->{$lbl}}, $val, $wrn, $crt, $min, $max, $graphlabel;
# change to 2 later!!!
verbose (2, "Perfdata deciphered: ###$val###$graphlabel###");
}
# Link the relevant part of the spec hash to the %perfdata for further use
# For every service specification, remove ignored items, and map items to map
#lock %spec;
foreach my $svcspec (keys %spec) {
next unless $svc =~ m#${svcspec}#;
lock %{$spec{$svcspec}};
# For every host specification
foreach my $hostspec (keys %{$spec{$svcspec}}) {
next unless ($hst =~ /^${hostspec}$/i || $hostspec eq '^self^');
lock %{$spec{$svcspec}->{$hostspec}};
my $curspec :shared = $spec{$svcspec}->{$hostspec};
$curperf->{spec} = $curspec;
# Remove perfdata DS's from the ignore map
exists $curspec->{ignore_items} and do {
lock @@{$curspec->{ignore_items}};
foreach (@@{$curspec->{ignore_items}}) {
next unless exists $curperf->{perf}->{$_};
#print Dumper ($curperf->{perf}->{$_});
delete $curperf->{perf}->{$_};
}
};
# Map DS names if needed
exists $curspec->{map_items} and do {
lock %{$curspec->{map_items}};
foreach (keys %{$curspec->{map_items}}) {
next unless exists $curperf->{perf}->{$_};
$curperf->{perf}->{$curspec->{map_items}->{$_}} = $curperf->{perf}->{$_};
delete $curperf->{perf}->{$_};
}
};
# This service is probably useless, since it yields no stats that we want to graph according to the spec
if (keys %{$curperf->{perf}} == 0) {
delete $curperf->{perf};
delete $perfdata{$hst}->{$svc};
delete $perfdata{$hst} unless keys %{$perfdata{$hst}} > 0;
}
#/maestro=2196MB;2406;2706;0;3007
#/cognos/iowa=68% /cognos/ohio=53%
#/usr/local/groundwork/common/bin/rrdtool create \
#/var/local/cacti-0.8.7h/rra/sdpadfs300w_avgdiskreadpersec_9866.rrd \
#--step 300 \
#DS:AvgDiskWriteQueueLe:GAUGE:600:0:100 \
#DS:AvgDiskReadQueueLen:GAUGE:600:0:100 \
#DS:PercentFreeSpace:GAUGE:600:0:100 \
#DS:PercentDiskWriteTim:GAUGE:600:0:100 \
#DS:PercentDiskReadTime:GAUGE:600:0:100 \
#DS:AvgDiskReadPerSec:GAUGE:600:0:U \
#DS:AvgDiskWritePerSec:GAUGE:600:0:U \
#DS:FreeMegabytes:GAUGE:600:0:U \
#RRA:AVERAGE:0.5:1:500 \
#RRA:AVERAGE:0.5:1:600 \
#RRA:AVERAGE:0.5:6:700 \
#RRA:AVERAGE:0.5:24:775 \
#RRA:AVERAGE:0.5:288:797 \
#RRA:MAX:0.5:1:500 \
#RRA:MAX:0.5:1:600 \
#RRA:MAX:0.5:6:700 \
#RRA:MAX:0.5:24:775 \
#RRA:MAX:0.5:288:797 \
#
# rrdcreate?
# rrdtool create filename [--start|-b start time] [--step|-s step] [--no-overwrite] [DS:ds-name:DST:dst arguments] [RRA:CF:cf arguments]
# If the RRD data file for the current data set does not exist, create it
if (! -f "${rrapath}/${hst}_${svc}.rrd") {
#print "###", keys %{$perfdata{$hst}->{$svc}}, "###\n";
lock %{$curspec->{create_items}};
my @@create_item_regexs = keys %{$curspec->{create_items}};
my $ds_create_spec = '';
foreach my $dsitem (keys %{$curperf->{perf}}) {
my $create_item_spec_match = join "", grep { $dsitem =~ /^$_$/i } @@create_item_regexs;
lock %{$curspec->{create_items}->{$create_item_spec_match}};
$ds_create_spec .= ($create_item_spec_match eq '') ?
"DS:$dsitem:$curspec->{create_items}->{$create_item_spec_match}->{type}:600:$curspec->{create_items}->{$create_item_spec_match}->{min}:$curspec->{create_items}->{$create_item_spec_match}->{max} " :
"DS:$dsitem:GAUGE:600:0:U ";
}
#print "####$ds_create_spec####\n";
chomp $ds_create_spec;
my @@rrdout = `$rrdtool create ${rrapath}/${hst}_${svc}.rrd --step 300 $ds_create_spec $rracacspec 2>&1`;
verbose (1, "Create RRD: $rrdtool create ${rrapath}/${hst}_${svc}.rrd --step 300 $ds_create_spec $rracacspec\nResponse: " . join ("\n", @@rrdout));
}
# rrdupdate
# rrdtool {update | updatev} filename [--template|-t ds-name[:ds-name]...] [--daemon address] [--] N|timestamp:value[:value...] at-timestamp@@value[:value...] [timestamp:value[:value...] ...]
my $valsupdate = join ":", (map { $curperf->{perf}->{$_}->[0]; } keys %{$curperf->{perf}});
my @@rrdout = `$rrdtool update ${rrapath}/${hst}_${svc}.rrd $curperf->{time}:$valsupdate 2>&1`;
verbose (1, "Update RRD: $rrdtool update ${rrapath}/${hst}_${svc}.rrd $curperf->{time}:$valsupdate\nResponse: " . join ("\n", @@rrdout));
#next;
# Record processed data
# 0 - initial unprocessed, 1 - error, try again, 2 - successfully processed previously
lock %perfhist;
$perfhist{$hst} = &share ({}) unless exists $perfhist{$hst};
lock %{$perfhist{$hst}};
unless (exists $perfhist{$hst}->{$svc} && $perfhist{$hst}->{$svc} != 1) {
$perfhist{$hst}->{$svc} = 0; # Initially mark it as unprocessed by Cacti
$pnagcac -> enqueue ("Next service");
$pnagcac -> enqueue ("Host: ${hst}");
$pnagcac -> enqueue ("Service: ${svc}");
$pnagcac -> enqueue ("Host Spec: ${hostspec}");
$pnagcac -> enqueue ("Service Spec: ${svcspec}");
foreach my $lbl (keys %{$curperf->{perf}}) {
$pnagcac -> enqueue ("Perf: $lbl");
$pnagcac -> enqueue (join "::: ", grep { defined $_ ? $_ : ""; } @@{$curperf->{perf}->{$lbl}});
}
$pnagcac -> enqueue ("End service");
}
} # End foreach hostspec
} # End foreach svcspec
} # End while (1)
verbose 1, "Pending queue items: " . $pnag->pending();
verbose (1, "------ Update RRD thread terminated ------");
return 0;
}
sub verbose {
my $level = shift;
my $string = shift;
# print STDERR "### ", $string, "\n" if $verbose && $verbose >= $level;
if ($outtype eq 'log') {
my $dt = `date +"%a %b %d %T"`; chomp $dt;
print LOG "$dt => $string", "\n" if $verbose && $verbose >= $level;
} elsif ($outtype eq 'stderr') {
print STDERR "### ", $string, "\n" if $verbose && $verbose >= $level;
}
}
sub graceful_die {
my $immediate = shift;
my $state = shift;
my $str = shift;
verbose 0, $str if $str && $str ne '';
if ($immediate) {
if ($outtype eq 'log') {
close LOG;
$pidfile -> remove;
}
exit $state;
} else {
lock $terminate;
$terminate = 1;
}
}
sub reload {
verbose (0, "SIGHUP caught. Reloading configuration");
lock $waiton;
$waiton = 1 unless $waiton; # If waiton is already non-zero - we're in the process of reloading, so DND
}
sub end_program {
verbose (0, "Program terminate requested by user");
lock $terminate;
$terminate = 1;
}
# Args: cols, tables, conditions
sub DB_get {
my $colnames_p = shift;
my @@colnames = split /\s*,\s*/, $colnames_p;
my $tblnames_p = shift;
my @@tblnames = split /\s*,\s*/, $tblnames_p;
my $cond_p = shift;
my %res;
my $query = "SELECT $colnames_p FROM $tblnames_p";
$query .= " WHERE $cond_p" if $cond_p;
verbose 1, "###$query###";
my $sth = $cacdb -> prepare ($query);
graceful_die 1, 1, "Error initializing DB query \"$query\". Received: " . $cacdb->errstr unless $sth;
#verbose 0, "\n###$query prepared\n";
my $ref;
graceful_die 1, 1, "Error executing DB query \"$query\". Received: " . $cacdb->errstr unless $sth -> execute;
#verbose 0, "\n###$query executed\n";
while ($ref = $sth->fetchrow_hashref()) {
#verbose 0, (Dumper ($ref));
#verbose 0, "#########Next row\n";
foreach (@@colnames) {
s#.*\.##;
#verbose 0, "#########$_##\n";
# $res{"$_"} = [] unless exists $res{"$_"};
# push @@{$res{"$_"}}, $ref -> {"$_"};
push @@{$res{$_}||=[]}, $ref->{$_};
#verbose 0, "####" . $ref -> {"$_"} . "####\n";
}
}
#verbose 0, Dumper (\%res);
#verbose 0, "#######Done\n";
$sth -> finish;
return \%res;
}
sub get_cacti_data_templates {
my $res = DB_get ("id, name", "data_template");
return undef unless keys %$res > 0;
my %res2;
#print Dumper ($res);
for (my $ctr = 0; $ctr < @@{$res->{name}}; $ctr++) {
$res2{$res->{name}->[$ctr]} = $res->{id}->[$ctr];
}
return \%res2;
}
sub get_cacti_data_template_component_id {
my $templ_name = shift;
my $comp_name = shift;
#select data_template_rrd.id, data_template.name, data_template_rrd.data_source_name from data_template,data_template_data,data_template_rrd where data_template_rrd.data_template_id=data_template.id and data_template_data.data_template_id=data_template.id and data_template_data.local_data_id=0 and data_template_rrd.local_data_id=0;
my $res = DB_get ("data_template_rrd.id", "data_template, data_template_data, data_template_rrd", "data_template_rrd.data_template_id=data_template.id AND data_template_data.data_template_id=data_template.id AND data_template_data.local_data_id='0' AND data_template_rrd.local_data_id='0' AND data_template.name='" . $templ_name . "' AND data_template_rrd.data_source_name='" . $comp_name . "'");
return keys %$res == 1 ? $res -> {id} : undef;
}
#sub get_cacti_data_sources {
# my $res = DB_get ("id, name", "graph_templates");
# return undef unless keys %$res > 0;
# my %res2;
#print Dumper ($res);
# for (my $ctr = 0; $ctr < @@{$res->{name}}; $ctr++) {
# $res2{$res->{name}->[$ctr]} = $res->{id}->[$ctr];
# }
# return \%res2;
#}
sub get_cacti_host_template_ds {
my $host_name = shift;
my $templ_name = shift;
my $res = DB_get ("data_template_data.local_data_id", "data_local, data_template_data", "data_local.id=data_template_data.local_data_id AND data_local.host_id='" . $cacti_hosts{$host_name} . "' AND data_template_data.data_template_id='" . $data_templates{$templ_name} . "'");
return keys %$res == 1 ? $res->{local_data_id} : undef;
}
sub get_cacti_host_ds_components {
my $host_name = shift;
my $res = DB_get ("data_template_rrd.id, data_source_name, name_cache", "data_template_data, data_template_rrd, data_local", "host_id='" . $cacti_hosts{$host_name} . "' and data_template_rrd.local_data_id=data_local.id and data_local.id=data_template_data.local_data_id");
return undef unless keys %$res > 0;
my %res2;
#print Dumper ($res);
for (my $ctr = 0; $ctr < @@{$res->{id}}; $ctr++) {
$res2{"$res->{name_cache}->[$ctr]" . "($res->{data_source_name}->[$ctr])"} = $res->{id}->[$ctr];
}
return \%res2;
}
sub get_cacti_graph_templates {
my $res = DB_get ("id, name", "graph_templates");
return undef unless keys %$res > 0;
my %res2;
#print Dumper ($res);
for (my $ctr = 0; $ctr < @@{$res->{name}}; $ctr++) {
$res2{$res->{name}->[$ctr]} = $res->{id}->[$ctr];
}
return \%res2;
}
sub get_cacti_graph_template_component {
my $templ_name = shift;
my $res = DB_get ("name", "graph_template_input", "graph_template_id='" . $graph_templates{$templ_name} . "'");
return keys %$res == 0 ? undef : $res->{name}->[0];
}
sub get_cacti_graph {
my $host_name = shift;
my $res = DB_get ("graph_templates_graph.local_graph_id, graph_templates_graph.title_cache", "graph_local, graph_templates_graph", "graph_local.id=graph_templates_graph.local_graph_id AND graph_local.host_id='" . $cacti_hosts{$host_name} . "'");
my %res2;
#print Dumper ($res);
for (my $ctr = 0; $ctr < @@{$res->{local_graph_id}}; $ctr++) {
$res2{$res->{title_cache}->[$ctr]} = $res->{local_graph_id}->[$ctr];
}
return \%res2;
}
sub get_cacti_hosts {
my $res = DB_get ("id, description, hostname", "host");
return undef unless keys %$res > 0;
my %res2;
#print Dumper ($res);
for (my $ctr = 0; $ctr < @@{$res->{id}}; $ctr++) {
$res2{$res->{hostname}->[$ctr]} = $res->{id}->[$ctr];
$res2{$res->{description}->[$ctr]} = $res->{id}->[$ctr];
}
return \%res2;
}
@
1.4
log
@Working, good version. Threads, log rotation, signal response
@
text
@d7 1
a7 1
# $Header: /usr/local/nagios/libexec/eventhandlers/RCS/cacti_update,v 1.3 2013/02/13 20:01:55 nagios Exp nagios $
d150 1
a150 1
while ( $_ = $pnagcac -> dequeue ) {
d160 1
d488 1
a488 1
# For each graph component of relevant ds item
d563 1
a563 1
my $gritem = join "", keys %{$curgritem};
d590 1
a590 1
$text = $curgritem -> {$gritem} -> {text} =~ m#\^item\^$# ? $data->{perf}->{$curds}->[5] : $curgritem -> {$gritem} -> {text};
a940 3
$pnag = Thread::Queue -> new;
$pnagcac = Thread::Queue -> new;
d950 1
a950 1
$pidfile -> remove;
d956 3
d1181 7
a1187 2
$pnag -> enqueue ("Reload") if $waiton == 1;
$waiton = 2;
d1200 2
d1203 1
d1217 1
a1217 1
LK: while ( $_ = $pnag -> dequeue ) {
d1220 1
a1220 4
/^(Terminate|Reload)$/ and do {
$pnagcac -> enqueue ("$1");
last LK;
};
d1240 1
a1240 1
verbose (1, "Perfdata line matching spec: ###$svc###$hst###$svcout###$svcperf###");
a1384 19
# foreach my $hsthist (keys %perfhist) {
# foreach my $svchist (keys %{$perfhist{$hsthist}}) {
# $perfhist{$hsthist}->{$svchist} = 1 unless $perfhist{$hsthist}->{$svchist};
# }
# }
# }
# }
# If thread is done with success (0), mark the services in progress as done
#lock $thread_stat;
#if ($thread_stat == 0) {
# $thread_stat = 3; # Thread is not currently running
# foreach my $hsthist (keys %perfhist) {
# foreach my $svchist (keys %{$perfhist{$hsthist}}) {
# $perfhist{$hsthist}->{$svchist} = 2 if $perfhist{$hsthist}->{$svchist} == 1;
# }
# }
#}
a1387 5
# Remove old data
#foreach (keys %{$curperf->{perf}}) {
# delete $curperf->{perf}->{$_};
#}
#delete $curperf->{perf};
d1390 2
@
1.3
log
@Working version, mostly rewritten
@
text
@d7 1
a7 1
# $Header$
d22 2
a23 1
#use File::Pid;
d27 1
a27 1
my $mech;
d33 1
d35 1
d38 2
a39 1
my $pidpath = "/var/run/" . $myname . ".pid";
d53 1
d55 1
a55 1
my @@graph_templates;
d59 3
a61 2
my $pnag :shared;
my $pnagcac :shared;
d63 1
a63 1
my @@data_templates_created;
d67 3
d84 11
d112 36
d151 1
a151 1
last if /Terminate/;
a158 1
return 0 if /Terminate/;
d186 1
a186 3
#lock $terminate;
#last if $terminate == 1;
#next;
a216 3
lock $terminate;
last if $terminate == 1;
d221 3
d239 4
a242 1
return 0 if grep m#^$cactiserv$#i, @@data_templates_created;
d245 1
a245 1
$mech->get ("${cacti_url}/data_templates.php");
d247 5
a251 5
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Templates#) {
verbose 0, "Cacti: Failed to fetch \"${cacti_url}/data_templates.php\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
d253 1
a253 1
verbose 2, "Cacti: Query of ${cacti_url}/data_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d257 12
a268 6
$mech->submit_form(
form_name => 'form_data_template',
fields => {
filter => $cactiserv
},
);
d270 1
a270 7
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Templates#) {
verbose 0, "Cacti: Failed to submit to \"${cacti_url}/data_templates.php\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Submit to ${cacti_url}/data_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d274 5
a278 5
if (grep m#{spec}->{graph_template_name}_${cactiserv}$/i, @@graph_templates;
d506 1
a506 1
@@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values if keys %data_template_sel == 0;
d512 4
a515 3
my $keytemp = join "", grep m#^${cactiserv}\s+\-\s+\(${curds}\)$#i, keys %data_template_sel;
if ($keytemp eq "") {
d519 2
a520 1
#print "\n###$keytemp###\n";
d523 2
a524 1
$data_template_sel_items -> value ($data_template_sel{$keytemp});
d589 1
a589 1
$text = $curgritem -> {$gritem} -> {text} =~ m#^\^item\^$# ? $data->{perf}->{$curds}->[5] : $curgritem -> {$gritem} -> {text};
d628 6
a633 3
@@graph_templates = `$php -q ${cacti_path}/cli/add_graphs.php --list-graph-templates`;
shift @@graph_templates;
map { chomp; s/^\d+\s+//; } @@graph_templates;
d645 6
d652 1
a652 1
return 0 if exists $data_source_created{$cactiserv} && grep m#^$host$#i, @@{$data_source_created{$cactiserv}};
d656 1
a656 1
$mech -> get ("${cacti_url}/data_sources.php");
d658 5
a662 5
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Sources#) {
verbose 0, "Cacti: Failed to fetch \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
d664 1
a664 1
verbose 2, "Cacti: Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d670 5
a674 5
($data_template_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^template_id$/,
);
@@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values;
d677 4
a680 4
my $servkey = join "", grep m#^$cactiserv$#i, keys %data_template_sel;
my $hostkey;
if (exists $data_template_sel{$servkey}) { # No hosts with the template???
$data_template_sel_items -> value ($data_template_sel{$servkey});
d683 5
a687 5
($host_sel_items) = $mech -> find_all_inputs (
type => 'option',
name_regex => qr/^host_id$/,
);
@@host_sel{$host_sel_items->value_names} = $host_sel_items->possible_values;
d690 4
a693 4
$hostkey = join "", grep m#^$host #i, keys %host_sel;
$hostkey = join "", grep m# \(${host}\.#i, keys %host_sel if $hostkey eq '';
if (exists $host_sel{$hostkey}) {
$host_sel_items -> value ($host_sel{$hostkey});
d697 9
a705 3
$mech -> submit_form (
form_name => 'form_data_sources',
);
d707 1
a707 7
unless ($mech -> success() && $mech->title() =~ m#Console -> Data Sources#) {
verbose 0, "Cacti: Failed to search \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
return 1;
}
verbose 2, "Cacti: Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d709 3
a711 3
return 0 if $mech->response()->decoded_content !~ m#No Data Sources#;
}
}
d717 2
a718 1
$mech->follow_link (text => 'Add');
d734 1
a734 1
@@data_template_sel{$data_template_sel_items->value_names} = $data_template_sel_items->possible_values;
d737 3
a739 2
$servkey = join "", grep m#^$cactiserv$#i, keys %data_template_sel;
$data_template_sel_items -> value ($data_template_sel{$servkey});
d749 1
a749 1
$hostkey = join "", grep m#^$host #i, keys %host_sel;
d778 2
a779 2
$data_source_created{$cactiserv} = [] unless exists $data_source_created{$cactiserv};
push @@{$data_source_created{$cactiserv}}, $host;
d803 7
a809 2
return 1 unless exists $cacti_hosts{$hst}; # Host could not be located in Cacti for some reason (unprobable since this was already checked)
my @@host_graphs = `$php ${cacti_path}/cli/add_tree.php --list-graphs --host-id=$cacti_hosts{$hst}`;
d814 2
a815 1
if (grep m#^\d+\s+\S+\s+\-\s+$g_templ_title\($uniqname\)\s+#i, @@host_graphs) {
d839 1
a839 1
@@graph_template_sel{$graph_template_sel_items->value_names} = $graph_template_sel_items->possible_values;
a844 1
$graphkey = join "", grep m#^$data->{spec}->{graph_template_name}_${cactiserv}$#i, keys %graph_template_sel;
d846 2
d849 2
a850 1
$graph_template_sel_items -> value ($graph_template_sel{$graphkey});
d857 1
a857 1
@@host_sel{$host_sel_items->value_names} = $host_sel_items->possible_values;
d860 4
a863 3
my $hostkey = join "", grep m#^$host #i, keys %host_sel;
$hostkey = join "", grep m# \(${host}\.princeton\.edu\)#i, keys %host_sel if $hostkey eq '';
$host_sel_items -> value ($host_sel{$hostkey});
d866 2
a867 2
$hostkey =~ m#^(\S+)#;
my $hostkey_temp = $1;
d873 2
a874 1
unless ($mech -> success() && $mech->response()->decoded_content =~ m#${hostkey_temp} \- ${g_templ_title}\(${uniqname}\)#) {
d898 1
a898 1
@@ds_sel{$ds_sel_items->value_names} = $ds_sel_items->possible_values;
d900 4
a903 2
my $dskey = join "", grep m#^${host} \- ${cactiserv} \($found_ds_name\)$#i, keys %ds_sel;
$ds_sel_items -> value ($ds_sel{$dskey});
d936 2
a937 4
open LOG, ">> $log_file" or die "Cannot open logfile \"$log_file\"";
#$pidfile = File::Pid -> new ({file => $pidpath,});
#$pidfile -> write or die "Cannot write PID file: $!";
a939 10
open PERS, "< $persistence_file" and do {
foreach () {
chomp;
my ($hst, $svc) = split /::::/;
$perfhist{$hst} = &share ({}) unless exists $perfhist{$hst};
$perfhist{$hst}->{$svc} = 2;
}
close PERS;
};
d943 1
a943 1
$SIG{HUP} = \&read_config; # SIGHUP causes configuration re-read
d947 1
a947 1
verbose 0, "###### Program Started ###########\n";
d949 2
a950 3
verbose 1, "Trying to log to Cacti...";
$mech = WWW::Mechanize->new(agent => 'Mozilla/5.0', stack_depth => '2', noproxy => '1');
d952 2
a953 1
$mech->credentials($cacti_user, $cacti_pass);
a954 2
## Get initial Cacti login page
$mech->get($cacti_url);
d956 4
a959 4
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Console#) {
verbose 0, "Failed to login. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
graceful_die 1, 1;
d962 12
a973 2
verbose 1, "Login to Cacti successful\n";
verbose 2, "Response:\n" . $mech->response()->decoded_content . "\n\n##########################";
a974 1
# We read config initially. Later it can be done using SIGHUP
d982 17
a998 2
# Nagios pipe read
read_perfdata $rrd_thr, $cac_thr;
d1000 9
a1008 2
# Be clean and log the **** out
$mech->get ("${cacti_url}/logout.php");
a1009 1
graceful_die 1, 0, "########## Program terminated ##########";
d1013 1
d1017 3
a1019 3
@@graph_templates = `$php -q ${cacti_path}/cli/add_graphs.php --list-graph-templates`;
shift @@graph_templates;
map { chomp; s/^\d+\s+//; } @@graph_templates;
d1021 2
a1022 2
my @@cac_hosts = `$php -q ${cacti_path}/cli/add_graphs.php --list-hosts`;
foreach (@@cac_hosts) { /^(\d+)\s+(\S+)\s+(.*)/ and do { $cacti_hosts{$2} = $1; $cacti_hosts{$3} = $1; }; }
a1173 1
lock $pnag;
d1177 9
a1185 7
if (lock $terminate && $terminate) {
# If one of the threads is still running, just display a message
if ($rrd_thr -> is_running || $cac_thr -> is_running) {
verbose 1, "Waiting for the threads to complete...";
} else { # Otherwise finish
last;
}
d1187 1
d1193 7
d1204 1
d1208 8
a1215 1
while ( $_ = $pnag -> dequeue ) {
d1249 1
a1366 1
lock $pnagcac;
a1405 7
lock $terminate;
if ($terminate) {
lock $pnagcac;
$pnagcac -> enqueue ("Terminate");
last;
}
d1435 1
a1435 1
#$pidfile -> remove;
d1444 6
d1456 150
@
1.2
log
@Mostly working
@
text
@d7 1
a7 1
# $HEADER$
d10 2
a11 1
use lib qw(/usr/local/perl/modules/lib/perl5/site_perl/5.8.8 /usr/local/perl/modules/lib/perl5/5.8.8 /usr/local/perl/modules/lib64/perl5/site_perl/5.8.8 /usr/local/perl/modules/lib64/perl5/5.8.8 /var/local/groundwork/perl/lib/site_perl/5.8.8/);
d13 1
d18 5
a22 2
use forks;
use forks::shared;
d25 2
a26 2
my $mech = WWW::Mechanize->new(agent => 'Mozilla/5.0', stack_depth => '2', noproxy => '1');
d34 2
d48 3
a50 3
my %cacti_hosts :shared;
my %curperfdata :shared;
my @@graph_templates :shared;
d54 2
d60 14
a73 49
sub read_config ();
sub read_perfdata ();
sub clean_perfdata ();
sub cacti_update ();
sub dt_check_create ($$);
sub gt_check_create ($$);
sub ds_check_create ($$);
sub g_check_create ($$);
open LOG, ">> $log_file";
sub verbose ($$) {
my $level = shift;
my $string = shift;
if ($outtype eq 'log') {
my $dt = `date +"%a %b %d %T"`; chomp $dt;
print LOG "$dt => $string", "\n" if $verbose && $verbose >= $level;
} elsif ($outtype eq 'stderr') {
print STDERR "### ", $string, "\n" if $verbose && $verbose >= $level;
}
}
sub graceful_die ($$) {
my $immediate = shift;
my $str = shift;
verbose 0, $str;
if ($immediate) {
exit 1;
} else {
lock $terminate;
$terminate = 1;
}
}
sub end_program () {
verbose (0, "Program terminate requested by user");
lock $terminate;
$terminate = 1;
}
$SIG{HUP} = \&read_config; # SIGHUP causes configuration re-read
$SIG{TERM} = \&end_program; # SIGTERM causes graceful termination
$SIG{INT} = \&end_program; # CTRL+C causes graceful termination
open LOG, ">> $log_file";
verbose 0, "###### Program Started ###########\n";
d75 1
a75 1
verbose 1, "Trying to log to Cacti...";
d77 1
a77 38
$mech->credentials($cacti_user, $cacti_pass);
## Get initial Cacti login page
$mech->get($cacti_url);
unless ($mech -> success() && $mech->response()->decoded_content =~ m#Console#) {
verbose 0, "Failed to login. Answer: " . $mech->status();
verbose 2, "Response:\n" . $mech->response()->decoded_content;
exit 1;
}
verbose 1, "Login to Cacti successful\n";
verbose 2, "Response:\n" . $mech->response()->decoded_content . "\n\n##########################";
# We read config initially. Later it can be done using SIGHUP
read_config ();
#my $clean_task = threads -> create(\&clean_perfdata);
#$clean_task -> detach();
#my $cacti_task = threads -> create(\&cacti_update);
#$cacti_task -> detach();
# This is an infinite loop, reading and parsing the perfdata pipe
read_perfdata ();
# Give the threads a chance to complete their work
#while ($cacti_task -> is_running() || $clean_task -> is_running()) {}
#while ($clean_task -> is_running()) {}
#while ($cacti_task -> is_running()) {}
# Be clean and log the **** out
$mech->get ("${cacti_url}/logout.php");
verbose 0, "########## Program terminated ##########";
close LOG;
exit 0;
d83 1
a83 1
sub cacti_update () {
d90 6
d97 8
a104 22
while (1) {
{ lock %curperfdata;
foreach my $curserv (keys %curperfdata) {
lock %{$curperfdata{$curserv}};
foreach my $curhost (keys %{$curperfdata{$curserv}}) {
lock %{$curperfdata{$curserv}->{$curhost}};
next if $curperfdata{$curserv}->{$curhost}->{cactidone} || ! exists $curperfdata{$curserv}->{$curhost}->{perf};
# Check if the host exists, first. If it's not in Cacti, there's nothing to do really
lock %cacti_hosts;
next unless grep /^${curhost}(|\.princeton\.edu)$/i, keys %cacti_hosts;
# Check if the data template exists, and if not, create it
next if dt_check_create ($curserv, $curhost);
# Check if the graph template exists, and if not, create it
next if gt_check_create ($curserv, $curhost);
#{
#lock %{$curperfdata{$curserv}->{$curhost}};
#$curperfdata{$curserv}->{$curhost}->{cactidone} = 1;
#next;
#}
d106 23
a128 2
# Check if the data source exists, and if not, create it
next if ds_check_create ($curserv, $curhost);
d130 31
a160 4
# Check if the graph exists, and if not, create it
unless (g_check_create ($curserv, $curhost)) {
lock %{$curperfdata{$curserv}->{$curhost}->{perf}};
$curperfdata{$curserv}->{$curhost}->{cactidone} = 1;
d162 2
a163 8
foreach (keys %{$curperfdata{$curserv}->{$curhost}->{perf}}) {
delete $curperfdata{$curserv}->{$curhost}->{perf}->{$_};
}
delete $curperfdata{$curserv}->{$curhost}->{perf};
}
}
} }
#sleep 5;
d168 6
d177 2
a178 1
sub dt_check_create ($$) {
d181 3
a183 7
my $data = $curperfdata{$serv}->{$host};
my $cactiserv;
{
lock %{$data->{perf}};
# We need a unique name for a template, unique for service name AND its perfdata items
$cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
}
d192 1
a192 1
verbose 0, "Failed to fetch \"${cacti_url}/data_templates.php\". Answer: " . $mech->status();
d197 1
a197 1
verbose 2, "Query of ${cacti_url}/data_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d209 1
a209 1
verbose 0, "Failed to submit to \"${cacti_url}/data_templates.php\". Answer: " . $mech->status();
d214 1
a214 1
verbose 2, "Submit to ${cacti_url}/data_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d219 1
a219 1
verbose (1, "Data Template already exists for \"$cactiserv\"");
d222 1
a222 1
verbose (1, "Data Template not found for \"$cactiserv\" - will create");
d229 1
a229 1
verbose 0, "Failed to go to the data template addition page. Answer: " . $mech->status();
d234 1
a234 1
verbose 2, "Accessed the page to add a data template:\n" . $mech->response()->decoded_content . "\n\n######################";
d238 2
a239 4
{
lock %curperfdata; lock %{$curperfdata{$serv}}; lock %{$data}; lock %{$data->{perf}};
@@dsnames = keys %{$data->{perf}}; # Our pefdata labels, which are also internal data source names for Cacti
}
d244 5
a248 4
{
lock %curperfdata; lock %{$curperfdata{$serv}}; lock %{$data}; lock %{$data->{spec}}; lock %{$data->{spec}->{create_items}};
@@create_item_regexs = keys %{$data->{spec}->{create_items}};
$create_item_spec_match = join "", grep { $inids =~ /^$_$/i } @@create_item_regexs;
d256 12
a267 13
lock %{$data->{spec}->{create_items}->{$create_item_spec_match}};
# In Cacti, we first create an initial data template, with an initial data source name, and then we can add more
$mech->submit_form(
fields => {
template_name => "$cactiserv",
name => "|host_description| - $cactiserv",
active => 'unchecked',
data_source_name => $inids,
rrd_minimum => $data->{spec}->{create_items}->{$create_item_spec_match}->{min},
rrd_maximum => $data->{spec}->{create_items}->{$create_item_spec_match}->{max},
data_source_type_id => $typemap{$data->{spec}->{create_items}->{$create_item_spec_match}->{type}},
},
);
d271 1
a271 1
verbose 0, "Failed to save the new data template \"$serv\" -- \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
d276 1
a276 1
verbose 2, "Saved the new data template \"$serv\" to ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
d288 1
a288 1
verbose 0, "Failed to create new item in the new data template \"$serv\" -- \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
d293 1
a293 1
verbose 2, "Created new component for new data template \"$serv\", ds component \"$nextds\" in ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
d295 11
a305 12
{
lock %curperfdata; lock %{$curperfdata{$serv}}; lock %{$data}; lock %{$data->{spec}}; lock %{$data->{spec}->{create_items}}; lock %{$data->{spec}->{create_items}->{$create_item_spec_match}};
##################################################
# Then we save it with necessary parameters
$mech->submit_form(
fields => {
data_source_name => $nextds,
rrd_minimum => $data->{spec}->{create_items}->{$create_item_spec_match}->{min},
rrd_maximum => $data->{spec}->{create_items}->{$create_item_spec_match}->{max},
data_source_type_id => $typemap{$data->{spec}->{create_items}->{$create_item_spec_match}->{type}},
},
);
d309 1
a309 1
verbose 0, "Failed to save the new data template \"$serv\" with new item \"$nextds\" - \"${cacti_url}/data_templates.php?action=template_edit\". Answer: " . $mech->status();
d314 1
a314 1
verbose 2, "Saved new component for new data template \"$serv\", ds component \"$nextds\" in ${cacti_url}/data_templates.php?action=template_edit:\n" . $mech->response()->decoded_content . "\n\n######################";
d321 1
a321 1
verbose (1, "Successfully created a new data template for service \"$cactiserv\"");
d326 2
a327 1
sub gt_check_create ($$) {
a329 1
my $data = $curperfdata{$serv}->{$host};
d332 6
a337 9
{
lock %{$data->{perf}};
$uniqname = unpack ("L", md5(join "", sort keys %{$data->{perf}}));
$cactiserv = "${serv}_${uniqname}";
lock %{$data->{spec}};
lock @@graph_templates;
# Does the template exist?
return 0 if grep /^$data->{spec}->{graph_template_name}_${cactiserv}$/i, @@graph_templates;
d340 1
a340 1
verbose 1, "Graph template not found. Will create";
d346 1
a346 1
verbose 0, "Failed to fetch \"${cacti_url}/graph_templates.php\". Answer: " . $mech->status();
d351 1
a351 1
verbose 2, "Query of ${cacti_url}/graph_templates.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d357 1
a357 1
verbose 0, "Failed to follow the \"Add\" link. Answer: " . $mech->status();
d362 1
a362 1
verbose 2, "Followed the \"Add\" link:\n" . $mech->response()->decoded_content . "\n\n######################";
d368 1
a368 3
{
lock %{$data->{spec}};
d377 3
a379 6
{
# If the desired graph label is the same as the data source item name (for a single DS, we need to get it out)
lock %{$data->{perf}};
my ($firstlbl) = keys %{$data->{perf}};
lock @@{$data->{perf}->{$firstlbl}};
$g_templ_label = $data->{spec}->{graph_label} =~ m#\^item\^#i ? $data->{perf}->{$firstlbl}->[5] : $data->{spec}->{graph_label};
a384 2
}
d399 1
a399 1
verbose 0, "Failed to save the new graph template \"${g_templ_name}_${cactiserv}\". Answer: " . $mech->status();
d404 1
a404 1
verbose 2, "Saved new graph template \"${g_templ_name}_${cactiserv}\":\n" . $mech->response()->decoded_content . "\n\n######################";
a408 3
{
lock %{$data->{perf}};
lock %{$data->{spec}};
d410 1
d422 1
a422 3
{
lock %{$data->{spec}->{graph_items}};
lock @@{$data->{spec}->{graph_items}->{$graph_item_spec_match}};
d424 1
d432 1
a432 1
verbose 0, "Failed to add a new graph component by following the \"Add\" link. Answer: " . $mech->status();
d437 1
a437 1
verbose 2, "Followed the \"Add\" link to add a new graph component:\n" . $curcont . "\n\n######################";
d454 1
a454 1
verbose 0, "Could not locate the data_template ID for \"$cactiserv\"";
a497 1
lock %{$curgritem};
a498 1
lock %{$curgritem->{$gritem}};
a524 2
{
lock %{$data->{perf}->{$curds}};
a525 1
}
d542 1
a542 1
$mech -> field (hard_return => 'on') if $gr_items[@@gr_items-1] eq $curgritem;
d552 1
a552 1
verbose 0, "Failed to save a new graph item $curds -> $func for new graph template \"$g_templ_name\". Answer: " . $mech->status();
d557 1
a557 2
verbose 2, "Saved new graph item $curds -> $func for new graph template \"$g_templ_name\":\n" . $mech->response()->decoded_content . "\n\n######################";
} # end lock @@gr_items
d562 1
a562 1
verbose 1, "Graph template \"${g_templ_name}_${cactiserv}\" successfully created";
a563 1
lock @@graph_templates;
d572 2
a573 1
sub ds_check_create ($$) {
d576 1
a576 7
my $data = $curperfdata{$serv}->{$host};
my $cactiserv;
{
lock %{$data->{perf}};
$cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
}
d586 1
a586 1
verbose 0, "Failed to fetch \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
d591 1
a591 1
verbose 2, "Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d629 1
a629 1
verbose 0, "Failed to search \"${cacti_url}/data_sources.php\". Answer: " . $mech->status();
d634 1
a634 1
verbose 2, "Query of ${cacti_url}/data_sources.php resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
d641 1
a641 1
verbose 1, "Data source not found for host \"$host\" and service \"$cactiserv\". Will create";
d647 1
a647 1
verbose 0, "Failed to add a new data source by following the \"Add\" link. Answer: " . $mech->status();
d652 1
a652 1
verbose 2, "Followed the \"Add\" link to add a new data source:\n" . $mech->response()->decoded_content . "\n\n######################";
d682 1
a682 1
verbose 0, "Failed to create a new data source by associating a host with data template. Answer: " . $mech->status();
d687 1
a687 1
verbose 2, "Created a new data source:\n" . $mech->response()->decoded_content . "\n\n######################";
d698 1
a698 1
verbose 0, "Failed to save a new data source for template \"$cactiserv\" and host \"$host\". Answer: " . $mech->status();
d706 1
a706 1
verbose 2, "Saved a new data source for template \"$cactiserv\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
d708 1
a708 1
verbose 1, "Successfully created a new data source for host \"$host\" and service \"$cactiserv\"";
d714 2
a715 1
sub g_check_create ($$) {
a717 1
my $data = $curperfdata{$serv}->{$host};
a719 2
{
lock %{$data->{perf}};
a721 1
}
d732 1
a732 2
{
lock %{$data->{spec}};
d734 4
a737 1
return 0 if grep m#^\d+\s+\S+\s+\-\s+$g_templ_title\($uniqname\)\s+#i, @@host_graphs;
d740 1
a740 1
verbose 1, "Graph for host \"$host\" and service \"$serv\" could not be located. Will create";
d745 1
a745 1
verbose 0, "Failed to add a new graph for template \"$cactiserv\" and host \"$host\". Answer: " . $mech->status();
d750 1
a750 1
verbose 2, "Created a new graph for template \"$cactiserv\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
d763 1
a763 2
{
lock %{$data->{spec}};
d790 1
a790 1
verbose 0, "Failed to save the new graph for graph template \"${g_templ_title}(${uniqname})\" and host \"$host\". Answer: " . $mech->status();
d795 1
a795 1
verbose 2, "Saved the new graph for graph template \"${g_templ_title}(${uniqname})\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
d822 1
a822 1
verbose 0, "Failed to save the components of the new graph for graph template \"${g_templ_name}_${cactiserv}\" and host \"$host\". Answer: " . $mech->status();
d827 2
a828 2
verbose 2, "Saved the components of the new graph for graph template \"${g_templ_name}_${cactiserv}\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
verbose 1, "Successfully created a graph for host \"$host\"";
d833 54
a886 13
sub read_config () {
lock (%spec);
{
lock (@@graph_templates);
@@graph_templates = `$php -q ${cacti_path}/cli/add_graphs.php --list-graph-templates`;
shift @@graph_templates;
map { chomp; s/^\d+\s+//; } @@graph_templates;
}
{
lock (%cacti_hosts);
my @@cac_hosts = `$php -q ${cacti_path}/cli/add_graphs.php --list-hosts`;
foreach (@@cac_hosts) { /^(\d+)\s+(\S+)\s+(.*)/ and do { $cacti_hosts{$2} = $1; $cacti_hosts{$3} = $1; }; }
d889 32
a920 1
open SPECFILE, "< $spec_file" or graceful_die (1, "Unable to open the service spec file!!!\n");
d924 2
a937 1
lock %{$spec{$curservreg}};
a945 1
lock %{$spec{$curservreg}};
d948 1
a948 1
$spec{$curservreg} -> {$curhostreg} = &share ({});
a954 2
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
a961 2
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
a968 2
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
a975 2
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
a976 1
lock %{$spec{$curservreg}->{$curhostreg}->{map_items}};
a981 2
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
a982 1
lock @@{$spec{$curservreg}->{$curhostreg}->{ignore_items}};
a988 3
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
lock %{$spec{$curservreg}->{$curhostreg}->{create_items}};
a995 3
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
lock %{$spec{$curservreg}->{$curhostreg}->{graph_items}};
a998 1
lock %{$spec{$curservreg}->{$curhostreg}->{graph_items}->{$itemspec}};
a1012 4
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
lock %{$spec{$curservreg}->{$curhostreg}->{create_items}};
lock %{$spec{$curservreg}->{$curhostreg}->{create_items}->{$createitemspec}};
a1017 6
lock %{$spec{$curservreg}};
lock %{$spec{$curservreg}->{$curhostreg}};
lock %{$spec{$curservreg}->{$curhostreg}->{graph_items}};
lock @@{$spec{$curservreg}->{$curhostreg}->{graph_items}->{$itemspec}};
lock %{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}[@@{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}} - 1]};
lock %{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}[@@{$spec{$curservreg} -> {$curhostreg} -> {graph_items} -> {$itemspec}} - 1] -> {$itemspec2}};
d1054 3
a1056 2
# The following will continuously read the perfdata Nagios pipe, and load necessary results into %curpefdata
sub read_perfdata () {
d1059 1
a1059 2
open PERFDATA, "< $perf_file" or do { graceful_die (0, "Unable to open the perfdata file \"$perf_file\"!!!"); return 1; };
d1069 26
d1102 1
a1103 2
# This skips perfdata lines not matching the spec - don't care about these
d1115 5
a1119 9
lock %curperfdata;
$curperfdata{$svc} = &share ({}) unless exists $curperfdata{$svc};
lock %{$curperfdata{$svc}};
$curperfdata{$svc}->{$hst} = &share ({}) unless exists $curperfdata{$svc}->{$hst};
lock %{$curperfdata{$svc}->{$hst}};
my $perfdata :shared = $curperfdata{$svc}->{$hst};
$perfdata->{perf} = &share ({});
$perfdata->{time} = $tm;
$perfdata->{cactidone} = 0;
d1134 2
a1135 4
lock %{$perfdata->{perf}};
$perfdata->{perf}->{$lbl} = &share ([]);
lock @@{$perfdata->{perf}->{$lbl}};
push @@{$perfdata->{perf}->{$lbl}}, $val, $wrn, $crt, $min, $max, $graphlabel;
d1138 1
a1138 1
verbose (1, "Perfdata deciphered: ###$val###$graphlabel###");
d1141 1
a1141 1
# Link the relevant part of the spec hash to the %curperfdata for further use
d1143 4
a1146 2
foreach my $nextspec (keys %spec) {
next unless $svc =~ m#${nextspec}#;
a1147 1
lock %{$spec{$nextspec}};
d1149 1
a1149 1
foreach my $hostspec (keys %{$spec{$nextspec}}) {
d1152 3
a1154 6
lock %{$spec{$nextspec}->{$hostspec}};
my $curspec :shared = $spec{$nextspec}->{$hostspec};
$curperfdata{$svc}->{$hst}->{spec} = $curspec;
#$spec{$nextspec}->{$hostspec}->{matched} = &share ({}) unless exists $spec{$nextspec}->{$hostspec}->{matched};
#$spec{$nextspec}->{$hostspec}->{matched}->{$svc} = $hst;
a1158 2
lock %{$perfdata->{perf}};
d1160 3
a1162 3
next unless exists $perfdata->{perf}->{$_};
#print Dumper ($perfdata->{perf}->{$_});
delete $perfdata->{perf}->{$_};
d1170 3
a1172 3
next unless exists $perfdata->{perf}->{$_};
$perfdata->{perf}->{$curspec->{map_items}->{$_}} = $perfdata->{perf}->{$_};
delete $perfdata->{perf}->{$_};
a1175 1
{ lock %{$perfdata->{perf}};
d1177 5
a1181 5
if (keys %{$perfdata->{perf}} == 0) {
delete $perfdata->{perf};
delete $curperfdata{$svc}->{$hst};
delete $curperfdata{$svc} unless keys %{$curperfdata{$svc}} > 0;
}}
d1213 1
a1213 1
#print "###", keys %{$curperfdata{$svc}->{$hst}}, "###\n";
d1218 1
a1218 1
foreach my $dsitem (keys %{$perfdata->{perf}}) {
d1225 1
a1225 1
d1233 3
a1235 4
lock %{$perfdata->{perf}};
my $valsupdate = join ":", (map { lock @@{$perfdata->{perf}->{$_}}; $perfdata->{perf}->{$_}->[0]; } keys %{$perfdata->{perf}});
my @@rrdout = `$rrdtool update ${rrapath}/${hst}_${svc}.rrd $perfdata->{time}:$valsupdate 2>&1`;
verbose (1, "Update RRD: $rrdtool update ${rrapath}/${hst}_${svc}.rrd $perfdata->{time}:$valsupdate\nResponse: " . join ("\n", @@rrdout));
d1237 40
d1278 1
a1278 1
} # End foreach nextspec
d1280 5
a1284 7
lock %{$perfdata->{perf}};
$perfdata->{cactidone} = 1;
foreach (keys %{$perfdata->{perf}}) {
delete $perfdata->{perf}->{$_};
}
delete $perfdata->{perf};
d1287 5
a1291 1
last if $terminate == 1;
d1294 2
a1295 1
close PERFDATA;
d1299 12
a1310 21
sub clean_perfdata () {
while (1) {
{ lock %curperfdata;
foreach my $svc (keys %curperfdata) {
lock %{$curperfdata{$svc}};
foreach my $hst (keys %{$curperfdata{$svc}}) {
lock %{$curperfdata{$svc}->{$hst}};
my $perfdata = $curperfdata{$svc}->{$hst};
# Essentially we check %curperfdata contents for entries where "cactidone" is marked as "1" (completed)
# by the "cacti_update" thread. This tells us to delete this outdated piece of perfdata
if ($perfdata->{cactidone} && exists $perfdata->{perf}) {
# change to 2 later!!!
verbose (1, "Cleaning perfdata: $svc/$hst");
#print Dumper ($perfdata);
lock %{$perfdata->{perf}};
foreach (keys %{$perfdata->{perf}}) {
delete $perfdata->{perf}->{$_};
}
delete $perfdata->{perf};
d1312 5
a1316 12
# This is commented out, because same hosts/services will come up again and again with new perfdata
# Hence no need to waste CPU cycles deallocating them
#foreach my $servhostprop (keys %{$perfdata}) {
# next if $_ eq 'spec';
# delete $perfdata->{$servhostprop};
#}
#delete $curperfdata{$svc}->{$hst};
#delete $curperfdata{$svc} if keys %{$curperfdata{$svc}} == 0;
}
}
} }
sleep 20;
d1318 7
d1326 1
a1326 1
last if $terminate == 1;
d1330 5
@
1.1
log
@Initial revision
@
text
@d7 2
d16 2
a17 2
use threads;
use threads::shared;
d48 3
a107 19
#unless ($mech -> success() && $mech->title() =~ m#Login to Cacti#) {
# verbose 0, "Failed to fetch \"$cacti_url\". Answer: " . $mech->status();
# verbose 2, "Response:\n" . $mech->response()->decoded_content;
# exit 1;
#}
#verbose 2, "Query of $cacti_url resulted in:\n" . $mech->response()->decoded_content . "\n\n######################";
#verbose 1, "Trying to log in...";
## Send login credentials
#$mech->submit_form(
# form_name => 'login',
# fields => {
# login_username => $cacti_user,
# login_password => $cacti_pass,
# }
#);
d120 4
a123 4
my $clean_task = threads -> create(\&clean_perfdata);
$clean_task -> detach();
my $cacti_task = threads -> create(\&cacti_update);
$cacti_task -> detach();
d129 3
a131 1
while ($cacti_task -> is_running() || $clean_task -> is_running()) {}
d153 1
a153 1
#return 0;
d159 2
a160 2
{ lock %{$curperfdata{$curserv}->{$curhost}};
next if $curperfdata{$curserv}->{$curhost}->{cactidone}; }
d163 2
a164 2
{ lock %cacti_hosts;
next unless grep /^${curhost}.princeton.edu$/i, keys %cacti_hosts; }
d168 1
a168 5
{
lock %{$curperfdata{$curserv}->{$curhost}};
$curperfdata{$curserv}->{$curhost}->{cactidone} = 1;
next;
}
d171 5
d182 1
a182 1
lock %{$curperfdata{$curserv}->{$curhost}};
d184 5
d192 1
a192 1
sleep 10;
d203 1
a203 1
my $data :shared;
d206 1
a206 3
lock %curperfdata; lock %{$curperfdata{$serv}};
$data = $curperfdata{$serv}->{$host};
lock %{$data}; lock %{$data->{perf}};
d211 3
d348 2
d359 1
a359 1
my $cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
d361 12
a372 2
# Does the template exist?
return 0 if grep /^$data->{spec}->{graph_template_name}$/i, @@graph_templates;
d398 21
a418 6
my $title = "|host_description| - " . $data->{spec}->{graph_title};
my $hgt = exists $data->{spec}->{graph_height} ? $data->{spec}->{graph_height} : 120;
my $wdt = exists $data->{spec}->{graph_width} ? $data->{spec}->{graph_width} : 500;
my $t_upper = exists $data->{spec}->{graph_upper_limit} ? $data->{spec}->{graph_upper_limit} : 100;
my $t_lower = exists $data->{spec}->{graph_lower_limit} ? $data->{spec}->{graph_lower_limit} : 0;
my $t_base = exists $data->{spec}->{graph_base} ? $data->{spec}->{graph_base} : 1000;
d422 2
d426 1
a426 1
name => $data->{spec}->{graph_template_name},
d433 1
a433 1
vertical_label => $data->{spec}->{graph_label},
d436 1
a436 1
d438 1
a438 1
verbose 0, "Failed to save the new graph template \"$data->{spec}->{graph_template_name}\". Answer: " . $mech->status();
d443 1
a443 1
verbose 2, "Saved new graph template \"$data->{spec}->{graph_template_name}\":\n" . $mech->response()->decoded_content . "\n\n######################";
d447 10
a456 4
my @@dsnames = keys %{$data->{perf}};
my @@graph_item_regexs = keys %{$data->{spec}->{graph_items}};
my (%data_template_sel, %colors_sel, %function_type_sel, %graph_type_sel);
my ($data_template_sel_items, $colors_sel_items, $function_type_sel_items, $graph_type_sel_items);
d461 6
a466 1
my @@gr_items = @@{$data->{spec}->{graph_items}->{$graph_item_spec_match}};
d489 2
d499 2
a500 1
d525 16
d542 1
d555 18
a572 1
my $text = $curgritem -> {$gritem} -> {text} =~ m#^\^item\^$# ? $curds : $curgritem -> {$gritem} -> {text};
d580 3
a582 1
$keytemp = $colorkeys[int (rand (scalar (@@colorkeys)))] if $keytemp eq '';
d588 2
a589 1
my $hard_return = $gr_items[@@gr_items-1] eq $curgritem ? 'checked' : 'unchecked';
d594 1
a594 1
hard_return => $hard_return,
d599 1
a599 1
verbose 0, "Failed to save a new graph item $curds -> $func for new graph template \"$data->{spec}->{graph_template_name}\". Answer: " . $mech->status();
d604 2
a605 2
verbose 2, "Saved new graph item $curds -> $func for new graph template \"$data->{spec}->{graph_template_name}\":\n" . $mech->response()->decoded_content . "\n\n######################";
d610 7
d625 9
a633 1
my $cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
d672 1
d695 2
d729 1
d757 3
d762 1
d772 8
a779 1
my $cactiserv = "${serv}_" . unpack ("L", md5(join "", sort keys %{$data->{perf}}));
d781 1
a781 1
my ($graph_template_sel_items, $host_sel_items);
d783 2
a784 1
my $hst = join "", grep m#^${host}\.princeton\.edu$#i, keys %cacti_hosts;
d789 7
a795 1
return 0 if grep m#^\d+\s+${host}\s+\-\s+ $data->{spec}->{graph_title}\s+${cactiserv}\s*$#i, @@host_graphs;
d816 7
a822 1
my $graphkey = join "", grep m#^$data->{spec}->{graph_template_name}$#i, keys %graph_template_sel;
d834 1
d836 5
d845 2
a846 2
unless ($mech -> success() && $mech->response()->decoded_content =~ m#${host} \- $data->{spec}->{graph_template_name}#) {
verbose 0, "Failed to save the new graph for graph template \"$data->{spec}->{graph_template_name}\" and host \"$host\". Answer: " . $mech->status();
d851 1
a851 1
verbose 2, "Saved the new graph for graph template \"$data->{spec}->{graph_template_name}\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
d878 1
a878 1
verbose 0, "Failed to save the components of the new graph for graph template \"$data->{spec}->{graph_template_name}\" and host \"$host\". Answer: " . $mech->status();
d883 2
a884 1
verbose 2, "Saved the components of the new graph for graph template \"$data->{spec}->{graph_template_name}\" and host \"$host\":\n" . $mech->response()->decoded_content . "\n\n######################";
d901 1
a901 1
foreach (@@cac_hosts) { /^(\d+)\s+(\S+)/ and $cacti_hosts{$2} = $1; }
d1098 1
d1124 1
a1124 1
$val =~ s/[^0-9]//g;
d1138 1
a1138 1
next unless $svc =~ /${nextspec}/i;
d1153 3
a1155 2
lock @@{$curspec->{ignore_items}};
lock %{$perfdata->{perf}};
d1157 2
a1158 2
foreach (@@{$curspec->{ignore_items}}) {
next unless exists $perfdata->{perf}->{$_};
d1160 3
a1162 2
delete $perfdata->{perf}->{$_};
}
d1165 8
a1172 6
lock %{$curspec->{map_items}};
foreach (keys %{$curspec->{map_items}}) {
next unless exists $perfdata->{perf}->{$_};
$perfdata->{perf}->{$curspec->{map_items}->{$_}} = $perfdata->{perf}->{$_};
delete $perfdata->{perf}->{$_};
}
d1174 1
d1180 1
a1180 1
}
d1232 1
d1240 7
a1246 1
sleep 5;
d1268 1
a1268 1
$perfdata->{cactidone} and do {
d1271 1
a1271 1
d1286 1
a1286 1
};
@