diff --git a/scenarios/misc/static_agent.yaml b/scenarios/misc/static_agent.yaml index c4e7021..35b121c 100644 --- a/scenarios/misc/static_agent.yaml +++ b/scenarios/misc/static_agent.yaml @@ -13,3 +13,10 @@ execution: title: List all files class: shell method: ls -al + - + title: Run sample script + class: shell + script: | + #!/bin/bash + echo "hello" + echo "world" diff --git a/shaker/agent/agent.py b/shaker/agent/agent.py index dbc5107..d114fac 100644 --- a/shaker/agent/agent.py +++ b/shaker/agent/agent.py @@ -13,7 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import shlex +import tempfile import time from oslo_concurrency import processutils @@ -55,6 +57,27 @@ def send_reply(socket, agent_id, result): return res +def run_command(command): + command_stdout, command_stderr = None, None + + if command['type'] == 'program': + command_stdout, command_stderr = processutils.execute( + *shlex.split(command['data']), check_exit_code=False) + + elif command['type'] == 'script': + fd = tempfile.mkstemp() + os.write(fd[0], command['data']) + os.close(fd[0]) + LOG.debug('stored script into %s', fd[1]) + command_stdout, command_stderr = processutils.execute( + *shlex.split('bash %s' % fd[1]), check_exit_code=False) + + else: + command_stderr = 'Unknown command type : %s' % command['type'] + + return dict(stdout=command_stdout, stderr=command_stderr) + + def main(): utils.init_config_and_logging(config.COMMON_OPTS + config.AGENT_OPTS) @@ -81,13 +104,9 @@ def main(): time.sleep(start_at - now) - # do something useful - command_stdout, command_stderr = processutils.execute( - *shlex.split(command), check_exit_code=False) - send_reply(socket, agent_id, { - 'stdout': command_stdout, - 'stderr': command_stderr, - }) + result = run_command(command) + send_reply(socket, agent_id, result) + elif task['operation'] == 'configure': if 'polling_interval' in task: polling_interval = task.get('polling_interval') diff --git a/shaker/engine/executors/__init__.py b/shaker/engine/executors/__init__.py index cda5229..ddf2d3e 100644 --- a/shaker/engine/executors/__init__.py +++ b/shaker/engine/executors/__init__.py @@ -13,18 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from shaker.engine.executors import base from shaker.engine.executors import iperf from shaker.engine.executors import netperf +from shaker.engine.executors import shell EXECUTORS = { - 'shell': base.ShellExecutor, + 'shell': shell.ShellExecutor, 'netperf': netperf.NetperfExecutor, 'iperf': iperf.IperfExecutor, 'iperf_graph': iperf.IperfGraphExecutor, 'netperf_wrapper': netperf.NetperfWrapperExecutor, - '_default': base.ShellExecutor, + '_default': shell.ShellExecutor, } diff --git a/shaker/engine/executors/base.py b/shaker/engine/executors/base.py index 933c8ce..89376ca 100644 --- a/shaker/engine/executors/base.py +++ b/shaker/engine/executors/base.py @@ -21,15 +21,23 @@ LOG = logging.getLogger(__name__) class CommandLine(object): def __init__(self, command): - self.commands = [command] + self.tokens = [command] def add(self, param_name, param_value=None): - self.commands.append('%s' % param_name) + self.tokens.append('%s' % param_name) if param_value: - self.commands.append(str(param_value)) + self.tokens.append(str(param_value)) def make(self): - return ' '.join(self.commands) + return dict(type='program', data=' '.join(self.tokens)) + + +class Script(object): + def __init__(self, script): + self.script = script + + def make(self): + return dict(type='script', data=self.script) class BaseExecutor(object): @@ -48,8 +56,3 @@ class BaseExecutor(object): stderr=message.get('stderr'), command=self.get_command(), agent=self.agent) - - -class ShellExecutor(BaseExecutor): - def get_command(self): - return self.test_definition['method'] diff --git a/shaker/engine/executors/shell.py b/shaker/engine/executors/shell.py new file mode 100644 index 0000000..59d2e11 --- /dev/null +++ b/shaker/engine/executors/shell.py @@ -0,0 +1,30 @@ +# Copyright (c) 2015 Mirantis Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_log import log as logging + +from shaker.engine.executors import base + + +LOG = logging.getLogger(__name__) + + +class ShellExecutor(base.BaseExecutor): + def get_command(self): + if 'method' in self.test_definition: + cmd = base.CommandLine(self.test_definition['method']) + elif 'script' in self.test_definition: + cmd = base.Script(self.test_definition['script']) + return cmd.make() diff --git a/tests/test_iperf_graph_executor.py b/tests/test_iperf_graph_executor.py index 239e328..177947c 100644 --- a/tests/test_iperf_graph_executor.py +++ b/tests/test_iperf_graph_executor.py @@ -27,18 +27,20 @@ class TestIperfGraphExecutor(testtools.TestCase): def test_get_command(self): executor = iperf.IperfGraphExecutor({}, AGENT) - expected = ('sudo nice -n -20 iperf --client %s --format m --nodelay ' - '--len 8k --time 60 --parallel 1 ' - '--reportstyle C --interval 1') % IP + expected = {'data': ('sudo nice -n -20 iperf --client %s --format m ' + '--nodelay --len 8k --time 60 --parallel 1 ' + '--reportstyle C --interval 1') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) def test_get_command_udp(self): executor = iperf.IperfGraphExecutor( {'udp': True, 'time': 30}, AGENT) - expected = ('sudo nice -n -20 iperf --client %s --format m --nodelay ' - '--len 8k --udp --time 30 --parallel 1 ' - '--reportstyle C --interval 1') % IP + expected = {'data': ('sudo nice -n -20 iperf --client %s --format m ' + '--nodelay --len 8k --udp --time 30 --parallel 1 ' + '--reportstyle C --interval 1') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) def test_process_reply(self): diff --git a/tests/test_netperf_executor.py b/tests/test_netperf_executor.py index ea242f2..d552374 100644 --- a/tests/test_netperf_executor.py +++ b/tests/test_netperf_executor.py @@ -27,12 +27,14 @@ class TestNetperfExecutor(testtools.TestCase): def test_get_command(self): executor = netperf.NetperfExecutor({}, AGENT) - expected = 'netperf -H %s -l 60 -t TCP_STREAM' % IP + expected = {'data': ('netperf -H %s -l 60 -t TCP_STREAM') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) def test_get_command_options(self): executor = netperf.NetperfExecutor( {'method': 'UDP_STREAM', 'time': 30}, AGENT) - expected = 'netperf -H %s -l 30 -t UDP_STREAM' % IP + expected = {'data': ('netperf -H %s -l 30 -t UDP_STREAM') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) diff --git a/tests/test_netperf_wrapper_executor.py b/tests/test_netperf_wrapper_executor.py index ae6f7ae..575951e 100644 --- a/tests/test_netperf_wrapper_executor.py +++ b/tests/test_netperf_wrapper_executor.py @@ -27,14 +27,18 @@ class TestNetperfWrapperExecutor(testtools.TestCase): def test_get_command(self): executor = netperf.NetperfWrapperExecutor({}, AGENT) - expected = 'netperf-wrapper -H %s -l 60 -s 1 -f csv tcp_download' % IP + expected = {'data': ('netperf-wrapper -H %s -l 60 -s 1 ' + '-f csv tcp_download') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) def test_get_command_with_params(self): executor = netperf.NetperfWrapperExecutor( dict(method='ping', time=10, interval=0.5), AGENT) - expected = 'netperf-wrapper -H %s -l 10 -s 0.5 -f csv ping' % IP + expected = {'data': ('netperf-wrapper -H %s -l 10 -s 0.5 ' + '-f csv ping') % IP, + 'type': 'program'} self.assertEqual(expected, executor.get_command()) def test_process_reply(self):