File Coverage

blib/lib/Net/Intermapper.pm
Criterion Covered Total %
statement 55 343 16.0
branch 0 162 0.0
condition n/a
subroutine 17 29 58.6
pod 8 12 66.6
total 80 546 14.6


line stmt bran cond sub pod time code
1             package Net::Intermapper;
2 1     1   15052 use strict;
  1         2  
  1         26  
3 1     1   480 use Moose;
  1         600999  
  1         12  
4              
5             # REST IO stuff here
6 1     1   9204 use IO::Socket::SSL qw( SSL_VERIFY_NONE );
  1         74628  
  1         8  
7 1     1   715 use LWP::UserAgent;
  1         36392  
  1         37  
8              
9             # Generics
10 1     1   36 use File::Path;
  1         2  
  1         233  
11 1     1   5 use URI::Escape;
  1         1  
  1         59  
12 1     1   852 use Text::CSV_XS;
  1         7420  
  1         90  
13 1     1   649 use Data::Dumper;
  1         6291  
  1         108  
14 1     1   1087 use XML::Simple;
  1         10709  
  1         11  
15              
16             # Net::Intermapper::*
17 1     1   874 use Net::Intermapper::User;
  1         6  
  1         91  
18 1     1   756 use Net::Intermapper::Device;
  1         3  
  1         89  
19 1     1   495 use Net::Intermapper::Interface;
  1         3  
  1         70  
20 1     1   513 use Net::Intermapper::Map;
  1         4  
  1         60  
21 1     1   468 use Net::Intermapper::Vertice;
  1         2  
  1         64  
22              
23             BEGIN {
24 1     1   6 use Exporter ();
  1         1  
  1         19  
25 1     1   3 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $ERROR %_CHANGED);
  1         1  
  1         101  
26 1     1   1 $VERSION = '0.04';
27 1         17 @ISA = qw(Exporter);
28 1         2 @EXPORT = qw();
29 1         2 @EXPORT_OK = qw();
30 1         2 %EXPORT_TAGS = ();
31 1         1 %_CHANGED = ();
32 1         2039 $ERROR = ""; # TODO: Document error properly!
33             }
34              
35             # Moose!
36              
37             has 'ssl_options' => (
38             is => 'rw',
39             isa => 'HashRef',
40             default => sub { { 'SSL_verify_mode' => SSL_VERIFY_NONE, 'verify_hostname' => '0' } }
41             );
42              
43             has 'ssl' => (
44             is => 'rw',
45             isa => 'Str',
46             default => '1',
47             );
48              
49             has 'hostname' => (
50             is => 'rw',
51             isa => 'Str',
52             required => '1',
53             );
54              
55             has 'port' => (
56             is => 'rw',
57             isa => 'Int',
58             default => sub { 8181 },
59             );
60              
61             has 'modifyport' => (
62             is => 'rw',
63             isa => 'Int',
64             default => sub { 443 },
65             );
66            
67             has 'username' => (
68             is => 'rw',
69             isa => 'Str',
70             default => sub { "admin" },
71             );
72              
73             has 'password' => (
74             is => 'rw',
75             isa => 'Str',
76             default => sub { "nmsadmin" },
77             );
78            
79             has 'format' => (
80             is => 'rw',
81             isa => 'Str',
82             default => sub { "csv" },
83             );
84              
85             has 'cache' => (
86             is => 'rw',
87             isa => 'Int',
88             default => sub { "1" }, # Cache any request
89             );
90              
91             has 'mock' => (
92             is => 'rw',
93             isa => 'Int',
94             default => sub { "0" },
95             );
96              
97             sub users # No Moose here :(
98 0     0 1   { my $self = shift;
99 0           $ERROR = "";
100 0 0         $_CHANGED{"users"} = !$self->{"Users"} ? 1 : $_CHANGED{"users"};
101 0 0         if (@_)
102             { #my %args = @_;
103             #$self->{"Users"} = $args{"users"};
104 0           $self->{"Users"} = $_[0]; # Expect a hash ref to be passed
105             # Yes, this code is slightly based of the Net::Cisco::ACS code so may be some of it is weird
106             # Are you really reading the comments now?
107 0 0         if ($self->mock())
108 0           { return $self->{"Users"}; }
109             } else
110 0 0         { if (!$self->cache) # No caching? Always reload
111 0 0         { $self->{"Users"} = $self->query("users") unless $self->mock; }
112             else
113 0 0         { if (!$self->mock)
114 0 0         { $self->{"Users"} = $self->query("users") if $_CHANGED{"users"}; } # Only reload if changed
115             }
116             }
117 0 0         return wantarray ? % { $self->{"Users"} } : $self->{"Users"};
  0            
118             }
119              
120             sub devices # No Moose here :(
121 0     0 1   { my $self = shift;
122 0           $ERROR = "";
123 0 0         $_CHANGED{"devices"} = !$self->{"Devices"} ? 1 : $_CHANGED{"devices"};
124 0 0         if (@_)
125             { #my %args = @_;
126             #$self->{"Devices"} = $args{"devices"};
127 0           $self->{"Devices"} = $_[0]; # Expect a hash ref to be passed
128             } else
129 0 0         { if (!$self->cache) # No caching? Always reload
130 0           { $self->{"Devices"} = $self->query("devices"); }
131             else
132 0 0         { $self->{"Devices"} = $self->query("devices") if $_CHANGED{"devices"}; # Only reload if changed
133             }
134             }
135 0 0         return wantarray ? % { $self->{"Devices"} } : $self->{"Devices"};
  0            
136             }
137              
138             sub interfaces # No Moose here :(
139 0     0 1   { my $self = shift;
140 0           $ERROR = "";
141 0 0         $_CHANGED{"interfaces"} = !$self->{"Interfaces"} ? 1 : $_CHANGED{"interfaces"};
142 0 0         if (@_)
143             { #my %args = @_;
144             #$self->{"Interfaces"} = $args{"interfaces"};
145 0           $self->{"Interfaces"} = $_[0]; # Expect a hash ref to be passed
146             } else
147 0 0         { if (!$self->cache) # No caching? Always reload
148 0           { $self->{"Interfaces"} = $self->query("interfaces"); }
149             else
150 0 0         { $self->{"Interfaces"} = $self->query("interfaces") if $_CHANGED{"interfaces"}; # Only reload if changed
151             }
152             }
153 0 0         return wantarray ? % { $self->{"Interfaces"} } : $self->{"Interfaces"};
  0            
154             }
155              
156             sub maps # No Moose here :(
157 0     0 1   { my $self = shift;
158 0           $ERROR = "";
159 0 0         $_CHANGED{"maps"} = !$self->{"Maps"} ? 1 : $_CHANGED{"maps"};
160 0 0         if (@_)
161             { #my %args = @_;
162             #$self->{"Maps"} = $args{"maps"};
163 0           $self->{"Maps"} = $_[0]; # Expect a hash ref to be passed
164             } else
165 0 0         { if (!$self->cache) # No caching? Always reload
166 0           { $self->{"Maps"} = $self->query("maps"); }
167             else
168 0 0         { $self->{"Maps"} = $self->query("maps") if $_CHANGED{"maps"}; # Only reload if changed
169             }
170             }
171 0 0         return wantarray ? % { $self->{"Maps"} } : $self->{"Maps"};
  0            
172             }
173              
174             sub vertices # No Moose here :(
175 0     0 1   { my $self = shift;
176 0           $ERROR = "";
177 0 0         $_CHANGED{"vertices"} = !$self->{"Vertices"} ? 1 : $_CHANGED{"vertices"};
178 0 0         if (@_)
179             { #my %args = @_;
180             #$self->{"Vertices"} = $args{"vertices"};
181 0           $self->{"Vertices"} = $_[0]; # Expect a hash ref to be passed
182             } else
183 0 0         { if (!$self->cache) # No caching? Always reload
184 0           { $self->{"Vertices"} = $self->query("vertices"); }
185             else
186 0 0         { $self->{"Vertices"} = $self->query("vertices") if $_CHANGED{"vertices"}; # Only reload if changed
187             }
188             }
189 0 0         return wantarray ? % { $self->{"Vertices"} } : $self->{"Vertices"};
  0            
190             }
191              
192             sub query
193 0     0 0   { my ($self, $type) = @_;
194 0           my $hostname = $self->hostname;
195 0           my $username = $self->username;
196 0           my $password = $self->password;
197 0           my $port = $self->port;
198 0           my $format = $self->format;
199 0 0         if ($self->ssl)
200 0           { $hostname = "https://$username:$password\@$hostname:$port"; } else
201 0           { $hostname = "http://$username:$password\@$hostname:$port"; }
202 0           $hostname .= "/~export/$type.$format";
203 0           my $request = HTTP::Request->new("GET" => $hostname);
204 0           my $useragent = LWP::UserAgent->new (ssl_opts => $self->ssl_options);
205 0           my $result = $useragent->request($request);
206 0 0         if ($result->code eq "400") { $ERROR = "Bad Request - HTTP Status: 400"; }
  0            
207 0 0         if ($result->code eq "410") { $ERROR = "Unknown $type queried by name or ID - HTTP Status: 410"; }
  0            
208 0 0         if ($self->format eq "csv")
209 0           { $self->parse_csv($type, $result->decoded_content);
210             }
211 0 0         if ($self->format eq "tab")
212 0           { $self->parse_tab($type, $result->decoded_content);
213             }
214              
215 0 0         if ($self->format eq "xml")
216             { #$self->parse_xml($type, $result->content); # XML seems to be broken?!?
217             #warn Dumper $result->content;
218             #This needs work!!
219             }
220 0           $_CHANGED{$type} = 0;
221 0 0         return $self->{"Users"} if $type eq "users";
222 0 0         return $self->{"Devices"} if $type eq "devices";
223 0 0         return $self->{"Interfaces"} if $type eq "interfaces";
224 0 0         return $self->{"Maps"} if $type eq "maps";
225 0 0         return $self->{"Vertices"} if $type eq "vertices";
226             }
227              
228             # It seems that Maps and Interfaces cannot be created?
229             sub create
230 0     0 1   { my $self = shift;
231 0           my @entries = @_;
232 0 0         return unless @entries;
233 0           my $username = $self->username;
234 0           my $password = $self->password;
235 0           my $format = $self->format; # csv or xml (unsupported at this point)
236 0           my $type = "";
237            
238 0           my $hostname = $self->hostname;
239 0           my $port = $self->modifyport;
240 0 0         if ($port ne "") { $port = ":$port"; }
  0            
241 0 0         if ($self->ssl)
242 0           { $hostname = "https://$username:$password\@$hostname$port/~import/file"; } else
243 0           { $hostname = "http://$username:$password\@$hostname$port/~import/file"; }
244              
245 0           my $data = $entries[0]->header($format);
246 0           $type = lc(ref($entries[0]));
247 0           $type =~ s/^net\:\:intermapper\:\://; # Needed for the change flags@
248 0           while(@entries)
249 0           { my $entry = shift @entries;
250 0 0         if ($format eq "csv")
251 0           { $data .= $entry->toCSV; }
252 0 0         if ($format eq "tab")
253 0           { $data .= $entry->toTAB; }
254 0           $data =~ s/^\s*//g;
255             }
256              
257 0           my $request = HTTP::Request->new(POST => "$hostname");
258 0           my $useragent = LWP::UserAgent->new("ssl_opts" => $self->ssl_options);
259              
260 0           $request->content_type('application/x-www-form-urlencoded');
261 0           $request->content($data);
262 0           $request->header('Accept' => 'text/html');
263 0           my $result = $useragent->request($request);
264 0           $_CHANGED{$type} = 0; # Flag smart caching to force reload
265 0           return $result;
266             }
267              
268             # This SHOULD be sufficient?
269             sub update
270 0     0 1   { my $self = shift;
271 0           my $entry = shift;
272 0           $entry->mode("update");
273 0           return $self->create($entry);
274             }
275              
276             # This SHOULD be sufficient?
277             sub delete
278 0     0 1   { my $self = shift;
279 0           my $entry = shift;
280 0           $entry->mode("delete");
281 0           return $self->create($entry);
282             }
283              
284             sub parse_xml # Broken!
285 0     0 0   { my $self = shift;
286 0           my $type = shift;
287 0           my $xml_ref = shift;
288 0           my $xmlsimple = XML::Simple->new();
289 0           my $xmlout = $xmlsimple->XMLin($xml_ref);
290 0 0         if ($type eq "users")
291 0           { my $users_ref = $xmlout->{"users"};
292 0           my %users = ();
293 0           for my $key (@ {$users_ref})
  0            
294 0           { my $user = Net::Intermapper::User->new( @{ $key } );
  0            
295 0           $users{$key} = $user;
296             }
297 0           $self->{"Users"} = \%users; #Not sure if this works with the
298 0           return $self->{"Users"};
299             }
300            
301 0 0         if ($type eq "devices")
302 0           { my $devices_ref = $xmlout->{"devices"};
303 0           my %devices = ();
304 0           for my $key (@ {$devices_ref})
  0            
305 0           { my $device = Net::Intermapper::Device->new( @{ $key } );
  0            
306 0           $devices{$key} = $device;
307             }
308 0           $self->{"Devices"} = \%devices;
309 0           return $self->{"Devices"};
310             }
311            
312 0 0         if ($type eq "interfaces")
313 0           { my $interfaces_ref = $xmlout->{"interfaces"};
314 0           my %interfaces = ();
315 0           for my $key (@ {$interfaces_ref})
  0            
316 0           { my $interface = Net::Intermapper::Interface->new( @{ $key } );
  0            
317 0           $interfaces{$key} = $interface;
318             }
319 0           $self->{"Interfaces"} = \%interfaces;
320 0           return $self->{"Interfaces"};
321             }
322            
323 0 0         if ($type eq "maps")
324 0           { my $maps_ref = $xmlout->{"maps"};
325 0           my %maps = ();
326 0           for my $key (@ {$maps_ref})
  0            
327 0           { my $map = Net::Intermapper::Map->new( @{ $key } );
  0            
328 0           $maps{$key} = $map;
329             }
330 0           $self->{"Maps"} = \%maps;
331 0           return $self->{"Maps"};
332             }
333              
334 0 0         if ($type eq "vertices")
335 0           { my $vertices_ref = $xmlout->{"vertices"};
336 0           my %vertices = ();
337 0           for my $key (@ {$vertices_ref})
  0            
338 0           { my $vertice = Net::Intermapper::Vertice->new( @{ $key } );
  0            
339 0           $vertices{$key} = $vertice;
340             }
341 0           $self->{"Vertices"} = \%vertices;
342 0           return $self->{"Vertices"};
343             }
344            
345             }
346              
347             sub parse_csv
348 0     0 0   { my $self = shift;
349 0           my $type = shift;
350 0           my $csv_ref = shift;
351 0           my @header = ();
352 0           my %data = ();
353 0 0         if ($type eq "users")
354 0           { @header = @Net::Intermapper::User::HEADERS; }
355 0 0         if ($type eq "devices")
356 0           { @header = @Net::Intermapper::Device::HEADERS; }
357 0 0         if ($type eq "interfaces")
358 0           { @header = @Net::Intermapper::Interface::HEADERS; }
359 0 0         if ($type eq "maps")
360 0           { @header = @Net::Intermapper::Map::HEADERS; }
361 0 0         if ($type eq "vertices")
362 0           { @header = @Net::Intermapper::Vertice::HEADERS; }
363            
364 0           my @lines = split(/\r\n/,$csv_ref);
365 0           my $csv = Text::CSV_XS->new ({ "auto_diag" => "1", "binary" => "1" });
366 0           for my $line (@lines)
367 0           { my $i = 0;
368 0           my %fields = ();
369 0 0         if ($csv->parse ($line))
370 0           { my @fields = $csv->fields;
371 0           for my $field (@fields)
372 0           { $fields{$header[$i]} = $field;
373 0           $i++;
374             }
375 0 0         if ($type eq "users")
376 0           { my $user = Net::Intermapper::User->new( %fields );
377 0           $data{$user->Name} = $user;
378             }
379 0 0         if ($type eq "devices")
380 0           { my $device = Net::Intermapper::Device->new( %fields );
381 0           $data{$device->Id} = $device;
382             }
383 0 0         if ($type eq "interfaces")
384 0           { my $interface = Net::Intermapper::Interface->new( %fields );
385 0           $data{$interface->InterfaceID} = $interface;
386             }
387 0 0         if ($type eq "maps")
388 0           { my $map = Net::Intermapper::Map->new( %fields );
389 0           $data{$map->MapName} = $map;
390             }
391 0 0         if ($type eq "vertices")
392 0           { my $vertice = Net::Intermapper::Vertice->new( %fields );
393 0           $data{$vertice->Id} = $vertice;
394             }
395              
396             }
397             }
398 0 0         if ($type eq "users")
399 0           { $self->{"Users"} = \%data;
400 0           return $self->{"Users"};
401             }
402 0 0         if ($type eq "devices")
403 0           { $self->{"Devices"} = \%data;
404 0           return $self->{"Devices"};
405             }
406 0 0         if ($type eq "interfaces")
407 0           { $self->{"Interfaces"} = \%data;
408 0           return $self->{"Interfaces"};
409             }
410 0 0         if ($type eq "maps")
411 0           { $self->{"Maps"} = \%data;
412 0           return $self->{"Maps"};
413             }
414 0 0         if ($type eq "vertices")
415 0           { $self->{"Vertices"} = \%data;
416 0           return $self->{"Vertices"};
417             }
418              
419             }
420              
421             sub parse_tab
422 0     0 0   { my $self = shift;
423 0           my $type = shift;
424 0           my $tab_ref = shift;
425 0           my @header = ();
426 0           my %data = ();
427 0 0         if ($type eq "users")
428 0           { @header = @Net::Intermapper::User::HEADERS; }
429 0 0         if ($type eq "devices")
430 0           { @header = @Net::Intermapper::Device::HEADERS; }
431 0 0         if ($type eq "interfaces")
432 0           { @header = @Net::Intermapper::Interface::HEADERS; }
433 0 0         if ($type eq "maps")
434 0           { @header = @Net::Intermapper::Map::HEADERS; }
435 0 0         if ($type eq "vertices")
436 0           { @header = @Net::Intermapper::Vertice::HEADERS; }
437 0           my $linecount = 0;
438 0           my @lines = split(/[\r\n]{1,2}/,$tab_ref);
439 0           for my $line (@lines)
440 0           { my $i = 0;
441 0           my %fields = ();
442 0           my @fields = split(/\t/,$line);
443 0 0         if (!$linecount) { $linecount++; next; } # Skip header line - KNOWN VALUES
  0            
  0            
444 0           for my $field (@fields)
445 0           { $fields{$header[$i]} = $field;
446 0           $i++;
447             }
448 0 0         if ($type eq "users")
449 0           { my $user = Net::Intermapper::User->new( %fields );
450 0           $data{$user->Name} = $user;
451             }
452 0 0         if ($type eq "devices")
453 0           { my $device = Net::Intermapper::Device->new( %fields );
454 0           $data{$device->Id} = $device;
455             }
456 0 0         if ($type eq "interfaces")
457 0           { my $interface = Net::Intermapper::Interface->new( %fields );
458 0           $data{$interface->InterfaceID} = $interface;
459             }
460 0 0         if ($type eq "maps")
461 0           { my $map = Net::Intermapper::Map->new( %fields );
462 0           $data{$map->MapName} = $map;
463             }
464 0 0         if ($type eq "vertices")
465 0           { my $vertice = Net::Intermapper::Vertice->new( %fields );
466 0           $data{$vertice->Id} = $vertice;
467             }
468             }
469 0 0         if ($type eq "users")
470 0           { $self->{"Users"} = \%data;
471 0           return $self->{"Users"};
472             }
473 0 0         if ($type eq "devices")
474 0           { $self->{"Devices"} = \%data;
475 0           return $self->{"Devices"};
476             }
477 0 0         if ($type eq "interfaces")
478 0           { $self->{"Interfaces"} = \%data;
479 0           return $self->{"Interfaces"};
480             }
481 0 0         if ($type eq "maps")
482 0           { $self->{"Maps"} = \%data;
483 0           return $self->{"Maps"};
484             }
485 0 0         if ($type eq "vertices")
486 0           { $self->{"Vertices"} = \%data;
487 0           return $self->{"Vertices"};
488             }
489              
490             }
491              
492             =pod
493              
494             =head1 NAME
495              
496             Net::Intermapper - Interface with the HelpSystems Intermapper HTTP API
497              
498             =head1 SYNOPSIS
499              
500             use Net::Intermapper;
501             my $intermapper = Net::Intermapper->new(hostname=>"10.0.0.1", username=>"admin", password=>"nmsadmin");
502             # Options:
503             # hostname - IP or hostname of Intermapper 5.x and 6.x server
504             # username - Username of Administrator user
505             # password - Password of user
506             # ssl - SSL enabled (1 - default) or disabled (0)
507             # port - TCP port for querying information. Defaults to 8181
508             # modifyport - TCP port for modifying information. Default to 443
509             # cache - Boolean to enable smart caching or force network queries
510              
511             my %users = $intermapper->users;
512             my $users_ref = $intermapper->users;
513             # Retrieve all users from Intermapper, Net::Intermapper::User instances
514             # Returns hash or hashref, depending on context
515            
516             my %devices = $intermapper->devices;
517             my $devices_ref = $intermapper->devices;
518             # Retrieve all devices from Intermapper, Net::Intermapper::Device instances
519             # Returns hash or hashref, depending on context
520              
521             my %maps = $intermapper->maps;
522             my $maps_ref = $intermapper->maps;
523             # Retrieve all maps from Intermapper, Net::Intermapper::Map instances
524             # Returns hash or hashref, depending on context
525              
526             my %interfaces = $intermapper->interfaces;
527             my $interfaces_ref = $intermapper->interfaces;
528             # Retrieve all interfaces from Intermapper, Net::Intermapper::Interface instances
529             # Returns hash or hashref, depending on context
530              
531             my %vertices = $intermapper->vertices;
532             my $vertices_ref = $intermapper->vertices;
533             # Retrieve all vertices from Intermapper, Net::Intermapper::Vertice instances
534             # Returns hash or hashref, depending on context
535              
536             my $user = $intermapper->users->{"admin"};
537            
538             # Each class will generate specific header. These are typically only for internal use but are compliant to the import format Intermapper uses.
539             print $user->header;
540             print $device->header;
541             print $map->header;
542             print $interface->header;
543             print $vertice->header;
544              
545             print $user->toTAB;
546             print $device->toXML; # This one is broken still!
547             print $map->toCSV;
548             # Works on ALL subclasses
549             # Produce human-readable output of each record in the formats Intermapper supports
550            
551             my $user = Net::Intermapper::User->new(Name=>"testuser", Password=>"Test12345");
552             my $response = $intermapper->create($user);
553             # Create new user
554             # Return value is HTTP::Response object
555            
556             my $device = Net::Intermapper::Device->new(Name=>"testDevice", MapName=>"TestMap", MapPath=>"/TestMap", Address=>"10.0.0.1");
557             my $response = $intermapper->create($device);
558             # Create new device
559             # Return value is HTTP::Response object
560              
561             $user->Password("Foobar123");
562             my $response = $intermapper->update($user);
563             # Update existing user
564             # Return value is HTTP::Response object
565              
566             my $user = $intermapper->users->{"bob"};
567             my $response = $intermapper->delete($user);
568             # Delete existing user
569             # Return value is HTTP::Response object
570              
571             my $device = $intermapper->devices->{"UniqueDeviceID"};
572             my $response = $intermapper->delete($device);
573             # Delete existing device
574             # Return value is HTTP::Response object
575              
576             my $users = { "Tom" => $tom_user, "Bob" => $bob_user };
577             $intermapper->users($users);
578             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
579             # But it can be done with users, devices, interfaces, maps and vertices
580             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
581            
582             =head1 DESCRIPTION
583              
584             Net::Intermapper is a perl wrapper around the HelpSystems Intermapper API provided through HTTP/HTTPS for access to user accounts, device information, maps, interfaces and graphical elements.
585              
586             All calls are handled through an instance of the L<Net::Intermapper> class.
587              
588             use Net::Intermapper;
589             my $intermapper = Net::Intermapper->new(hostname => '10.0.0.1', username => 'admin', password => 'nmsadmin');
590              
591             =over 3
592              
593             =item new
594              
595             Class constructor. Returns object of Net::Intermapper on succes. Required fields are:
596              
597             =over 5
598              
599             =item hostname
600              
601             =item username
602              
603             =item password
604              
605             =back
606              
607             Optional fields are
608              
609             =over 5
610              
611             =item ssl
612              
613             =item ssl_options
614              
615             =item port
616              
617             =item modifyport
618              
619             =item cache
620              
621             =back
622              
623             =item hostname
624              
625             IP or hostname of Intermapper server. This is a required value in the constructor but can be redefined afterwards.
626              
627             =item username
628              
629             Username of Administrator user. This is a required value in the constructor but can be redefined afterwards.
630             As the API is used a different mechanism to query information than it uses to update, this needs to be changed when switching. Typically, the built-in C<admin> user is used for modifying a record.
631             This value is not automatically changed when running C<create> or C<update>.
632              
633             =item password
634              
635             Password of user. This is a required value in the constructor but can be redefined afterwards.
636             As the API is used a different mechanism to query information than it uses to update, this needs to be changed when switching. Typically, the built-in C<admin> user is used for modifying a record.
637             This value is not automatically changed when running C<create> or C<update>.
638              
639             =item ssl
640              
641             SSL enabled (1 - default) or disabled (0).
642              
643             =item ssl_options
644              
645             Value is passed directly to L<LWP::UserAgent> as C<ssl_opt>. Default value (hash-ref) is
646              
647             { 'SSL_verify_mode' => SSL_VERIFY_NONE, 'verify_hostname' => '0' }
648              
649             This is an optional value in the constructor and can be redefined afterwards.
650            
651             =item port
652              
653             TCP port used for queries. This is an optional value in the constructor and can be redefined afterwards. By default, this is set to 8181.
654             As the API is used a different mechanism to query information than it uses to update, the C<port> value is used for queries only and is automatically switched. Set this ONLY if you have customized Intermapper to listen to a different port.
655              
656             =item modifyport
657              
658             TCP port used for modifying values. This is an optional value in the constructor and can be redefined afterwards. By default, this is set to 443.
659             As the API is used a different mechanism to modify (create and update) information than it uses to query, the C<modifyport> value is used for modifying only and is automatically switched. Set this ONLY if you have customized Intermapper to listen to a different port.
660              
661             =item cache
662              
663             Set to true (default) to use in-memory dataset to avoid unnecessary queries. Dataset are always queries when changes are made (after delete, create or update), per type. Changes to users dataset will not affect the devices dataset. This is a required value in the constructor but can be redefined afterwards.
664              
665             $intermapper->cache(0);
666             $intermapper->update($user);
667             # Users have changed.
668             my $users = $intermapper->users;
669             # This will trigger network traffic
670             my $devices = $intermapper->devices
671             # This will NOT trigger network traffic
672              
673             =back
674              
675             From the class instance, call the different methods for retrieving values.
676              
677             =over 3
678              
679             =item users
680              
681             Returns all users
682              
683             my %users = $intermapper->users();
684             my $user = $users{"Bob"};
685             print $user->Password;
686            
687             The returned hash contains instances of L<Net::Intermapper::User>, using the username as the hash key. In scalar context, will return hashref. This method will typically trigger a network connection, depending on caching.
688              
689             Modify the in-memory users dataset:
690              
691             my $users = { "Tom" => $tom_user, "Bob" => $bob_user };
692             $intermapper->users($users);
693             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
694             # But it can be done with users, devices, interfaces, maps and vertices
695             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
696            
697             =item devices
698              
699             returns all devices
700            
701             my %devices = $intermapper->devices();
702             my $device = $devices{"UniqueDeviceID"};
703             print $device->Address;
704              
705             The returned hash contains instances of L<Net::Intermapper::Device>, using the device ID as the hash key. In scalar context, will return hashref. This method will typically trigger a network connection, depending on caching.
706              
707             Modify the in-memory users dataset:
708              
709             my $devices = { "MainRouter1" => $main1, "MainRouter2" => $main2 };
710             $intermapper->devices($devices);
711             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
712             # But it can be done with users, devices, interfaces, maps and vertices
713             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
714            
715             =item maps
716              
717             returns all maps
718            
719             my %maps = $intermapper->maps();
720             my $map = $maps{"MainMap"};
721             print $map->Name;
722              
723             The returned hash contains instances of L<Net::Intermapper::Map>, using the map name as the hash key. In scalar context, will return hashref. This method will typically trigger a network connection, depending on caching.
724              
725             Modify the in-memory users dataset:
726              
727             my $maps = { "MainMap" => $main1, "Layer2" => $main2 };
728             $intermapper->maps($maps);
729             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
730             # But it can be done with users, devices, interfaces, maps and vertices
731             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
732            
733             =item interfaces
734              
735             returns all interfaces
736            
737             my %interfaces = $intermapper->interfaces();
738             my $interface = $devices{"UniqueInterfaceID"};
739             print $interface->Address;
740              
741             The returned hash contains instances of L<Net::Intermapper::Interface>, using the interface ID (generated by Intermapper) as the hash key. In scalar context, will return hashref. This method will typically trigger a network connection, depending on caching.
742              
743             Modify the in-memory users dataset:
744              
745             my $interfaces = { "UniqueKey1" => $iface1, "UniqueKey2" => $iface2 };
746             $intermapper->interfaces($interfaces);
747             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
748             # But it can be done with users, devices, interfaces, maps and vertices
749             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
750            
751             =item vertices
752              
753             returns all vertices
754            
755             my %vertices = $intermapper->vertices();
756             my $vertice = $vertices{"ID"}; # Unique Vertex ID
757             print $vertice->Shape;
758              
759             The returned hash contains instances of L<Net::Intermapper::Vertice>, using the vertex ID as the hash key. In scalar context, will return hashref. This method will typically trigger a network connection, depending on caching.
760              
761             Modify the in-memory users dataset:
762              
763             my $vertices = { "UniqueVertexID1" => $vid1, "UniqueVertexID2" => $vid2 };
764             $intermapper->vertices($vertices);
765             # At this point, there is no real reason to do this as update, create and delete work with explicit arguments.
766             # But it can be done with users, devices, interfaces, maps and vertices
767             # Pass a hashref to each method. This will NOT affect the smart-caching (only explicit calls to create, update and delete do this - for now).
768            
769             =item create
770              
771             This method created a new entry in Intermapper, depending on the argument passed. Record type is detected automatically.
772              
773             $intermapper->username("admin");
774             $intermapper->password("nmsadmin");
775             my $user = Net::Intermapper::User->new(Name=>"testuser", Password=>"Test12345");
776             my $response = $intermapper->create($user);
777             # Error checking needs to be added
778             # print $Net::Intermapper::ERROR unless $id;
779             # $Net::Intermapper::ERROR contains details about failure
780              
781             # Add more examples
782             # Interfaces and maps cannot be explicitly created!
783            
784             =item update
785              
786             This method updates an existing entry in Intermapper, depending on the argument passed. Record type is detected automatically.
787              
788             my $user = $intermapper->users->{"testuser"};
789             $user->Password("TopSecret"); # Change password. Password policies will be enforced!
790             my $response = $intermapper->update($user);
791             # Error checking needs to be added
792             # Update user based on Net::Intermapper::User instance
793             # print $Net::Intermapper::ERROR unless $id;
794             # $Net::Intermapper::ERROR contains details about failure
795              
796             =item delete
797              
798             This method deletes an existing entry in Intermapper, depending on the argument passed. Record type is detected automatically.
799              
800             my $user = $intermapper->users->{"bob"};
801             my $response = $intermapper->delete($user);
802             # Delete existing user
803              
804             my $device = $intermapper->devices->{"UniqueDeviceID"}; # This key is generated by Intermapper
805             $intermapper->delete($device);
806             # Delete existing device
807            
808             =item $ERROR
809              
810             NEEDS TO BE ADDED
811              
812             This variable will contain detailed error information.
813            
814             =back
815              
816             =head1 REQUIREMENTS
817              
818             For this library to work, you need an instance with Intermapper (obviously) or a simulator like L<Net::Intermapper::Mock>.
819              
820             =over 3
821              
822             =item L<Moose>
823              
824             =item L<IO::Socket::SSL>
825              
826             =item L<LWP::UserAgent>
827              
828             =item L<XML::Simple>
829              
830             =item L<MIME::Base64>
831              
832             =item L<URI::Escape>
833              
834             =item L<Text::CSV_XS>
835              
836             =back
837            
838             =head1 BUGS
839              
840             None so far
841              
842             =head1 TODO
843              
844             =over 3
845              
846             =item Filtering should be added (match= keyword in Intermapper documentation)
847              
848             =item XML input and output needs to be completed!
849              
850             =item $ERROR variable needs to actually contain error message!
851              
852             =back
853              
854             =head1 SUPPORT
855              
856             None so far :)
857              
858             =head1 AUTHOR
859              
860             Hendrik Van Belleghem
861             CPAN ID: BEATNIK
862             hendrik.vanbelleghem@gmail.com
863              
864             =head1 COPYRIGHT
865              
866             This program is free software licensed under the...
867              
868             The General Public License (GPL)
869             Version 2, June 1991
870              
871             The full text of the license can be found in the
872             LICENSE file included with this module.
873              
874              
875             =head1 SEE ALSO
876              
877             L<http://download.intermapper.com/docs/UserGuide/Content/09-Reference/09-05-Advanced_Importing/the_directive_line.htm>
878             L<http://download.intermapper.com/schema/imserverschema.html>
879              
880             =cut
881              
882             #################### main pod documentation end ###################
883              
884             __PACKAGE__->meta->make_immutable();
885              
886             1;
887             # The preceding line will help the module return a true value
888