Merge "Introduce command-dict and validator"

This commit is contained in:
Jenkins 2015-06-08 21:09:31 +00:00 committed by Gerrit Code Review
commit 7aa76f8db8
4 changed files with 85 additions and 72 deletions

View File

@ -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):

View File

@ -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. "

View File

@ -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")

View File

@ -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")