File Coverage

blib/lib/Elasticsearch/Role/CxnPool/Sniff.pm
Criterion Covered Total %
statement 43 43 100.0
branch 17 20 85.0
condition 7 8 87.5
subroutine 9 9 100.0
pod 3 4 75.0
total 79 84 94.0


line stmt bran cond sub pod time code
1             package Elasticsearch::Role::CxnPool::Sniff;
2             $Elasticsearch::Role::CxnPool::Sniff::VERSION = '1.05';
3 10     10   8786 use Moo::Role;
  10         27  
  10         92  
4             with 'Elasticsearch::Role::CxnPool';
5             requires 'next_cxn', 'sniff', 'sniff_cxn';
6 10     10   9982 use namespace::clean;
  10         27  
  10         88  
7              
8 10     10   2402 use Elasticsearch::Util qw(parse_params);
  10         24  
  10         77  
9 10     10   2976 use List::Util qw(min);
  10         24  
  10         885  
10 10     10   58 use Try::Tiny;
  10         36  
  10         6548  
11              
12             has 'sniff_interval' => ( is => 'ro', default => 300 );
13             has 'next_sniff' => ( is => 'rw', default => 0 );
14             has 'sniff_max_content_length' => ( is => 'ro' );
15              
16             #===================================
17             sub BUILDARGS {
18             #===================================
19 12     12 0 88 my ( $class, $params ) = parse_params(@_);
20 12 50       89 $params->{sniff_max_content_length} = !$params->{max_content_length}
21             unless defined $params->{sniff_max_content_length};
22 12         45 return $params;
23             }
24              
25             #===================================
26             sub schedule_check {
27             #===================================
28 14     14 1 59 my $self = shift;
29 14         105 $self->logger->info("Require sniff before next request");
30 14         4238 $self->next_sniff(-1);
31             }
32              
33             #===================================
34             sub parse_sniff {
35             #===================================
36 39     39 1 603 my $self = shift;
37 39         72 my $protocol = shift;
38 39 100       335 my $nodes = shift or return;
39              
40 26         51 my @live_nodes;
41 26         52 my $max = 0;
42 26         125 my $sniff_max = $self->sniff_max_content_length;
43              
44 26         113 for my $node_id ( keys %$nodes ) {
45 48         95 my $data = $nodes->{$node_id};
46              
47 48 100       184 my $host = $data->{ $protocol . "_address" } or next;
48 47 100       309 $host =~ s{^inet\[[^/]*/([^\]]+)\]}{$1} or next;
49              
50 46 50       157 $host = $self->should_accept_node( $host, $node_id, $data )
51             or next;
52              
53 46         100 push @live_nodes, $host;
54 46 100 100     417 next unless $sniff_max and $data->{$protocol};
55              
56 2   50     9 my $node_max = $data->{$protocol}{max_content_length_in_bytes} || 0;
57 2 100       39 $max
    50          
58             = $node_max == 0 ? $max
59             : $max == 0 ? $node_max
60             : min( $node_max, $max );
61             }
62              
63 26 100       143 return unless @live_nodes;
64              
65 24 100 100     156 $self->cxn_factory->max_content_length($max)
66             if $sniff_max and $max;
67              
68 24         151 $self->set_cxns(@live_nodes);
69 24         196 my $next = $self->next_sniff( time() + $self->sniff_interval );
70 24         2922 $self->logger->infof( "Next sniff at: %s", scalar localtime($next) );
71              
72 24         2813 return 1;
73             }
74              
75             #===================================
76 46     46 1 166 sub should_accept_node { return $_[1] }
77             #===================================
78              
79             1;
80              
81             =pod
82              
83             =encoding UTF-8
84              
85             =head1 NAME
86              
87             Elasticsearch::Role::CxnPool::Sniff - A CxnPool role for connecting to a local cluster with a dynamic node list
88              
89             =head1 VERSION
90              
91             version 1.05
92              
93             =head1 CONFIGURATION
94              
95             =head2 C<sniff_interval>
96              
97             How often should we perform a sniff in order to detect whether new nodes
98             have been added to the cluster. Defaults to `300` seconds.
99              
100             =head2 C<sniff_max_content_length>
101              
102             Whether we should set the
103             L<max_content_length|Elasticsearch::Role::Cxn::HTTP/max_content_length>
104             dynamically while sniffing. Defaults to true unless a fixed
105             C<max_content_length> was specified.
106              
107             =head1 METHODS
108              
109             =head2 C<schedule_check()>
110              
111             $cxn_pool->schedule_check
112              
113             Schedules a sniff before the next request is processed.
114              
115             =head2 C<parse_sniff()>
116              
117             $bool = $cxn_pool->parse_sniff(\%nodes);
118              
119             Parses the response from a sniff request and extracts the hostname/ip
120             of all listed nodes, filtered through L</should_accept_node()>. If any live
121             nodes are found, they are passed to L<Elasticsearch::Role::CxnPool/set_cxns()>.
122             The L<max_content_length|Elasticsearch::Role::Cxn::HTTP/max_content_length>
123             is also detected if L</sniff_max_content_length> is true.
124              
125             =head2 C<should_accept_node()>
126              
127             $host = $cxn_pool->should_accept_node($host,$node_id,\%node_data)
128              
129             This method serves as a hook which can be overridden by the user. When
130             a sniff is performed, this method is called with the C<host>
131             (eg C<192.168.5.100:9200>), the C<node_id> (the ID assigned to the node
132             by Elasticsearch) and the C<node_data> which contains the information
133             about the node that Elasticsearch has returned, eg:
134              
135             {
136             "transport_address" => "inet[192.168.5.100/192.168.5.100:9300]",
137             "http" : {
138             "publish_address" => "inet[/192.168.5.100:9200]",
139             "max_content_length" => "100mb",
140             "bound_address" => "inet[/0:0:0:0:0:0:0:0:9200]",
141             "max_content_length_in_bytes" : 104857600
142             },
143             "version" => "0.90.4",
144             "name" => "Silver Sable",
145             "hostname" => "search1.domain.com",
146             "http_address" => "inet[/192.168.5.100:9200]"
147             }
148              
149             If the node should be I<accepted> (ie used to serve data), then it should
150             return the C<host> value to use. By default, nodes are always
151             accepted.
152              
153             =head1 AUTHOR
154              
155             Clinton Gormley <drtech@cpan.org>
156              
157             =head1 COPYRIGHT AND LICENSE
158              
159             This software is Copyright (c) 2014 by Elasticsearch BV.
160              
161             This is free software, licensed under:
162              
163             The Apache License, Version 2.0, January 2004
164              
165             =cut
166              
167             __END__
168              
169             # ABSTRACT: A CxnPool role for connecting to a local cluster with a dynamic node list
170