Statistics
| Branch: | Tag: | Revision:

root / ncclient / operations / rpc.py @ 541247ba

History | View | Annotate | Download (5.1 kB)

1 589b23e4 Shikhar Bhushan
# Copyright 2009 Shikhar Bhushan
2 589b23e4 Shikhar Bhushan
#
3 589b23e4 Shikhar Bhushan
# Licensed under the Apache License, Version 2.0 (the "License");
4 589b23e4 Shikhar Bhushan
# you may not use this file except in compliance with the License.
5 589b23e4 Shikhar Bhushan
# You may obtain a copy of the License at
6 589b23e4 Shikhar Bhushan
#
7 589b23e4 Shikhar Bhushan
#    http://www.apache.org/licenses/LICENSE-2.0
8 589b23e4 Shikhar Bhushan
#
9 589b23e4 Shikhar Bhushan
# Unless required by applicable law or agreed to in writing, software
10 589b23e4 Shikhar Bhushan
# distributed under the License is distributed on an "AS IS" BASIS,
11 589b23e4 Shikhar Bhushan
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 589b23e4 Shikhar Bhushan
# See the License for the specific language governing permissions and
13 589b23e4 Shikhar Bhushan
# limitations under the License.
14 589b23e4 Shikhar Bhushan
15 38a9b062 Shikhar Bhushan
from threading import Event, Lock
16 38a9b062 Shikhar Bhushan
from uuid import uuid1
17 1d540e60 Shikhar Bhushan
from weakref import WeakValueDictionary
18 38a9b062 Shikhar Bhushan
19 1d540e60 Shikhar Bhushan
from ncclient.content import TreeBuilder
20 1d540e60 Shikhar Bhushan
from ncclient.content import qualify as _
21 1d540e60 Shikhar Bhushan
from ncclient.content import unqualify as __
22 3e022b7b Shikhar Bhushan
from ncclient.glue import Listener
23 3e022b7b Shikhar Bhushan
24 3e022b7b Shikhar Bhushan
from . import logger
25 3e022b7b Shikhar Bhushan
from reply import RPCReply
26 3e022b7b Shikhar Bhushan
27 541247ba Shikhar Bhushan
# Cisco does not include message-id attribute in <rpc-reply> in case of an error.
28 541247ba Shikhar Bhushan
# This is messed up however we have to deal with it.
29 541247ba Shikhar Bhushan
# So essentially, there can be only one operation at a time if we are talking to
30 541247ba Shikhar Bhushan
# a Cisco device.
31 e91a5349 Shikhar Bhushan
32 5858a82c Shikhar Bhushan
class RPC(object):
33 5858a82c Shikhar Bhushan
    
34 11d9e642 Shikhar Bhushan
    def __init__(self, session, async=False):
35 541247ba Shikhar Bhushan
        if session.is_remote_cisco and async:
36 541247ba Shikhar Bhushan
            raise UserWarning('Asynchronous mode not supported for Cisco devices')
37 38a9b062 Shikhar Bhushan
        self._session = session
38 1d540e60 Shikhar Bhushan
        self._async = async
39 11d9e642 Shikhar Bhushan
        self._id = uuid1().urn
40 5858a82c Shikhar Bhushan
        self._listener = RPCReplyListener(session)
41 5858a82c Shikhar Bhushan
        self._listener.register(self._id, self)
42 3e022b7b Shikhar Bhushan
        self._reply = None
43 11d9e642 Shikhar Bhushan
        self._reply_event = Event()
44 efed7d4c Shikhar Bhushan
    
45 11d9e642 Shikhar Bhushan
    def _build(self, op, encoding='utf-8'):
46 5858a82c Shikhar Bhushan
        if isinstance(op, dict):
47 5858a82c Shikhar Bhushan
            return self.build_from_spec(self._id, op, encoding)
48 11d9e642 Shikhar Bhushan
        else:
49 3e022b7b Shikhar Bhushan
            return self.build_from_string(self._id, op, encoding)
50 efed7d4c Shikhar Bhushan
    
51 e91a5349 Shikhar Bhushan
    def _request(self, op):
52 5858a82c Shikhar Bhushan
        req = self._build(op)
53 efed7d4c Shikhar Bhushan
        self._session.send(req)
54 1d540e60 Shikhar Bhushan
        if self._async:
55 41e2ed46 Shikhar Bhushan
            return self._reply_event
56 41e2ed46 Shikhar Bhushan
        else:
57 ee4bb099 Shikhar Bhushan
            self._reply_event.wait()
58 efed7d4c Shikhar Bhushan
            self._reply.parse()
59 3e022b7b Shikhar Bhushan
            return self._reply
60 ee4bb099 Shikhar Bhushan
    
61 41e2ed46 Shikhar Bhushan
    def _set_reply(self, raw):
62 3e022b7b Shikhar Bhushan
        self._reply = RPCReply(raw)
63 41e2ed46 Shikhar Bhushan
    
64 41e2ed46 Shikhar Bhushan
    def _set_reply_event(self):
65 3e022b7b Shikhar Bhushan
        self._reply_event.set()
66 ee4bb099 Shikhar Bhushan
    
67 41e2ed46 Shikhar Bhushan
    def _delivery_hook(self):
68 41e2ed46 Shikhar Bhushan
        'For subclasses'
69 41e2ed46 Shikhar Bhushan
        pass
70 41e2ed46 Shikhar Bhushan
    
71 41e2ed46 Shikhar Bhushan
    def deliver(self, raw):
72 41e2ed46 Shikhar Bhushan
        self._set_reply(raw)
73 41e2ed46 Shikhar Bhushan
        self._delivery_hook()
74 41e2ed46 Shikhar Bhushan
        self._set_reply_event()
75 41e2ed46 Shikhar Bhushan
    
76 589b23e4 Shikhar Bhushan
    @property
77 35ad9d81 Shikhar Bhushan
    def has_reply(self):
78 3e022b7b Shikhar Bhushan
        return self._reply_event.isSet()
79 589b23e4 Shikhar Bhushan
    
80 589b23e4 Shikhar Bhushan
    @property
81 ee4bb099 Shikhar Bhushan
    def reply(self):
82 ee4bb099 Shikhar Bhushan
        return self._reply
83 ee4bb099 Shikhar Bhushan
    
84 ee4bb099 Shikhar Bhushan
    @property
85 41e2ed46 Shikhar Bhushan
    def is_async(self):
86 41e2ed46 Shikhar Bhushan
        return self._async
87 41e2ed46 Shikhar Bhushan
    
88 41e2ed46 Shikhar Bhushan
    @property
89 38a9b062 Shikhar Bhushan
    def id(self):
90 ee4bb099 Shikhar Bhushan
        return self._id
91 ee4bb099 Shikhar Bhushan
    
92 ee4bb099 Shikhar Bhushan
    @property
93 ee4bb099 Shikhar Bhushan
    def session(self):
94 ee4bb099 Shikhar Bhushan
        return self._session
95 efed7d4c Shikhar Bhushan
    
96 3e022b7b Shikhar Bhushan
    @property
97 3e022b7b Shikhar Bhushan
    def reply_event(self):
98 3e022b7b Shikhar Bhushan
        return self._reply_event
99 3e022b7b Shikhar Bhushan
    
100 11d9e642 Shikhar Bhushan
    @staticmethod
101 11d9e642 Shikhar Bhushan
    def build_from_spec(msgid, opspec, encoding='utf-8'):
102 11d9e642 Shikhar Bhushan
        "TODO: docstring"
103 11d9e642 Shikhar Bhushan
        spec = {
104 1d540e60 Shikhar Bhushan
            'tag': _('rpc'),
105 11d9e642 Shikhar Bhushan
            'attributes': {'message-id': msgid},
106 11d9e642 Shikhar Bhushan
            'children': opspec
107 11d9e642 Shikhar Bhushan
            }
108 11d9e642 Shikhar Bhushan
        return TreeBuilder(spec).to_string(encoding)
109 11d9e642 Shikhar Bhushan
    
110 11d9e642 Shikhar Bhushan
    @staticmethod
111 11d9e642 Shikhar Bhushan
    def build_from_string(msgid, opstr, encoding='utf-8'):
112 11d9e642 Shikhar Bhushan
        "TODO: docstring"
113 11d9e642 Shikhar Bhushan
        decl = '<?xml version="1.0" encoding="%s"?>' % encoding
114 5858a82c Shikhar Bhushan
        doc = (u'<rpc message-id="%s" xmlns="%s">%s</rpc>' %
115 11d9e642 Shikhar Bhushan
               (msgid, BASE_NS, opstr)).encode(encoding)
116 5858a82c Shikhar Bhushan
        return '%s%s' % (decl, doc)
117 3e022b7b Shikhar Bhushan
118 3e022b7b Shikhar Bhushan
119 3e022b7b Shikhar Bhushan
class RPCReplyListener(Listener):
120 3e022b7b Shikhar Bhushan
    
121 3e022b7b Shikhar Bhushan
    # TODO - determine if need locking
122 3e022b7b Shikhar Bhushan
    
123 541247ba Shikhar Bhushan
    # one instance per session
124 541247ba Shikhar Bhushan
    def __new__(cls, session):
125 541247ba Shikhar Bhushan
        instance = session.get_listener_instance(cls)
126 3e022b7b Shikhar Bhushan
        if instance is None:
127 3e022b7b Shikhar Bhushan
            instance = object.__new__(cls)
128 3e022b7b Shikhar Bhushan
            instance._id2rpc = WeakValueDictionary()
129 541247ba Shikhar Bhushan
            instance._cisco = session.is_remote_cisco
130 3e022b7b Shikhar Bhushan
            instance._errback = None
131 541247ba Shikhar Bhushan
            session.add_listener(instance)
132 3e022b7b Shikhar Bhushan
        return instance
133 3e022b7b Shikhar Bhushan
    
134 3e022b7b Shikhar Bhushan
    def __str__(self):
135 3e022b7b Shikhar Bhushan
        return 'RPCReplyListener'
136 3e022b7b Shikhar Bhushan
    
137 3e022b7b Shikhar Bhushan
    def set_errback(self, errback):
138 3e022b7b Shikhar Bhushan
        self._errback = errback
139 3e022b7b Shikhar Bhushan
140 41e2ed46 Shikhar Bhushan
    def register(self, id, rpc):
141 41e2ed46 Shikhar Bhushan
        self._id2rpc[id] = rpc
142 3e022b7b Shikhar Bhushan
    
143 3e022b7b Shikhar Bhushan
    def callback(self, root, raw):
144 3e022b7b Shikhar Bhushan
        tag, attrs = root
145 3e022b7b Shikhar Bhushan
        if __(tag) != 'rpc-reply':
146 3e022b7b Shikhar Bhushan
            return
147 541247ba Shikhar Bhushan
        rpc = None
148 3e022b7b Shikhar Bhushan
        for key in attrs:
149 3e022b7b Shikhar Bhushan
            if __(key) == 'message-id':
150 3e022b7b Shikhar Bhushan
                id = attrs[key]
151 3e022b7b Shikhar Bhushan
                try:
152 541247ba Shikhar Bhushan
                    rpc = self._id2rpc.pop(id)
153 41e2ed46 Shikhar Bhushan
                except KeyError:
154 541247ba Shikhar Bhushan
                    logger.warning('[RPCReplyListener.callback] no object '
155 3e022b7b Shikhar Bhushan
                                   + 'registered for message-id: [%s]' % id)
156 41e2ed46 Shikhar Bhushan
                except Exception as e:
157 41e2ed46 Shikhar Bhushan
                    logger.debug('[RPCReplyListener.callback] error - %r' % e)
158 3e022b7b Shikhar Bhushan
                break
159 3e022b7b Shikhar Bhushan
        else:
160 541247ba Shikhar Bhushan
            if self._cisco:
161 541247ba Shikhar Bhushan
                assert(len(self._id2rpc) == 1)
162 541247ba Shikhar Bhushan
                rpc = self._id2rpc.values()[0]
163 541247ba Shikhar Bhushan
                self._id2rpc.clear()
164 541247ba Shikhar Bhushan
            else:
165 541247ba Shikhar Bhushan
                logger.warning('<rpc-reply> without message-id received: %s' % raw)
166 541247ba Shikhar Bhushan
        logger.debug('[RPCReplyListener.callback] delivering to %r' % rpc)
167 541247ba Shikhar Bhushan
        rpc.deliver(raw)
168 3e022b7b Shikhar Bhushan
    
169 3e022b7b Shikhar Bhushan
    def errback(self, err):
170 3e022b7b Shikhar Bhushan
        if self._errback is not None:
171 1d540e60 Shikhar Bhushan
            self._errback(err)