Package entropy :: Package transceivers :: Package uri_handlers :: Package plugins :: Package interfaces :: Module ssh_plugin

Source Code for Module entropy.transceivers.uri_handlers.plugins.interfaces.ssh_plugin

  1  # -*- coding: utf-8 -*- 
  2  """ 
  3   
  4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
  5      @contact: lxnay@sabayonlinux.org 
  6      @copyright: Fabio Erculiani 
  7      @license: GPL-2 
  8   
  9      B{EntropyTransceiver SSH URI Handler module}. 
 10   
 11  """ 
 12  import os 
 13  import time 
 14  import tempfile 
 15   
 16  from entropy.output import brown, darkgreen 
 17  from entropy.i18n import _ 
 18  from entropy.exceptions import ConnectionError 
 19  from entropy.transceivers.uri_handlers.skel import EntropyUriHandler 
20 21 -class EntropySshUriHandler(EntropyUriHandler):
22 23 PLUGIN_API_VERSION = 0 24 25 """ 26 EntropyUriHandler based SSH (with pubkey) transceiver plugin. 27 """ 28 29 _DEFAULT_TIMEOUT = 60 30 _DEFAULT_PORT = 22 31 _TXC_CMD = "/usr/bin/scp" 32 _SSH_CMD = "/usr/bin/ssh" 33 34 @staticmethod
35 - def approve_uri(uri):
36 if uri.startswith("ssh://"): 37 return True 38 return False
39 40 @staticmethod
41 - def get_uri_name(uri):
42 myuri = uri.split("/")[2:][0].split(":")[0] 43 myuri = myuri.split("@")[-1] 44 return myuri
45 46 @staticmethod
47 - def hide_sensible_data(uri):
48 return uri
49
50 - def __init__(self, uri):
51 EntropyUriHandler.__init__(self, uri) 52 53 import socket, subprocess, pty 54 self._socket, self._subprocess = socket, subprocess 55 self._pty = pty 56 self.__host = EntropySshUriHandler.get_uri_name(self._uri) 57 self.__user, self.__port, self.__dir = self.__extract_scp_data( 58 self._uri) 59 60 # as documentation suggests 61 # test out connection first 62 self.__test_connection()
63
64 - def __enter__(self):
65 pass
66
67 - def __exit__(self, exc_type, exc_value, traceback):
68 self.close()
69
70 - def __test_connection(self):
71 tries = 5 72 while tries: 73 tries -= 1 74 try: 75 sock = self._socket.create_connection( 76 (self.__host, self.__port), 5) 77 sock.close() 78 return 79 except self._socket.error: 80 time.sleep(1) 81 continue 82 83 raise ConnectionError("cannot connect to %s on port %s" % ( 84 self.__host, self.__port,))
85
86 - def __extract_scp_data(self, uri):
87 88 no_ssh_split = uri.split("ssh://")[-1] 89 user = '' 90 if "@" in no_ssh_split: 91 user = no_ssh_split.split("@")[0] 92 93 port = uri.split(":")[-1] 94 try: 95 port = int(port) 96 except ValueError: 97 port = EntropySshUriHandler._DEFAULT_PORT 98 99 sdir = '~/' 100 proposed_sdir = no_ssh_split.split(":", 1)[-1].split(":")[0] 101 if proposed_sdir: 102 sdir = proposed_sdir 103 104 return user, port, sdir
105
106 - def _parse_progress_line(self, line):
107 108 line_data = line.strip().split() 109 if len(line_data) < 5: 110 # mmh... not possible to properly parse data 111 self.updateProgress(line.strip(), back = True) 112 return 113 114 percent = line_data[1] 115 tx_speed = line_data[3] 116 tx_size = line_data[2] 117 eta = line_data[4] 118 119 # create text 120 mytxt = _("Transfer status") 121 current_txt = brown(" <-> %s: " % (mytxt,)) + \ 122 darkgreen(tx_size) + " " + \ 123 brown("[") + str(percent) + brown("]") + \ 124 " " + eta + " " + tx_speed 125 126 self.updateProgress(current_txt, back = True)
127
128 - def _update_progress(self, std_r):
129 read_buf = "" 130 try: 131 char = std_r.read(1) 132 while char: 133 if (char == "\r") and read_buf: 134 self._parse_progress_line(read_buf) 135 read_buf = "" 136 elif (char != "\r"): 137 read_buf += char 138 char = std_r.read(1) 139 except IOError: 140 return
141
142 - def _fork_cmd(self, args):
143 144 pid, fd = self._pty.fork() 145 146 if pid == 0: 147 proc = self._subprocess.Popen(args) 148 os._exit(proc.wait()) 149 elif pid == -1: 150 raise ConnectionError("cannot forkpty()") 151 else: 152 dead = False 153 return_code = 1 154 std_r = os.fdopen(fd, "r") 155 while not dead: 156 157 try: 158 dead, return_code = os.waitpid(pid, os.WNOHANG) 159 except OSError as e: 160 if e.errno != 10: 161 raise 162 dead = True 163 164 time.sleep(0.5) 165 self._update_progress(std_r) 166 std_r.close() 167 168 return return_code
169
170 - def _exec_cmd(self, args):
171 172 fd, tmp_path = tempfile.mkstemp() 173 fd_err, tmp_path_err = tempfile.mkstemp() 174 os.close(fd) 175 os.close(fd_err) 176 177 with open(tmp_path, "wb") as std_f: 178 with open(tmp_path_err, "wb") as std_f_err: 179 proc = self._subprocess.Popen(args, stdout = std_f, 180 stderr = std_f_err) 181 exec_rc = proc.wait() 182 183 std_f = open(tmp_path, "rb") 184 output = std_f.read() 185 std_f.close() 186 std_f = open(tmp_path_err, "rb") 187 error = std_f.read() 188 std_f.close() 189 190 os.remove(tmp_path) 191 os.remove(tmp_path_err) 192 return exec_rc, output, error
193
194 - def _setup_common_args(self, remote_path):
195 args = [] 196 if self._speed_limit: 197 args += ["-l", str(self._speed_limit*8)] # scp wants kbits/sec 198 remote_ptr = os.path.join(self.__dir, remote_path) 199 remote_str = "" 200 if self.__user: 201 remote_str += self.__user + "@" 202 remote_str += self.__host + ":" + remote_ptr 203 204 return args, remote_str
205
206 - def download(self, remote_path, save_path):
207 args = [EntropySshUriHandler._TXC_CMD] 208 c_args, remote_str = self._setup_common_args(remote_path) 209 args.extend(c_args) 210 args += ["-B", "-P", str(self.__port), remote_str, save_path] 211 return self._fork_cmd(args) == 0
212
213 - def upload(self, load_path, remote_path):
214 args = [EntropySshUriHandler._TXC_CMD] 215 c_args, remote_str = self._setup_common_args(remote_path) 216 args.extend(c_args) 217 args += ["-B", "-P", str(self.__port), load_path, remote_str] 218 return self._fork_cmd(args) == 0
219
220 - def _setup_fs_args(self):
221 args = [EntropySshUriHandler._SSH_CMD] 222 remote_str = "" 223 if self.__user: 224 remote_str += self.__user + "@" 225 remote_str += self.__host 226 return args, remote_str
227
228 - def rename(self, remote_path_old, remote_path_new):
229 args, remote_str = self._setup_fs_args() 230 remote_ptr_old = os.path.join(self.__dir, remote_path_old) 231 remote_ptr_new = os.path.join(self.__dir, remote_path_new) 232 args += [remote_str, "mv", remote_ptr_old, remote_ptr_new] 233 return self._exec_cmd(args)[0] == 0
234
235 - def delete(self, remote_path):
236 args, remote_str = self._setup_fs_args() 237 remote_ptr = os.path.join(self.__dir, remote_path) 238 args += [remote_str, "rm", remote_ptr] 239 return self._exec_cmd(args)[0] == 0
240
241 - def get_md5(self, remote_path):
242 args, remote_str = self._setup_fs_args() 243 remote_ptr = os.path.join(self.__dir, remote_path) 244 args += [remote_str, "md5sum", remote_ptr] 245 exec_rc, output, error = self._exec_cmd(args) 246 if exec_rc: 247 return None 248 return output.strip().split()[0]
249
250 - def list_content(self, remote_path):
251 args, remote_str = self._setup_fs_args() 252 remote_ptr = os.path.join(self.__dir, remote_path) 253 args += [remote_str, "ls", "-1", remote_ptr] 254 exec_rc, output, error = self._exec_cmd(args) 255 if exec_rc: 256 return [] 257 return [x for x in output.split("\n") if x]
258
259 - def list_content_metadata(self, remote_path):
260 args, remote_str = self._setup_fs_args() 261 remote_ptr = os.path.join(self.__dir, remote_path) 262 args += [remote_str, "ls", "-1lA", remote_ptr] 263 exec_rc, output, error = self._exec_cmd(args) 264 if exec_rc: 265 return [] 266 267 data = [] 268 for item in output.split("\n"): 269 item = item.strip().split() 270 if len(item) < 5: 271 continue 272 perms, owner, group, size, name = item[0], item[2], item[3], \ 273 item[4], item[-1] 274 data.append((name, size, owner, group, perms,)) 275 return data
276
277 - def is_dir(self, remote_path):
278 args, remote_str = self._setup_fs_args() 279 remote_ptr = os.path.join(self.__dir, remote_path) 280 args += [remote_str, "test", "-d", remote_ptr] 281 exec_rc, output, error = self._exec_cmd(args) 282 return exec_rc == 0
283
284 - def is_file(self, remote_path):
285 args, remote_str = self._setup_fs_args() 286 remote_ptr = os.path.join(self.__dir, remote_path) 287 args += [remote_str, "test", "-f", remote_ptr] 288 exec_rc, output, error = self._exec_cmd(args) 289 return exec_rc == 0
290
291 - def is_path_available(self, remote_path):
292 args, remote_str = self._setup_fs_args() 293 remote_ptr = os.path.join(self.__dir, remote_path) 294 args += [remote_str, "stat", remote_ptr] 295 exec_rc, output, error = self._exec_cmd(args) 296 return exec_rc == 0
297
298 - def makedirs(self, remote_path):
299 args, remote_str = self._setup_fs_args() 300 remote_ptr = os.path.join(self.__dir, remote_path) 301 args += [remote_str, "mkdir", "-p", remote_ptr] 302 exec_rc, output, error = self._exec_cmd(args) 303 return exec_rc == 0
304
305 - def keep_alive(self):
306 return
307
308 - def close(self):
309 return
310