parent
3114e7a123
commit
c3a396daba
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2017, Major Hayden <major@mhtx.net>
|
||||
#
|
||||
# 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 an __init__.py."""
|
|
@ -51,7 +51,6 @@ class MonitorStackCLI(click.MultiCommand):
|
|||
@property
|
||||
def cmd_folder(self):
|
||||
"""Get the path to the plugin directory."""
|
||||
|
||||
return os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
|
@ -61,7 +60,6 @@ class MonitorStackCLI(click.MultiCommand):
|
|||
|
||||
def list_commands(self, ctx):
|
||||
"""Get a list of all available commands."""
|
||||
|
||||
rv = list()
|
||||
for _, pkg_name, _ in pkgutil.iter_modules([self.cmd_folder]):
|
||||
rv.append(pkg_name)
|
||||
|
@ -70,7 +68,6 @@ class MonitorStackCLI(click.MultiCommand):
|
|||
|
||||
def get_command(self, ctx, name):
|
||||
"""Load a command and run it."""
|
||||
|
||||
for _, pkg_name, _ in pkgutil.iter_modules([self.cmd_folder]):
|
||||
if pkg_name == name:
|
||||
mod = importlib.import_module(
|
||||
|
@ -102,7 +99,6 @@ VALID_OUTPUT_FORMATS = [
|
|||
@pass_context
|
||||
def cli(ctx, output_format, verbose):
|
||||
"""A complex command line interface."""
|
||||
|
||||
ctx.verbose = verbose
|
||||
pass
|
||||
|
||||
|
@ -110,7 +106,6 @@ def cli(ctx, output_format, verbose):
|
|||
@cli.resultcallback(replace=True)
|
||||
def process_result(result, output_format, verbose):
|
||||
"""Render the output into the proper format."""
|
||||
|
||||
module_name = 'monitorstack.common.formatters'
|
||||
method_name = 'write_{}'.format(output_format)
|
||||
output_formatter = getattr(
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2017, Major Hayden <major@mhtx.net>
|
||||
#
|
||||
# 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 an __init__.py."""
|
|
@ -20,7 +20,6 @@ import click
|
|||
|
||||
def write_json(result):
|
||||
"""Output in raw JSON format."""
|
||||
|
||||
output = json.dumps(result, indent=2)
|
||||
click.echo(output)
|
||||
return True
|
||||
|
@ -28,7 +27,6 @@ def write_json(result):
|
|||
|
||||
def write_line(result):
|
||||
"""Output in line format."""
|
||||
|
||||
for key, value in result['variables'].items():
|
||||
click.echo("{} {}".format(key, value))
|
||||
|
||||
|
@ -37,13 +35,11 @@ def write_line(result):
|
|||
|
||||
def _current_time():
|
||||
"""Return the current time in nanoseconds."""
|
||||
|
||||
return int(time.time() * 1000000000)
|
||||
|
||||
|
||||
def _telegraf_line_format(sets, quote=False):
|
||||
"""Return a comma separated string."""
|
||||
|
||||
store = list()
|
||||
for k, v in sets.items():
|
||||
k = k.replace(' ', '_')
|
||||
|
@ -63,7 +59,6 @@ def _telegraf_line_format(sets, quote=False):
|
|||
|
||||
def write_telegraf(result):
|
||||
"""Output in telegraf format."""
|
||||
|
||||
resultant = [result['measurement_name']]
|
||||
if 'meta' in result:
|
||||
resultant.append(_telegraf_line_format(sets=result['meta']))
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2017, Major Hayden <major@mhtx.net>
|
||||
#
|
||||
# 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 an __init__.py."""
|
|
@ -11,7 +11,7 @@
|
|||
# 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.
|
||||
"""Plugin for KVM metrics."""
|
||||
"""Get metrics from a KVM hypervisor."""
|
||||
|
||||
import platform
|
||||
import socket
|
||||
|
@ -21,12 +21,14 @@ import click
|
|||
from monitorstack.cli import pass_context
|
||||
|
||||
|
||||
DOC = """Get metrics from a KVM hypervisor"""
|
||||
DOC = """Get metrics from a KVM hypervisor."""
|
||||
COMMAND = 'kvm'
|
||||
|
||||
|
||||
@click.command('kvm', short_help=DOC.split('\n')[0])
|
||||
@click.command(COMMAND, short_help=DOC.split('\n')[0])
|
||||
@pass_context
|
||||
def cli(ctx):
|
||||
"""Get metrics from a KVM hypervisor."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
# Lower level import because we only want to load this module
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get nova instance quotas."""
|
||||
|
||||
import click
|
||||
|
||||
|
@ -29,6 +30,7 @@ COMMAND_NAME = 'os_vm_quota_instance'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova instance quotas."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get nova ram quotas."""
|
||||
|
||||
import click
|
||||
|
||||
|
@ -29,6 +30,7 @@ COMMAND_NAME = 'os_vm_quota_ram'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova ram quotas."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get the number of cores used by this tenant."""
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -31,6 +32,7 @@ COMMAND_NAME = 'os_vm_used_cores'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova used cores."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get nova used disk."""
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -31,6 +32,7 @@ COMMAND_NAME = 'os_vm_used_disk'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova used disk."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get nova used instances."""
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -31,6 +32,7 @@ COMMAND_NAME = 'os_vm_used_instance'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova used instances."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Get nova used ram."""
|
||||
|
||||
import collections
|
||||
|
||||
|
@ -31,6 +32,7 @@ COMMAND_NAME = 'os_vm_used_ram'
|
|||
default='openstack.ini')
|
||||
@pass_context
|
||||
def cli(ctx, config_file):
|
||||
"""Get nova used ram."""
|
||||
setattr(cli, '__doc__', DOC)
|
||||
|
||||
output = {
|
||||
|
|
|
@ -19,12 +19,14 @@ import click
|
|||
|
||||
from monitorstack.cli import pass_context
|
||||
|
||||
DOC = """Get system uptime."""
|
||||
COMMAND_NAME = 'uptime'
|
||||
|
||||
@click.command('uptime', short_help='Get system uptime')
|
||||
|
||||
@click.command(COMMAND_NAME, short_help=DOC)
|
||||
@pass_context
|
||||
def cli(ctx):
|
||||
"""Get system uptime."""
|
||||
|
||||
uptime = get_uptime()
|
||||
output = {
|
||||
'exit_code': 0,
|
||||
|
@ -42,7 +44,6 @@ def cli(ctx):
|
|||
|
||||
def get_uptime():
|
||||
"""Read the uptime from the proc filesystem."""
|
||||
|
||||
with open('/proc/uptime', 'r') as f:
|
||||
output = f.read()
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""Common code for utils."""
|
||||
|
||||
import os
|
||||
import shelve
|
||||
|
@ -28,6 +29,7 @@ except ImportError:
|
|||
|
||||
|
||||
def is_int(value):
|
||||
"""Check if a variable is an integer."""
|
||||
for v_type in [int, float]:
|
||||
try:
|
||||
value = v_type(value)
|
||||
|
@ -43,6 +45,7 @@ class LocalCache(object):
|
|||
"""Context Manager for opening and closing access to the DBM."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialization method for class."""
|
||||
"""Set the Path to the DBM to create/Open."""
|
||||
|
||||
self.db_cache = os.path.join(
|
||||
|
@ -55,12 +58,10 @@ class LocalCache(object):
|
|||
|
||||
:return: Open DBM
|
||||
"""
|
||||
|
||||
return self.open_shelve
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
"""Close DBM Connection."""
|
||||
|
||||
self.close_shelve()
|
||||
|
||||
def _open_shelve(self):
|
||||
|
@ -68,13 +69,16 @@ class LocalCache(object):
|
|||
|
||||
@property
|
||||
def open_shelve(self):
|
||||
"""Open shelved data."""
|
||||
return self._open_shelve()
|
||||
|
||||
def close_shelve(self):
|
||||
"""Close shelved data."""
|
||||
self.open_shelve.close()
|
||||
|
||||
|
||||
def read_config(config_file):
|
||||
"""Read an OpenStack configuration."""
|
||||
cfg = os.path.abspath(os.path.expanduser(config_file))
|
||||
if not os.path.isfile(cfg):
|
||||
raise IOError('Config file "{}" was not found'.format(cfg))
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
# 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.
|
||||
"""OpenStack-related utilities."""
|
||||
|
||||
try:
|
||||
from openstack import connection as os_conn
|
||||
|
@ -24,14 +25,19 @@ from monitorstack import utils
|
|||
|
||||
|
||||
class OpenStack(object):
|
||||
"""Class for reusable OpenStack utility methods."""
|
||||
|
||||
def __init__(self, os_auth_args):
|
||||
"""Initialization method for class."""
|
||||
self.os_auth_args = os_auth_args
|
||||
|
||||
@property
|
||||
def conn(self):
|
||||
"""Return an OpenStackSDK connection."""
|
||||
return os_conn.Connection(**self.os_auth_args)
|
||||
|
||||
def get_consumer_usage(self, servers=None, marker=None, limit=512):
|
||||
"""Retrieve current usage by an OpenStack cloud consumer."""
|
||||
tenant_kwargs = {'details': True, 'all_tenants': True, 'limit': limit}
|
||||
if not servers:
|
||||
servers = list()
|
||||
|
@ -53,6 +59,7 @@ class OpenStack(object):
|
|||
return servers
|
||||
|
||||
def get_compute_limits(self, project_id, interface='internal'):
|
||||
"""Determine limits of compute resources."""
|
||||
url = self.conn.compute.session.get_endpoint(
|
||||
interface=interface,
|
||||
service_type='compute'
|
||||
|
@ -63,6 +70,7 @@ class OpenStack(object):
|
|||
return quota_data.json()
|
||||
|
||||
def get_project_name(self, project_id):
|
||||
"""Retrieve the name of a project."""
|
||||
with utils.LocalCache() as c:
|
||||
try:
|
||||
project_name = c.get(project_id)
|
||||
|
@ -75,6 +83,7 @@ class OpenStack(object):
|
|||
return project_name
|
||||
|
||||
def get_projects(self):
|
||||
"""Retrieve a list of projects."""
|
||||
_consumers = list()
|
||||
with utils.LocalCache() as c:
|
||||
for project in self.conn.identity.projects():
|
||||
|
@ -83,6 +92,7 @@ class OpenStack(object):
|
|||
return _consumers
|
||||
|
||||
def get_flavors(self):
|
||||
"""Retrieve a list of flavors."""
|
||||
flavor_cache = dict()
|
||||
for flavor in self.conn.compute.flavors():
|
||||
entry = flavor_cache[flavor['id']] = dict()
|
||||
|
|
1
setup.py
1
setup.py
|
@ -12,6 +12,7 @@
|
|||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""The setup script."""
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
mock>=2.0.0
|
||||
pytest
|
||||
tox
|
||||
mock>=2.0.0
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2017, Major Hayden <major@mhtx.net>
|
||||
#
|
||||
# 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 an __init__.py."""
|
|
@ -38,7 +38,7 @@ class LibvirtStub(object):
|
|||
|
||||
class lookupByID(object): # noqa
|
||||
"""Stubbed lookupByID class."""
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, *args, **kwargs): # noqa
|
||||
pass
|
||||
|
||||
def maxVcpus(self): # noqa
|
||||
|
@ -50,7 +50,6 @@ class TestKvm(object):
|
|||
|
||||
def test_run(self):
|
||||
"""Ensure the run() method works."""
|
||||
|
||||
sys.modules['libvirt'] = LibvirtStub
|
||||
|
||||
runner = CliRunner()
|
||||
|
|
|
@ -24,6 +24,7 @@ class TestUtils(unittest.TestCase):
|
|||
"""Tests for the utilities."""
|
||||
|
||||
def setUp(self):
|
||||
"""Initial setup for class."""
|
||||
os_config_file = os.path.expanduser(
|
||||
os.path.abspath(__file__ + '/../../etc/openstack.ini')
|
||||
)
|
||||
|
@ -33,6 +34,7 @@ class TestUtils(unittest.TestCase):
|
|||
self.config_defaults = conf.defaults()
|
||||
|
||||
def tearDown(self):
|
||||
"""Destroy the local cache."""
|
||||
local_cache = os.path.join(
|
||||
tempfile.gettempdir(),
|
||||
'monitorstack.openstack.dbm'
|
||||
|
@ -40,31 +42,33 @@ class TestUtils(unittest.TestCase):
|
|||
if os.path.exists(local_cache):
|
||||
os.remove(local_cache)
|
||||
|
||||
def test_is_int_is_int(self):
|
||||
def test_is_int_is_int(self): # noqa
|
||||
self.assertTrue(isinstance(utils.is_int(value=1), int))
|
||||
|
||||
def test_is_int_is_int_str(self):
|
||||
def test_is_int_is_int_str(self): # noqa
|
||||
self.assertTrue(isinstance(utils.is_int(value='1'), int))
|
||||
|
||||
def test_is_int_is_not_int(self):
|
||||
def test_is_int_is_not_int(self): # noqa
|
||||
self.assertTrue(isinstance(utils.is_int(value='a'), str))
|
||||
|
||||
def test_read_config_not_found(self):
|
||||
def test_read_config_not_found(self): # noqa
|
||||
self.assertRaises(
|
||||
IOError,
|
||||
utils.read_config,
|
||||
'not-a-file'
|
||||
)
|
||||
|
||||
def test_read_config_found_dict_return(self):
|
||||
def test_read_config_found_dict_return(self): # noqa
|
||||
self.assertTrue(isinstance(self.config, dict))
|
||||
|
||||
def test_read_config_found_defaults_in_sections(self):
|
||||
"""Read config defaults from each section."""
|
||||
for k, v in self.config.items():
|
||||
for key in self.config_defaults.keys():
|
||||
self.assertTrue(key in v.keys())
|
||||
|
||||
def test_local_cache(self):
|
||||
"""Test local cache."""
|
||||
with utils.LocalCache() as c:
|
||||
c['test_key'] = True
|
||||
self.assertTrue('test_key' in c)
|
||||
|
|
Loading…
Reference in New Issue