a790279dd1fb06cdeae9b71f21e6195144cd228b
[APKPM.git] / lib / APKPM / CPE.pm
1 package APKPM::CPE;
2
3 use base qw(Gearman::Driver::Worker);
4 use Moose;
5 use Time::HiRes qw(time);
6 use Data::Dump qw(dump);
7 use Redis;
8 use Net::Ping;
9
10 use lib 'lib';
11 use H1::EasyGateway;
12 use H1::Davolink;
13
14 with 'APKPM::Gearman::Client';
15 with 'APKPM::Gearman';
16
17 sub prefix { 'CPE_' }
18
19 sub poll : Job : Encode(e_json) {
20         my ( $self, $job, $workload ) = @_;
21
22         my $redis = Redis->new;
23         $redis->del( $_ ) foreach $redis->keys('CPE.*');
24
25         my $start = $self->datetime_now;
26
27         $redis->set( 'CPE.start' => $start );
28
29         my $entries = $self->do( 'LDAP_search' => "(&(cn=$workload*)(dhcpStatements=*))" );
30
31         my $taskset = $self->gc->new_task_set;
32         my $results;
33
34         foreach my $entry ( @$entries ) {
35
36                 my $username = $entry->{cn} || die "no cn in ", dump($entry);
37
38                 if ( $entry->{dhcpStatements} !~ m/fixed-address\s+(\S+)/ ) {
39                         $redis->sadd('CPE.error.no-ip' => $username);
40                         next;
41                 }
42                 my $ip = $1;
43
44                 if ( $entry->{dhcpOption} !~ m/vendor-class-identifier\s\"([^"]+)\"/ ) {
45                         $redis->sadd('CPE.error.vendor' => $username);
46                         next;
47                 }
48
49                 my $vendor = $1;
50
51                 $taskset->add_task('CPE_info', "$ip $username $vendor", {
52                         on_complete => sub { push @$results, ${$_[0]} }
53                 });
54                 $redis->sadd('CPE.queued' => $ip);
55
56                 $vendor =~ s/\s+/_/g; # sadd dies on spaces in keys
57                 $redis->sadd("CPE.vendor.$vendor" => $ip); # FIXME
58         }
59
60         warn "# wait";
61         $taskset->wait;
62
63         my $finish = $self->datetime_now;
64         $redis->set( 'CPE.finish' => $finish );
65
66         my $poll;
67         foreach my $k ( $redis->keys('CPE.*') ) {
68                 my $n = $k;
69                 $n =~ s/^CPE\.//;
70                 $n =~ s/\./_/g;
71                 $poll->{$n} = eval { $redis->scard($k) } || $redis->get($k);
72         }
73
74         warn "# poll = ",dump $poll;
75         $self->do_background_json('Store_insert', { _table => 'CPE_poll', %$poll });
76
77         warn "# results = ", dump $results;
78         return $poll;
79 }
80
81 sub info : Job : Decode(d_array) : Encode(e_json) {
82         my ( $self, $job, $workload ) = @_;
83
84         my ( $ip, $username, $vendor ) = @$workload;
85
86         my $redis = Redis->new;
87
88         return { error => "invalid workload", expected => "ip username" } unless $ip && $username;
89
90         my $p = Net::Ping->new;
91         $p->hires;
92
93         my ( $ok, $rtt, $ping_ip ) = $p->ping( $ip );
94
95         if ( $ok ) {
96                 $redis->sadd( 'CPE.ping.ok' => $ip );
97         } else {
98                 $redis->sadd( 'CPE.ping.error' => $ip );
99                 return { error => "ping $ip" };
100         }
101
102         $self->do_background_json( 'Store_insert', {
103                  _table => 'ping',
104                 username => $username,
105                 timestamp => $self->datetime_now,
106                 ip => $ping_ip,
107                 rtt => $rtt,
108         });
109
110         if ( $vendor =~ m/SAMSUNG/ ) {
111                 $vendor = 'Davolink';
112         } elsif ( $vendor =~ m/zte/ ) {
113                 $vendor = 'EasyGateway';
114         } else {
115                 $redis->sadd( 'CPE.skipped' => $username );
116                 $vendor = undef;
117         }
118
119         if ( $vendor ) {
120                 $redis->sadd( "CPE.$vendor.queued" => $ip );
121
122                 my $module = 'H1::' . $vendor;
123                 my $ret = eval { $module->info( $ip ) };
124
125                 warn "# $module ",dump($ret);
126
127                 if ( $ret ) {
128                         $self->do_background_json( 'Store_insert', {
129                                 _table => $vendor,
130                                 ip => $ip,
131                                 username => $username,
132                                 timestamp => $self->datetime_now,
133                                 h => $self->to_hstore( $ret ),
134                         });
135                         $redis->sadd( "CPE.$vendor.ok" => $ip );
136                 } else {
137                         $redis->sadd( "CPE.$vendor.error" => $ip );
138                 }
139         }
140
141         return { ip => $ip, rtt => $rtt };
142 }
143
144 1;