1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
12 from stat import S_ISDIR
16 from paramiko.ssh_exception import AuthenticationException
18 LOG = logging.getLogger(__name__)
21 class SSHClientContext(paramiko.SSHClient):
23 def __init__(self, ip, user, passwd, port=22):
28 super(SSHClientContext, self).__init__()
30 def sync_exec_command(self, cmd):
31 _, stdout, stderr = self.exec_command(cmd)
32 ret = stdout.channel.recv_exit_status()
33 out = stdout.read().strip()
34 err = stderr.read().strip()
36 "in %s,%s,return:%s,output:%s:error:%s" %
37 (self.host, cmd, ret, out, err))
51 self.set_missing_host_key_policy(paramiko.AutoAddPolicy())
54 def __exit__(self, exc_type, exc_val, exc_tb):
56 if exc_type == AuthenticationException:
60 class SFTPClientContext(object):
62 def __init__(self, ip, user, passwd, port=22):
69 self.t = paramiko.Transport((self.host, self.port))
70 self.t.connect(username=self.user, password=self.passwd)
71 self.sftp = paramiko.SFTPClient.from_transport(self.t)
73 def get(self, remote, local):
74 self.sftp.get(remote, local)
76 def put(self, local, remote):
77 self.sftp.put(local, remote)
79 def mkdir(self, path):
82 def rmdir(self, path):
88 def __exit__(self, exc_type, exc_val, exc_tb):
89 if exc_type == TypeError:
94 def upload_conf_file(host, user, passwd, src, dst):
95 with SFTPClientContext(host, user, passwd) as ftp:
97 LOG.info('putting file:%s to %s:%s' % (src, host, dst))
101 def upload_dir(host, user, passwd, local_dir, remote_dir):
102 assert remote_dir.startswith('/')
103 assert local_dir != '/'
104 while local_dir.endswith('/'):
105 local_dir = local_dir[:-1]
106 while remote_dir.endswith('/'):
107 remote_dir = remote_dir[:-1]
108 remote_dir = os.path.join(remote_dir, os.path.basename(local_dir))
109 ret, _, _ = run_cmd(host, user, passwd, "sudo rm -rf %s" % remote_dir)
110 if ret != 0 and ret != 1:
112 "somehow failed in rm -rf %s on host:%s,return:%s" %
113 (remote_dir, host, ret))
115 with SFTPClientContext(host, user, passwd) as sftp:
117 for root, dirs, files in os.walk(local_dir):
118 for filename in files:
119 local_file = os.path.join(root, filename)
120 remote_file = local_file.replace(local_dir, remote_dir)
122 sftp.put(local_file, remote_file)
124 sftp.mkdir(os.path.split(remote_file)[0])
125 sftp.put(local_file, remote_file)
126 LOG.info("upload %s to remote %s" % (local_file, remote_file))
128 local_path = os.path.join(root, name)
129 remote_path = local_path.replace(local_dir, remote_dir)
131 sftp.mkdir(remote_path)
132 LOG.info("mkdir path %s" % remote_path)
133 except Exception as e:
138 def isdir(path, sftp):
143 file_stat = sftp.stat(path).st_mode
144 is_dir = S_ISDIR(file_stat)
147 return exists, is_dir, file_stat
150 def download_file(host, user, passwd, remote_path, local_path):
151 assert not remote_path.endswith('/')
152 remote_file_name = os.path.basename(remote_path)
153 if local_path.endswith('/'):
154 if not os.path.exists(local_path):
155 raise Exception('path:%s not exist.' % local_path)
156 dest = os.path.join(local_path, remote_file_name)
158 if os.path.isdir(local_path):
159 dest = os.path.join(local_path, remote_file_name)
161 dir_path = os.path.dirname(local_path)
162 if not os.path.exists(dir_path):
163 raise Exception('path:%s not exist' % dir_path)
165 transport = paramiko.Transport((host, 22))
166 transport.connect(username=user, password=passwd)
167 sftp = paramiko.SFTPClient.from_transport(transport)
168 exists, is_dir, st = isdir(remote_path, sftp)
169 if exists and not is_dir:
170 sftp.get(remote_path, dest)
173 raise Exception('error:cannot find the file or file is dir')
177 def download_dir(host, user, passwd, remote_path, local_path):
178 while remote_path.endswith('/'):
179 remote_path = remote_path[:-1]
180 if local_path.endswith('/'):
181 if not os.path.exists(local_path):
182 raise Exception('path:%s not exist.' % local_path)
183 dest_path = os.path.join(local_path, os.path.basename(remote_path))
185 if os.path.isdir(local_path):
186 dest_path = os.path.join(local_path, os.path.basename(remote_path))
188 dir_name = os.path.dirname(local_path)
189 if os.path.exists(dir_name):
190 dest_path = local_path
192 raise Exception('path:%s is not exists' % dir_name)
194 "download_dir from host:%s:%s to dest:%s" %
195 (host, remote_path, dest_path))
196 transport = paramiko.Transport((host, 22))
197 transport.connect(username=user, password=passwd)
198 sftp = paramiko.SFTPClient.from_transport(transport)
199 exists, is_dir, _ = isdir(remote_path, sftp)
200 if exists and is_dir:
205 st = sftp.lstat(path).st_mode
206 relative_path = path[len(remote_path):]
207 if relative_path.startswith('/'):
208 relative_path = relative_path[1:]
209 local = os.path.join(dest_path, relative_path)
210 if os.path.exists(local):
214 file_list = sftp.listdir(path)
215 for item in file_list:
216 fullpath = os.path.join(path, item)
217 _, is_dir, st = isdir(fullpath, sftp)
221 dest = os.path.join(local, item)
222 sftp.get(fullpath, dest)
226 'path:%s:%s not exists or is not a dir' %
231 def run_cmd(host, user, passwd, cmd):
232 with SSHClientContext(host, user, passwd) as ssh:
234 ret, stdout, stderr = ssh.sync_exec_command(cmd)
235 return ret, stdout, stderr
238 class SshFileTransfer(object):
240 def __init__(self, ip, user, passwd):
241 self.ip, self.user, self.passwd = ip, user, passwd
243 def upload_dir(self, src, dst):
244 return upload_dir(self.ip, self.user, self.passwd, src, dst)
246 def download_dir(self, src, dst):
247 download_dir(self.ip, self.user, self.passwd, src, dst)
249 def upload_file(self, src, dst):
250 upload_conf_file(self.ip, self.user, self.passwd, src, dst)
252 def download_file(self, src, dst):
253 download_file(self.ip, self.user, self.passwd, src, dst)