root / ncclient / operations / rpc.py @ f0271461
History | View | Annotate | Download (4 kB)
1 |
# Copyright 2009 Shikhar Bhushan
|
---|---|
2 |
#
|
3 |
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
# you may not use this file except in compliance with the License.
|
5 |
# You may obtain a copy of the License at
|
6 |
#
|
7 |
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
#
|
9 |
# Unless required by applicable law or agreed to in writing, software
|
10 |
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
# See the License for the specific language governing permissions and
|
13 |
# limitations under the License.
|
14 |
|
15 |
from threading import Event, Lock |
16 |
from uuid import uuid1 |
17 |
from weakref import WeakKeyDictionary |
18 |
|
19 |
from listener import SessionListener |
20 |
from ncclient.content.builders import RPCBuilder |
21 |
from ncclient.content.parsers import RPCReplyParser |
22 |
|
23 |
class RPC: |
24 |
|
25 |
_listeners = WeakKeyDictionary() |
26 |
_lock = Lock() |
27 |
|
28 |
def __init__(self, session): |
29 |
self._session = session
|
30 |
self._id = None |
31 |
self._reply = None # RPCReply |
32 |
self._reply_event = None |
33 |
|
34 |
@property
|
35 |
def _listener(self): |
36 |
with self._lock: |
37 |
return self._listeners.setdefault(self._session, SessionListener()) |
38 |
|
39 |
def deliver(self, raw): |
40 |
self._reply = RPCReply(raw)
|
41 |
self._reply_event.set()
|
42 |
|
43 |
def _do_request(self, op, reply_event=None): |
44 |
self._id = uuid1().urn
|
45 |
# get the listener instance for this session
|
46 |
# <rpc-reply> with message id will reach response_cb
|
47 |
self._listener.register(self._id, self) |
48 |
# only effective the first time, transport.session.Subject internally
|
49 |
# uses a set type for listeners
|
50 |
self._session.add_listener(self._listener) |
51 |
req = RPCBuilder.build(self._id, op)
|
52 |
self._session.send(req)
|
53 |
if reply_event is not None: # if we were provided an Event to use |
54 |
self._reply_event = reply_event
|
55 |
else: # otherwise, block till response received and return it |
56 |
self._reply_event = Event()
|
57 |
self._reply_event.wait()
|
58 |
self._reply.parse()
|
59 |
return self._reply |
60 |
|
61 |
def request(self, *args, **kwds): |
62 |
raise NotImplementedError |
63 |
|
64 |
@property
|
65 |
def has_reply(self): |
66 |
try:
|
67 |
return self._reply_event.isSet() |
68 |
except TypeError: # reply_event is None |
69 |
return False |
70 |
|
71 |
@property
|
72 |
def reply(self): |
73 |
return self._reply |
74 |
|
75 |
@property
|
76 |
def id(self): |
77 |
return self._id |
78 |
|
79 |
@property
|
80 |
def session(self): |
81 |
return self._session |
82 |
|
83 |
class RPCReply: |
84 |
|
85 |
def __init__(self, raw): |
86 |
self._raw = raw
|
87 |
self._parsed = False |
88 |
self._errs = []
|
89 |
|
90 |
def __str__(self): |
91 |
return self._raw |
92 |
|
93 |
def parse(self): |
94 |
if not self._parsed: |
95 |
errs = RPCReplyParser.parse(self._raw)
|
96 |
for raw, err_dict in errs: |
97 |
self._errs.append(RPCError(raw, err_dict))
|
98 |
self._parsed = True |
99 |
|
100 |
@property
|
101 |
def raw(self): |
102 |
return self._raw |
103 |
|
104 |
@property
|
105 |
def parsed(self): |
106 |
return self._parsed |
107 |
|
108 |
@property
|
109 |
def ok(self): |
110 |
return True if self._parsed and not self._errs else False |
111 |
|
112 |
@property
|
113 |
def errors(self): |
114 |
return self._errs |
115 |
|
116 |
class RPCError(Exception): # raise it if you like |
117 |
|
118 |
def __init__(self, raw, err_dict): |
119 |
self._raw = raw
|
120 |
self._dict = err_dict
|
121 |
|
122 |
def __str__(self): |
123 |
# TODO
|
124 |
return self._raw |
125 |
|
126 |
def __dict__(self): |
127 |
return self._dict |
128 |
|
129 |
@property
|
130 |
def raw(self): |
131 |
return self._raw |
132 |
|
133 |
@property
|
134 |
def type(self): |
135 |
return self._dict.get('type', None) |
136 |
|
137 |
@property
|
138 |
def severity(self): |
139 |
return self._dict.get('severity', None) |
140 |
|
141 |
@property
|
142 |
def tag(self): |
143 |
return self._dict.get('tag', None) |
144 |
|
145 |
@property
|
146 |
def path(self): |
147 |
return self._dict.get('path', None) |
148 |
|
149 |
@property
|
150 |
def message(self): |
151 |
return self._dict.get('message', None) |
152 |
|
153 |
@property
|
154 |
def info(self): |
155 |
return self._dict.get('info', None) |