blob: 45f85d85f764b2e71f2b5635c26a61daf50bcebe [file] [log] [blame]
Daniel Mellado21d4d5c2016-11-08 17:02:42 +00001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import six
14import sys
15
16from oslo_log import log
17
18from tempest import config
19from tempest.lib.common import ssh
20from tempest.lib.common.utils import test_utils
21import tempest.lib.exceptions
22
23CONF = config.CONF
24
25LOG = log.getLogger(__name__)
26
27
28def debug_ssh(function):
29 """Decorator to generate extra debug info in case of ssh failure"""
30 def wrapper(self, *args, **kwargs):
31 try:
32 return function(self, *args, **kwargs)
33 except tempest.lib.exceptions.SSHTimeout:
34 try:
35 original_exception = sys.exc_info()
36 caller = test_utils.find_test_caller() or "not found"
37 if self.server:
38 msg = 'Caller: %s. Timeout trying to ssh to server %s'
39 LOG.debug(msg, caller, self.server)
40 if self.log_console and self.servers_client:
41 try:
42 msg = 'Console log for server %s: %s'
43 console_log = (
44 self.servers_client.get_console_output(
45 self.server['id'])['output'])
46 LOG.debug(msg, self.server['id'], console_log)
47 except Exception:
48 msg = 'Could not get console_log for server %s'
49 LOG.debug(msg, self.server['id'])
50 # re-raise the original ssh timeout exception
51 six.reraise(*original_exception)
52 finally:
53 # Delete the traceback to avoid circular references
54 _, _, trace = original_exception
55 del trace
56 return wrapper
57
58
59class RemoteClient(object):
60
61 def __init__(self, ip_address, username, password=None, pkey=None,
62 server=None, servers_client=None):
63 """Executes commands in a VM over ssh
64
65 :param ip_address: IP address to ssh to
66 :param username: ssh username
67 :param password: ssh password (optional)
68 :param pkey: ssh public key (optional)
69 :param server: server dict, used for debugging purposes
70 :param servers_client: servers client, used for debugging purposes
71 """
72 self.server = server
73 self.servers_client = servers_client
74 self.log_console = CONF.compute_feature_enabled.console_output
75
76 self.ssh_client = ssh.Client(ip_address, username, password, pkey=pkey)
77
78 @debug_ssh
79 def exec_command(self, cmd):
80 # Shell options below add more clearness on failures,
81 # path is extended for some non-cirros guest oses (centos7)
82 cmd = CONF.validation.ssh_shell_prologue + " " + cmd
junbolib236c242017-07-18 18:12:37 +080083 LOG.debug("Remote command: %s", cmd)
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000084 return self.ssh_client.exec_command(cmd)
85
86 @debug_ssh
87 def validate_authentication(self):
88 """Validate ssh connection and authentication
89
90 This method raises an Exception when the validation fails.
91 """
92 self.ssh_client.test_connection_auth()