summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Beierl <mark.beierl@emc.com>2016-05-12 10:05:25 -0600
committerMark Beierl <mark.beierl@emc.com>2016-05-12 10:35:49 -0600
commitd0f40c056a9283f30df45da5d35b72ce79b5d9a0 (patch)
treea0ece870394afa7eb1f936b2cf3a8c4583853d4f
parent4e7e1d2ffea89950ae516a19997765daccf92664 (diff)
Results DB Reporting
Add the ability to push results to the test result db. If the environment variable TEST_DB_URL is defined, results will be pushed there. If not, no push is attempted. Change-Id: Ib833530d7379c5f37f0d2904a83d31a4ee559ae6 JIRA: STORPERF-13 Signed-off-by: Mark Beierl <mark.beierl@emc.com>
-rw-r--r--storperf/db/job_db.py7
-rw-r--r--storperf/db/test_results_db.py56
-rw-r--r--storperf/plot/barchart.py2
-rw-r--r--storperf/storperf_master.py5
-rw-r--r--storperf/test_executor.py68
-rw-r--r--storperf/tests/db_tests/graphite_db_test.py14
-rw-r--r--storperf/tests/db_tests/job_db_test.py7
-rw-r--r--storperf/tests/utilities/__init__.py8
-rw-r--r--storperf/tests/utilities/dictionary.py42
-rw-r--r--storperf/utilities/__init__.py8
-rw-r--r--storperf/utilities/dictionary.py15
11 files changed, 217 insertions, 15 deletions
diff --git a/storperf/db/job_db.py b/storperf/db/job_db.py
index 412c6bc..3d66be8 100644
--- a/storperf/db/job_db.py
+++ b/storperf/db/job_db.py
@@ -201,9 +201,12 @@ class JobDB(object):
return workload_executions
- def record_workload_params(self, job_id, params):
+ def record_workload_params(self, params):
"""
"""
+ if (self.job_id is None):
+ self.create_job_id()
+
with db_mutex:
db = sqlite3.connect(JobDB.db_name)
@@ -215,7 +218,7 @@ class JobDB(object):
param,
value)
values (?, ?, ?)""",
- (job_id,
+ (self.job_id,
param,
value,))
db.commit()
diff --git a/storperf/db/test_results_db.py b/storperf/db/test_results_db.py
new file mode 100644
index 0000000..8636e52
--- /dev/null
+++ b/storperf/db/test_results_db.py
@@ -0,0 +1,56 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import json
+import requests
+import os
+
+
+def get_installer_type(logger=None):
+ """
+ Get installer type (fuel, apex, joid, compass)
+ """
+ try:
+ installer = os.environ['INSTALLER_TYPE']
+ except KeyError:
+ if logger:
+ logger.error("Impossible to retrieve the installer type")
+ installer = "Unknown_installer"
+
+ return installer
+
+
+def push_results_to_db(db_url, project, case_name, logger, pod_name,
+ version, scenario, criteria, build_tag, payload):
+ """
+ POST results to the Result target DB
+ """
+ url = db_url + "/results"
+ installer = get_installer_type(logger)
+ params = {"project_name": project, "case_name": case_name,
+ "pod_name": pod_name, "installer": installer,
+ "version": version, "scenario": scenario, "criteria": criteria,
+ "build_tag": build_tag, "details": payload}
+
+ headers = {'Content-Type': 'application/json'}
+ try:
+ if logger:
+ logger.debug("Pushing results to %s" % (url))
+ r = requests.post(url, data=json.dumps(params), headers=headers)
+ if logger:
+ logger.debug(r)
+ logger.debug(r.status_code)
+ logger.debug(r.content)
+ return True
+ except Exception, e:
+ logger.error("Error [push_results_to_db('%s', '%s', '%s', " +
+ "'%s', '%s', '%s', '%s', '%s', '%s')]:" %
+ (db_url, project, case_name, pod_name, version,
+ scenario, criteria, build_tag, payload), e)
+ return False
diff --git a/storperf/plot/barchart.py b/storperf/plot/barchart.py
index 871defa..6fcfd8d 100644
--- a/storperf/plot/barchart.py
+++ b/storperf/plot/barchart.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2015 EMC and others.
+# Copyright (c) 2016 EMC and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
diff --git a/storperf/storperf_master.py b/storperf/storperf_master.py
index 0f86a95..395a2ab 100644
--- a/storperf/storperf_master.py
+++ b/storperf/storperf_master.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2015 EMC and others.
+# Copyright (c) 2016 EMC and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -312,13 +312,12 @@ class StorPerfMaster(object):
thread.join()
self._test_executor.slaves = slaves
- job_id = self._test_executor.execute()
params = metadata
params['agent_count'] = self.agent_count
params['public_network'] = self.public_network
params['volume_size'] = self.volume_size
- self.job_db.record_workload_params(job_id, params)
+ job_id = self._test_executor.execute(params)
return job_id
diff --git a/storperf/test_executor.py b/storperf/test_executor.py
index 8230174..592c33d 100644
--- a/storperf/test_executor.py
+++ b/storperf/test_executor.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2015 EMC and others.
+# Copyright (c) 2016 EMC and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -11,8 +11,11 @@ from os import listdir
from os.path import isfile, join
from storperf.carbon.converter import Converter
from storperf.carbon.emitter import CarbonMetricTransmitter
+from storperf.db import test_results_db
+from storperf.db.graphite_db import GraphiteDB
from storperf.db.job_db import JobDB
from storperf.fio.fio_invoker import FIOInvoker
+from storperf.utilities import dictionary
from threading import Thread
import copy
import imp
@@ -35,6 +38,7 @@ class TestExecutor(object):
self.precondition = True
self.deadline = None
self.warm = True
+ self.metadata = None
self._queue_depths = [1, 4, 8]
self._block_sizes = [512, 4096, 16384]
self.event_listeners = set()
@@ -138,9 +142,12 @@ class TestExecutor(object):
return imp.load_source(mname, no_ext + '.py')
return None
- def execute(self):
+ def execute(self, metadata):
self.job_db.create_job_id()
- self._workload_thread = Thread(target=self.execute_workloads, args=())
+ self.job_db.record_workload_params(metadata)
+ self.metadata = metadata
+ self._workload_thread = Thread(target=self.execute_workloads,
+ args=())
self._workload_thread.start()
return self.job_db.job_id
@@ -158,8 +165,14 @@ class TestExecutor(object):
def execute_workloads(self):
self._terminated = False
+ self.logger.info("Starting job %s" % (self.job_db.job_id))
+
+ start_time = time.time()
+
for workload_module in self.workload_modules:
workload_name = getattr(workload_module, "__name__")
+ self.logger.info("Starting workload %s" % (workload_name))
+
constructorMethod = getattr(workload_module, workload_name)
workload = constructorMethod()
if (self.filename is not None):
@@ -215,6 +228,55 @@ class TestExecutor(object):
self._workload_executors = []
+ self.logger.info("Completed workload %s" % (workload_name))
+ self.logger.info("Completed job %s" % (self.job_db.job_id))
+ end_time = time.time()
+ pod_name = dictionary.get_key_from_dict(self.metadata,
+ 'pod_name',
+ 'Unknown')
+ version = dictionary.get_key_from_dict(self.metadata,
+ 'version',
+ 'Unknown')
+ scenario = dictionary.get_key_from_dict(self.metadata,
+ 'scenario',
+ 'Unknown')
+ build_tag = dictionary.get_key_from_dict(self.metadata,
+ 'build_tag',
+ 'Unknown')
+ duration = end_time - start_time
+ test_db = os.environ.get('TEST_DB_URL')
+
+ if test_db is not None:
+ # I really do not like doing this. As our threads just
+ # terminated, their final results are still being spooled
+ # off to Carbon. Need to give that a little time to finish
+ time.sleep(5)
+ self.logger.info("Pushing results to %s" % (test_db))
+
+ payload = self.metadata
+ payload['timestart'] = start_time
+ payload['duration'] = duration
+ payload['status'] = 'OK'
+ graphite_db = GraphiteDB()
+ payload['metrics'] = graphite_db.fetch_averages(self.job_db.job_id)
+ criteria = {}
+ criteria['block_sizes'] = self.block_sizes
+ criteria['queue_depths'] = self.block_sizes
+
+ try:
+ test_results_db.push_results_to_db(test_db,
+ "storperf",
+ "Latency Test",
+ self.logger,
+ pod_name,
+ version,
+ scenario,
+ criteria,
+ build_tag,
+ payload)
+ except:
+ self.logger.exception("Error pushing results into Database")
+
def execute_on_node(self, workload):
invoker = FIOInvoker()
diff --git a/storperf/tests/db_tests/graphite_db_test.py b/storperf/tests/db_tests/graphite_db_test.py
index ce970bb..e13545b 100644
--- a/storperf/tests/db_tests/graphite_db_test.py
+++ b/storperf/tests/db_tests/graphite_db_test.py
@@ -1,5 +1,13 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
from storperf.db.graphite_db import GraphiteDB
-import this
import unittest
@@ -9,13 +17,13 @@ class GraphiteDBTest(unittest.TestCase):
self.graphdb = GraphiteDB()
self.graphdb._job_db = self
- def test_wilcard_pattern(self):
+ def test_wildcard_pattern(self):
workload = "job_id"
expected = "job_id.*.*.*.*.*.*"
actual = self.graphdb.make_fullname_pattern(workload)
self.assertEqual(expected, actual, actual)
- def test_no_wilcard_pattern(self):
+ def test_no_wildcard_pattern(self):
workload = "job_id.workload.host.queue-depth.1.block-size.16"
actual = self.graphdb.make_fullname_pattern(workload)
self.assertEqual(workload, actual, actual)
diff --git a/storperf/tests/db_tests/job_db_test.py b/storperf/tests/db_tests/job_db_test.py
index 0972f84..fe3d9f1 100644
--- a/storperf/tests/db_tests/job_db_test.py
+++ b/storperf/tests/db_tests/job_db_test.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2015 EMC and others.
+# Copyright (c) 2016 EMC and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -186,6 +186,7 @@ class JobDBTest(unittest.TestCase):
def test_job_params(self):
expected = {"a": "1", "b": "2"}
- self.job.record_workload_params("ABCD", expected)
- actual = self.job.fetch_workload_params("ABCD")
+ self.job.job_id = "ABCD"
+ self.job.record_workload_params(expected)
+ actual = self.job.fetch_workload_params(self.job.job_id)
self.assertEqual(expected, actual)
diff --git a/storperf/tests/utilities/__init__.py b/storperf/tests/utilities/__init__.py
new file mode 100644
index 0000000..73444b6
--- /dev/null
+++ b/storperf/tests/utilities/__init__.py
@@ -0,0 +1,8 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
diff --git a/storperf/tests/utilities/dictionary.py b/storperf/tests/utilities/dictionary.py
new file mode 100644
index 0000000..0819cef
--- /dev/null
+++ b/storperf/tests/utilities/dictionary.py
@@ -0,0 +1,42 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import unittest
+from storperf.utilities import dictionary
+
+
+class DictionaryTest(unittest.TestCase):
+
+ def setUp(self):
+ self.dictionary = {}
+ self.dictionary['key'] = 'value'
+ pass
+
+ def test_get_no_default(self):
+ expected = None
+ actual = dictionary.get_key_from_dict(self.dictionary, 'no-key')
+ self.assertEqual(expected, actual)
+
+ def test_get_with_default(self):
+ expected = 'value 2'
+ actual = dictionary.get_key_from_dict(
+ self.dictionary, 'no-key', expected)
+ self.assertEqual(expected, actual)
+
+ def test_get_with_value(self):
+ expected = 'value'
+ actual = dictionary.get_key_from_dict(
+ self.dictionary, 'key')
+ self.assertEqual(expected, actual)
+
+ def test_get_with_value_and_default(self):
+ expected = 'value'
+ actual = dictionary.get_key_from_dict(
+ self.dictionary, 'key', 'value 2')
+ self.assertEqual(expected, actual)
diff --git a/storperf/utilities/__init__.py b/storperf/utilities/__init__.py
new file mode 100644
index 0000000..73444b6
--- /dev/null
+++ b/storperf/utilities/__init__.py
@@ -0,0 +1,8 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
diff --git a/storperf/utilities/dictionary.py b/storperf/utilities/dictionary.py
new file mode 100644
index 0000000..95f625c
--- /dev/null
+++ b/storperf/utilities/dictionary.py
@@ -0,0 +1,15 @@
+##############################################################################
+# Copyright (c) 2016 EMC and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+def get_key_from_dict(dictionary, key, default_value=None):
+ if key in dictionary:
+ return dictionary[key]
+ else:
+ return default_value