blob: 085fce30bfa49f3cbeeb9b9e660328449529ddf4 [file] [log] [blame]
Jay Pipes051075a2012-04-28 17:39:37 -04001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack, LLC
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
Daryl Walleck1465d612011-11-02 02:22:15 -050018import time
19import socket
20import warnings
Jay Pipes051075a2012-04-28 17:39:37 -040021
Daryl Walleck6b9b2882012-04-08 21:43:39 -050022from tempest import exceptions
Daryl Walleck1465d612011-11-02 02:22:15 -050023
Jay Pipes051075a2012-04-28 17:39:37 -040024
Daryl Walleck1465d612011-11-02 02:22:15 -050025with warnings.catch_warnings():
26 warnings.simplefilter("ignore")
27 import paramiko
28
29
30class Client(object):
31
Jay Pipes051075a2012-04-28 17:39:37 -040032 def __init__(self, host, username, password=None, timeout=300,
33 channel_timeout=10, look_for_keys=False, key_filename=None):
Daryl Walleck1465d612011-11-02 02:22:15 -050034 self.host = host
35 self.username = username
36 self.password = password
Jay Pipes051075a2012-04-28 17:39:37 -040037 self.look_for_keys = look_for_keys
38 self.key_filename = key_filename
Daryl Walleck1465d612011-11-02 02:22:15 -050039 self.timeout = int(timeout)
Jay Pipes051075a2012-04-28 17:39:37 -040040 self.channel_timeout = int(channel_timeout)
Daryl Walleck1465d612011-11-02 02:22:15 -050041
42 def _get_ssh_connection(self):
43 """Returns an ssh connection to the specified host"""
44 _timeout = True
45 ssh = paramiko.SSHClient()
46 ssh.set_missing_host_key_policy(
47 paramiko.AutoAddPolicy())
48 _start_time = time.time()
49
50 while not self._is_timed_out(self.timeout, _start_time):
51 try:
52 ssh.connect(self.host, username=self.username,
Jay Pipes051075a2012-04-28 17:39:37 -040053 password=self.password,
54 look_for_keys=self.look_for_keys,
55 key_filename=self.key_filename,
56 timeout=self.timeout)
Daryl Walleck1465d612011-11-02 02:22:15 -050057 _timeout = False
58 break
59 except socket.error:
60 continue
61 except paramiko.AuthenticationException:
Jay Pipes051075a2012-04-28 17:39:37 -040062 time.sleep(5)
Daryl Walleck1465d612011-11-02 02:22:15 -050063 continue
64 if _timeout:
Daryl Walleck6b9b2882012-04-08 21:43:39 -050065 raise exceptions.SSHTimeout(host=self.host,
66 user=self.username,
67 password=self.password)
Daryl Walleck1465d612011-11-02 02:22:15 -050068 return ssh
69
70 def _is_timed_out(self, timeout, start_time):
71 return (time.time() - timeout) > start_time
72
73 def connect_until_closed(self):
74 """Connect to the server and wait until connection is lost"""
75 try:
76 ssh = self._get_ssh_connection()
77 _transport = ssh.get_transport()
78 _start_time = time.time()
79 _timed_out = self._is_timed_out(self.timeout, _start_time)
80 while _transport.is_active() and not _timed_out:
81 time.sleep(5)
82 _timed_out = self._is_timed_out(self.timeout, _start_time)
83 ssh.close()
84 except (EOFError, paramiko.AuthenticationException, socket.error):
85 return
86
87 def exec_command(self, cmd):
88 """Execute the specified command on the server.
89
90 :returns: data read from standard output of the command
91
92 """
93 ssh = self._get_ssh_connection()
94 stdin, stdout, stderr = ssh.exec_command(cmd)
Jay Pipes051075a2012-04-28 17:39:37 -040095 stdin.flush()
96 stdin.channel.shutdown_write()
97 stdout.channel.settimeout(self.channel_timeout)
98 status = stdout.channel.recv_exit_status()
99 try:
100 output = stdout.read()
101 except socket.timeout:
102 if status == 0:
103 return None, status
Daryl Walleck1465d612011-11-02 02:22:15 -0500104 ssh.close()
Jay Pipes051075a2012-04-28 17:39:37 -0400105 return status, output
Daryl Walleck1465d612011-11-02 02:22:15 -0500106
107 def test_connection_auth(self):
108 """ Returns true if ssh can connect to server"""
109 try:
110 connection = self._get_ssh_connection()
111 connection.close()
112 except paramiko.AuthenticationException:
113 return False
114
115 return True