File Coverage

blib/lib/Net/Silverpeak/Orchestrator.pm
Criterion Covered Total %
statement 26 427 6.0
branch 0 164 0.0
condition 0 21 0.0
subroutine 9 63 14.2
pod 48 49 97.9
total 83 724 11.4


line stmt bran cond sub pod time code
1             package Net::Silverpeak::Orchestrator;
2             $Net::Silverpeak::Orchestrator::VERSION = '0.016000';
3             # ABSTRACT: Silverpeak Orchestrator REST API client library
4              
5 3     3   794596 use 5.024;
  3         11  
6 3     3   1790 use Moo;
  3         24997  
  3         22  
7 3     3   4753 use feature 'signatures';
  3         10  
  3         774  
8 3     3   2146 use Types::Standard qw( Bool Str );
  3         446279  
  3         62  
9 3     3   9639 use Carp qw( croak );
  3         8  
  3         245  
10 3     3   2069 use HTTP::CookieJar;
  3         140882  
  3         227  
11 3     3   39 use List::Util qw( any );
  3         6  
  3         425  
12 3     3   2066 use URI::Escape::XS qw( uri_escape );
  3         10990  
  3         331  
13             # use Data::Dumper::Concise;
14              
15 3     3   24 no warnings "experimental::signatures";
  3         6  
  3         18663  
16              
17              
18             has 'user' => (
19             isa => Str,
20             is => 'rw',
21             predicate => 1,
22             );
23             has 'passwd' => (
24             isa => Str,
25             is => 'rw',
26             predicate => 1,
27             );
28             has 'api_key' => (
29             isa => Str,
30             is => 'rw',
31             predicate => 1,
32             );
33              
34              
35             has 'is_logged_in' => (
36             isa => Bool,
37             is => 'rwp',
38             default => sub { 0 },
39             );
40              
41             with 'Role::REST::Client';
42              
43             has '+persistent_headers' => (
44             default => sub {
45             my $self = shift;
46             my %headers;
47             $headers{'X-Auth-Token'} = $self->api_key
48             if $self->has_api_key;
49             return \%headers;
50             },
51             );
52              
53             around 'do_request' => sub($orig, $self, $method, $uri, $opts) {
54             # $uri .= '?apiKey=' . $self->api_key
55             # if $self->has_api_key;
56             # warn 'request: ' . Dumper([$method, $uri, $opts]);
57             my $response = $orig->($self, $method, $uri, $opts);
58             # warn 'response: ' . Dumper($response);
59             return $response;
60             };
61              
62 0     0     sub _build_user_agent ($self) {
  0            
  0            
63 0           require HTTP::Thin;
64              
65 0           my %params = $self->clientattrs->%*;
66 0 0 0       if ($self->has_user && $self->has_passwd) {
67 0           $params{cookie_jar} = HTTP::CookieJar->new;
68             }
69              
70 0           return HTTP::Thin->new(%params);
71             }
72              
73 0     0     sub _error_handler ($self, $res) {
  0            
  0            
  0            
74             my $error_message = ref $res->data eq 'HASH' && exists $res->data->{error}
75             ? $res->data->{error}
76 0 0 0       : $res->response->decoded_content;
77              
78 0           croak('error (' . $res->code . '): ' . $error_message);
79             }
80              
81 0     0     sub _post_with_params ($self, $endpoint, $params, @rest) {
  0            
  0            
  0            
  0            
  0            
82 0           my $uri_params = $self->_urlencode_data($params);
83 0           my $uri = $endpoint;
84 0 0         $uri .= $endpoint =~ /\?/
85             ? '&' . $uri_params
86             : '?' . $uri_params;
87              
88 0           return $self->post($uri, @rest);
89             }
90              
91              
92 0     0 1   sub login($self) {
  0            
  0            
93 0 0 0       die "user and password required\n"
94             unless $self->has_user && $self->has_passwd;
95              
96 0           my $res = $self->post('/gms/rest/authentication/login', {
97             user => $self->user,
98             password => $self->passwd,
99             });
100              
101 0 0         $self->_error_handler($res)
102             unless $res->code == 200;
103              
104 0           my @cookies = $self->user_agent->cookie_jar->cookies_for($self->server);
105 0 0         if (my ($csrf_cookie) = grep { $_->{name} eq 'orchCsrfToken' } @cookies ) {
  0            
106 0           $self->set_persistent_header('X-XSRF-TOKEN' => $csrf_cookie->{value});
107             }
108              
109 0           $self->_set_is_logged_in(1);
110              
111 0           return 1;
112             }
113              
114              
115 0     0 1   sub logout($self) {
  0            
  0            
116 0 0 0       die "user and password required\n"
117             unless $self->has_user && $self->has_passwd;
118              
119 0           my $res = $self->get('/gms/rest/authentication/logout');
120 0 0         $self->_error_handler($res)
121             unless $res->code == 200;
122              
123 0           delete $self->persistent_headers->{'X-XSRF-TOKEN'};
124              
125 0           $self->_set_is_logged_in(0);
126              
127 0           return 1;
128             }
129              
130              
131 0     0 1   sub get_version($self) {
  0            
  0            
132 0           my $res = $self->get('/gms/rest/gms/versions');
133 0 0         $self->_error_handler($res)
134             unless $res->code == 200;
135              
136 0           return $res->data->{current};
137             }
138              
139 0     0     sub _is_version_93 ($self) {
  0            
  0            
140 0           state $rv;
141 0 0         return $rv
142             if defined $rv;
143 0           my $version = $self->get_version;
144 0           my ($major, $minor) = split(/\./, $version);
145 0   0       return ($major == 9 && $minor >= 3) || $major > 9;
146             }
147              
148              
149 0     0 1   sub list_templategroups($self) {
  0            
  0            
150 0           my $res = $self->get('/gms/rest/template/templateGroups');
151 0 0         $self->_error_handler($res)
152             unless $res->code == 200;
153 0           return $res->data;
154             }
155              
156              
157 0     0 1   sub get_templategroup($self, $name) {
  0            
  0            
  0            
158 0 0         my $res = $self->_is_version_93
159             ? $self->get('/gms/rest/template/templateGroups', { templateGroup => $name })
160             : $self->get('/gms/rest/template/templateGroups/' . uri_escape($name));
161 0 0         $self->_error_handler($res)
162             unless $res->code == 200;
163             # version 9.3+ returns an array with a single hashref
164             # instead of the hashref
165 0 0         return $self->_is_version_93
166             ? $res->data->[0]
167             : $res->data;
168             }
169              
170              
171 0     0 1   sub create_templategroup($self, $name, $data = {}) {
  0            
  0            
  0            
  0            
172 0           $data->{name} = $name;
173 0           my $res = $self->post('/gms/rest/template/templateCreate',
174             $data);
175 0 0         $self->_error_handler($res)
176             unless $res->code == 204;
177 0           return 1;
178             }
179              
180              
181 0     0 1   sub update_templates_of_templategroup($self, $name, $templatenames) {
  0            
  0            
  0            
  0            
182 0 0         croak('templates names must be passed as an arrayref')
183             unless ref $templatenames eq 'ARRAY';
184              
185 0 0         my $res = $self->_is_version_93
186             ? $self->_post_with_params('/gms/rest/template/templateSelection',
187             { templateGroup => $name }, $templatenames)
188             : $self->post('/gms/rest/template/templateSelection/' . uri_escape($name),
189             $templatenames);
190 0 0         $self->_error_handler($res)
191             unless $res->code == 200;
192 0           return $res->data;
193             }
194              
195              
196 0     0 1   sub update_templategroup($self, $name, $data) {
  0            
  0            
  0            
  0            
197 0 0         my $res = $self->_is_version_93
198             ? $self->_post_with_params('/gms/rest/template/templateGroups', { templateGroup => $name }, $data)
199             : $self->post('/gms/rest/template/templateGroups/' . uri_escape($name), $data);
200 0 0         $self->_error_handler($res)
201             unless $res->code == 200;
202 0           return $res->data;
203             }
204              
205              
206 0     0 1   sub delete_templategroup($self, $name) {
  0            
  0            
  0            
207 0 0         my $res = $self->_is_version_93
208             ? $self->delete('/gms/rest/template/templateGroups', { templateGroup => $name })
209             : $self->delete('/gms/rest/template/templateGroups/' . uri_escape($name));
210 0 0         $self->_error_handler($res)
211             unless $res->code == 204;
212 0           return 1;
213             }
214              
215              
216 0     0 1   sub has_segmentation_enabled ($self) {
  0            
  0            
217 0           my $res = $self->get('/gms/rest/vrf/config/enable');
218 0 0         $self->_error_handler($res)
219             unless $res->code == 200;
220 0           return $res->data->{enable};
221             }
222              
223              
224 0     0 1   sub get_vrf_zones_map ($self) {
  0            
  0            
225 0           my $res = $self->get("/gms/rest/zones/vrfZonesMap");
226 0 0         $self->_error_handler($res)
227             unless $res->code == 200;
228 0           return $res->data;
229             }
230              
231              
232 0     0 1   sub get_vrf_by_id ($self) {
  0            
  0            
233 0           my $res = $self->get("/gms/rest/vrf/config/segments");
234 0 0         $self->_error_handler($res)
235             unless $res->code == 200;
236 0           return $res->data;
237             }
238              
239              
240 0     0 1   sub get_vrf_security_policies_by_ids ($self, $source_vrf_id, $destination_vrf_id) {
  0            
  0            
  0            
  0            
241 0           my $mapname = $source_vrf_id . '_' . $destination_vrf_id;
242 0 0         my $res = $self->_is_version_93
243             ? $self->get('/gms/rest/vrf/config/securityPolicies', { map => $mapname })
244             : $self->get('/gms/rest/vrf/config/securityPolicies/' . uri_escape($mapname));
245 0 0         $self->_error_handler($res)
246             unless $res->code == 200;
247 0           return $res->data;
248             }
249              
250              
251 0     0 1   sub update_vrf_security_policies_by_ids ($self, $source_vrf_id, $destination_vrf_id, $data) {
  0            
  0            
  0            
  0            
  0            
252 0           my $mapname = $source_vrf_id . '_' . $destination_vrf_id;
253 0 0         my $res = $self->_is_version_93
254             ? $self->_post_with_params('/gms/rest/vrf/config/securityPolicies', { map => $mapname }, $data)
255             : $self->post('/gms/rest/vrf/config/securityPolicies/' . uri_escape($mapname), $data);
256 0 0         $self->_error_handler($res)
257             unless $res->code == 204;
258 0           return 1;
259             }
260              
261              
262 0     0 1   sub list_appliances($self) {
  0            
  0            
263 0           my $res = $self->get('/gms/rest/appliance');
264 0 0         $self->_error_handler($res)
265             unless $res->code == 200;
266 0           return $res->data;
267             }
268              
269              
270 0     0 1   sub get_appliance($self, $id) {
  0            
  0            
  0            
271 0 0         my $res = $self->_is_version_93
272             ? $self->get('/gms/rest/appliance', { nePk => $id })
273             : $self->get('/gms/rest/appliance/' . uri_escape($id));
274 0 0         $self->_error_handler($res)
275             unless $res->code == 200;
276 0           return $res->data;
277             }
278              
279              
280 0     0 1   sub get_appliance_extrainfo ($self, $id) {
  0            
  0            
  0            
281 0 0         my $res = $self->_is_version_93
282             ? $self->get('/gms/rest/appliance/extraInfo', { nePk => $id })
283             : $self->get('/gms/rest/appliance/extraInfo/'. uri_escape($id));
284 0 0         $self->_error_handler($res)
285             unless $res->code == 200;
286 0           return $res->data;
287             }
288              
289              
290 0     0 1   sub get_ha_groups_by_id ($self) {
  0            
  0            
291 0           my $res = $self->get("/gms/rest/haGroups");
292 0 0         $self->_error_handler($res)
293             unless $res->code == 200;
294 0           return $res->data;
295             }
296              
297              
298 0     0 1   sub list_groups ($self) {
  0            
  0            
299 0           my $res = $self->get('/gms/rest/gms/group');
300 0 0         $self->_error_handler($res)
301             unless $res->code == 200;
302 0           return $res->data;
303             }
304              
305              
306 0     0 1   sub get_deployment ($self, $id) {
  0            
  0            
  0            
307 0 0         my $res = $self->_is_version_93
308             ? $self->get('/gms/rest/deployment', { nePk => $id })
309             : $self->get('/gms/rest/deployment/' . uri_escape($id));
310 0 0         $self->_error_handler($res)
311             unless $res->code == 200;
312 0           return $res->data;
313             }
314              
315              
316 0     0 1   sub get_interface_state ($self, $id) {
  0            
  0            
  0            
317 0 0         my $res = $self->_is_version_93
318             ? $self->get('/gms/rest/interfaceState', { nePk => $id })
319             : $self->get('/gms/rest/interfaceState/'. uri_escape($id));
320 0 0         $self->_error_handler($res)
321             unless $res->code == 200;
322 0           return $res->data;
323             }
324              
325              
326 0     0 1   sub get_interface_labels_by_type ($self) {
  0            
  0            
327 0           my $res = $self->get("/gms/rest/gms/interfaceLabels");
328 0 0         $self->_error_handler($res)
329             unless $res->code == 200;
330 0           return $res->data;
331             }
332              
333              
334 0     0 1   sub get_appliance_ipsla_configs ($self, $id) {
  0            
  0            
  0            
335 0 0         my $res = $self->_is_version_93
336             ? $self->get('/gms/rest/ipsla/config/managers', { nePk => $id })
337             : $self->get('/gms/rest/ipsla/config/managers/' . uri_escape($id));
338 0 0         $self->_error_handler($res)
339             unless $res->code == 200;
340 0           return $res->data;
341             }
342              
343              
344 0     0 1   sub get_appliance_ipsla_states ($self, $id) {
  0            
  0            
  0            
345 0 0         my $res = $self->_is_version_93
346             ? $self->get('/gms/rest/ipsla/state/managers', { nePk => $id })
347             : $self->get('/gms/rest/ipsla/state/managers/'. uri_escape($id));
348 0 0         $self->_error_handler($res)
349             unless $res->code == 200;
350 0           return $res->data;
351             }
352              
353              
354 0     0 1   sub get_appliance_bgp_system_config ($self, $id, $params = {}) {
  0            
  0            
  0            
  0            
355 0 0         my $res = $self->_is_version_93
356             ? $self->get('/gms/rest/bgp/config/system', { nePk => $id, $params->%* })
357             : $self->get('/gms/rest/bgp/config/system/' . uri_escape($id), $params);
358 0 0         $self->_error_handler($res)
359             unless $res->code == 200;
360 0           return $res->data;
361             }
362              
363              
364 0     0 1   sub get_appliance_bgp_system_config_allvrfs ($self, $id, $params = {}) {
  0            
  0            
  0            
  0            
365 0 0         my $res = $self->_is_version_93
366             ? $self->get('/gms/rest/bgp/config/allVrfs/system', { nePk => $id, $params->%* })
367             : $self->get('/gms/rest/bgp/config/allVrfs/system/' . uri_escape($id), $params);
368 0 0         $self->_error_handler($res)
369             unless $res->code == 200;
370 0           return $res->data;
371             }
372              
373              
374 0     0 1   sub get_appliance_bgp_neighbors ($self, $id, $params = {}) {
  0            
  0            
  0            
  0            
375 0 0         my $res = $self->_is_version_93
376             ? $self->get('/gms/rest/bgp/config/allVrfs/neighbor', { nePk => $id, $params->%* })
377             : $self->get('/gms/rest/bgp/config/allVrfs/neighbor/' . uri_escape($id), $params);
378 0 0         $self->_error_handler($res)
379             unless $res->code == 200;
380 0           return $res->data;
381             }
382              
383              
384 0     0 1   sub get_appliance_backups ($self, $id, $params = {}) {
  0            
  0            
  0            
  0            
385             $params->{runningConfig} = 'false'
386 0 0         unless exists $params->{runningConfig};
387 0 0         my $res = $self->_is_version_93
388             ? $self->get('/gms/rest/appliance/backup', { nePk => $id, $params->%* })
389             : $self->get('/gms/rest/appliance/backup/' . uri_escape($id), $params);
390 0 0         $self->_error_handler($res)
391             unless $res->code == 200;
392 0           return $res->data;
393             }
394              
395              
396 0     0 1   sub list_template_applianceassociations($self) {
  0            
  0            
397 0           my $res = $self->get('/gms/rest/template/applianceAssociation');
398 0 0         $self->_error_handler($res)
399             unless $res->code == 200;
400 0           return $res->data;
401             }
402              
403              
404 0     0 1   sub list_applianceids_by_templategroupname($self, $name) {
  0            
  0            
  0            
405 0           my $associations = $self->list_template_applianceassociations;
406 0           my @appliance_ids;
407 0           for my $appliance_id (keys %$associations) {
408             push @appliance_ids, $appliance_id
409 0 0   0     if any { $_ eq $name } $associations->{$appliance_id}->@*;
  0            
410             }
411 0           return \@appliance_ids;
412             }
413              
414              
415 0     0 1   sub list_addressgroups($self) {
  0            
  0            
416 0           my $res = $self->get('/gms/rest/ipObjects/addressGroup');
417 0 0         $self->_error_handler($res)
418             unless $res->code == 200;
419 0           return $res->data;
420             }
421              
422              
423 0     0 1   sub list_addressgroup_names($self) {
  0            
  0            
424 0           my $res = $self->get('/gms/rest/ipObjects/addressGroupNames');
425 0 0         $self->_error_handler($res)
426             unless $res->code == 200;
427 0           return $res->data;
428             }
429              
430              
431 0     0 1   sub get_addressgroup($self, $name) {
  0            
  0            
  0            
432 0 0         my $res = $self->_is_version_93
433             ? $self->get('/gms/rest/ipObjects/addressGroup', { name => $name })
434             : $self->get('/gms/rest/ipObjects/addressGroup/' . uri_escape($name));
435 0 0         $self->_error_handler($res)
436             unless $res->code == 200;
437 0           return $res->data;
438             }
439              
440              
441 0     0 1   sub create_or_update_addressgroup($self, $name, $data) {
  0            
  0            
  0            
  0            
442 0           $data->{name} = $name;
443 0           $data->{type} = 'AG';
444 0           my $res = $self->post('/gms/rest/ipObjects/addressGroup', $data);
445 0 0         $self->_error_handler($res)
446             unless $res->code == 204;
447 0           return 1;
448             }
449              
450              
451 0     0 1   sub update_addressgroup($self, $name, $data) {
  0            
  0            
  0            
  0            
452 0           $data->{name} = $name;
453 0           $data->{type} = 'AG';
454 0           my $res = $self->put('/gms/rest/ipObjects/addressGroup', $data);
455 0 0         $self->_error_handler($res)
456             unless $res->code == 204;
457 0           return 1;
458             }
459              
460              
461 0     0 1   sub delete_addressgroup($self, $name) {
  0            
  0            
  0            
462 0 0         my $res = $self->_is_version_93
463             ? $self->delete('/gms/rest/ipObjects/addressGroup', { name => $name })
464             : $self->delete('/gms/rest/ipObjects/addressGroup/' . uri_escape($name));
465 0 0         $self->_error_handler($res)
466             unless $res->code == 204;
467 0           return 1;
468             }
469              
470              
471 0     0 1   sub list_servicegroups($self) {
  0            
  0            
472 0           my $res = $self->get('/gms/rest/ipObjects/serviceGroup');
473 0 0         $self->_error_handler($res)
474             unless $res->code == 200;
475 0           return $res->data;
476             }
477              
478              
479 0     0 1   sub list_servicegroup_names($self) {
  0            
  0            
480 0           my $res = $self->get('/gms/rest/ipObjects/serviceGroupNames');
481 0 0         $self->_error_handler($res)
482             unless $res->code == 200;
483 0           return $res->data;
484             }
485              
486              
487 0     0 1   sub get_servicegroup($self, $name) {
  0            
  0            
  0            
488 0 0         my $res = $self->_is_version_93
489             ? $self->get('/gms/rest/ipObjects/serviceGroup', { name => $name })
490             : $self->get('/gms/rest/ipObjects/serviceGroup/' . uri_escape($name));
491 0 0         $self->_error_handler($res)
492             unless $res->code == 200;
493 0           return $res->data;
494             }
495              
496              
497 0     0 1   sub create_or_update_servicegroup($self, $name, $data) {
  0            
  0            
  0            
  0            
498 0           $data->{name} = $name;
499 0           $data->{type} = 'SG';
500 0           my $res = $self->post('/gms/rest/ipObjects/serviceGroup', $data);
501 0 0         $self->_error_handler($res)
502             unless $res->code == 204;
503 0           return 1;
504             }
505              
506              
507 0     0 1   sub update_servicegroup($self, $name, $data) {
  0            
  0            
  0            
  0            
508 0           $data->{name} = $name;
509 0           $data->{type} = 'SG';
510 0           my $res = $self->put('/gms/rest/ipObjects/serviceGroup', $data);
511 0 0         $self->_error_handler($res)
512             unless $res->code == 204;
513 0           return 1;
514             }
515              
516              
517 0     0 1   sub delete_servicegroup($self, $name) {
  0            
  0            
  0            
518 0 0         my $res = $self->_is_version_93
519             ? $self->delete('/gms/rest/ipObjects/serviceGroup', { name => $name })
520             : $self->delete('/gms/rest/ipObjects/serviceGroup/' . uri_escape($name));
521 0 0         $self->_error_handler($res)
522             unless $res->code == 204;
523 0           return 1;
524             }
525              
526              
527 0     0 1   sub list_domain_applications($self, $resource_key='userDefined') {
  0            
  0            
  0            
528 0 0         my $res = $self->_is_version_93
529             ? $self->get('/gms/rest/applicationDefinition',
530             {
531             resourceKey => $resource_key,
532             base => 'dnsClassification',
533             })
534             : $self->get('/gms/rest/applicationDefinition/dnsClassification',
535             { resourceKey => $resource_key });
536 0 0         $self->_error_handler($res)
537             unless $res->code == 200;
538 0           return $res->data;
539             }
540              
541              
542 0     0 1   sub create_or_update_domain_application($self, $domain, $data) {
  0            
  0            
  0            
  0            
543 0           $data->{domain} = $domain;
544 0           my $res = $self->post('/gms/rest/applicationDefinition/dnsClassification2/domain', $data);
545 0 0         $self->_error_handler($res)
546             unless $res->code == 200;
547 0           return 1;
548             }
549              
550              
551 0     0 1   sub delete_domain_application($self, $domain) {
  0            
  0            
  0            
552 0 0         my $res = $self->_is_version_93
553             ? $self->delete('/gms/rest/applicationDefinition/dnsClassification', { domain => $domain })
554             : $self->delete('/gms/rest/applicationDefinition/dnsClassification/' . uri_escape($domain));
555 0 0         $self->_error_handler($res)
556             unless $res->code == 200;
557 0           return 1;
558             }
559              
560              
561 0     0 1   sub list_application_groups($self, $resource_key='userDefined') {
  0            
  0            
  0            
562 0           my $res = $self->get('/gms/rest/applicationDefinition/applicationTags',
563             { resourceKey => $resource_key });
564 0 0         $self->_error_handler($res)
565             unless $res->code == 200;
566 0           return $res->data;
567             }
568              
569              
570 0     0 1   sub create_or_update_application_group($self, $name, $data) {
  0            
  0            
  0            
  0            
571 0           my $application_groups = $self->list_application_groups;
572             # set or overwrite existing application group
573 0           $application_groups->{$name} = $data;
574 0           my $res = $self->post('/gms/rest/applicationDefinition/applicationTags',
575             $application_groups);
576 0 0         $self->_error_handler($res)
577             unless $res->code == 200;
578 0           return 1;
579             }
580              
581              
582 0     0 1   sub delete_application_group($self, $name) {
  0            
  0            
  0            
583 0           my $application_groups = $self->list_application_groups;
584             # set or overwrite existing application group
585             croak("application '$name' doesn't exist")
586 0 0         unless exists $application_groups->{$name};
587 0           delete $application_groups->{$name};
588 0           my $res = $self->post('/gms/rest/applicationDefinition/applicationTags',
589             $application_groups);
590 0 0         $self->_error_handler($res)
591             unless $res->code == 200;
592 0           return 1;
593             }
594              
595              
596             sub DEMOLISH {
597 0     0 0   my $self = shift;
598              
599 0 0 0       $self->logout
      0        
600             if $self->has_user
601             && $self->has_passwd
602             && $self->is_logged_in;
603             }
604              
605             1;
606              
607             __END__
608              
609             =pod
610              
611             =encoding UTF-8
612              
613             =head1 NAME
614              
615             Net::Silverpeak::Orchestrator - Silverpeak Orchestrator REST API client library
616              
617             =head1 VERSION
618              
619             version 0.016000
620              
621             =head1 SYNOPSIS
622              
623             use strict;
624             use warnings;
625             use Net::Silverpeak::Orchestrator;
626              
627             my $orchestrator = Net::Silverpeak::Orchestrator->new(
628             server => 'https://orchestrator.example.com',
629             user => 'username',
630             passwd => '$password',
631             clientattrs => { timeout => 30 },
632             );
633              
634             $orchestrator->login;
635              
636             # OR
637              
638             $orchestrator = Net::Silverpeak::Orchestrator->new(
639             server => 'https://orchestrator.example.com',
640             api_key => '$api-key',
641             clientattrs => { timeout => 30 },
642             );
643              
644             =head1 DESCRIPTION
645              
646             This module is a client library for the Silverpeak Orchestrator REST API.
647             Currently it is developed and tested against version 9.3.3.
648              
649             The REST API endpoints have changed with version 9.3 and since version 0.011
650             this module handles both.
651              
652             =head1 ATTRIBUTES
653              
654             =head2 is_logged_in
655              
656             Returns true if successfully logged in.
657              
658             =head1 METHODS
659              
660             =head2 login
661              
662             Logs into the Silverpeak Orchestrator.
663             Only required when using username and password, not for api key.
664              
665             =head2 logout
666              
667             Logs out of the Silverpeak Orchestrator.
668             Only possible when using username and password, not for api key.
669              
670             =head2 get_version
671              
672             Returns the Silverpeak Orchestrator version.
673              
674             =head2 list_templategroups
675              
676             Returns an arrayref of template groups.
677              
678             =head2 get_templategroup
679              
680             Returns a template group by name.
681              
682             =head2 create_templategroup
683              
684             Takes a template group name and a hashref with its config.
685              
686             Returns true on success.
687              
688             Throws an exception on error.
689              
690             =head2 update_templates_of_templategroup
691              
692             Takes a template group name and an arrayref of template names.
693              
694             Returns true on success.
695              
696             Throws an exception on error.
697              
698             =head2 update_templategroup
699              
700             Takes a template group name and a hashref of template configs.
701              
702             Returns true on success.
703              
704             Throws an exception on error.
705              
706             =head2 delete_templategroup
707              
708             Takes a template group name.
709              
710             Returns true on success.
711              
712             Throws an exception on error.
713              
714             =head2 has_segmentation_enabled
715              
716             Returns true if segmentation is enabled, else false.
717              
718             =head2 get_vrf_zones_map
719              
720             Returns a hashref of firewall zones indexed by VRF id and firewall zone id.
721              
722             =head2 get_vrf_by_id
723              
724             Returns a hashref of VRFs indexed by their id.
725              
726             =head2 get_vrf_security_policies_by_ids
727              
728             Takes the source and destination vrf ids.
729              
730             Returns a hashref containing all settings and security policies of a vrf.
731              
732             =head2 update_vrf_security_policies_by_ids
733              
734             Takes the source and destination vrf ids.
735              
736             Returns true on success.
737              
738             Throws an exception on error.
739              
740             =head2 list_appliances
741              
742             Returns an arrayref of appliances.
743              
744             =head2 get_appliance
745              
746             Returns an appliance by id.
747              
748             =head2 get_appliance_extrainfo
749              
750             Takes an appliance id.
751              
752             Returns a hashref with additional infos about the appliance like its location.
753              
754             =head2 get_ha_groups_by_id
755              
756             Returns a hashref of HA groups indexed by their id.
757              
758             =head2 list_groups
759              
760             Returns an arrayref of appliance groups.
761              
762             =head2 get_deployment
763              
764             Takes an appliance id.
765              
766             Returns a hashref containing the deployment data.
767              
768             =head2 get_interface_state
769              
770             Takes an interface id.
771              
772             Returns a hashref containing the interface state.
773              
774             =head2 get_interface_labels_by_type
775              
776             Returns a hashref containing the interface labels indexed by LAN/WAN and their id.
777              
778             =head2 get_appliance_ipsla_configs
779              
780             Takes an appliance id.
781              
782             Returns a hashref containing all IP SLA configurations.
783              
784             =head2 get_appliance_ipsla_states
785              
786             Takes an appliance id.
787              
788             Returns a hashref containing all IP SLA states.
789              
790             =head2 get_appliance_bgp_system_config
791              
792             Takes an appliance id and an optional hashref with additional query parameters.
793              
794             Returns a hashref containing the BGP system config.
795              
796             =head2 get_appliance_bgp_system_config_allvrfs
797              
798             Takes an appliance id and an optional hashref with additional query parameters.
799              
800             Returns a hashref containing the BGP system config for all VRFs indexed by VRF ID.
801              
802             =head2 get_appliance_bgp_neighbors
803              
804             Takes an appliance id and an optional hashref with additional query parameters.
805              
806             Returns a hashref containing all BGP neighbors.
807              
808             =head2 get_appliance_backups
809              
810             Takes an appliance id and an optional hashref with additional query parameters.
811             The runningConfig parameter defaults to false vs. true when not specified so
812             the contents of all backups aren't fetched.
813              
814             By passing { runningConfig => 'true', id => $id } as parameters, the contents
815             of a single backup can be fetched.
816              
817             Returns an arrayref of hashrefs containing all available backups.
818              
819             =head2 list_template_applianceassociations
820              
821             Returns a hashref of template to appliances associations.
822              
823             =head2 list_applianceids_by_templategroupname
824              
825             Returns an arrayref of appliance IDs a templategroup is assigned to.
826              
827             =head2 list_addressgroups
828              
829             Returns an arrayref of address groups.
830              
831             =head2 list_addressgroup_names
832              
833             Returns an arrayref of address group names.
834              
835             =head2 get_addressgroup
836              
837             Returns an address group by name.
838              
839             =head2 create_or_update_addressgroup
840              
841             Takes an address group name and a hashref of address group config.
842              
843             Returns true on success.
844              
845             Throws an exception on error.
846              
847             =head2 update_addressgroup
848              
849             Takes an address group name and a hashref of address group config.
850              
851             Returns true on success.
852              
853             Throws an exception on error.
854              
855             =head2 delete_addressgroup
856              
857             Takes an address group name.
858              
859             Returns true on success.
860              
861             Throws an exception on error.
862              
863             =head2 list_servicegroups
864              
865             Returns an arrayref of service groups.
866              
867             =head2 list_servicegroup_names
868              
869             Returns an arrayref of service group names.
870              
871             =head2 get_servicegroup
872              
873             Returns a service group by name.
874              
875             =head2 create_or_update_servicegroup
876              
877             Takes a service group name and a hashref of service group config.
878              
879             Returns true on success.
880              
881             Throws an exception on error.
882              
883             =head2 update_servicegroup
884              
885             Takes a service group name and a hashref of service group config.
886              
887             Returns true on success.
888              
889             Throws an exception on error.
890              
891             =head2 delete_servicegroup
892              
893             Takes a service group name.
894              
895             Returns true on success.
896              
897             Throws an exception on error.
898              
899             =head2 list_domain_applications
900              
901             Returns an arrayref of domain name applications for a resource key which
902             defaults to 'userDefined'.
903              
904             =head2 create_or_update_domain_application
905              
906             Takes a domain name application domain, not name, and a hashref of its config.
907              
908             Returns true on success.
909              
910             Throws an exception on error.
911              
912             =head2 delete_domain_application
913              
914             Takes a domain name, not application name.
915              
916             Returns true on success.
917              
918             Throws an exception on error.
919              
920             =head2 list_application_groups
921              
922             Returns a hashref of application groups indexed by their name for a resource
923             key which defaults to 'userDefined'.
924              
925             =head2 create_or_update_application_group
926              
927             Takes a application group name, and a hashref of its config.
928              
929             Returns true on success.
930              
931             Throws an exception on error.
932              
933             Because there is no API endpoint for creating or editing a single application
934             group, this method has to load all application groups using
935             L<list_application_groups>, modify and then save them.
936              
937             =head2 delete_application_group
938              
939             Takes an application group name.
940              
941             Returns true on success.
942              
943             Throws an exception on error.
944              
945             Because there is no API endpoint for deleting a single application group,
946             this method has to load all application groups using
947             L<list_application_groups>, remove the requested application group and then
948             save them.
949              
950             =head1 KNOWN SILVERPEAK ORCHESTRATOR BUGS
951              
952             =over
953              
954             =item http 500 response on api key authentication
955              
956             Orchestrator versions before version 9.0.4 respond with a http 500 error on
957             every request using an api key that has no expiration date set.
958             The only workaround is to set an expiration date for it.
959              
960             =back
961              
962             =for Pod::Coverage has_user has_passwd has_api_key
963              
964             =for Pod::Coverage DEMOLISH
965              
966             =head1 AUTHOR
967              
968             Alexander Hartmaier <abraxxa@cpan.org>
969              
970             =head1 COPYRIGHT AND LICENSE
971              
972             This software is copyright (c) 2024 by Alexander Hartmaier.
973              
974             This is free software; you can redistribute it and/or modify it under
975             the same terms as the Perl 5 programming language system itself.
976              
977             =cut