File Coverage

blib/lib/Brocade/BSC.pm
Criterion Covered Total %
statement 25 27 92.5
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 34 36 94.4


line stmt bran cond sub pod time code
1             # Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
2             #
3             # All rights reserved.
4             #
5             # Redistribution and use in source and binary forms, with or without
6             # modification, are permitted provided that the following conditions are met:
7             #
8             # 1. Redistributions of source code must retain the above copyright notice,
9             # this list of conditions and the following disclaimer.
10             #
11             # 2. Redistributions in binary form must reproduce the above copyright notice,
12             # this list of conditions and the following disclaimer in the documentation
13             # and/or other materials provided with the distribution.
14             #
15             # 3. Neither the name of the copyright holder nor the names of its
16             # contributors may be used to endorse or promote products derived from this
17             # software without specific prior written permission.
18             #
19             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29             # THE POSSIBILITY OF SUCH DAMAGE.
30              
31             =head1 NAME
32              
33             Brocade::BSC - Configure and query the Brocade SDN controller.
34              
35             =head1 VERSION
36              
37             Version 1.0.4
38              
39             =head1 DESCRIPTION
40              
41             A I object is used to model, query, and configure Brocade's
42             OpenDaylight-based Software-Defined Networking controller.
43              
44             Most API methods return a duple: a I object, and a
45             reference to a data structure with the requested information. Status
46             should always be verified before attempting to dereference the second
47             return value.
48              
49             =cut
50              
51 1     1   19951 use version; our $VERSION = qv("v1.0.4");
  1         1935  
  1         6  
52              
53 1     1   71 use strict;
  1         2  
  1         18  
54 1     1   4 use warnings;
  1         5  
  1         35  
55              
56             package Brocade::BSC;
57              
58 1     1   541 use Brocade::BSC::Status qw(:constants);
  1         3  
  1         241  
59              
60 1     1   820 use YAML;
  1         9413  
  1         52  
61 1     1   182424 use LWP;
  1         394214  
  1         39  
62 1     1   8 use HTTP::Status qw(:constants :is status_message);
  1         2  
  1         583  
63 1     1   963 use JSON -convert_blessed_universally;
  1         12029  
  1         6  
64 1     1   668 use XML::Parser;
  0            
  0            
65             use Carp::Assert;
66              
67             =head1 METHODS
68              
69             =cut
70              
71             # Constructor ==========================================================
72             #
73             =over 4
74              
75             =item B
76              
77             Creates a new I object and populates fields with values
78             from argument hash, if present, or YAML configuration file.
79              
80             ### parameters:
81             # + cfgfile - path to YAML configuration file specifying controller attributes
82             # + ipAddr - IP address of controller
83             # + portNum - TCP port for controller's REST interface
84             # + adminName - username
85             # + adminPassword - password
86             # + timeout - for HTTP requests, in seconds
87             #
88             ### YAML configuration file labels and default values
89             #
90             # parameter hash | YAML label | default value
91             # -------------- | ----------- | -------------
92             # ipAddr | ctrlIpAddr | 127.0.0.1
93             # portNum | ctrlPortNum | 8181
94             # adminName | ctrlUname | admin
95             # adminPassword | ctrlPswd | admin
96             # timeout | timeout | 5
97              
98             Returns new I object.
99              
100             =cut
101             sub new {
102             my $caller = shift;
103             my %params = @_;
104              
105             my $yamlcfg;
106             if ($params{cfgfile} && ( -e $params{cfgfile})) {
107             $yamlcfg = YAML::LoadFile($params{cfgfile});
108             }
109             my $self = {
110             ipAddr => '127.0.0.1',
111             portNum => '8181',
112             adminName => 'admin',
113             adminPassword => 'admin',
114             timeout => 5
115             };
116             if ($yamlcfg) {
117             $yamlcfg->{ctrlIpAddr}
118             && ($self->{ipAddr} = $yamlcfg->{ctrlIpAddr});
119             $yamlcfg->{ctrlPortNum}
120             && ($self->{portNum} = $yamlcfg->{ctrlPortNum});
121             $yamlcfg->{ctrlUname}
122             && ($self->{adminName} = $yamlcfg->{ctrlUname});
123             $yamlcfg->{ctrlPswd}
124             && ($self->{adminPassword} = $yamlcfg->{ctrlPswd});
125             $yamlcfg->{timeout}
126             && ($self->{timeout} = $yamlcfg->{timeout});
127             }
128             map { $params{$_} && ($self->{$_} = $params{$_}) }
129             qw(ipAddr portNum adminName adminPassword timeout);
130             bless $self;
131             }
132              
133             # Method ===============================================================
134             # _http_req : semi-private; send HTTP request to BSC Controller
135             # Parameters: $method (string, req) HTTP verb
136             # : $urlpath (string, req) path for REST request
137             # : $data (string, opt)
138             # : $headerref (hash ref, opt)
139             # Returns : HTTP::Response
140             #
141             sub _http_req {
142             my $self = shift;
143             my ($method, $urlpath, $data, $headerref) = @_;
144             my %headers = $headerref ? %$headerref : ();
145              
146             my $url = "http://$$self{ipAddr}:$$self{portNum}$urlpath";
147             my $ua = LWP::UserAgent->new;
148             $ua->timeout($self->{timeout});
149             my $req = HTTP::Request->new($method => $url);
150             while (my($header, $value) = each %headers) {
151             $req->header($header => $value);
152             }
153             if ($data) {
154             $req->content($data);
155             }
156             $req->authorization_basic($$self{adminName}, $$self{adminPassword});
157              
158             return $ua->request($req);
159             }
160              
161             # Method ===============================================================
162             #
163             =item B
164              
165             # Returns pretty-printed JSON string representing BSC object.
166              
167             =cut
168             sub as_json {
169             my $self = shift;
170             my $json = new JSON->canonical->allow_blessed->convert_blessed;
171             return $json->pretty->encode($self);
172             }
173              
174             # Method ===============================================================
175             #
176             =item B
177              
178             # Returns : BSC::Status
179             # : reference to an array of node names
180              
181             =cut
182             sub get_nodes_operational_list {
183             my $self = shift;
184             my @nodeNames = ();
185             my $status = new Brocade::BSC::Status;
186             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes";
187              
188             my $resp = $self->_http_req('GET', $urlpath);
189             if ($resp->code == HTTP_OK) {
190             if ($resp->content =~ /\"nodes\"/) {
191             my $nodes = decode_json($resp->content)->{nodes}->{node};
192             if (! $nodes) {
193             $status->code($BSC_DATA_NOT_FOUND);
194             }
195             else {
196             foreach (@$nodes) {
197             push @nodeNames, $_->{id};
198             }
199             $status->code($BSC_OK);
200             }
201             }
202             else {
203             $status->code($BSC_DATA_NOT_FOUND);
204             }
205             }
206             else {
207             $status->http_err($resp);
208             }
209             return ($status, \@nodeNames);
210             }
211              
212             # Method ===============================================================
213             #
214             =item B
215              
216             # Parameter : node name (string, required)
217             # Returns : BSC::Status
218             # : array reference containing node info
219              
220             =cut
221             sub get_node_info {
222             my $self = shift;
223             my $node = shift;
224             my $node_info = undef;
225             my $status = new Brocade::BSC::Status;
226             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes/node/$node";
227              
228             my $resp = $self->_http_req('GET', $urlpath);
229             if ($resp->code == HTTP_OK) {
230             if ($resp->content =~ /\"node\"/) {
231             $node_info = decode_json($resp->content)->{node};
232             $status->code($node_info ? $BSC_OK : $BSC_DATA_NOT_FOUND);
233             }
234             }
235             else {
236             $status->http_err($resp);
237             }
238             return ($status, $node_info);
239             }
240              
241             # Method ===============================================================
242             #
243             =item B
244              
245             # Parameter : node name (string, required)
246             # Returns : BSC::Status - NODE_CONFIGURED or NODE_NOT_FOUND
247              
248             =cut
249             sub check_node_config_status {
250             my $self = shift;
251             my $node = shift;
252             my $status = new Brocade::BSC::Status;
253              
254             my $urlpath = "/restconf/config/opendaylight-inventory:nodes/node/$node";
255             my $resp = $self->_http_req('GET', $urlpath);
256             $status->code(($resp->code == HTTP_OK)
257             ? $BSC_NODE_CONFIGURED : $BSC_NODE_NOT_FOUND);
258             return $status;
259             }
260              
261             # Method ===============================================================
262             #
263             =item B
264              
265             # Parameter : node name (string, required)
266             # Returns : BSC::Status - NODE_CONNECTED or NODE_DISCONNECTED
267              
268             =cut
269             sub check_node_conn_status {
270             my $self = shift;
271             my $node = shift;
272             my $status = new Brocade::BSC::Status;
273             ($status, my $nodeStatus) = $self->get_all_nodes_conn_status();
274             if ($status->ok) {
275             $status->code($BSC_NODE_NOT_FOUND);
276             foreach (@$nodeStatus) {
277             if ($_->{id} eq $node) {
278             $status->code($_->{connected} ? $BSC_NODE_CONNECTED
279             : $BSC_NODE_DISCONNECTED);
280             last;
281             }
282             }
283             }
284             return $status;
285             }
286              
287             # Method ===============================================================
288             #
289             =item B
290              
291             # Returns : BSC::Status
292             # : array reference - list of node identifiers
293              
294             =cut
295             sub get_all_nodes_in_config {
296             my $self = shift;
297             my @nodeNames = ();
298             my $status = new Brocade::BSC::Status;
299             my $urlpath = "/restconf/config/opendaylight-inventory:nodes";
300              
301             my $resp = $self->_http_req('GET', $urlpath);
302             if ($resp->code == HTTP_OK) {
303             if ($resp->content =~ /\"nodes\"/) {
304             my $nodes = decode_json($resp->content)->{nodes}->{node};
305             if (! $nodes) {
306             $status->code($BSC_DATA_NOT_FOUND);
307             }
308             else {
309             foreach (@$nodes) {
310             push @nodeNames, $_->{id};
311             }
312             $status->code($BSC_OK);
313             }
314             }
315             else {
316             $status->code($BSC_DATA_NOT_FOUND);
317             }
318             }
319             else {
320             $status->http_err($resp);
321             }
322             return ($status, \@nodeNames);
323             }
324              
325             # Method ===============================================================
326             #
327             =item B
328              
329             # Returns : BSC::Status
330             # : reference to array of hashes:
331             # { id => nodename,
332             # connected => boolean }
333              
334             =cut
335             #
336             # Openflow devices on the Controller are always prefixed with "openflow:"
337             # Since Openflow devices initiate communication with the Controller, and
338             # not vice versa as with NETCONF devices, any Openflow devices in the
339             # operational inventory are shown as connected.
340             #
341             sub get_all_nodes_conn_status {
342             my $self = shift;
343             my @nodeStatus = ();
344             my $status = new Brocade::BSC::Status;
345             my $connected = undef;
346             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes";
347              
348             my $resp = $self->_http_req('GET', $urlpath);
349             if ($resp->code == HTTP_OK) {
350             if ($resp->content =~ /\"nodes\"/) {
351             my $nodes = decode_json($resp->content)->{nodes}->{node};
352             if (! $nodes) {
353             $status->code($BSC_DATA_NOT_FOUND);
354             }
355             else {
356             foreach (@$nodes) {
357             if ($_->{id} =~ /^openflow:/) {
358             $connected = 1;
359             }
360             else {
361             $connected = $_->{"netconf-node-inventory:connected"};
362             }
363             push @nodeStatus, {'id' => $_->{id},
364             'connected' => $connected}
365             }
366             $status->code($BSC_OK);
367             }
368             }
369             else {
370             $status->code($BSC_DATA_NOT_FOUND);
371             }
372             }
373             else {
374             $status->http_err($resp);
375             }
376             return ($status, \@nodeStatus);
377             }
378              
379             # Method ===============================================================
380             #
381             =item B
382              
383             # Returns : BSC::Status
384             # : array reference - list of node identifiers
385              
386             =cut
387             sub get_netconf_nodes_in_config {
388             my $self = shift;
389             my @netconf_nodes = undef;
390              
391             my ($status, $nodelist_ref) = $self->get_all_nodes_in_config();
392             $status->ok and @netconf_nodes = grep !/^openflow:/, @$nodelist_ref;
393             return ($status, \@netconf_nodes);
394             }
395              
396             # Method ===============================================================
397             #
398             =item B
399              
400             # Returns : BSC::Status
401             # : reference to array of hashes:
402             # { id => nodename,
403             # connected => boolean }
404              
405             =cut
406             sub get_netconf_nodes_conn_status {
407             my $self = shift;
408             my @netconf_nodes = undef;
409              
410             my ($status, $nodestatus_ref) = $self->get_all_nodes_conn_status();
411             $status->ok and
412             @netconf_nodes = grep { $_->{id} !~ /^openflow:/ } @$nodestatus_ref;
413             return ($status, \@netconf_nodes);
414             }
415              
416             # Method ===============================================================
417             #
418             =item B
419              
420             # Parameters: node name (string, required)
421             # Returns : BSC::Status
422             # : array reference - supported schemas on node
423              
424             =cut
425             sub get_schemas {
426             my $self = shift;
427             my $node = shift;
428             my $schemas = undef;
429             my $status = new Brocade::BSC::Status;
430             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes/node/"
431             . "$node/yang-ext:mount/ietf-netconf-monitoring:netconf-state/schemas";
432              
433             my $resp = $self->_http_req('GET', $urlpath);
434             if ($resp->code == HTTP_OK) {
435             if ($resp->content =~ /\"schemas\"/) {
436             $schemas = decode_json($resp->content)->{schemas}->{schema};
437             $status->code($schemas ? $BSC_OK : $BSC_DATA_NOT_FOUND);
438             }
439             else {
440             $status->code($BSC_DATA_NOT_FOUND);
441             }
442             }
443             else {
444             $status->http_err($resp);
445             }
446             return ($status, $schemas);
447             }
448              
449             # Method ===============================================================
450             #
451             =item B
452              
453             # Parameters: node name
454             # : YANG schema ID
455             # : YANG schema version
456             # Returns : BSC::Status
457             # : requested YANG schema as formatted JSON
458              
459             =cut
460             sub get_schema {
461             my $self = shift;
462             my ($node, $schemaId, $schemaVersion) = @_;
463             my $status = new Brocade::BSC::Status;
464             my $schema = undef;
465              
466             my $urlpath = "/restconf/operations/opendaylight-inventory:nodes"
467             . "/node/$node/yang-ext:mount/ietf-netconf-monitoring:get-schema";
468             my $payload = qq({"input":{"identifier":"$schemaId","version":)
469             . qq("$schemaVersion","format":"yang"}});
470             my %headers = ('content-type'=>'application/yang.data+json',
471             'accept'=>'text/json, text/html, application/xml, */*');
472              
473             my $resp = $self->_http_req('POST', $urlpath, $payload, \%headers);
474             if ($resp->code == HTTP_OK) {
475             my $xmltree_ref = new XML::Parser(Style => 'Tree')->parse($resp->content);
476             assert ($xmltree_ref->[0] eq 'get-schema');
477             assert ($xmltree_ref->[1][1] eq 'output');
478             assert ($xmltree_ref->[1][2][1] eq 'data');
479             assert ($xmltree_ref->[1][2][2][1] == 0);
480             $schema = $xmltree_ref->[1][2][2][2];
481             $status->code($BSC_OK);
482             }
483             else {
484             $status->http_err($resp);
485             }
486             return ($status, $schema);
487             }
488              
489             # Method ===============================================================
490             #
491             =item B
492              
493             # Parameters: node name
494             # Returns : BSC::Status
495             # : hash reference - operations supported by specified node
496              
497             =cut
498             sub get_netconf_operations {
499             my $self = shift;
500             my $node = shift;
501             my $operations = undef;
502             my $status = new Brocade::BSC::Status;
503             my $urlpath = "/restconf/operations/opendaylight-inventory:nodes/node/$node/yang-ext:mount/";
504              
505             my $resp = $self->_http_req('GET', $urlpath);
506             if ($resp->code == HTTP_OK) {
507             if ($resp->content =~ /\"operations\"/) {
508             $operations = decode_json($resp->content)->{operations};
509             $status->code($BSC_OK);
510             }
511             else {
512             $status->code($BSC_DATA_NOT_FOUND);
513             }
514             }
515             else {
516             $status->http_err($resp);
517             }
518             return ($status, $operations);
519             }
520              
521             # Method ===============================================================
522             #
523             =item B
524              
525             # Returns : BSC::Status
526             # : array reference - hashes of module state
527              
528             =cut
529             sub get_all_modules_operational_state {
530             my $self = shift;
531             my $modules = undef;
532             my $status = new Brocade::BSC::Status;
533             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:modules";
534            
535             my $resp = $self->_http_req('GET', $urlpath);
536             if ($resp->code == HTTP_OK) {
537             if ($resp->content =~ /\"modules\"/) {
538             # BVC returns bad JSON on this REST call. Sanitize.
539             my $json = $resp->content;
540             $json =~ s/\\\n//g;
541             $modules = decode_json($json)->{modules}->{module};
542             $status->code($modules ? $BSC_OK : $BSC_DATA_NOT_FOUND);
543             }
544             else {
545             $status->code($BSC_DATA_NOT_FOUND);
546             }
547             }
548             else {
549             $status->http_err($resp);
550             }
551             return ($status, $modules);
552             }
553              
554             # Method ===============================================================
555             #
556             =item B
557              
558             # Parameter : module type
559             # : module name
560             # Returns : BSC::Status
561             # : array reference - hash of module state
562              
563             =cut
564             sub get_module_operational_state {
565             my $self = shift;
566             my ($moduleType, $moduleName) = @_;
567             my $module = undef;
568             my $status = new Brocade::BSC::Status;
569             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:modules/module/$moduleType/$moduleName";
570              
571             my $resp = $self->_http_req('GET', $urlpath);
572             if ($resp->code == HTTP_OK ) {
573             if ($resp->content =~ /\"module\"/) {
574             $module = decode_json($resp->content)->{module};
575             $status->code($module ? $BSC_OK : $BSC_DATA_NOT_FOUND);
576             }
577             else {
578             $status->code($BSC_DATA_NOT_FOUND);
579             }
580             }
581             else {
582             $status->http_err($resp);
583             }
584             return ($status, $module);
585             }
586              
587             # Method ===============================================================
588             #
589             =item B
590              
591             # Parameters: node name
592             # Returns : BSC::Status
593             # : hash reference - session listing on specified node
594              
595             =cut
596             sub get_sessions_info {
597             my $self = shift;
598             my $node = shift;
599             my $sessions = undef;
600             my $status = new Brocade::BSC::Status;
601             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes/node/$node/yang-ext:mount/ietf-netconf-monitoring:netconf-state/sessions";
602              
603             my $resp = $self->_http_req('GET', $urlpath);
604             if ($resp->code == HTTP_OK) {
605             if ($resp->content =~ /\"sessions\"/) {
606             $sessions = decode_json($resp->content)->{sessions};
607             $status->code($sessions ? $BSC_OK : $BSC_DATA_NOT_FOUND);
608             }
609             else {
610             $status->code($BSC_DATA_NOT_FOUND);
611             }
612             }
613             else {
614             $status->http_err($resp);
615             }
616             return ($status, $sessions);
617             }
618              
619             # Method ===============================================================
620             #
621             =item B
622              
623             # Parameters:
624             # Returns : BSC::Status
625             # : hash reference - streams info
626              
627             =cut
628             sub get_streams_info {
629             my $self = shift;
630             my $streams = undef;
631             my $status = new Brocade::BSC::Status;
632             my $urlpath = "/restconf/streams";
633              
634             my $resp = $self->_http_req('GET', $urlpath);
635             if ($resp->code == HTTP_OK) {
636             if ($resp->content =~ /\"streams\"/) {
637             $streams = decode_json($resp->content)->{streams};
638             $status->code($streams ? $BSC_OK : $BSC_DATA_NOT_FOUND);
639             }
640             else {
641             $status->code($BSC_DATA_NOT_FOUND);
642             }
643             }
644             else {
645             $status->http_err($resp);
646             }
647             return ($status, $streams);
648             }
649              
650             # Method ===============================================================
651             #
652             =item B
653              
654             # Parameters:
655             # Returns : BSC::Status
656             # : array reference ~ name/provider pairs
657              
658             =cut
659             sub get_service_providers_info {
660             my $self = shift;
661             my $service = undef;
662             my $status = new Brocade::BSC::Status;
663             my $urlpath = "/restconf/config/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:services";
664              
665             my $resp = $self->_http_req('GET', $urlpath);
666             if ($resp->code == HTTP_OK) {
667             if ($resp->content =~ /\"services\"/) {
668             $service = decode_json($resp->content)->{services}->{service};
669             $status->code($service ? $BSC_OK : $BSC_DATA_NOT_FOUND);
670             }
671             else {
672             $status->code($BSC_DATA_NOT_FOUND);
673             }
674             }
675             else {
676             $status->http_err($resp);
677             }
678             return ($status, $service);
679             }
680              
681             # Method ===============================================================
682             #
683             =item B
684              
685             # Parameters: node name
686             # Returns : BSC::Status
687             # : array reference ~ name/provider pairs
688              
689             =cut
690             sub get_service_provider_info {
691             my $self = shift;
692             my $name = shift;
693             my $service = undef;
694             my $status = new Brocade::BSC::Status;
695             my $urlpath = "/restconf/config/opendaylight-inventory:nodes/node"
696             . "/controller-config/yang-ext:mount/config:services/service/$name";
697              
698             my $resp = $self->_http_req('GET', $urlpath);
699             if ($resp->code == HTTP_OK) {
700             if ($resp->content =~ /\"service\"/) {
701             $service = decode_json($resp->content)->{service};
702             $status->code($BSC_OK);
703             }
704             else {
705             $status->code($BSC_DATA_NOT_FOUND);
706             }
707             }
708             else {
709             $status->http_err($resp);
710             }
711             return ($status, $service);
712             }
713              
714             # Method ===============================================================
715             #
716             =item B
717              
718             Add a mount point on controller for specified node.
719              
720             # Parameters: node name
721             # Returns : BSC::Status
722              
723             =cut
724             sub add_netconf_node {
725             my $self = shift;
726             my $node = shift;
727             my $status = new Brocade::BSC::Status($BSC_OK);
728              
729             my $urlpath = "/restconf/config/opendaylight-inventory:nodes/node/controller-config/yang-ext:mount/config:modules";
730             my %headers = ('content-type' => 'application/xml',
731             'accept' => 'application/xml');
732             my $xmlPayload = <
733            
734             prefix:sal-netconf-connector
735             $node->{name}
736            
$node->{ipAddr}
737             $node->{portNum}
738             $node->{adminName}
739             $node->{adminPassword}
740             $node->{tcpOnly}
741            
742             prefix:netty-event-executor
743             global-event-executor
744            
745            
746             prefix:binding-broker-osgi-registry
747             binding-osgi-broker
748            
749            
750             prefix:dom-broker-osgi-registry
751             dom-broker
752            
753            
754             prefix:netconf-client-dispatcher
755             global-netconf-dispatcher
756            
757            
758             prefix:threadpool
759             global-netconf-processing-executor
760            
761            
762             END_XML
763              
764             my $resp = $self->_http_req('POST', $urlpath, $xmlPayload, \%headers);
765             $resp->is_success or $status->http_err($resp);
766             return $status;
767             }
768              
769             # Method ===============================================================
770             #
771             =item B
772              
773             # Parameters: node name
774             # Returns : BSC::Status
775             # :
776              
777             =cut
778             sub delete_netconf_node {
779             my $self = shift;
780             my $node = shift;
781             my $status = new Brocade::BSC::Status($BSC_OK);
782             my $urlpath = "/restconf/config/opendaylight-inventory:nodes/node"
783             . "/controller-config/yang-ext:mount/config:modules/module"
784             . "/odl-sal-netconf-connector-cfg:sal-netconf-connector/"
785             . $node->{name};
786              
787             my $resp = $self->_http_req('DELETE', $urlpath);
788             $resp->is_success or $status->http_err($resp);
789             return $status;
790             }
791              
792             # Method ===============================================================
793             #
794             # =item B
795             #
796             # # Parameters:
797             # # Returns : BSC::Status
798             # # :
799             #
800             # =cut
801             sub modify_netconf_node_in_config {
802             my $self = shift;
803             my $node = shift;
804              
805             die "XXX";
806             }
807              
808             # Method ===============================================================
809             #
810             =item B
811              
812             # Parameters: node name
813             # Returns : base restconf URL for configuration of mounted netconf node
814              
815             =cut
816             sub get_ext_mount_config_urlpath {
817             my $self = shift;
818             my $node = shift;
819              
820             return "/restconf/config/opendaylight-inventory:nodes/node/"
821             . "$node/yang-ext:mount/";
822             }
823              
824             # Method ===============================================================
825             #
826             =item B
827              
828             # Parameters: node name
829             # Returns : base restconf URL for operational status of mounted netconf node
830              
831             =cut
832             sub get_ext_mount_operational_urlpath {
833             my $self = shift;
834             my $node = shift;
835              
836             return "/restconf/operational/opendaylight-inventory:nodes/node/"
837             . "$node/yang-ext:mount/";
838             }
839              
840             # Method ===============================================================
841             #
842             =item B
843              
844             # Parameters: node name
845             # Returns : base restconf URL for node, operational status
846              
847             =cut
848             sub get_node_operational_urlpath {
849             my $self = shift;
850             my $node = shift;
851              
852             return "/restconf/operational/opendaylight-inventory:nodes/node/$node";
853             }
854              
855             # Method ===============================================================
856             #
857             =item B
858              
859             # Parameters: node name
860             # Returns : base restconf URL for node, configuration
861              
862             =cut
863             sub get_node_config_urlpath {
864             my $self = shift;
865             my $node = shift;
866              
867             return "/restconf/config/opendaylight-inventory:nodes/node/$node";
868             }
869              
870             # Method ===============================================================
871             #
872             =item B
873              
874             # Returns : BSC::Status
875             # : array reference - node names
876              
877             =cut
878             sub get_openflow_nodes_operational_list {
879             my $self = shift;
880             my $status = new Brocade::BSC::Status;
881             my @nodelist = ();
882              
883             my $urlpath = "/restconf/operational/opendaylight-inventory:nodes";
884             my $resp = $self->_http_req('GET', $urlpath);
885             if ($resp->code == HTTP_OK) {
886             if ($resp->content =~ /\"nodes\"/) {
887             my $nodes = decode_json($resp->content)->{nodes}->{node};
888             if (! $nodes) {
889             $status->code($BSC_DATA_NOT_FOUND);
890             }
891             else {
892             $status->code($BSC_OK);
893             foreach (@$nodes) {
894             $_->{id} =~ /^(openflow:[0-9]*)/ && push @nodelist, $1;
895             }
896             }
897             }
898             }
899             else {
900             $status->http_err($resp);
901             }
902             return ($status, \@nodelist);
903             }
904              
905             # Module ===============================================================
906             1;
907              
908             =back
909              
910             =head1 AUTHOR
911              
912             C<< >>
913              
914             =head1 BUGS
915              
916             Please report any bugs or feature requests to C,
917             or through the web interface at
918             L.
919             I will be notified, and then you'll automatically be notified of progress on
920             your bug as I make changes.
921              
922              
923             =head1 SUPPORT
924              
925             You can find documentation for this module with the perldoc command.
926              
927             perldoc Brocade::BSC
928              
929              
930             You can also look for information at:
931              
932             =over 4
933              
934             =item * RT: CPAN's request tracker (report bugs here)
935              
936             L
937              
938             =back
939              
940              
941             =head1 ACKNOWLEDGEMENTS
942              
943             Brocade::BSC is entirely based on L
944             created by Sergei Garbuzov.
945              
946              
947             =head1 COPYRIGHT
948              
949             Copyright (c) 2015, BROCADE COMMUNICATIONS SYSTEMS, INC
950              
951             All rights reserved.