1#!/usr/bin/perl
2
3# collectd - contrib/migrate-4-5.px
4# Copyright (C) 2010  Florian Forster
5#
6# Permission is hereby granted, free of charge, to any person obtaining a
7# copy of this software and associated documentation files (the "Software"),
8# to deal in the Software without restriction, including without limitation
9# the rights to use, copy, modify, merge, publish, distribute, sublicense,
10# and/or sell copies of the Software, and to permit persons to whom the
11# Software is furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice shall be included in
14# all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22# DEALINGS IN THE SOFTWARE.
23#
24# Authors:
25#   Florian Forster <octo at collectd.org>
26
27use strict;
28use warnings;
29
30use Getopt::Long ('GetOptions');
31use Data::Dumper ();
32use File::Basename ('dirname');
33
34our $InDir = '/var/lib/collectd';
35our $RRDtool = 'rrdtool';
36our $RRDFilter = 'rrd_filter.px';
37
38our %TypesCounterToDerive = # {{{
39(
40  apache_bytes => ["count"],
41  apache_requests => ["count"],
42  arc_counts => ["demand_data", "demand_metadata", "prefetch_data", "prefetch_metadata"],
43  arc_l2_bytes => ["read", "write"],
44  ath_stat => ["value"],
45  compression => ["uncompressed", "compressed"],
46  connections => ["value"],
47  cpu => ["value"],
48  current => ["value"],
49  disk_merged => ["read", "write"],
50  disk_octets => ["read", "write"],
51  disk_ops => ["read", "write"],
52  disk_ops_complex => ["value"],
53  disk_time => ["read", "write"],
54  dns_answer => ["value"],
55  dns_notify => ["value"],
56  dns_octets => ["queries", "responses"],
57  dns_opcode => ["value"],
58  dns_qtype => ["value"],
59  dns_query => ["value"],
60  dns_question => ["value"],
61  dns_rcode => ["value"],
62  dns_reject => ["value"],
63  dns_request => ["value"],
64  dns_resolver => ["value"],
65  dns_response => ["value"],
66  dns_transfer => ["value"],
67  dns_update => ["value"],
68  dns_zops => ["value"],
69  fscache_stat => ["value"],
70  fork_rate => ["value"],
71  http_request_methods => ["count"],
72  http_requests => ["count"],
73  http_response_codes => ["count"],
74  if_collisions => ["value"],
75  if_dropped => ["rx", "tx"],
76  if_errors => ["rx", "tx"],
77  if_multicast => ["value"],
78  if_octets => ["rx", "tx"],
79  if_packets => ["rx", "tx"],
80  if_rx_errors => ["value"],
81  if_tx_errors => ["value"],
82  io_octets => ["rx", "tx"],
83  io_packets => ["rx", "tx"],
84  ipt_bytes => ["value"],
85  ipt_packets => ["value"],
86  irq => ["value"],
87  memcached_command => ["value"],
88  memcached_octets => ["rx", "tx"],
89  memcached_ops => ["value"],
90  mysql_commands => ["value"],
91  mysql_handler => ["value"],
92  mysql_locks => ["value"],
93  mysql_log_position => ["value"],
94  mysql_octets => ["rx", "tx"],
95  nfs_procedure => ["value"],
96  nginx_requests => ["value"],
97  node_octets => ["rx", "tx"],
98  node_stat => ["value"],
99  operations => ["value"],
100  pg_blks => ["value"],
101  pg_n_tup_c => ["value"],
102  pg_scan => ["value"],
103  pg_xact => ["value"],
104  protocol_counter => ["value"],
105  ps_cputime => ["user", "syst"],
106  ps_pagefaults => ["minflt", "majflt"],
107  serial_octets => ["rx", "tx"],
108  swap_io => ["value"],
109  virt_cpu_total => ["ns"],
110  virt_vcpu => ["ns"],
111  vmpage_action => ["value"],
112  vmpage_faults => ["minflt", "majflt"],
113  vmpage_io => ["in", "out"],
114); # }}} %TypesCounterToDerive
115
116our %TypesRenameDataSource = # {{{
117(
118  absolute => "count",
119  apache_bytes => "count",
120  apache_connections => "count",
121  apache_idle_workers => "count",
122  apache_requests => "count",
123  apache_scoreboard => "count",
124  conntrack => "entropy",
125  contextswitch => "contextswitches",
126  delay => "seconds",
127  entropy => "entropy",
128  file_size => "bytes",
129  frequency => "frequency",
130  frequency_offset => "ppm",
131  http_request_methods => "count",
132  http_requests => "count",
133  http_response_codes => "count",
134  percent => "percent",
135  ping => "ping",
136  records => "count",
137  time_dispersion => "seconds",
138  timeleft => "timeleft",
139  time_offset => "seconds",
140  users => "users",
141  virt_cpu_total => "ns",
142  virt_vcpu => "ns",
143); # }}} %TypesRenameDataSource
144
145sub handle_file # {{{
146{
147  my @path = @_;
148  my $path = join ('/', @path);
149
150  if (!($path =~ m/\.rrd$/))
151  {
152    return;
153  }
154
155  my $tmp = pop (@path);
156  $tmp =~ s/\.rrd$//;
157  my ($type, $type_inst) = split (m/-/, $tmp, 2);
158  $type_inst ||= '';
159
160  $tmp = pop (@path);
161  my ($plugin, $plugin_inst) = split (m/-/, $tmp, 2);
162  $plugin_inst ||= '';
163
164  if ($TypesRenameDataSource{$type})
165  {
166    my $old_ds = $TypesRenameDataSource{$type};
167    print "$RRDtool tune \"$path\" --data-source-rename ${old_ds}:value\n";
168  }
169
170  if ($TypesCounterToDerive{$type})
171  {
172    my $ds_names = $TypesCounterToDerive{$type};
173
174    for (@$ds_names)
175    {
176      my $name = $_;
177      print "$RRDtool tune \"$path\" --data-source-type ${name}:DERIVE --minimum ${name}:0 --maximum ${name}:U\n";
178    }
179  }
180
181  if ((($plugin eq 'df') || ($plugin eq 'interface'))
182    && (!$plugin_inst) && ($type_inst))
183  {
184    my $dir = join ('/', @path);
185    print "mkdir -p \"$dir/$plugin-$type_inst\"\n";
186    if (($plugin eq 'df') and ($type eq 'df'))
187    {
188      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-free.rrd\" --map free:value\n";
189      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-used.rrd\" --map used:value\n";
190    }
191    else
192    {
193      print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
194    }
195  }
196} # }}} sub handle_file
197
198sub scan_dir # {{{
199{
200  my @dir_parts = @_;
201  my $dir_str = join ('/', @dir_parts);
202  my $dh;
203
204  opendir ($dh, $dir_str) || die;
205  while (my $entry = readdir ($dh))
206  {
207    my $entry_path = "$dir_str/$entry";
208
209    if ($entry =~ m/^\./)
210    {
211      next;
212    }
213
214    if (-d $entry_path)
215    {
216      scan_dir (@dir_parts, $entry);
217    }
218    elsif (-f $entry_path)
219    {
220      handle_file (@dir_parts, $entry);
221    }
222  }
223  closedir ($dh);
224} # }}} sub scan_dir
225
226sub exit_usage # {{{
227{
228  print STDERR <<EOF;
229migrate-4-5.px [OPTIONS]
230
231Valid options are:
232
233  --indir <dir>         Source directory
234                        Default: $InDir
235  --rrdtool <path>      Path to the RRDtool binary
236                        Default: $RRDtool
237  --rrdfilter <path>    Path to the rrd_filter.px script
238                        Default: $RRDFilter
239
240EOF
241  exit (1);
242} # }}} sub exit_usage
243
244GetOptions ("indir|i=s" => \$InDir,
245        "rrdtool=s" => \$RRDtool,
246        "rrdfilter=s" => \$RRDFilter,
247        "help|h" => \&exit_usage) or exit_usage ();
248
249print "#!/bin/bash\n\n";
250
251scan_dir ($InDir);
252
253# vim: set sw=2 sts=2 et fdm=marker :
254