Support run cyclictest on BareMetal 33/3633/3
authorQiLiang <liangqi1@huawei.com>
Wed, 25 Nov 2015 01:23:46 +0000 (09:23 +0800)
committerQiLiang <liangqi1@huawei.com>
Sun, 10 Jan 2016 09:59:03 +0000 (09:59 +0000)
JIRA: YARDSTICK-122

Change-Id: I8144215059a9abea08314a4c1e6a733dcdf0df53
Signed-off-by: QiLiang <liangqi1@huawei.com>
samples/cyclictest-node-context.yaml [new file with mode: 0644]
setup.py
tests/unit/benchmark/scenarios/compute/test_cyclictest.py
yardstick/benchmark/scenarios/compute/cyclictest.py
yardstick/ssh.py

diff --git a/samples/cyclictest-node-context.yaml b/samples/cyclictest-node-context.yaml
new file mode 100644 (file)
index 0000000..d74d1e5
--- /dev/null
@@ -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
index 3ef09d1..48f00f4 100755 (executable)
--- 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"
index a87b391..8074290 100644 (file)
@@ -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)
index e8fc63c..478b0a1 100644 (file)
@@ -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()
index 253fd2e..339f834 100644 (file)
@@ -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)