Enabling support of 'script_inline' option

Starting from rev.0.4.2 following format of results is supported:
{"
   "\"additive\": [{chart data}, {chart data}, ...], "
   "\"complete\": [{chart data}, {chart data}, ...]}\n"

This patch enables support of all other types of output format
by using 'TextArea' widget

Change-Id: I5d31c3450c5f6a622cf66eebb8edf0c5878ab64f
This commit is contained in:
astaroverov 2017-03-03 10:23:59 +03:00 committed by Staroverov Anton
parent 71fc24e160
commit 4e5d802e0c
4 changed files with 118 additions and 51 deletions

View File

@ -161,19 +161,23 @@ class BootRuncommandDelete(vm_utils.VMScenario):
code, out, err = self._run_command(
fip["ip"], port, username, password, command=command)
text_area_output = ["StdErr: %s" % (err or "(none)"),
"StdOut:"]
if code:
raise exceptions.ScriptError(
"Error running command %(command)s. "
"Error %(code)s: %(error)s" % {
"command": command, "code": code, "error": err})
# Let's try to load output data
try:
data = json.loads(out)
except ValueError as e:
raise exceptions.ScriptError(
"Command %(command)s has not output valid JSON: %(error)s."
" Output: %(output)s" % {
"command": command, "error": str(e), "output": out})
# 'echo 42' produces very json-compatible result
# - check it here
if not isinstance(data, dict):
raise ValueError
except ValueError:
# It's not a JSON, probably it's 'script_inline' result
data = []
except (exceptions.TimeoutException,
exceptions.SSHTimeout):
console_logs = self._get_server_console_output(server,
@ -185,38 +189,16 @@ class BootRuncommandDelete(vm_utils.VMScenario):
self._delete_server_with_fip(server, fip,
force_delete=force_delete)
if type(data) != dict:
raise exceptions.ScriptError(
"Command has returned data in unexpected format.\n"
"Expected format: {"
"\"additive\": [{chart data}, {chart data}, ...], "
"\"complete\": [{chart data}, {chart data}, ...]}\n"
"Actual data: %s" % data)
if set(data) - {"additive", "complete"}:
LOG.warning(
"Deprecated since Rally release 0.4.1: command has "
"returned data in format {\"key\": <value>, ...}\n"
"Expected format: {"
"\"additive\": [{chart data}, {chart data}, ...], "
"\"complete\": [{chart data}, {chart data}, ...]}")
output = None
try:
output = [[str(k), float(v)] for k, v in data.items()]
except (TypeError, ValueError):
raise exceptions.ScriptError(
"Command has returned data in unexpected format.\n"
"Expected format: {key1: <number>, "
"key2: <number>, ...}.\n"
"Actual data: %s" % data)
if output:
self.add_output(additive={"title": "Command output",
"chart_plugin": "Lines",
"data": output})
else:
if isinstance(data, dict) and set(data) == {"additive", "complete"}:
for chart_type, charts in data.items():
for chart in charts:
self.add_output(**{chart_type: chart})
else:
# it's a dict with several unknown lines
text_area_output.extend(out.split("\n"))
self.add_output(complete={"title": "Script Output",
"chart_plugin": "TextArea",
"data": text_area_output})
@scenario.configure(context={"cleanup": ["nova", "heat"],

View File

@ -0,0 +1,35 @@
{% set flavor_name = flavor_name or "m1.tiny" %}
{
"VMTasks.boot_runcommand_delete": [
{
"args": {
"flavor": {
"name": "{{flavor_name}}"
},
"image": {
"name": "^cirros.*-disk$"
},
"floating_network": "public",
"force_delete": false,
"command": {
"interpreter": "/bin/sh",
"script_inline": "ls -la"
},
"username": "cirros"
},
"runner": {
"type": "constant",
"times": 10,
"concurrency": 2
},
"context": {
"users": {
"tenants": 3,
"users_per_tenant": 2
},
"network": {
}
}
}
]
}

View File

@ -0,0 +1,24 @@
{% set flavor_name = flavor_name or "m1.tiny" %}
---
VMTasks.boot_runcommand_delete:
-
args:
flavor:
name: "{{flavor_name}}"
image:
name: "^cirros.*-disk$"
floating_network: "public"
force_delete: false
command:
interpreter: "/bin/sh"
script_inline: "ls -la"
username: "cirros"
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 3
users_per_tenant: 2
network: {}

View File

@ -75,21 +75,43 @@ class VMTasksTestCase(test.ScenarioTestCase):
scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete="foo_force")
scenario.add_output.assert_called_once_with(
additive={"title": "Command output", "chart_plugin": "Lines",
"data": [["foo", 42.0]]})
complete={"chart_plugin": "TextArea",
"data": [
"StdErr: foo_err",
"StdOut:",
"{\"foo\": 42}"],
"title": "Script Output"})
@ddt.data(
{"output": (0, "", ""), "raises": exceptions.ScriptError},
{"output": (0, "{\"foo\": 42}", ""),
"expected": [{"additive": {"chart_plugin": "Lines",
"data": [["foo", 42.0]],
"title": "Command output"}}]},
{"output": (0, "", ""),
"expected": [{"complete": {"chart_plugin": "TextArea",
"data": [
"StdErr: (none)",
"StdOut:",
""],
"title": "Script Output"}}]},
{"output": (1, "{\"foo\": 42}", ""), "raises": exceptions.ScriptError},
{"output": ("", 1, ""), "raises": TypeError},
{"output": (0, "{\"foo\": 42}", ""),
"expected": [{"complete": {"chart_plugin": "TextArea",
"data": [
"StdErr: (none)",
"StdOut:",
"{\"foo\": 42}"],
"title": "Script Output"}}]},
{"output": (0, "{\"additive\": [1, 2]}", ""),
"expected": [{"additive": 1}, {"additive": 2}]},
"expected": [{"complete": {"chart_plugin": "TextArea",
"data": [
"StdErr: (none)",
"StdOut:", "{\"additive\": [1, 2]}"],
"title": "Script Output"}}]},
{"output": (0, "{\"complete\": [3, 4]}", ""),
"expected": [{"complete": 3}, {"complete": 4}]},
"expected": [{"complete": {"chart_plugin": "TextArea",
"data": [
"StdErr: (none)",
"StdOut:",
"{\"complete\": [3, 4]}"],
"title": "Script Output"}}]},
{"output": (0, "{\"additive\": [1, 2], \"complete\": [3, 4]}", ""),
"expected": [{"additive": 1}, {"additive": 2},
{"complete": 3}, {"complete": 4}]}
@ -172,13 +194,14 @@ class VMTasksTestCase(test.ScenarioTestCase):
scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
mock_json.loads.side_effect = ValueError()
self.assertRaises(exceptions.ScriptError,
scenario.run,
"foo_image", "foo_flavor", "foo_interpreter",
"foo_script", "foo_username")
scenario.run("foo_image", "foo_flavor", "foo_interpreter",
"foo_script", "foo_username")
scenario.add_output.assert_called_once_with(complete={
"chart_plugin": "TextArea", "data": ["StdErr: foo_err",
"StdOut:", "{\"foo\": 42}"],
"title": "Script Output"})
scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete=False)
self.assertFalse(scenario.add_output.called)
def test_boot_runcommand_delete_custom_image(self):
context = {
@ -221,8 +244,11 @@ class VMTasksTestCase(test.ScenarioTestCase):
scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete="foo_force")
scenario.add_output.assert_called_once_with(
additive={"title": "Command output", "chart_plugin": "Lines",
"data": [["foo", 42.0]]})
complete={"chart_plugin": "TextArea",
"data": [
"StdErr: foo_err",
"StdOut:", "{\"foo\": 42}"],
"title": "Script Output"})
@mock.patch("%s.heat" % BASE)
@mock.patch("%s.sshutils" % BASE)