File Coverage

blib/lib/WWW/Crab/Client.pm
Criterion Covered Total %
statement 40 64 62.5
branch 3 14 21.4
condition 9 29 31.0
subroutine 11 15 73.3
pod 3 3 100.0
total 66 125 52.8


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             WWW::Crab::Client - Crab client library
4              
5             =head1 SYNOPSIS
6              
7             use WWW::Crab::Client;
8              
9             my $crab = new WWW::Crab::Client();
10              
11             eval {
12             $crab->start();
13             };
14              
15             # Perform the cron job actions ...
16              
17             my $finished_ok = eval {
18             $crab->finish(status => WWW::Crab::Client::SUCCESS, stdout => $message);
19             };
20             unless ($finished_ok) {
21             print "Failed to report job completion.\n" . $@ . "\n" . $message;
22             }
23              
24             =head1 DESCRIPTION
25              
26             This module implements a subset of the Crab protocol sufficient
27             for reporting the status of a cron job to the Crab server.
28             It is intended to work similarly to the Python Crab client module,
29             but be more convient for cron jobs written in Perl.
30              
31             =cut
32              
33             package WWW::Crab::Client;
34              
35 1     1   944 use strict;
  1         2  
  1         45  
36              
37 1     1   1367 use Config::IniFiles;
  1         149854  
  1         41  
38 1     1   104681 use File::HomeDir;
  1         37252  
  1         111  
39 1     1   10 use File::Spec;
  1         1  
  1         22  
40 1     1   983 use HTTP::Request;
  1         37997  
  1         52  
41 1     1   12 use JSON;
  1         41  
  1         11  
42 1     1   4224 use LWP::UserAgent;
  1         46912  
  1         55  
43 1     1   1094 use Sys::Hostname;
  1         1514  
  1         100  
44              
45             our $VERSION = 0.06;
46              
47             use constant {
48 1         980 SUCCESS => 0,
49             FAIL => 1,
50             UNKNOWN => 2,
51             COULDNOTSTART => 3,
52             ALREADYRUNNING=> 4,
53             WARNING => 5,
54 1     1   7 };
  1         2  
55              
56             =head1 CONSTRUCTOR
57              
58             =over 4
59              
60             =item new()
61              
62             Constructs a new client object. All parameters are optional.
63             If no job identifier is given, then a null value is sent to
64             the server. If the command is unspecified, C<$0> will be used.
65             No communication is performed until the L or L
66             methods are called.
67              
68             my $crab = new WWW::Crab::Client(id => 'job identifier',
69             command => 'command name',
70             server => 'localhost',
71             port => 8000,
72             hostname => 'localhost',
73             username => 'username',
74             timeout => 30);
75              
76             If the other settings are not specified, the crab settings files
77             will be read, the CRABHOST and CRABPORT environment variables will
78             be checked, or defaults will be used.
79              
80             =cut
81              
82             sub new {
83 1     1 1 1108 my $class = shift;
84 1         2 my %opt = @_;
85              
86 1         12 my $conf = new Config::IniFiles(-file => \'', -allowempty => 1);
87 1   50     23148 my $conf_system = File::Spec->catfile($ENV{'CRABSYSCONFIG'} || '/etc/crab',
88             'crab.ini');
89 1   33     76 my $conf_user = File::Spec->catfile($ENV{'CRABUSERCONFIG'} ||
90             (File::HomeDir->my_home() . '/.crab'),
91             'crab.ini');
92 1 50       107 $conf = new Config::IniFiles(-file => $conf_system, '-import' => $conf,
93             -allowempty => 1)
94             if (-e $conf_system);
95              
96 1 50       12 $conf = new Config::IniFiles(-file => $conf_user, '-import' => $conf,
97             -allowempty => 1)
98             if (-e $conf_user);
99              
100 1   50     25 my $self = {
      33        
      33        
      33        
      33        
      33        
      33        
101             id => $opt{'id'} || undef,
102             command => $opt{'command'} || $0,
103             server => $opt{'server'} || $ENV{'CRABHOST'} ||
104             $conf->val('server', 'host', 'localhost'),
105             port => $opt{'port'} || $ENV{'CRABPORT'} ||
106             $conf->val('server', 'port', 8000),
107             hostname => $opt{'hostname'} || $conf->val('client', 'hostname',
108             hostname()),
109             username => $opt{'username'} || $conf->val('client', 'username',
110             _get_username()),
111             timeout => $opt{'timeout'} || $conf->val('server', 'timeout', 30),
112             };
113              
114 1         72 return bless $self, $class;
115             }
116              
117             =back
118              
119             =head1 METHODS
120              
121             =over 4
122              
123             =item start()
124              
125             Reports that the job has started.
126              
127             $crab->start();
128              
129             This method uses "die" to raise an exception if it is unsuccessful
130             in reporting to the Crab server.
131              
132             Returns a true value on success.
133              
134             =cut
135              
136             sub start {
137 0     0 1 0 my $self = shift;
138              
139 0         0 return $self->_write_json($self->_get_url('start'), {
140             command => $self->{'command'}});
141             }
142              
143             =item finish()
144              
145             Reports that the job has finished. If the status is not specified,
146             UNKNOWN will be sent.
147              
148             $crab->finish(status => WWW::Crab::Client::SUCCESS,
149             stdout => $command_output,
150             stderr => $error_message);
151              
152             The following constants are defined in this module, and should be used
153             to obtain the appropriate Crab status codes:
154              
155             SUCCESS
156             FAIL
157             UNKNOWN
158             COULDNOTSTART
159             ALREADYRUNNING
160             WARNING
161              
162             This method uses "die" to raise an exception if it is unsuccessful
163             in reporting to the Crab server.
164              
165             Returns a true value on success.
166              
167             =cut
168              
169             sub finish {
170 0     0 1 0 my $self = shift;
171 0         0 my %opt = @_;
172              
173 0 0 0     0 return $self->_write_json($self->_get_url('finish'), {
      0        
174             command => $self->{'command'},
175             status => defined $opt{'status'} ? $opt{'status'} : UNKNOWN,
176             stdout => $opt{'stdout'} || '',
177             stderr => $opt{'stderr'} || ''});
178             }
179              
180             # _write_json()
181             #
182             # Sends the given object to the Crab server as a JSON message.
183             #
184             # $self->_write_json($self->_get_url($ACTION), $HASHREF);
185             #
186             # Dies on failure, and returns 1 on success. Could be improved
187             # to return a useful value on success, so long as it is 'true'.
188              
189             sub _write_json {
190 0     0   0 my $self = shift;
191 0         0 my $url = shift;
192 0         0 my $obj = shift;
193              
194 0         0 my $ua = new LWP::UserAgent(timeout => $self->{'timeout'});
195 0         0 my $req = new HTTP::Request(PUT => $url);
196 0         0 $req->content(encode_json($obj));
197 0         0 my $res = $ua->request($req);
198 0 0       0 die $res->status_line() unless $res->is_success();
199 0         0 return 1;
200             }
201              
202             # _get_url()
203             #
204             # Returns the URL to be used for a given Crab aaction.
205             #
206             # my $url = $self->_get_url($ACTION);
207             #
208             # Where the action is typically 'start' or 'finish'.
209              
210             sub _get_url {
211 0     0   0 my $self = shift;
212 0         0 my $action = shift;
213              
214 0         0 my @path = ($self->{'hostname'}, $self->{'username'});
215 0 0       0 push @path, $self->{'id'} if defined $self->{'id'};
216              
217 0         0 return 'http://' . $self->{'server'} . ':' . $self->{'port'} . '/' .
218             join('/', 'api', '0', $action, @path);
219             }
220              
221             # _get_username()
222             #
223             # Detects the username of the current user.
224             #
225             # This provides the default value for the username parameter
226             # of the WWW::Crab::Client constructor.
227              
228             sub _get_username {
229 1     1   1190 my $username = undef;
230              
231 1         3 eval {
232 1         1136 $username = scalar getpwuid($<);
233             };
234              
235 1 50       12 return $username if defined $username;
236              
237 0           eval {
238 0           require Win32;
239 0           $username = Win32::LoginName();
240             };
241              
242 0 0         return $username if defined $username;
243              
244 0           return 'user';
245             }
246              
247             1;
248              
249             __END__