File Coverage

lib/Net/ISC/DHCPd/Leases.pm
Criterion Covered Total %
statement 45 50 90.0
branch 10 14 71.4
condition n/a
subroutine 8 9 88.8
pod 3 3 100.0
total 66 76 86.8


line stmt bran cond sub pod time code
1             package Net::ISC::DHCPd::Leases;
2              
3             =head1 NAME
4              
5             Net::ISC::DHCPd::Leases - Parse ISC DHCPd leases
6              
7             =head1 SYNOPSIS
8              
9             my $leases = Net::ISC::DHCPd::Leases->new(
10             file => '/var/lib/dhcp3/dhcpd.leases',
11             );
12              
13             # parse the leases file
14             $leases->parse;
15              
16             for my $lease ($leases->leases) {
17             say "lease has ended" if($lease->ends < time);
18             }
19              
20             if(my $n = $leases->find_leases({ ends => time }) {
21             say "$n lease(s) has expired now";
22             }
23              
24             =head1 DESCRIPTION
25              
26             An object constructed from this class represents a leases file for
27             the dhcpd server. It is read-only, so changes to the leases file
28             must be done through a running server, using L<Net::ISC::DHCPd::OMAPI>.
29              
30             The object has one important attribute, which is L</leases>. This
31             attribute holds a list of L<Net::ISC::DHCPd::Leases::Lease> objects
32             constructed from all the leases found in the leases file.
33              
34             To parse the leases file, this module use L<POE::Filter::DHCPd::Lease>,
35             but this can be customized by setting C<_parser> in the constructor.
36             Even though it is possible, it is recommended to add features/
37             bugfixes to L<POE::Filter::DHCPd::Lease|https://rt.cpan.org/Public/Dist/Display.html?Name=POE-Filter-DHCPd-Lease>
38             instead.
39              
40             =cut
41              
42 6     6   3389 use Moose;
  6         531285  
  6         55  
43 6     6   42333 use Net::ISC::DHCPd::Leases::Lease;
  6         30  
  6         280  
44 6     6   6970 use POE::Filter::DHCPd::Lease;
  6         37043  
  6         236  
45 6     6   948 use MooseX::Types::Path::Class qw(File);
  6         74238  
  6         88  
46              
47             =head1 ATTRIBUTES
48              
49             =head2 leases
50              
51             Holds a list of all the leases found after reading the leases file.
52              
53             =cut
54              
55             has leases => (
56             is => 'ro',
57             isa => 'ArrayRef',
58             auto_deref => 1,
59             default => sub { [] },
60             );
61              
62             =head2 file
63              
64             This attribute holds a L<Path::Class::File> object to the leases file.
65             It is read-write and the default value is "/var/lib/dhcp3/dhcpd.leases".
66              
67             =cut
68              
69             has file => (
70             is => 'rw',
71             isa => File,
72             coerce => 1,
73             default => sub {
74             Path::Class::File->new('', 'var', 'lib', 'dhcp3', 'dhcpd.leases');
75             },
76             );
77              
78             has fh => (
79             is => 'rw',
80             isa => 'FileHandle',
81             required => 0,
82             );
83              
84             has _filehandle => (
85             is => 'ro',
86             lazy_build => 1,
87             );
88              
89             sub _build__filehandle {
90 1     1   3 my $self = shift;
91 1 50       27 if ($self->fh) {
92 0         0 return $self->fh;
93             }
94              
95 1         28 $self->file->openr;
96             }
97              
98             __PACKAGE__->meta->add_method(filehandle => sub {
99 0     0   0 Carp::cluck('->filehandle is replaced with private attribute _filehandle');
100 0         0 shift->_filehandle;
101             });
102              
103             has _parser => (
104             is => 'ro',
105             isa => 'Object',
106             default => sub { POE::Filter::DHCPd::Lease->new },
107             );
108              
109             =head1 METHODS
110              
111             =head2 parse
112              
113             Read lines from L</file>, and parses every lease it can find.
114             Returns the number of leases found. Will add each found lease to
115             L</leases>.
116              
117             =cut
118              
119             sub parse {
120 1     1 1 1321 my $self = shift;
121 1         35 my $fh = $self->_filehandle;
122 1         30 my $parser = $self->_parser;
123 1         2 my $n = 0;
124              
125 1         630 while(my $line = readline $fh) {
126 104         23931 $n++;
127              
128 104         346 $parser->get_one_start([$line]);
129 104 100       771 if ($line =~ /^\s*}/) {
130 10         37 my $leases = $parser->get_one;
131             #print scalar @$leases;
132 10 50       4474 if (@$leases) {
133 10         33 $self->add_lease($leases->[0]);
134             }
135             }
136             }
137              
138 1         1308 return $n;
139             }
140              
141             =head2 find_leases
142              
143             This method will return zero or more L<Net::ISC::DHCPd::Leases::Lease>
144             objects as a list. It takes a hash-ref which will be matched against
145             the attributes of the child leases.
146              
147             =cut
148              
149             sub find_leases {
150 1     1 1 3754 my $self = shift;
151 1 50       6 my $query = shift or return;
152 1         2 my @leases;
153              
154             LEASE:
155 1         41 for my $lease ($self->leases) {
156 10         53 for my $key (keys %$query) {
157 10 100       28 next LEASE unless($lease->$key eq $query->{$key});
158             }
159 1         8 push @leases, $lease;
160             }
161              
162 1         10 return @leases;
163             }
164              
165             =head2 add_lease
166              
167             This method does not make much sense, and will probably get removed.
168             See L</DESCRIPTION> for more details.
169              
170             =cut
171              
172             sub add_lease {
173 10     10 1 21 my $self = shift;
174              
175 10 50       63 if(blessed $_[0]) {
176 0         0 return push @{$self->leases}, $_[0];
  0         0  
177             }
178              
179 10         13 my %lease = %{ $_[0] }; # shallow copy
  10         64  
180 10         46 my %map = (
181             ip => 'ip_address',
182             binding => 'state',
183             hostname => 'client_hostname',
184             hw_ethernet => 'hardware_address',
185             );
186              
187 10         27 for my $key (keys %map) {
188 40 100       82 if(defined $lease{$key}) {
189 30         71 $lease{ $map{$key} } = delete $lease{$key};
190             }
191             }
192              
193 10         16 return push @{$self->leases}, Net::ISC::DHCPd::Leases::Lease->new(\%lease);
  10         394  
194             }
195              
196             =head1 COPYRIGHT & LICENSE
197              
198             =head1 AUTHOR
199              
200             See L<Net::ISC::DHCPd>.
201              
202             =cut
203              
204             1;