Commit dfeb0df6 authored by Navid Sassan's avatar Navid Sassan
Browse files

Merge branch 'develop' into 'master'

new release

See merge request linuxfabrik-icinga-plugins/lib-linux!4
parents 8f024c1b a08fb475
#! /usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
"""Extends argparse by new input argument data types on demand.
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020043001'
def csv(arg):
"""Returns a list from a `csv` input argument.
"""
return [x.strip() for x in arg.split(',')]
def float_or_none(arg):
"""Returns None or float from a `float_or_none` input argument.
"""
if arg is None or str(arg).lower() == 'none':
return None
return float(arg)
def int_or_none(arg):
"""Returns None or int from a `int_or_none` input argument.
"""
if arg is None or str(arg).lower() == 'none':
return None
return int(arg)
def range_or_none(arg):
"""Returns None or range from a `range_or_none` input argument.
"""
return str_or_none(arg)
def str_or_none(arg):
"""Returns None or str from a `str_or_none` input argument.
"""
if arg is None or str(arg).lower() == 'none':
return None
return str(arg)
......@@ -27,8 +27,8 @@ import subprocess
import sys
import time
from globals import STATE_OK, STATE_UNKNOWN, STATE_WARN, STATE_CRIT
import disk
from globals2 import STATE_OK, STATE_UNKNOWN, STATE_WARN, STATE_CRIT
import disk2
def bits2human(n, format="%(value).1f%(symbol)s"):
......@@ -82,23 +82,23 @@ def coe(result, state=STATE_UNKNOWN):
This is useful if calling complex library functions in your checks
`main()` function. Don't use this in functions.
If a more complex library function, for example `lib.url.fetch()` fails, it
If a more complex library function, for example `lib.url2.fetch()` fails, it
returns `(False, 'the reason why I failed')`, otherwise `(True,
'this is my result'). This forces you to do some error handling.
To keep things simple, use `result = lib.base.coe(lib.url.fetch(...))`.
To keep things simple, use `result = lib.base2.coe(lib.url2.fetch(...))`.
If `fetch()` fails, your plugin will exit with STATE_UNKNOWN (default) and
print the original error message. Otherwise your script just goes on.
The use case in `main()` - without `coe`:
>>> success, html = lib.url.fetch(URL)
>>> success, html = lib.url2.fetch(URL)
>>> if not success:
>>> print(html) # contains the error message here
>>>> exit(STATE_UNKNOWN)
Or simply:
>>> html = lib.base.coe(lib.url.fetch(URL))
>>> html = lib.base2.coe(lib.url2.fetch(URL))
Parameters
----------
......@@ -741,30 +741,31 @@ def sum_lod(mylist):
def state2str(state, empty_ok=True, prefix='', suffix=''):
"""Return the state's string representation.
The square brackets around the state cause icingaweb2 to color the state.
>> lib.base.state2str(2)
'CRIT'
'[CRIT]'
>>> lib.base.state2str(0)
''
>>> lib.base.state2str(0, empty_ok=False)
'OK'
'[OK]'
>>> lib.base.state2str(0, empty_ok=False, suffix=' ')
'OK '
'[OK] '
>>> lib.base.state2str(0, empty_ok=False, prefix=' (', suffix=')')
' (OK)'
' ([OK])'
"""
state = int(state)
if state == STATE_OK and empty_ok:
return ''
if state == STATE_OK and not empty_ok:
return '{}OK{}'.format(prefix, suffix)
return '{}[OK]{}'.format(prefix, suffix)
if state == STATE_WARN:
return '{}WARN{}'.format(prefix, suffix)
return '{}[WARNING]{}'.format(prefix, suffix)
if state == STATE_CRIT:
return '{}CRIT{}'.format(prefix, suffix)
return '{}[CRITICAL]{}'.format(prefix, suffix)
if state == STATE_UNKNOWN:
return '{}UNKNOWN{}'.format(prefix, suffix)
return '{}[UNKNOWN]{}'.format(prefix, suffix)
return state
......@@ -775,11 +776,11 @@ def test(args):
"""
if args[0] and os.path.isfile(args[0]):
success, stdout = disk.read_file(args[0])
success, stdout = disk2.read_file(args[0])
else:
stdout = args[0]
if args[1] and os.path.isfile(args[1]):
success, stderr = disk.read_file(args[1])
success, stderr = disk2.read_file(args[1])
else:
stderr = args[1]
retc = int(args[2])
......@@ -823,7 +824,7 @@ def version(v):
True
>>> '3.0.7' < '3.0.11'
False
>>> lib.base.version(psutil.__version__) >= lib.base.version('5.3.0')
>>> lib.base2.version(psutil.__version__) >= lib.base2.version('5.3.0')
True
Parameters
......
This diff is collapsed.
......@@ -13,22 +13,22 @@ SQLite, optionally supporting expiration of keys. No detailed error handling
here. If the cache does not work, we (currently) don't report the reason and
simply return `False`.
>>> cache.get('session-key')
>>> cache2.get('session-key')
False
>>> cache.set('session-key', '123abc', expire=base.now() + 5)
>>> cache2.set('session-key', '123abc', expire=base2.now() + 5)
True
>>> cache.get('session-key')
>>> cache2.get('session-key')
u'123abc'
>>> time.sleep(6)
>>> cache.get('session-key')
>>> cache2.get('session-key')
False
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020051301'
import base
import db_sqlite
import base2
import db_sqlite2
def get(key, as_dict=False):
......@@ -46,39 +46,39 @@ def get(key, as_dict=False):
failure.
"""
success, conn = db_sqlite.connect(filename='linuxfabrik-plugin-cache.db')
success, conn = db_sqlite2.connect(filename='linuxfabrik-plugin-cache.db')
if not success:
return False
success, result = db_sqlite.select(
success, result = db_sqlite2.select(
conn,
sql='SELECT key, value, timestamp FROM cache WHERE key = :key;',
data={'key': key}, fetchone=True
)
if not success:
# error accessing or querying the cache
db_sqlite.close(conn)
db_sqlite2.close(conn)
return False
if not result or result is None:
# key not found
db_sqlite.close(conn)
db_sqlite2.close(conn)
return False
if result['timestamp'] != 0 and result['timestamp'] <= base.now():
if result['timestamp'] != 0 and result['timestamp'] <= base2.now():
# key was found, but timstamp was set and has expired:
# delete all expired keys and return false
data = {'key' : result['key']}
success, result = db_sqlite.delete(
success, result = db_sqlite2.delete(
conn,
sql='DELETE FROM cache WHERE timestamp <= {};'.format(base.now())
sql='DELETE FROM cache WHERE timestamp <= {};'.format(base2.now())
)
success, result = db_sqlite.commit(conn)
db_sqlite.close(conn)
success, result = db_sqlite2.commit(conn)
db_sqlite2.close(conn)
return False
# return the value
db_sqlite.close(conn)
db_sqlite2.close(conn)
if not as_dict:
# just return the value (as used to when for example using Redis)
......@@ -109,7 +109,7 @@ def set(key, value, expire=0):
`True` on success, `False` on failure.
"""
success, conn = db_sqlite.connect(filename='linuxfabrik-plugin-cache.db')
success, conn = db_sqlite2.connect(filename='linuxfabrik-plugin-cache.db')
if not success:
return False
......@@ -118,14 +118,14 @@ def set(key, value, expire=0):
value TEXT NOT NULL,
timestamp INT NOT NULL
'''
success, result = db_sqlite.create_table(conn, definition, table='cache')
success, result = db_sqlite2.create_table(conn, definition, table='cache')
if not success:
db_sqlite.close(conn)
db_sqlite2.close(conn)
return False
success, result = db_sqlite.create_index(conn, column_list='key', table='cache', unique=True)
success, result = db_sqlite2.create_index(conn, column_list='key', table='cache', unique=True)
if not success:
db_sqlite.close(conn)
db_sqlite2.close(conn)
return False
data = {
......@@ -134,13 +134,13 @@ def set(key, value, expire=0):
'timestamp': expire,
}
success, result = db_sqlite.replace(conn, data, table='cache')
success, result = db_sqlite2.replace(conn, data, table='cache')
if not success:
db_sqlite.close(conn)
db_sqlite2.close(conn)
return False
success, result = db_sqlite.commit(conn)
db_sqlite.close(conn)
success, result = db_sqlite2.commit(conn)
db_sqlite2.close(conn)
if not success:
return False
......
#! /usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
"""Simple Cache in the form of a Key-Value Store (KVS) like Redis, based on
SQLite, optionally supporting expiration of keys. No detailed error handling
here. If the cache does not work, we (currently) don't report the reason and
simply return `False`.
>>> cache3.get('session-key')
False
>>> cache3.set('session-key', '123abc', expire=base.now() + 5)
True
>>> cache3.get('session-key')
u'123abc'
>>> time.sleep(6)
>>> cache3.get('session-key')
False
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020051301'
import base3
import db_sqlite3
def get(key, as_dict=False):
"""Get the value of key. If the key does not exist, `False` is returned.
Parameters
----------
key : str
The search key.
Returns
-------
str or bool
The value that belongs to the key, `False` if not found or on
failure.
"""
success, conn = db_sqlite3.connect(filename='linuxfabrik-plugin-cache.db')
if not success:
return False
success, result = db_sqlite3.select(
conn,
sql='SELECT key, value, timestamp FROM cache WHERE key = :key;',
data={'key': key}, fetchone=True
)
if not success:
# error accessing or querying the cache
db_sqlite3.close(conn)
return False
if not result or result is None:
# key not found
db_sqlite3.close(conn)
return False
if result['timestamp'] != 0 and result['timestamp'] <= base3.now():
# key was found, but timstamp was set and has expired:
# delete all expired keys and return false
data = {'key' : result['key']}
success, result = db_sqlite3.delete(
conn,
sql='DELETE FROM cache WHERE timestamp <= {};'.format(base.now())
)
success, result = db_sqlite3.commit(conn)
db_sqlite3.close(conn)
return False
# return the value
db_sqlite3.close(conn)
if not as_dict:
# just return the value (as used to when for example using Redis)
return result['value']
# return all columns
return result
def set(key, value, expire=0):
"""Set key to hold the string value.
Keys have to be unique. If the key already holds a value, it is
overwritten, including the expire timestamp in seconds.
Parameters
----------
key : str
The key.
value : str
The value. Always stored as string.
expire : int
Set the expire unix timestamp, in seconds. If 0 (default), key never
expires.
Returns
-------
bool
`True` on success, `False` on failure.
"""
success, conn = db_sqlite3.connect(filename='linuxfabrik-plugin-cache.db')
if not success:
return False
definition = '''
key TEXT NOT NULL,
value TEXT NOT NULL,
timestamp INT NOT NULL
'''
success, result = db_sqlite3.create_table(conn, definition, table='cache')
if not success:
db_sqlite3.close(conn)
return False
success, result = db_sqlite3.create_index(conn, column_list='key', table='cache', unique=True)
if not success:
db_sqlite3.close(conn)
return False
data = {
'key': key,
'value': value,
'timestamp': expire,
}
success, result = db_sqlite3.replace(conn, data, table='cache')
if not success:
db_sqlite3.close(conn)
return False
success, result = db_sqlite3.commit(conn)
db_sqlite3.close(conn)
if not success:
return False
return True
......@@ -23,10 +23,10 @@ except ImportError as e:
print('Python module "mysql.connector" is not installed.')
exit(3)
import base
import disk
import base2
import disk2
if base.version(mysql.connector.__version__) < base.version('2.0.0'):
if base2.version(mysql.connector.__version__) < base2.version('2.0.0'):
try:
import MySQLdb.cursors
except ImportError as e:
......@@ -60,10 +60,10 @@ def connect(mysql_connection):
"""Connect to a MySQL/MariaDB. `mysql_connection` has to be a dict.
>>> mysql_connection = {
... 'user': args.USERNAME,
... 'password': args.PASSWORD,
... 'host': args.HOSTNAME,
... 'database': args.DATABASE,
... 'user': args2.USERNAME,
... 'password': args2.PASSWORD,
... 'host': args2.HOSTNAME,
... 'database': args2.DATABASE,
... 'raise_on_warnings': True
... }
>>> conn = connect(mysql_connection)
......@@ -83,7 +83,7 @@ def select(conn, sql, data={}, fetchone=False):
database.
"""
if base.version(mysql.connector.__version__) >= base.version('2.0.0'):
if base2.version(mysql.connector.__version__) >= base2.version('2.0.0'):
cursor = conn.cursor(dictionary=True)
else:
cursor = conn.cursor(MySQLdb.cursors.DictCursor)
......
#! /usr/bin/env python3
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
"""Library for accessing MySQL/MariaDB servers.
For details have a look at
https://dev.mysql.com/doc/connector-python/en/
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020050101'
try:
import mysql.connector
except ImportError as e:
print('Python module "mysql.connector" is not installed.')
exit(3)
import base3
import disk3
if base3.version(mysql.connector.__version__) < base3.version('2.0.0'):
try:
import MySQLdb.cursors
except ImportError as e:
print('Python module "MySQLdb.cursors" is not installed.')
exit(3)
def close(conn):
"""This closes the database connection.
"""
try:
conn.close()
except:
pass
return True
def commit(conn):
"""Save (commit) any changes.
"""
try:
conn.commit()
except Exception as e:
return(False, 'Error: {}'.format(e))
return (True, None)
def connect(mysql_connection):
"""Connect to a MySQL/MariaDB. `mysql_connection` has to be a dict.
>>> mysql_connection = {
... 'user': args3.USERNAME,
... 'password': args3.PASSWORD,
... 'host': args3.HOSTNAME,
... 'database': args3.DATABASE,
... 'raise_on_warnings': True
... }
>>> conn = connect(mysql_connection)
"""
try:
conn = mysql.connector.connect(**mysql_connection)
except Exception as e:
return(False, 'Connecting to DB failed, Error: {}'.format(e))
return (True, conn)
def select(conn, sql, data={}, fetchone=False):
"""The SELECT statement is used to query the database. The result of a
SELECT is zero or more rows of data where each row has a fixed number
of columns. A SELECT statement does not make any changes to the
database.
"""
if base3.version(mysql.connector.__version__) >= base3.version('2.0.0'):
cursor = conn.cursor(dictionary=True)
else:
cursor = conn.cursor(MySQLdb.cursors.DictCursor)
try:
if data:
cursor.execute(sql, data)
else:
cursor.execute(sql)
if fetchone:
return (True, [cursor.fetchone()])
return (True, cursor.fetchall())
except Exception as e:
return(False, 'Query failed: {}, Error: {}, Data: {}'.format(sql, e, data))
#! /usr/bin/env python2
# -*- encoding: utf-8; py-indent-offset: 4 -*-
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
# https://git.linuxfabrik.ch/linuxfabrik-icinga-plugins/checks-linux/-/blob/master/CONTRIBUTING.md
"""This is one typical use case of this library (taken from `disk-io`):
>>> conn = lib.base2.coe(lib.db_sqlite2.connect(filename='disk-io.db'))
>>> lib.base2.coe(lib.db_sqlite2.create_table(conn, definition, drop_table_first=False))
>>> lib.base2.coe(lib.db_sqlite2.create_index(conn, 'name')) # optional
>>> lib.base2.coe(lib.db_sqlite2.insert(conn, data))
>>> lib.base2.coe(lib.db_sqlite2.cut(conn, max=args2.COUNT*len(disks)))
>>> lib.base2.coe(lib.db_sqlite2.commit(conn))
>>> result = lib.base2.coe(lib.db_sqlite2.select(conn,
'SELECT * FROM perfdata WHERE name = :name ORDER BY timestamp DESC LIMIT 2',
{'name': disk}
>>> lib.db_sqlite2.close(conn)
"""
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2020051701'
import os
import sqlite3
import base2
import disk2
def close(conn):
"""This closes the database connection. Note that this does not
automatically call commit(). If you just close your database connection
without calling commit() first, your changes will be lost.
"""
try:
conn.close()
except:
pass
return True
def commit(conn):
"""Save (commit) any changes.
"""
try:
conn.commit()
except Exception as e:
return(False, 'Error: {}'.format(e))
return (True, None)
def connect(path='', filename=''):
"""Connect to a SQLite database file. If path is ommitted, the
temporary directory is used. If filename is ommitted,
`linuxfabrik-plugins.db` is used.
"""
def get_filename(path='', filename=''):