Merge "Introduce command-dict and validator"
This commit is contained in:
commit
7aa76f8db8
@ -21,10 +21,10 @@ import six
|
||||
|
||||
from rally.benchmark.scenarios import base
|
||||
from rally.benchmark import utils as bench_utils
|
||||
from rally.benchmark import validation
|
||||
from rally.common.i18n import _
|
||||
from rally.common import log as logging
|
||||
from rally.common import sshutils
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.wrappers import network as network_wrapper
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -40,32 +40,33 @@ class VMScenario(base.Scenario):
|
||||
"""
|
||||
|
||||
@base.atomic_action_timer("vm.run_command_over_ssh")
|
||||
def _run_command_over_ssh(self, ssh, interpreter, script,
|
||||
is_file=True):
|
||||
def _run_command_over_ssh(self, ssh, command):
|
||||
"""Run command inside an instance.
|
||||
|
||||
This is a separate function so that only script execution is timed.
|
||||
|
||||
:param ssh: A SSHClient instance.
|
||||
:param interpreter: The interpreter that will be used to execute
|
||||
the script.
|
||||
:param script: Path to the script file or its content in a StringIO.
|
||||
:param is_file: if True, script represent a path,
|
||||
else, script contains an inline script.
|
||||
:param command: Dictionary specifying command to execute.
|
||||
See `validation.valid_command' docstring for details.
|
||||
|
||||
:returns: tuple (exit_status, stdout, stderr)
|
||||
"""
|
||||
if not is_file:
|
||||
stdin = script
|
||||
elif isinstance(script, six.string_types):
|
||||
stdin = open(script, "rb")
|
||||
elif isinstance(script, six.moves.StringIO):
|
||||
stdin = script
|
||||
else:
|
||||
raise exceptions.ScriptError(
|
||||
"Either file path or StringIO expected, given %s" %
|
||||
type(script).__name__)
|
||||
validation.check_command_dict(command)
|
||||
|
||||
return ssh.execute(interpreter, stdin=stdin)
|
||||
# NOTE(pboldin): Here we `get' the values and not check for the keys
|
||||
# due to template-driven configuration generation that can leave keys
|
||||
# defined but values empty.
|
||||
if command.get("script_file") or command.get("script_inline"):
|
||||
cmd = command["interpreter"]
|
||||
if command.get("script_file"):
|
||||
stdin = open(command["script_file"], "rb")
|
||||
elif command.get("script_inline"):
|
||||
stdin = six.moves.StringIO(command["script_inline"])
|
||||
elif command.get("remote_path"):
|
||||
cmd = command["remote_path"]
|
||||
stdin = None
|
||||
|
||||
return ssh.execute(cmd, stdin=stdin)
|
||||
|
||||
def _boot_server_with_fip(self, image, flavor,
|
||||
use_floating_ip=True, floating_network=None,
|
||||
@ -135,30 +136,30 @@ class VMScenario(base.Scenario):
|
||||
timeout=120
|
||||
)
|
||||
|
||||
def _run_command(self, server_ip, port, username, password, interpreter,
|
||||
script, pkey=None, is_file=True):
|
||||
def _run_command(self, server_ip, port, username, password, command,
|
||||
pkey=None):
|
||||
"""Run command via SSH on server.
|
||||
|
||||
Create SSH connection for server, wait for server to become
|
||||
available (there is a delay between server being set to ACTIVE
|
||||
and sshd being available). Then call run_command_over_ssh to actually
|
||||
execute the command.
|
||||
Create SSH connection for server, wait for server to become available
|
||||
(there is a delay between server being set to ACTIVE and sshd being
|
||||
available). Then call run_command_over_ssh to actually execute the
|
||||
command.
|
||||
|
||||
:param server_ip: server ip address
|
||||
:param port: ssh port for SSH connection
|
||||
:param username: str. ssh username for server
|
||||
:param password: Password for SSH authentication
|
||||
:param interpreter: server's interpreter to execute the script
|
||||
:param script: script to run on server
|
||||
:param command: Dictionary specifying command to execute.
|
||||
See `valiation.valid_command' docstring for explanation.
|
||||
:param pkey: key for SSH authentication
|
||||
:param is_file: if True, script represent a path,
|
||||
else, script contains an inline script.
|
||||
|
||||
:returns: tuple (exit_status, stdout, stderr)
|
||||
"""
|
||||
pkey = pkey if pkey else self.context["user"]["keypair"]["private"]
|
||||
ssh = sshutils.SSH(username, server_ip, port=port,
|
||||
pkey=pkey, password=password)
|
||||
self._wait_for_ssh(ssh)
|
||||
return self._run_command_over_ssh(ssh, interpreter,
|
||||
script, is_file)
|
||||
return self._run_command_over_ssh(ssh, command)
|
||||
|
||||
@staticmethod
|
||||
def _ping_ip_address(host):
|
||||
|
@ -84,8 +84,9 @@ class VMTasks(nova_utils.NovaScenario, vm_utils.VMScenario,
|
||||
key_name=self.context["user"]["keypair"]["name"],
|
||||
**kwargs)
|
||||
try:
|
||||
code, out, err = self._run_command(fip["ip"], port, username,
|
||||
password, interpreter, script)
|
||||
code, out, err = self._run_command(
|
||||
fip["ip"], port, username, password,
|
||||
command={"script_file": script, "interpreter": interpreter})
|
||||
if code:
|
||||
raise exceptions.ScriptError(
|
||||
"Error running script %(script)s. "
|
||||
|
@ -19,9 +19,7 @@ import subprocess
|
||||
import mock
|
||||
import netaddr
|
||||
from oslotest import mockpatch
|
||||
import six
|
||||
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.scenarios.vm import utils
|
||||
from tests.unit import test
|
||||
|
||||
@ -38,26 +36,55 @@ class VMScenarioTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("%s.open" % VMTASKS_UTILS,
|
||||
side_effect=mock.mock_open(), create=True)
|
||||
def test__run_command_over_ssh(self, mock_open):
|
||||
def test__run_command_over_ssh_script_file(self, mock_open):
|
||||
mock_ssh = mock.MagicMock()
|
||||
vm_scenario = utils.VMScenario()
|
||||
vm_scenario._run_command_over_ssh(mock_ssh, "interpreter", "script")
|
||||
mock_ssh.execute.assert_called_once_with("interpreter",
|
||||
stdin=mock_open.side_effect())
|
||||
vm_scenario._run_command_over_ssh(
|
||||
mock_ssh,
|
||||
{
|
||||
"script_file": "foobar",
|
||||
"interpreter": ["interpreter", "interpreter_arg"],
|
||||
}
|
||||
)
|
||||
mock_ssh.execute.assert_called_once_with(
|
||||
["interpreter", "interpreter_arg"],
|
||||
stdin=mock_open.side_effect())
|
||||
mock_open.assert_called_once_with("foobar", "rb")
|
||||
|
||||
def test__run_command_over_ssh_stringio(self):
|
||||
@mock.patch("%s.six.moves.StringIO" % VMTASKS_UTILS)
|
||||
def test__run_command_over_ssh_script_inline(self, mock_stringio):
|
||||
mock_ssh = mock.MagicMock()
|
||||
vm_scenario = utils.VMScenario()
|
||||
script = six.moves.StringIO("script")
|
||||
vm_scenario._run_command_over_ssh(mock_ssh, "interpreter", script)
|
||||
mock_ssh.execute.assert_called_once_with("interpreter",
|
||||
stdin=script)
|
||||
vm_scenario._run_command_over_ssh(
|
||||
mock_ssh,
|
||||
{
|
||||
"script_inline": "foobar",
|
||||
"interpreter": ["interpreter", "interpreter_arg"],
|
||||
}
|
||||
)
|
||||
mock_ssh.execute.assert_called_once_with(
|
||||
["interpreter", "interpreter_arg"],
|
||||
stdin=mock_stringio.return_value)
|
||||
mock_stringio.assert_called_once_with("foobar")
|
||||
|
||||
def test__run_command_over_ssh_remote_path(self):
|
||||
mock_ssh = mock.MagicMock()
|
||||
vm_scenario = utils.VMScenario()
|
||||
vm_scenario._run_command_over_ssh(
|
||||
mock_ssh,
|
||||
{
|
||||
"remote_path": ["foo", "bar"],
|
||||
}
|
||||
)
|
||||
mock_ssh.execute.assert_called_once_with(
|
||||
["foo", "bar"],
|
||||
stdin=None)
|
||||
|
||||
def test__run_command_over_ssh_fails(self):
|
||||
vm_scenario = utils.VMScenario()
|
||||
self.assertRaises(exceptions.ScriptError,
|
||||
self.assertRaises(ValueError,
|
||||
vm_scenario._run_command_over_ssh,
|
||||
None, "interpreter", 10)
|
||||
None, command={})
|
||||
|
||||
def test__wait_for_ssh(self):
|
||||
ssh = mock.MagicMock()
|
||||
@ -85,35 +112,17 @@ class VMScenarioTestCase(test.TestCase):
|
||||
|
||||
vm_scenario = utils.VMScenario()
|
||||
vm_scenario.context = {"user": {"keypair": {"private": "ssh"}}}
|
||||
vm_scenario._run_command("1.2.3.4", 22, "username",
|
||||
"password", "int", "/path/to/foo/script.sh",
|
||||
is_file=True)
|
||||
vm_scenario._run_command("1.2.3.4", 22, "username", "password",
|
||||
command={"script_file": "foo",
|
||||
"interpreter": "bar"})
|
||||
|
||||
mock_ssh_class.assert_called_once_with("username", "1.2.3.4", port=22,
|
||||
pkey="ssh",
|
||||
password="password")
|
||||
mock_ssh_instance.wait.assert_called_once_with()
|
||||
mock_run_command_over_ssh.assert_called_once_with(
|
||||
mock_ssh_instance, "int", "/path/to/foo/script.sh", True)
|
||||
|
||||
@mock.patch(VMTASKS_UTILS + ".sshutils.SSH")
|
||||
def test__run_command_inline_script(self, mock_ssh):
|
||||
mock_ssh_instance = mock.MagicMock()
|
||||
mock_ssh.return_value = mock_ssh_instance
|
||||
mock_ssh_instance.execute.return_value = "foobar"
|
||||
vm_scenario = utils.VMScenario()
|
||||
vm_scenario._wait_for_ssh = mock.Mock()
|
||||
vm_scenario.context = {"user": {"keypair": {"private": "foo_pkey"}}}
|
||||
result = vm_scenario._run_command("foo_ip", "foo_port", "foo_username",
|
||||
"foo_password", "foo_interpreter",
|
||||
"foo_script", is_file=False)
|
||||
mock_ssh.assert_called_once_with("foo_username", "foo_ip",
|
||||
port="foo_port", pkey="foo_pkey",
|
||||
password="foo_password")
|
||||
vm_scenario._wait_for_ssh.assert_called_once_with(mock_ssh_instance)
|
||||
mock_ssh_instance.execute.assert_called_once_with("foo_interpreter",
|
||||
stdin="foo_script")
|
||||
self.assertEqual(result, "foobar")
|
||||
mock_ssh_instance,
|
||||
{"script_file": "foo", "interpreter": "bar"})
|
||||
|
||||
@mock.patch(VMTASKS_UTILS + ".sys")
|
||||
@mock.patch("subprocess.Popen")
|
||||
|
@ -37,8 +37,9 @@ class VMTasksTestCase(test.TestCase):
|
||||
|
||||
def test_boot_runcommand_delete(self):
|
||||
self.scenario.boot_runcommand_delete(
|
||||
"foo_image", "foo_flavor", "foo_script",
|
||||
"foo_interpreter", "foo_username",
|
||||
"foo_image", "foo_flavor",
|
||||
script="foo_script", interpreter="foo_interpreter",
|
||||
username="foo_username",
|
||||
password="foo_password",
|
||||
use_floating_ip="use_fip",
|
||||
floating_network="ext_network",
|
||||
@ -56,7 +57,8 @@ class VMTasksTestCase(test.TestCase):
|
||||
|
||||
self.scenario._run_command.assert_called_once_with(
|
||||
"foo_ip", 22, "foo_username", "foo_password",
|
||||
"foo_interpreter", "foo_script")
|
||||
command={"script_file": "foo_script",
|
||||
"interpreter": "foo_interpreter"})
|
||||
self.scenario._delete_server_with_fip.assert_called_once_with(
|
||||
"foo_server", self.ip, force_delete="foo_force")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user