root / ncclient / operations / rpc.py @ bd7957fb
History | View | Annotate | Download (12.5 kB)
1 | a14c36f9 | Shikhar Bhushan | # Copyright 2009 Shikhar Bhushan
|
---|---|---|---|
2 | a14c36f9 | Shikhar Bhushan | #
|
3 | a14c36f9 | Shikhar Bhushan | # Licensed under the Apache License, Version 2.0 (the "License");
|
4 | a14c36f9 | Shikhar Bhushan | # you may not use this file except in compliance with the License.
|
5 | a14c36f9 | Shikhar Bhushan | # You may obtain a copy of the License at
|
6 | a14c36f9 | Shikhar Bhushan | #
|
7 | a14c36f9 | Shikhar Bhushan | # http://www.apache.org/licenses/LICENSE-2.0
|
8 | a14c36f9 | Shikhar Bhushan | #
|
9 | a14c36f9 | Shikhar Bhushan | # Unless required by applicable law or agreed to in writing, software
|
10 | a14c36f9 | Shikhar Bhushan | # distributed under the License is distributed on an "AS IS" BASIS,
|
11 | a14c36f9 | Shikhar Bhushan | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 | a14c36f9 | Shikhar Bhushan | # See the License for the specific language governing permissions and
|
13 | a14c36f9 | Shikhar Bhushan | # limitations under the License.
|
14 | a14c36f9 | Shikhar Bhushan | |
15 | a14c36f9 | Shikhar Bhushan | from threading import Event, Lock |
16 | a14c36f9 | Shikhar Bhushan | from uuid import uuid1 |
17 | a14c36f9 | Shikhar Bhushan | |
18 | 9667bcb2 | Shikhar Bhushan | from ncclient.xml_ import * |
19 | 0cdb8b3c | Shikhar Bhushan | from ncclient.transport import SessionListener |
20 | a14c36f9 | Shikhar Bhushan | |
21 | 216bb34c | Shikhar Bhushan | from errors import OperationError, TimeoutExpiredError, MissingCapabilityError |
22 | a14c36f9 | Shikhar Bhushan | |
23 | a14c36f9 | Shikhar Bhushan | import logging |
24 | 9667bcb2 | Shikhar Bhushan | logger = logging.getLogger("ncclient.operations.rpc")
|
25 | a14c36f9 | Shikhar Bhushan | |
26 | a14c36f9 | Shikhar Bhushan | |
27 | a14c36f9 | Shikhar Bhushan | class RPCReply: |
28 | 4f650d54 | Shikhar Bhushan | |
29 | a7cb58ce | Shikhar Bhushan | """Represents an *<rpc-reply>*. Only concerns itself with whether the
|
30 | 216bb34c | Shikhar Bhushan | operation was successful.
|
31 | 216bb34c | Shikhar Bhushan |
|
32 | 216bb34c | Shikhar Bhushan | .. note::
|
33 | 216bb34c | Shikhar Bhushan | If the reply has not yet been parsed there is an implicit, one-time
|
34 | 216bb34c | Shikhar Bhushan | parsing overhead to accessing the attributes defined by this class and
|
35 | 216bb34c | Shikhar Bhushan | any subclasses.
|
36 | 216bb34c | Shikhar Bhushan | """
|
37 | a7cb58ce | Shikhar Bhushan | |
38 | a14c36f9 | Shikhar Bhushan | def __init__(self, raw): |
39 | a14c36f9 | Shikhar Bhushan | self._raw = raw
|
40 | a14c36f9 | Shikhar Bhushan | self._parsed = False |
41 | a14c36f9 | Shikhar Bhushan | self._root = None |
42 | a14c36f9 | Shikhar Bhushan | self._errors = []
|
43 | 4f650d54 | Shikhar Bhushan | |
44 | a14c36f9 | Shikhar Bhushan | def __repr__(self): |
45 | a14c36f9 | Shikhar Bhushan | return self._raw |
46 | 4f650d54 | Shikhar Bhushan | |
47 | a7cb58ce | Shikhar Bhushan | def _parsing_hook(self, root): |
48 | a7cb58ce | Shikhar Bhushan | """Subclass can implement.
|
49 | a7cb58ce | Shikhar Bhushan |
|
50 | a7cb58ce | Shikhar Bhushan | :type root: :class:`~xml.etree.ElementTree.Element`
|
51 | a7cb58ce | Shikhar Bhushan | """
|
52 | a7cb58ce | Shikhar Bhushan | pass
|
53 | 4f650d54 | Shikhar Bhushan | |
54 | a14c36f9 | Shikhar Bhushan | def parse(self): |
55 | a7cb58ce | Shikhar Bhushan | """Parse the *<rpc-reply>*"""
|
56 | 65c6a607 | Shikhar Bhushan | if self._parsed: |
57 | 65c6a607 | Shikhar Bhushan | return
|
58 | 9667bcb2 | Shikhar Bhushan | root = self._root = to_ele(self._raw) # The <rpc-reply> element |
59 | 9667bcb2 | Shikhar Bhushan | # Per RFC 4741 an <ok/> tag is sent when there are no errors or warnings
|
60 | 9667bcb2 | Shikhar Bhushan | ok = root.find(qualify("ok"))
|
61 | 9667bcb2 | Shikhar Bhushan | if ok is None: |
62 | 9667bcb2 | Shikhar Bhushan | # Create RPCError objects from <rpc-error> elements
|
63 | 9667bcb2 | Shikhar Bhushan | error = root.find(qualify("rpc-error"))
|
64 | a14c36f9 | Shikhar Bhushan | if error is not None: |
65 | a14c36f9 | Shikhar Bhushan | for err in root.getiterator(error.tag): |
66 | 9667bcb2 | Shikhar Bhushan | # Process a particular <rpc-error>
|
67 | 9667bcb2 | Shikhar Bhushan | self._errors.append(RPCError(err))
|
68 | a14c36f9 | Shikhar Bhushan | self._parsing_hook(root)
|
69 | a14c36f9 | Shikhar Bhushan | self._parsed = True |
70 | 4f650d54 | Shikhar Bhushan | |
71 | a14c36f9 | Shikhar Bhushan | @property
|
72 | a14c36f9 | Shikhar Bhushan | def xml(self): |
73 | a7cb58ce | Shikhar Bhushan | "*<rpc-reply>* as returned"
|
74 | a14c36f9 | Shikhar Bhushan | return self._raw |
75 | 4f650d54 | Shikhar Bhushan | |
76 | a14c36f9 | Shikhar Bhushan | @property
|
77 | a14c36f9 | Shikhar Bhushan | def ok(self): |
78 | a7cb58ce | Shikhar Bhushan | "Boolean value indicating if there were no errors."
|
79 | a14c36f9 | Shikhar Bhushan | if not self._parsed: |
80 | a14c36f9 | Shikhar Bhushan | self.parse()
|
81 | a14c36f9 | Shikhar Bhushan | return not self._errors # empty list => false |
82 | 4f650d54 | Shikhar Bhushan | |
83 | a14c36f9 | Shikhar Bhushan | @property
|
84 | a14c36f9 | Shikhar Bhushan | def error(self): |
85 | 216bb34c | Shikhar Bhushan | """Short for :attr:`errors` [0]; :const:`None` if there were no errors.
|
86 | 216bb34c | Shikhar Bhushan | """
|
87 | a14c36f9 | Shikhar Bhushan | if not self._parsed: |
88 | a14c36f9 | Shikhar Bhushan | self.parse()
|
89 | a14c36f9 | Shikhar Bhushan | if self._errors: |
90 | a14c36f9 | Shikhar Bhushan | return self._errors[0] |
91 | a14c36f9 | Shikhar Bhushan | else:
|
92 | a14c36f9 | Shikhar Bhushan | return None |
93 | 4f650d54 | Shikhar Bhushan | |
94 | a14c36f9 | Shikhar Bhushan | @property
|
95 | a14c36f9 | Shikhar Bhushan | def errors(self): |
96 | 216bb34c | Shikhar Bhushan | """`list` of :class:`RPCError` objects. Will be empty if there were no
|
97 | 216bb34c | Shikhar Bhushan | *<rpc-error>* elements in reply.
|
98 | 216bb34c | Shikhar Bhushan | """
|
99 | a14c36f9 | Shikhar Bhushan | if not self._parsed: |
100 | a14c36f9 | Shikhar Bhushan | self.parse()
|
101 | a14c36f9 | Shikhar Bhushan | return self._errors |
102 | a14c36f9 | Shikhar Bhushan | |
103 | a14c36f9 | Shikhar Bhushan | |
104 | 9667bcb2 | Shikhar Bhushan | class RPCError(OperationError): |
105 | 4f650d54 | Shikhar Bhushan | |
106 | 9667bcb2 | Shikhar Bhushan | """Represents an *<rpc-error>*. It is a type of :exc:`OperationError`
|
107 | 2abf9522 | Shikhar Bhushan | and can be raised like any other exception."""
|
108 | a7cb58ce | Shikhar Bhushan | |
109 | 9667bcb2 | Shikhar Bhushan | def __init__(self, err): |
110 | 9667bcb2 | Shikhar Bhushan | self._type = None |
111 | bd7957fb | Shikhar Bhushan | self._tag = None |
112 | 9667bcb2 | Shikhar Bhushan | self._severity = None |
113 | 9667bcb2 | Shikhar Bhushan | self._info = None |
114 | 9667bcb2 | Shikhar Bhushan | self._path = None |
115 | 9667bcb2 | Shikhar Bhushan | self._message = None |
116 | 9667bcb2 | Shikhar Bhushan | for subele in err: |
117 | 22566666 | Shikhar Bhushan | if subele.tag == qualify("error-type"): |
118 | 22566666 | Shikhar Bhushan | self._type = subele.text
|
119 | 22566666 | Shikhar Bhushan | elif subele.tag == qualify("error-tag"): |
120 | 9667bcb2 | Shikhar Bhushan | self._tag = subele.text
|
121 | 9667bcb2 | Shikhar Bhushan | elif subele.tag == qualify("error-severity"): |
122 | 9667bcb2 | Shikhar Bhushan | self._severity = subele.text
|
123 | 9667bcb2 | Shikhar Bhushan | elif subele.tag == qualify("error-info"): |
124 | 9667bcb2 | Shikhar Bhushan | self._info = subele.text
|
125 | 9667bcb2 | Shikhar Bhushan | elif subele.tag == qualify("error-path"): |
126 | 9667bcb2 | Shikhar Bhushan | self._path = subele.text
|
127 | 9667bcb2 | Shikhar Bhushan | elif subele.tag == qualify("error-message"): |
128 | 9667bcb2 | Shikhar Bhushan | self._message = subele.text
|
129 | a14c36f9 | Shikhar Bhushan | if self.message is not None: |
130 | d771dffc | Shikhar Bhushan | OperationError.__init__(self, self.message) |
131 | a14c36f9 | Shikhar Bhushan | else:
|
132 | c1bdbd86 | Shikhar Bhushan | OperationError.__init__(self, self.to_dict()) |
133 | 22566666 | Shikhar Bhushan | |
134 | 22566666 | Shikhar Bhushan | def to_dict(self): |
135 | 22566666 | Shikhar Bhushan | return {
|
136 | 22566666 | Shikhar Bhushan | 'type': self.type, |
137 | bd7957fb | Shikhar Bhushan | 'tag': self.tag, |
138 | bd7957fb | Shikhar Bhushan | 'severity': self.severity, |
139 | 22566666 | Shikhar Bhushan | 'path': self.path, |
140 | 22566666 | Shikhar Bhushan | 'message': self.message, |
141 | 22566666 | Shikhar Bhushan | 'info': self.info |
142 | 22566666 | Shikhar Bhushan | } |
143 | 22566666 | Shikhar Bhushan | |
144 | a14c36f9 | Shikhar Bhushan | @property
|
145 | a14c36f9 | Shikhar Bhushan | def type(self): |
146 | 2abf9522 | Shikhar Bhushan | "`string` representing text of *error-type* element"
|
147 | 9667bcb2 | Shikhar Bhushan | return self._type |
148 | bd7957fb | Shikhar Bhushan | |
149 | a14c36f9 | Shikhar Bhushan | @property
|
150 | a14c36f9 | Shikhar Bhushan | def tag(self): |
151 | 2abf9522 | Shikhar Bhushan | "`string` representing text of *error-tag* element"
|
152 | 9667bcb2 | Shikhar Bhushan | return self._tag |
153 | bd7957fb | Shikhar Bhushan | |
154 | bd7957fb | Shikhar Bhushan | @property
|
155 | bd7957fb | Shikhar Bhushan | def severity(self): |
156 | bd7957fb | Shikhar Bhushan | "`string` representing text of *error-severity* element"
|
157 | bd7957fb | Shikhar Bhushan | return self._severity |
158 | bd7957fb | Shikhar Bhushan | |
159 | a14c36f9 | Shikhar Bhushan | @property
|
160 | a14c36f9 | Shikhar Bhushan | def path(self): |
161 | 2abf9522 | Shikhar Bhushan | "`string` or :const:`None`; representing text of *error-path* element"
|
162 | 9667bcb2 | Shikhar Bhushan | return self._path |
163 | 4f650d54 | Shikhar Bhushan | |
164 | a14c36f9 | Shikhar Bhushan | @property
|
165 | a14c36f9 | Shikhar Bhushan | def message(self): |
166 | 2abf9522 | Shikhar Bhushan | "`string` or :const:`None`; representing text of *error-message* element"
|
167 | 9667bcb2 | Shikhar Bhushan | return self._message |
168 | 4f650d54 | Shikhar Bhushan | |
169 | a14c36f9 | Shikhar Bhushan | @property
|
170 | a14c36f9 | Shikhar Bhushan | def info(self): |
171 | 2abf9522 | Shikhar Bhushan | "`string` (XML) or :const:`None`, representing *error-info* element"
|
172 | 9667bcb2 | Shikhar Bhushan | return self._info |
173 | a14c36f9 | Shikhar Bhushan | |
174 | a14c36f9 | Shikhar Bhushan | |
175 | 0cdb8b3c | Shikhar Bhushan | class RPCReplyListener(SessionListener): |
176 | 4f650d54 | Shikhar Bhushan | |
177 | a7cb58ce | Shikhar Bhushan | # internal use
|
178 | a7cb58ce | Shikhar Bhushan | |
179 | 7b02d55b | Shikhar Bhushan | # one instance per session -- maybe there is a better way??
|
180 | a14c36f9 | Shikhar Bhushan | def __new__(cls, session): |
181 | a14c36f9 | Shikhar Bhushan | instance = session.get_listener_instance(cls) |
182 | a14c36f9 | Shikhar Bhushan | if instance is None: |
183 | a14c36f9 | Shikhar Bhushan | instance = object.__new__(cls)
|
184 | a14c36f9 | Shikhar Bhushan | instance._lock = Lock() |
185 | 6a2dfeb4 | Shikhar Bhushan | instance._id2rpc = {} |
186 | 0304f041 | Shikhar Bhushan | #instance._pipelined = session.can_pipeline
|
187 | a14c36f9 | Shikhar Bhushan | session.add_listener(instance) |
188 | a14c36f9 | Shikhar Bhushan | return instance
|
189 | 4f650d54 | Shikhar Bhushan | |
190 | a14c36f9 | Shikhar Bhushan | def register(self, id, rpc): |
191 | a14c36f9 | Shikhar Bhushan | with self._lock: |
192 | a14c36f9 | Shikhar Bhushan | self._id2rpc[id] = rpc |
193 | 4f650d54 | Shikhar Bhushan | |
194 | a14c36f9 | Shikhar Bhushan | def callback(self, root, raw): |
195 | a14c36f9 | Shikhar Bhushan | tag, attrs = root |
196 | 9667bcb2 | Shikhar Bhushan | if tag != qualify("rpc-reply"): |
197 | a14c36f9 | Shikhar Bhushan | return
|
198 | 0304f041 | Shikhar Bhushan | for key in attrs: # in the <rpc-reply> attributes |
199 | 9667bcb2 | Shikhar Bhushan | if key == "message-id": # if we found msgid attr |
200 | 0304f041 | Shikhar Bhushan | id = attrs[key] # get the msgid
|
201 | 9667bcb2 | Shikhar Bhushan | with self._lock: |
202 | 9667bcb2 | Shikhar Bhushan | try:
|
203 | 9667bcb2 | Shikhar Bhushan | rpc = self._id2rpc[id] # the corresponding rpc |
204 | 9667bcb2 | Shikhar Bhushan | logger.debug("Delivering to %r" % rpc)
|
205 | 0304f041 | Shikhar Bhushan | rpc.deliver_reply(raw) |
206 | 9667bcb2 | Shikhar Bhushan | except KeyError: |
207 | 9667bcb2 | Shikhar Bhushan | raise OperationError("Unknown message-id: %s", id) |
208 | 9667bcb2 | Shikhar Bhushan | # no catching other exceptions, fail loudly if must
|
209 | 9667bcb2 | Shikhar Bhushan | else:
|
210 | 9667bcb2 | Shikhar Bhushan | # if no error delivering, can del the reference to the RPC
|
211 | 9667bcb2 | Shikhar Bhushan | del self._id2rpc[id] |
212 | 9667bcb2 | Shikhar Bhushan | break
|
213 | a14c36f9 | Shikhar Bhushan | else:
|
214 | 9667bcb2 | Shikhar Bhushan | raise OperationError("Could not find 'message-id' attribute in <rpc-reply>") |
215 | 0304f041 | Shikhar Bhushan | |
216 | a14c36f9 | Shikhar Bhushan | def errback(self, err): |
217 | 6a2dfeb4 | Shikhar Bhushan | try:
|
218 | 6a2dfeb4 | Shikhar Bhushan | for rpc in self._id2rpc.values(): |
219 | 6a2dfeb4 | Shikhar Bhushan | rpc.deliver_error(err) |
220 | 6a2dfeb4 | Shikhar Bhushan | finally:
|
221 | 6a2dfeb4 | Shikhar Bhushan | self._id2rpc.clear()
|
222 | 4de03d63 | Shikhar Bhushan | |
223 | 4de03d63 | Shikhar Bhushan | |
224 | 4de03d63 | Shikhar Bhushan | class RPC(object): |
225 | 4f650d54 | Shikhar Bhushan | |
226 | 216bb34c | Shikhar Bhushan | """Base class for all operations.
|
227 | 216bb34c | Shikhar Bhushan |
|
228 | 216bb34c | Shikhar Bhushan | Directly corresponds to *<rpc>* requests. Handles making the request, and
|
229 | 216bb34c | Shikhar Bhushan | taking delivery of the reply.
|
230 | 216bb34c | Shikhar Bhushan | """
|
231 | a7cb58ce | Shikhar Bhushan | |
232 | bbd4ce54 | Shikhar Bhushan | #: Subclasses can specify their dependencies on capabilities. List of URI's
|
233 | a7cb58ce | Shikhar Bhushan | # or abbreviated names, e.g. ':writable-running'. These are verified at the
|
234 | a7cb58ce | Shikhar Bhushan | # time of object creation. If the capability is not available, a
|
235 | a7cb58ce | Shikhar Bhushan | # :exc:`MissingCapabilityError` is raised.
|
236 | 4de03d63 | Shikhar Bhushan | DEPENDS = [] |
237 | a7cb58ce | Shikhar Bhushan | |
238 | bbd4ce54 | Shikhar Bhushan | #: Subclasses can specify a different reply class, but it must be a
|
239 | a7cb58ce | Shikhar Bhushan | # subclass of :class:`RPCReply`.
|
240 | 4de03d63 | Shikhar Bhushan | REPLY_CLS = RPCReply |
241 | 4f650d54 | Shikhar Bhushan | |
242 | 9667bcb2 | Shikhar Bhushan | def __init__(self, session, async=False, timeout=None, raise_mode="none"): |
243 | 4de03d63 | Shikhar Bhushan | self._session = session
|
244 | 4de03d63 | Shikhar Bhushan | try:
|
245 | 4de03d63 | Shikhar Bhushan | for cap in self.DEPENDS: |
246 | 4de03d63 | Shikhar Bhushan | self._assert(cap)
|
247 | 4de03d63 | Shikhar Bhushan | except AttributeError: |
248 | 4f650d54 | Shikhar Bhushan | pass
|
249 | 4de03d63 | Shikhar Bhushan | self._async = async
|
250 | 4de03d63 | Shikhar Bhushan | self._timeout = timeout
|
251 | 6c70b245 | Shikhar Bhushan | self._raise_mode = raise_mode
|
252 | 9667bcb2 | Shikhar Bhushan | self._id = uuid1().urn # Keeps things simple instead of having a class attr that has to be locked |
253 | 4de03d63 | Shikhar Bhushan | self._listener = RPCReplyListener(session)
|
254 | 4de03d63 | Shikhar Bhushan | self._listener.register(self._id, self) |
255 | 4de03d63 | Shikhar Bhushan | self._reply = None |
256 | 4f650d54 | Shikhar Bhushan | self._error = None |
257 | a7cb58ce | Shikhar Bhushan | self._event = Event()
|
258 | 4f650d54 | Shikhar Bhushan | |
259 | 9667bcb2 | Shikhar Bhushan | def _build(self, subele): |
260 | a7cb58ce | Shikhar Bhushan | # internal
|
261 | 9667bcb2 | Shikhar Bhushan | ele = new_ele("rpc", {"message-id": self._id}, xmlns=BASE_NS_1_0) |
262 | 9667bcb2 | Shikhar Bhushan | ele.append(subele) |
263 | 9667bcb2 | Shikhar Bhushan | return to_xml(ele)
|
264 | 4f650d54 | Shikhar Bhushan | |
265 | 4de03d63 | Shikhar Bhushan | def _request(self, op): |
266 | a7cb58ce | Shikhar Bhushan | """Subclasses call this method to make the RPC request.
|
267 | 0304f041 | Shikhar Bhushan |
|
268 | 0304f041 | Shikhar Bhushan | In synchronous mode, waits until the reply is received and returns
|
269 | a7cb58ce | Shikhar Bhushan | :class:`RPCReply`.
|
270 | 0304f041 | Shikhar Bhushan |
|
271 | 0304f041 | Shikhar Bhushan | In asynchronous mode, returns immediately, returning a reference to this
|
272 | 0304f041 | Shikhar Bhushan | object. The :attr:`event` attribute will be set when the reply has been
|
273 | 0304f041 | Shikhar Bhushan | received (see :attr:`reply`) or an error occured (see :attr:`error`).
|
274 | 0304f041 | Shikhar Bhushan |
|
275 | a7cb58ce | Shikhar Bhushan | :type opspec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
|
276 | 0304f041 | Shikhar Bhushan | :rtype: :class:`RPCReply` (sync) or :class:`RPC` (async)
|
277 | a7cb58ce | Shikhar Bhushan | """
|
278 | 9667bcb2 | Shikhar Bhushan | logger.info('Requesting %r' % self.__class__.__name__) |
279 | 4de03d63 | Shikhar Bhushan | req = self._build(op)
|
280 | 66cd54c8 | Shikhar Bhushan | self._session.send(req)
|
281 | 66cd54c8 | Shikhar Bhushan | if self._async: |
282 | 9667bcb2 | Shikhar Bhushan | logger.debug('Async request, returning %r', self) |
283 | 0304f041 | Shikhar Bhushan | return self |
284 | 4de03d63 | Shikhar Bhushan | else:
|
285 | 9667bcb2 | Shikhar Bhushan | logger.debug('Sync request, will wait for timeout=%r' %
|
286 | 9667bcb2 | Shikhar Bhushan | self._timeout)
|
287 | 66cd54c8 | Shikhar Bhushan | self._event.wait(self._timeout) |
288 | 66cd54c8 | Shikhar Bhushan | if self._event.isSet(): |
289 | 66cd54c8 | Shikhar Bhushan | if self._error: |
290 | 6c70b245 | Shikhar Bhushan | # Error that prevented reply delivery
|
291 | 0cdb8b3c | Shikhar Bhushan | raise self._error |
292 | 66cd54c8 | Shikhar Bhushan | self._reply.parse()
|
293 | 6c70b245 | Shikhar Bhushan | if self._reply.error is not None: |
294 | 6c70b245 | Shikhar Bhushan | # <rpc-error>'s [ RPCError ]
|
295 | 6c70b245 | Shikhar Bhushan | if self._raise_mode == "all": |
296 | 7b02d55b | Shikhar Bhushan | raise self._reply.error |
297 | 6c70b245 | Shikhar Bhushan | elif (self._raise_mode == "errors" and |
298 | 6c70b245 | Shikhar Bhushan | self._reply.error.type == "error"): |
299 | 6c70b245 | Shikhar Bhushan | raise self._reply.error |
300 | 66cd54c8 | Shikhar Bhushan | return self._reply |
301 | 4de03d63 | Shikhar Bhushan | else:
|
302 | 216bb34c | Shikhar Bhushan | raise TimeoutExpiredError
|
303 | 4f650d54 | Shikhar Bhushan | |
304 | a7cb58ce | Shikhar Bhushan | def request(self, *args, **kwds): |
305 | dd8b8dd7 | Shikhar Bhushan | "Subclasses implement this method."
|
306 | dd225c7a | Shikhar Bhushan | return self._request(self.SPEC) |
307 | 6c70b245 | Shikhar Bhushan | |
308 | 4de03d63 | Shikhar Bhushan | def _assert(self, capability): |
309 | a7cb58ce | Shikhar Bhushan | """Subclasses can use this method to verify that a capability is available
|
310 | a7cb58ce | Shikhar Bhushan | with the NETCONF server, before making a request that requires it. A
|
311 | 216bb34c | Shikhar Bhushan | :exc:`MissingCapabilityError` will be raised if the capability is not
|
312 | a7cb58ce | Shikhar Bhushan | available."""
|
313 | 4de03d63 | Shikhar Bhushan | if capability not in self._session.server_capabilities: |
314 | bbd4ce54 | Shikhar Bhushan | raise MissingCapabilityError('Server does not support [%s]' % |
315 | bbd4ce54 | Shikhar Bhushan | capability) |
316 | 0304f041 | Shikhar Bhushan | |
317 | a7cb58ce | Shikhar Bhushan | def deliver_reply(self, raw): |
318 | a7cb58ce | Shikhar Bhushan | # internal use
|
319 | 4de03d63 | Shikhar Bhushan | self._reply = self.REPLY_CLS(raw) |
320 | a7cb58ce | Shikhar Bhushan | self._event.set()
|
321 | 4f650d54 | Shikhar Bhushan | |
322 | a7cb58ce | Shikhar Bhushan | def deliver_error(self, err): |
323 | a7cb58ce | Shikhar Bhushan | # internal use
|
324 | 0cdb8b3c | Shikhar Bhushan | self._error = err
|
325 | a7cb58ce | Shikhar Bhushan | self._event.set()
|
326 | 4f650d54 | Shikhar Bhushan | |
327 | 4de03d63 | Shikhar Bhushan | @property
|
328 | 4de03d63 | Shikhar Bhushan | def reply(self): |
329 | a7cb58ce | Shikhar Bhushan | ":class:`RPCReply` element if reply has been received or :const:`None`"
|
330 | 4de03d63 | Shikhar Bhushan | return self._reply |
331 | 4f650d54 | Shikhar Bhushan | |
332 | 4de03d63 | Shikhar Bhushan | @property
|
333 | a7cb58ce | Shikhar Bhushan | def error(self): |
334 | a7cb58ce | Shikhar Bhushan | """:exc:`Exception` type if an error occured or :const:`None`.
|
335 | 0304f041 | Shikhar Bhushan |
|
336 | a7cb58ce | Shikhar Bhushan | .. note::
|
337 | a7cb58ce | Shikhar Bhushan | This represents an error which prevented a reply from being
|
338 | a7cb58ce | Shikhar Bhushan | received. An *<rpc-error>* does not fall in that category -- see
|
339 | a7cb58ce | Shikhar Bhushan | :class:`RPCReply` for that.
|
340 | a7cb58ce | Shikhar Bhushan | """
|
341 | a7cb58ce | Shikhar Bhushan | return self._error |
342 | a7cb58ce | Shikhar Bhushan | |
343 | a7cb58ce | Shikhar Bhushan | @property
|
344 | 4de03d63 | Shikhar Bhushan | def id(self): |
345 | a7cb58ce | Shikhar Bhushan | "The *message-id* for this RPC"
|
346 | 4de03d63 | Shikhar Bhushan | return self._id |
347 | 4f650d54 | Shikhar Bhushan | |
348 | 4de03d63 | Shikhar Bhushan | @property
|
349 | 4de03d63 | Shikhar Bhushan | def session(self): |
350 | a7cb58ce | Shikhar Bhushan | """The :class:`~ncclient.transport.Session` object associated with this
|
351 | a7cb58ce | Shikhar Bhushan | RPC"""
|
352 | 4de03d63 | Shikhar Bhushan | return self._session |
353 | 4f650d54 | Shikhar Bhushan | |
354 | 4de03d63 | Shikhar Bhushan | @property
|
355 | a7cb58ce | Shikhar Bhushan | def event(self): |
356 | a7cb58ce | Shikhar Bhushan | """:class:`~threading.Event` that is set when reply has been received or
|
357 | a7cb58ce | Shikhar Bhushan | error occured."""
|
358 | a7cb58ce | Shikhar Bhushan | return self._event |
359 | a7cb58ce | Shikhar Bhushan | |
360 | a7cb58ce | Shikhar Bhushan | def set_async(self, async=True): |
361 | a7cb58ce | Shikhar Bhushan | """Set asynchronous mode for this RPC."""
|
362 | a7cb58ce | Shikhar Bhushan | self._async = async
|
363 | a7cb58ce | Shikhar Bhushan | if async and not session.can_pipeline: |
364 | a7cb58ce | Shikhar Bhushan | raise UserWarning('Asynchronous mode not supported for this device/session') |
365 | a7cb58ce | Shikhar Bhushan | |
366 | 6c70b245 | Shikhar Bhushan | def set_raise_mode(self, mode): |
367 | 9667bcb2 | Shikhar Bhushan | assert(choice in ("all", "errors", "none")) |
368 | 6c70b245 | Shikhar Bhushan | self._raise_mode = mode
|
369 | e0e01d37 | Shikhar Bhushan | |
370 | a7cb58ce | Shikhar Bhushan | def set_timeout(self, timeout): |
371 | 9667bcb2 | Shikhar Bhushan | """Set the timeout for synchronous waiting; defining how long the RPC
|
372 | 9667bcb2 | Shikhar Bhushan | request will block on a reply before raising an error. Irrelevant for
|
373 | 9667bcb2 | Shikhar Bhushan | asynchronous usage."""
|
374 | a7cb58ce | Shikhar Bhushan | self._timeout = timeout
|
375 | 4f650d54 | Shikhar Bhushan | |
376 | a7cb58ce | Shikhar Bhushan | #: Whether this RPC is asynchronous
|
377 | 9667bcb2 | Shikhar Bhushan | is_async = property(fget=lambda self: self._async, fset=set_async) |
378 | 4f650d54 | Shikhar Bhushan | |
379 | a7cb58ce | Shikhar Bhushan | #: Timeout for synchronous waiting
|
380 | 4de03d63 | Shikhar Bhushan | timeout = property(fget=lambda self: self._timeout, fset=set_timeout) |