File Coverage

blib/lib/Search/Elasticsearch/Role/CxnPool/Sniff.pm
Criterion Covered Total %
statement 47 47 100.0
branch 16 18 88.8
condition 11 13 84.6
subroutine 10 10 100.0
pod 3 4 75.0
total 87 92 94.5


line stmt bran cond sub pod time code
1             # Licensed to Elasticsearch B.V. under one or more contributor
2             # license agreements. See the NOTICE file distributed with
3             # this work for additional information regarding copyright
4             # ownership. Elasticsearch B.V. licenses this file to you under
5             # the Apache License, Version 2.0 (the "License"); you may
6             # not use this file except in compliance with the License.
7             # You may obtain a copy of the License at
8             #
9             # http://www.apache.org/licenses/LICENSE-2.0
10             #
11             # Unless required by applicable law or agreed to in writing,
12             # software distributed under the License is distributed on an
13             # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14             # KIND, either express or implied. See the License for the
15             # specific language governing permissions and limitations
16             # under the License.
17              
18             package Search::Elasticsearch::Role::CxnPool::Sniff;
19             $Search::Elasticsearch::Role::CxnPool::Sniff::VERSION = '8.00';
20 11     11   5863 use Moo::Role;
  11         27  
  11         71  
21             with 'Search::Elasticsearch::Role::CxnPool';
22             requires 'next_cxn', 'sniff';
23 11     11   4122 use namespace::clean;
  11         33  
  11         84  
24              
25 11     11   3034 use Search::Elasticsearch::Util qw(parse_params);
  11         23  
  11         72  
26 11     11   2752 use List::Util qw(min);
  11         26  
  11         907  
27 11     11   75 use Try::Tiny;
  11         29  
  11         6044  
28              
29             has 'sniff_interval' => ( is => 'ro', default => 300 );
30             has 'next_sniff' => ( is => 'rw', default => 0 );
31             has 'sniff_max_content_length' => ( is => 'ro' );
32              
33             #===================================
34             sub BUILDARGS {
35             #===================================
36 12     12 0 54 my ( $class, $params ) = parse_params(@_);
37             $params->{sniff_max_content_length} = !$params->{max_content_length}
38 12 50       65 unless defined $params->{sniff_max_content_length};
39 12         36 return $params;
40             }
41              
42             #===================================
43             sub schedule_check {
44             #===================================
45 14     14 1 46 my $self = shift;
46 14         278 $self->logger->info("Require sniff before next request");
47 14         402 $self->next_sniff(-1);
48             }
49              
50             #===================================
51             sub parse_sniff {
52             #===================================
53 38     38 1 346 my $self = shift;
54 38 100       178 my $nodes = shift or return;
55 25         48 my @live_nodes;
56 25         52 my $max = 0;
57 25         92 my $sniff_max = $self->sniff_max_content_length;
58              
59 25         108 for my $node_id ( keys %$nodes ) {
60 47         91 my $data = $nodes->{$node_id};
61              
62 47   66     205 my $addr = $data->{http}{publish_address} || $data->{http_address};
63 47 100       137 my $host = $self->_extract_host($addr)
64             or next;
65              
66 46 50       119 $host = $self->should_accept_node( $host, $node_id, $data )
67             or next;
68              
69 46         107 push @live_nodes, $host;
70 46 100 66     213 next unless $sniff_max and $data->{http};
71              
72 43   100     154 my $node_max = $data->{http}{max_content_length_in_bytes} || 0;
73 43 100       144 $max
    100          
74             = $node_max == 0 ? $max
75             : $max == 0 ? $node_max
76             : min( $node_max, $max );
77             }
78              
79 25 100       91 return unless @live_nodes;
80              
81 24 100 100     117 $self->cxn_factory->max_content_length($max)
82             if $sniff_max and $max;
83              
84 24         117 $self->set_cxns(@live_nodes);
85 24         120 my $next = $self->next_sniff( time() + $self->sniff_interval );
86 24         1499 $self->logger->infof( "Next sniff at: %s", scalar localtime($next) );
87              
88 24         1027 return 1;
89             }
90              
91             #===================================
92             sub _extract_host {
93             #===================================
94 53     53   118 my $self = shift;
95 53   100     165 my $host = shift || return;
96 51         259 $host =~ s{^inet\[(.+)\]$}{$1};
97 51         187 $host =~ s{^[^/]*/}{};
98 51         198 return $host;
99             }
100              
101             #===================================
102 46     46 1 171 sub should_accept_node { return $_[1] }
103             #===================================
104              
105             1;
106              
107             =pod
108              
109             =encoding UTF-8
110              
111             =head1 NAME
112              
113             Search::Elasticsearch::Role::CxnPool::Sniff - A CxnPool role for connecting to a local cluster with a dynamic node list
114              
115             =head1 VERSION
116              
117             version 8.00
118              
119             =head1 CONFIGURATION
120              
121             =head2 C
122              
123             How often should we perform a sniff in order to detect whether new nodes
124             have been added to the cluster. Defaults to `300` seconds.
125              
126             =head2 C
127              
128             Whether we should set the
129             L
130             dynamically while sniffing. Defaults to true unless a fixed
131             C was specified.
132              
133             =head1 METHODS
134              
135             =head2 C
136              
137             $cxn_pool->schedule_check
138              
139             Schedules a sniff before the next request is processed.
140              
141             =head2 C
142              
143             $bool = $cxn_pool->parse_sniff(\%nodes);
144              
145             Parses the response from a sniff request and extracts the hostname/ip
146             of all listed nodes, filtered through L. If any live
147             nodes are found, they are passed to L.
148             The L
149             is also detected if L is true.
150              
151             =head2 C
152              
153             $host = $cxn_pool->should_accept_node($host,$node_id,\%node_data)
154              
155             This method serves as a hook which can be overridden by the user. When
156             a sniff is performed, this method is called with the C
157             (eg C<192.168.5.100:9200>), the C (the ID assigned to the node
158             by Elasticsearch) and the C which contains the information
159             about the node that Elasticsearch has returned, eg:
160              
161             {
162             "transport_address" => "inet[192.168.5.100/192.168.5.100:9300]",
163             "http" : {
164             "publish_address" => "inet[/192.168.5.100:9200]",
165             "max_content_length" => "100mb",
166             "bound_address" => "inet[/0:0:0:0:0:0:0:0:9200]",
167             "max_content_length_in_bytes" : 104857600
168             },
169             "version" => "0.90.4",
170             "name" => "Silver Sable",
171             "hostname" => "search1.domain.com",
172             "http_address" => "inet[/192.168.5.100:9200]"
173             }
174              
175             If the node should be I (ie used to serve data), then it should
176             return the C value to use. By default, nodes are always
177             accepted.
178              
179             =head1 AUTHOR
180              
181             Enrico Zimuel
182              
183             =head1 COPYRIGHT AND LICENSE
184              
185             This software is Copyright (c) 2022 by Elasticsearch BV.
186              
187             This is free software, licensed under:
188              
189             The Apache License, Version 2.0, January 2004
190              
191             =cut
192              
193             __END__