blob: 573cdd628a425f64d084af37e4e2d01446d22754 [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
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000013import sys
14
15from oslo_log import log
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000016from tempest import config
17from tempest.lib.common import ssh
18from tempest.lib.common.utils import test_utils
lkuchlan1d1461d2020-08-04 11:19:11 +030019from tempest.lib import exceptions
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000020
21CONF = config.CONF
22
23LOG = log.getLogger(__name__)
24
25
26def debug_ssh(function):
27 """Decorator to generate extra debug info in case of ssh failure"""
28 def wrapper(self, *args, **kwargs):
29 try:
30 return function(self, *args, **kwargs)
lkuchlan1d1461d2020-08-04 11:19:11 +030031 except exceptions.SSHTimeout:
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000032 try:
33 original_exception = sys.exc_info()
34 caller = test_utils.find_test_caller() or "not found"
35 if self.server:
36 msg = 'Caller: %s. Timeout trying to ssh to server %s'
37 LOG.debug(msg, caller, self.server)
38 if self.log_console and self.servers_client:
39 try:
40 msg = 'Console log for server %s: %s'
41 console_log = (
42 self.servers_client.get_console_output(
43 self.server['id'])['output'])
44 LOG.debug(msg, self.server['id'], console_log)
45 except Exception:
46 msg = 'Could not get console_log for server %s'
47 LOG.debug(msg, self.server['id'])
48 # re-raise the original ssh timeout exception
haixin48895812020-09-30 13:50:37 +080049 raise original_exception
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000050 finally:
51 # Delete the traceback to avoid circular references
52 _, _, trace = original_exception
53 del trace
54 return wrapper
55
56
57class RemoteClient(object):
58
59 def __init__(self, ip_address, username, password=None, pkey=None,
60 server=None, servers_client=None):
61 """Executes commands in a VM over ssh
62
63 :param ip_address: IP address to ssh to
64 :param username: ssh username
65 :param password: ssh password (optional)
66 :param pkey: ssh public key (optional)
67 :param server: server dict, used for debugging purposes
68 :param servers_client: servers client, used for debugging purposes
69 """
70 self.server = server
71 self.servers_client = servers_client
72 self.log_console = CONF.compute_feature_enabled.console_output
silvacarlossa894bae2021-10-29 11:07:59 -030073 kwargs = {}
Goutham Pacha Ravi35b2bf12022-03-17 00:53:45 +053074
75 try:
silvacarlossa894bae2021-10-29 11:07:59 -030076 kwargs['ssh_key_type'] = CONF.validation.ssh_key_type
Goutham Pacha Ravi35b2bf12022-03-17 00:53:45 +053077 except Exception:
78 # Not all versions of tempest support the
79 # "validation.ssh_key_type" config option
80 pass
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000081
silvacarlossa894bae2021-10-29 11:07:59 -030082 self.ssh_client = ssh.Client(
83 ip_address, username, password, pkey=pkey, **kwargs)
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000084
85 @debug_ssh
86 def exec_command(self, cmd):
87 # Shell options below add more clearness on failures,
88 # path is extended for some non-cirros guest oses (centos7)
89 cmd = CONF.validation.ssh_shell_prologue + " " + cmd
junbolib236c242017-07-18 18:12:37 +080090 LOG.debug("Remote command: %s", cmd)
Daniel Mellado21d4d5c2016-11-08 17:02:42 +000091 return self.ssh_client.exec_command(cmd)
92
93 @debug_ssh
94 def validate_authentication(self):
95 """Validate ssh connection and authentication
96
97 This method raises an Exception when the validation fails.
98 """
99 self.ssh_client.test_connection_auth()