root / ncclient / operations / rpc.py @ 0c89e420
History | View | Annotate | Download (13.2 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 | 9667bcb2 | Shikhar Bhushan | class RPCError(OperationError): |
28 | 4f650d54 | Shikhar Bhushan | |
29 | 19e7c7f6 | Shikhar Bhushan | "Represents an `rpc-error`. It is a type of :exc:`OperationError` and can be raised as such."
|
30 | 11bab021 | Shikhar Bhushan | |
31 | 11bab021 | Shikhar Bhushan | tag_to_attr = { |
32 | 11bab021 | Shikhar Bhushan | qualify("error-type"): "_type", |
33 | 11bab021 | Shikhar Bhushan | qualify("error-tag"): "_tag", |
34 | 11bab021 | Shikhar Bhushan | qualify("error-severity"): "_severity", |
35 | 11bab021 | Shikhar Bhushan | qualify("error-info"): "_info", |
36 | 11bab021 | Shikhar Bhushan | qualify("error-path"): "_path", |
37 | 11bab021 | Shikhar Bhushan | qualify("error-message"): "_message" |
38 | 11bab021 | Shikhar Bhushan | } |
39 | 11bab021 | Shikhar Bhushan | |
40 | 4bc8021f | Shikhar Bhushan | def __init__(self, raw): |
41 | 4bc8021f | Shikhar Bhushan | self._raw = raw
|
42 | 7c4ff459 | Shikhar Bhushan | for attr in RPCError.tag_to_attr.values(): |
43 | 11bab021 | Shikhar Bhushan | setattr(self, attr, None) |
44 | 4bc8021f | Shikhar Bhushan | for subele in raw: |
45 | 7c4ff459 | Shikhar Bhushan | attr = RPCError.tag_to_attr.get(subele.tag, None)
|
46 | 11bab021 | Shikhar Bhushan | if attr is not None: |
47 | 0c55eea9 | Shikhar Bhushan | setattr(self, attr, subele.text if attr != "_info" else to_xml(subele) ) |
48 | a14c36f9 | Shikhar Bhushan | if self.message is not None: |
49 | d771dffc | Shikhar Bhushan | OperationError.__init__(self, self.message) |
50 | a14c36f9 | Shikhar Bhushan | else:
|
51 | c1bdbd86 | Shikhar Bhushan | OperationError.__init__(self, self.to_dict()) |
52 | 22566666 | Shikhar Bhushan | |
53 | 22566666 | Shikhar Bhushan | def to_dict(self): |
54 | 0c55eea9 | Shikhar Bhushan | return dict([ (attr[1:], getattr(self, attr)) for attr in RPCError.tag_to_attr.values() ]) |
55 | 22566666 | Shikhar Bhushan | |
56 | 4bc8021f | Shikhar Bhushan | @property
|
57 | 4bc8021f | Shikhar Bhushan | def xml(self): |
58 | 19e7c7f6 | Shikhar Bhushan | "The `rpc-error` element as returned in XML."
|
59 | 4bc8021f | Shikhar Bhushan | return self._raw |
60 | 4bc8021f | Shikhar Bhushan | |
61 | a14c36f9 | Shikhar Bhushan | @property
|
62 | a14c36f9 | Shikhar Bhushan | def type(self): |
63 | 19e7c7f6 | Shikhar Bhushan | "The contents of the `error-type` element."
|
64 | 9667bcb2 | Shikhar Bhushan | return self._type |
65 | bd7957fb | Shikhar Bhushan | |
66 | a14c36f9 | Shikhar Bhushan | @property
|
67 | a14c36f9 | Shikhar Bhushan | def tag(self): |
68 | 19e7c7f6 | Shikhar Bhushan | "The contents of the `error-tag` element."
|
69 | 9667bcb2 | Shikhar Bhushan | return self._tag |
70 | bd7957fb | Shikhar Bhushan | |
71 | bd7957fb | Shikhar Bhushan | @property
|
72 | bd7957fb | Shikhar Bhushan | def severity(self): |
73 | 19e7c7f6 | Shikhar Bhushan | "The contents of the `error-severity` element."
|
74 | bd7957fb | Shikhar Bhushan | return self._severity |
75 | bd7957fb | Shikhar Bhushan | |
76 | a14c36f9 | Shikhar Bhushan | @property
|
77 | a14c36f9 | Shikhar Bhushan | def path(self): |
78 | 19e7c7f6 | Shikhar Bhushan | "The contents of the `error-path` element if present or `None`."
|
79 | 9667bcb2 | Shikhar Bhushan | return self._path |
80 | 11bab021 | Shikhar Bhushan | |
81 | a14c36f9 | Shikhar Bhushan | @property
|
82 | a14c36f9 | Shikhar Bhushan | def message(self): |
83 | 19e7c7f6 | Shikhar Bhushan | "The contents of the `error-message` element if present or `None`."
|
84 | 9667bcb2 | Shikhar Bhushan | return self._message |
85 | 11bab021 | Shikhar Bhushan | |
86 | a14c36f9 | Shikhar Bhushan | @property
|
87 | a14c36f9 | Shikhar Bhushan | def info(self): |
88 | 19e7c7f6 | Shikhar Bhushan | "XML string or `None`; representing the `error-info` element."
|
89 | 9667bcb2 | Shikhar Bhushan | return self._info |
90 | a14c36f9 | Shikhar Bhushan | |
91 | a14c36f9 | Shikhar Bhushan | |
92 | 4bc8021f | Shikhar Bhushan | class RPCReply: |
93 | 4bc8021f | Shikhar Bhushan | |
94 | 4bc8021f | Shikhar Bhushan | """Represents an *rpc-reply*. Only concerns itself with whether the operation was successful.
|
95 | 4bc8021f | Shikhar Bhushan |
|
96 | 4bc8021f | Shikhar Bhushan | .. note::
|
97 | 4bc8021f | Shikhar Bhushan | If the reply has not yet been parsed there is an implicit, one-time parsing overhead to
|
98 | c15671aa | Shikhar Bhushan | accessing some of the attributes defined by this class.
|
99 | 4bc8021f | Shikhar Bhushan | """
|
100 | 4bc8021f | Shikhar Bhushan | |
101 | 4bc8021f | Shikhar Bhushan | ERROR_CLS = RPCError |
102 | 4bc8021f | Shikhar Bhushan | "Subclasses can specify a different error class, but it should be a subclass of `RPCError`."
|
103 | 4bc8021f | Shikhar Bhushan | |
104 | 4bc8021f | Shikhar Bhushan | def __init__(self, raw): |
105 | 4bc8021f | Shikhar Bhushan | self._raw = raw
|
106 | 4bc8021f | Shikhar Bhushan | self._parsed = False |
107 | 4bc8021f | Shikhar Bhushan | self._root = None |
108 | 4bc8021f | Shikhar Bhushan | self._errors = []
|
109 | 4bc8021f | Shikhar Bhushan | |
110 | 4bc8021f | Shikhar Bhushan | def __repr__(self): |
111 | 4bc8021f | Shikhar Bhushan | return self._raw |
112 | 4bc8021f | Shikhar Bhushan | |
113 | 4bc8021f | Shikhar Bhushan | def parse(self): |
114 | 4bc8021f | Shikhar Bhushan | "Parses the *rpc-reply*."
|
115 | 4bc8021f | Shikhar Bhushan | if self._parsed: return |
116 | 4bc8021f | Shikhar Bhushan | root = self._root = to_ele(self._raw) # The <rpc-reply> element |
117 | 4bc8021f | Shikhar Bhushan | # Per RFC 4741 an <ok/> tag is sent when there are no errors or warnings
|
118 | 4bc8021f | Shikhar Bhushan | ok = root.find(qualify("ok"))
|
119 | 4bc8021f | Shikhar Bhushan | if ok is None: |
120 | 4bc8021f | Shikhar Bhushan | # Create RPCError objects from <rpc-error> elements
|
121 | 4bc8021f | Shikhar Bhushan | error = root.find(qualify("rpc-error"))
|
122 | 4bc8021f | Shikhar Bhushan | if error is not None: |
123 | 4bc8021f | Shikhar Bhushan | for err in root.getiterator(error.tag): |
124 | 4bc8021f | Shikhar Bhushan | # Process a particular <rpc-error>
|
125 | b2d60e49 | Shikhar Bhushan | self._errors.append(self.ERROR_CLS(err)) |
126 | b2d60e49 | Shikhar Bhushan | self._parsing_hook(root)
|
127 | 4bc8021f | Shikhar Bhushan | self._parsed = True |
128 | b2d60e49 | Shikhar Bhushan | |
129 | b2d60e49 | Shikhar Bhushan | def _parsing_hook(self, root): |
130 | c15671aa | Shikhar Bhushan | "No-op by default. Gets passed the *root* element for the reply."
|
131 | b2d60e49 | Shikhar Bhushan | pass
|
132 | 4bc8021f | Shikhar Bhushan | |
133 | 4bc8021f | Shikhar Bhushan | @property
|
134 | 4bc8021f | Shikhar Bhushan | def xml(self): |
135 | 4bc8021f | Shikhar Bhushan | "*rpc-reply* element as returned."
|
136 | 4bc8021f | Shikhar Bhushan | return self._raw |
137 | 4bc8021f | Shikhar Bhushan | |
138 | 4bc8021f | Shikhar Bhushan | @property
|
139 | 4bc8021f | Shikhar Bhushan | def ok(self): |
140 | 4bc8021f | Shikhar Bhushan | "Boolean value indicating if there were no errors."
|
141 | 4bc8021f | Shikhar Bhushan | return not self.errors # empty list => false |
142 | 4bc8021f | Shikhar Bhushan | |
143 | 4bc8021f | Shikhar Bhushan | @property
|
144 | 4bc8021f | Shikhar Bhushan | def error(self): |
145 | 19e7c7f6 | Shikhar Bhushan | "Returns the first :class:`RPCError` and `None` if there were no errors."
|
146 | 4bc8021f | Shikhar Bhushan | self.parse()
|
147 | 4bc8021f | Shikhar Bhushan | if self._errors: |
148 | 4bc8021f | Shikhar Bhushan | return self._errors[0] |
149 | 4bc8021f | Shikhar Bhushan | else:
|
150 | 4bc8021f | Shikhar Bhushan | return None |
151 | 4bc8021f | Shikhar Bhushan | |
152 | 4bc8021f | Shikhar Bhushan | @property
|
153 | 4bc8021f | Shikhar Bhushan | def errors(self): |
154 | 19e7c7f6 | Shikhar Bhushan | "List of `RPCError` objects. Will be empty if there were no *rpc-error* elements in reply."
|
155 | 4bc8021f | Shikhar Bhushan | self.parse()
|
156 | 4bc8021f | Shikhar Bhushan | return self._errors |
157 | 4bc8021f | Shikhar Bhushan | |
158 | 4bc8021f | Shikhar Bhushan | |
159 | 11bab021 | Shikhar Bhushan | class RPCReplyListener(SessionListener): # internal use |
160 | 11bab021 | Shikhar Bhushan | |
161 | 11bab021 | Shikhar Bhushan | creation_lock = Lock() |
162 | 11bab021 | Shikhar Bhushan | |
163 | 7b02d55b | Shikhar Bhushan | # one instance per session -- maybe there is a better way??
|
164 | a14c36f9 | Shikhar Bhushan | def __new__(cls, session): |
165 | 7c4ff459 | Shikhar Bhushan | with RPCReplyListener.creation_lock:
|
166 | 11bab021 | Shikhar Bhushan | instance = session.get_listener_instance(cls) |
167 | 11bab021 | Shikhar Bhushan | if instance is None: |
168 | 11bab021 | Shikhar Bhushan | instance = object.__new__(cls)
|
169 | 11bab021 | Shikhar Bhushan | instance._lock = Lock() |
170 | 11bab021 | Shikhar Bhushan | instance._id2rpc = {} |
171 | 11bab021 | Shikhar Bhushan | #instance._pipelined = session.can_pipeline
|
172 | 11bab021 | Shikhar Bhushan | session.add_listener(instance) |
173 | 11bab021 | Shikhar Bhushan | return instance
|
174 | 4f650d54 | Shikhar Bhushan | |
175 | a14c36f9 | Shikhar Bhushan | def register(self, id, rpc): |
176 | a14c36f9 | Shikhar Bhushan | with self._lock: |
177 | a14c36f9 | Shikhar Bhushan | self._id2rpc[id] = rpc |
178 | 4f650d54 | Shikhar Bhushan | |
179 | a14c36f9 | Shikhar Bhushan | def callback(self, root, raw): |
180 | a14c36f9 | Shikhar Bhushan | tag, attrs = root |
181 | 9667bcb2 | Shikhar Bhushan | if tag != qualify("rpc-reply"): |
182 | a14c36f9 | Shikhar Bhushan | return
|
183 | 0304f041 | Shikhar Bhushan | for key in attrs: # in the <rpc-reply> attributes |
184 | 9667bcb2 | Shikhar Bhushan | if key == "message-id": # if we found msgid attr |
185 | 0304f041 | Shikhar Bhushan | id = attrs[key] # get the msgid
|
186 | 9667bcb2 | Shikhar Bhushan | with self._lock: |
187 | 11bab021 | Shikhar Bhushan | try:
|
188 | 9667bcb2 | Shikhar Bhushan | rpc = self._id2rpc[id] # the corresponding rpc |
189 | 9667bcb2 | Shikhar Bhushan | logger.debug("Delivering to %r" % rpc)
|
190 | 0304f041 | Shikhar Bhushan | rpc.deliver_reply(raw) |
191 | 9667bcb2 | Shikhar Bhushan | except KeyError: |
192 | 11bab021 | Shikhar Bhushan | raise OperationError("Unknown 'message-id': %s", id) |
193 | 9667bcb2 | Shikhar Bhushan | # no catching other exceptions, fail loudly if must
|
194 | 9667bcb2 | Shikhar Bhushan | else:
|
195 | 9667bcb2 | Shikhar Bhushan | # if no error delivering, can del the reference to the RPC
|
196 | 9667bcb2 | Shikhar Bhushan | del self._id2rpc[id] |
197 | 9667bcb2 | Shikhar Bhushan | break
|
198 | a14c36f9 | Shikhar Bhushan | else:
|
199 | 9667bcb2 | Shikhar Bhushan | raise OperationError("Could not find 'message-id' attribute in <rpc-reply>") |
200 | 0304f041 | Shikhar Bhushan | |
201 | a14c36f9 | Shikhar Bhushan | def errback(self, err): |
202 | 6a2dfeb4 | Shikhar Bhushan | try:
|
203 | 6a2dfeb4 | Shikhar Bhushan | for rpc in self._id2rpc.values(): |
204 | 6a2dfeb4 | Shikhar Bhushan | rpc.deliver_error(err) |
205 | 6a2dfeb4 | Shikhar Bhushan | finally:
|
206 | 6a2dfeb4 | Shikhar Bhushan | self._id2rpc.clear()
|
207 | 4de03d63 | Shikhar Bhushan | |
208 | 4de03d63 | Shikhar Bhushan | |
209 | 19e7c7f6 | Shikhar Bhushan | class RaiseMode(object): |
210 | 19e7c7f6 | Shikhar Bhushan | |
211 | 19e7c7f6 | Shikhar Bhushan | NONE = 0
|
212 | 19e7c7f6 | Shikhar Bhushan | "Don't attempt to raise any type of `rpc-error` as :exc:`RPCError`."
|
213 | 19e7c7f6 | Shikhar Bhushan | |
214 | 19e7c7f6 | Shikhar Bhushan | ERRORS = 1
|
215 | 19e7c7f6 | Shikhar Bhushan | "Raise only when the `error-type` indicates it is an honest-to-god error."
|
216 | 19e7c7f6 | Shikhar Bhushan | |
217 | 19e7c7f6 | Shikhar Bhushan | ALL = 2
|
218 | 19e7c7f6 | Shikhar Bhushan | "Don't look at the `error-type`, always raise."
|
219 | 19e7c7f6 | Shikhar Bhushan | |
220 | 19e7c7f6 | Shikhar Bhushan | |
221 | 4de03d63 | Shikhar Bhushan | class RPC(object): |
222 | 4bc8021f | Shikhar Bhushan | |
223 | c15671aa | Shikhar Bhushan | """Base class for all operations, directly corresponding to *rpc* requests. Handles making the request, and taking delivery of the reply."""
|
224 | 19e7c7f6 | Shikhar Bhushan | |
225 | 4de03d63 | Shikhar Bhushan | DEPENDS = [] |
226 | c15671aa | Shikhar Bhushan | """Subclasses can specify their dependencies on capabilities as a list of URI's or abbreviated names, e.g. ':writable-running'. These are verified at the time of instantiation. If the capability is not available, :exc:`MissingCapabilityError` is raised."""
|
227 | 4bc8021f | Shikhar Bhushan | |
228 | 4de03d63 | Shikhar Bhushan | REPLY_CLS = RPCReply |
229 | c15671aa | Shikhar Bhushan | "By default :class:`RPCReply`. Subclasses can specify a :class:`RPCReply` subclass."
|
230 | 4bc8021f | Shikhar Bhushan | |
231 | 19e7c7f6 | Shikhar Bhushan | def __init__(self, session, async=False, timeout=30, raise_mode=RaiseMode.NONE): |
232 | c15671aa | Shikhar Bhushan | """
|
233 | c15671aa | Shikhar Bhushan | *session* is the :class:`~ncclient.transport.Session` instance
|
234 | c15671aa | Shikhar Bhushan |
|
235 | c15671aa | Shikhar Bhushan | *async* specifies whether the request is to be made asynchronously, see :attr:`is_async`
|
236 | c15671aa | Shikhar Bhushan |
|
237 | c15671aa | Shikhar Bhushan | *timeout* is the timeout for a synchronous request, see :attr:`timeout`
|
238 | c15671aa | Shikhar Bhushan |
|
239 | c15671aa | Shikhar Bhushan | *raise_mode* specifies the exception raising mode, see :attr:`raise_mode`
|
240 | c15671aa | Shikhar Bhushan | """
|
241 | 4de03d63 | Shikhar Bhushan | self._session = session
|
242 | 4de03d63 | Shikhar Bhushan | try:
|
243 | 4de03d63 | Shikhar Bhushan | for cap in self.DEPENDS: |
244 | 4de03d63 | Shikhar Bhushan | self._assert(cap)
|
245 | 4de03d63 | Shikhar Bhushan | except AttributeError: |
246 | 4f650d54 | Shikhar Bhushan | pass
|
247 | 4de03d63 | Shikhar Bhushan | self._async = async
|
248 | 4de03d63 | Shikhar Bhushan | self._timeout = timeout
|
249 | 6c70b245 | Shikhar Bhushan | self._raise_mode = raise_mode
|
250 | 4bc8021f | Shikhar Bhushan | self._id = uuid1().urn # Keeps things simple instead of having a class attr with running ID that has to be locked |
251 | 4de03d63 | Shikhar Bhushan | self._listener = RPCReplyListener(session)
|
252 | 4de03d63 | Shikhar Bhushan | self._listener.register(self._id, self) |
253 | 4de03d63 | Shikhar Bhushan | self._reply = None |
254 | 4f650d54 | Shikhar Bhushan | self._error = None |
255 | a7cb58ce | Shikhar Bhushan | self._event = Event()
|
256 | 4bc8021f | Shikhar Bhushan | |
257 | 4bc8021f | Shikhar Bhushan | def _wrap(self, subele): |
258 | 4bc8021f | Shikhar Bhushan | # internal use
|
259 | 0c89e420 | Leonidas Poulopoulos | ele = new_ele("rpc", {"message-id": self._id}) |
260 | 9667bcb2 | Shikhar Bhushan | ele.append(subele) |
261 | 9667bcb2 | Shikhar Bhushan | return to_xml(ele)
|
262 | 4f650d54 | Shikhar Bhushan | |
263 | 4de03d63 | Shikhar Bhushan | def _request(self, op): |
264 | 19e7c7f6 | Shikhar Bhushan | """Implementations of :meth:`request` call this method to send the request and process the reply.
|
265 | 0304f041 | Shikhar Bhushan |
|
266 | 19e7c7f6 | Shikhar Bhushan | In synchronous mode, blocks until the reply is received and returns :class:`RPCReply`. Depending on the :attr:`raise_mode` a `rpc-error` element in the reply may lead to an :exc:`RPCError` exception.
|
267 | 0304f041 | Shikhar Bhushan |
|
268 | c15671aa | Shikhar Bhushan | In asynchronous mode, returns immediately, returning `self`. The :attr:`event` attribute will be set when the reply has been received (see :attr:`reply`) or an error occured (see :attr:`error`).
|
269 | 4bc8021f | Shikhar Bhushan |
|
270 | c15671aa | Shikhar Bhushan | *op* is the operation to be requested as an :class:`~xml.etree.ElementTree.Element`
|
271 | a7cb58ce | Shikhar Bhushan | """
|
272 | 9667bcb2 | Shikhar Bhushan | logger.info('Requesting %r' % self.__class__.__name__) |
273 | 4bc8021f | Shikhar Bhushan | req = self._wrap(op)
|
274 | 66cd54c8 | Shikhar Bhushan | self._session.send(req)
|
275 | 66cd54c8 | Shikhar Bhushan | if self._async: |
276 | 9667bcb2 | Shikhar Bhushan | logger.debug('Async request, returning %r', self) |
277 | 0304f041 | Shikhar Bhushan | return self |
278 | 4de03d63 | Shikhar Bhushan | else:
|
279 | b2d60e49 | Shikhar Bhushan | logger.debug('Sync request, will wait for timeout=%r' % self._timeout) |
280 | 66cd54c8 | Shikhar Bhushan | self._event.wait(self._timeout) |
281 | 66cd54c8 | Shikhar Bhushan | if self._event.isSet(): |
282 | 66cd54c8 | Shikhar Bhushan | if self._error: |
283 | 6c70b245 | Shikhar Bhushan | # Error that prevented reply delivery
|
284 | 0cdb8b3c | Shikhar Bhushan | raise self._error |
285 | 66cd54c8 | Shikhar Bhushan | self._reply.parse()
|
286 | 6c70b245 | Shikhar Bhushan | if self._reply.error is not None: |
287 | 6c70b245 | Shikhar Bhushan | # <rpc-error>'s [ RPCError ]
|
288 | 19e7c7f6 | Shikhar Bhushan | if self._raise_mode == RaiseMode.ALL: |
289 | 7b02d55b | Shikhar Bhushan | raise self._reply.error |
290 | 19e7c7f6 | Shikhar Bhushan | elif (self._raise_mode == RaiseMode.ERRORS and self._reply.error.type == "error"): |
291 | 6c70b245 | Shikhar Bhushan | raise self._reply.error |
292 | 66cd54c8 | Shikhar Bhushan | return self._reply |
293 | 4de03d63 | Shikhar Bhushan | else:
|
294 | 216bb34c | Shikhar Bhushan | raise TimeoutExpiredError
|
295 | 4f650d54 | Shikhar Bhushan | |
296 | b2d60e49 | Shikhar Bhushan | def request(self): |
297 | 4bc8021f | Shikhar Bhushan | """Subclasses must implement this method. Typically only the request needs to be built as an
|
298 | c15671aa | Shikhar Bhushan | :class:`~xml.etree.ElementTree.Element` and everything else can be handed off to
|
299 | 4bc8021f | Shikhar Bhushan | :meth:`_request`."""
|
300 | 4bc8021f | Shikhar Bhushan | pass
|
301 | 6c70b245 | Shikhar Bhushan | |
302 | 4de03d63 | Shikhar Bhushan | def _assert(self, capability): |
303 | 4bc8021f | Shikhar Bhushan | """Subclasses can use this method to verify that a capability is available with the NETCONF
|
304 | 4bc8021f | Shikhar Bhushan | server, before making a request that requires it. A :exc:`MissingCapabilityError` will be
|
305 | 4bc8021f | Shikhar Bhushan | raised if the capability is not available."""
|
306 | 4de03d63 | Shikhar Bhushan | if capability not in self._session.server_capabilities: |
307 | b2d60e49 | Shikhar Bhushan | raise MissingCapabilityError('Server does not support [%s]' % capability) |
308 | 0304f041 | Shikhar Bhushan | |
309 | a7cb58ce | Shikhar Bhushan | def deliver_reply(self, raw): |
310 | a7cb58ce | Shikhar Bhushan | # internal use
|
311 | 4de03d63 | Shikhar Bhushan | self._reply = self.REPLY_CLS(raw) |
312 | a7cb58ce | Shikhar Bhushan | self._event.set()
|
313 | 4f650d54 | Shikhar Bhushan | |
314 | a7cb58ce | Shikhar Bhushan | def deliver_error(self, err): |
315 | a7cb58ce | Shikhar Bhushan | # internal use
|
316 | 0cdb8b3c | Shikhar Bhushan | self._error = err
|
317 | a7cb58ce | Shikhar Bhushan | self._event.set()
|
318 | 4bc8021f | Shikhar Bhushan | |
319 | 4de03d63 | Shikhar Bhushan | @property
|
320 | 4de03d63 | Shikhar Bhushan | def reply(self): |
321 | 19e7c7f6 | Shikhar Bhushan | ":class:`RPCReply` element if reply has been received or `None`"
|
322 | 4de03d63 | Shikhar Bhushan | return self._reply |
323 | 4bc8021f | Shikhar Bhushan | |
324 | 4de03d63 | Shikhar Bhushan | @property
|
325 | a7cb58ce | Shikhar Bhushan | def error(self): |
326 | 19e7c7f6 | Shikhar Bhushan | """:exc:`Exception` type if an error occured or `None`.
|
327 | 0304f041 | Shikhar Bhushan |
|
328 | a7cb58ce | Shikhar Bhushan | .. note::
|
329 | 4bc8021f | Shikhar Bhushan | This represents an error which prevented a reply from being received. An *rpc-error*
|
330 | 4bc8021f | Shikhar Bhushan | does not fall in that category -- see `RPCReply` for that.
|
331 | a7cb58ce | Shikhar Bhushan | """
|
332 | a7cb58ce | Shikhar Bhushan | return self._error |
333 | 4bc8021f | Shikhar Bhushan | |
334 | a7cb58ce | Shikhar Bhushan | @property
|
335 | 4de03d63 | Shikhar Bhushan | def id(self): |
336 | 4bc8021f | Shikhar Bhushan | "The *message-id* for this RPC."
|
337 | 4de03d63 | Shikhar Bhushan | return self._id |
338 | 4bc8021f | Shikhar Bhushan | |
339 | 4de03d63 | Shikhar Bhushan | @property
|
340 | 4de03d63 | Shikhar Bhushan | def session(self): |
341 | 4bc8021f | Shikhar Bhushan | "The `~ncclient.transport.Session` object associated with this RPC."
|
342 | 4de03d63 | Shikhar Bhushan | return self._session |
343 | 4f650d54 | Shikhar Bhushan | |
344 | 4de03d63 | Shikhar Bhushan | @property
|
345 | a7cb58ce | Shikhar Bhushan | def event(self): |
346 | c15671aa | Shikhar Bhushan | """:class:`~threading.Event` that is set when reply has been received or when an error preventing
|
347 | 4bc8021f | Shikhar Bhushan | delivery of the reply occurs.
|
348 | 4bc8021f | Shikhar Bhushan | """
|
349 | a7cb58ce | Shikhar Bhushan | return self._event |
350 | a7cb58ce | Shikhar Bhushan | |
351 | 19e7c7f6 | Shikhar Bhushan | def __set_async(self, async=True): |
352 | a7cb58ce | Shikhar Bhushan | self._async = async
|
353 | a7cb58ce | Shikhar Bhushan | if async and not session.can_pipeline: |
354 | a7cb58ce | Shikhar Bhushan | raise UserWarning('Asynchronous mode not supported for this device/session') |
355 | a7cb58ce | Shikhar Bhushan | |
356 | 19e7c7f6 | Shikhar Bhushan | def __set_raise_mode(self, mode): |
357 | 9667bcb2 | Shikhar Bhushan | assert(choice in ("all", "errors", "none")) |
358 | 6c70b245 | Shikhar Bhushan | self._raise_mode = mode
|
359 | e0e01d37 | Shikhar Bhushan | |
360 | 19e7c7f6 | Shikhar Bhushan | def __set_timeout(self, timeout): |
361 | a7cb58ce | Shikhar Bhushan | self._timeout = timeout
|
362 | 4f650d54 | Shikhar Bhushan | |
363 | 19e7c7f6 | Shikhar Bhushan | raise_mode = property(fget=lambda self: self._raise_mode, fset=__set_raise_mode) |
364 | 19e7c7f6 | Shikhar Bhushan | """Depending on this exception raising mode, an `rpc-error` in the reply may be raised as an :exc:`RPCError` exception. Valid values are the constants defined in :class:`RaiseMode`. """
|
365 | 4bc8021f | Shikhar Bhushan | |
366 | 19e7c7f6 | Shikhar Bhushan | is_async = property(fget=lambda self: self._async, fset=__set_async) |
367 | c15671aa | Shikhar Bhushan | """Specifies whether this RPC will be / was requested asynchronously. By default RPC's are synchronous."""
|
368 | 4bc8021f | Shikhar Bhushan | |
369 | 19e7c7f6 | Shikhar Bhushan | timeout = property(fget=lambda self: self._timeout, fset=__set_timeout) |
370 | 19e7c7f6 | Shikhar Bhushan | """Timeout in seconds for synchronous waiting defining how long the RPC request will block on a reply before raising :exc:`TimeoutExpiredError`.
|
371 | 4bc8021f | Shikhar Bhushan |
|
372 | 4bc8021f | Shikhar Bhushan | Irrelevant for asynchronous usage.
|
373 | 4bc8021f | Shikhar Bhushan | """ |