38aa41ba5fa2c0640a2b3dd9e0f8ce8b2703b09d
[snmp-json.git] / printer-callbacks.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 use Net::SNMP;
6 use Data::Dump qw(dump);
7
8 my $dir = 'public/json/monitor/printers/';
9 $dir = "/tmp/printers-" unless -d $dir;
10
11 use JSON;
12 sub save_json {
13         my ( $ip, $json ) = @_;
14         my $path = $dir . $ip;
15         open(my $fh, '>', $path) || die "$path: $!";
16         print $fh encode_json $json;
17         close($fh);
18         warn "# $path ", -s $path, " bytes\n";
19 }
20
21 sub iso_datetime {
22         my ($ss,$mm,$hh,$d,$m,$y) = localtime(time);
23         return sprintf "%04d-%02d-%02dT%02d:%02d:%02d", $y+1900, $m, $d, $hh, $mm, $ss;
24 }
25
26 my $log_path = join('.', $dir . (split(/T/,iso_datetime,2))[0], 'json');
27 open(my $log, '>>', $log_path) || die "$log_path: $!";
28
29 my $community = 'public';
30 my @printers = qw(
31 10.60.0.20
32
33 10.60.0.40
34
35 10.60.3.15
36 10.60.3.17
37 );
38
39 @printers = @ARGV if @ARGV;
40
41 my %vars = qw[
42 info                            iso.3.6.1.2.1.1.1.0
43 hostname                        iso.3.6.1.2.1.43.5.1.1.16.1
44 serial                          iso.3.6.1.2.1.43.5.1.1.17.1
45 pages                           iso.3.6.1.2.1.43.10.2.1.4.1
46 @message                        iso.3.6.1.2.1.43.18.1.1.8
47 @consumable.name        iso.3.6.1.2.1.43.11.1.1.6.1
48 @consumable.max         iso.3.6.1.2.1.43.11.1.1.8.1
49 @consumable.curr        iso.3.6.1.2.1.43.11.1.1.9.1
50 @tray.dim_x                     iso.3.6.1.2.1.43.8.2.1.4.1
51 @tray.dim_y                     iso.3.6.1.2.1.43.8.2.1.5.1
52 @tray.max                       iso.3.6.1.2.1.43.8.2.1.9.1
53 @tray.capacity          iso.3.6.1.2.1.43.8.2.1.10.1
54 @tray.name                      iso.3.6.1.2.1.43.8.2.1.13.1
55 ];
56
57 our $response;
58
59 sub columns_cb {
60         my ( $session, $oid2name ) = @_;
61
62         my $ip = $session->hostname;
63
64         if ( ! defined $session->var_bind_list ) {
65                 warn "ERROR: $ip ", $session->error, "\n";
66                 warn dump($session);
67                 return;
68         }
69
70
71         warn "# $ip var_bind_list ", dump( $session->var_bind_list );
72         my $results = $session->var_bind_list;
73         $response->{$ip} = { ip => $ip, utime => time() };
74         # oid_lex_sort would be wonderfull to use here, but it doesn't work
75         foreach my $r_oid ( sort {
76                         my ($af,$bf) = ($a,$b);
77                         $af =~ s{\.(\d+)$}{sprintf("%03d",$1)}eg;
78                         $bf =~ s{\.(\d+)$}{sprintf("%03d",$1)}eg;
79                         $af cmp $bf
80         } keys %$results ) {
81                 my $var = $results->{$r_oid};
82                 my $oid = (grep {
83                         substr($r_oid,0,length($_)) eq $_
84                 } keys %$oid2name)[0] || die "no name for $r_oid in ",dump($oid2name);
85                 my $name = $oid2name->{$oid};
86                 if ( $name =~ m{^\@} ) {
87                         my $no_prefix = $name;
88                         $no_prefix =~ s{^\@}{};
89                         push @{ $response->{$ip}->{ $no_prefix } }, $var;
90                 } else {
91                         $response->{$ip}->{ $name } = $var;
92                 }
93         }
94
95         warn "## $ip response ",dump($response->{$ip});
96 }
97
98 foreach my $host ( @printers ) {
99
100         my ( $snmp, $err ) = Net::SNMP->session(
101                 -hostname => $host,
102                 -version => 1,
103                 -community => $community,
104                 -timeout => 2,
105                 -retries => 0,
106                 -nonblocking => 1,
107         );
108
109         if ( ! $snmp ) {
110                 warn "ERROR: $host $err\n";
111                 next;
112         }
113
114         my @columns;
115         my @vars;
116         my $oid2name;
117         while ( my ($name,$oid) = each %vars ) {
118                 warn "# $name $oid\n";
119                 $oid =~ s{^iso}{.1};
120                 if ( $name =~ m/^\@/ ) {
121                         push @columns, $oid;
122                 } else {
123                         push @vars, $oid;
124                 }
125                 $oid2name->{$oid} = $name;
126         }
127         $snmp->get_request( -varbindlist => [ @vars ], -callback => [ \&columns_cb, $oid2name ] );
128         $snmp->get_entries( -columns =>  [ @columns ], -callback => [ \&columns_cb, $oid2name ] );
129
130 }
131
132 warn "# dispatch requests for ",dump(@printers);
133 snmp_dispatcher;
134
135 foreach my $ip ( keys %$response ) {
136
137         my $status = $response->{$ip};
138         foreach my $group ( grep { /\w+\.\w+/ } keys %$status ) {
139                 my ( $prefix,$name ) = split(/\./,$group,2);
140                 if ( ref $status->{$group} eq 'ARRAY' ) { # some consumables are non-repeatable on low-end devices
141                         foreach my $i ( 0 .. $#{ $status->{$group} } ) {
142                                 $status->{$prefix}->[$i]->{$name} = $status->{$group}->[$i];
143                         }
144                 } else {
145                         $status->{$prefix}->[0]->{$name} = $status->{$group};
146                 }
147                 delete $status->{$group};
148         }
149
150         print "$ip ",dump($status);
151         save_json $ip => $response->{$ip};
152         print $log encode_json($response->{$ip}),"\n";
153 }
154
155 close($log);
156 warn "# log $log_path ", -s $log_path, " bytes\n";
157