File Coverage

blib/lib/ZipTie/Client.pm
Criterion Covered Total %
statement 28 60 46.6
branch 0 10 0.0
condition 0 3 0.0
subroutine 10 14 71.4
pod n/a
total 38 87 43.6


line stmt bran cond sub pod time code
1             package ZipTie::Client;
2              
3 1     1   697 use strict;
  1         3  
  1         40  
4 1     1   5 use warnings;
  1         2  
  1         36  
5 1     1   15 use vars qw($AUTOLOAD $VERSION);
  1         1  
  1         465  
6              
7             =head1 NAME
8              
9             ZipTie::Client - Webservice client for the ZipTie server
10              
11             =head1 VERSION
12              
13             Version 1.3
14              
15             =cut
16              
17             $VERSION = "1.3";
18              
19             =head1 SYNOPSIS
20              
21             use ZipTie::Client;
22              
23             my $client = ZipTie::Client->new(username => 'admin', password => 'password', host => 'localhost:8080', );
24              
25             $client->devices()->createDevice('10.1.2.1', 'Default', 'ZipTie::Adapters::Cisco::IOS');
26              
27             $client->devicetags()->addTag('HQ');
28             $client->devicetags()->tagDevices('HQ', '10.1.2.1@Default');
29              
30             =head1 DESCRIPTION
31              
32             C is a simple webservice client for a ZipTie server.
33              
34             =head1 PUBLIC SUB-ROUTINES
35              
36             =over
37              
38             =item $client = ZipTie::Client->new( %options )
39             Creates the client.
40              
41             username: The ZipTie server username
42             password: The ZipTie server password
43             host: The ZipTie server host and port. (Defaults to 'localhost:8080')
44             scheme: The protocol scheme to use to connect to the server. (Defaults to 'https')
45             on_fault: The method that will be called when there is an error from the server. (Default will call C)
46              
47             If no username is specified the ZipTie::Client will try to use $ENV{'ZIPTIE_AUTHENTICATION'} to authenticate. This
48             environment variable is set by the ZipTie server when running script tools. Authors of script tools my simply create
49             an instance of the ZipTie::Client with no options and the authentication will be handled automatically.
50              
51             =cut
52             sub new
53             {
54 0     0     my ( $proto, %params ) = @_;
55 0   0       my $package = ref($proto) || $proto;
56              
57 0           my $self = {
58             username => undef,
59             password => undef,
60             host => 'localhost:8080',
61             scheme => 'https',
62             on_fault => undef,
63             };
64              
65 0           foreach my $key ( keys %params )
66             {
67 0           $self->{$key} = $params{$key};
68             }
69              
70 0           bless($self, $package);
71             }
72              
73             =item C
74             Gets an instance of a webservice endpoint. As a shortcut ports can be accessed directly with a method named
75             the same as the port name.
76              
77             # These two lines do the same thing.
78             $port = $client->port("devices");
79             $port = $client->devices();
80              
81             =cut
82             sub port
83             {
84 0     0     my $self = shift;
85 0 0         my $portname = shift or die('No port specified');
86              
87 0           my $portkey = "port_$portname";
88 0           my $port = $self->{$portkey};
89 0 0         if ($port)
90             {
91 0           return $port;
92             }
93              
94 0           my $primary_url = '';
95 0 0         if ($self->{username})
96             {
97 0           $primary_url = $self->{scheme}. '://' . $self->{host} . '/server/';
98             }
99             else
100             {
101             # Token should be of the form '://:@[:]'
102 0           my $token = $ENV{'ZIPTIE_AUTHENTICATION'};
103 0 0         if ($token)
104             {
105 0           $primary_url = $token;
106             }
107             else
108             {
109 0           confess("Must specify a username and password.");
110             }
111             }
112              
113 0           my $proxy_url = $primary_url . $portname;
114              
115 0           my $ns_url = 'http://www.ziptie.org/server/' . $portname;
116              
117 0           $port = ZipTie::Client::Port->new($self, $proxy_url, $ns_url, $self->{on_fault});
118              
119 0           $self->{$portkey} = $port;
120              
121 0           return $port;
122             }
123              
124             =item logout
125             Logout the client session from the server. This should always be called for good-housekeeping when you
126             are finished with the client so the server can free resources more quickly.
127              
128             $client->logout();
129              
130             =cut
131             sub logout
132             {
133 0     0     my $self = shift;
134              
135 0           $self->port("security")->logoutCurrentUser();
136             }
137              
138             sub AUTOLOAD
139             {
140 0     0     my $self = shift;
141 0           my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::') + 2);
142 0 0         return if $method eq 'DESTROY';
143              
144 0           $self->port($method, @_);
145             }
146              
147             1;
148              
149             package ZipTie::Client::Port;
150              
151 1     1   4 use strict;
  1         2  
  1         38  
152 1     1   5 use warnings;
  1         2  
  1         30  
153 1     1   5 use vars qw($AUTOLOAD $VERSION);
  1         1  
  1         48  
154              
155 1     1   5 use Carp;
  1         1  
  1         78  
156 1     1   794 use HTTP::Cookies;
  1         12422  
  1         32  
157 1     1   751 use HTTP::Response;
  1         27856  
  1         35  
158 1     1   504 use SOAP::Lite 0.69;
  0            
  0            
159             use LWP::UserAgent;
160              
161             use constant DEBUG => 0;
162              
163             $VERSION = "1.3";
164              
165             sub new
166             {
167             my ($pkg, $client, $proxy_url, $ns_url, $on_fault) = @_;
168              
169             my $cookie_jar = HTTP::Cookies->new(ignore_discard => 1);
170              
171             my $auth = $client->{scheme} . '://' . $client->{host} . '/server';
172             if ($client->{username})
173             {
174             $auth .= '?j_username=' . $client->{username} . '&j_password=' . $client->{password};
175              
176             my $ua = LWP::UserAgent->new(cookie_jar => $cookie_jar);
177             my $response = $ua->head($auth);
178             if (!$response->is_success)
179             {
180             die $response->status_line;
181             }
182             }
183              
184             my $proxy = SOAP::Lite
185             -> proxy($proxy_url, cookie_jar => $cookie_jar)
186             -> uri($ns_url);
187              
188             $proxy->on_fault($on_fault || \&_on_fault);
189             $proxy->ns($ns_url, 'ns1');
190              
191             my $self = {
192             "proxy" => $proxy,
193             };
194              
195             bless($self, $pkg);
196             }
197              
198             sub _convert_args
199             {
200             my $self = shift;
201              
202             my %args = ();
203             if (@_ eq 1 and ref($_[0]) eq 'HASH')
204             {
205             %args = %{$_[0]};
206             }
207             elsif (@_ % 2)
208             {
209             confess("Arguments to must be name=>value pairs");
210             }
211             else
212             {
213             %args = @_;
214             }
215              
216             my @params;
217              
218             foreach my $key (keys(%args))
219             {
220             my $name = $key;
221             my $value = $args{$key};
222              
223             my $ref = ref($value);
224             if ($ref eq 'HASH')
225             {
226             print("A Hash\n") if (DEBUG);
227             my @converted = $self->_convert_args($value);
228             push(@params, SOAP::Data->name($name)->value(\@converted));
229             }
230             elsif ($ref eq 'ARRAY')
231             {
232             print("An Array\n") if (DEBUG);
233              
234             foreach my $entry (@$value)
235             {
236             $ref = ref($entry);
237             if ($ref eq 'HASH')
238             {
239             my @converted = $self->_convert_args(%$entry);
240             push(@params, SOAP::Data->name($name)->value(\@converted));
241             }
242             else
243             {
244             push(@params, SOAP::Data->name($name)->value($entry));
245             }
246             }
247             }
248             else
249             {
250             print("Name: $name\nValue: $value\n") if (DEBUG);
251             push(@params, SOAP::Data->name($name)->value($value));
252             }
253             }
254              
255             @params;
256             }
257              
258             sub _call
259             {
260             my $self = shift or die;
261             my $method = shift or die;
262              
263             my @args = $self->_convert_args(@_);
264              
265             my $proxy = $self->{"proxy"};
266             my $result = $proxy->$method(@args);
267              
268             wantarray ? $result->paramsall() : $result->result();
269             }
270              
271             sub _on_fault
272             {
273             my($soap, $res) = @_;
274             die ref $res ? $res->faultdetail : $soap->transport->status, "\n";
275             }
276              
277             sub AUTOLOAD
278             {
279             my $self = shift;
280             my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::') + 2);
281             return if $method eq 'DESTROY';
282              
283             # Generate the requested method. This AUTOLOAD will only be called the first time the method is called.
284             # All subsequent calls will call the generated method directly.
285             eval("sub $method { my \$self = shift; \$self->_call('$method', \@_); }");
286              
287             $self->$method(@_);
288             }
289              
290             1;
291              
292             =back
293              
294             =head1 LICENSE
295              
296             The contents of this file are subject to the Mozilla Public License
297             Version 1.1 (the "License"); you may not use this file except in
298             compliance with the License. You may obtain a copy of the License at
299             http://www.mozilla.org/MPL/
300              
301             Software distributed under the License is distributed on an "AS IS"
302             basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
303             License for the specific language governing rights and limitations
304             under the License.
305              
306             The Original Code is ZipTie.
307              
308             The Initial Developer of the Original Code is AlterPoint.
309             Portions created by AlterPoint are Copyright (C) 2007-2008,
310             AlterPoint, Inc. All Rights Reserved.
311              
312             =head1 AUTHOR
313              
314             lbayer (lbayer@ziptie.org)
315              
316             =head1 BUGS
317              
318             Please report any bugs or feature requests through the ziptie bugzilla
319             web interface at L.
320              
321             =cut