Фиксация наработок
parent
f328f68463
commit
8656085ee4
|
@ -0,0 +1,84 @@
|
|||
# coding: utf-8
|
||||
"""Command line interface."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import click
|
||||
from pysnmp.hlapi.asyncio import SnmpEngine
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
|
||||
|
||||
try:
|
||||
import uvloop # noqa: WPS433
|
||||
except ImportError:
|
||||
logging.info('For performance boost install uvloop')
|
||||
else:
|
||||
uvloop.install()
|
||||
|
||||
|
||||
DEFAULT_INTERVAL = 10.0
|
||||
|
||||
|
||||
async def worker(
|
||||
interval: float,
|
||||
host: str,
|
||||
db_engine: Optional[AsyncEngine],
|
||||
):
|
||||
"""Connect to host, gather metrics and store to database.
|
||||
|
||||
Args:
|
||||
interval: seconds to wait between iterations.
|
||||
host: hostname or IP of the host.
|
||||
db_engine: SQLAlchemy Engine object.
|
||||
|
||||
"""
|
||||
snmp_engine = SnmpEngine()
|
||||
while True:
|
||||
print(host)
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
|
||||
async def scheduler(interval: float, dsn: str, hosts: Tuple[str]):
|
||||
"""Schdule async worker for each host.
|
||||
|
||||
Args:
|
||||
interval: seconds to wait between iterations.
|
||||
dsn: SQLAlchemy connection string.
|
||||
hosts: hosts to monitor.
|
||||
|
||||
"""
|
||||
db_engine = None
|
||||
if dsn:
|
||||
db_engine = create_async_engine(dsn, echo='debug', future=True)
|
||||
async with db_engine.begin() as conn:
|
||||
# await conn.run_sync(meta.drop_all)
|
||||
# await conn.run_sync(meta.create_all)
|
||||
pass
|
||||
await asyncio.gather(
|
||||
*(worker(interval, host, db_engine) for host in hosts),
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
'-i',
|
||||
'--interval',
|
||||
type=click.FloatRange(0, min_open=True),
|
||||
default=DEFAULT_INTERVAL,
|
||||
help='Collect metrics every interval seconds.',
|
||||
show_default=True,
|
||||
)
|
||||
@click.option(
|
||||
'-d',
|
||||
'--dsn',
|
||||
help='DSN connection string to store metrics.',
|
||||
show_default=True,
|
||||
)
|
||||
@click.argument('hosts', nargs=-1, required=True)
|
||||
def command(*args, **kwargs):
|
||||
"""Collect OpenBSD SNMP metrics from HOST.
|
||||
|
||||
Multiple hosts can be specified with spaces.
|
||||
""" # noqa: DAR101
|
||||
asyncio.run(scheduler(*args, **kwargs))
|
|
@ -0,0 +1,6 @@
|
|||
# coding: utf-8
|
||||
"""Code to be run if invoked with python -m."""
|
||||
|
||||
from obsdsnmp import command
|
||||
|
||||
command(auto_envvar_prefix='OBSDSNMP')
|
|
@ -0,0 +1,25 @@
|
|||
# coding: utf-8
|
||||
"""SQLAlchemy models for monitored hosts."""
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
metadata = sa.MetaData()
|
||||
|
||||
MAX_DOMAIN_NAME = 255
|
||||
host = sa.Table(
|
||||
'host',
|
||||
metadata,
|
||||
sa.Column('id', sa.Integer, primary_key=True),
|
||||
sa.Column(
|
||||
'hostname',
|
||||
sa.String(MAX_DOMAIN_NAME),
|
||||
unique=True,
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column('sysname', sa.Text, nullable=False),
|
||||
sa.Column('description', sa.Text, nullable=False),
|
||||
sa.Column('contact', sa.Text, nullable=False),
|
||||
sa.Column('location', sa.Text, nullable=False),
|
||||
sa.Column('uptime', sa.Time, nullable=False),
|
||||
sa.Column('modified', sa.DateTime, onupdate=sa.func.utc_timestamp()),
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
Usage: command [OPTIONS] HOSTS...
|
||||
Try 'command --help' for help.
|
||||
|
||||
Error: Missing argument 'HOSTS...'.
|
|
@ -0,0 +1,11 @@
|
|||
Usage: command [OPTIONS] HOSTS...
|
||||
|
||||
Collect OpenBSD SNMP metrics from HOST.
|
||||
|
||||
Multiple hosts can be specified with spaces.
|
||||
|
||||
Options:
|
||||
-i, --interval FLOAT RANGE Collect metrics every interval seconds. [default:
|
||||
10.0;x>0]
|
||||
-d, --dsn TEXT DSN connection string to store metrics.
|
||||
--help Show this message and exit.
|
|
@ -0,0 +1,88 @@
|
|||
# coding: utf-8
|
||||
"""Test CLI of the application."""
|
||||
|
||||
from runpy import run_module
|
||||
|
||||
from click.testing import CliRunner
|
||||
from pytest import MonkeyPatch, CaptureFixture
|
||||
from pytest_snapshot.plugin import Snapshot
|
||||
|
||||
import obsdsnmp
|
||||
|
||||
|
||||
def printer(*args, **kwargs):
|
||||
"""Monkeypatch function, that prints args kwargs to stdout.
|
||||
|
||||
Args:
|
||||
args: positional arguments.
|
||||
kwargs: key-value arguments.
|
||||
"""
|
||||
print(args, kwargs) # noqa: WPS421
|
||||
|
||||
|
||||
async def async_printer(*args, **kwargs):
|
||||
"""Monkeypatch function, that prints args kwargs to stdout.
|
||||
|
||||
Args:
|
||||
args: positional arguments.
|
||||
kwargs: key-value arguments.
|
||||
"""
|
||||
print(args, kwargs) # noqa: WPS421
|
||||
|
||||
|
||||
def test_empty_run(snapshot: Snapshot):
|
||||
"""Test invoking without arguments.
|
||||
|
||||
The app shall give error information.
|
||||
|
||||
Args:
|
||||
snapshot: instance of pytest_snapshot fixture.
|
||||
|
||||
"""
|
||||
runner = CliRunner()
|
||||
invoke_result = runner.invoke(obsdsnmp.command, [])
|
||||
assert invoke_result.exit_code == 2
|
||||
snapshot.assert_match(invoke_result.output, 'empty_run')
|
||||
|
||||
|
||||
def test_help(snapshot: Snapshot):
|
||||
"""Test invoking help.
|
||||
|
||||
The app shall give help.
|
||||
|
||||
Args:
|
||||
snapshot: instance of pytest_snapshot fixture.
|
||||
|
||||
"""
|
||||
runner = CliRunner()
|
||||
invoke_result = runner.invoke(obsdsnmp.command, ['--help'])
|
||||
assert invoke_result.exit_code == 0
|
||||
snapshot.assert_match(invoke_result.output, 'help')
|
||||
|
||||
|
||||
def test_worker(monkeypatch: MonkeyPatch):
|
||||
"""Test setting interval.
|
||||
|
||||
Args:
|
||||
monkeypatch: pytest monkeypatch fixture.
|
||||
"""
|
||||
monkeypatch.setattr(obsdsnmp, 'worker', async_printer)
|
||||
runner = CliRunner()
|
||||
invoke_result = runner.invoke(obsdsnmp.command, ['-i', '1', 'test'])
|
||||
assert invoke_result.exit_code == 0
|
||||
assert invoke_result.output == '{0} {1}\n'.format((1.0, 'test', None), {})
|
||||
|
||||
|
||||
def test_package(monkeypatch: MonkeyPatch, capsys: CaptureFixture):
|
||||
"""Test __main__ invokation.
|
||||
|
||||
Args:
|
||||
monkeypatch: pytest monkeypatch fixture.
|
||||
capsys: capture stdout fixture.
|
||||
"""
|
||||
monkeypatch.setattr(obsdsnmp, 'command', printer)
|
||||
run_module('obsdsnmp')
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == '{0} {1}\n'.format((), {
|
||||
'auto_envvar_prefix': 'OBSDSNMP',
|
||||
})
|
Loading…
Reference in New Issue