Robot Framework SSH Library
javaclient.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 try:
17  from com.trilead.ssh2 import (Connection, SCPClient as JavaSCPClient,
18  SFTPException, SFTPv3Client,
19  SFTPv3DirectoryEntry, StreamGobbler)
20 except ImportError:
21  raise ImportError(
22  'Importing Trilead SSH library failed. '
23  'Make sure you have the Trilead JAR distribution in your CLASSPATH.'
24  )
25 import jarray
26 import os
27 from java.io import (BufferedReader, File, FileOutputStream, InputStreamReader,
28  IOException)
29 
30 from .abstractclient import (AbstractShell, AbstractSSHClient,
31  AbstractSFTPClient, AbstractCommand,
32  SSHClientException, SFTPFileInfo)
33 try:
34  from robot.api import logger
35 except ImportError:
36  logger = None
37 
38 
40  pass
41 
42 
43 def _wait_until_timeout(_shell, timeout):
44  timeout_condition = 1
45  rc = 32
46  condition = _shell.waitForCondition(rc , int(timeout) * 1000)
47 
48  if condition & timeout_condition != 0:
49  raise SSHClientException("Timed out in %s seconds" % int(timeout))
50 
52 
53  def _get_client(self):
54  client = Connection(self.configconfig.host, self.configconfig.port)
55  timeout = int(float(self.configconfig.timeout)*1000)
56  client.connect(None, timeout, timeout)
57  return client
58 
59  @staticmethod
60  def enable_logging(logfile):
61  return False
62 
63  def _login(self, username, password, allow_agent='ignored', look_for_keys='ignored',
64  proxy_cmd=None, jumphost_alias_or_index=None, read_config=False, keep_alive_interval=None):
65  if allow_agent or look_for_keys or keep_alive_interval:
66  raise JavaSSHClientException("Arguments 'allow_agent', 'look_for_keys', "
67  "`jumphost_index_or_alias` and `keep_alive_interval`"
68  " do not work with Jython.")
69 
70  auth = self.clientclient.authenticateWithPassword(username, password) if password \
71  else self.clientclient.authenticateWithNone(username)
72  if not auth:
73  raise SSHClientException
74 
75  def _login_with_public_key(self, username, key_file, password,
76  allow_agent='ignored', look_for_keys='ignored',
77  proxy_cmd=None, jumphost_alias_or_index=None,
78  read_config=False, keep_alive_interval=None):
79  if allow_agent or look_for_keys or keep_alive_interval:
80  raise JavaSSHClientException("Arguments 'allow_agent', 'look_for_keys', "
81  "`jumphost_index_or_alias` and `keep_alive_interval`"
82  " do not work with Jython.")
83  try:
84  success = self.clientclient.authenticateWithPublicKey(username,
85  File(key_file),
86  password)
87  if not success:
88  raise SSHClientException
89  except IOError:
90  # IOError is raised also when the keyfile is invalid
91  raise SSHClientException
92 
93  def _start_command(self, command, sudo=False, sudo_password=None, invoke_subsystem=False, forward_agent=False):
94  new_shell = self.clientclient.openSession()
95  if sudo:
96  new_shell.requestDumbPTY()
97  cmd = RemoteCommand(command, self.configconfig.encoding)
98  cmd.run_in(new_shell, sudo, sudo_password, invoke_subsystem)
99  return cmd
100 
102  return SFTPClient(self.clientclient, self.configconfig.encoding)
103 
105  return SCPTransferClient(self.clientclient, self.configconfig.encoding)
106 
108  return SCPClient(self.clientclient)
109 
110  def _create_shell(self):
111  return Shell(self.clientclient, self.configconfig.term_type,
112  self.configconfig.width, self.configconfig.height)
113 
114  def create_local_ssh_tunnel(self, local_port, remote_host, remote_port, *args):
115  self.clientclient.createLocalPortForwarder(int(local_port), remote_host, int(remote_port))
116  logger.info("Now forwarding port %s to %s:%s ..." % (local_port, remote_host, remote_port))
117 
118 
120 
121  def __init__(self, client, term_type, term_width, term_height):
122  shell = client.openSession()
123  shell.requestPTY(term_type, term_width, term_height, 0, 0, None)
124  shell.startShell()
125  self.shellshell = shell
126  self._stdout_stdout = shell.getStdout()
127  self._stdin_stdin = shell.getStdin()
128 
129  def read(self):
130  if self._output_available_output_available():
131  read_bytes = jarray.zeros(self._output_available_output_available(), 'b')
132  self._stdout_stdout.read(read_bytes)
133  return ''.join(chr(b & 0xFF) for b in read_bytes)
134  return ''
135 
136  def read_byte(self):
137  if self._output_available_output_available():
138  return chr(self._stdout_stdout.read())
139  return ''
140 
141  @staticmethod
142  def resize(width, height):
143  logger.warn('Setting width or height is not supported with Jython.')
144 
145  def _output_available(self):
146  return self._stdout_stdout.available()
147 
148  def write(self, text):
149  self._stdin_stdin.write(text)
150  self._stdin_stdin.flush()
151 
152 
154 
155  def __init__(self, ssh_client, encoding):
156  self._client_client = SFTPv3Client(ssh_client)
157  self._client_client.setCharset(encoding)
158  super(SFTPClient, self).__init__(encoding)
159 
160  def _list(self, path):
161  for item in self._client_client.ls(path):
162  if item.filename not in ('.', '..'):
163  yield SFTPFileInfo(item.filename, item.attributes.permissions)
164 
165  def _stat(self, path):
166  attributes = self._client_client.stat(path)
167  return SFTPFileInfo('', attributes.permissions)
168 
169  def _create_remote_file(self, destination, mode):
170  remote_file = self._client_client.createFile(destination)
171  try:
172  file_stat = self._client_client.fstat(remote_file)
173  file_stat.permissions = mode
174  self._client_client.fsetstat(remote_file, file_stat)
175  except SFTPException:
176  pass
177  return remote_file
178 
179  def _write_to_remote_file(self, remote_file, data, position):
180  self._client_client.write(remote_file, position, data, 0, len(data))
181 
182  def _close_remote_file(self, remote_file):
183  self._client_client.closeFile(remote_file)
184 
185  def _get_file(self, remote_path, local_path, scp_preserve_times):
186  local_file = FileOutputStream(local_path)
187  remote_file_size = self._client_client.stat(remote_path).size
188  remote_file = self._client_client.openFileRO(remote_path)
189  array_size_bytes = 4096
190  data = jarray.zeros(array_size_bytes, 'b')
191  offset = 0
192  while True:
193  read_bytes = self._client_client.read(remote_file, offset, data, 0,
194  array_size_bytes)
195  data_length = len(data)
196  if read_bytes == -1:
197  break
198  if remote_file_size - offset < array_size_bytes:
199  data_length = remote_file_size - offset
200  local_file.write(data, 0, data_length)
201  offset += data_length
202  self._client_client.closeFile(remote_file)
203  local_file.flush()
204  local_file.close()
205 
206  def _absolute_path(self, path):
207  return self._client_client.canonicalPath(path)
208 
209  def _readlink(self, path):
210  return self._client_client.readLink(path)
211 
212 
213 class SCPClient():
214  def __init__(self, ssh_client):
215  self._scp_client_scp_client = JavaSCPClient(ssh_client)
216 
217  def put_file(self, source, destination, *args):
218  self._scp_client_scp_client.put(source, destination)
219 
220  def get_file(self, source, destination, *args):
221  self._scp_client_scp_client.get(source, destination)
222 
223  def put_directory(self, source, destination, *args):
224  raise JavaSSHClientException('`Put Directory` not available with `scp=ALL` option. Try again with '
225  '`scp=TRANSFER` or `scp=OFF`.')
226 
227  def get_directory(self, source, destination, *args):
228  raise JavaSSHClientException('`Get Directory` not available with `scp=ALL` option. Try again with '
229  '`scp=TRANSFER` or `scp=OFF`.')
230 
231 
233 
234  def __init__(self, ssh_client, encoding):
235  self._scp_client_scp_client = JavaSCPClient(ssh_client)
236  super(SCPTransferClient, self).__init__(ssh_client, encoding)
237 
238  def _put_file(self, source, destination, mode, newline, path_separator, scp_preserve_times):
239  self._create_remote_file_create_remote_file_create_remote_file(destination, mode)
240  self._scp_client_scp_client.put(source, destination.rsplit(path_separator, 1)[0])
241 
242  def _get_file(self, remote_path, local_path, scp_preserve_times):
243  self._scp_client_scp_client.get(remote_path, local_path.rsplit(os.sep, 1)[0])
244 
245 
247 
248  def read_outputs(self, timeout=None, *args):
249  if timeout:
250  _wait_until_timeout(self._shell_shell, timeout)
251  stdout = self._read_from_stream_read_from_stream(self._shell_shell.getStdout())
252  stderr = self._read_from_stream_read_from_stream(self._shell_shell.getStderr())
253  rc = self._shell_shell.getExitStatus() or 0
254  self._shell_shell.close()
255  return stdout, stderr, rc
256 
257  def _read_from_stream(self, stream):
258  reader = BufferedReader(InputStreamReader(StreamGobbler(stream),
259  self._encoding_encoding))
260  result = ''
261  line = reader.readLine()
262  while line is not None:
263  result += line + '\n'
264  line = reader.readLine()
265  return result
266 
267  def _execute(self):
268  command = self._command_command.decode(self._encoding_encoding)
269  self._shell_shell.execCommand(command)
270 
271  def _execute_with_sudo(self, sudo_password=None):
272  command = 'sudo ' + self._command_command.decode(self._encoding_encoding)
273  if sudo_password is None:
274  self._shell_shell.execCommand(command)
275  else:
276  self._shell_shell.execCommand('echo %s | sudo --stdin --prompt "" %s' % (sudo_password, command))
277 
278  def _invoke(self):
279  command = self._command_command.decode(self._encoding_encoding)
280  self._shell_shell.startSubSystem(command)
281 
Base class for the remote command.
Base class for the SFTP implementation.
def _create_remote_file(self, destination, mode)
Base class for the SSH client implementation.
Base class for the shell implementation.
Wrapper class for the language specific file information objects.
def _start_command(self, command, sudo=False, sudo_password=None, invoke_subsystem=False, forward_agent=False)
Definition: javaclient.py:93
def _login(self, username, password, allow_agent='ignored', look_for_keys='ignored', proxy_cmd=None, jumphost_alias_or_index=None, read_config=False, keep_alive_interval=None)
Definition: javaclient.py:64
def enable_logging(logfile)
Enables logging of SSH events to a file.
Definition: javaclient.py:60
def _login_with_public_key(self, username, key_file, password, allow_agent='ignored', look_for_keys='ignored', proxy_cmd=None, jumphost_alias_or_index=None, read_config=False, keep_alive_interval=None)
Definition: javaclient.py:78
def create_local_ssh_tunnel(self, local_port, remote_host, remote_port, *args)
Definition: javaclient.py:114
def _read_from_stream(self, stream)
Definition: javaclient.py:257
def _execute_with_sudo(self, sudo_password=None)
Definition: javaclient.py:271
def read_outputs(self, timeout=None, *args)
Definition: javaclient.py:248
def put_directory(self, source, destination, *args)
Definition: javaclient.py:223
def __init__(self, ssh_client)
Definition: javaclient.py:214
def get_directory(self, source, destination, *args)
Definition: javaclient.py:227
def get_file(self, source, destination, *args)
Definition: javaclient.py:220
def put_file(self, source, destination, *args)
Definition: javaclient.py:217
def _put_file(self, source, destination, mode, newline, path_separator, scp_preserve_times)
Definition: javaclient.py:238
def _get_file(self, remote_path, local_path, scp_preserve_times)
Definition: javaclient.py:242
def __init__(self, ssh_client, encoding)
Definition: javaclient.py:234
def __init__(self, ssh_client, encoding)
Definition: javaclient.py:155
def _close_remote_file(self, remote_file)
Definition: javaclient.py:182
def _get_file(self, remote_path, local_path, scp_preserve_times)
Definition: javaclient.py:185
def _write_to_remote_file(self, remote_file, data, position)
Definition: javaclient.py:179
def _create_remote_file(self, destination, mode)
Definition: javaclient.py:169
def read_byte(self)
Reads a single byte from the shell.
Definition: javaclient.py:136
def read(self)
Reads all the output from the shell.
Definition: javaclient.py:129
def __init__(self, client, term_type, term_width, term_height)
Definition: javaclient.py:121
def resize(width, height)
Definition: javaclient.py:142
def write(self, text)
Writes the text in the current shell.
Definition: javaclient.py:148
def _wait_until_timeout(_shell, timeout)
Definition: javaclient.py:43