8 from stat import S_ISDIR
12 from paramiko.ssh_exception import AuthenticationException
14 LOG = logging.getLogger(__name__)
17 class SSHClientContext(paramiko.SSHClient):
18 def __init__(self, ip, user, passwd, port=22):
23 super(SSHClientContext, self).__init__()
25 def sync_exec_command(self, cmd):
26 _, stdout, stderr = self.exec_command(cmd)
27 ret = stdout.channel.recv_exit_status()
28 out = stdout.read().strip()
29 err = stderr.read().strip()
30 LOG.info("in %s,%s,return:%s,output:%s:error:%s" % (self.host, cmd, ret, out, err))
34 super(SSHClientContext, self).connect(self.host, self.port, self.user, self.passwd, timeout=10)
37 self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
40 def __exit__(self, exc_type, exc_val, exc_tb):
42 if exc_type == AuthenticationException:
46 class SFTPClientContext(object):
47 def __init__(self, ip, user, passwd, port=22):
54 self.t = paramiko.Transport((self.host, self.port))
55 self.t.connect(username=self.user, password=self.passwd)
56 self.sftp = paramiko.SFTPClient.from_transport(self.t)
58 def get(self, remote, local):
59 self.sftp.get(remote, local)
61 def put(self, local, remote):
62 self.sftp.put(local, remote)
64 def mkdir(self, path):
67 def rmdir(self, path):
73 def __exit__(self, exc_type, exc_val, exc_tb):
74 if exc_type == TypeError:
79 def upload_conf_file(host, user, passwd, src, dst):
80 with SFTPClientContext(host, user, passwd) as ftp:
82 LOG.info('putting file:%s to %s:%s' % (src, host, dst))
86 def upload_dir(host, user, passwd, local_dir, remote_dir):
87 assert remote_dir.startswith('/')
88 assert local_dir != '/'
89 while local_dir.endswith('/'):
90 local_dir = local_dir[:-1]
91 while remote_dir.endswith('/'):
92 remote_dir = remote_dir[:-1]
93 remote_dir = os.path.join(remote_dir, os.path.basename(local_dir))
94 ret, _, _ = run_cmd(host, user, passwd, "sudo rm -rf %s" % remote_dir)
95 if ret != 0 and ret != 1:
96 LOG.error("somehow failed in rm -rf %s on host:%s,return:%s" % (remote_dir, host, ret))
98 with SFTPClientContext(host, user, passwd) as sftp:
100 for root, dirs, files in os.walk(local_dir):
101 for filename in files:
102 local_file = os.path.join(root, filename)
103 remote_file = local_file.replace(local_dir, remote_dir)
105 sftp.put(local_file, remote_file)
107 sftp.mkdir(os.path.split(remote_file)[0])
108 sftp.put(local_file, remote_file)
109 LOG.info("upload %s to remote %s" % (local_file, remote_file))
111 local_path = os.path.join(root, name)
112 remote_path = local_path.replace(local_dir, remote_dir)
114 sftp.mkdir(remote_path)
115 LOG.info("mkdir path %s" % remote_path)
121 def isdir(path, sftp):
126 file_stat = sftp.stat(path).st_mode
127 is_dir = S_ISDIR(file_stat)
130 return exists, is_dir, file_stat
133 def download_file(host, user, passwd, remote_path, local_path):
134 assert not remote_path.endswith('/')
135 remote_file_name = os.path.basename(remote_path)
136 if local_path.endswith('/'):
137 if not os.path.exists(local_path):
138 raise Exception('path:%s not exist.' % local_path)
139 dest = os.path.join(local_path, remote_file_name)
141 if os.path.isdir(local_path):
142 dest = os.path.join(local_path, remote_file_name)
144 dir_path = os.path.dirname(local_path)
145 if not os.path.exists(dir_path):
146 raise Exception('path:%s not exist' % dir_path)
148 transport = paramiko.Transport((host, 22))
149 transport.connect(username=user, password=passwd)
150 sftp = paramiko.SFTPClient.from_transport(transport)
151 exists, is_dir, st = isdir(remote_path, sftp)
152 if exists and not is_dir:
153 sftp.get(remote_path, dest)
156 raise Exception('error:cannot find the file or file is dir')
160 def download_dir(host, user, passwd, remote_path, local_path):
161 while remote_path.endswith('/'):
162 remote_path = remote_path[:-1]
163 if local_path.endswith('/'):
164 if not os.path.exists(local_path):
165 raise Exception('path:%s not exist.' % local_path)
166 dest_path = os.path.join(local_path, os.path.basename(remote_path))
168 if os.path.isdir(local_path):
169 dest_path = os.path.join(local_path, os.path.basename(remote_path))
171 dir_name = os.path.dirname(local_path)
172 if os.path.exists(dir_name):
173 dest_path = local_path
175 raise Exception('path:%s is not exists' % dir_name)
176 LOG.info("download_dir from host:%s:%s to dest:%s" % (host, remote_path, dest_path))
177 transport = paramiko.Transport((host, 22))
178 transport.connect(username=user, password=passwd)
179 sftp = paramiko.SFTPClient.from_transport(transport)
180 exists, is_dir, _ = isdir(remote_path, sftp)
181 if exists and is_dir:
186 st = sftp.lstat(path).st_mode
187 relative_path = path[len(remote_path):]
188 if relative_path.startswith('/'): relative_path = relative_path[1:]
189 local = os.path.join(dest_path, relative_path)
190 if os.path.exists(local):
194 file_list = sftp.listdir(path)
195 for item in file_list:
196 fullpath = os.path.join(path, item)
197 _, is_dir, st = isdir(fullpath, sftp)
201 dest = os.path.join(local, item)
202 sftp.get(fullpath, dest)
205 raise Exception('path:%s:%s not exists or is not a dir' % (host, remote_path))
209 def run_cmd(host, user, passwd, cmd):
210 with SSHClientContext(host, user, passwd) as ssh:
212 ret, stdout, stderr = ssh.sync_exec_command(cmd)
213 return ret, stdout, stderr
216 class SshFileTransfer(object):
217 def __init__(self, ip, user, passwd):
218 self.ip, self.user, self.passwd = ip, user, passwd
220 def upload_dir(self, src, dst):
221 return upload_dir(self.ip, self.user, self.passwd, src, dst)
223 def download_dir(self, src, dst):
224 download_dir(self.ip, self.user, self.passwd, src, dst)
226 def upload_file(self, src, dst):
227 upload_conf_file(self.ip, self.user, self.passwd, src, dst)
229 def download_file(self, src, dst):
230 download_file(self.ip, self.user, self.passwd, src, dst)