# cisco returns incorrectly namespaced xml
CISCO_BS = 'urn:ietf:params:netconf:base:1.0'
-# we'd like BASE_NS to be prefixed as "netconf"
try:
register_namespace = ET.register_namespace
except AttributeError:
# cElementTree uses ElementTree's _namespace_map, so that's ok
ElementTree._namespace_map[uri] = prefix
+# we'd like BASE_NS to be prefixed as "netconf"
register_namespace('netconf', BASE_NS)
qualify = lambda tag, ns: '{%s}%s' % (namespace, tag)
unqualify = lambda tag: tag[tag.rfind('}')+1:]
-
################################################################################
# Build XML using Python data structures :-)
def __init__(self):
"TODO: docstring"
+ self._q = Queue()
self._listeners = set([])
- self._outQ = Queue()
self._lock = Lock()
-
+
def _dispatch_received(self, raw):
"TODO: docstring"
root = parse_root(raw)
def send(self, message):
"TODO: docstring"
logger.debug('queueing:%s' % message)
- self._outQ.put(message)
+ self._q.put(message)
class Listener:
from weakref import WeakValueDictionary
from . import logger
-from ncclient.content.parsers import RootParser
-from ncclient.content.common import qualify as _
-from ncclient.content.common import unqualify as __
-from ncclient.content.common import BASE_NS, CISCO_BS
-q_rpcreply = [_('rpc-reply', BASE_NS), _('rpc-reply', CISCO_BS)]
-class SessionListener:
+class RPCReplyListener(Listener):
'''This is the glue between received data and the object it should be
forwarded to.
logger.error('SessionListener.error: %r' % err)
if self._errback is not None:
errback(err)
+
+
+class NotificationListener(Listener):
+
+ pass
\ No newline at end of file
from uuid import uuid1
from weakref import WeakKeyDictionary
+from . import logger
from listener import SessionListener
from ncclient.content.builders import RPCBuilder
from ncclient.content.parsers import RPCReplyParser
+_listeners = WeakKeyDictionary()
+_lock = Lock()
+
+def get_listener(session):
+ with self._lock:
+ return _listeners.setdefault(session, ReplyListener())
+
class RPC:
-
- _listeners = WeakKeyDictionary()
- _lock = Lock()
-
+
def __init__(self, session):
self._session = session
self._id = None
self._reply_event = None
@property
- def _listener(self):
- with self._lock:
- return self._listeners.setdefault(self._session, SessionListener())
- def deliver(self, raw):
- self._reply = RPCReply(raw)
- self._reply_event.set()
-
- def _do_request(self, op, reply_event=None):
+ def _request(self, op):
self._id = uuid1().urn
+ self._reply = RPCReply()
# get the listener instance for this session
# <rpc-reply> with message id will reach response_cb
self._listener.register(self._id, self)
self._reply_event = Event()
self._reply_event.wait()
self._reply.parse()
- return self._reply
+ return self._reply
def request(self, *args, **kwds):
raise NotImplementedError
class RPCReply:
- def __init__(self, raw):
- self._raw = raw
- self._parsed = False
- self._errs = []
+ def __init__(self, event):
+ self._delivery_event = event
+ self._raw = None
+ self._errs = None
def __str__(self):
return self._raw
self._errs.append(RPCError(raw, err_dict))
self._parsed = True
+ def deliver(self, raw):
+ self._raw = raw
+ self._delivery_event.set()
+
+ def received(self, timeout=None):
+ self._delivery_event.wait(timeout)
+ return True
+
@property
def raw(self):
return self._raw
@property
def info(self):
return self._dict.get('info', None)
+
+class Notification:
+
+ pass
+
+
+
+from builder import TreeBuilder
+from common import BASE_NS
+from common import qualify as _
+
+################################################################################
+
+_ = qualify
+
+def build(msgid, op, encoding='utf-8'):
+ "TODO: docstring"
+ if isinstance(op, basestring):
+ return RPCBuilder.build_from_string(msgid, op, encoding)
+ else:
+ return RPCBuilder.build_from_spec(msgid, op, encoding)
+
+def build_from_spec(msgid, opspec, encoding='utf-8'):
+ "TODO: docstring"
+ spec = {
+ 'tag': _('rpc', BASE_NS),
+ 'attributes': {'message-id': msgid},
+ 'children': opspec
+ }
+ return TreeBuilder(spec).to_string(encoding)
+
+def build_from_string(msgid, opstr, encoding='utf-8'):
+ "TODO: docstring"
+ decl = '<?xml version="1.0" encoding="%s"?>' % encoding
+ doc = (u'''<rpc message-id="%s" xmlns="%s">%s</rpc>''' %
+ (msgid, BASE_NS, opstr)).encode(encoding)
+ return (decl + doc)
+
+################################################################################
+
+# parsing stuff TODO
+
+
"TODO: docstring"
import logging
-logger = logging.getLogger('ncclient.transport')
\ No newline at end of file
+logger = logging.getLogger('ncclient.transport')
# See the License for the specific language governing permissions and
# limitations under the License.
+"TODO: docstrings"
+
from ncclient import TransportError
+class AuthenticationError(TransportError):
+ pass
+
class SessionCloseError(TransportError):
def __init__(self, in_buf, out_buf=None):
msg = 'Unexpected session close.'
if in_buf:
- msg += ' .. IN_BUFFER: ||%s|| ' % in_buf
+ msg += ' IN_BUFFER: {%s}' % in_buf
if out_buf:
- msg += ' .. OUT_BUFFER: ||%s||' % out_buf
+ msg += ' OUT_BUFFER: {%s}' % out_buf
SSHError.__init__(self, msg)
class SSHError(TransportError):
pass
-class AuthenticationError(TransportError):
- pass
-
class SSHUnknownHostError(SSHError):
def __init__(self, hostname, key):
from xml.etree import cElementTree as ET
-from ncclient.content import TreeBuilder
-from ncclient.content import BASE_NS
+from ncclient.glue import Listener
+from ncclient.content import TreeBuilder, BASE_NS
from ncclient.content import qualify as _
-
+from ncclient.content import unqualify as __
def build(capabilities, encoding='utf-8'):
"Given a list of capability URI's returns encoded <hello> message"
# limitations under the License.
from threading import Thread, Event
+
from ncclient.capabilities import Capabilities, CAPABILITIES
+from ncclient.glue import Subject
+from ncclient.transport import logger
import hello
-from . import logger
-from ncclient.glue import Subject
class Session(Thread, Subject):
TICK = 0.1
class SSHSession(Session):
-
+
def __init__(self):
Session.__init__(self)
self._host_keys = paramiko.HostKeys()
else: # if we didn't break out of the loop, full delim was parsed
msg_till = buf.tell() - n
buf.seek(0)
- self.dispatch('received', buf.read(msg_till).strip())
+ self._dispatch_received(buf.read(msg_till).strip())
buf.seek(n+1, os.SEEK_CUR)
rest = buf.read()
buf = StringIO()
except Exception as e:
self.close()
logger.debug('*** broke out of main loop ***')
- self.dispatch('error', e)
+ self._dispatch_error(e)
@property
def transport(self):
- '''Get underlying paramiko.transport object; this is provided so methods
- like transport.set_keepalive can be called.
+ '''Get underlying paramiko transport object; this is provided so methods
+ like set_keepalive can be called on it. See paramiko.Transport
+ documentation for details.
'''
return self._transport