Revision 8b4b9936

/dev/null
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
class Capabilities:
16
    
17
    def __init__(self, capabilities=None):
18
        self._dict = {}
19
        if isinstance(capabilities, dict):
20
            self._dict = capabilities
21
        elif isinstance(capabilities, list):
22
            for uri in capabilities:
23
                self._dict[uri] = Capabilities.guess_shorthand(uri)
24
    
25
    def __contains__(self, key):
26
        return ( key in self._dict ) or ( key in self._dict.values() )
27
    
28
    def __iter__(self):
29
        return self._dict.keys().__iter__()
30
    
31
    def __repr__(self):
32
        return repr(self._dict.keys())
33
    
34
    def add(self, uri, shorthand=None):
35
        if shorthand is None:
36
            shorthand = Capabilities.guess_shorthand(uri)
37
        self._dict[uri] = shorthand
38
    
39
    set = add
40
    
41
    def remove(self, key):
42
        if key in self._dict:
43
            del self._dict[key]
44
        else:
45
            for uri in self._dict:
46
                if self._dict[uri] == key:
47
                    del self._dict[uri]
48
                    break
49
    
50
    @staticmethod
51
    def guess_shorthand(uri):
52
        if uri.startswith('urn:ietf:params:netconf:capability:'):
53
            return (':' + uri.split(':')[5])
54

  
55
    
56
CAPABILITIES = Capabilities([
57
    'urn:ietf:params:netconf:base:1.0',
58
    'urn:ietf:params:netconf:capability:writable-running:1.0',
59
    'urn:ietf:params:netconf:capability:candidate:1.0',
60
    'urn:ietf:params:netconf:capability:confirmed-commit:1.0',
61
    'urn:ietf:params:netconf:capability:rollback-on-error:1.0',
62
    'urn:ietf:params:netconf:capability:startup:1.0',
63
    'urn:ietf:params:netconf:capability:url:1.0',
64
    'urn:ietf:params:netconf:capability:validate:1.0',
65
    'urn:ietf:params:netconf:capability:xpath:1.0',
66
    'urn:ietf:params:netconf:capability:notification:1.0',
67
    'urn:ietf:params:netconf:capability:interleave:1.0'
68
    ])
69

  
70
if __name__ == "__main__":
71
    assert(':validate' in CAPABILITIES) # test __contains__
b/ncclient/content/__init__.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
'This module serves as an XML abstraction layer'
15
'This module serves as an XML abstraction layer'
16

  
17
import logging
18
logger = logging.getLogger('ncclient.content')
b/ncclient/content/builders.py
23 23
    '''
24 24
    
25 25
    def __init__(self, spec):
26
        self._root = Builder.build(spec)
26
        self._root = TreeBuilder.build(spec)
27 27
        
28 28
    def to_string(self, encoding='utf-8'):
29 29
        return ET.tostring(self._root, encoding)
......
39 39
            ele = ET.Element(spec.get('tag'), spec.get('attributes', {}))
40 40
            ele.text = spec.get('text', '')
41 41
            for child in spec.get('children', []):
42
                ele.append(Builder.build(child))
42
                ele.append(TreeBuilder.build(child))
43 43
            return ele
44 44
        elif spec.has_key('comment'):
45 45
            return ET.Comment(spec.get('comment'))
......
53 53
    def build(capabilities, encoding='utf-8'):
54 54
        children = [{'tag': 'capability', 'text': uri } for uri in capabilities]
55 55
        spec = {
56
            'tag': _('hello', Hello.NS),
56
            'tag': _('hello', BASE_NS),
57 57
            'children': [{
58 58
                        'tag': 'capabilities',
59 59
                        'children': children
......
65 65
class RPCBuilder:
66 66
    
67 67
    @staticmethod
68
    def build(msgid, op, encoding='utf-8'):
69
        if isinstance(opspec, basestring):
70
            return build_from_string(msgid, op, encoding)
71
        else:
72
            return build_from_spec(msgid, op, encoding)
73
    
74
    @staticmethod
68 75
    def build_from_spec(msgid, opspec, encoding='utf-8'):
69 76
        if isinstance(opspec, dict):
70 77
            opspec = [opspec]
71 78
        return TreeBuilder({
72
                'tag': _('rpc', RPC.NS),
79
                'tag': _('rpc', BASE_NS),
73 80
                'attributes': {'message-id': msgid},
74 81
                'children': opspec
75 82
                }).to_string(encoding)
b/ncclient/content/common.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
16

  
15 17
def qualify(tag, namespace=None):
16 18
    'Returns qualified name of form `{namespace}tag`'
17 19
    if namespace is None:
18 20
        return tag
19 21
    else:
20 22
        return '{%s}%s' % (namespace, tag)
21

  
22
BASE_NS = 'urn:ietf:params:xml:ns:netconf:base:1.0'
b/ncclient/content/parsers.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
from xml.etree import cElementTree as ElementTree
15
from xml.etree import cElementTree as ET
16 16

  
17 17
from common import BASE_NS
18 18
from common import qualify as _
b/ncclient/operations/__init__.py
14 14

  
15 15
'NETCONF Remote Procedure Calls (RPC) and protocol operations'
16 16

  
17
from ncclient import content
18
from ncclient.capabilities import CAPABILITIES
19
from rpc import RPC, RPCReply, RPCError
17
import logging
18
logger = logging.getLogger('ncclient.operations')
20 19

  
21
from retrieve import Get, GetConfig
22
from edit import EditConfig, DeleteConfig
23
from session import CloseSession, KillSession
24
from lock import Lock, Unlock
25
from notification import CreateSubscription
26

  
27
__all__ = [
28
    'Get',
29
    'GetConfig',
30
    'EditConfig',
31
    'DeleteConfig',
32
    'Lock',
33
    'Unlock',
34
    'CloseSession',
35
    'KillSession',
36
    'CreateSubscription',
37
    ]
20
#from ncclient.session import CAPABILITIES
21
#
22
#from retrieve import Get, GetConfig
23
#from edit import EditConfig, DeleteConfig
24
#from session import CloseSession, KillSession
25
#from lock import Lock, Unlock
26
#from notification import CreateSubscription
27
#
28
#__all__ = [
29
#    'Get',
30
#    'GetConfig',
31
#    'EditConfig',
32
#    'DeleteConfig',
33
#    'Lock',
34
#    'Unlock',
35
#    'CloseSession',
36
#    'KillSession',
37
#    'CreateSubscription',
38
#    ]
b/ncclient/operations/listener.py
1
#!/usr/bin/env python
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 weakref import WeakValueDictionary
16

  
17
from ncclient.content.parsers import RootParser
2 18

  
3 19
_listeners = WeakValueDictionary()
4 20

  
b/ncclient/operations/rpc.py
17 17
from threading import Event, Lock
18 18
from uuid import uuid1
19 19

  
20
_listeners = WeakValueDictionary()
21

  
22
def get_listener(session):
23
    try:
24
        return _listeners[session]
25
    except KeyError:
26
        _listeners[session] = MessageListener()
27
        return _listeners[session]
20
from listener import get_listener
21
from ncclient.content.builders import RPCBuilder
28 22

  
29 23
class RPC:
30 24
    
......
36 30
        self._reply_event = Event()
37 31
        self.listener.register(self._id, self)
38 32
        session.add_listener(self.listener)
39

  
33
    
40 34
    def _response_cb(self, reply):
41 35
        self._reply = reply
42 36
        self._event.set()
43 37
    
44
    def _do_request(self, operation):
45
        'operation is xml string'
46
        self._session.send(content.RPC.make(self._id, operation))
38
    def _do_request(self, op):
39
        self._session.send(RPCBuilder.build(self._id, op))
47 40
        if not self._async:
48 41
            self._reply_event.wait()
49 42
        return self._reply
......
85 78
        pass
86 79
    
87 80

  
88
class MessageListener:
89
    
90
    def __init__(self):
91
        # {message-id: RPC}
92
        self._rpc = WeakValueDictionary()
93
        # if the session gets closed by remote endpoint,
94
        # need to know if it is an error event or was requested through
95
        # a NETCONF operation i.e. CloseSession
96
        self._expecting_close = False
97
        # other recognized names and behavior on receiving them
98
        self._recognized = []
99
    
100
    def __str__(self):
101
        return 'MessageListener'
102
    
103
    def expect_close(self):
104
        self._expecting_close = True
105
    
106
    def register(self, id, op):
107
        self._id2rpc[id] = op
108
    
109
    ### Events
110
    
111
    def reply(self, raw):
112
        pass
113
    
114
    def error(self, err):
115
        from ncclient.session.session import SessionCloseError
116
        if err is SessionCloseError:
117
            logger.debug('session closed by remote endpoint, expecting_close=%s' %
118
                         self._expecting_close)
119
            if not self._expecting_close:
120
                raise err
121

  
b/ncclient/session/__init__.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
from session import SessionError, SessionCloseError
15
import logging
16
logger = logging.getLogger('ncclient.session')
17

  
18
from session import DebugListener, SessionError, SessionCloseError
16 19
from ssh import SSHSession
20
from capabilities import CAPABILITIES, Capabilities
17 21

  
18 22
__all__ = [
23
    'DebugListener'
24
    'Session'
19 25
    'SSHSession',
20 26
    'SessionError',
21 27
    'SessionCloseError',
28
    'Capabilities',
29
    'CAPABILITIES'
22 30
]
b/ncclient/session/capabilities.py
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
class Capabilities:
16
    
17
    def __init__(self, capabilities=None):
18
        self._dict = {}
19
        if isinstance(capabilities, dict):
20
            self._dict = capabilities
21
        elif isinstance(capabilities, list):
22
            for uri in capabilities:
23
                self._dict[uri] = Capabilities.guess_shorthand(uri)
24
    
25
    def __contains__(self, key):
26
        return ( key in self._dict ) or ( key in self._dict.values() )
27
    
28
    def __iter__(self):
29
        return self._dict.keys().__iter__()
30
    
31
    def __repr__(self):
32
        return repr(self._dict.keys())
33
    
34
    def add(self, uri, shorthand=None):
35
        if shorthand is None:
36
            shorthand = Capabilities.guess_shorthand(uri)
37
        self._dict[uri] = shorthand
38
    
39
    set = add
40
    
41
    def remove(self, key):
42
        if key in self._dict:
43
            del self._dict[key]
44
        else:
45
            for uri in self._dict:
46
                if self._dict[uri] == key:
47
                    del self._dict[uri]
48
                    break
49
    
50
    @staticmethod
51
    def guess_shorthand(uri):
52
        if uri.startswith('urn:ietf:params:netconf:capability:'):
53
            return (':' + uri.split(':')[5])
54

  
55
    
56
CAPABILITIES = Capabilities([
57
    'urn:ietf:params:netconf:base:1.0',
58
    'urn:ietf:params:netconf:capability:writable-running:1.0',
59
    'urn:ietf:params:netconf:capability:candidate:1.0',
60
    'urn:ietf:params:netconf:capability:confirmed-commit:1.0',
61
    'urn:ietf:params:netconf:capability:rollback-on-error:1.0',
62
    'urn:ietf:params:netconf:capability:startup:1.0',
63
    'urn:ietf:params:netconf:capability:url:1.0',
64
    'urn:ietf:params:netconf:capability:validate:1.0',
65
    'urn:ietf:params:netconf:capability:xpath:1.0',
66
    'urn:ietf:params:netconf:capability:notification:1.0',
67
    'urn:ietf:params:netconf:capability:interleave:1.0'
68
    ])
69

  
70
if __name__ == "__main__":
71
    assert(':validate' in CAPABILITIES) # test __contains__
b/ncclient/session/session.py
13 13
# limitations under the License.
14 14

  
15 15
import logging
16
from threading import Thread, Event
16
from threading import Thread, Lock, Event
17 17
from Queue import Queue
18 18

  
19 19
from capabilities import Capabilities, CAPABILITIES
20 20

  
21
logger = logging.getLogger('ncclient.session.session')
21
logger = logging.getLogger('ncclient.session')
22 22

  
23 23
class SessionError(Exception):
24 24
    
......
26 26

  
27 27
class SessionCloseError(SessionError):
28 28
    
29
    def __str__(self):
30
        return 'RECEIVED: %s | UNSENT: %s' % (self._in_buf, self._out_buf)
31
    
32 29
    def __init__(self, in_buf, out_buf=None):
33 30
        SessionError.__init__(self)
34 31
        self._in_buf, self._out_buf = in_buf, out_buf
35

  
32
        
33
    def __str__(self):
34
        msg = 'Session closed by remote endpoint.'
35
        if self._in_buf:
36
            msg += '\nIN_BUFFER: %s' % self._in_buf
37
        if self._out_buf:
38
            msg += '\nOUT_BUFFER: %s' % self._out_buf
39
        return msg
40
    
36 41
class Session(Thread):
37 42
    
38 43
    def __init__(self):
......
42 47
        self._id = None # session-id
43 48
        self._q = Queue()
44 49
        self._connected = False # to be set/cleared by subclass implementation
45
        self._listeners = set(listeners)
50
        self._listeners = set([])
46 51
        self._lock = Lock()
47 52
    
48 53
    def _post_connect(self):
......
67 72
        proceed.wait()
68 73
        # received hello message or an error happened
69 74
        self.remove_listener(listener)
70
        if self._error:
75
        if error:
71 76
            self._close()
72 77
            raise self._error
73 78
    
......
135 140
class HelloListener:
136 141
    
137 142
    def __init__(self, init_cb, error_cb):
138
        self._init_cb, self._error_cb = reply_cb, error_cb
143
        self._init_cb, self._error_cb = init_cb, error_cb
139 144
    
140 145
    def __str__(self):
141 146
        return 'HelloListener'
......
153 158
    
154 159
    def error(self, err):
155 160
        self._error_cb(err)
161

  
162

  
163
class DebugListener:
164
    
165
    def __str__(self):
166
        return 'DebugListener'
167
    
168
    def reply(self, raw):
169
        logger.debug('DebugListener:reply:%s' % raw)
170
    
171
    def error(self, err):
172
        logger.debug('DebugListener:error:%s' % err)
b/ncclient/session/ssh.py
12 12
# See the License for the specific language governing permissions and
13 13
# limitations under the License.
14 14

  
15
import logging
16 15
from cStringIO import StringIO
17 16
from os import SEEK_CUR
18 17
import socket
19 18

  
20 19
import paramiko
21 20

  
21
from . import logger
22 22
from session import Session, SessionError, SessionCloseError
23 23

  
24
logger = logging.getLogger('ncclient.ssh')
25

  
26 24
BUF_SIZE = 4096
27 25
MSG_DELIM = ']]>]]>'
28 26

  

Also available in: Unified diff