Switch to SSHClient API usage in execute_on_remote

Switch to SSHClient API usage in execute_on_remote: remote.check_call
check_call has been aligned to SSHClient

Change-Id: I6a6a0db5ccc1175c296a64d0c928d51558d51189
(cherry picked from commit 8e90a5b)
This commit is contained in:
Alexey Stepanov 2016-08-10 14:29:13 +03:00
parent 041999f32f
commit e58bd3b3f9
5 changed files with 73 additions and 93 deletions

View File

@ -160,14 +160,15 @@ def verify_network_list_api(os_conn, net_count=None):
def check_ceph_image_size(ip, expected_size, device='vdc'):
ret = ssh_manager.check_call(
ip=ip,
cmd="df -m /dev/{device}* | grep ceph | awk"
" {size}".format(device=device,
size=re.escape('{print $2}'))
)['stdout']
command="df -m /dev/{device}* | grep ceph | awk"
" {size}".format(device=device,
size=re.escape('{print $2}'))
).stdout
if not ret:
logger.error("Partition not present! {}: ".format(
ssh_manager.check_call(ip=ip, cmd="df -m")))
logger.error(
"Partition not present! {}: ".format(
ssh_manager.check_call(ip=ip, command="df -m").stdout_str))
raise Exception()
logger.debug("Partitions: {part}".format(part=ret))
assert_true(abs(float(ret[0].rstrip()) / expected_size - 1) < 0.1,
@ -242,7 +243,7 @@ def enable_feature_group(env, group):
# update nailgun configs via puppet from that value
ssh_manager.check_call(
ip=ssh_manager.admin_ip,
cmd='puppet apply /etc/puppet/modules/fuel/examples/nailgun.pp'
command='puppet apply /etc/puppet/modules/fuel/examples/nailgun.pp'
)
def check_api_group_enabled():
@ -1380,20 +1381,20 @@ def check_free_space_admin(env, min_disk_admin=50, disk_id=0):
admin_ip = env.ssh_manager.admin_ip
var_free_space = ssh_manager.check_call(
ip=admin_ip,
cmd="df -h /var")['stdout'][1].split()[3][:-1]
command="df -h /var")['stdout'][1].split()[3][:-1]
system_dirs = ['/boot/efi', '/boot$', 'docker-docker--pool', 'SWAP',
'os-root']
system_dirs_size = 0
for sys_dir in system_dirs:
system_dir = ssh_manager.check_call(
ip=admin_ip,
cmd="lsblk -b | grep -we {0} | tail -1".format(
command="lsblk -b | grep -we {0} | tail -1".format(
sys_dir))['stdout'][0]
system_dir = int(re.findall(r"\D(\d{9,12})\D", system_dir)[0])
system_dirs_size += system_dir
system_files_var = int(ssh_manager.check_call(
ip=admin_ip,
cmd="df -B1 /var")['stdout'][1].split()[2])
command="df -B1 /var")['stdout'][1].split()[2])
init_size = (min_disk_admin - system_dirs_size)
min_var_free_space = (init_size * 0.4 - system_files_var) / 1024 ** 3
if var_free_space < min_var_free_space:
@ -1402,11 +1403,11 @@ def check_free_space_admin(env, min_disk_admin=50, disk_id=0):
min_var_free_space, var_free_space))
system_files_log = int(ssh_manager.check_call(
ip=admin_ip,
cmd="df -B1 /var/log")['stdout'][1].split()[2])
command="df -B1 /var/log")['stdout'][1].split()[2])
min_log_free_space = (init_size * 0.6 - system_files_log) / 1024 ** 3
log_free_space = ssh_manager.check_call(
ip=admin_ip,
cmd="df -h /var/log")['stdout'][1].split()[3][:-1]
command="df -h /var/log")['stdout'][1].split()[3][:-1]
if log_free_space < min_log_free_space:
raise ValueError(
"The minimal /var/log size should be {0}, current {1}".format(
@ -1445,7 +1446,7 @@ def check_free_space_slave(env, min_disk_slave=150):
for ip in compute_ip:
vm_storage_free_space = ssh_manager.check_call(
ip=ip,
cmd="df -h /var/lib/nova")['stdout'][1].split()[3][:-1]
command="df -h /var/lib/nova")['stdout'][1].split()[3][:-1]
if vm_storage_free_space < 4 * small_flavor_disk:
raise ValueError(
"The minimal vm-nova storage size should be {0}, "

View File

@ -11,31 +11,3 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
class UnexpectedExitCode(Exception):
def __init__(self, command, ec, expected_ec, stdout=None, stderr=None):
"""Exception for unexpected exit code after executing shell/ssh command
:param command: str - executed command
:param ec: int - actual exit code
:param expected_ec: list of integers - expected exit codes
:param stdout: str
:param stderr: str
"""
self.ec = ec
self.expected_ec = expected_ec
self.cmd = command
self.stdout = stdout
self.stderr = stderr
super(UnexpectedExitCode, self).__init__()
def __str__(self):
message = "Command '{cmd:s}' returned unexpected exit code {code:d}," \
" while waiting for {exp}".format(cmd=self.cmd,
code=self.ec,
exp=self.expected_ec)
if self.stdout:
message += "stdout: {}\n".format(self.stdout)
if self.stderr:
message += "stderr: {}\n".format(self.stderr)
return message

View File

@ -17,6 +17,7 @@ import os
import posixpath
import re
import traceback
from warnings import warn
from devops.helpers.helpers import wait
from devops.models.node import SSHClient
@ -27,7 +28,6 @@ import yaml
from fuelweb_test import logger
from fuelweb_test.helpers.metaclasses import SingletonMeta
from fuelweb_test.helpers.exceptions import UnexpectedExitCode
from fuelweb_test.settings import SSH_FUEL_CREDENTIALS
from fuelweb_test.settings import SSH_SLAVE_CREDENTIALS
@ -99,8 +99,10 @@ class SSHManager(object):
""" Function returns remote SSH connection to node by ip address
:param ip: IP of host
:type ip: str
:param port: port for SSH
:return: SSHClient
:type port: int
:rtype: SSHClient
"""
if (ip, port) not in self.connections:
logger.debug('SSH_MANAGER:Create new connection for '
@ -175,9 +177,34 @@ class SSHManager(object):
remote = self.get_remote(ip=ip, port=port)
return remote.execute(cmd)
def check_call(self, ip, cmd, port=22, verbose=False):
def check_call(
self,
ip,
command, port=22, verbose=False, timeout=None,
error_info=None,
expected=None, raise_on_err=True):
"""Execute command and check for return code
:type ip: str
:type command: str
:type port: int
:type verbose: bool
:type timeout: int
:type error_info: str
:type expected: list
:type raise_on_err: bool
:rtype: ExecResult
:raises: DevopsCalledProcessError
"""
remote = self.get_remote(ip=ip, port=port)
return remote.check_call(cmd, verbose)
return remote.check_call(
command=command,
verbose=verbose,
timeout=timeout,
error_info=error_info,
expected=expected,
raise_on_err=raise_on_err
)
def execute_on_remote(self, ip, cmd, port=22, err_msg=None,
jsonify=False, assert_ec_equal=None,
@ -201,11 +228,16 @@ class SSHManager(object):
if yamlify and jsonify:
raise ValueError('Conflicting arguments: yamlify and jsonify!')
orig_result = self.execute(ip=ip, port=port, cmd=cmd)
remote = self.get_remote(ip=ip, port=port)
orig_result = remote.check_call(
command=cmd,
error_info=err_msg,
expected=assert_ec_equal,
raise_on_err=raise_on_assert
)
# Now create fallback result
# TODO(astepanov): switch to SSHClient output after tests adoptation
# TODO(astepanov): process whole parameters on SSHClient().check_call()
result = {
'stdout': orig_result['stdout'],
@ -215,43 +247,10 @@ class SSHManager(object):
'stderr_str': ''.join(orig_result['stderr']).strip(),
}
details_log = (
"Host: {host}\n"
"Command: '{cmd}'\n"
"Exit code: {code}\n"
"STDOUT:\n{stdout}\n"
"STDERR:\n{stderr}".format(
host=ip, cmd=cmd, code=result['exit_code'],
stdout=result['stdout_str'], stderr=result['stderr_str']
))
if result['exit_code'] not in assert_ec_equal:
error_msg = (
err_msg or
"Unexpected exit_code returned: actual {0}, expected {1}."
"".format(
result['exit_code'],
' '.join(map(str, assert_ec_equal))))
log_msg = (
"{0} Command: '{1}' "
"Details:\n{2}".format(
error_msg, cmd, details_log))
logger.error(log_msg)
if raise_on_assert:
raise UnexpectedExitCode(cmd,
result['exit_code'],
assert_ec_equal,
stdout=result['stdout_str'],
stderr=result['stderr_str'])
else:
logger.debug(details_log)
if jsonify:
result['stdout_json'] = \
self._json_deserialize(result['stdout_str'])
result['stdout_json'] = orig_result.stdout_json
elif yamlify:
result['stdout_yaml'] = \
self._yaml_deserialize(result['stdout_str'])
result['stdout_yaml'] = orig_result.stdout_yaml
return result
@ -267,6 +266,10 @@ class SSHManager(object):
:return: obj
:raise: Exception
"""
warn(
'_json_deserialize is not used anymore and will be removed later',
DeprecationWarning)
if isinstance(json_string, list):
json_string = ''.join(json_string).strip()
@ -287,6 +290,10 @@ class SSHManager(object):
:return: obj
:raise: Exception
"""
warn(
'_yaml_deserialize is not used anymore and will be removed later',
DeprecationWarning)
if isinstance(yaml_string, list):
yaml_string = ''.join(yaml_string).strip()

View File

@ -1049,14 +1049,14 @@ def get_ceph_partitions(ip, device, fs_type="xfs"):
# Moved from checkers.py for improvement of code
ret = SSHManager().check_call(
ip=ip,
cmd="parted {device} print | grep {type}".format(device=device,
type=fs_type)
)['stdout']
command="parted {device} print | grep {type}".format(device=device,
type=fs_type)
).stdout
if not ret:
logger.error(
"Partition not present! {partitions}: ".format(
partitions=SSHManager().check_call(
ip=ip, cmd="parted {device} print")))
ip=ip, command="parted {device} print").stdout_str))
raise Exception()
logger.debug("Partitions: {part}".format(part=ret))
return ret
@ -1067,7 +1067,7 @@ def get_mongo_partitions(ip, device):
# Moved from checkers.py for improvement of code
ret = SSHManager().check_call(
ip=ip,
cmd="lsblk | grep {device} | awk {size}".format(
command="lsblk | grep {device} | awk {size}".format(
device=device,
size=re.escape('{print $4}'))
)['stdout']
@ -1075,7 +1075,7 @@ def get_mongo_partitions(ip, device):
logger.error(
"Partition not present! {partitions}: ".format(
partitions=SSHManager().check_call(
ip=ip, cmd="parted {device} print")))
ip=ip, command="parted {device} print").stdout_str))
raise Exception()
logger.debug("Partitions: {part}".format(part=ret))
return ret
@ -1152,8 +1152,8 @@ def get_quantity_of_numa(ip):
numa = int(SSHManager().check_call(
ip=ip,
cmd="lstopo | grep NUMANode| wc -l"
)['stdout'][0])
command="lstopo | grep NUMANode| wc -l"
).stdout[0])
if not numa:
logger.debug("There are no NUMA nodes on {0}".format(ip))

View File

@ -14,6 +14,7 @@
import tempfile
import textwrap
from devops.error import DevopsCalledProcessError
from devops.helpers.helpers import tcp_ping
from devops.helpers.helpers import wait
from proboscis.asserts import assert_equal
@ -28,7 +29,6 @@ from fuelweb_test.helpers import utils
from fuelweb_test.helpers.decorators import log_snapshot_after_test
from fuelweb_test import settings
from fuelweb_test.tests import base_test_case
from fuelweb_test.helpers.exceptions import UnexpectedExitCode
@test(groups=["ubuntu_bootstrap_builder", "bvt_ubuntu_bootstrap"])
@ -296,7 +296,7 @@ class UbuntuBootstrapBuild(base_test_case.TestBasic):
"Bootstrap {0} was not deleted and still available: {1}"
.format(uuid, bootstrap_uuids))
assert_raises(UnexpectedExitCode,
assert_raises(DevopsCalledProcessError,
self.env.fuel_bootstrap_actions.activate_bootstrap_image,
uuid)
@ -311,7 +311,7 @@ class UbuntuBootstrapBuild(base_test_case.TestBasic):
assert_true(uuid is not None, "No active bootstrap. Possibly centos "
"is active or something went wrong.")
assert_raises(
UnexpectedExitCode,
DevopsCalledProcessError,
self.env.fuel_bootstrap_actions.delete_bootstrap_image,
uuid)