root / src / ssh.py @ fd40449b
History | View | Annotate | Download (3.7 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 |
import logging |
16 |
import paramiko |
17 |
|
18 |
from select import select as select |
19 |
|
20 |
from session import Session, SessionError |
21 |
|
22 |
logger = logging.getLogger('ncclient.ssh')
|
23 |
|
24 |
class SSHError(SessionError): pass |
25 |
|
26 |
class SSHSession(Session): |
27 |
|
28 |
BUF_SIZE = 4096
|
29 |
|
30 |
MSG_DELIM = ']]>>]]>'
|
31 |
|
32 |
def __init__(self, capabilities, reply_cb=None, |
33 |
load_known_hosts=True,
|
34 |
missing_host_key_policy=paramiko.RejectPolicy): |
35 |
Session.__init__(self, capabilities)
|
36 |
self._inBuf = '' |
37 |
self._outBuf = '' |
38 |
self._client = SSHClient()
|
39 |
if load_known_hosts:
|
40 |
self._client.load_system_host_keys()
|
41 |
self._client.set_missing_host_key_policy(host_key_policy)
|
42 |
|
43 |
def _greet_cb(self, reply): |
44 |
self._init(reply)
|
45 |
self._cb = self._real_cb |
46 |
|
47 |
def _greet(self): |
48 |
self._real_cb = self._cb |
49 |
self._cb = self._greet_cb |
50 |
self._q.add(self._make_hello()) |
51 |
|
52 |
def load_host_keys(self, filename): |
53 |
self._client.load_host_keys(filename)
|
54 |
|
55 |
def set_missing_host_key_policy(self, policy): |
56 |
self._client.set_missing_host_key_policy(policy)
|
57 |
|
58 |
def set_reply_callback(self, cb): |
59 |
self._cb = cb
|
60 |
|
61 |
def connect(self, hostname, port=830, username=None, password=None, |
62 |
key_filename=None, timeout=None, allow_agent=True, |
63 |
look_for_keys=True):
|
64 |
self._client.connect(hostname, port=port, username=username,
|
65 |
password=password, key_filename=key_filename, |
66 |
timeout=timeout, allow_agent=allow_agent, |
67 |
look_for_keys=look_for_keys) |
68 |
transport = self._client.get_transport()
|
69 |
self._channel = transport.open_session()
|
70 |
self._channel.invoke_subsystem('netconf') |
71 |
self._greet()
|
72 |
Session.connect(self) # starts thread |
73 |
|
74 |
def run(self): |
75 |
sock = self._channel
|
76 |
sock.setblocking(0)
|
77 |
q = self._q
|
78 |
while True: |
79 |
(r, w, e) = select([sock], [sock], [], 60)
|
80 |
if w:
|
81 |
if not q.empty(): |
82 |
self._outBuffer += ( q.get() + MSG_DELIM )
|
83 |
if self._outBuffer: |
84 |
n = sock.send(self._outBuffer)
|
85 |
self._outBuffer = self._outBuffer[n:] |
86 |
if r:
|
87 |
data = sock.recv(BUF_SIZE) |
88 |
if data:
|
89 |
self._inBuf += data
|
90 |
# probably not very efficient:
|
91 |
pos = self._inBuf.find(DELIM)
|
92 |
if pos != -1: |
93 |
msg = self._inBuf[:pos]
|
94 |
self._inBuf = self._inBuf[(pos + len(DELIM)):] |
95 |
self._reply_cb(msg)
|
96 |
else:
|
97 |
connected = False
|
98 |
# it's not an error if we asked for it
|
99 |
# via CloseSession -- need a way to know this
|
100 |
raise SessionError
|
101 |
|
102 |
class CallbackPolicy(paramiko.MissingHostKeyPolicy): |
103 |
|
104 |
def __init__(self, cb): |
105 |
self._cb = cb
|
106 |
|
107 |
def missing_host_key(self, client, hostname, key): |
108 |
if not self._cb(hostname, key): |
109 |
raise SSHError
|