line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SSH::RPC::Client; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = 1.201; |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
1600
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
6
|
1
|
|
|
1
|
|
1044
|
use Class::InsideOut qw(readonly private id register); |
|
1
|
|
|
|
|
9375
|
|
|
1
|
|
|
|
|
11
|
|
7
|
1
|
|
|
1
|
|
145
|
use JSON; |
|
1
|
|
|
|
|
15
|
|
|
1
|
|
|
|
|
8
|
|
8
|
1
|
|
|
1
|
|
1984
|
use Net::OpenSSH; |
|
1
|
|
|
|
|
54580
|
|
|
1
|
|
|
|
|
58
|
|
9
|
1
|
|
|
1
|
|
887
|
use SSH::RPC::Result; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
380
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
SSH::RPC::Client - The requestor, or client side, of an RPC call over SSH. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use SSH::RPC::Client; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $rpc = SSH::RPC::Client->new($host, $user); |
20
|
|
|
|
|
|
|
my $result = $rpc->run($command, \%args); # returns a SSH::RPC::Result object |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
if ($result->isSuccess) { |
23
|
|
|
|
|
|
|
say $result->getResponse; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
else { |
26
|
|
|
|
|
|
|
die $result->getError; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
SSH::RPC::Client allows you to make a remote procedure call over SSH to an L on the other end. In this way you can execute methods remotely on other servers while also passing and receiving complex data structures. The arguments and return values are serialized into JSON allowing shells to be written in languages other than Perl. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 METHODS |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
The following methods are available from this class. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=cut |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head2 ssh |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Constructs and returns a reference to the L object. |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
readonly ssh => my %ssh; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head2 new ( host, user, [ pass ]) |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Constructor. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head3 host |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
The hostname or ip address you want to connect to. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head3 user |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
The username you want to connect as. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head3 pass |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
The password to connect to this account. Can be omitted if you've set up an ssh key to automatically authenticate. See man ssh-keygen for details. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=cut |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub new { |
70
|
0
|
|
|
0
|
1
|
|
my ($class, $host, $user, $pass) = @_; |
71
|
0
|
|
|
|
|
|
my $self = register($class); |
72
|
0
|
|
|
|
|
|
$ssh{id $self} = Net::OpenSSH->new($host,user=>$user, password=>$pass, timeout=>30, master_opts => [ '-T']); |
73
|
0
|
|
|
|
|
|
return $self; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
#------------------------------------------------------------------- |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=head2 run ( command, [ args ] ) |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Execute a command on the remote shell. Returns a reference to an L object. |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head3 command |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
The method you wish to invoke. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head3 args |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
If the method has any arguments pass them in here as a scalar, hash reference, or array reference. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=cut |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub run { |
94
|
0
|
|
|
0
|
1
|
|
my ($self, $command, $args) = @_; |
95
|
0
|
|
|
|
|
|
my $json = JSON->new->utf8->pretty->encode({ |
96
|
|
|
|
|
|
|
command => $command, |
97
|
|
|
|
|
|
|
args => $args, |
98
|
|
|
|
|
|
|
}) . "\n"; # all requests must end with a \n |
99
|
0
|
|
|
|
|
|
my $ssh = $self->ssh; |
100
|
0
|
|
|
|
|
|
my $response; |
101
|
0
|
0
|
|
|
|
|
if ($ssh) { |
102
|
0
|
|
|
|
|
|
my $out; |
103
|
0
|
0
|
|
|
|
|
if ($out = $ssh->capture({stdin_data => $json, ssh_opts => ['-T']})) { |
104
|
0
|
|
|
|
|
|
$response = eval{JSON->new->utf8->decode($out)}; |
|
0
|
|
|
|
|
|
|
105
|
0
|
0
|
|
|
|
|
if ($@) { |
106
|
0
|
|
|
|
|
|
$response = {error=>"Response translation error. $@".$ssh->error, status=>510}; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
else { |
110
|
0
|
|
|
|
|
|
$response = {error=>"Transmission error. ".$ssh->error, status=>406}; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
else { |
114
|
0
|
|
|
|
|
|
$response = {error=>"Connection error. ".$ssh->error, status=>408}; |
115
|
|
|
|
|
|
|
} |
116
|
0
|
|
|
|
|
|
return SSH::RPC::Result->new($response); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head1 SEE ALSO |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
L and L are also good ways of solving this same problem. I chose not to use either for these reasons: |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=over |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=item Arbitrary Execution |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
They both allow arbitrary execution of Perl on the remote machine. While that's not all bad, in my circumstance that was a security risk that was unacceptable. Instead, SSH::RPC requires both a client and a shell be written, so you know exactly what's allowed to be executed. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item Language Neutral |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Because SSH::RPC uses JSON as a serialization layer between the connection, clients and shells can be written in languages other than Perl and still interoperate. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item Net::OpenSSH |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
The Net::OpenSSH module that SSH::RPC is based upon is fast, flexible, and most importantly way easier to install than the modules required by GRID::Machine and IPC::PerlSSH. |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=back |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head1 PREREQS |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
This package requires the following modules: |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
L |
145
|
|
|
|
|
|
|
L |
146
|
|
|
|
|
|
|
L |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head1 CAVEATS |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
You cannot use this module inside of mod_perl currently. Not sure why, but it hoses the SSH connection. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 AUTHOR |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
JT Smith |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 LEGAL |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
------------------------------------------------------------------- |
159
|
|
|
|
|
|
|
SSH::RPC::Client is Copyright 2008-2009 Plain Black Corporation |
160
|
|
|
|
|
|
|
and is licensed under the same terms as Perl itself. |
161
|
|
|
|
|
|
|
------------------------------------------------------------------- |
162
|
|
|
|
|
|
|
http://www.plainblack.com info@plainblack.com |
163
|
|
|
|
|
|
|
------------------------------------------------------------------- |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
1; |
169
|
|
|
|
|
|
|
|