Hello community,
here is the log from the commit of package hanadb_exporter for openSUSE:Factory
checked in at 2019-12-11 12:13:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/hanadb_exporter (Old)
and /work/SRC/openSUSE:Factory/.hanadb_exporter.new.4691 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hanadb_exporter"
Wed Dec 11 12:13:39 2019 rev:6 rq:755692 version:0.5.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/hanadb_exporter/hanadb_exporter.changes
2019-11-13 13:29:16.511757138 +0100
+++
/work/SRC/openSUSE:Factory/.hanadb_exporter.new.4691/hanadb_exporter.changes
2019-12-11 12:13:57.964531091 +0100
@@ -1,0 +2,14 @@
+Tue Dec 10 09:17:42 UTC 2019 - Xabier Arbulu <[email protected]>
+
+- Version 0.5.3 Improve metrics collection if some of the rows
+result is None. Before, if any result was None the result was
+not exported. Now, only metrics with None value are ommitted
+
+-------------------------------------------------------------------
+Mon Dec 9 08:21:18 UTC 2019 - Xabier Arbulu <[email protected]>
+
+- Version 0.5.2 Add the option to use the hanadb_exporter with
+the stored user key. This gives the option to avoid the plain
+user/password strings usage.
+
+-------------------------------------------------------------------
Old:
----
hanadb_exporter-0.5.1.tar.gz
New:
----
hanadb_exporter-0.5.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ hanadb_exporter.spec ++++++
--- /var/tmp/diff_new_pack.MXYiDI/_old 2019-12-11 12:13:59.020530794 +0100
+++ /var/tmp/diff_new_pack.MXYiDI/_new 2019-12-11 12:13:59.024530793 +0100
@@ -26,7 +26,7 @@
%endif
Name: hanadb_exporter
-Version: 0.5.1
+Version: 0.5.3
Release: 0
Summary: SAP HANA database metrics exporter
License: Apache-2.0
++++++ hanadb_exporter-0.5.1.tar.gz -> hanadb_exporter-0.5.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/README.md
new/hanadb_exporter-0.5.3/README.md
--- old/hanadb_exporter-0.5.1/README.md 2019-11-06 12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/README.md 2019-12-10 12:20:40.946509434 +0100
@@ -51,9 +51,9 @@
zypper in python3-PyHDB
```
-## Configuring and running the exporter
+## Configuring the exporter
-1. Create the `config.json` configuration file.
+Create the `config.json` configuration file.
An example of `config.json` available in
[config.json.example](config.json.example). Here the most
important items in the configuration file:
- `exposition_port`: Port where the prometheus exporter will be exposed
(8001 by default).
@@ -61,6 +61,7 @@
- `timeout`: Timeout to connect to the database. After this time the app
will fail (even in daemon mode).
- `hana.host`: Address of the SAP HANA database.
- `hana.port`: Port where the SAP HANA database is exposed.
+ - `hana.userkey`: Stored user key. This is the secure option if you don't
want to have the password in the configuration file. The `userkey` and
`user/password` are self exclusive being the first the default if both options
are set.
- `hana.user`: An existing user with access right to the SAP HANA database.
- `hana.password`: Password of an existing user.
- `logging.config_file`: Python logging system configuration file (by
default WARN and ERROR level messages will be sent to the syslog)
@@ -70,14 +71,44 @@
Using the default [configuration file](./logging_config.ini), it will redirect
the logs to the file assigned in the [json configuration
file](./config.json.example) and to the syslog (only logging level up to
WARNING).
-2. Start the exporter by running the following command:
+### Using the stored user key
+
+This is the recommended option if we want to keep the database secure (for
development environments the `user/password` with `SYSTEM` user can be used as
it's faster to setup).
+To use the `userkey` option the `dbapi` must be installed (usually stored in
`/hana/shared/PRD/hdbclient/hdbcli-N.N.N.tar.gz` and installable with pip3).
+It cannot be used from other different client (the key is stored in the client
itself). This will raise the `hdbcli.dbapi.Error: (-10104, 'Invalid value for
KEY')` error.
+For that a new stored user key must be created with the user that is running
python. For that (please, notice that the `hdbclient` is the same as the
`dbapi` python package):
+```
+/hana/shared/PRD/hdbclient/hdbuserstore set yourkey host:30013@SYSTEMDB
hanadb_exporter pass
+```
+
+Some tips:
+- Set `SYSTEMDB` as default database, this way the exporter will know where to
get the tenants data.
+- Don't use the stored user key created for the backup as this is created
using the sidadm user.
+- The usage of a user with access only to the monitoring tables is recommended
instead of using SYSTEM user.
+- If a user with monitoring role is used the user must exist in all the
databases (SYSTEMDB+tenants).
+
+### Create a new user with monitoring role
+Run the next commands to create a user with moniroting roles (**the commands
must be executed in all the databases**):
+```
+su - prdadm
+hdbsql -u SYSTEM -p pass -d SYSTEMDB #(PRD for the tenant in this example)
+CREATE USER HANADB_EXPORTER_USER PASSWORD MyExporterPassword NO
FORCE_FIRST_PASSWORD_CHANGE;
+CREATE ROLE HANADB_EXPORTER_ROLE;
+GRANT MONITORING TO HANADB_EXPORTER_ROLE;
+GRANT HANADB_EXPORTER_ROLE TO HANADB_EXPORTER_USER;
+```
+
+
+## Running the exporter
+
+Start the exporter by running the following command:
```
hanadb_exporter -c config.json -m metrics.json
# Or
python3 hanadb_exporter/main.py -c config.json -m metrics.json
```
-## Running as a daemon
+### Running as a daemon
The hanadb_exporter can be executed using `systemd`. For that, the best option
is to install the
project using a rpm package. This can be done following the next steps (this
example is for tumbleweed):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/hanadb_exporter/__init__.py
new/hanadb_exporter-0.5.3/hanadb_exporter/__init__.py
--- old/hanadb_exporter-0.5.1/hanadb_exporter/__init__.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter/__init__.py 2019-12-10
12:20:40.946509434 +0100
@@ -8,4 +8,4 @@
:since: 2019-05-09
"""
-__version__ = "0.5.0"
+__version__ = "0.5.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/hanadb_exporter/db_manager.py
new/hanadb_exporter-0.5.3/hanadb_exporter/db_manager.py
--- old/hanadb_exporter-0.5.1/hanadb_exporter/db_manager.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter/db_manager.py 2019-12-10
12:20:40.946509434 +0100
@@ -17,14 +17,20 @@
RECONNECTION_INTERVAL = 15
+class UserKeyNotSupportedError(ValueError):
+ """
+ User key not supported error
+ """
+
+
class DatabaseManager(object):
"""
Manage the connection to a multi container HANA system
"""
TENANT_DATA_QUERY =\
-"""SELECT SQL_PORT FROM SYS_DATABASES.M_SERVICES
-WHERE (SERVICE_NAME='indexserver' and COORDINATOR_TYPE= 'MASTER')"""
+"""SELECT DATABASE_NAME,SQL_PORT FROM SYS_DATABASES.M_SERVICES
+WHERE COORDINATOR_TYPE='MASTER'"""
def __init__(self):
self._logger = logging.getLogger(__name__)
@@ -38,24 +44,50 @@
data = self._system_db_connector.query(self.TENANT_DATA_QUERY)
formatted_data = utils.format_query_result(data)
for tenant_data in formatted_data:
- yield int(tenant_data['SQL_PORT'])
+ if tenant_data['DATABASE_NAME'] != 'SYSTEMDB':
+ yield tenant_data['DATABASE_NAME'],
int(tenant_data['SQL_PORT'])
- def _connect_tenants(self, host, user, password):
+ def _connect_tenants(self, host, connection_data):
"""
Connect to the tenants
Args:
host (str): Host of the HANA database
- user (str): System database user name (SYSTEM usually)
- password (str): System database user password
+ connection_data (dict): Data retrieved from _get_connection_data
"""
- for tenant_port in self._get_tenants_port():
+ for database, tenant_port in self._get_tenants_port():
conn = hdb_connector.HdbConnector()
+ # If userkey is used database name must be added to connect to
tenants
+ if connection_data.get('userkey'):
+ connection_data['databaseName'] = database
conn.connect(
- host, tenant_port, user=user, password=password,
RECONNECT='FALSE')
+ host, tenant_port, **connection_data)
self._db_connectors.append(conn)
- def start(self, host, port, user, password, multi_tenant=True,
timeout=600):
+ def _get_connection_data(self, userkey, user, password):
+ """
+ Check that provided user data is valid. user/password pair or userkey
must be provided
+ """
+ if userkey:
+ if hdb_connector.API == 'pyhdb':
+ raise UserKeyNotSupportedError(
+ 'userkey usage is not supported with pyhdb connector,
hdbcli must be installed')
+ self._logger.info('stored user key %s will be used to connect to
the database', userkey)
+ if user or password:
+ self._logger.warn(
+ 'userkey will be used to create the connection.
user/password are omitted')
+ elif user and password:
+ self._logger.info('user/password combination will be used to
connect to the databse')
+ else:
+ raise ValueError(
+ 'Provided user data is not valid. userkey or user/password
pair must be provided')
+
+ return {'userkey': userkey,
+ 'user': user,
+ 'password': password,
+ 'RECONNECT': 'FALSE'}
+
+ def start(self, host, port, **kwargs):
"""
Start de database manager. This will open a connection with the System
database and
retrieve the current environemtn tenant databases data
@@ -63,30 +95,39 @@
Args:
host (str): Host of the HANA database
port (int): Port of the System database (3XX13 when XX is the
instance number)
+ userkey (str): User stored key
user (str): System database user name (SYSTEM usually)
password (str): System database user password
multi_tenant (bool): Connect to all tenants checking the data in
the System database
timeout (int, opt): Timeout in seconds to connect to the System
database
"""
+ connection_data = self._get_connection_data(
+ kwargs.get('userkey', None), kwargs.get('user', ''),
kwargs.get('password', ''))
current_time = time.time()
- timeout = current_time + timeout
+ timeout = current_time + kwargs.get('timeout', 600)
while current_time <= timeout:
try:
- self._system_db_connector.connect(
- host, port, user=user, password=password,
RECONNECT='FALSE')
+ # parameters are passed using kwargs to the connect method
+ # pyhdb only uses 'user' and `password`
+ # dbapi uses 'user', 'password', 'userkey' and other optional
params
+ self._system_db_connector.connect(host, port,
**connection_data)
self._db_connectors.append(self._system_db_connector)
break
except hdb_connector.connectors.base_connector.ConnectionError as
err:
self._logger.error(
'the connection to the system database failed. error
message: %s', str(err))
+ # This conditions is used to stop the exporter if the provided
userkey is not valid
+ if 'Invalid value for KEY' in str(err):
+ raise
hdb_connector.connectors.base_connector.ConnectionError(
+ 'provided userkey is not valid. Check if dbapi is
installed correctly')
time.sleep(RECONNECTION_INTERVAL)
current_time = time.time()
else:
raise hdb_connector.connectors.base_connector.ConnectionError(
'timeout reached connecting the System database')
- if multi_tenant:
- self._connect_tenants(host, user, password)
+ if kwargs.get('multi_tenant', True):
+ self._connect_tenants(host, connection_data)
def get_connectors(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/hanadb_exporter/main.py
new/hanadb_exporter-0.5.3/hanadb_exporter/main.py
--- old/hanadb_exporter-0.5.1/hanadb_exporter/main.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter/main.py 2019-12-10
12:20:40.946509434 +0100
@@ -92,7 +92,9 @@
dbs = db_manager.DatabaseManager()
dbs.start(
hana_config['host'], hana_config.get('port', 30013),
- hana_config['user'], hana_config['password'],
+ user=hana_config.get('user', ''),
+ password=hana_config.get('password', ''),
+ userkey=hana_config.get('userkey', None),
multi_tenant=config.get('multi_tenant', True),
timeout=config.get('timeout', 600))
except KeyError as err:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/hanadb_exporter-0.5.1/hanadb_exporter/prometheus_exporter.py
new/hanadb_exporter-0.5.3/hanadb_exporter/prometheus_exporter.py
--- old/hanadb_exporter-0.5.1/hanadb_exporter/prometheus_exporter.py
2019-11-06 12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter/prometheus_exporter.py
2019-12-10 12:20:40.946509434 +0100
@@ -111,16 +111,18 @@
if column_name.lower() == metric.value.lower():
metric_value = column_value
if metric_value is None:
- raise ValueError(
- 'Specified value in metrics.json for metric'
- ' "{}": ({}) not found in the query result'.format(
- metric.name, metric.value))
+ self._logger.warn(
+ 'Specified value in metrics.json for metric "%s": (%s) not
found or it is '\
+ 'invalid (None) in the query result',
+ metric.name, metric.value)
+ continue
elif len(labels) != len(metric.labels):
# Log when a label(s) specified in metrics.json is not found
in the query result
- raise ValueError(
- 'One or more label(s) specified in metrics.json'
- ' for metric: "{}" is not found in the the query
result'.format(
- metric.name))
+ self._logger.warn(
+ 'One or more label(s) specified in metrics.json '
+ 'for metric "%s" that are not found in the query result',
+ metric.name)
+ continue
else:
# Add sid, insnr and database_name labels
combined_labels = self.metadata_labels + labels
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/hanadb_exporter.changes
new/hanadb_exporter-0.5.3/hanadb_exporter.changes
--- old/hanadb_exporter-0.5.1/hanadb_exporter.changes 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter.changes 2019-12-10
12:20:40.950507434 +0100
@@ -1,4 +1,18 @@
-------------------------------------------------------------------
+Tue Dec 10 09:17:42 UTC 2019 - Xabier Arbulu <[email protected]>
+
+- Version 0.5.3 Improve metrics collection if some of the rows
+result is None. Before, if any result was None the result was
+not exported. Now, only metrics with None value are ommitted
+
+-------------------------------------------------------------------
+Mon Dec 9 08:21:18 UTC 2019 - Xabier Arbulu <[email protected]>
+
+- Version 0.5.2 Add the option to use the hanadb_exporter with
+the stored user key. This gives the option to avoid the plain
+user/password strings usage.
+
+-------------------------------------------------------------------
Wed Nov 6 12:48:03 UTC 2019 - Diego Akechi <[email protected]>
- Version 0.5.1 Add the SAP HANA current alerts rating metric.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/hanadb_exporter.spec
new/hanadb_exporter-0.5.3/hanadb_exporter.spec
--- old/hanadb_exporter-0.5.1/hanadb_exporter.spec 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/hanadb_exporter.spec 2019-12-10
12:20:40.950507434 +0100
@@ -26,7 +26,7 @@
%endif
Name: hanadb_exporter
-Version: 0.5.1
+Version: 0.5.3
Release: 0
Summary: SAP HANA database metrics exporter
License: Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/tests/db_manager_test.py
new/hanadb_exporter-0.5.3/tests/db_manager_test.py
--- old/hanadb_exporter-0.5.1/tests/db_manager_test.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/tests/db_manager_test.py 2019-12-10
12:20:40.950507434 +0100
@@ -44,15 +44,21 @@
self._db_manager._system_db_connector = mock.Mock()
self._db_manager._system_db_connector.query.return_value = 'result'
ports = ['30040', '30041']
- mock_format_query.return_value = [{'SQL_PORT': ports[0]}, {'SQL_PORT':
ports[1]}]
-
- for i, port in enumerate(self._db_manager._get_tenants_port()):
- assert port == int(ports[i])
+ dbs = ['PRD', 'QAS']
+ mock_format_query.return_value = [
+ {'DATABASE_NAME': dbs[0], 'SQL_PORT': ports[0]},
+ {'DATABASE_NAME': dbs[1], 'SQL_PORT': ports[1]},
+ {'DATABASE_NAME': 'SYSTEMDB', 'SQL_PORT': '30013'}]
+
+ for i, data in enumerate(self._db_manager._get_tenants_port()):
+ assert data[0] == dbs[i]
+ assert data[1] == int(ports[i])
@mock.patch('hanadb_exporter.db_manager.hdb_connector.HdbConnector')
def test_connect_tenants(self, mock_hdb):
- self._db_manager._get_tenants_port = mock.Mock(return_value=[1, 2, 3])
+ self._db_manager._get_tenants_port = mock.Mock(return_value=[
+ ('db1', 1), ('db2', 2),('db3', 3)])
mock_conn1 = mock.Mock()
mock_conn2 = mock.Mock()
@@ -60,24 +66,121 @@
mock_hdb.side_effect = [mock_conn1, mock_conn2, mock_conn3]
- self._db_manager._connect_tenants('10.10.10.10', 'SYSTEM', 'pass')
+ connection_data = {'mock_data': 'data'}
+
+ self._db_manager._connect_tenants('10.10.10.10', connection_data)
assert mock_hdb.call_count == 3
- mock_conn1.connect.assert_called_once_with(
- '10.10.10.10', 1, user='SYSTEM', password='pass',
RECONNECT='FALSE')
- mock_conn2.connect.assert_called_once_with(
- '10.10.10.10', 2, user='SYSTEM', password='pass',
RECONNECT='FALSE')
- mock_conn3.connect.assert_called_once_with(
- '10.10.10.10', 3, user='SYSTEM', password='pass',
RECONNECT='FALSE')
+ mock_conn1.connect.assert_called_once_with('10.10.10.10', 1,
**connection_data)
+ mock_conn2.connect.assert_called_once_with('10.10.10.10', 2,
**connection_data)
+ mock_conn3.connect.assert_called_once_with('10.10.10.10', 3,
**connection_data)
assert self._db_manager._db_connectors == [mock_conn1, mock_conn2,
mock_conn3]
+ @mock.patch('hanadb_exporter.db_manager.hdb_connector.HdbConnector')
+ def test_connect_tenants_userkey(self, mock_hdb):
+
+ self._db_manager._get_tenants_port = mock.Mock(return_value=[
+ ('db1', 1), ('db2', 2),('db3', 3)])
+
+ mock_conn1 = mock.Mock()
+ mock_conn2 = mock.Mock()
+ mock_conn3 = mock.Mock()
+
+ mock_hdb.side_effect = [mock_conn1, mock_conn2, mock_conn3]
+
+ connection_data = {'mock_data': 'data', 'userkey': 'userkey'}
+ updated_connection_data = [
+ {'mock_data': 'data', 'userkey': 'userkey', 'databaseName': 'db1'},
+ {'mock_data': 'data', 'userkey': 'userkey', 'databaseName': 'db2'},
+ {'mock_data': 'data', 'userkey': 'userkey', 'databaseName': 'db3'}
+ ]
+
+ self._db_manager._connect_tenants('10.10.10.10', connection_data)
+
+ assert mock_hdb.call_count == 3
+
+ mock_conn1.connect.assert_called_once_with('10.10.10.10', 1,
**updated_connection_data[0])
+ mock_conn2.connect.assert_called_once_with('10.10.10.10', 2,
**updated_connection_data[1])
+ mock_conn3.connect.assert_called_once_with('10.10.10.10', 3,
**updated_connection_data[2])
+
+ assert self._db_manager._db_connectors == [mock_conn1, mock_conn2,
mock_conn3]
+
+ def test_get_connection_data_invalid_data(self):
+
+ with pytest.raises(ValueError) as err:
+ self._db_manager._get_connection_data(None, '', '')
+ assert 'Provided user data is not valid. userkey or user/password pair
must be provided' \
+ in str(err.value)
+
+ with pytest.raises(ValueError) as err:
+ self._db_manager._get_connection_data(None, 'user', '')
+ assert 'Provided user data is not valid. userkey or user/password pair
must be provided' \
+ in str(err.value)
+
+ with pytest.raises(ValueError) as err:
+ self._db_manager._get_connection_data(None, '', 'pass')
+ assert 'Provided user data is not valid. userkey or user/password pair
must be provided' \
+ in str(err.value)
+
+ @mock.patch('hanadb_exporter.db_manager.hdb_connector')
+ def test_get_connection_data_not_supported(self, mock_api):
+
+ mock_api.API = 'pyhdb'
+ with pytest.raises(db_manager.UserKeyNotSupportedError) as err:
+ self._db_manager._get_connection_data('userkey', '', '')
+ assert 'userkey usage is not supported with pyhdb connector, hdbcli
must be installed' \
+ in str(err.value)
+
+ @mock.patch('hanadb_exporter.db_manager.hdb_connector')
+ @mock.patch('logging.Logger.warn')
+ @mock.patch('logging.Logger.info')
+ def test_get_connection_data_userkey(self, logger,logger_warn, mock_api):
+
+ mock_api.API = 'dbapi'
+ connection_data = self._db_manager._get_connection_data('userkey', '',
'')
+ assert connection_data == {
+ 'userkey': 'userkey', 'user': '', 'password': '', 'RECONNECT':
'FALSE'}
+ logger.assert_called_once_with(
+ 'stored user key %s will be used to connect to the database',
'userkey')
+ assert logger_warn.call_count == 0
+
+ @mock.patch('hanadb_exporter.db_manager.hdb_connector')
+ @mock.patch('logging.Logger.warn')
+ @mock.patch('logging.Logger.info')
+ def test_get_connection_data_userkey_warn(self, logger,logger_warn,
mock_api):
+
+ mock_api.API = 'dbapi'
+ connection_data = self._db_manager._get_connection_data('userkey',
'user', '')
+ assert connection_data == {
+ 'userkey': 'userkey', 'user': 'user', 'password': '', 'RECONNECT':
'FALSE'}
+ logger.assert_called_once_with(
+ 'stored user key %s will be used to connect to the database',
'userkey')
+ logger_warn.assert_called_once_with(
+ 'userkey will be used to create the connection. user/password are
omitted')
+
+ @mock.patch('hanadb_exporter.db_manager.hdb_connector')
+ @mock.patch('logging.Logger.info')
+ def test_get_connection_data_pass(self, logger, mock_api):
+
+ mock_api.API = 'dbapi'
+ connection_data = self._db_manager._get_connection_data(None, 'user',
'pass')
+ assert connection_data == {
+ 'userkey': None, 'user': 'user', 'password': 'pass', 'RECONNECT':
'FALSE'}
+ logger.assert_called_once_with(
+ 'user/password combination will be used to connect to the databse')
+
@mock.patch('hanadb_exporter.db_manager.hdb_connector.connectors.base_connector')
@mock.patch('logging.Logger.error')
@mock.patch('time.sleep')
@mock.patch('time.time')
def test_start_timeout(self, mock_time, mock_sleep, mock_logger,
mock_exception):
+
+ self._db_manager._get_connection_data = mock.Mock()
+ connection_data = {'mock_data': 'data'}
+ self._db_manager._get_connection_data.return_value = connection_data
+
mock_exception.ConnectionError = Exception
mock_time.side_effect = [0, 1, 2, 3]
self._db_manager._system_db_connector = mock.Mock()
@@ -87,16 +190,17 @@
mock_exception.ConnectionError('err'),
mock_exception.ConnectionError('err')]
+ # Method under test
with pytest.raises(mock_exception.ConnectionError) as err:
self._db_manager.start(
- '10.10.10.10', 30013, 'user', 'pass', multi_tenant=False,
timeout=2)
+ '10.10.10.10', 30013, user='user', password='pass',
multi_tenant=False, timeout=2)
assert 'timeout reached connecting the System database' in
str(err.value)
self._db_manager._system_db_connector.connect.assert_has_calls([
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE')
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data)
])
mock_sleep.assert_has_calls([
@@ -115,9 +219,47 @@
@mock.patch('hanadb_exporter.db_manager.hdb_connector.connectors.base_connector')
@mock.patch('logging.Logger.error')
+ @mock.patch('time.time')
+ def test_start_invalid_key(self, mock_time, mock_logger, mock_exception):
+
+ self._db_manager._get_connection_data = mock.Mock()
+ connection_data = {'mock_data': 'data'}
+ self._db_manager._get_connection_data.return_value = connection_data
+
+ mock_exception.ConnectionError = Exception
+ mock_time.side_effect = [0, 1, 2, 3]
+ self._db_manager._system_db_connector = mock.Mock()
+ self._db_manager._connect_tenants = mock.Mock()
+
+ self._db_manager._system_db_connector.connect.side_effect = [
+ mock_exception.ConnectionError('Error: Invalid value for KEY')]
+
+ # Method under test
+ with pytest.raises(mock_exception.ConnectionError) as err:
+ self._db_manager.start(
+ '10.10.10.10', 30013, user='user', password='pass',
multi_tenant=False, timeout=2)
+
+ assert 'provided userkey is not valid. Check if dbapi is installed
correctly' in str(err.value)
+
+ self._db_manager._system_db_connector.connect.assert_called_once_with(
+ '10.10.10.10', 30013, **connection_data)
+
+ mock_logger.assert_called_once_with(
+ 'the connection to the system database failed. error message: %s',
+ 'Error: Invalid value for KEY')
+
+ self._db_manager._connect_tenants.assert_not_called()
+
+
@mock.patch('hanadb_exporter.db_manager.hdb_connector.connectors.base_connector')
+ @mock.patch('logging.Logger.error')
@mock.patch('time.sleep')
@mock.patch('time.time')
def test_start_correct(self, mock_time, mock_sleep, mock_logger,
mock_exception):
+
+ self._db_manager._get_connection_data = mock.Mock()
+ connection_data = {'mock_data': 'data'}
+ self._db_manager._get_connection_data.return_value = connection_data
+
mock_exception.ConnectionError = Exception
mock_time.side_effect = [0, 1, 2, 3]
self._db_manager._system_db_connector = mock.Mock()
@@ -129,12 +271,12 @@
None]
self._db_manager.start(
- '10.10.10.10', 30013, 'user', 'pass', multi_tenant=False,
timeout=2)
+ '10.10.10.10', 30013, user='user', password='pass',
multi_tenant=False, timeout=2)
self._db_manager._system_db_connector.connect.assert_has_calls([
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE')
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data)
])
mock_sleep.assert_has_calls([
@@ -155,6 +297,11 @@
@mock.patch('time.sleep')
@mock.patch('time.time')
def test_start_correct_multitenant(self, mock_time, mock_sleep,
mock_logger, mock_exception):
+
+ self._db_manager._get_connection_data = mock.Mock()
+ connection_data = {'mock_data': 'data'}
+ self._db_manager._get_connection_data.return_value = connection_data
+
mock_exception.ConnectionError = Exception
mock_time.side_effect = [0, 1, 2, 3]
self._db_manager._system_db_connector = mock.Mock()
@@ -166,12 +313,12 @@
None]
self._db_manager.start(
- '10.10.10.10', 30013, 'user', 'pass', multi_tenant=True, timeout=2)
+ '10.10.10.10', 30013, user='user', password='pass',
multi_tenant=True, timeout=2)
self._db_manager._system_db_connector.connect.assert_has_calls([
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE'),
- mock.call('10.10.10.10', 30013, user='user', password='pass',
RECONNECT='FALSE')
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data),
+ mock.call('10.10.10.10', 30013, **connection_data)
])
mock_sleep.assert_has_calls([
@@ -185,7 +332,7 @@
])
assert self._db_manager._db_connectors ==
[self._db_manager._system_db_connector]
-
self._db_manager._connect_tenants.assert_called_once_with('10.10.10.10',
'user', 'pass')
+
self._db_manager._connect_tenants.assert_called_once_with('10.10.10.10',
connection_data)
def test_get_connectors(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/hanadb_exporter-0.5.1/tests/main_test.py
new/hanadb_exporter-0.5.3/tests/main_test.py
--- old/hanadb_exporter-0.5.1/tests/main_test.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/tests/main_test.py 2019-12-10
12:20:40.950507434 +0100
@@ -137,7 +137,8 @@
mock_setup_logging.assert_called_once_with(config)
mock_db_manager.assert_called_once_with()
db_instance.start.assert_called_once_with(
- '10.10.10.10', 1234, 'user', 'pass', multi_tenant=True,
timeout=600)
+ '10.10.10.10', 1234, user='user', password='pass',
+ userkey=None, multi_tenant=True, timeout=600)
db_instance.get_connectors.assert_called_once_with()
mock_exporters.assert_called_once_with(
connectors='connectors', metrics_file='metrics')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/hanadb_exporter-0.5.1/tests/prometheus_exporter_test.py
new/hanadb_exporter-0.5.3/tests/prometheus_exporter_test.py
--- old/hanadb_exporter-0.5.1/tests/prometheus_exporter_test.py 2019-11-06
12:59:54.036643763 +0100
+++ new/hanadb_exporter-0.5.3/tests/prometheus_exporter_test.py 2019-12-10
12:20:40.950507434 +0100
@@ -180,10 +180,12 @@
assert metric_obj == mock_gauge_instance
@mock.patch('hanadb_exporter.prometheus_exporter.core')
- @mock.patch('logging.Logger.error')
- def test_manage_gauge_incorrect_label(self, mock_logger, mock_core):
+ @mock.patch('logging.Logger.warn')
+ @mock.patch('logging.Logger.debug')
+ def test_manage_gauge_incorrect_label(self, logger_debug, logger_warn,
mock_core):
mock_gauge_instance = mock.Mock()
+ mock_gauge_instance.samples = []
mock_core.GaugeMetricFamily = mock.Mock()
mock_core.GaugeMetricFamily.return_value = mock_gauge_instance
@@ -195,28 +197,30 @@
mock_metric.value = 'column3'
formatted_query = [
- {'column1': 'data1', 'column2': 'data2', 'column3': 'data3'},
- {'column1': 'data4', 'column2': 'data5', 'column3': 'data6'},
- {'column1': 'data7', 'column2': 'data8', 'column3': 'data9'}
+ {'column1': 'data1', 'column2': 'data2', 'column3': 'data3'}
]
- with pytest.raises(ValueError) as err:
- metric_obj = self._collector._manage_gauge(mock_metric,
formatted_query)
+ metric_obj = self._collector._manage_gauge(mock_metric,
formatted_query)
mock_core.GaugeMetricFamily.assert_called_once_with(
'name', 'description', None,
['sid', 'insnr', 'database_name', 'column4', 'column5'], 'mb')
- assert('One or more label(s) specified in metrics.json'
- ' for metric: "{}" is not found in the the query result'.format(
- 'name') in str(err.value))
+ logger_warn.assert_called_once_with(
+ 'One or more label(s) specified in metrics.json '
+ 'for metric "%s" that are not found in the query result',
+ 'name')
+
+ assert mock_gauge_instance.call_count == 0
+ logger_debug.assert_called_once_with('%s \n', [])
@mock.patch('hanadb_exporter.prometheus_exporter.core')
- @mock.patch('logging.Logger.error')
- def test_manage_gauge_incorrect_value(self, mock_logger, mock_core):
+ @mock.patch('logging.Logger.warn')
+ @mock.patch('logging.Logger.debug')
+ def test_manage_gauge_incorrect_value(self, logger_debug, logger_warn,
mock_core):
mock_gauge_instance = mock.Mock()
- mock_gauge_instance.samples = 'samples'
+ mock_gauge_instance.samples = []
mock_core.GaugeMetricFamily = mock.Mock()
mock_core.GaugeMetricFamily.return_value = mock_gauge_instance
@@ -229,20 +233,27 @@
formatted_query = [
{'column1': 'data1', 'column2': 'data2', 'column3': 'data3'},
- {'column1': 'data4', 'column2': 'data5', 'column3': 'data6'},
- {'column1': 'data7', 'column2': 'data8', 'column3': 'data9'}
+ {'column1': 'data4', 'column4': None, 'column3': 'data6'}
]
- with pytest.raises(ValueError) as err:
- metric_obj = self._collector._manage_gauge(mock_metric,
formatted_query)
+ metric_obj = self._collector._manage_gauge(mock_metric,
formatted_query)
mock_core.GaugeMetricFamily.assert_called_once_with(
'name', 'description', None,
['sid', 'insnr', 'database_name', 'column1', 'column2'], 'mb')
- assert('Specified value in metrics.json for metric'
- ' "{}": ({}) not found in the query result'.format(
- 'name', 'column4') in str(err.value))
+ logger_warn.assert_has_calls([
+ mock.call(
+ 'Specified value in metrics.json for metric "%s": (%s) not
found or it is '\
+ 'invalid (None) in the query result',
+ 'name', 'column4'),
+ mock.call(
+ 'Specified value in metrics.json for metric "%s": (%s) not
found or it is '\
+ 'invalid (None) in the query result',
+ 'name', 'column4')
+ ])
+ assert mock_gauge_instance.call_count == 0
+ logger_debug.assert_called_once_with('%s \n', [])
def test_reconnect_connected(self):
self._mock_connector.isconnected.return_value = True