Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / dulwich / contrib / paramiko_vendor.py @ 959

History | View | Annotate | Download (4.19 KB)

1
# paramiko_vendor.py -- paramiko implementation of the SSHVendor interface
2
# Copyright (C) 2013 Aaron O'Mullan <aaron.omullan@friendco.de>
3
#
4
# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
5
# General Public License as public by the Free Software Foundation; version 2.0
6
# or (at your option) any later version. You can redistribute it and/or
7
# modify it under the terms of either of these two licenses.
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
# You should have received a copy of the licenses; if not, see
16
# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
17
# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
18
# License, Version 2.0.
19
#
20

    
21
"""Paramiko SSH support for Dulwich.
22

23
To use this implementation as the SSH implementation in Dulwich, override
24
the dulwich.client.get_ssh_vendor attribute:
25

26
  >>> from dulwich import client as _mod_client
27
  >>> from dulwich.contrib.paramiko_vendor import ParamikoSSHVendor
28
  >>> _mod_client.get_ssh_vendor = ParamikoSSHVendor
29

30
This implementation is experimental and does not have any tests.
31
"""
32

    
33
import paramiko
34
import paramiko.client
35
import threading
36

    
37
class _ParamikoWrapper(object):
38
    STDERR_READ_N = 2048  # 2k
39

    
40
    def __init__(self, client, channel, progress_stderr=None):
41
        self.client = client
42
        self.channel = channel
43
        self.progress_stderr = progress_stderr
44
        self.should_monitor = bool(progress_stderr) or True
45
        self.monitor_thread = None
46
        self.stderr = b''
47

    
48
        # Channel must block
49
        self.channel.setblocking(True)
50

    
51
        # Start
52
        if self.should_monitor:
53
            self.monitor_thread = threading.Thread(
54
                target=self.monitor_stderr)
55
            self.monitor_thread.start()
56

    
57
    def monitor_stderr(self):
58
        while self.should_monitor:
59
            # Block and read
60
            data = self.read_stderr(self.STDERR_READ_N)
61

    
62
            # Socket closed
63
            if not data:
64
                self.should_monitor = False
65
                break
66

    
67
            # Emit data
68
            if self.progress_stderr:
69
                self.progress_stderr(data)
70

    
71
            # Append to buffer
72
            self.stderr += data
73

    
74
    def stop_monitoring(self):
75
        # Stop StdErr thread
76
        if self.should_monitor:
77
            self.should_monitor = False
78
            self.monitor_thread.join()
79

    
80
            # Get left over data
81
            data = self.channel.in_stderr_buffer.empty()
82
            self.stderr += data
83

    
84
    def can_read(self):
85
        return self.channel.recv_ready()
86

    
87
    def write(self, data):
88
        return self.channel.sendall(data)
89

    
90
    def read_stderr(self, n):
91
        return self.channel.recv_stderr(n)
92

    
93
    def read(self, n=None):
94
        data = self.channel.recv(n)
95
        data_len = len(data)
96

    
97
        # Closed socket
98
        if not data:
99
            return
100

    
101
        # Read more if needed
102
        if n and data_len < n:
103
            diff_len = n - data_len
104
            return data + self.read(diff_len)
105
        return data
106

    
107
    def close(self):
108
        self.channel.close()
109
        self.stop_monitoring()
110

    
111

    
112
class ParamikoSSHVendor(object):
113

    
114
    def __init__(self):
115
        self.ssh_kwargs = {}
116

    
117
    def run_command(self, host, command, username=None, port=None,
118
                    progress_stderr=None):
119
        if not isinstance(command, bytes):
120
            raise TypeError(command)
121
        # Paramiko needs an explicit port. None is not valid
122
        if port is None:
123
            port = 22
124

    
125
        client = paramiko.SSHClient()
126

    
127
        policy = paramiko.client.MissingHostKeyPolicy()
128
        client.set_missing_host_key_policy(policy)
129
        client.connect(host, username=username, port=port,
130
                       **self.ssh_kwargs)
131

    
132
        # Open SSH session
133
        channel = client.get_transport().open_session()
134

    
135
        # Run commands
136
        channel.exec_command(command)
137

    
138
        return _ParamikoWrapper(
139
            client, channel, progress_stderr=progress_stderr)