Revision b2d60e49

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

  
15
#_capability_map = {
16
#    "urn:liberouter:params:netconf:capability:power-control:1.0":
17
#        [":power-control", ":power-control:1.0"]
18
#}
19

  
20 15
def _abbreviate(uri):
21 16
    if uri.startswith("urn:ietf:params:netconf:"):
22 17
        splitted = uri.split(":")
23 18
        if ":capability:" in uri:
24
            return [ ":" + splitted[5], ":" + splitted[5] + ":" + splitted[6] ]
19
            name, version = splitted[5], splitted[6]
20
            return [ ":" + name, ":" + name + ":" + version ]
25 21
        elif ":base:" in uri:
26 22
            return [ ":base", ":base" + ":" + splitted[5] ]
27
    #elif uri in _capability_map:
28
    #    return _capability_map[uri]
29 23
    return []
30 24

  
31 25
def schemes(url_uri):
......
62 56
        return len(self._dict)
63 57

  
64 58
    def __iter__(self):
65
        return self._dict.keys().__iter__()
59
        return self._dict.iterkeys()
66 60

  
67 61
    def __repr__(self):
68 62
        return repr(self._dict.keys())
69 63

  
70
    def __list__(self):
71
        return self._dict.keys()
72

  
73 64
    def add(self, uri):
74 65
        "Add a capability."
75 66
        self._dict[uri] = _abbreviate(uri)
......
77 68
    def remove(self, uri):
78 69
        "Remove a capability."
79 70
        if key in self._dict:
80
            del self._dict[key]
81
    
82
    #def get_uri(self, shorthand):
83
    #    "Returns the URI that is inferred for a given shorthand."
84
    #    for uri, abbrs in self._dict.items():
85
    #        if shorthand in abbrs:
86
    #            return uri
71
            del self._dict[key]
b/ncclient/manager.py
19 19
import transport
20 20

  
21 21
import logging
22

  
22 23
logger = logging.getLogger('ncclient.manager')
23 24

  
24 25
CAPABILITIES = [
......
33 34
    "urn:ietf:params:netconf:capability:xpath:1.0",
34 35
    "urn:liberouter:params:netconf:capability:power-control:1.0"
35 36
    "urn:ietf:params:netconf:capability:interleave:1.0"
36
    #'urn:ietf:params:netconf:capability:notification:1.0', # TODO    
37 37
]
38
"""A list of URI's representing the client's capabilities. This is used during the initial
39
capability exchange. Modify this if you need to announce some capability not already included.
40
"""
38
"A list of URI's representing the client's capabilities. This is used during the initial capability exchange. Modify this if you need to announce some capability not already included."
41 39

  
42 40
OPERATIONS = {
43 41
    "get": operations.Get,
......
55 53
    "poweroff_machine": operations.PoweroffMachine,
56 54
    "reboot_machine": operations.RebootMachine
57 55
}
58
"""Dictionary of method names and corresponding `~ncclient.operations.RPC` subclasses. It is used to
59
lookup operations, e.g. "get_config" is mapped to `~ncclient.operations.GetConfig`. It is thus
60
possible to add additional operations to the `Manager` API."""
56
"""Dictionary of method names and corresponding `~ncclient.operations.RPC` subclasses. It is used to lookup operations, e.g. "get_config" is mapped to `~ncclient.operations.GetConfig`. It is thus possible to add additional operations to the `Manager` API."""
61 57

  
62 58
def connect_ssh(*args, **kwds):
63
    """Initializes a NETCONF session over SSH, and creates a connected `Manager` instance. *host*
64
    must be specified, all the other arguments are optional and depend on the kind of host key
65
    verification and user authentication you want to complete.
59
    """Initializes a NETCONF session over SSH, and creates a connected `Manager` instance. *host* must be specified, all the other arguments are optional and depend on the kind of host key verification and user authentication you want to complete.
66 60
        
67
    For the purpose of host key verification, on -NIX systems a user's :file:`~/.ssh/known_hosts`
68
    file is automatically considered. The *unknown_host_cb* argument specifies a callback that will
69
    be invoked when the server's host key cannot be verified. See
70
    :func:`~ncclient.transport.ssh.default_unknown_host_cb` for function signature.
61
    For the purpose of host key verification, on -NIX systems a user's :file:`~/.ssh/known_hosts` file is automatically considered. The *unknown_host_cb* argument specifies a callback that will be invoked when the server's host key cannot be verified. See :func:`~ncclient.transport.ssh.default_unknown_host_cb` for function signature.
71 62
    
72 63
    First, ``publickey`` authentication is attempted. If a specific *key_filename* is specified, it
73 64
    will be loaded and authentication attempted using it. If *allow_agent* is :const:`True` and an
......
76 67
    an encrypted key file is encountered, the *password* argument will be used as a decryption
77 68
    passphrase.
78 69
    
79
    If ``publickey`` authentication fails and the *password* argument has been supplied,
80
    ``password`` / ``keyboard-interactive`` SSH authentication will be attempted.
70
    If ``publickey`` authentication fails and the *password* argument has been supplied, ``password`` / ``keyboard-interactive`` SSH authentication will be attempted.
81 71
    
82 72
    :param host: hostname or address on which to connect
83 73
    :type host: `string`
......
110 100
    :raises: :exc:`~ncclient.transport.AuthenticationError`
111 101
    
112 102
    :rtype: `Manager`
113
    """    
103
    """
114 104
    session = transport.SSHSession(capabilities.Capabilities(CAPABILITIES))
115 105
    session.load_known_hosts()
116 106
    session.connect(*args, **kwds)
......
119 109
connect = connect_ssh
120 110
"Same as :func:`connect_ssh`, since SSH is the default (and currently, the only) transport."
121 111

  
112
class OpExecutor(type):
113
    def __new__(cls, name, bases, attrs):
114
        def make_wrapper(op_cls):
115
            def wrapper(self, *args, **kwds):
116
                return self.execute(op_cls, *args, **kwds)
117
            wrapper.func_doc = op_cls.request.func_doc
118
            return wrapper
119
        for op_name, op_cls in OPERATIONS.iteritems():
120
            attrs[op_name] = make_wrapper(op_cls)
121
        return super(OpExecutor, cls).__new__(cls, name, bases, attrs)
122

  
122 123
class Manager(object):
123 124

  
125
    __metaclass__ = OpExecutor
126

  
127
    RAISE_NONE = 0
128
    RAISE_ERRORS = 1
129
    RAISE_ALL = 2
130

  
124 131
    def __init__(self, session):
125 132
        self._session = session
126 133
        self._async_mode = False
127 134
        self._timeout = None
128
        self._raise_mode = 'all'
135
        self._raise_mode = self.RAISE_ALL
129 136

  
130 137
    def __enter__(self):
131 138
        return self
132 139

  
133
    def __exit__(self, *argss):
140
    def __exit__(self, *args):
134 141
        self.close_session()
135 142
        return False
136 143

  
137
    def __getattr__(self, name):
138
        op = OPERATIONS.get(name, None)
139
        if op is None:
140
            raise AttributeError
141
        else:
142
            return op(self._session,
143
                      async=self._async_mode,
144
                      timeout=self._timeout,
145
                      raise_mode=self._raise_mode).request
146
    
144
    def execute(self, cls, *args, **kwds):
145
        return cls(self._session,
146
                   async=self._async_mode,
147
                   timeout=self._timeout,
148
                   raise_mode=self._raise_mode).request(*args, **kwds)
149

  
147 150
    def locked(self, target):
148 151
        return operations.LockContext(self._session, target)
149
    
152

  
150 153
    @property
151 154
    def client_capabilities(self):
152 155
        return self._session._client_capabilities
......
167 170
        self._async_mode = mode
168 171

  
169 172
    def set_raise_mode(self, mode):
170
        assert(choice in ("all", "errors", "none"))
173
        assert(choice in (self.RAISE_NONE, self.RAISE_ERRORS, self.RAISE_ALL))
171 174
        self._raise_mode = mode
172 175

  
173 176
    async_mode = property(fget=lambda self: self._async_mode, fset=set_async_mode)
b/ncclient/operations/edit.py
27 27

  
28 28
    "*<edit-config>* RPC"
29 29
    
30
    def request(self, target, config, default_operation=None, test_option=None,
31
                error_option=None):
30
    def request(self, target, config, default_operation=None, test_option=None, error_option=None):
32 31
        node = new_ele("edit-config")
33 32
        node.append(util.datastore_or_url("target", target, self._assert))
34 33
        if error_option is not None:
......
95 94
            self._assert(":confirmed-commit")
96 95
            sub_ele(node, "confirmed")
97 96
            if timeout is not None:
98
                # TODO check if timeout is a valid integer?
99 97
                sub_ele(node, "confirm-timeout").text = timeout
100 98
        return self._request(node)
101 99

  
b/ncclient/operations/flowmon.py
26 26

  
27 27
    DEPENDS = ["urn:liberouter:params:netconf:capability:power-control:1.0"]
28 28
    
29
    def request(self, target):
29
    def request(self):
30 30
        return self._request(new_ele(qualify("poweroff-machine", PC_URN)))
31 31

  
32 32
class RebootMachine(RPC):
......
35 35

  
36 36
    DEPENDS = ["urn:liberouter:params:netconf:capability:power-control:1.0"]
37 37

  
38
    def request(self, target):
38
    def request(self):
39 39
        return self._request(new_ele(qualify("reboot-machine", PC_URN)))
b/ncclient/operations/lock.py
28 28
    
29 29
    def request(self, target):
30 30
        node = new_ele("lock")
31
        sub_ele(sub_ele(node, "target"), "running")
31
        sub_ele(sub_ele(node, "target"), target)
32 32
        return self._request(node)
33 33

  
34 34

  
......
38 38
    
39 39
    def request(self, target):
40 40
        node = new_ele("unlock")
41
        sub_ele(sub_ele(node, "target"), "running")
41
        sub_ele(sub_ele(node, "target"), target)
42 42
        return self._request(node)
43 43

  
44 44

  
b/ncclient/operations/rpc.py
54 54
    def to_dict(self):
55 55
        return dict([ (attr[1:], getattr(self, attr)) for attr in RPCError.tag_to_attr.values() ])
56 56
    
57
    "*rpc-error* element as returned."
58 57
    @property
59 58
    def xml(self):
59
        "*rpc-error* element as returned."
60 60
        return self._raw
61 61
    
62 62
    @property
......
123 123
            if error is not None:
124 124
                for err in root.getiterator(error.tag):
125 125
                    # Process a particular <rpc-error>
126
                    self._errors.append(ERROR_CLS(err))
126
                    self._errors.append(self.ERROR_CLS(err))
127
        self._parsing_hook(root)
127 128
        self._parsed = True
129

  
130
    def _parsing_hook(self, root):
131
        pass
128 132
    
129 133
    @property
130 134
    def xml(self):
......
264 268
            logger.debug('Async request, returning %r', self)
265 269
            return self
266 270
        else:
267
            logger.debug('Sync request, will wait for timeout=%r' %
268
                         self._timeout)
271
            logger.debug('Sync request, will wait for timeout=%r' % self._timeout)
269 272
            self._event.wait(self._timeout)
270 273
            if self._event.isSet():
271 274
                if self._error:
......
283 286
            else:
284 287
                raise TimeoutExpiredError
285 288

  
286
    def request(self, *args, **kwds):
289
    def request(self):
287 290
        """Subclasses must implement this method. Typically only the request needs to be built as an
288 291
        `~xml.etree.ElementTree.Element` and everything else can be handed off to
289 292
        :meth:`_request`."""
......
294 297
        server, before making a request that requires it. A :exc:`MissingCapabilityError` will be
295 298
        raised if the capability is not available."""
296 299
        if capability not in self._session.server_capabilities:
297
            raise MissingCapabilityError('Server does not support [%s]' %
298
                                         capability)
300
            raise MissingCapabilityError('Server does not support [%s]' % capability)
299 301
    
300 302
    def deliver_reply(self, raw):
301 303
        # internal use
b/ncclient/transport/errors.py
36 36
class SSHUnknownHostError(SSHError):
37 37

  
38 38
    def __init__(self, host, fingerprint):
39
        SSHError.__init__(self, 'Unknown host key [%s] for [%s]'
40
                          % (fingerprint, host))
39
        SSHError.__init__(self, 'Unknown host key [%s] for [%s]' % (fingerprint, host))
41 40
        self.host = host
42 41
        self.fingerprint = fingerprint
b/ncclient/xml_.py
71 71
    return xml if xml.startswith('<?xml') else '<?xml version="1.0" encoding="%s"?>%s' % (encoding, xml)
72 72

  
73 73
def to_ele(x):
74
    """Convert XML to `~xml.etree.ElementTree.Element`. If passed an
75
    `~xml.etree.ElementTree.Element` simply returns that.
74
    """Convert XML to `~xml.etree.ElementTree.Element`. If passed an `~xml.etree.ElementTree.Element` simply returns that.
76 75
    
77 76
    :arg x: the XML document or element
78 77
    :type x: `string` or `~xml.etree.ElementTree.Element`

Also available in: Unified diff