fixes
[ncclient] / ncclient / manager.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 "Thin layer of abstraction around NCClient"
16
17 import capabilities
18 import operations
19 import transport
20
21 import logging
22 logger = logging.getLogger('ncclient.manager')
23
24 def connect_ssh(*args, **kwds):
25     """Connect to NETCONF server over SSH. See :meth:`SSHSession.connect()
26     <ncclient.transport.SSHSession.connect>` for function signature."""
27     session = transport.SSHSession(capabilities.CAPABILITIES)
28     session.load_known_hosts()
29     session.connect(*args, **kwds)
30     return Manager(session)
31
32 #: Same as :meth:`connect_ssh`
33 connect = connect_ssh
34
35 #: Raise all :class:`~ncclient.operations.rpc.RPCError`
36 RAISE_ALL = 0
37 #: Only raise when *error-severity* is "error" i.e. no warnings
38 RAISE_ERR = 1
39 #: Don't raise any
40 RAISE_NONE = 2
41
42 class Manager:
43
44     """API for NETCONF operations. Currently only supports making synchronous
45     RPC requests.
46
47     It is also a context manager, so a :class:`Manager` instance can be used
48     with the *with* statement. The session is closed when the context ends. """
49
50     def __init__(self, session):
51         self._session = session
52         self._raise = RAISE_ALL
53
54     def set_rpc_error_action(self, action):
55         """Specify the action to take when an *<rpc-error>* element is encountered.
56
57         :arg action: one of :attr:`RAISE_ALL`, :attr:`RAISE_ERR`, :attr:`RAISE_NONE`
58         """
59         self._raise = action
60
61     def __enter__(self):
62         return self
63
64     def __exit__(self, *args):
65         self.close()
66         return False
67
68     def do(self, op, *args, **kwds):
69         op = operations.OPERATIONS[op](self._session)
70         reply = op.request(*args, **kwds)
71         if not reply.ok:
72             if self._raise == RAISE_ALL:
73                 raise reply.error
74             elif self._raise == RAISE_ERROR:
75                 for error in reply.errors:
76                     if error.severity == 'error':
77                         raise error
78         return reply
79
80     #: :see: :meth:`Get.request() <ncclient.operations.Get.request>`
81     get = lambda self, *args, **kwds: self.do('get', *args, **kwds)
82
83     #: :see: :meth:`GetConfig.request() <ncclient.operations.GetConfig.request>`
84     get_config = lambda self, *args, **kwds: self.do('get-config', *args, **kwds)
85
86     #: :see: :meth:`EditConfig.request() <ncclient.operations.EditConfig.request>`
87     edit_config = lambda self, *args, **kwds: self.do('edit-config', *args, **kwds)
88
89     #: :see: :meth:`CopyConfig.request() <ncclient.operations.CopyConfig.request>`
90     copy_config = lambda self, *args, **kwds: self.do('copy-config', *args, **kwds)
91
92     #: :see: :meth:`GetConfig.request() <ncclient.operations.Validate.request>`
93     validate = lambda self, *args, **kwds: self.do('validate', *args, **kwds)
94
95     #: :see: :meth:`Commit.request() <ncclient.operations.Commit.request>`
96     commit = lambda self, *args, **kwds: self.do('commit', *args, **kwds)
97
98     #: :see: :meth:`DiscardChanges.request() <ncclient.operations.DiscardChanges.request>`
99     discard_changes = lambda self, *args, **kwds: self.do('discard-changes', *args, **kwds)
100
101     #: :see: :meth:`DeleteConfig.request() <ncclient.operations.DeleteConfig.request>`
102     delete_config = lambda self, *args, **kwds: self.do('delete-config', *args, **kwds)
103
104     #: :see: :meth:`Lock.request() <ncclient.operations.Lock.request>`
105     lock = lambda self, *args, **kwds: self.do('lock', *args, **kwds)
106
107     #: :see: :meth:`DiscardChanges.request() <ncclient.operations.Unlock.request>`
108     unlock = lambda self, *args, **kwds: self.do('unlock', *args, **kwds)
109
110     #: :see: :meth:`CloseSession.request() <ncclient.operations.CloseSession.request>`
111     close_session = lambda self, *args, **kwds: self.do('close-session', *args, **kwds)
112
113     #: :see: :meth:`KillSession.request() <ncclient.operations.KillSession.request>`
114     kill_session = lambda self, *args, **kwds: self.do('kill-session', *args, **kwds)
115
116     def locked(self, target):
117         """Returns a context manager for the *with* statement.
118
119         :arg target: name of the datastore to lock
120         :type target: `string`
121         :rtype: :class:`~ncclient.operations.LockContext`
122         """
123         return operations.LockContext(self._session, target)
124
125     def close(self):
126         """Closes the NETCONF session. First does *<close-session>* RPC."""
127         try: # try doing it clean
128             self.close_session()
129         except Exception as e:
130             logger.debug('error doing <close-session> -- %r' % e)
131         if self._session.connected: # if that didn't work...
132             self._session.close()
133
134     @property
135     def session(self, session):
136         ":class:`~ncclient.transport.Session` instance"
137         return self._session
138
139     @property
140     def client_capabilities(self):
141         ":class:`~ncclient.capabilities.Capabilities` object for client"
142         return self._session._client_capabilities
143
144     @property
145     def server_capabilities(self):
146         ":class:`~ncclient.capabilities.Capabilities` object for server"
147         return self._session._server_capabilities
148
149     @property
150     def session_id(self):
151         "*<session-id>* as assigned by NETCONF server"
152         return self._session.id
153
154     @property
155     def connected(self):
156         "Whether currently connected to NETCONF server"
157         return self._session.connected