Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ 11bab021

History | View | Annotate | Download (12.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 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 11bab021 Shikhar Bhushan
    
109 11bab021 Shikhar Bhushan
    tag_to_attr = {
110 11bab021 Shikhar Bhushan
        qualify("error-type"): "_type",
111 11bab021 Shikhar Bhushan
        qualify("error-tag"): "_tag",
112 11bab021 Shikhar Bhushan
        qualify("error-severity"): "_severity",
113 11bab021 Shikhar Bhushan
        qualify("error-info"): "_info",
114 11bab021 Shikhar Bhushan
        qualify("error-path"): "_path",
115 11bab021 Shikhar Bhushan
        qualify("error-message"): "_message"
116 11bab021 Shikhar Bhushan
    }
117 11bab021 Shikhar Bhushan
    
118 9667bcb2 Shikhar Bhushan
    def __init__(self, err):
119 11bab021 Shikhar Bhushan
        for attr in tag_to_attr.values():
120 11bab021 Shikhar Bhushan
            setattr(self, attr, None)
121 9667bcb2 Shikhar Bhushan
        for subele in err:
122 11bab021 Shikhar Bhushan
            attr = tag_to_attr.get(subele.tag, None)
123 11bab021 Shikhar Bhushan
            if attr is not None:
124 11bab021 Shikhar Bhushan
                setattr(self, attr, subele.text)
125 a14c36f9 Shikhar Bhushan
        if self.message is not None:
126 d771dffc Shikhar Bhushan
            OperationError.__init__(self, self.message)
127 a14c36f9 Shikhar Bhushan
        else:
128 c1bdbd86 Shikhar Bhushan
            OperationError.__init__(self, self.to_dict())
129 22566666 Shikhar Bhushan
    
130 22566666 Shikhar Bhushan
    def to_dict(self):
131 11bab021 Shikhar Bhushan
        return dict([ (attr[1:], gettattr(self, attr)) for attr in tag_to_attr.values() ])
132 22566666 Shikhar Bhushan
    
133 a14c36f9 Shikhar Bhushan
    @property
134 a14c36f9 Shikhar Bhushan
    def type(self):
135 2abf9522 Shikhar Bhushan
        "`string` representing text of *error-type* element"
136 9667bcb2 Shikhar Bhushan
        return self._type
137 bd7957fb Shikhar Bhushan
    
138 a14c36f9 Shikhar Bhushan
    @property
139 a14c36f9 Shikhar Bhushan
    def tag(self):
140 2abf9522 Shikhar Bhushan
        "`string` representing text of *error-tag* element"
141 9667bcb2 Shikhar Bhushan
        return self._tag
142 bd7957fb Shikhar Bhushan
    
143 bd7957fb Shikhar Bhushan
    @property
144 bd7957fb Shikhar Bhushan
    def severity(self):
145 bd7957fb Shikhar Bhushan
        "`string` representing text of *error-severity* element"
146 bd7957fb Shikhar Bhushan
        return self._severity
147 bd7957fb Shikhar Bhushan
    
148 a14c36f9 Shikhar Bhushan
    @property
149 a14c36f9 Shikhar Bhushan
    def path(self):
150 2abf9522 Shikhar Bhushan
        "`string` or :const:`None`; representing text of *error-path* element"
151 9667bcb2 Shikhar Bhushan
        return self._path
152 11bab021 Shikhar Bhushan
    
153 a14c36f9 Shikhar Bhushan
    @property
154 a14c36f9 Shikhar Bhushan
    def message(self):
155 2abf9522 Shikhar Bhushan
        "`string` or :const:`None`; representing text of *error-message* element"
156 9667bcb2 Shikhar Bhushan
        return self._message
157 11bab021 Shikhar Bhushan
    
158 a14c36f9 Shikhar Bhushan
    @property
159 a14c36f9 Shikhar Bhushan
    def info(self):
160 2abf9522 Shikhar Bhushan
        "`string` (XML) or :const:`None`, representing *error-info* element"
161 9667bcb2 Shikhar Bhushan
        return self._info
162 a14c36f9 Shikhar Bhushan
163 a14c36f9 Shikhar Bhushan
164 11bab021 Shikhar Bhushan
class RPCReplyListener(SessionListener): # internal use
165 11bab021 Shikhar Bhushan
    
166 11bab021 Shikhar Bhushan
    creation_lock = Lock()
167 11bab021 Shikhar Bhushan
    
168 7b02d55b Shikhar Bhushan
    # one instance per session -- maybe there is a better way??
169 a14c36f9 Shikhar Bhushan
    def __new__(cls, session):
170 11bab021 Shikhar Bhushan
        with creation_lock:
171 11bab021 Shikhar Bhushan
            instance = session.get_listener_instance(cls)
172 11bab021 Shikhar Bhushan
            if instance is None:
173 11bab021 Shikhar Bhushan
                instance = object.__new__(cls)
174 11bab021 Shikhar Bhushan
                instance._lock = Lock()
175 11bab021 Shikhar Bhushan
                instance._id2rpc = {}
176 11bab021 Shikhar Bhushan
                #instance._pipelined = session.can_pipeline
177 11bab021 Shikhar Bhushan
                session.add_listener(instance)
178 11bab021 Shikhar Bhushan
            return instance
179 4f650d54 Shikhar Bhushan
180 a14c36f9 Shikhar Bhushan
    def register(self, id, rpc):
181 a14c36f9 Shikhar Bhushan
        with self._lock:
182 a14c36f9 Shikhar Bhushan
            self._id2rpc[id] = rpc
183 4f650d54 Shikhar Bhushan
184 a14c36f9 Shikhar Bhushan
    def callback(self, root, raw):
185 a14c36f9 Shikhar Bhushan
        tag, attrs = root
186 9667bcb2 Shikhar Bhushan
        if tag != qualify("rpc-reply"):
187 a14c36f9 Shikhar Bhushan
            return
188 0304f041 Shikhar Bhushan
        for key in attrs: # in the <rpc-reply> attributes
189 9667bcb2 Shikhar Bhushan
            if key == "message-id": # if we found msgid attr
190 0304f041 Shikhar Bhushan
                id = attrs[key] # get the msgid
191 9667bcb2 Shikhar Bhushan
                with self._lock:
192 11bab021 Shikhar Bhushan
                    try:
193 9667bcb2 Shikhar Bhushan
                        rpc = self._id2rpc[id] # the corresponding rpc
194 9667bcb2 Shikhar Bhushan
                        logger.debug("Delivering to %r" % rpc)
195 0304f041 Shikhar Bhushan
                        rpc.deliver_reply(raw)
196 9667bcb2 Shikhar Bhushan
                    except KeyError:
197 11bab021 Shikhar Bhushan
                        raise OperationError("Unknown 'message-id': %s", id)
198 9667bcb2 Shikhar Bhushan
                    # no catching other exceptions, fail loudly if must
199 9667bcb2 Shikhar Bhushan
                    else:
200 9667bcb2 Shikhar Bhushan
                        # if no error delivering, can del the reference to the RPC
201 9667bcb2 Shikhar Bhushan
                        del self._id2rpc[id]
202 9667bcb2 Shikhar Bhushan
                        break
203 a14c36f9 Shikhar Bhushan
        else:
204 9667bcb2 Shikhar Bhushan
            raise OperationError("Could not find 'message-id' attribute in <rpc-reply>")
205 0304f041 Shikhar Bhushan
    
206 a14c36f9 Shikhar Bhushan
    def errback(self, err):
207 6a2dfeb4 Shikhar Bhushan
        try:
208 6a2dfeb4 Shikhar Bhushan
            for rpc in self._id2rpc.values():
209 6a2dfeb4 Shikhar Bhushan
                rpc.deliver_error(err)
210 6a2dfeb4 Shikhar Bhushan
        finally:
211 6a2dfeb4 Shikhar Bhushan
            self._id2rpc.clear()
212 4de03d63 Shikhar Bhushan
213 4de03d63 Shikhar Bhushan
214 4de03d63 Shikhar Bhushan
class RPC(object):
215 4f650d54 Shikhar Bhushan
216 216bb34c Shikhar Bhushan
    """Base class for all operations.
217 216bb34c Shikhar Bhushan

218 216bb34c Shikhar Bhushan
    Directly corresponds to *<rpc>* requests. Handles making the request, and
219 216bb34c Shikhar Bhushan
    taking delivery of the reply.
220 216bb34c Shikhar Bhushan
    """
221 a7cb58ce Shikhar Bhushan
222 bbd4ce54 Shikhar Bhushan
    #: Subclasses can specify their dependencies on capabilities. List of URI's
223 a7cb58ce Shikhar Bhushan
    # or abbreviated names, e.g. ':writable-running'. These are verified at the
224 a7cb58ce Shikhar Bhushan
    # time of object creation. If the capability is not available, a
225 a7cb58ce Shikhar Bhushan
    # :exc:`MissingCapabilityError` is raised.
226 4de03d63 Shikhar Bhushan
    DEPENDS = []
227 a7cb58ce Shikhar Bhushan
228 bbd4ce54 Shikhar Bhushan
    #: Subclasses can specify a different reply class, but it must be a
229 a7cb58ce Shikhar Bhushan
    # subclass of :class:`RPCReply`.
230 4de03d63 Shikhar Bhushan
    REPLY_CLS = RPCReply
231 4f650d54 Shikhar Bhushan
232 9667bcb2 Shikhar Bhushan
    def __init__(self, session, async=False, timeout=None, raise_mode="none"):
233 4de03d63 Shikhar Bhushan
        self._session = session
234 4de03d63 Shikhar Bhushan
        try:
235 4de03d63 Shikhar Bhushan
            for cap in self.DEPENDS:
236 4de03d63 Shikhar Bhushan
                self._assert(cap)
237 4de03d63 Shikhar Bhushan
        except AttributeError:
238 4f650d54 Shikhar Bhushan
            pass
239 4de03d63 Shikhar Bhushan
        self._async = async
240 4de03d63 Shikhar Bhushan
        self._timeout = timeout
241 6c70b245 Shikhar Bhushan
        self._raise_mode = raise_mode
242 9667bcb2 Shikhar Bhushan
        self._id = uuid1().urn # Keeps things simple instead of having a class attr that has to be locked
243 4de03d63 Shikhar Bhushan
        self._listener = RPCReplyListener(session)
244 4de03d63 Shikhar Bhushan
        self._listener.register(self._id, self)
245 4de03d63 Shikhar Bhushan
        self._reply = None
246 4f650d54 Shikhar Bhushan
        self._error = None
247 a7cb58ce Shikhar Bhushan
        self._event = Event()
248 4f650d54 Shikhar Bhushan
249 9667bcb2 Shikhar Bhushan
    def _build(self, subele):
250 a7cb58ce Shikhar Bhushan
        # internal
251 9667bcb2 Shikhar Bhushan
        ele = new_ele("rpc", {"message-id": self._id}, xmlns=BASE_NS_1_0)
252 9667bcb2 Shikhar Bhushan
        ele.append(subele)
253 9667bcb2 Shikhar Bhushan
        return to_xml(ele)
254 4f650d54 Shikhar Bhushan
255 4de03d63 Shikhar Bhushan
    def _request(self, op):
256 a7cb58ce Shikhar Bhushan
        """Subclasses call this method to make the RPC request.
257 0304f041 Shikhar Bhushan
        
258 0304f041 Shikhar Bhushan
        In synchronous mode, waits until the reply is received and returns
259 a7cb58ce Shikhar Bhushan
        :class:`RPCReply`.
260 0304f041 Shikhar Bhushan
        
261 0304f041 Shikhar Bhushan
        In asynchronous mode, returns immediately, returning a reference to this
262 0304f041 Shikhar Bhushan
        object. The :attr:`event` attribute will be set when the reply has been
263 0304f041 Shikhar Bhushan
        received (see :attr:`reply`) or an error occured (see :attr:`error`).
264 0304f041 Shikhar Bhushan
        
265 a7cb58ce Shikhar Bhushan
        :type opspec: :obj:`dict` or :obj:`string` or :class:`~xml.etree.ElementTree.Element`
266 0304f041 Shikhar Bhushan
        :rtype: :class:`RPCReply` (sync) or :class:`RPC` (async)
267 a7cb58ce Shikhar Bhushan
        """
268 9667bcb2 Shikhar Bhushan
        logger.info('Requesting %r' % self.__class__.__name__)
269 4de03d63 Shikhar Bhushan
        req = self._build(op)
270 66cd54c8 Shikhar Bhushan
        self._session.send(req)
271 66cd54c8 Shikhar Bhushan
        if self._async:
272 9667bcb2 Shikhar Bhushan
            logger.debug('Async request, returning %r', self)
273 0304f041 Shikhar Bhushan
            return self
274 4de03d63 Shikhar Bhushan
        else:
275 9667bcb2 Shikhar Bhushan
            logger.debug('Sync request, will wait for timeout=%r' %
276 9667bcb2 Shikhar Bhushan
                         self._timeout)
277 66cd54c8 Shikhar Bhushan
            self._event.wait(self._timeout)
278 66cd54c8 Shikhar Bhushan
            if self._event.isSet():
279 66cd54c8 Shikhar Bhushan
                if self._error:
280 6c70b245 Shikhar Bhushan
                    # Error that prevented reply delivery
281 0cdb8b3c Shikhar Bhushan
                    raise self._error
282 66cd54c8 Shikhar Bhushan
                self._reply.parse()
283 6c70b245 Shikhar Bhushan
                if self._reply.error is not None:
284 6c70b245 Shikhar Bhushan
                    # <rpc-error>'s [ RPCError ]
285 6c70b245 Shikhar Bhushan
                    if self._raise_mode == "all":
286 7b02d55b Shikhar Bhushan
                        raise self._reply.error
287 6c70b245 Shikhar Bhushan
                    elif (self._raise_mode == "errors" and
288 6c70b245 Shikhar Bhushan
                          self._reply.error.type == "error"):
289 6c70b245 Shikhar Bhushan
                        raise self._reply.error
290 66cd54c8 Shikhar Bhushan
                return self._reply
291 4de03d63 Shikhar Bhushan
            else:
292 216bb34c Shikhar Bhushan
                raise TimeoutExpiredError
293 4f650d54 Shikhar Bhushan
294 a7cb58ce Shikhar Bhushan
    def request(self, *args, **kwds):
295 dd8b8dd7 Shikhar Bhushan
        "Subclasses implement this method."
296 dd225c7a Shikhar Bhushan
        return self._request(self.SPEC)
297 6c70b245 Shikhar Bhushan
    
298 4de03d63 Shikhar Bhushan
    def _assert(self, capability):
299 a7cb58ce Shikhar Bhushan
        """Subclasses can use this method to verify that a capability is available
300 a7cb58ce Shikhar Bhushan
        with the NETCONF server, before making a request that requires it. A
301 216bb34c Shikhar Bhushan
        :exc:`MissingCapabilityError` will be raised if the capability is not
302 a7cb58ce Shikhar Bhushan
        available."""
303 4de03d63 Shikhar Bhushan
        if capability not in self._session.server_capabilities:
304 bbd4ce54 Shikhar Bhushan
            raise MissingCapabilityError('Server does not support [%s]' %
305 bbd4ce54 Shikhar Bhushan
                                         capability)
306 0304f041 Shikhar Bhushan
    
307 a7cb58ce Shikhar Bhushan
    def deliver_reply(self, raw):
308 a7cb58ce Shikhar Bhushan
        # internal use
309 4de03d63 Shikhar Bhushan
        self._reply = self.REPLY_CLS(raw)
310 a7cb58ce Shikhar Bhushan
        self._event.set()
311 4f650d54 Shikhar Bhushan
312 a7cb58ce Shikhar Bhushan
    def deliver_error(self, err):
313 a7cb58ce Shikhar Bhushan
        # internal use
314 0cdb8b3c Shikhar Bhushan
        self._error = err
315 a7cb58ce Shikhar Bhushan
        self._event.set()
316 4f650d54 Shikhar Bhushan
317 4de03d63 Shikhar Bhushan
    @property
318 4de03d63 Shikhar Bhushan
    def reply(self):
319 a7cb58ce Shikhar Bhushan
        ":class:`RPCReply` element if reply has been received or :const:`None`"
320 4de03d63 Shikhar Bhushan
        return self._reply
321 4f650d54 Shikhar Bhushan
322 4de03d63 Shikhar Bhushan
    @property
323 a7cb58ce Shikhar Bhushan
    def error(self):
324 a7cb58ce Shikhar Bhushan
        """:exc:`Exception` type if an error occured or :const:`None`.
325 0304f041 Shikhar Bhushan
        
326 a7cb58ce Shikhar Bhushan
        .. note::
327 a7cb58ce Shikhar Bhushan
            This represents an error which prevented a reply from being
328 a7cb58ce Shikhar Bhushan
            received. An *<rpc-error>* does not fall in that category -- see
329 a7cb58ce Shikhar Bhushan
            :class:`RPCReply` for that.
330 a7cb58ce Shikhar Bhushan
        """
331 a7cb58ce Shikhar Bhushan
        return self._error
332 a7cb58ce Shikhar Bhushan
333 a7cb58ce Shikhar Bhushan
    @property
334 4de03d63 Shikhar Bhushan
    def id(self):
335 a7cb58ce Shikhar Bhushan
        "The *message-id* for this RPC"
336 4de03d63 Shikhar Bhushan
        return self._id
337 4f650d54 Shikhar Bhushan
338 4de03d63 Shikhar Bhushan
    @property
339 4de03d63 Shikhar Bhushan
    def session(self):
340 a7cb58ce Shikhar Bhushan
        """The :class:`~ncclient.transport.Session` object associated with this
341 a7cb58ce Shikhar Bhushan
        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 a7cb58ce Shikhar Bhushan
        """:class:`~threading.Event` that is set when reply has been received or
347 a7cb58ce Shikhar Bhushan
        error occured."""
348 a7cb58ce Shikhar Bhushan
        return self._event
349 a7cb58ce Shikhar Bhushan
350 a7cb58ce Shikhar Bhushan
    def set_async(self, async=True):
351 a7cb58ce Shikhar Bhushan
        """Set asynchronous mode for this RPC."""
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 6c70b245 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 a7cb58ce Shikhar Bhushan
    def set_timeout(self, timeout):
361 9667bcb2 Shikhar Bhushan
        """Set the timeout for synchronous waiting; defining how long the RPC
362 9667bcb2 Shikhar Bhushan
        request will block on a reply before raising an error. Irrelevant for
363 9667bcb2 Shikhar Bhushan
        asynchronous usage."""
364 a7cb58ce Shikhar Bhushan
        self._timeout = timeout
365 4f650d54 Shikhar Bhushan
366 a7cb58ce Shikhar Bhushan
    #: Whether this RPC is asynchronous
367 9667bcb2 Shikhar Bhushan
    is_async = property(fget=lambda self: self._async, fset=set_async)
368 4f650d54 Shikhar Bhushan
369 a7cb58ce Shikhar Bhushan
    #: Timeout for synchronous waiting
370 4de03d63 Shikhar Bhushan
    timeout = property(fget=lambda self: self._timeout, fset=set_timeout)