File Coverage

blib/lib/Varnish/CLI.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Varnish::CLI;
2 1     1   27140 use Moose;
  0            
  0            
3             use Net::Telnet;
4             use Carp;
5             use Digest::SHA qw/sha256_hex/;
6              
7             =head1 NAME
8              
9             Varnish::CLI - An interface to the Varnish CLI
10              
11             =head1 VERSION
12              
13             Version 0.03
14              
15             =cut
16              
17             our $VERSION = '0.03';
18              
19              
20             =head1 SYNOPSIS
21              
22             Varnish CLI is a great administration tool, but a bit difficult to script for.
23             This module allows easy script interface to it.
24              
25             use Varnish::CLI;
26             my $varnish = Varnish::CLI->new( host => $host,
27             port => $port,
28             timeout => $timeout,
29             secret => $secret,
30             );
31             $varnish->send( 'url.purge .*' );
32              
33             The Varnish::CLI can be initialised without any parameters, and will usually work for the default
34             Varnish settings:
35              
36             my $varnish = Varnish::CLI->new();
37              
38             If you have started your Varnish CLI with a secret, you must will have to pass the contents
39             of your secret file, otherwise authentication will fail... Makes sense!! :)
40             Remember - complete contents of the secret file (including a newline if it exists!)
41              
42             my $varnish = Varnish::CLI->new( secret => $secret );
43            
44             =head1 PROPERTIES
45              
46             has host => ( is => 'ro',
47             isa => 'Str',
48             required => 1,
49             default => 'localhost' );
50              
51             has port => ( is => 'ro',
52             isa => 'Int',
53             required => 1,
54             default => 6082 );
55              
56             has timeout => ( is => 'rw',
57             isa => 'Int',
58             required => 1,
59             default => 1 );
60              
61             has t => ( is => 'rw',
62             isa => 'Net::Telnet',
63             clearer => 'clear_t' );
64            
65             has secret => ( is => 'rw',
66             isa => 'Str' );
67              
68             has connected => ( is => 'rw',
69             isa => 'Int',
70             default => 0,
71             required => 1 );
72              
73             has last_lines => ( is => 'rw',
74             isa => 'ArrayRef',
75             default => sub{ [] } );
76              
77             has last_status => ( is => 'rw',
78             isa => 'Int',
79             );
80              
81             =cut
82             has host => ( is => 'ro',
83             isa => 'Str',
84             required => 1,
85             default => 'localhost' );
86              
87             has port => ( is => 'ro',
88             isa => 'Int',
89             required => 1,
90             default => 6082 );
91              
92             has timeout => ( is => 'rw',
93             isa => 'Int',
94             required => 1,
95             default => 1 );
96              
97             has secret => ( is => 'rw',
98             isa => 'Str' );
99              
100             has t => ( is => 'rw',
101             isa => 'Net::Telnet',
102             clearer => 'clear_t' );
103            
104             has connected => ( is => 'rw',
105             isa => 'Int',
106             default => 0,
107             required => 1 );
108              
109             has last_lines => ( is => 'rw',
110             isa => 'ArrayRef',
111             default => sub{ [] } );
112              
113             has last_status => ( is => 'rw',
114             isa => 'Int',
115             );
116              
117              
118             =head1 SUBROUTINES/METHODS
119              
120             =head2 connect
121              
122             Connect to the Varnish CLI interface
123              
124             =cut
125             sub connect{
126             my( $self ) = shift;
127             if( $self->t() and $self->connected() ){
128             return 1;
129             }
130             my $t = Net::Telnet->new(
131             Host => $self->host(),
132             Port => $self->port(),
133             Timeout => $self->timeout(),
134             Output_record_separator => "\n",
135             Input_record_separator => "\n",
136             );
137             $self->t( $t );
138             $t->open();
139             $self->_parse_response();
140              
141             # A 107 response on connection means the Varnish CLI expects authentication
142             if( $self->last_status() == 107 ){
143             if( not $self->secret() ){
144             croak( "Connection failed: authentication required, but no secret given\n" );
145             }
146            
147             my $challenge = substr( $self->last_lines()->[0], 0, 32 );
148             my $auth = sha256_hex( $challenge . "\n" . $self->secret() . $challenge . "\n" );
149             $self->send( "auth $auth" );
150             if( $self->last_status != 200 ){
151             croak( "Authentication failed!\n" );
152             }
153             }
154            
155             if( $self->last_status() != 200 ){
156             croak( "Connection failed\nStatus: " . $self->last_status() . "\n".
157             "Last lines: \n\t" . join( "\t", @{ $self->last_lines() } ) . "\n" );
158             }
159             return 1;
160             }
161              
162             =head2 close
163              
164             Close the connection to the Varnish CLI interface
165              
166             =cut
167             sub close{
168             my( $self ) = shift;
169             if( not $self->t() or not $self->connected() ){
170             carp( "Close called, but not connected" );
171             return 1;
172             }
173             my $t = $self->t();
174             $t->print( 'quit' );
175             $t->close();
176             $self->clear_t();
177             $self->connected( 0 );
178             }
179              
180             =head2 send
181              
182             Send a command to the Varnish CLi
183              
184             =cut
185             sub send{
186             my( $self, $command ) = @_;
187             if( ! $command ){
188             croak( "Cannot call send without a command" );
189             }
190             # Make sure we're connected
191             $self->connect();
192             $self->t->print( $command );
193             $self->_parse_response();
194             if( $self->last_status() != 200 ){
195             croak( "Command failed: $command\nStatus: " . $self->last_status() . "\n".
196             "Last lines: \n\t" . join( "\t", @{ $self->last_lines() } ) . "\n" );
197             }
198             }
199              
200             # Private method to parse the response from the CLI
201             sub _parse_response{
202             my $self = shift;
203             my $t = $self->t();
204             my $line = $t->getline();
205             if( $line !~ m/^(\d+)\s*(\d+)\s*$/ ){
206             $self->connected( 0 );
207             print "Next line:\n";
208             print $t->getline();
209             croak( "Unexpected line:\n($line)" );
210              
211             }
212             my $status = $1;
213             my $chars = $2;
214             my $got_chars = 0;
215             $self->connected( 1 );
216             my @lines;
217             while( $got_chars < $chars ){
218             push( @lines, $t->getline() );
219             $got_chars += length( $lines[-1] );
220             }
221             # There's always one empty line after
222             push( @lines, $t->getline() );
223             $self->last_lines( \@lines );
224             $self->last_status( $status );
225             }
226              
227             =head1 AUTHOR
228              
229             Robin Clarke, C<< <perl at robinclarke.net> >>
230              
231             =head1 BUGS
232              
233             Please report any bugs or feature requests to C<bug-varnish at rt.cpan.org>, or through
234             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Varnish>. I will be notified, and then you'll
235             automatically be notified of progress on your bug as I make changes.
236              
237              
238              
239              
240             =head1 SUPPORT
241              
242             You can find documentation for this module with the perldoc command.
243              
244             perldoc Varnish::CLI
245              
246             You can also look for information at:
247              
248             =over 4
249              
250             =item * Repository on Github
251              
252             L<https://github.com/robin13/Varnish-CLI>
253              
254             =item * RT: CPAN's request tracker
255              
256             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Varnish>
257              
258             =item * AnnoCPAN: Annotated CPAN documentation
259              
260             L<http://annocpan.org/dist/Varnish>
261              
262             =item * CPAN Ratings
263              
264             L<http://cpanratings.perl.org/d/Varnish>
265              
266             =item * Search CPAN
267              
268             L<http://search.cpan.org/dist/Varnish/>
269              
270             =back
271              
272              
273             =head1 ACKNOWLEDGEMENTS
274              
275             L<http://www.varnish-cache.org/>
276              
277             =head1 LICENSE AND COPYRIGHT
278              
279             Copyright 2011 Robin Clarke.
280              
281             This program is free software; you can redistribute it and/or modify it
282             under the terms of either: the GNU General Public License as published
283             by the Free Software Foundation; or the Artistic License.
284              
285             See http://dev.perl.org/licenses/ for more information.
286              
287              
288             =cut
289              
290             1; # End of Varnish