1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
Python interface to remctl
OVERVIEW
The Python interface to remctl provides Python bindings to the libremctl
client library plus a high-level interface that translates the libremctl
API into something closer to idiomatic Python.
This module provides three interfaces: a low-level interface that
provides a minimal translation from the libremctl API; a simple
interface in Python that performs a single call to a remctl server and
returns the result as an object; and a full interface in Python which
provides more control over the connection, returns individual output
tokens, and allows multiple commands to be sent via the same connection.
REQUIREMENTS
The module has been tested with Python 2.5 and may not work with older
versions of Python, although the only known incompatibility are
parameters in setup.py not supported prior to Python 2.3.
SIMPLIFIED INTERFACE
remctl.remctl(host, port, principal, command)
Runs a command on the remote system and returns an object containing
the results.
Arguments:
* host (required): string, the host to connect to
* port (optional): unsigned short, the port to connect to
* principal (optional): string, authentication identity of host
* command (required): sequence or iterator yielding the command
If port is not given, the library default is used (try 4373 first
and fall back to attempting the legacy 4444 port). If principal is
not given, the library default (host/<host> with the realm
determined by the domain-realm mapping) is used. To use the
defaults, only the host and command may be specified using named
arguments, or None can be passed as the port and principal
arguments.
command can be any sequence or iterator that returns a series of
strings or things that can be converted to strings making up the
command.
Returns an object of type RemctlSimpleResult with the following
attributes:
* stdout: string, the standard output from the command
* stderr: string, the standard error from the command
* status: integer, the exit status of the command
Exceptions:
* ValueError, TypeError: an invalid argument was supplied
* RemctlProtocolError: an error occurred in the remctl communication
The value attribute (or string value) of the RemctlProtocolError
exception contains the string returned by the remctl library. This
may be an internal error (such as a network error) or an error
returned by the remote server (such as an unknown command error).
Here is an example using the simplified interface:
import remctl, sys
command = ('test', 'test')
try:
result = remctl.remctl(host = 'foo.example.com', command = command)
except remctl.RemctlProtocolError, error:
print "Error:", str(error)
sys.exit(1)
if result.stdout:
print "stdout:", result.stdout
if result.stderr:
print "stderr:", result.stderr
print "exit status:", result.status
FULL INTERFACE
The full remctl interface requires the user to do more bookkeeping, but
provides more flexibility and visibility into what is happening at a
protocol level. It allows issuing multiple commands on the same
persistant connection (provided that the remote server supports protocol
version two; if it doesn't, the library will transparently fall back to
opening a connection for each command).
To use the full interface, first create a connection object with
remctl.Remctl() (either passing it the connection arguments or then
calling its open() method), and then call the command() method to issue
a command. Read output tokens with output() until a status token has
been received. Then the command is complete and another command can be
issued.
remctl.Remctl(host, port, principal)
The constructor. Create a new Remctl object. The arguments are
optional; if given, the constructor immediately calls open() and
passes those arguments to it. See below for their meaning and
possible exceptions.
All further methods below must be called on a Remctl object as returned
by the constructor.
Remctl.set_source_ip(source)
Sets the source IP for outgoing connections. This method must be
called prior to calling open() and will affect all subsequent open()
calls on the same object.
Arguments:
* source (required): string, the source IP address
The source may be either an IPv4 or an IPv6 address (if IPv6 is
supported). It must be an IP address, not a host name.
Exceptions:
* RemctlError: a memory allocation failure occurred
Remctl.open(host, port, principal)
Open a connection to a remote server and authenticate. There is no
return value; an exception is thrown on any error.
Arguments:
* host (required): string, the host to connect to
* port (optional): unsigned short, the port to connect to
* principal (optional): string, authentication identity of host
If port is not given, the library default is used (try 4373 first
and fall back to attempting the legacy 4444 port). If principal is
not given, the library default (host/<host> with the realm
determined by the domain-realm mapping) is used.
Exceptions:
* ValueError, TypeError: an invalid argument was supplied
* RemctlError: a network or authentication error occurred
The value attribute (or string value) of the RemctlError exception
contains the string returned by the remctl library, the same as
would be returned by the error() method.
Remctl.command(command)
Send a command to the remote host. There is no return value; an
exception is thrown on any error.
The Remctl object must already be connected. The command may, under
the remctl protocol, contain any character, but be aware that most
remctl servers will reject commands or arguments containing ASCII 0
(NUL). This currently therefore cannot be used for upload of
arbitrary unencoded binary data.
Arguments:
* command (required): sequence or iterator yielding the command
command can be any sequence or iterator that returns a series of
strings or things that can be converted to strings making up the
command.
Exceptions:
* ValueError, TypeError: an invalid argument was supplied
* RemctlError: a network or authentication error occurred
* RemctlNotOpenedError: no connection currently open
The value attribute (or string value) of the RemctlError exception
contains the string returned by the remctl library, the same as
would be returned by the error() method.
Remctl.output()
Reads an output token from the server and returns it as a tuple. A
command will result in either one error token or zero or more output
tokens followed by a status token. The output is complete as soon
as any token other than an output token has been received, but the
module will keep returning done tokens to the caller for as long as
output() is called without another call to command().
The members of the returned tuple are:
* type: string, "output", "status", "error", or "done"
* output: string, the returned output or error
* stream: integer, 1 for stdout or 2 for stderr for an output token
* status: integer, exit status of command for a status token
* error: integer, remctl protocol error for an error token
type will always be present. The other members of the tuple may be
None depending on the type of token. Output tokens will have
output and stream information, error tokens will have output and
error information, and status tokens will have status information.
done tokens will return None for all other elements.
For error tokens, error holds the numeric error code (see the remctl
protocol specification), which is the recommended value for programs
to check when looking for specific errors. output will contain an
English text translation of the error code and the exact text may
change.
Exceptions:
* RemctlNotOpenedError: no connection currently open
Remctl.close()
Close a connection. After calling this method, open() must be
called for this object before sending any further commands. The
connection will also be automatically closed when the object is
destroyed, so calling this method is often not necessary.
Remctl.error()
Returns the error from the last failed Remctl method. This will be
the same string as was returned as the string value of a RemctlError
or RemctlProtocolError exception.
LOW-LEVEL INTERFACE
This module also provides a _remctl module, which exports a low-level
interface with essentially the same API as the C API. It is very
similar to the simplified and full interface above except that the
simplified call returns its results as a tuple, status codes are
returned from functions instead of throwing exceptions (exceptions are
only thrown for things like out-of-memory errors), argument checking
won't be as nice and in some cases relies on the underlying libremctl C
library to do the error checking, and command arguments have to be lists
and not arbitrary sequences or iterators.
The _remctl interface is not currently documented or intended for direct
use. Use at your own risk.
HISTORY
The original implementation was written by Thomas L. Kula
<kula@tproa.net> and was known as pyremctl. As of remctl 2.13 it is
part of the stock remctl distribution and ongoing maintenance is done by
Russ Allbery and Thomas L. Kula.
THANKS
Andrew Mortensen for general code formatting comments and a reminder to
free malloc'd memory.
|