Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 76 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import logging
from libprobe import logger
from libprobe.asset import Asset
from libprobe.probe import Probe
from libprobe.check import Check
from libprobe.severity import Severity
from libprobe.exceptions import (
CheckException,
Expand All @@ -42,71 +43,84 @@ from libprobe.exceptions import (
__version__ = "0.1.0"


async def my_first_check(asset: Asset, asset_config: dict, check_config: dict):
"""My first check.
Arguments:
asset: Asset contains an id, name and check which should be used
for logging;
asset_config: local configuration for this asset, for example credentials;
check_config: configuration for this check; contains for example the
interval at which the check is running and an address of
the asset to probe;
"""
if "ignore_this_check_iteration":
# nothing will be send to InfraSonar for this check iteration;
raise IgnoreResultException()

if "no_longer_try_this_check":
# nothing will be send to InfraSonar for this check iteration and the
# check will not start again until the probe restarts or configuration
# has been changed;
raise IgnoreCheckException()

if "something_has_happened":
# send a check error to InfraSonar because something has happened which
# prevents us from building a check result; The default severity for a
# CheckException is MEDIUM but this can be overwritten;
raise CheckException("something went wrong", severity=Severity.LOW)

if "something_unexpected_has_happened":
# other exceptions will be converted to CheckException, MEDIUM severity
raise Exception("something went wrong")

# A check result may have multiple types, items, and/or metrics
result = {"myType": [{"name": "my item"}]}

if "result_is_incomplete":
# optionally, IncompleteResultException can be given another severity;
# the default severity is LOW.
raise IncompleteResultException('missing type x', result)

if "not_count_as_check_result":
# optionally, NoCountException can be raised in which case the check
# result is not counted by InfraSonar; Thus, the last seen services
# will not "see" this check result.
# A severity can be given if we also want a check error; (similar to
# the IncompleteResultException exception)
raise NoCountException('do not count this check result', result)

# Use the asset in logging; this will include asset info and the check key
logging.info(f"log something; {asset}")

# In alpha versions and debug logging enabled, unknown exception will be
# logged when debug logging is enabled. You may use logger.exception()
# yourself if you want exception logging for debug logging only.
try:
42 / 0 # ZeroDivision error for example
except Exception:
logger.exception() # log the exception only when DEBUG logging

# Return the check result
return result
class MyFirstCheck(Check):

key = 'myFirstCheck'
unchanged_eol = 0 # Can be for example 14400, to prevent sending the same
# check result for the next 4 hours (0=disabled)

@staticmethod
async def run(asset: Asset, local_config: dict, config: dict) -> dict:
"""My first check.
Arguments:
asset:
Asset contains an id, name and check which should be used
for logging;
local_config:
local configuration for this asset, for example
credentials;
config:
configuration for this check; contains for example the
interval at which the check is running and an address of
the asset to probe;
"""
if "ignore_this_check_iteration":
# nothing will be send to InfraSonar for this check iteration;
raise IgnoreResultException()

if "no_longer_try_this_check":
# nothing will be send to InfraSonar for this check iteration and
# the check will not start again until the probe restarts or
# configuration has been changed;
raise IgnoreCheckException()

if "something_has_happened":
# send a check error to InfraSonar because something has happened
# which prevents us from building a check result; The default
# severity for a CheckException is MEDIUM but this can be
# overwritten;
raise CheckException("something went wrong", severity=Severity.LOW)

if "something_unexpected_has_happened":
# exceptions will be converted to CheckException, MEDIUM severity
raise Exception("something went wrong")

# A check result may have multiple types, items, and/or metrics
result = {"myType": [{"name": "my item"}]}

if "result_is_incomplete":
# optionally, IncompleteResultException with severity;
# the default severity is LOW.
raise IncompleteResultException('missing type x', result)

if "not_count_as_check_result":
# optionally, NoCountException can be raised in which case the
# check result is not counted by InfraSonar; Thus, the last seen
# services will not "see" this check result.
# A severity can be given if we also want a check error;
# (similar to the IncompleteResultException exception)
raise NoCountException('do not count this check result', result)

# Use the asset in logging; includes asset info and the check key
logging.info(f"log something; {asset}")

# In alpha versions and debug logging enabled, unknown exception will
# be logged when debug logging is enabled.
# You may use logger.exception() yourself if you want exception
# logging for debug logging only.
try:
42 / 0 # ZeroDivision error for example
except Exception:
logger.exception() # log the exception only when DEBUG logging

# Return the check result
return result


if __name__ == "__main__":
checks = {
"myFirstCheck": my_first_check,
}
checks = (
MyFirstCheck
)

# Initialize the probe with a name, version and checks
probe = Probe("myProbe", __version__, checks)
Expand Down
23 changes: 23 additions & 0 deletions libprobe/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import abc
from .asset import Asset


class Check(abc.ABC):
key: str # Check key
unchanged_eol: int = 0 # For example: 14400 for 4 hours, 0 for disabled

def __init_subclass__(cls, **kwargs):
if not hasattr(cls, 'key'):
raise NotImplementedError('key not implemented')
if not isinstance(cls.key, str):
raise NotImplementedError('key must be type str')
return super().__init_subclass__(**kwargs)

# Method run(..) must return a check result, it receives:
# asset: Asset
# local_config: Local configuration (credentials etc.)
# config: Asset configuration from InfraSonar
@staticmethod
@abc.abstractmethod
async def run(asset: Asset, local_config: dict, config: dict) -> dict:
...
3 changes: 1 addition & 2 deletions libprobe/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
username: charlie
password: "my other secret"
"""
from typing import Optional
import logging


Expand Down Expand Up @@ -50,7 +49,7 @@ def decrypt(layer, fernet):
decrypt(v, fernet)


def get_config(conf: dict, probe_name: str, asset_id: int, use: Optional[str]):
def get_config(conf: dict, probe_name: str, asset_id: int, use: str | None):
# use might both be None or an empty string, depending if the `_use` option
# is available for the probe; both must be ignored
probe = conf.get(use or probe_name)
Expand Down
3 changes: 1 addition & 2 deletions libprobe/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from .severity import Severity
from typing import Optional


class IgnoreResultException(Exception):
Expand Down Expand Up @@ -62,7 +61,7 @@ def __init__(
self,
msg: str,
result: dict,
severity: Optional[Severity] = None):
severity: Severity | None = None):
assert isinstance(result, dict)
self.is_exception = severity is not None
super().__init__(
Expand Down
4 changes: 2 additions & 2 deletions libprobe/net/package.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
import msgpack
import struct
from typing import Optional, Any
from typing import Any


class Package(object):
Expand All @@ -10,7 +10,7 @@ class Package(object):

st_package = struct.Struct('<QIHBB')

def __init__(self, barray: Optional[bytearray] = None):
def __init__(self, barray: bytearray | None = None):
if barray is None:
return

Expand Down
17 changes: 8 additions & 9 deletions libprobe/net/protocol.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import asyncio
import logging
from typing import Union, Optional, Dict, Tuple
from .package import Package


Expand All @@ -14,19 +13,19 @@ class Protocol(asyncio.Protocol):
def __init__(self):
super().__init__()
self._buffered_data = bytearray()
self._package: Optional[Package] = None
self._requests: Dict[int, Tuple[asyncio.Future,
Optional[asyncio.Task]]] = dict()
self._package: Package | None = None
self._requests: dict[int, tuple[asyncio.Future,
asyncio.Task | None]] = dict()
self._pid = 0
self.transport: Optional[asyncio.Transport] = None
self.transport: asyncio.Transport | None = None

def connection_made(self, transport: asyncio.Transport): # type: ignore
'''
override asyncio.Protocol
'''
self.transport = transport

def connection_lost(self, exc: Optional[Exception]):
def connection_lost(self, exc: Exception | None):
'''
override asyncio.Protocol
'''
Expand All @@ -40,7 +39,7 @@ def is_connected(self) -> bool:
def request(
self,
pkg: Package,
timeout: Union[None, float, int] = None
timeout: float | int | None = None
) -> asyncio.Future:
self._pid += 1
self._pid %= 0x10000
Expand Down Expand Up @@ -86,7 +85,7 @@ def data_received(self, data: bytes):
def on_package_received(self, pkg: Package):
raise NotImplementedError

async def _timer(self, pid: int, timeout: Union[float, int]):
async def _timer(self, pid: int, timeout: float | int):
await asyncio.sleep(timeout)
try:
future, task = self._requests.pop(pid)
Expand All @@ -97,7 +96,7 @@ async def _timer(self, pid: int, timeout: Union[float, int]):
future.set_exception(TimeoutError(
f'request timed out on package id: {pid}'))

def _get_future(self, pkg: Package) -> Optional[asyncio.Future]:
def _get_future(self, pkg: Package) -> asyncio.Future | None:
future, task = self._requests.pop(pkg.pid, (None, None))
if future is None:
logging.error(
Expand Down
Loading