commit 729b056da37f21af3a7f5165f6ad98da03804ff6 Author: Mohammed Naser Date: Sun Aug 16 11:34:47 2020 -0400 Initial commit 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}