File Coverage

lib/RRDTool/Rawish.pm
Criterion Covered Total %
statement 119 126 94.4
branch 69 88 78.4
condition 19 36 52.7
subroutine 23 25 92.0
pod 13 13 100.0
total 243 288 84.3


line stmt bran cond sub pod time code
1             package RRDTool::Rawish;
2 4     4   66000 use strict;
  4         4  
  4         84  
3 4     4   11 use warnings;
  4         5  
  4         75  
4 4     4   66 use 5.008;
  4         14  
5              
6 4     4   12 use Carp ();
  4         8  
  4         76  
7 4     4   1846 use Capture::Tiny qw(capture);
  4         82409  
  4         225  
8 4     4   1075 use File::Which ();
  4         1898  
  4         5711  
9              
10             our $VERSION = '0.040';
11              
12             sub new {
13 1     1 1 459 my ($class, @args) = @_;
14 1 50 33     6 my %args = @args == 1 && ref $args[0] eq 'HASH' ? %{$args[0]} : @args;
  0         0  
15              
16 1 50 33     5 my $rrdtool_path = $args{rrdtool_path} || File::Which::which('rrdtool')
17             or Carp::croak 'Not found rrdtool command';
18 1 50       24 if (not -x $rrdtool_path) {
19 1         127 Carp::croak "Cannot execute $rrdtool_path";
20             }
21              
22             return bless {
23             command => $rrdtool_path,
24             remote => $args{remote},
25             rrdfile => $args{rrdfile},
26 0         0 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 14023 my ($self, $params, $opts) = @_;
41 5 100       88 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
42 4 100       71 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
43 3 100 100     72 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
44              
45 2 100       6 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
46              
47 2         7 my $exit_status = $self->_system($self->{command}, 'create', $self->{rrdfile}, _opt_array($opts), @$params);
48 2         9 return $exit_status;
49             }
50              
51             sub update {
52 4     4 1 1633 my ($self, $params, $opts) = @_;
53 4 100       98 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
54 3 100       65 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
55 2 100 66     73 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
56              
57 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
58              
59 1         4 my $exit_status = $self->_system($self->{command}, 'update', $self->{rrdfile}, _opt_array($opts), @$params);
60 1         4 return $exit_status;
61             }
62              
63             sub graph {
64 2     2 1 982 my ($self, $filename, $params, $opts) = @_;
65 2 100       65 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     7 Carp::croak 'Not HASH reference: $opts' if defined $opts && ref($opts) ne 'HASH';
68              
69 1 50       3 $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         17 return $img;
73             }
74              
75             sub dump {
76 3     3 1 1407 my ($self, $opts) = @_;
77 3 100       65 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
78 2 100 66     73 Carp::croak 'Not HASH reference: $opts' if defined $opts && ref($opts) ne 'HASH';
79              
80 1 50       2 $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         4 return $xml;
84             }
85              
86             sub restore {
87 4     4 1 1599 my ($self, $xmlfile, $opts) = @_;
88 4 100       70 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
89 3 100       66 Carp::croak 'Require xmlfile' if not defined $xmlfile;
90 2 100 66     84 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
91              
92 1         3 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 1000 my ($self) = @_;
98 2 100       78 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
99              
100 1         2 my $opts = {};
101 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
102              
103 1         3 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         4 my $lines = [ split "\n", $text ];
107 1         4 my ($timestamp, $tmp) = split ':', $lines->[2];
108 1         4 return $timestamp;
109             }
110              
111             sub fetch {
112 4     4 1 1885 my ($self, $CF, $opts) = @_;
113 4 100       68 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
114 3 100       76 Carp::croak 'Require CF' if not defined $CF;
115 2 100 66     63 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     4 return $text if (!$text and $exit_status != 0);
121              
122 1         6 my $lines = [ split "\n", $text ];
123 1         3 return $lines;
124             }
125              
126             sub xport {
127 3     3 1 3123 my ($self, $params, $opts) = @_;
128 3 100       66 Carp::croak 'Not ARRAY reference: params' if ref($params) ne 'ARRAY';
129 2 100 66     64 Carp::croak 'Not HASH reference: opts' if defined $opts && ref($opts) ne 'HASH';
130              
131 1 50       2 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
132              
133 1         3 my ($xml, $exit_status) = $self->_readpipe($self->{command}, 'xport', _opt_array($opts), @$params);
134 1         4 return $xml;
135             }
136              
137             sub info {
138 2     2 1 967 my ($self) = @_;
139 2 100       64 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
140              
141 1 50       2 my $opts_str = $self->{remote} ? "--daemon" : "";
142              
143 1         3 my ($text, $exit_status) = $self->_readpipe($self->{command}, 'info', $self->{rrdfile}, $opts_str);
144 1 50 33     4 return $text if (!$text and $exit_status != 0);
145              
146 1         2 my $value = {};
147 1         8 my $lines = [ split "\n", $text ];
148 1         3 for (@$lines) {
149 30         44 my ($k, $v) = split ' = ', $_;
150 30         64 $v =~ s/"(.+)"/$1/g;
151 30 100       76 if ($k =~ /^rra\[(\d+)]\.(.+)\[(\d+)\]\.(.+)$/) { # rra[0].cdp_prep[0].value = NaN
    100          
    100          
152 4         12 $value->{rra}->[$1]->{$2}->[$3]->{$4} = $v;
153             }
154             elsif ($k =~ /^rra\[(\d+)\]\.(.+)$/) { # rra[0].cf = "LAST"
155 5         10 $value->{rra}->[$1]->{$2} = $v;
156             }
157             elsif ($k =~ /^ds\[(.+)\]\.(.+)$/) { # ds[rx].type = "DERIVE"
158 16         30 $value->{ds}->{$1}->{$2} = $v;
159             }
160             else {
161 5         9 $value->{$k} = $v;
162             }
163             }
164 1         4 return $value;
165             }
166              
167             sub flushcached {
168 1     1 1 662 my ($self, $opts) = @_;
169 1 50       4 Carp::croak 'Require rrdfile' if not defined $self->{rrdfile};
170 1 50       3 Carp::croak 'Require remote' if not defined $self->{remote};
171 1 50       3 $opts->{'--daemon'} = $self->{remote} if $self->{remote};
172              
173 1         4 my $exit_status = $self->_system($self->{command}, 'flushcached', _opt_array($opts), $self->{rrdfile});
174 1         5 return $exit_status;
175             }
176              
177              
178             sub _system {
179 5     5   8 my ($self, @expr) = @_;
180              
181             my ($stdout, $stderr, $exit_status) = capture {
182 5     5   3649 system(_sanitize(join(" ", @expr)));
183 5         111 };
184 5         3610 chomp $stderr;
185 5 50       15 $self->{rrderror} = $stderr if $exit_status != 0;
186 5         10 return $exit_status;
187             }
188              
189             sub _readpipe {
190 6     6   9 my ($self, @expr) = @_;
191              
192             my ($stdout, $stderr, $exit_status) = capture {
193 6     6   3450 system(_sanitize(join(" ", @expr)));
194 6         130 };
195 6         3526 chomp $stderr;
196 6 100       17 $self->{rrderror} = $stderr if $exit_status != 0;
197 6         13 return ($stdout, $exit_status);
198             }
199              
200             sub _sanitize {
201 11     11   12 my $command = shift;
202 11         27 $command =~ s/[^a-z0-9#_@\s\-\.\,\:\/=\+\-\*\%]//gi;
203 11         27 return $command;
204             }
205              
206             sub _opt_array {
207 10     10   10 my ($opts) = @_;
208              
209             return map {
210 10 100       34 ($opts->{$_} eq 1) ? $_ : ($_, $opts->{$_})
  11         44  
211             } sort(keys %$opts);
212             }
213              
214             1;
215             __END__