Added VM instances used and quotas (#6)

The following plugins add a basic OpenStack API framework which is used
to pull metrics for nova vm quotas and usage for RAM, vCPUs, disk, and
instance count.

added codecov.yml

Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
This commit is contained in:
Kevin Carter 2017-03-09 09:48:17 -06:00 committed by Major Hayden
parent f943e47f70
commit 37a9950ab2
22 changed files with 842 additions and 27 deletions

View File

@ -1,2 +1,3 @@
Kevin Carter <kcarter@linux.com>
Kevin Carter <kevin.carter@rackspace.com>
Major Hayden <major@mhtx.net>

View File

@ -1,7 +1,8 @@
CHANGES
=======
* Improve test coverage
* Added VM instances used and quotas
* Improve test coverage (#4)
* Remove sys from uptime test (#3)
* Increase test coverage for uptime
* Added KVM Metric plugin (#2)

4
codecov.yml Normal file
View File

@ -0,0 +1,4 @@
coverage:
round: down
range: 70..80
precision: 5

47
etc/openstack.ini Normal file
View File

@ -0,0 +1,47 @@
# Store the authentication credentials needed to query a given OpenStack Service.
# All sections are overrides for the defaults. If you only need to connect to a
# single cloud simply store the credentials needd in the DEFAULT section and
# override whatever is needed within the local sections.
[DEFAULT]
insecure = false
auth_url = https://example.com:5000/v3
# NOTE(cloudnull):
# When using keystone V3 you will need the .*domain_name configuration options.
user_domain_name = default # This is required when Keystone V3 is being used
project_domain_name = default # This is required when Keystone V3 is being used
# If you're using keystone V2 you will need the tenant_name option.
tenant_name = admin # This is required when Keystone V2 is being used
# NEVER Mix and match the options tenant name and domain_name options.
# You are be required to run either V2 or V3 as it pertains to this config.
# If you provide both tenant_name and .*domain_name options at the same time
# the plugins will fail API version negotiation.
username = admin
password = Secrete
# The verify option is for SSL. If your SSL certificate is not
# valid set this option to false else omit it or set it true.
verify = false
[keystone]
[glance]
[nova]
project_name = nova
[neutron]
[heat]
[cinder]
[ironic]
auth_url = https://example2.com:5000/v3
project_name = ironic
user_domain_name = users
project_domain_name = projects
password = SuperSecrete

View File

@ -51,6 +51,7 @@ 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__),
@ -60,6 +61,7 @@ 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)
@ -68,6 +70,7 @@ 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(
@ -99,6 +102,7 @@ VALID_OUTPUT_FORMATS = [
@pass_context
def cli(ctx, output_format, verbose):
"""A complex command line interface."""
ctx.verbose = verbose
pass
@ -106,6 +110,7 @@ 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(

View File

@ -18,13 +18,9 @@ import time
import click
def current_time():
"""Return the current time in nanoseconds."""
return int(time.time() * 1000000000)
def write_json(result):
"""Output in raw JSON format."""
output = json.dumps(result, indent=2)
click.echo(output)
return True
@ -32,36 +28,52 @@ def write_json(result):
def write_line(result):
"""Output in line format."""
for key, value in result['variables'].items():
click.echo("{} {}".format(key, value))
return True
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(' ', '_')
for v_type in [int, float]:
try:
v = v_type(v)
except ValueError:
pass # v was not a int, float, or long
else:
break
if not isinstance(v, (int, float, bool)) and quote:
store.append('{}="{}"'.format(k, v))
else:
store.append('{}={}'.format(k, v))
return ','.join(store).rstrip(',')
def write_telegraf(result):
"""Output in telegraf format."""
def line_format(sets, quote=False):
store = list()
for k, v in sets.items():
k = k.replace(' ', '_')
for v_type in [int, float]:
try:
v = v_type(v)
except ValueError:
pass # v was not a int, float, or long
else:
break
if not isinstance(v, (int, float, bool)) and quote:
store.append('{}="{}"'.format(k, v))
else:
store.append('{}={}'.format(k, v))
return ','.join(store).rstrip(',')
resultant = [result['measurement_name']]
if 'meta' in result:
resultant.append(line_format(sets=result['meta']))
resultant.append(line_format(sets=result['variables'], quote=True))
resultant.append(str(current_time()))
resultant.append(_telegraf_line_format(sets=result['meta']))
resultant.append(
_telegraf_line_format(
sets=result['variables'],
quote=True
)
)
resultant.append(str(_current_time()))
click.echo(' '.join(resultant))
return True

View File

@ -0,0 +1,59 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova cores quotas."""
COMMAND_NAME = 'os_vm_quota_cores'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'quotas': 'cores'
},
'variables': {}
}
nova_config = utils.read_config(config_file=config_file)['nova']
interface = nova_config.pop('interface', 'internal')
_ost = ost.OpenStack(os_auth_args=nova_config)
try:
variables = output['variables']
for project in _ost.get_projects():
limits = _ost.get_compute_limits(
project_id=project.id,
interface=interface
)
variables[project.name] = int(limits['quota_set']['cores'])
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,59 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova instance quotas."""
COMMAND_NAME = 'os_vm_quota_instance'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'quotas': 'instances'
},
'variables': {}
}
nova_config = utils.read_config(config_file=config_file)['nova']
interface = nova_config.pop('interface', 'internal')
_ost = ost.OpenStack(os_auth_args=nova_config)
try:
variables = output['variables']
for project in _ost.get_projects():
limits = _ost.get_compute_limits(
project_id=project.id,
interface=interface
)
variables[project.name] = int(limits['quota_set']['instances'])
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,59 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova ram quotas."""
COMMAND_NAME = 'os_vm_quota_ram'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'quotas': 'ram'
},
'variables': {}
}
nova_config = utils.read_config(config_file=config_file)['nova']
interface = nova_config.pop('interface', 'internal')
_ost = ost.OpenStack(os_auth_args=nova_config)
try:
variables = output['variables']
for project in _ost.get_projects():
limits = _ost.get_compute_limits(
project_id=project.id,
interface=interface
)
variables[project.name] = int(limits['quota_set']['ram'])
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,63 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 collections
import click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova used cores."""
COMMAND_NAME = 'os_vm_used_cores'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'used': 'cores'
},
'variables': {}
}
used_collection = collections.Counter()
nova_config = utils.read_config(config_file=config_file)['nova']
_ost = ost.OpenStack(os_auth_args=nova_config)
flavors = _ost.get_flavors()
try:
variables = output['variables']
for used in _ost.get_consumer_usage():
flavor = flavors[used['flavor']['id']]
used_collection[used['name']] += int(flavor['vcpus'])
output['meta'][used['flavor']['id']] = True
output['meta'][used['flavor']['name']] = True
variables.update(used_collection)
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,63 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 collections
import click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova used disk."""
COMMAND_NAME = 'os_vm_used_disk'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'used': 'disk'
},
'variables': {}
}
used_collection = collections.Counter()
nova_config = utils.read_config(config_file=config_file)['nova']
_ost = ost.OpenStack(os_auth_args=nova_config)
flavors = _ost.get_flavors()
try:
variables = output['variables']
for used in _ost.get_consumer_usage():
flavor = flavors[used['flavor']['id']]
used_collection[used['name']] += int(flavor['disk'])
output['meta'][used['flavor']['id']] = True
output['meta'][used['flavor']['name']] = True
variables.update(used_collection)
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,59 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 collections
import click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova used instances."""
COMMAND_NAME = 'os_vm_used_instance'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'used': 'instances'
},
'variables': {}
}
used_collection = collections.Counter()
nova_config = utils.read_config(config_file=config_file)['nova']
_ost = ost.OpenStack(os_auth_args=nova_config)
try:
variables = output['variables']
for used in _ost.get_consumer_usage():
used_collection[used['name']] += 1
variables.update(used_collection)
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -0,0 +1,63 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 collections
import click
from monitorstack import utils
from monitorstack.cli import pass_context
from monitorstack.utils import os_utils as ost
DOC = """Get nova used ram."""
COMMAND_NAME = 'os_vm_used_ram'
@click.command(COMMAND_NAME, short_help=DOC)
@click.option('--config-file',
help='OpenStack configuration file',
default='openstack.ini')
@pass_context
def cli(ctx, config_file):
setattr(cli, '__doc__', DOC)
output = {
'measurement_name': COMMAND_NAME,
'meta': {
'used': 'ram'
},
'variables': {}
}
used_collection = collections.Counter()
nova_config = utils.read_config(config_file=config_file)['nova']
_ost = ost.OpenStack(os_auth_args=nova_config)
flavors = _ost.get_flavors()
try:
variables = output['variables']
for used in _ost.get_consumer_usage():
flavor = flavors[used['flavor']['id']]
used_collection[used['name']] += int(flavor['ram'])
output['meta'][used['flavor']['id']] = True
output['meta'][used['flavor']['name']] = True
variables.update(used_collection)
except Exception as exp:
output['exit_code'] = 1
output['message'] = '{} failed -- Error: {}'.format(COMMAND_NAME, exp)
else:
output['exit_code'] = 0
output['message'] = '{} is ok'.format(COMMAND_NAME)
finally:
return output

View File

@ -24,6 +24,7 @@ from monitorstack.cli import pass_context
@pass_context
def cli(ctx):
"""Get system uptime."""
uptime = get_uptime()
output = {
'exit_code': 0,
@ -41,6 +42,7 @@ def cli(ctx):
def get_uptime():
"""Read the uptime from the proc filesystem."""
with open('/proc/uptime', 'r') as f:
output = f.read()

View File

@ -0,0 +1,95 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 shelve
import sys
import tempfile
# Lower import to support conditional configuration parser
try:
if sys.version_info > (3, 2, 0):
import configparser as ConfigParser
else:
import ConfigParser
except ImportError:
raise SystemExit('No configparser module was found.')
def is_int(value):
for v_type in [int, float]:
try:
value = v_type(value)
except ValueError:
pass # v was not a int, float, or long
else:
return value
else:
return value
class LocalCache(object):
"""Context Manager for opening and closing access to the DBM."""
def __init__(self):
"""Set the Path to the DBM to create/Open."""
self.db_cache = os.path.join(
tempfile.gettempdir(),
'monitorstack.openstack.dbm'
)
def __enter__(self):
"""Open the DBM in r/w mode.
:return: Open DBM
"""
return self.open_shelve
def __exit__(self, type, value, traceback):
"""Close DBM Connection."""
self.close_shelve()
def _open_shelve(self):
return shelve.open(self.db_cache)
@property
def open_shelve(self):
return self._open_shelve()
def close_shelve(self):
self.open_shelve.close()
def read_config(config_file):
cfg = os.path.abspath(os.path.expanduser(config_file))
if not os.path.isfile(cfg):
raise IOError('Config file "{}" was not found'.format(cfg))
parser = ConfigParser.ConfigParser()
parser.optionxform = str
parser.read([cfg])
args = dict()
defaults = dict([(k, v) for k, v in parser.items(section='DEFAULT')])
for section in parser.sections():
if section == 'DEFAULT':
continue
sec = args[section] = defaults
for key, value in parser.items(section):
sec[key] = is_int(value=value)
return args

View File

@ -0,0 +1,90 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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.
try:
from openstack import connection as os_conn
from openstack import exceptions as os_exp
except ImportError as e:
raise SystemExit('OpenStack plugins require access to the OpenStackSDK.'
' Please install "python-openstacksdk".'
' ERROR: %s' % str(e))
from monitorstack import utils
class OpenStack(object):
def __init__(self, os_auth_args):
self.os_auth_args = os_auth_args
@property
def conn(self):
return os_conn.Connection(**self.os_auth_args)
def get_consumer_usage(self, servers=None, marker=None, limit=512):
tenant_kwargs = {'details': True, 'all_tenants': True, 'limit': limit}
if not servers:
servers = list()
if marker:
tenant_kwargs['marker'] = marker
count = 0
for server in self.conn.compute.servers(**tenant_kwargs):
servers.append(server)
count += 1
if count == limit:
return self.get_consumer_usage(
servers=servers,
marker=servers[-1].id
)
return servers
def get_compute_limits(self, project_id, interface='internal'):
url = self.conn.compute.session.get_endpoint(
interface=interface,
service_type='compute'
)
quota_data = self.conn.compute.session.get(
url + '/os-quota-sets/' + project_id
)
return quota_data.json()
def get_project_name(self, project_id):
with utils.LocalCache() as c:
try:
project_name = c.get(project_id)
if not project_name:
project_info = self.conn.identity.get_project(project_id)
project_name = c[project_info.id] = project_info.name
except os_exp.ResourceNotFound:
return None
else:
return project_name
def get_projects(self):
_consumers = list()
with utils.LocalCache() as c:
for project in self.conn.identity.projects():
_consumers.append(project)
c[project.id] = project.name
return _consumers
def get_flavors(self):
flavor_cache = dict()
for flavor in self.conn.compute.flavors():
entry = flavor_cache[flavor['id']] = dict()
entry.update(flavor)
return flavor_cache

View File

@ -1,2 +1,3 @@
pytest
tox
mock>=2.0.0

0
tests/__init__.py Normal file
View File

View File

@ -35,7 +35,7 @@ class TestFormatters(object):
def test_current_time(self):
"""Test current_time()."""
result = formatters.current_time()
result = formatters._current_time()
assert isinstance(result, int)
assert result > 0

62
tests/test_os_vm.py Normal file
View File

@ -0,0 +1,62 @@
# Copyright 2017, Kevin Carter <kevin@cloudnull.com>
#
# 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 KVM plugin."""
import json
from click.testing import CliRunner
from monitorstack.cli import cli
def _runner(module):
runner = CliRunner()
result = runner.invoke(cli, ['-f', 'json', module])
return json.loads(result.output)
class TestOs(object):
"""Tests for the os_vm.* monitors."""
def test_os_vm_quota_cores(self):
"""Ensure the run() method works."""
# result_json = _runner(module='os_vm_quota_cores')
# variables = result_json['variables']
# meta = result_json['meta']
pass
def test_os_vm_quota_instances(self):
"""Ensure the run() method works."""
pass
def test_os_vm_quota_ram(self):
"""Ensure the run() method works."""
pass
def test_os_vm_used_cores(self):
"""Ensure the run() method works."""
pass
def test_os_vm_used_disk(self):
"""Ensure the run() method works."""
pass
def test_os_vm_used_instances(self):
"""Ensure the run() method works."""
pass
def test_os_vm_used_ram(self):
"""Ensure the run() method works."""
pass

View File

@ -46,7 +46,7 @@ class LibvirtStub(object):
class TestKvm(object):
"""Tests for the uptime monitor class."""
"""Tests for the kvm monitor."""
def test_run(self):
"""Ensure the run() method works."""

70
tests/test_utils.py Normal file
View File

@ -0,0 +1,70 @@
# 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.
"""Tests for the uptime plugin."""
import os
import tempfile
import unittest
from monitorstack import utils
class TestUptime(unittest.TestCase):
"""Tests for the utilities."""
def setUp(self):
os_config_file = os.path.expanduser(
os.path.abspath(__file__ + '/../../etc/openstack.ini')
)
self.config = utils.read_config(os_config_file)
conf = utils.ConfigParser.RawConfigParser()
conf.read([os_config_file])
self.config_defaults = conf.defaults()
def tearDown(self):
local_cache = os.path.join(
tempfile.gettempdir(),
'monitorstack.openstack.dbm'
)
if os.path.exists(local_cache):
os.remove(local_cache)
def test_is_int_is_int(self):
self.assertTrue(isinstance(utils.is_int(value=1), int))
def test_is_int_is_int_str(self):
self.assertTrue(isinstance(utils.is_int(value='1'), int))
def test_is_int_is_not_int(self):
self.assertTrue(isinstance(utils.is_int(value='a'), str))
def test_read_config_not_found(self):
self.assertRaises(
IOError,
utils.read_config,
'not-a-file'
)
def test_read_config_found_dict_return(self):
self.assertTrue(isinstance(self.config, dict))
def test_read_config_found_defaults_in_sections(self):
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):
with utils.LocalCache() as c:
c['test_key'] = True
self.assertTrue('test_key' in c)