From a33f57371c740e0ab749bfffa4d31c08ef5c5b74 Mon Sep 17 00:00:00 2001 From: QiLiang Date: Wed, 25 Nov 2015 09:23:46 +0800 Subject: [PATCH] Support run cyclictest on BareMetal JIRA: YARDSTICK-122 Change-Id: I8144215059a9abea08314a4c1e6a733dcdf0df53 Signed-off-by: QiLiang --- samples/cyclictest-node-context.yaml | 50 +++++++ setup.py | 1 + .../benchmark/scenarios/compute/test_cyclictest.py | 159 ++++++++++----------- .../benchmark/scenarios/compute/cyclictest.py | 105 ++++++++++++-- yardstick/ssh.py | 7 + 5 files changed, 227 insertions(+), 95 deletions(-) create mode 100644 samples/cyclictest-node-context.yaml diff --git a/samples/cyclictest-node-context.yaml b/samples/cyclictest-node-context.yaml new file mode 100644 index 000000000..d74d1e5e3 --- /dev/null +++ b/samples/cyclictest-node-context.yaml @@ -0,0 +1,50 @@ +--- +# Sample benchmark task config file +# Measure system high resolution by using Cyclictest +# +# For this sample just like running the command below on the test vm and +# getting latencies info back to the yardstick. +# +# sudo bash cyclictest -a 1 -i 1000 -p 99 -l 1000 -t 1 -h 90 -m -n -q +# + +schema: "yardstick:task:0.1" + +scenarios: +- + type: Cyclictest + options: + affinity: 1 + interval: 1000 + priority: 99 + loops: 1000 + threads: 1 + histogram: 90 + host: kvm.LF + runner: + type: Duration + duration: 1 + interval: 1 + sla: + max_min_latency: 50 + max_avg_latency: 100 + max_max_latency: 1000 + action: monitor + setup_options: + rpm_dir: "/opt/rpm" + script_dir: "/opt/scripts" + image_dir: "/opt/image" + host_setup_seqs: + - "host-setup0.sh" + - "reboot" + - "host-setup1.sh" + - "host-run-qemu.sh" + guest_setup_seqs: + - "guest-setup0.sh" + - "reboot" + - "guest-setup1.sh" + +context: + type: Node + name: LF + file: /root/yardstick/pod.yaml diff --git a/setup.py b/setup.py index 3ef09d111..48f00f47c 100755 --- a/setup.py +++ b/setup.py @@ -36,6 +36,7 @@ setup( "mock>=1.0.1", # remove with python3 "paramiko", "netifaces", + "scp", "six", "testrepository>=0.0.18", "testtools>=1.4.0" diff --git a/tests/unit/benchmark/scenarios/compute/test_cyclictest.py b/tests/unit/benchmark/scenarios/compute/test_cyclictest.py index a87b39142..807429025 100644 --- a/tests/unit/benchmark/scenarios/compute/test_cyclictest.py +++ b/tests/unit/benchmark/scenarios/compute/test_cyclictest.py @@ -22,41 +22,65 @@ from yardstick.benchmark.scenarios.compute import cyclictest class CyclictestTestCase(unittest.TestCase): def setUp(self): - self.ctx = { + self.scenario_cfg = { + "host": "kvm.LF", + "setup_options": { + "rpm_dir": "/opt/rpm", + "host_setup_seqs": [ + "host-setup0.sh", + "host-setup1.sh", + "host-run-qemu.sh" + ], + "script_dir": "/opt/scripts", + "image_dir": "/opt/image", + "guest_setup_seqs": [ + "guest-setup0.sh", + "guest-setup1.sh" + ] + }, + "sla": { + "action": "monitor", + "max_min_latency": 50, + "max_avg_latency": 100, + "max_max_latency": 1000 + }, + "options": { + "priority": 99, + "threads": 1, + "loops": 1000, + "affinity": 1, + "interval": 1000, + "histogram": 90 + } + } + self.context_cfg = { "host": { - "ip": "192.168.50.28", - "user": "root", - "key_filename": "mykey.key" + "ip": "10.229.43.154", + "key_filename": "/yardstick/resources/files/yardstick_key", + "role": "BareMetal", + "name": "kvm.LF", + "user": "root" } } def test_cyclictest_successful_setup(self, mock_ssh): - c = cyclictest.Cyclictest({}, self.ctx) - c.setup() - + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) mock_ssh.SSH().execute.return_value = (0, '', '') - self.assertIsNotNone(c.client) + + c.setup() + self.assertIsNotNone(c.guest) + self.assertIsNotNone(c.host) self.assertEqual(c.setup_done, True) def test_cyclictest_successful_no_sla(self, mock_ssh): - - options = { - "affinity": 2, - "interval": 100, - "priority": 88, - "loops": 10000, - "threads": 2, - "histogram": 80 - } - args = { - "options": options, - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.pop("sla", None) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() - + c.guest = mock_ssh.SSH() sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') @@ -65,29 +89,19 @@ class CyclictestTestCase(unittest.TestCase): self.assertEqual(result, expected_result) def test_cyclictest_successful_sla(self, mock_ssh): - - options = { - "affinity": 2, - "interval": 100, - "priority": 88, - "loops": 10000, - "threads": 2, - "histogram": 80 - } - sla = { - "max_min_latency": 100, - "max_avg_latency": 500, - "max_max_latency": 1000, - } - args = { - "options": options, - "sla": sla - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.update({"sla": { + "action": "monitor", + "max_min_latency": 100, + "max_avg_latency": 500, + "max_max_latency": 1000 + } + }) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() - + c.guest = mock_ssh.SSH() sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') @@ -97,14 +111,13 @@ class CyclictestTestCase(unittest.TestCase): def test_cyclictest_unsuccessful_sla_min_latency(self, mock_ssh): - args = { - "options": {}, - "sla": {"max_min_latency": 10} - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.update({"sla": {"max_min_latency": 10}}) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() + c.guest = mock_ssh.SSH() sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') @@ -112,14 +125,13 @@ class CyclictestTestCase(unittest.TestCase): def test_cyclictest_unsuccessful_sla_avg_latency(self, mock_ssh): - args = { - "options": {}, - "sla": {"max_avg_latency": 10} - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.update({"sla": {"max_avg_latency": 10}}) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() + c.guest = mock_ssh.SSH() sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') @@ -127,14 +139,13 @@ class CyclictestTestCase(unittest.TestCase): def test_cyclictest_unsuccessful_sla_max_latency(self, mock_ssh): - args = { - "options": {}, - "sla": {"max_max_latency": 10} - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.update({"sla": {"max_max_latency": 10}}) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() + c.guest = mock_ssh.SSH() sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') @@ -142,27 +153,13 @@ class CyclictestTestCase(unittest.TestCase): def test_cyclictest_unsuccessful_script_error(self, mock_ssh): - options = { - "affinity": 2, - "interval": 100, - "priority": 88, - "loops": 10000, - "threads": 2, - "histogram": 80 - } - sla = { - "max_min_latency": 100, - "max_avg_latency": 500, - "max_max_latency": 1000, - } - args = { - "options": options, - "sla": sla - } - c = cyclictest.Cyclictest(args, self.ctx) result = {} + self.scenario_cfg.update({"sla": {"max_max_latency": 10}}) + c = cyclictest.Cyclictest(self.scenario_cfg, self.context_cfg) + mock_ssh.SSH().execute.return_value = (0, '', '') + c.setup() - c.server = mock_ssh.SSH() + c.guest = mock_ssh.SSH() mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, c.run, result) diff --git a/yardstick/benchmark/scenarios/compute/cyclictest.py b/yardstick/benchmark/scenarios/compute/cyclictest.py index e8fc63cf7..478b0a1a2 100644 --- a/yardstick/benchmark/scenarios/compute/cyclictest.py +++ b/yardstick/benchmark/scenarios/compute/cyclictest.py @@ -9,6 +9,9 @@ import pkg_resources import logging import json +import re +import time +import os import yardstick.ssh as ssh from yardstick.benchmark.scenarios import base @@ -53,30 +56,104 @@ class Cyclictest(base.Scenario): __scenario_type__ = "Cyclictest" TARGET_SCRIPT = "cyclictest_benchmark.bash" + WORKSPACE = "/root/workspace/" + REBOOT_CMD_PATTERN = r";\s*reboot\b" def __init__(self, scenario_cfg, context_cfg): self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg self.setup_done = False - def setup(self): - '''scenario setup''' - self.target_script = pkg_resources.resource_filename( - "yardstick.benchmark.scenarios.compute", - Cyclictest.TARGET_SCRIPT) + def _put_files(self, client): + setup_options = self.scenario_cfg["setup_options"] + rpm_dir = setup_options["rpm_dir"] + script_dir = setup_options["script_dir"] + image_dir = setup_options["image_dir"] + LOG.debug("Send RPMs from %s to workspace %s" % + (rpm_dir, self.WORKSPACE)) + client.put(rpm_dir, self.WORKSPACE, recursive=True) + LOG.debug("Send scripts from %s to workspace %s" % + (script_dir, self.WORKSPACE)) + client.put(script_dir, self.WORKSPACE, recursive=True) + LOG.debug("Send guest image from %s to workspace %s" % + (image_dir, self.WORKSPACE)) + client.put(image_dir, self.WORKSPACE, recursive=True) + + def _connect_host(self): + host = self.context_cfg["host"] + user = host.get("user", "root") + ip = host.get("ip", None) + key_filename = host.get("key_filename", "~/.ssh/id_rsa") + + LOG.debug("user:%s, host:%s", user, ip) + self.host = ssh.SSH(user, ip, key_filename=key_filename) + self.host.wait(timeout=600) + + def _connect_guest(self): host = self.context_cfg["host"] user = host.get("user", "root") ip = host.get("ip", None) key_filename = host.get("key_filename", "~/.ssh/id_rsa") LOG.debug("user:%s, host:%s", user, ip) - print "key_filename:" + key_filename - self.client = ssh.SSH(user, ip, key_filename=key_filename) - self.client.wait(timeout=600) + self.guest = ssh.SSH(user, ip, port=5555, key_filename=key_filename) + self.guest.wait(timeout=600) + + def _run_setup_cmd(self, client, cmd): + LOG.debug("Run cmd: %s" % cmd) + status, stdout, stderr = client.execute(cmd) + if status: + if re.search(self.REBOOT_CMD_PATTERN, cmd): + LOG.debug("Error on reboot") + else: + raise RuntimeError(stderr) + + def _run_host_setup_scripts(self, scripts): + setup_options = self.scenario_cfg["setup_options"] + script_dir = os.path.basename(setup_options["script_dir"]) + + for script in scripts: + cmd = "cd %s/%s; export PATH=./:$PATH; %s" %\ + (self.WORKSPACE, script_dir, script) + self._run_setup_cmd(self.host, cmd) + + if re.search(self.REBOOT_CMD_PATTERN, cmd): + time.sleep(3) + self._connect_host() + + def _run_guest_setup_scripts(self, scripts): + setup_options = self.scenario_cfg["setup_options"] + script_dir = os.path.basename(setup_options["script_dir"]) + + for script in scripts: + cmd = "cd %s/%s; export PATH=./:$PATH; %s" %\ + (self.WORKSPACE, script_dir, script) + self._run_setup_cmd(self.guest, cmd) + + if re.search(self.REBOOT_CMD_PATTERN, cmd): + time.sleep(3) + self._connect_guest() + + def setup(self): + '''scenario setup''' + setup_options = self.scenario_cfg["setup_options"] + host_setup_seqs = setup_options["host_setup_seqs"] + guest_setup_seqs = setup_options["guest_setup_seqs"] + + self._connect_host() + self._put_files(self.host) + self._run_host_setup_scripts(host_setup_seqs) + + self._connect_guest() + self._put_files(self.guest) + self._run_guest_setup_scripts(guest_setup_seqs) # copy script to host - self.client.run("cat > ~/cyclictest_benchmark.sh", - stdin=open(self.target_script, "rb")) + self.target_script = pkg_resources.resource_filename( + "yardstick.benchmark.scenarios.compute", + Cyclictest.TARGET_SCRIPT) + self.guest.run("cat > ~/cyclictest_benchmark.sh", + stdin=open(self.target_script, "rb")) self.setup_done = True @@ -98,9 +175,9 @@ class Cyclictest(base.Scenario): cmd_args = "-a %s -i %s -p %s -l %s -t %s -h %s %s" \ % (affinity, interval, priority, loops, threads, histogram, default_args) - cmd = "sudo bash cyclictest_benchmark.sh %s" % (cmd_args) + cmd = "bash cyclictest_benchmark.sh %s" % (cmd_args) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) + status, stdout, stderr = self.guest.execute(cmd) if status: raise RuntimeError(stderr) @@ -121,7 +198,7 @@ class Cyclictest(base.Scenario): assert sla_error == "", sla_error -def _test(): +def _test(): # pragma: no cover '''internal test function''' key_filename = pkg_resources.resource_filename("yardstick.resources", "files/yardstick_key") @@ -159,5 +236,5 @@ def _test(): cyclictest.run(result) print result -if __name__ == '__main__': +if __name__ == '__main__': # pragma: no cover _test() diff --git a/yardstick/ssh.py b/yardstick/ssh.py index 253fd2e3d..339f834b7 100644 --- a/yardstick/ssh.py +++ b/yardstick/ssh.py @@ -63,6 +63,7 @@ import socket import time import paramiko +from scp import SCPClient import six import logging @@ -254,3 +255,9 @@ class SSH(object): time.sleep(interval) if time.time() > (start_time + timeout): raise SSHTimeout("Timeout waiting for '%s'" % self.host) + + def put(self, files, remote_path=b'.', recursive=False): + client = self._get_client() + + with SCPClient(client.get_transport()) as scp: + scp.put(files, remote_path, recursive) -- 2.16.6