From 5f9ddd6dba022aadf21c592b9125475af028de0f Mon Sep 17 00:00:00 2001 From: Major Hayden Date: Tue, 21 Feb 2017 11:25:27 -0500 Subject: [PATCH] Proof of concept --- .coveragerc | 3 + .travis.yml | 24 +++++++ AUTHORS | 1 + ChangeLog | 7 ++ README.md | 2 - README.rst | 6 ++ monitorstack/__init__.py | 0 monitorstack/cli.py | 113 +++++++++++++++++++++++++++++++ monitorstack/plugins/__init__.py | 0 monitorstack/plugins/uptime.py | 34 ++++++++++ requirements.txt | 3 + setup.cfg | 28 ++++++++ setup.py | 29 ++++++++ test-requirements.txt | 2 + tests/test_uptime.py | 32 +++++++++ tox.ini | 32 +++++++++ 16 files changed, 314 insertions(+), 2 deletions(-) create mode 100644 .coveragerc create mode 100644 .travis.yml create mode 100644 AUTHORS create mode 100644 ChangeLog delete mode 100644 README.md create mode 100644 README.rst create mode 100644 monitorstack/__init__.py create mode 100755 monitorstack/cli.py create mode 100644 monitorstack/plugins/__init__.py create mode 100644 monitorstack/plugins/uptime.py create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 test-requirements.txt create mode 100644 tests/test_uptime.py create mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..45d651d --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[run] +branch = True +source = monitorstack diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..be57266 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,24 @@ +sudo: false +language: python +cache: pip +matrix: + include: + - python: "2.7" + env: TOXENV=py27 + - python: "3.3" + env: TOXENV=py33 + - python: "3.4" + env: TOXENV=py34 + - python: "pypy" + env: TOXENV=pypy + - python: 2.7 + env: TOXENV=pep8 + - python: 3.3 + env: TOXENV=py3pep8 +before_install: + pip install codecov +after_success: + codecov +install: + - "pip install tox" +script: "tox" diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..a42a9eb --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Major Hayden diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..9117a79 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,7 @@ +CHANGES +======= + +* Uptime class +* Update README +* Import +* Initial commit diff --git a/README.md b/README.md deleted file mode 100644 index 2fcfddf..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# monitorstack -Monitoring plugins for OpenStack diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..3d31234 --- /dev/null +++ b/README.rst @@ -0,0 +1,6 @@ +monitorstack +============ + +Monitoring plugins for OpenStack. + +*Work in progress.* diff --git a/monitorstack/__init__.py b/monitorstack/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monitorstack/cli.py b/monitorstack/cli.py new file mode 100755 index 0000000..2cc1529 --- /dev/null +++ b/monitorstack/cli.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# Copyright 2017, Major Hayden +# +# 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. +"""Handle all shell commands/arguments/options.""" +import json +import os +import sys + + +import click + + +CONTEXT_SETTINGS = dict(auto_envvar_prefix='MonitorStack') + + +class Context(object): + """Set up a context object that we can pass.""" + + def __init__(self): + """Initialize class.""" + self.verbose = False + self.home = os.getcwd() + + def log(self, msg, *args): + """Log a message to stderr.""" + if args: + msg %= args + click.echo(msg, file=sys.stderr) + + def vlog(self, msg, *args): + """Log a message to stderr only if verbose is enabled.""" + if self.verbose: + self.log(msg, *args) + + +pass_context = click.make_pass_decorator(Context, ensure=True) +cmd_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), + 'plugins')) + + +class MonitorStackCLI(click.MultiCommand): + """Create a complex command finder.""" + + def list_commands(self, ctx): + """Get a list of all available commands.""" + rv = [] + for filename in os.listdir(cmd_folder): + if filename.endswith('.py') and not filename.startswith('__'): + rv.append(filename[:-3]) + rv.sort() + return rv + + def get_command(self, ctx, name): + """Load a command and run it.""" + try: + if sys.version_info[0] == 2: + name = name.encode('ascii', 'replace') + mod = __import__('monitorstack.plugins.' + name, + None, None, ['cli']) + except ImportError: + return + return mod.cli + + +VALID_OUTPUT_FORMATS = [ + 'json', + 'line', +] + + +@click.command(cls=MonitorStackCLI, context_settings=CONTEXT_SETTINGS) +@click.option( + '-f', '--format', 'output_format', + type=click.Choice(VALID_OUTPUT_FORMATS), + default='json', + help="Output format (valid options: {}".format( + ', '.join(VALID_OUTPUT_FORMATS) + ), +) +@click.option('-v', '--verbose', is_flag=True, help='Enables verbose mode.') +@pass_context +def cli(ctx, output_format, verbose): + """A complex command line interface.""" + ctx.verbose = verbose + pass + + +@cli.resultcallback(replace=True) +def process_result(result, output_format, verbose): + """Render the output into the proper format.""" + if output_format == 'json': + click.echo(json.dumps(result, indent=2)) + + elif output_format == 'line': + for key, value in result['variables'].items(): + click.echo("{} {}".format(key, value)) + + elif output_format == 'csv': + pass + +if __name__ == '__main__': + cli() diff --git a/monitorstack/plugins/__init__.py b/monitorstack/plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monitorstack/plugins/uptime.py b/monitorstack/plugins/uptime.py new file mode 100644 index 0000000..635761d --- /dev/null +++ b/monitorstack/plugins/uptime.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright 2017, Major Hayden +# +# 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. +"""Base monitoring class.""" +import click +from monitorstack.cli import pass_context + + +@click.command('uptime', short_help='Get system uptime') +@pass_context +def cli(ctx): + """Get system uptime.""" + with open('/proc/uptime', 'r') as f: + output = f.read() + uptime = output.split()[0] + output = { + 'exit_code': 0, + 'message': 'uptime is ok', + 'variables': { + 'uptime': uptime + } + } + return output diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..85e142c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +click +six +stevedore diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..02c2cbf --- /dev/null +++ b/setup.cfg @@ -0,0 +1,28 @@ +[metadata] +name = monitorstack +summary = Monitoring plugins for OpenStack +description-file = + README.rst +author = Major Hayden +author-email = major@mhtx.net +home-page = https://github.com/major/monitorstack +classifier = + Environment :: OpenStack + Intended Audience :: Information Technology + Intended Audience :: System Administrators + License :: OSI Approved :: Apache Software License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 + +[files] +packages = + monitorstack + +[entry_points] +console_scripts = + monitorstack = monitorstack.cli:cli diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..782bb21 --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# 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. + +# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT +import setuptools + +# In python < 2.7.4, a lazy loading of package `pbr` will break +# setuptools if some other modules registered functions in `atexit`. +# solution from: http://bugs.python.org/issue15881#msg170215 +try: + import multiprocessing # noqa +except ImportError: + pass + +setuptools.setup( + setup_requires=['pbr>=1.8'], + pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..5bbae8f --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +pytest +tox diff --git a/tests/test_uptime.py b/tests/test_uptime.py new file mode 100644 index 0000000..f9758cf --- /dev/null +++ b/tests/test_uptime.py @@ -0,0 +1,32 @@ +# Copyright 2017, Major Hayden +# +# 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. +"""Tests for the base class.""" +import click +from click.testing import CliRunner +import json + + +from monitorstack.cli import cli + + +class TestUptime(object): + """Tests for the uptime monitor class.""" + + def test_run(self): + """Ensure the run() method works.""" + runner = CliRunner() + result = runner.invoke(cli, ['-f', 'json', 'uptime']) + result_json = json.loads(result.output) + assert 'uptime' in result_json['variables'] + assert result.exit_code == 0 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..6dbb208 --- /dev/null +++ b/tox.ini @@ -0,0 +1,32 @@ +[tox] +envlist = {pypy,pep8,py3pep8,py26,py27,py33,py34} + +[testenv] +deps = + coverage + -rrequirements.txt + -rtest-requirements.txt +setenv = +commands = + coverage run -m pytest --capture=no --strict {posargs} + coverage report -m --omit="*/test*" + +[testenv:pep8] +deps = + flake8 + flake8-import-order + pep8-naming +commands = + flake8 . + +[testenv:py3pep8] +basepython = python3.3 +deps = + flake8 + flake8-import-order + pep8-naming +commands = + flake8 . + +[flake8] +exclude = .tox,*.egg,.git,_build,docs-rst