File Coverage

blib/lib/DNS/Oterica/Hub.pm
Criterion Covered Total %
statement 52 77 67.5
branch 9 22 40.9
condition 3 18 16.6
subroutine 13 18 72.2
pod 8 10 80.0
total 85 145 58.6


line stmt bran cond sub pod time code
1             package DNS::Oterica::Hub;
2             # ABSTRACT: the center of control for a DNS::Oterica system
3             $DNS::Oterica::Hub::VERSION = '0.303';
4 1     1   4 use Moose;
  1         2  
  1         4  
5             with 'DNS::Oterica::Role::RecordMaker';
6              
7             # use MooseX::AttributeHelpers;
8              
9 1     1   4120 use DNS::Oterica::Network;
  1         2  
  1         35  
10 1     1   483 use DNS::Oterica::Node;
  1         2  
  1         46  
11 1     1   472 use DNS::Oterica::Node::Domain;
  1         2  
  1         25  
12 1     1   359 use DNS::Oterica::Node::Host;
  1         2  
  1         42  
13 1     1   475 use DNS::Oterica::NodeFamily;
  1         3  
  1         162  
14              
15             #pod =head1 OVERVIEW
16             #pod
17             #pod The hub is the central collector of DNS::Oterica data. All new entries are
18             #pod given to the hub to collect. The hub takes care of preventing duplicates and
19             #pod keeping data synchronized.
20             #pod
21             #pod =cut
22              
23             has [ qw(_domain_registry _net_registry _node_family_registry) ] => (
24             is => 'ro',
25             isa => 'HashRef',
26             init_arg => undef,
27             default => sub { {} },
28             );
29              
30             #pod =attr ns_family
31             #pod
32             #pod This is the name of the family whose hosts will be used for NS records for
33             #pod hosts and in SOA lines.
34             #pod
35             #pod =cut
36              
37             has ns_family => (
38             is => 'ro',
39             isa => 'Str',
40             required => 1,
41             );
42              
43             #pod =attr hostmaster
44             #pod
45             #pod This is the email address to be used as the contact point in SOA lines.
46             #pod
47             #pod =cut
48              
49             has hostmaster => (
50             is => 'ro',
51             isa => 'Str',
52             required => 1,
53             );
54              
55             sub soa_rname {
56 0     0 0 0 my ($self) = @_;
57 0         0 my $addr = $self->hostmaster;
58 0         0 $addr =~ s/@/./;
59 0         0 return $addr;
60             }
61              
62             use Module::Pluggable
63             search_path => [ qw(DNS::Oterica::NodeFamily) ],
64             require => 1,
65             $ENV{DNSO_TESTING_PLUGINS}
66 1 50       13 ? (only => [ split /,/, $ENV{DNSO_TESTING_PLUGINS} ])
67 1     1   567 : ();
  1         5941  
68              
69             has fallback_network_name => (is => 'ro', isa => 'Str', default => 'FALLBACK');
70             has all_network_name => (is => 'ro', isa => 'Str', default => 'ALL');
71              
72             sub BUILD {
73 1     1 0 2 my ($self) = @_;
74              
75 1         5 for my $plugin ($self->plugins) {
76             confess "tried to register " . $plugin->name . " twice" if exists
77 0 0       0 $self->_node_family_registry->{$plugin->name};
78 0         0 $self->_node_family_registry->{ $plugin->name }
79             = $plugin->new({ hub => $self });
80             }
81              
82             $self->add_network({
83 1         324 name => $self->fallback_network_name,
84             code => 'FB', # should it be configurable? eh.
85             subnets => [ '0.0.0.0/0' ],
86             });
87              
88 1         58 $self->add_network({
89             name => $self->all_network_name,
90             code => '',
91             subnets => [ '0.0.0.0/32' ],
92             });
93             }
94              
95             #pod =method domain
96             #pod
97             #pod my $new_domain = $hub->domain($name => \%arg);
98             #pod
99             #pod my $domain = $hub->domain($name);
100             #pod
101             #pod This method will return a domain found by name, or if C<\%arg> is given, will
102             #pod create a new domain.
103             #pod
104             #pod If no domain is found and C<\%arg> is not given, an exception is raised.
105             #pod
106             #pod If C<\%arg> is given for a domain that already exists, an exception is raised.
107             #pod
108             #pod =cut
109              
110             sub domain {
111 1     1 1 3 my ($self, $name, $arg) = @_;
112 1         25 my $domreg = $self->_domain_registry;
113              
114 1 50 33     4 confess "tried to create domain $name twice" if $domreg->{$name} and $arg;
115              
116             # XXX: This should be possible to do. -- rjbs, 2009-09-11
117             # confess "no such domain: $name" if ! defined $arg and ! $domreg->{$name};
118              
119             return $domreg->{$name} ||= DNS::Oterica::Node::Domain->new({
120             domain => $name,
121 1 50 33     5 %{ $arg || {} },
  1         35  
122             hub => $self,
123             });
124             }
125              
126             #pod =method network
127             #pod
128             #pod my $net = $hub->network($name);
129             #pod
130             #pod This method finds the named network and returns it. If no network for the
131             #pod given name is registered, an exception is raised.
132             #pod
133             #pod =cut
134              
135             sub network {
136 0     0 1 0 my ($self, $name) = @_;
137 0   0     0 return $self->_net_registry->{$name} || confess "no such network '$name'";
138             }
139              
140             #pod =method networks
141             #pod
142             #pod my @net = $hub->networks;
143             #pod
144             #pod =cut
145              
146             sub networks {
147 4     4 1 5 my ($self) = @_;
148 4         3 return values %{ $self->_net_registry };
  4         79  
149             }
150              
151             #pod =method add_network
152             #pod
153             #pod my $net = $hub->add_network(\%arg);
154             #pod
155             #pod This registers a new network, raising an exception if one already exists for
156             #pod the given name.
157             #pod
158             #pod =cut
159              
160             sub add_network {
161 4     4 1 5 my ($self, $arg) = @_;
162              
163 4         109 my $net = DNS::Oterica::Network->new({ %$arg, hub => $self });
164              
165 4         91 my $name = $net->name;
166 4 50       84 confess "tried to create $name twice" if $self->_net_registry->{$name};
167              
168 4         86 my $code = $net->code;
169              
170 4         5 my @errors;
171 4         7 for my $existing ($self->networks) {
172 6 50       363 if ($net->code eq $existing->code) {
173 0         0 push @errors, sprintf "code '%s' conflicts with network %s",
174             $code, $existing->name;
175             }
176              
177 6 100       121 next if $existing->name eq $self->all_network_name;
178              
179 4         111 for my $our ($net->subnets) {
180 4         105 for my $their ($existing->subnets) {
181 4 50       9 if ($our->overlaps($their) == $Net::IP::IP_IDENTICAL) {
182 0         0 push @errors, sprintf "network '%s' conflicts with network %s (%s)",
183             $our->ip, $existing->name, $their->ip;
184             }
185             }
186             }
187             }
188              
189 4 50       162 if (@errors) {
190 0         0 confess("errors registering network $name: " . join q{; }, @errors);
191             }
192              
193 4         95 $self->_net_registry->{$name} = $net;
194             }
195              
196             #pod =method host
197             #pod
198             #pod my $host = $hub->host($domain_name, $hostname);
199             #pod
200             #pod my $new_host = $hub->host($domain_name, $hostname, \%arg);
201             #pod
202             #pod This method will find or create a host, much like the C<L</domain>> method.
203             #pod
204             #pod =cut
205              
206             sub host {
207 0     0 1 0 my ($self, $domain_name, $name, $arg) = @_;
208 0         0 my $domain = $self->domain($domain_name);
209              
210             confess "tried to create $name . $domain_name twice"
211 0 0 0     0 if $domain->{$name} and $arg;
212              
213 0   0     0 return $domain->{nodes}{$name} ||= DNS::Oterica::Node::Host->new({
214             domain => $domain_name,
215             hostname => $name,
216             %$arg,
217             hub => $self,
218             });
219             }
220              
221             #pod =method nodes
222             #pod
223             #pod This method will return a list of all nodes registered with the system.
224             #pod
225             #pod B<Warning>: at present this will return only hosts.
226             #pod
227             #pod =cut
228              
229             sub nodes {
230 0     0 1 0 my ($self) = @_;
231              
232 0         0 my @nodes;
233              
234 0         0 for my $domain (values %{ $self->_domain_registry }) {
  0         0  
235 0 0       0 push @nodes, values %{ $domain->{nodes} || {} };
  0         0  
236             }
237              
238 0         0 return @nodes;
239             }
240              
241             #pod =method node_family
242             #pod
243             #pod my $family = $hub->node_family($family_name);
244             #pod
245             #pod This method will return the named familiy. If no such family exists, an
246             #pod exception will be raised.
247             #pod
248             #pod =cut
249              
250             sub node_family {
251 1     1 1 1 my ($self, $name) = @_;
252              
253 1   33     24 return $self->_node_family_registry->{$name}
254             || confess "unknown family $name";
255             }
256              
257             #pod =method node_families
258             #pod
259             #pod my @families = $hub->node_families;
260             #pod
261             #pod This method will return all node families. (These are set up during hub
262             #pod initialization.)
263             #pod
264             #pod =cut
265              
266             sub node_families {
267 0     0 1   my ($self) = @_;
268 0           return values %{ $self->_node_family_registry };
  0            
269             }
270              
271             __PACKAGE__->meta->make_immutable;
272 1     1   673 no Moose;
  1         1  
  1         6  
273             1;
274              
275             __END__
276              
277             =pod
278              
279             =encoding UTF-8
280              
281             =head1 NAME
282              
283             DNS::Oterica::Hub - the center of control for a DNS::Oterica system
284              
285             =head1 VERSION
286              
287             version 0.303
288              
289             =head1 OVERVIEW
290              
291             The hub is the central collector of DNS::Oterica data. All new entries are
292             given to the hub to collect. The hub takes care of preventing duplicates and
293             keeping data synchronized.
294              
295             =head1 ATTRIBUTES
296              
297             =head2 ns_family
298              
299             This is the name of the family whose hosts will be used for NS records for
300             hosts and in SOA lines.
301              
302             =head2 hostmaster
303              
304             This is the email address to be used as the contact point in SOA lines.
305              
306             =head1 METHODS
307              
308             =head2 domain
309              
310             my $new_domain = $hub->domain($name => \%arg);
311              
312             my $domain = $hub->domain($name);
313              
314             This method will return a domain found by name, or if C<\%arg> is given, will
315             create a new domain.
316              
317             If no domain is found and C<\%arg> is not given, an exception is raised.
318              
319             If C<\%arg> is given for a domain that already exists, an exception is raised.
320              
321             =head2 network
322              
323             my $net = $hub->network($name);
324              
325             This method finds the named network and returns it. If no network for the
326             given name is registered, an exception is raised.
327              
328             =head2 networks
329              
330             my @net = $hub->networks;
331              
332             =head2 add_network
333              
334             my $net = $hub->add_network(\%arg);
335              
336             This registers a new network, raising an exception if one already exists for
337             the given name.
338              
339             =head2 host
340              
341             my $host = $hub->host($domain_name, $hostname);
342              
343             my $new_host = $hub->host($domain_name, $hostname, \%arg);
344              
345             This method will find or create a host, much like the C<L</domain>> method.
346              
347             =head2 nodes
348              
349             This method will return a list of all nodes registered with the system.
350              
351             B<Warning>: at present this will return only hosts.
352              
353             =head2 node_family
354              
355             my $family = $hub->node_family($family_name);
356              
357             This method will return the named familiy. If no such family exists, an
358             exception will be raised.
359              
360             =head2 node_families
361              
362             my @families = $hub->node_families;
363              
364             This method will return all node families. (These are set up during hub
365             initialization.)
366              
367             =head1 AUTHOR
368              
369             Ricardo SIGNES <rjbs@cpan.org>
370              
371             =head1 COPYRIGHT AND LICENSE
372              
373             This software is copyright (c) 2016 by Ricardo SIGNES.
374              
375             This is free software; you can redistribute it and/or modify it under
376             the same terms as the Perl 5 programming language system itself.
377              
378             =cut