From 729b056da37f21af3a7f5165f6ad98da03804ff6 Mon Sep 17 00:00:00 2001 From: Mohammed Naser Date: Sun, 16 Aug 2020 11:34:47 -0400 Subject: [PATCH] Initial commit --- .dockerignore | 1 + .gitignore | 8 +++ Dockerfile | 22 ++++++ README.rst | 20 ++++++ bindep.txt | 3 + requirements.txt | 5 ++ setup.cfg | 10 +++ setup.py | 19 ++++++ tempest_pushgateway/__init__.py | 116 ++++++++++++++++++++++++++++++++ test-requirements.txt | 2 + tox.ini | 18 +++++ 11 files changed, 224 insertions(+) create mode 120000 .dockerignore create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.rst create mode 100644 bindep.txt create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 tempest_pushgateway/__init__.py create mode 100644 test-requirements.txt create mode 100644 tox.ini diff --git a/.dockerignore b/.dockerignore new file mode 120000 index 0000000..3e4e48b --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.gitignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5dc2f33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.tox +.stestr +.stestr.conf +etc +*.egg-info +__pycache__ +*.pyc +tempest.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5ede654 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# Copyright 2020 VEXXHOST, 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 docker.io/opendevorg/python-builder:3.7 as builder +COPY . /tmp/src +RUN assemble + +FROM docker.io/opendevorg/python-base:3.7 +COPY --from=builder /output/ /output +RUN /output/install-from-bindep && rm -rf /output +ENTRYPOINT ["/usr/local/bin/tempest-pushgateway"] diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..b72fbb1 --- /dev/null +++ b/README.rst @@ -0,0 +1,20 @@ +=================== +Tempest Pushgateway +=================== +Tempest Pushgateway is a small tool which takes a set of OpenStack credentials +using the environment variables, generates a ``tempest.conf`` configuration +file, runs the list of tests provided in the arguments and then pushes the +results to a Prometheus Pushgateway. + +This tool is helpful in running full integration tests against your cloud in +a periodic manner and seeing how long they take and if they passed or failed, +it also means that you can capitalize on all of the existing set of Tempest +integration tests. + +Usage +----- +You can use the Docker container which is published to ``vexxhost/tempest-pushgateway`` +and provide your OpenStack creentials in the environment, alternatively you can +simply install this locally and call ``tempest-pushgateway`` directly. The +only requirement is to set ``TEMPEST_PROMETHEUS`` environment variable to point +towards your Prometheus Pushgateway. diff --git a/bindep.txt b/bindep.txt new file mode 100644 index 0000000..03ab78a --- /dev/null +++ b/bindep.txt @@ -0,0 +1,3 @@ +gcc [compile] +libc6-dev [compile] +libc6 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..768f2d7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +heat-tempest-plugin +prometheus_client +python-tempestconf +tempest +tempest_horizon diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..22116ac --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[metadata] +name = tempest-pushgateway + +[entry_points] +console_scripts = + tempest-pushgateway = tempest_pushgateway:main + +[files] +packages = + tempest_pushgateway diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fd3c007 --- /dev/null +++ b/setup.py @@ -0,0 +1,19 @@ +# Copyright 2020 VEXXHOST, 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. + +import setuptools + +setuptools.setup( + setup_requires=['pbr'], + pbr=True) diff --git a/tempest_pushgateway/__init__.py b/tempest_pushgateway/__init__.py new file mode 100644 index 0000000..c61a7c2 --- /dev/null +++ b/tempest_pushgateway/__init__.py @@ -0,0 +1,116 @@ +# Copyright 2020 VEXXHOST, 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. + +import os +import io +import subprocess +import sys +import tempfile +import testtools + +import prometheus_client +import subunit + + +class PrometheusResult(testtools.TestResult): + + def __init__(self): + super().__init__() + + self._registry = prometheus_client.CollectorRegistry() + self._last_run_result = prometheus_client.Enum( + 'tempest_last_run_result', + 'Result of the last Tempest run', + labelnames=['test'], + states=[ + 'success', + 'failure', + 'error', + 'skip', + 'expectedfailure', + 'unexpectedsucces', + ], + registry=self._registry + ) + self._last_run_unixtime = prometheus_client.Gauge( + 'tempest_last_run_unixtime', + 'Time of the last Tempest test run', + labelnames=['test'], + registry=self._registry + ) + self._last_run_time = prometheus_client.Gauge( + 'tempest_last_run_time', + 'Run-time for the last Tempest run', + labelnames=['test'], + registry=self._registry + ) + + def stopTest(self, test): + start_timestamp = test._timestamps[0].timestamp() + end_timestamp = test._timestamps[1].timestamp() + outcome = test._outcome.replace('add', '').lower() + + if outcome != 'success': + print(test.__dict__) + + labels = { + 'test': test.id(), + } + + self._last_run_unixtime.labels(**labels).set(end_timestamp) + self._last_run_time.labels(**labels).set( + end_timestamp - start_timestamp + ) + self._last_run_result.labels(**labels).state(outcome) + + def stopTestRun(self): + super().stopTestRun() + prometheus_client.push_to_gateway(os.getenv('TEMPEST_PROMETHEUS'), + job='tempest', + registry=self._registry) + + +def main(): + tests = "\n".join(sys.argv[1:]) + + tempest_conf = tempfile.NamedTemporaryFile(mode='w+') + accounts_file = tempfile.NamedTemporaryFile(mode='w+') + + result = subprocess.call([ + 'discover-tempest-config', '--debug', '--non-admin', + '--create-accounts-file', accounts_file.name, + '--out', tempest_conf.name + ]) + if result != 0: + return + + with tempfile.NamedTemporaryFile(mode='w') as whitelist_file: + whitelist_file.write(tests) + whitelist_file.flush() + + result = subprocess.run([ + 'tempest', 'run', '--debug', '--subunit', '--concurrency=1', + '--config-file', tempest_conf.name, + '--whitelist-file', whitelist_file.name + ], capture_output=True) + + stream = io.BytesIO(result.stdout) + + suite = subunit.ByteStreamToStreamResult(stream) + result = testtools.StreamToExtendedDecorator(PrometheusResult()) + result.startTestRun() + try: + suite.run(result) + finally: + result.stopTestRun() diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..897e59f --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +flake8 +pylint diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..7641909 --- /dev/null +++ b/tox.ini @@ -0,0 +1,18 @@ +[testenv] +usedevelop = True +passenv = + OS_* +deps = + -rtest-requirements.txt + -rrequirements.txt + +[testenv:linters] +commands = + pylint tempest_pushgateway + flake8 tempest_pushgateway + +[testenv:run] +deps = + -rrequirements.txt +commands = + tempest-pushgateway {posargs}