File Coverage

blib/lib/XAS/Lib/WS/RemoteShell.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package XAS::Lib::WS::RemoteShell;
2              
3             our $VERSION = '0.02';
4              
5 1     1   1089 use XAS::Lib::XML;
  0            
  0            
6             use XAS::Class
7             version => $VERSION,
8             base => 'XAS::Lib::WS::Base',
9             utils => ':validation dotid',
10             codec => 'base64',
11             accessors => 'created command_id shell_id stderr stdout exitcode clixml',
12             ;
13              
14             # ----------------------------------------------------------------------
15             # Public Methods
16             # ----------------------------------------------------------------------
17              
18             sub create {
19             my $self = shift;
20              
21             my $uuid = $self->uuid->create_str;
22             my $xml = $self->_create_xml($uuid);
23              
24             $self->log->debug(sprintf('create: uuid - %s', $uuid));
25              
26             $self->_make_call($xml);
27              
28             return $self->_create_response($uuid);
29              
30             }
31              
32             sub command {
33             my $self = shift;
34             my ($command) = validate_params(\@_, [1]);
35              
36             my $uuid = $self->uuid->create_str;
37             my $xml = $self->_command_xml($uuid, $command);
38              
39             $self->{'stdout'} = '';
40             $self->{'stderr'} = '';
41             $self->{'exitcode'} = -1;
42              
43             $self->log->debug(sprintf('command: uuid - %s', $uuid));
44              
45             $self->_make_call($xml);
46             $self->_command_response($uuid);
47              
48             }
49              
50             sub delete {
51             my $self = shift;
52              
53             my $uuid = $self->uuid->create_str;
54             my $xml = $self->_delete_xml($uuid);
55              
56             $self->_make_call($xml);
57              
58             return $self->_delete_response($uuid);
59              
60             }
61              
62             sub destroy {
63             my $self = shift;
64              
65             if ($self->created) {
66              
67             $self->delete();
68              
69             $self->{'created'} = 0;
70              
71             }
72              
73             }
74              
75             sub receive {
76             my $self = shift;
77              
78             my $running;
79             my $uuid = $self->uuid->create_str;
80             my $xml = $self->_receive_xml($uuid);
81              
82             do {
83              
84             $self->_make_call($xml);
85             $running = $self->_receive_response($uuid);
86              
87             } while ($running);
88              
89             }
90              
91             sub send {
92             my $self = shift;
93             my ($buffer, $eot) = validate_params(\@_, [
94             1,
95             { optional => 1, default => 1 },
96             ]);
97              
98             my $uuid = $self->uuid->create_str;
99             my $xml = $self->_send_xml($uuid, $buffer, $eot);
100              
101             $self->_make_call($xml);
102              
103             return $self->_send_response($uuid);
104              
105             }
106              
107             sub signal {
108             my $self = shift;
109              
110             my $uuid = $self->uuid->create_str;
111             my $xml = $self->_signal_xml($uuid);
112              
113             $self->_make_call($xml);
114              
115             return $self->_signal_response($uuid);
116              
117             }
118              
119             sub check_exitcode {
120             my $self = shift;
121              
122             my $caller = (caller(1))[3];
123             my $errmsg = $self->stdout;
124              
125             if ($self->exitcode > 0) {
126              
127             if ($self->stderr =~ /CLIXML/) { # Powershell error response
128              
129             $self->_parse_clixml();
130             $errmsg = $self->clixml->doc->toString();
131              
132             } else {
133              
134             $errmsg = $self->stderr;
135              
136             }
137              
138             $self->throw_msg(
139             dotid($self->class) . sprintf('.%s.badrc', $caller),
140             'ws_badrc',
141             $self->exitcode,
142             $errmsg
143             );
144              
145             }
146              
147             }
148              
149             # ----------------------------------------------------------------------
150             # Private Methods
151             # ----------------------------------------------------------------------
152              
153             sub _check_command_id {
154             my $self = shift;
155             my $uuid = shift;
156              
157             $self->log->debug(sprintf('check_command_id: %s = %s', $uuid, $self->command_id));
158              
159             unless ($uuid eq $self->command_id) {
160              
161             $self->throw_msg(
162             dotid($self->class) . '.check_command_id.wrongid',
163             'ws_wrongid'
164             );
165              
166             }
167              
168             }
169              
170             sub _parse_clixml {
171             my $self = shift;
172              
173             my $xml = $self->stderr;
174              
175             $xml =~ s/\#< CLIXML//g;
176             $xml =~ s/_x000D_//g;
177             $xml =~ s/_x000A_//g;
178              
179             $self->clixml->load($xml);
180              
181             }
182              
183             sub _create_response {
184             my $self = shift;
185             my $uuid = shift;
186              
187             my $xpath;
188             my $stat = 0;
189              
190             $self->_check_relates_to($uuid);
191              
192             if ($self->xml->get_item('//x:ResourceCreated')) {
193              
194             if (my $item = $self->xml->get_item('//rsp:ShellId')) {
195              
196             $self->{'shell_id'} = $item;
197             $self->{'created'} = 1;
198              
199             $self->log->debug(sprintf('create_response: shell_id = %s', $self->shell_id));
200              
201             $stat = 1;
202              
203             } else {
204              
205             $self->throw_msg(
206             dotid($self->class) . '._create_response.shell_id',
207             'ws_noshellid',
208             );
209              
210             }
211              
212             } else {
213              
214             $self->throw_msg(
215             dotid($self->class) . '._create_response.shell_id',
216             'ws_noresource',
217             );
218              
219             }
220              
221             return $stat;
222              
223             }
224              
225             sub _command_response {
226             my $self = shift;
227             my $uuid = shift;
228              
229             my $xpath = '//rsp:CommandId';
230              
231             $self->_check_relates_to($uuid);
232              
233             if (my $id = $self->xml->get_item($xpath)) {
234              
235             $self->{'command_id'} = $id;
236              
237             } else {
238              
239             $self->throw_msg(
240             dotid($self->class) . '._command_reponse.command_id',
241             'ws_nocmdid',
242             );
243              
244             }
245              
246             }
247              
248             sub _receive_response {
249             my $self = shift;
250             my $uuid = shift;
251              
252             my $running = 1;
253             my $xpath = '//rsp:ReceiveResponse';
254              
255             $self->_check_relates_to($uuid);
256              
257             my $elements = $self->xml->get_items($xpath);
258              
259             foreach my $element (@$elements) {
260              
261             if ($element->nodeName =~ /Stream/) {
262              
263             my $name = $element->getAttribute('Name');
264             my $id = $element->getAttribute('CommandId');
265              
266             $self->_check_command_id($id);
267              
268             if ($name =~ /stdout/) {
269              
270             if (my $stuff = $element->textContent) {
271              
272             $self->{'stdout'} .= decode($stuff);
273              
274             }
275              
276             } elsif ($name =~ /stderr/) {
277              
278             if (my $stuff = $element->textContent) {
279              
280             $self->{'stderr'} .= decode($stuff);
281              
282             }
283              
284             }
285              
286             } elsif ($element->nodeName =~ /CommandState/) {
287              
288             my $state = $element->getAttribute('State');
289             my $id = $element->getAttribute('CommandId');
290              
291             $self->_check_command_id($id);
292              
293             $running = ($state =~ /Running/ || 0);
294              
295             if (my $children = $element->childNodes) {
296              
297             foreach my $child (@$children) {
298              
299             if ($child->nodeName =~ /ExitCode/) {
300              
301             $self->{'exitcode'} = $child->textContent;
302              
303             }
304              
305             }
306              
307             }
308              
309             }
310              
311             }
312              
313             return $running;
314              
315             }
316              
317             sub _send_response {
318             my $self = shift;
319             my $uuid = shift;
320              
321             my $stat = 0;
322             my $xpath = '//rsp:SendResponse';
323              
324             $self->_check_relates_to($uuid);
325              
326             $stat = 1 if ($self->xml->get_items($xpath));
327              
328             return $stat;
329              
330             }
331              
332             sub _signal_response {
333             my $self = shift;
334             my $uuid = shift;
335              
336             my $stat = 0;
337             my $xpath = '//rsp:SignalResponse';
338              
339             $self->_check_relates_to($uuid);
340              
341             $stat = 1 if ($self->xml->get_item($xpath));
342              
343             return $stat;
344              
345             }
346              
347             sub _delete_response {
348             my $self = shift;
349             my $uuid = shift;
350              
351             my $stat = 0;
352             my $xpath = '//rsp:DeleteResponse';
353              
354             $self->_check_relates_to($uuid);
355              
356             $stat = 1 if ($self->xml->get_item($xpath));
357              
358             }
359              
360             sub init {
361             my $class = shift;
362              
363             my $self = $class->SUPER::init(@_);
364              
365             $self->{'created'} = 0;
366             $self->{'clixml'} = XAS::Lib::XML->new();
367              
368             return $self;
369              
370             }
371              
372             # ----------------------------------------------------------------------
373             # XML boilerplate - we're using heredoc for simplcity
374             #
375             # XML for ws-manage RemoteShell was taken from
376             # http://msdn.microsoft.com/en-us/library/cc251731.aspx
377             # ----------------------------------------------------------------------
378              
379             sub _command_xml {
380             my $self = shift;
381             my $uuid = shift;
382             my $command = shift;
383              
384             my $url = $self->url;
385             my $timeout = $self->timeout;
386             my $shell_id = $self->shell_id;
387              
388             my $xml = <<"XML";
389            
390            
391             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
392             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
393             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
394            
395            
396             $url
397            
398            
399             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
400            
401            
402            
403             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
404            
405            
406            
407             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Command
408            
409            
410             512000
411            
412            
413             uuid:$uuid
414            
415            
416            
417            
418             $shell_id
419            
420            
421            
422             TRUE
423             FALSE
424            
425             PT$timeout.000S
426            
427            
428            
429            
430             "$command"
431            
432            
433            
434            
435             XML
436              
437             return $xml;
438              
439             }
440              
441             sub _create_xml {
442             my $self = shift;
443             my $uuid = shift;
444              
445             my $url = $self->url;
446             my $timeout = $self->timeout;
447              
448             my $xml = <<"XML";
449            
450            
451             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
452             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
453             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
454            
455            
456             $url
457            
458            
459             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
460            
461            
462            
463             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
464            
465            
466            
467             http://schemas.xmlsoap.org/ws/2004/09/transfer/Create
468            
469            
470             512000
471            
472            
473             uuid:$uuid
474            
475            
476            
477             TRUE
478             437
479            
480            
481             PT$timeout.000S
482            
483            
484            
485            
486             stdin
487             stdout stderr
488            
489            
490            
491             XML
492              
493             return $xml;
494              
495             }
496              
497             sub _delete_xml {
498             my $self = shift;
499             my $uuid = shift;
500              
501             my $url = $self->url;
502             my $timeout = $self->timeout;
503             my $shell_id = $self->shell_id;
504              
505             my $xml = <<"XML";
506            
507            
508             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
509             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
510             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
511            
512            
513             $url
514            
515            
516            
517             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
518            
519            
520            
521             http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete
522            
523            
524             512000
525            
526            
527             uuid:$uuid
528            
529            
530            
531             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
532            
533            
534            
535             $shell_id
536            
537            
538             PT$timeout.000S
539            
540            
541            
542             XML
543              
544             return $xml;
545              
546             }
547              
548             sub _receive_xml {
549             my $self = shift;
550             my $uuid = shift;
551              
552             my $url = $self->url;
553             my $timeout = $self->timeout;
554             my $shell_id = $self->shell_id;
555             my $command_id = $self->command_id;
556              
557             my $xml = <<"XML";
558            
559            
560             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
561             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
562             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
563            
564            
565             $url
566            
567            
568            
569             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
570            
571            
572            
573             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive
574            
575            
576             512000
577            
578            
579             uuid:$uuid
580            
581            
582            
583             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
584            
585            
586            
587             $shell_id
588            
589            
590             PT$timeout.000S
591            
592            
593            
594             xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell"
595             SequenceId="0">
596            
597             stdout stderr
598            
599            
600            
601            
602             XML
603              
604             return $xml;
605              
606             }
607              
608             sub _send_xml {
609             my $self = shift;
610             my $uuid = shift;
611             my $buffer = shift;
612             my $eot = shift;
613              
614             my $url = $self->url;
615             my $timeout = $self->timeout;
616             my $shell_id = $self->shell_id;
617             my $command_id = $self->command_id;
618              
619             $buffer = encode($buffer);
620              
621             my $xml = <<"XML";
622            
623            
624             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
625             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
626             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
627            
628            
629             $url
630            
631            
632            
633             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
634            
635            
636            
637             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Send
638            
639            
640             153600
641            
642            
643             uuid:$uuid
644            
645            
646            
647             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
648            
649            
650            
651             $shell_id
652            
653            
654             PT$timeout.000S
655            
656            
657            
658            
659             xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell"
660             Name="stdin" CommandId="$command_id">
661             $buffer
662            
663            
664            
665            
666             XML
667              
668             return $xml;
669              
670             }
671              
672             sub _signal_xml {
673             my $self = shift;
674             my $uuid = shift;
675              
676             my $url = $self->url;
677             my $timeout = $self->timeout;
678             my $shell_id = $self->shell_id;
679             my $command_id = $self->command_id;
680              
681             my $xml = <<"XML";
682            
683            
684             xmlns:s="http://www.w3.org/2003/05/soap-envelope"
685             xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
686             xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
687            
688            
689             $url
690            
691            
692            
693             http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
694            
695            
696            
697             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Signal
698            
699            
700             512000
701            
702            
703             uuid:$uuid
704            
705            
706            
707             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd
708            
709            
710            
711             $shell_id
712            
713            
714             PT$timeout.000S
715            
716            
717            
718             xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell"
719             CommandId="$command_id">
720            
721             http://schemas.microsoft.com/wbem/wsman/1/windows/shell/signal/terminate
722            
723            
724            
725            
726             XML
727              
728             return $xml;
729              
730             }
731              
732              
733             1;
734              
735             __END__