File Coverage

lib/RRDTool/Rawish.pm
Criterion Covered Total %
statement 114 121 94.2
branch 66 82 80.4
condition 19 36 52.7
subroutine 22 24 91.6
pod 12 12 100.0
total 233 275 84.7


line stmt bran cond sub pod time code
1             package RRDTool::Rawish;
2 4     4   165969 use strict;
  4         13  
  4         140  
3 4     4   22 use warnings;
  4         8  
  4         108  
4 4     4   67 use 5.008;
  4         18  
  4         147  
5              
6 4     4   23 use Carp ();
  4         5  
  4         72  
7 4     4   3882 use Capture::Tiny qw(capture);
  4         164084  
  4         308  
8 4     4   2701 use File::Which ();
  4         3202  
  4         7883  
9              
10             our $VERSION = '0.032';
11              
12             sub new {
13 1     1 1 1106 my ($class, @args) = @_;
14 1 50 33     10 my %args = @args == 1 && ref $args[0] eq 'HASH' ? %{$args[0]} : @args;
  0         0  
15              
16 1 50 33     9 my $rrdtool_path = $args{rrdtool_path} || File::Which::which('rrdtool')
17             or Carp::croak 'Not found rrdtool command';
18 1 50       18 if (not -x $rrdtool_path) {
19 1         209 Carp::croak "Cannot execute $rrdtool_path";
20             }
21              
22 0         0 return bless {
23             command => $rrdtool_path,
24             remote => $args{remote},
25             rrdfile => $args{rrdfile},
26             rrderror => "",
27             }, $class;
28             }
29              
30             sub version {
31 0     0 1 0 my $self = shift;
32 0         0 my ($ret, $exit_status) = $self->_readpipe($self->{command}, 'version');
33 0         0 $ret =~ /^RRDtool (\d+)\.(\d+).(\d+)/;
34 0         0 return "$1.$2$3"; # like "1.47"
35             }
36              
37 0     0 1 0 sub errstr { $_[0]->{rrderror} }
38              
39             sub create {
40 5     5 1 24330 my ($self, $params, $opts) = @_;
41 5 100       135 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
42 4 100       117 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
43 3 100 100     115 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
44              
45 2 100       8 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
46              
47 2         11 my $exit_status = $self->_system($self->{command}, 'create', $self->{rrdfile}, _opt_array($opts), @$params);
48 2         13 return $exit_status;
49             }
50              
51             sub update {
52 4     4 1 3068 my ($self, $params, $opts) = @_;
53 4 100       104 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
54 3 100       100 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
55 2 100 66     105 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
56              
57 1 50       4 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
58              
59 1         6 my $exit_status = $self->_system($self->{command}, 'update', $self->{rrdfile}, _opt_array($opts), @$params);
60 1         7 return $exit_status;
61             }
62              
63             sub graph {
64 2     2 1 1736 my ($self, $filename, $params, $opts) = @_;
65 2 100       96 Carp::croak 'Require filename' unless $filename;
66 1 50       4 Carp::croak 'Not ARRAY reference: $params' if ref($params) ne 'ARRAY';
67 1 50 33     9 Carp::croak 'Not HASH reference: $opts' if defined $opts && ref($opts) ne 'HASH';
68              
69 1 50       4 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
70              
71 1         3 my ($img, $exit_status) = $self->_readpipe($self->{command}, 'graph', $filename, _opt_array($opts), @$params);
72 1         26 return $img;
73             }
74              
75             sub dump {
76 3     3 1 2456 my ($self, $opts) = @_;
77 3 100       101 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
78 2 100 66     117 Carp::croak 'Not HASH reference: $opts' if defined $opts && ref($opts) ne 'HASH';
79              
80 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
81              
82 1         4 my ($xml, $exit_status) = $self->_readpipe($self->{command}, 'dump', $self->{rrdfile}, _opt_array($opts));
83 1         5 return $xml;
84             }
85              
86             sub restore {
87 4     4 1 2980 my ($self, $xmlfile, $opts) = @_;
88 4 100       102 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
89 3 100       101 Carp::croak 'Require xmlfile' if not defined $xmlfile;
90 2 100 66     105 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
91              
92 1         5 my $ret = $self->_system($self->{command}, 'restore', $xmlfile, $self->{rrdfile}, _opt_array($opts));
93 1         4 return $ret;
94             }
95              
96             sub lastupdate {
97 2     2 1 1831 my ($self) = @_;
98 2 100       100 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
99              
100 1         3 my $opts = {};
101 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
102              
103 1         4 my ($text, $exit_status) = $self->_readpipe($self->{command}, 'lastupdate', $self->{rrdfile}, _opt_array($opts));
104 1 50 33     5 return $text if (!$text and $exit_status != 0);
105              
106 1         6 my $lines = [ split "\n", $text ];
107 1         5 my ($timestamp, $tmp) = split ':', $lines->[2];
108 1         7 return $timestamp;
109             }
110              
111             sub fetch {
112 4     4 1 3404 my ($self, $CF, $opts) = @_;
113 4 100       99 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
114 3 100       98 Carp::croak 'Require CF' if not defined $CF;
115 2 100 66     101 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
116              
117 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
118              
119 1         4 my ($text, $exit_status) = $self->_readpipe($self->{command}, 'fetch', $self->{rrdfile}, $CF, _opt_array($opts));
120 1 50 33     5 return $text if (!$text and $exit_status != 0);
121              
122 1         7 my $lines = [ split "\n", $text ];
123 1         4 return $lines;
124             }
125              
126             sub xport {
127 3     3 1 5422 my ($self, $params, $opts) = @_;
128 3 100       105 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
129 2 100 66     105 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
130              
131 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
132              
133 1         6 my ($xml, $exit_status) = $self->_readpipe($self->{command}, 'xport', _opt_array($opts), @$params);
134 1         6 return $xml;
135             }
136              
137             sub info {
138 2     2 1 1854 my ($self) = @_;
139 2 100       97 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
140              
141 1 50       4 my $opts_str = $self->{remote} ? "--daemon" : "";
142              
143 1         5 my ($text, $exit_status) = $self->_readpipe($self->{command}, 'info', $self->{rrdfile}, $opts_str);
144 1 50 33     5 return $text if (!$text and $exit_status != 0);
145              
146 1         3 my $value = {};
147 1         12 my $lines = [ split "\n", $text ];
148 1         4 for (@$lines) {
149 30         52 my ($k, $v) = split ' = ', $_;
150 30         47 $v =~ s/"(.+)"/$1/g;
151 30 100       108 if ($k =~ /^rra\[(\d+)]\.(.+)\[(\d+)\]\.(.+)$/) { # rra[0].cdp_prep[0].value = NaN
    100          
    100          
152 4         16 $value->{rra}->[$1]->{$2}->[$3]->{$4} = $v;
153             }
154             elsif ($k =~ /^rra\[(\d+)\]\.(.+)$/) { # rra[0].cf = "LAST"
155 5         14 $value->{rra}->[$1]->{$2} = $v;
156             }
157             elsif ($k =~ /^ds\[(.+)\]\.(.+)$/) { # ds[rx].type = "DERIVE"
158 16         47 $value->{ds}->{$1}->{$2} = $v;
159             }
160             else {
161 5         10 $value->{$k} = $v;
162             }
163             }
164 1         6 return $value;
165             }
166              
167             sub _system {
168 4     4   12 my ($self, @expr) = @_;
169              
170             my ($stdout, $stderr, $exit_status) = capture {
171 4     4   4370 system(_sanitize(join(" ", @expr)));
172 4         141 };
173 4         4728 chomp $stderr;
174 4 50       17 $self->{rrderror} = $stderr if $exit_status != 0;
175 4         14 return $exit_status;
176             }
177              
178             sub _readpipe {
179 6     6   15 my ($self, @expr) = @_;
180              
181             my ($stdout, $stderr, $exit_status) = capture {
182 6     6   5131 system(_sanitize(join(" ", @expr)));
183 6         176 };
184 6         5791 chomp $stderr;
185 6 100       21 $self->{rrderror} = $stderr if $exit_status != 0;
186 6         20 return ($stdout, $exit_status);
187             }
188              
189             sub _sanitize {
190 10     10   12 my $command = shift;
191 10         36 $command =~ s/[^a-z0-9#_@\s\-\.\,\:\/=\+\-\*\%]//gi;
192 10         36 return $command;
193             }
194              
195             sub _opt_array {
196 9     9   12 my ($opts) = @_;
197              
198 10 100       54 return map {
199 9         43 ($opts->{$_} eq 1) ? $_ : ($_, $opts->{$_})
200             } sort(keys %$opts);
201             }
202              
203             1;
204             __END__