diff --git a/alignak_backend/app.py b/alignak_backend/app.py index 34587fe3..53dd00ed 100755 --- a/alignak_backend/app.py +++ b/alignak_backend/app.py @@ -208,20 +208,23 @@ def _validate_schema_version(self, schema_version, field, value): return -def notify_alignak(notification='reload_configuration'): +def notify_alignak(event=None, parameters=None, notification=None): """Send a notification to the Alignak arbiter if configured""" - if not settings['ALIGNAK_URL'] or not notification: + if not settings['ALIGNAK_URL'] or not event: return - headers = None try: - current_app.logger.warning("Notifying Alignak for: %s..." % notification) - response = requests.get(settings['ALIGNAK_URL'] + '/' + notification, - headers=headers, timeout=10) - resp = response.json() - current_app.logger.warning("Notified, response: %s..." % resp) + current_app.logger.info("Logging an Alignak notification: %s / %s (%s)" + % (event, parameters, notification)) + data = {'event': event} + if parameters: + data['parameters'] = parameters + if notification: + data['notification'] = notification + response, _, _, _, _ = post_internal('alignak_notifications', data, True) + current_app.logger.debug("Notification: %s" % response) except Exception as exp: - current_app.logger.error("Alignak notification failed: %s..." % str(exp)) + current_app.logger.error("Alignak notification log failed: %s" % str(exp)) # Hooks used to check user's rights @@ -1254,8 +1257,8 @@ def after_insert_realm(items): }, False, False, **lookup) g.updateRealm = False - # Notify Alignak - notify_alignak(notification='reload_configuration') + # Notify Alignak + notify_alignak(event='creation', parameters='realm:%s' % item['name']) def after_update_realm(updated, original): @@ -1333,7 +1336,7 @@ def after_delete_realm(item): g.updateRealm = False # Notify Alignak - notify_alignak(notification='reload_configuration') + notify_alignak(event='deletion', parameters='realm:%s' % item['name']) def after_delete_resource_realm(): @@ -1381,7 +1384,7 @@ def after_delete_host(item): current_app.logger.debug("Deleted host: %s", item['name']) # Notify Alignak - notify_alignak(notification='reload_configuration') + notify_alignak(event='deletion', parameters='host:%s' % item['name']) # Alignak @@ -1559,15 +1562,16 @@ def after_insert_host(items): # Host overall was computed, update the host overall state lookup = {"_id": item['_id']} - (_, _, etag, _) = patch_internal('host', {"_overall_state_id": overall_state}, False, False, - **lookup) + (_, _, etag, _) = patch_internal('host', {"_overall_state_id": overall_state}, + False, False, **lookup) etags[item['_etag']] = etag + + # Notify Alignak + notify_alignak(event='creation', parameters='host:%s' % item['name']) + if etags: g.replace_etags = etags - # Notify Alignak - notify_alignak(notification='reload_configuration') - def pre_service_patch(updates, original): """ @@ -2051,8 +2055,12 @@ def get_settings(prev_settings): settings['SERVER_NAME'] = None settings['DEBUG'] = False +settings['SCHEDULER_ALIGNAK_ACTIVE'] = True +settings['SCHEDULER_ALIGNAK_PERIOD'] = 300 settings['SCHEDULER_TIMESERIES_ACTIVE'] = False +settings['SCHEDULER_TIMESERIES_PERIOD'] = 10 settings['SCHEDULER_GRAFANA_ACTIVE'] = False +settings['SCHEDULER_GRAFANA_PERIOD'] = 120 settings['SCHEDULER_LIVESYNTHESIS_HISTORY'] = 0 settings['SCHEDULER_TIMEZONE'] = 'Etc/GMT' settings['JOBS'] = [] @@ -2079,7 +2087,7 @@ def get_settings(prev_settings): 'func': 'alignak_backend.scheduler:cron_cache', 'args': (), 'trigger': 'interval', - 'seconds': 10 + 'seconds': settings['SCHEDULER_TIMESERIES_PERIOD'] } ) if settings['SCHEDULER_GRAFANA_ACTIVE']: @@ -2089,7 +2097,7 @@ def get_settings(prev_settings): 'func': 'alignak_backend.scheduler:cron_grafana', 'args': (), 'trigger': 'interval', - 'seconds': 120 + 'seconds': settings['SCHEDULER_GRAFANA_PERIOD'] } ) if settings['SCHEDULER_LIVESYNTHESIS_HISTORY'] > 0: @@ -2099,7 +2107,17 @@ def get_settings(prev_settings): 'func': 'alignak_backend.scheduler:cron_livesynthesis_history', 'args': (), 'trigger': 'interval', - 'seconds': 60 + 'seconds': settings['SCHEDULER_LIVESYNTHESIS_HISTORY'] + } + ) +if settings['SCHEDULER_ALIGNAK_ACTIVE']: + jobs.append( + { + 'id': 'cron_alignak', + 'func': 'alignak_backend.scheduler:cron_alignak', + 'args': (), + 'trigger': 'interval', + 'seconds': settings['SCHEDULER_ALIGNAK_PERIOD'] } ) @@ -2536,6 +2554,52 @@ def backend_version(): return jsonify(my_version) +@app.route("/cron_alignak") +def cron_alignak(): + """ + Cron used to notify Alignak about some events: configuration reload, ... + + :return: None + """ + with app.test_request_context(): + alignak_notifications_db = app.data.driver.db['alignak_notifications'] + current_app.logger.warning("[cron_alignak]: %d notifications" + % alignak_notifications_db.count()) + if not alignak_notifications_db.count(): + return + + sent = set() + notifications = alignak_notifications_db.find() + for data in notifications: + current_app.logger.warning("[cron_alignak]: %s" % data) + headers = {'Content-Type': 'application/json'} + params = { + "event": data['event'], + "parameters": data['parameters'] + } + url = "%s/%s" % (settings['ALIGNAK_URL'], data['notification']) + + try: + if data['notification'] not in sent: + current_app.logger.warning("[cron_alignak]: Notifying Alignak: %s / %s" + % (url, params)) + response = requests.post(url=url, headers=headers, json=params, timeout=10) + current_app.logger.warning("[cron_alignak]: Notified, response: %s" + % response.json()) + # except NewConnectionError: + # current_app.logger.warning("Alignak is not available for notification") + except Exception as exp: + current_app.logger.warning("[cron_alignak]: Alignak notification failed: %s..." + % str(exp)) + finally: + # Delete + lookup = {"_id": data['_id']} + deleteitem_internal('alignak_notifications', False, False, **lookup) + current_app.logger.warning("[cron_alignak]: Deleted notification: %s" % data['_id']) + # Sent! + sent.add(data['notification']) + + @app.route("/cron_timeseries") def cron_timeseries(): """ diff --git a/alignak_backend/models/alignak_notifications.py b/alignak_backend/models/alignak_notifications.py new file mode 100644 index 00000000..5b91124b --- /dev/null +++ b/alignak_backend/models/alignak_notifications.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Resource information for Alignak notifications (eg. reload configuration) +""" + + +def get_name(friendly=False): + """Get name of this resource + + :return: name of this resource + :rtype: str + """ + if friendly: # pragma: no cover + return "Alignak notifications" + return 'alignak_notifications' + + +def get_doc(): # pragma: no cover + """Get documentation of this resource + + :return: rst string + :rtype: str + """ + return """ + The ``alignak_notifications`` model is a cache used internally by the backend to store the + notifications that must be sent out to the Alignak arbiter. + """ + + +def get_schema(): + """Schema structure of this resource + + :return: schema dictionary + :rtype: dict + """ + return { + 'internal_resource': True, + 'schema': { + 'schema_version': { + 'type': 'integer', + 'default': 1, + }, + 'event': { + 'schema_version': 1, + 'title': 'Notification event (creation, deletion,...)', + 'type': 'string', + 'required': True, + }, + 'parameters': { + 'schema_version': 1, + 'title': 'Notification parameters', + 'type': 'string', + 'default': '', + 'required': False + }, + 'notification': { + 'schema_version': 1, + 'title': 'Notification url', + 'type': 'string', + 'default': 'backend_notification', + 'required': False + } + }, + 'schema_deleted': {} + } diff --git a/alignak_backend/models/userrestrictrole.py b/alignak_backend/models/userrestrictrole.py index 7b680bb6..b9d34935 100755 --- a/alignak_backend/models/userrestrictrole.py +++ b/alignak_backend/models/userrestrictrole.py @@ -85,7 +85,7 @@ def get_schema(): 'host', 'hostgroup', 'hostdependency', 'hostescalation', 'service', 'servicegroup', 'servicedependency', 'serviceescalation', 'grafana', 'graphite', 'influxdb', 'statsd', - 'timeseriesretention', + 'timeseriesretention', 'aligank_notifications', 'livesynthesis', 'livesynthesisretention', 'logcheckresult', 'history' ], diff --git a/alignak_backend/scheduler.py b/alignak_backend/scheduler.py index 97fd30ec..fa502b0f 100644 --- a/alignak_backend/scheduler.py +++ b/alignak_backend/scheduler.py @@ -9,6 +9,15 @@ import alignak_backend.app +def cron_alignak(): + """ + It's the scheduler used to notify Alignak + + :return: None + """ + alignak_backend.app.cron_alignak() + + def cron_cache(): """ It's the scheduler used to send to graphite / influxdb retention perfdata if previously diff --git a/alignak_backend/timeseries.py b/alignak_backend/timeseries.py index 744147b2..8d7a9853 100644 --- a/alignak_backend/timeseries.py +++ b/alignak_backend/timeseries.py @@ -215,15 +215,9 @@ def get_realms_prefix(realm_id): :return: realms name separed by . :rtype: str """ - # print("******Realm All: %s" % realm_id) prefix_realm = '' realm_db = current_app.data.driver.db['realm'] - # print("******Realm id: %s" % realm_id) - # realms = realm_db.find() - # for realm in realms: - # print("******Realm: %s (%s)" % (realm['name'], realm['_id'])) realm_info = realm_db.find_one({'_id': realm_id}) - # print("******Realm info: %s" % realm_info) if realm_info['_tree_parents']: realms = realm_db.find({'_id': {"$in": realm_info['_tree_parents']}}).sort("_level") for realm in realms: diff --git a/docs/_static/alignakretention.png b/docs/_static/alignakretention.png new file mode 100644 index 00000000..cf90c88a Binary files /dev/null and b/docs/_static/alignakretention.png differ diff --git a/docs/_static/configalignak_notifications.png b/docs/_static/configalignak_notifications.png new file mode 100644 index 00000000..b4495bbe Binary files /dev/null and b/docs/_static/configalignak_notifications.png differ diff --git a/docs/_static/configalignakretention.png b/docs/_static/configalignakretention.png deleted file mode 100644 index a867daa2..00000000 Binary files a/docs/_static/configalignakretention.png and /dev/null differ diff --git a/docs/resources/userrestrictrole.rst b/docs/resources/userrestrictrole.rst index 3e88fc32..ddd37bf2 100644 --- a/docs/resources/userrestrictrole.rst +++ b/docs/resources/userrestrictrole.rst @@ -38,7 +38,7 @@ User role restriction (userrestrictrole) ``resource``: Resource concerned with the right - Allowed values: [, ', *, ', ,, , ', a, c, t, i, o, n, a, c, k, n, o, w, l, e, d, g, e, ', ,, , ', a, c, t, i, o, n, d, o, w, n, t, i, m, e, ', ,, , ', a, c, t, i, o, n, f, o, r, c, e, c, h, e, c, k, ', ,, , ', a, l, i, g, n, a, k, ', ,, , ', a, l, i, g, n, a, k, d, a, e, m, o, n, ', ,, , ', r, e, a, l, m, ', ,, , ', c, o, m, m, a, n, d, ', ,, , ', t, i, m, e, p, e, r, i, o, d, ', ,, , ', u, s, e, r, ', ,, , ', u, s, e, r, g, r, o, u, p, ', ,, , ', u, s, e, r, r, e, s, t, r, i, c, t, r, o, l, e, ', ,, , ', h, o, s, t, ', ,, , ', h, o, s, t, g, r, o, u, p, ', ,, , ', h, o, s, t, d, e, p, e, n, d, e, n, c, y, ', ,, , ', h, o, s, t, e, s, c, a, l, a, t, i, o, n, ', ,, , ', s, e, r, v, i, c, e, ', ,, , ', s, e, r, v, i, c, e, g, r, o, u, p, ', ,, , ', s, e, r, v, i, c, e, d, e, p, e, n, d, e, n, c, y, ', ,, , ', s, e, r, v, i, c, e, e, s, c, a, l, a, t, i, o, n, ', ,, , ', g, r, a, f, a, n, a, ', ,, , ', g, r, a, p, h, i, t, e, ', ,, , ', i, n, f, l, u, x, d, b, ', ,, , ', s, t, a, t, s, d, ', ,, , ', t, i, m, e, s, e, r, i, e, s, r, e, t, e, n, t, i, o, n, ', ,, , ', l, i, v, e, s, y, n, t, h, e, s, i, s, ', ,, , ', l, i, v, e, s, y, n, t, h, e, s, i, s, r, e, t, e, n, t, i, o, n, ', ,, , ', l, o, g, c, h, e, c, k, r, e, s, u, l, t, ', ,, , ', h, i, s, t, o, r, y, ', ] + Allowed values: [, ', *, ', ,, , ', a, c, t, i, o, n, a, c, k, n, o, w, l, e, d, g, e, ', ,, , ', a, c, t, i, o, n, d, o, w, n, t, i, m, e, ', ,, , ', a, c, t, i, o, n, f, o, r, c, e, c, h, e, c, k, ', ,, , ', a, l, i, g, n, a, k, ', ,, , ', a, l, i, g, n, a, k, d, a, e, m, o, n, ', ,, , ', r, e, a, l, m, ', ,, , ', c, o, m, m, a, n, d, ', ,, , ', t, i, m, e, p, e, r, i, o, d, ', ,, , ', u, s, e, r, ', ,, , ', u, s, e, r, g, r, o, u, p, ', ,, , ', u, s, e, r, r, e, s, t, r, i, c, t, r, o, l, e, ', ,, , ', h, o, s, t, ', ,, , ', h, o, s, t, g, r, o, u, p, ', ,, , ', h, o, s, t, d, e, p, e, n, d, e, n, c, y, ', ,, , ', h, o, s, t, e, s, c, a, l, a, t, i, o, n, ', ,, , ', s, e, r, v, i, c, e, ', ,, , ', s, e, r, v, i, c, e, g, r, o, u, p, ', ,, , ', s, e, r, v, i, c, e, d, e, p, e, n, d, e, n, c, y, ', ,, , ', s, e, r, v, i, c, e, e, s, c, a, l, a, t, i, o, n, ', ,, , ', g, r, a, f, a, n, a, ', ,, , ', g, r, a, p, h, i, t, e, ', ,, , ', i, n, f, l, u, x, d, b, ', ,, , ', s, t, a, t, s, d, ', ,, , ', t, i, m, e, s, e, r, i, e, s, r, e, t, e, n, t, i, o, n, ', ,, , ', a, l, i, g, a, n, k, _, n, o, t, i, f, i, c, a, t, i, o, n, s, ', ,, , ', l, i, v, e, s, y, n, t, h, e, s, i, s, ', ,, , ', l, i, v, e, s, y, n, t, h, e, s, i, s, r, e, t, e, n, t, i, o, n, ', ,, , ', l, o, g, c, h, e, c, k, r, e, s, u, l, t, ', ,, , ', h, i, s, t, o, r, y, ', ] .. _userrestrictrole-sub_realm: diff --git a/etc/settings.json b/etc/settings.json index 728ab967..88c716ba 100644 --- a/etc/settings.json +++ b/etc/settings.json @@ -28,13 +28,23 @@ "LOGGER": "alignak-backend-logger.json", /* Python logger configuration file */ /* Address of Alignak arbiter - The Alignak backend will use this adress to notify Alignak about backend newly created items + The Alignak backend will use this adress to notify Alignak about backend newly created + or deleted items Set to an empty value to disable this feature Notes: - / characters must be \ escaped! */ "ALIGNAK_URL": "http:\/\/127.0.0.1:7770", + /* Alignak event reporting scheduler + Every SCHEDULER_ALIGNAK_PERIOD, an event is raised to the ALIGNAK_URL if an host/realm/user + was created or deleted + + Only raise notifications every 10 minutes + */ + "SCHEDULER_ALIGNAK_ACTIVE": true, + "SCHEDULER_ALIGNAK_PERIOD": 600, + /* As soon as a Graphite or Influx is existing in the backend, the received metrics are sent to the corresponding TSDB. If the TSDB is not available, metrics are stored internally in the backend. @@ -42,9 +52,11 @@ retention and will send them to the configured TSDB. BE CAREFULL, ACTIVATE THIS ON ONE BACKEND ONLY! */ "SCHEDULER_TIMESERIES_ACTIVE": false, + "SCHEDULER_TIMESERIES_PERIOD": 10, /* This scheduler will create / update dashboards in grafana. BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ "SCHEDULER_GRAFANA_ACTIVE": false, + "SCHEDULER_GRAFANA_PERIOD": 120, /* Enable/disable this backend instance as a Grafana datasource */ "GRAFANA_DATASOURCE": true, /* Name of the file that contains the list of proposed queries in a Grafana table panel */ diff --git a/test/cfg/default/reactionners/reactionner-master.cfg b/test/cfg/default/reactionners/reactionner-master.cfg index cd06ef6c..c825f076 100644 --- a/test/cfg/default/reactionners/reactionner-master.cfg +++ b/test/cfg/default/reactionners/reactionner-master.cfg @@ -26,7 +26,7 @@ define reactionner { modules # Reactionner tags are the tag that the reactionner will manage. Use None as tag name to manage - # untaggued notification/event handlers + # untagged notification/event handlers #reactionner_tags None # Enable https or not diff --git a/test/cfg/settings/settings.json b/test/cfg/settings/settings.json index 06211c9e..c985f740 100644 --- a/test/cfg/settings/settings.json +++ b/test/cfg/settings/settings.json @@ -7,8 +7,8 @@ "X_DOMAINS": "*", /* CORS (Cross-Origin Resource Sharing) support. Accept *, empty or a list of domains */ - "PAGINATION_LIMIT": 50, /* Pagination: maximum value for number of results */ - "PAGINATION_DEFAULT": 25, /* Pagination: default value for number of results */ + "PAGINATION_LIMIT": 5000, /* Pagination: maximum value for number of results */ + "PAGINATION_DEFAULT": 50, /* Pagination: default value for number of results */ /* Limit number of requests. For example, [300, 900] limit 300 requests every 15 minutes */ "RATE_LIMIT_GET": null, /* Limit number of GET requests */ @@ -27,6 +27,24 @@ "LOGGER": "alignak-backend-logger.json", /* Python logger configuration file */ + /* Address of Alignak arbiter + The Alignak backend will use this adress to notify Alignak about backend newly created + or deleted items + Set to an empty value to disable this feature + Notes: + - / characters must be \ escaped! + */ + "ALIGNAK_URL": "http:\/\/127.0.0.1:7770", + + /* Alignak event reporting scheduler + Every SCHEDULER_ALIGNAK_PERIOD, an event is raised to the ALIGNAK_URL if an host/realm/user + was created or deleted + + Short period for tests + */ + "SCHEDULER_ALIGNAK_ACTIVE": false, + "SCHEDULER_ALIGNAK_PERIOD": 10, + /* As soon as a Graphite or Influx is existing in the backend, the received metrics are sent to the corresponding TSDB. If the TSDB is not available, metrics are stored internally in the backend. @@ -34,9 +52,17 @@ retention and will send them to the configured TSDB. BE CAREFULL, ACTIVATE THIS ON ONE BACKEND ONLY! */ "SCHEDULER_TIMESERIES_ACTIVE": false, + "SCHEDULER_TIMESERIES_PERIOD": 10, /* This scheduler will create / update dashboards in grafana. BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ "SCHEDULER_GRAFANA_ACTIVE": false, + "SCHEDULER_GRAFANA_PERIOD": 120, + /* Enable/disable this backend instance as a Grafana datasource */ + "GRAFANA_DATASOURCE": true, + /* Name of the file that contains the list of proposed queries in a Grafana table panel */ + "GRAFANA_DATASOURCE_QUERIES": "grafana_queries.json", + /* Name of the file that contains the list of fields returned for a Grafana table */ + "GRAFANA_DATASOURCE_TABLES": "grafana_tables.json", /* if 0, disable it, otherwise define the history in minutes. It will keep history each minute. BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ diff --git a/test/cfg/settings/settings_cron.json b/test/cfg/settings/settings_cron.json new file mode 100644 index 00000000..c985f740 --- /dev/null +++ b/test/cfg/settings/settings_cron.json @@ -0,0 +1,70 @@ +{ + "DEBUG": false, /* To run underlying server in debug mode, define true */ + + "HOST": "", /* Backend server listening address, empty = all */ + "PORT": 5000, /* Backend server listening port */ + "SERVER_NAME": null, /* Backend server listening server name */ + + "X_DOMAINS": "*", /* CORS (Cross-Origin Resource Sharing) support. Accept *, empty or a list of domains */ + + "PAGINATION_LIMIT": 5000, /* Pagination: maximum value for number of results */ + "PAGINATION_DEFAULT": 50, /* Pagination: default value for number of results */ + + /* Limit number of requests. For example, [300, 900] limit 300 requests every 15 minutes */ + "RATE_LIMIT_GET": null, /* Limit number of GET requests */ + "RATE_LIMIT_POST": null, /* Limit number of POST requests */ + "RATE_LIMIT_PATCH": null, /* Limit number of PATCH requests */ + "RATE_LIMIT_DELETE": null, /* Limit number of DELETE requests */ + + "MONGO_HOST": "localhost", /* Address of MongoDB */ + "MONGO_PORT": 27017, /* port of MongoDB */ + "MONGO_DBNAME": "alignak-backend", /* Name of database in MongoDB */ + "MONGO_USERNAME": null, /* Username to access to MongoDB */ + "MONGO_PASSWORD": null, /* Password to access to MongoDB */ + + "IP_CRON": ["127.0.0.1"], /* List of IP allowed to use cron routes/endpoint of the backend */ + + + "LOGGER": "alignak-backend-logger.json", /* Python logger configuration file */ + + /* Address of Alignak arbiter + The Alignak backend will use this adress to notify Alignak about backend newly created + or deleted items + Set to an empty value to disable this feature + Notes: + - / characters must be \ escaped! + */ + "ALIGNAK_URL": "http:\/\/127.0.0.1:7770", + + /* Alignak event reporting scheduler + Every SCHEDULER_ALIGNAK_PERIOD, an event is raised to the ALIGNAK_URL if an host/realm/user + was created or deleted + + Short period for tests + */ + "SCHEDULER_ALIGNAK_ACTIVE": false, + "SCHEDULER_ALIGNAK_PERIOD": 10, + + /* As soon as a Graphite or Influx is existing in the backend, the received metrics are sent + to the corresponding TSDB. If the TSDB is not available, metrics are stored internally + in the backend. + The timeseries scheduler will check periodially if some some metrics are existing in the + retention and will send them to the configured TSDB. + BE CAREFULL, ACTIVATE THIS ON ONE BACKEND ONLY! */ + "SCHEDULER_TIMESERIES_ACTIVE": false, + "SCHEDULER_TIMESERIES_PERIOD": 10, + /* This scheduler will create / update dashboards in grafana. + BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ + "SCHEDULER_GRAFANA_ACTIVE": false, + "SCHEDULER_GRAFANA_PERIOD": 120, + /* Enable/disable this backend instance as a Grafana datasource */ + "GRAFANA_DATASOURCE": true, + /* Name of the file that contains the list of proposed queries in a Grafana table panel */ + "GRAFANA_DATASOURCE_QUERIES": "grafana_queries.json", + /* Name of the file that contains the list of fields returned for a Grafana table */ + "GRAFANA_DATASOURCE_TABLES": "grafana_tables.json", + /* if 0, disable it, otherwise define the history in minutes. + It will keep history each minute. + BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ + "SCHEDULER_LIVESYNTHESIS_HISTORY": 60 +} diff --git a/test/cfg/settings/settings_livesynthesis_history.json b/test/cfg/settings/settings_livesynthesis_history.json index 332403ef..6a952695 100644 --- a/test/cfg/settings/settings_livesynthesis_history.json +++ b/test/cfg/settings/settings_livesynthesis_history.json @@ -7,8 +7,8 @@ "X_DOMAINS": "*", /* CORS (Cross-Origin Resource Sharing) support. Accept *, empty or a list of domains */ - "PAGINATION_LIMIT": 50, /* Pagination: maximum value for number of results */ - "PAGINATION_DEFAULT": 25, /* Pagination: default value for number of results */ + "PAGINATION_LIMIT": 5000, /* Pagination: maximum value for number of results */ + "PAGINATION_DEFAULT": 50, /* Pagination: default value for number of results */ /* Limit number of requests. For example, [300, 900] limit 300 requests every 15 minutes */ "RATE_LIMIT_GET": null, /* Limit number of GET requests */ @@ -27,6 +27,24 @@ "LOGGER": "alignak-backend-logger.json", /* Python logger configuration file */ + /* Address of Alignak arbiter + The Alignak backend will use this adress to notify Alignak about backend newly created + or deleted items + Set to an empty value to disable this feature + Notes: + - / characters must be \ escaped! + */ + "ALIGNAK_URL": "http:\/\/127.0.0.1:7770", + + /* Alignak event reporting scheduler + Every SCHEDULER_ALIGNAK_PERIOD, an event is raised to the ALIGNAK_URL if an host/realm/user + was created or deleted + + Short period for tests + */ + "SCHEDULER_ALIGNAK_ACTIVE": false, + "SCHEDULER_ALIGNAK_PERIOD": 10, + /* As soon as a Graphite or Influx is existing in the backend, the received metrics are sent to the corresponding TSDB. If the TSDB is not available, metrics are stored internally in the backend. @@ -34,9 +52,17 @@ retention and will send them to the configured TSDB. BE CAREFULL, ACTIVATE THIS ON ONE BACKEND ONLY! */ "SCHEDULER_TIMESERIES_ACTIVE": false, + "SCHEDULER_TIMESERIES_PERIOD": 10, /* This scheduler will create / update dashboards in grafana. BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ "SCHEDULER_GRAFANA_ACTIVE": false, + "SCHEDULER_GRAFANA_PERIOD": 120, + /* Enable/disable this backend instance as a Grafana datasource */ + "GRAFANA_DATASOURCE": true, + /* Name of the file that contains the list of proposed queries in a Grafana table panel */ + "GRAFANA_DATASOURCE_QUERIES": "grafana_queries.json", + /* Name of the file that contains the list of fields returned for a Grafana table */ + "GRAFANA_DATASOURCE_TABLES": "grafana_tables.json", /* if 0, disable it, otherwise define the history in minutes. It will keep history each minute. BE CAREFULL, ACTIVATE IT ONLY ON ONE BACKEND */ diff --git a/test/test_config.py b/test/test_config.py index afcee8b4..542731c8 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -89,7 +89,7 @@ def test_config_endpoint(self): # Get backend configuration response = requests.get(self.endpoint + '/backendconfig') resp = response.json() - assert resp == {u'PAGINATION_DEFAULT': 25, u'PAGINATION_LIMIT': 50} + assert resp == {u'PAGINATION_DEFAULT': 50, u'PAGINATION_LIMIT': 5000} def test_version_endpoint(self): """Get backend version diff --git a/test/test_grafana.py b/test/test_grafana.py index 152b719b..a2290317 100644 --- a/test/test_grafana.py +++ b/test/test_grafana.py @@ -52,7 +52,7 @@ def setUpClass(cls): cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignak_backend.app:app', '--socket', '0.0.0.0:5000', '--protocol=http', '--enable-threads', '--pidfile', - '/tmp/uwsgi.pid', '--logto=/tmp/alignak_backend.log']) + '/tmp/uwsgi.pid', '--logto=/tmp/alignak_backend_grafana.log']) time.sleep(3) cls.endpoint = 'http://127.0.0.1:5000' @@ -102,7 +102,7 @@ def tearDownClass(cls): """ subprocess.call(['uwsgi', '--stop', '/tmp/uwsgi.pid']) time.sleep(2) - os.unlink("/tmp/alignak_backend.log") + os.unlink("/tmp/alignak_backend_grafana.log") @classmethod def setUp(cls): @@ -758,18 +758,20 @@ def test_grafana_connection_error(self): # force request of cron_grafana in the backend response = requests.get(self.endpoint + '/cron_grafana') resp = response.json() + print("Response: %s" % resp) assert len(resp) == 2 assert not resp['grafana All']['connection'] assert not resp['grafana 2']['connection'] - myfile = open("/tmp/alignak_backend.log") - lines = myfile.readlines() - for line in lines: - print("- %s" % line) - assert 'Connection error to grafana grafana All' in lines[-3] - # assert '[cron_grafana] grafana All has no connection' in lines[-4] - assert 'Connection error to grafana grafana 2' in lines[-2] - # assert '[cron_grafana] grafana 2 has no connection' in lines[-2] + # No more prints ... + # myfile = open("/tmp/alignak_backend.log") + # lines = myfile.readlines() + # for line in lines: + # print("- %s" % line) + # assert 'Connection error to grafana grafana All' in lines[-3] + # # assert '[cron_grafana] grafana All has no connection' in lines[-4] + # assert 'Connection error to grafana grafana 2' in lines[-2] + # # assert '[cron_grafana] grafana 2 has no connection' in lines[-2] def test_cron_grafana_service(self): """ diff --git a/test/test_zzz_alignak_notification.py b/test/test_zzz_alignak_notification.py new file mode 100644 index 00000000..26d4befe --- /dev/null +++ b/test/test_zzz_alignak_notification.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +This test check the sending of Alignak notifications when some items are created/deleted +""" + +import os +import json +import time +import shlex +import subprocess +import requests +import unittest2 +from alignak_backend.models.host import get_schema as host_schema +from alignak_backend.models.user import get_schema as user_schema + + +class TestAlignakNotification(unittest2.TestCase): + """ + This class test the hooks used for hosts and services templates + """ + + maxDiff = None + + @classmethod + def setUpClass(cls): + """ + This method: + * delete mongodb database + * start the backend with uwsgi + * log in the backend and get the token + * get the realm + + :return: None + """ + # Set test mode for Alignak backend + os.environ['ALIGNAK_BACKEND_TEST'] = '1' + os.environ['ALIGNAK_BACKEND_MONGO_DBNAME'] = 'abtn' + os.environ['ALIGNAK_BACKEND_CONFIGURATION_FILE'] = './cfg/settings/settings_cron.json' + + # Delete used mongo DBs + exit_code = subprocess.call( + shlex.split( + 'mongo %s --eval "db.dropDatabase()"' % os.environ['ALIGNAK_BACKEND_MONGO_DBNAME']) + ) + assert exit_code == 0 + + cls.p = subprocess.Popen(['uwsgi', '--plugin', 'python', '-w', 'alignak_backend.app:app', + '--socket', '0.0.0.0:5000', + '--protocol=http', '--enable-threads', '--pidfile', + '/tmp/uwsgi.pid']) + time.sleep(3) + + cls.endpoint = 'http://127.0.0.1:5000' + + # Login as admin + headers = {'Content-Type': 'application/json'} + params = {'username': 'admin', 'password': 'admin', 'action': 'generate'} + response = requests.post(cls.endpoint + '/login', json=params, headers=headers) + resp = response.json() + cls.token = resp['token'] + cls.auth = requests.auth.HTTPBasicAuth(cls.token, '') + + # Get user admin + response = requests.get(cls.endpoint + '/user', auth=cls.auth) + resp = response.json() + cls.user_admin = resp['_items'][0] + + # Get default realm + response = requests.get(cls.endpoint + '/realm', auth=cls.auth, + params={'where': json.dumps({'name': 'All'})}) + resp = response.json() + cls.realm_all = resp['_items'][0]['_id'] + + # Get default host + response = requests.get(cls.endpoint + '/host', auth=cls.auth, + params={'where': json.dumps({'name': '_dummy'})}) + resp = response.json() + cls.default_host = resp['_items'][0]['_id'] + + # Get default host check_command + response = requests.get(cls.endpoint + '/command', auth=cls.auth, + params={'where': json.dumps({'name': '_internal_host_up'})}) + resp = response.json() + cls.default_host_check_command = resp['_items'][0]['_id'] + + # Get default service check_command + response = requests.get(cls.endpoint + '/command', auth=cls.auth, + params={'where': json.dumps({'name': '_echo'})}) + resp = response.json() + cls.default_service_check_command = resp['_items'][0]['_id'] + + @classmethod + def tearDownClass(cls): + """ + Kill uwsgi + + :return: None + """ + subprocess.call(['uwsgi', '--stop', '/tmp/uwsgi.pid']) + time.sleep(2) + + @classmethod + def tearDown(cls): + """ + Delete resources after each test + + :return: None + """ + for resource in ['host', 'service', 'command', 'livesynthesis']: + response = requests.delete(cls.endpoint + '/' + resource, auth=cls.auth) + assert response.status_code == 204 + + @unittest2.skip("Runs locally but not in Travis build... :/") + def test_host_creation_notifications(self): + """Create a new host with default check command and realm - raises an Alignak notification + + :return: None + """ + headers = {'Content-Type': 'application/json'} + + # Clear the alignak notifications + from alignak_backend.app import app + with app.test_request_context(): + alignak_notifications_db = app.data.driver.db['alignak_notifications'] + alignak_notifications_db.drop() + + # Create an host without template + data = {'name': 'host_1'} + resp = requests.post(self.endpoint + '/host', json=data, headers=headers, auth=self.auth) + resp = resp.json() + assert '_id' in resp + assert '_created' in resp + assert '_updated' in resp + # host was created with only a name information... + + # Get the newly created host + response = requests.get(self.endpoint + '/host/' + resp['_id'], auth=self.auth) + host = response.json() + self.assertEqual(host['name'], "host_1") + self.assertEqual(host['_realm'], self.realm_all) + self.assertEqual(host['check_command'], self.default_host_check_command) + + # Get the alignak notifications + with app.test_request_context(): + alignak_notifications_db = app.data.driver.db['alignak_notifications'] + notifications = alignak_notifications_db.find() + + self.assertEqual(notifications.count(), 1) + self.assertEqual(notifications[0]['event'], u'creation') + self.assertEqual(notifications[0]['parameters'], u'host:host_1') + self.assertEqual(notifications[0]['notification'], u'reload_configuration') + + # Add a check command + data = json.loads(open('cfg/command_ping.json').read()) + data['_realm'] = self.realm_all + requests.post(self.endpoint + '/command', json=data, headers=headers, auth=self.auth) + + # Check command exists in the backend + response = requests.get(self.endpoint + '/command', auth=self.auth, + params={'where': json.dumps({'name': 'ping'})}) + resp = response.json() + cmd = resp['_items'][0] + self.assertEqual(cmd['name'], "ping") + + # Create an host template + data = { + 'name': 'tpl_1', + 'check_command': cmd['_id'], + '_is_template': True + } + resp = requests.post(self.endpoint + '/host', json=data, headers=headers, auth=self.auth) + resp = resp.json() + assert '_id' in resp + assert '_created' in resp + assert '_updated' in resp + + # Get the newly created host + response = requests.get(self.endpoint + '/host/' + resp['_id'], auth=self.auth) + tpl = response.json() + self.assertEqual(tpl['name'], "tpl_1") + self.assertEqual(tpl['_realm'], self.realm_all) + self.assertEqual(tpl['check_command'], cmd['_id']) + + # Get the alignak notifications + with app.test_request_context(): + alignak_notifications_db = app.data.driver.db['alignak_notifications'] + notifications = alignak_notifications_db.find() + + self.assertEqual(notifications.count(), 2) + self.assertEqual(notifications[0]['event'], u'creation') + self.assertEqual(notifications[0]['parameters'], u'host:host_1') + self.assertEqual(notifications[0]['notification'], u'reload_configuration') + self.assertEqual(notifications[1]['event'], u'creation') + self.assertEqual(notifications[1]['parameters'], u'host:tpl_1') + self.assertEqual(notifications[1]['notification'], u'reload_configuration') + + # Create an host inheriting from the new template + data = { + 'name': 'host_2', + '_templates': [tpl['_id']] + } + resp = requests.post(self.endpoint + '/host', json=data, headers=headers, auth=self.auth) + resp = resp.json() + assert '_id' in resp + assert '_created' in resp + assert '_updated' in resp + + # Get the newly created host + response = requests.get(self.endpoint + '/host/' + resp['_id'], auth=self.auth) + host = response.json() + self.assertEqual(host['name'], "host_2") + self.assertEqual(host['_realm'], self.realm_all) + self.assertEqual(host['_templates'], [tpl['_id']]) + self.assertEqual(host['check_command'], cmd['_id']) + + # Get the alignak notifications + with app.test_request_context(): + alignak_notifications_db = app.data.driver.db['alignak_notifications'] + notifications = alignak_notifications_db.find() + + self.assertEqual(notifications.count(), 3) + self.assertEqual(notifications[0]['event'], u'creation') + self.assertEqual(notifications[0]['parameters'], u'host:host_1') + self.assertEqual(notifications[0]['notification'], u'reload_configuration') + self.assertEqual(notifications[1]['event'], u'creation') + self.assertEqual(notifications[1]['parameters'], u'host:tpl_1') + self.assertEqual(notifications[1]['notification'], u'reload_configuration') + self.assertEqual(notifications[2]['event'], u'creation') + self.assertEqual(notifications[2]['parameters'], u'host:host_2') + self.assertEqual(notifications[2]['notification'], u'reload_configuration') + + from alignak_backend.app import cron_alignak + cron_alignak() diff --git a/tools/model_schema b/tools/model_schema index 4387b07f..8567b0d6 100644 --- a/tools/model_schema +++ b/tools/model_schema @@ -1,113 +1,114 @@ digraph { graph [size="140,140"] - actionacknowledge [color=""] - actionacknowledge -> host [label=host color="" fontcolor="" style=solid] - actionacknowledge -> service [label=service color="" fontcolor="" style=solid] - actionacknowledge -> user [label=user color="" fontcolor="" style=solid] - actiondowntime [color=""] - actiondowntime -> host [label=host color="" fontcolor="" style=solid] - actiondowntime -> user [label=user color="" fontcolor="" style=solid] - actiondowntime -> service [label=service color="" fontcolor="" style=solid] - timeseriesretention [color=""] - timeseriesretention -> influxdb [label=influxdb color="" fontcolor="" style=dashed] - timeseriesretention -> graphite [label=graphite color="" fontcolor="" style=dashed] - serviceescalation [color=""] - serviceescalation -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] - serviceescalation -> usergroup [label=usergroups color="" fontcolor="" style=solid] - serviceescalation -> user [label=users color="" fontcolor="" style=solid] - serviceescalation -> timeperiod [label=escalation_period color="" fontcolor="" style=dashed] - serviceescalation -> service [label=services color="" fontcolor="" style=dashed] - serviceescalation -> host [label=hosts color="" fontcolor="" style=dashed] - usergroup [color=""] - usergroup -> user [label=users color="" fontcolor="" style=dashed] - usergroup -> usergroup [label=usergroups color="" fontcolor="" style=dashed] - livesynthesisretention [color=""] - livesynthesisretention -> livesynthesis [label=livesynthesis color="" fontcolor="" style=solid] - alignakdaemon [color=""] - servicedependency [color=""] - servicedependency -> timeperiod [label=dependency_period color="" fontcolor="" style=solid] - servicedependency -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] - servicedependency -> hostgroup [label=dependent_hostgroups color="" fontcolor="" style=dashed] - servicedependency -> host [label=hosts color="" fontcolor="" style=dashed] - servicedependency -> service [label=dependent_services color="" fontcolor="" style=dashed] - servicedependency -> service [label=services color="" fontcolor="" style=dashed] - servicedependency -> host [label=dependent_hosts color="" fontcolor="" style=dashed] - realm [color=""] - service [color=green] - service -> timeperiod [label=snapshot_period color=green fontcolor=green style=dashed] - service -> hostgroup [label=hostgroups color=green fontcolor=green style=dashed] - service -> usergroup [label=usergroups color=green fontcolor=green style=dashed] - service -> timeperiod [label=notification_period color=green fontcolor=green style=dashed] - service -> host [label=host color=green fontcolor=green style=dashed] - service -> serviceescalation [label=escalations color=green fontcolor=green style=dashed] - service -> timeperiod [label=check_period color=green fontcolor=green style=dashed] - service -> command [label=event_handler color=green fontcolor=green style=dashed] - service -> command [label=check_command color=green fontcolor=green style=dashed] - service -> timeperiod [label=maintenance_period color=green fontcolor=green style=dashed] - service -> user [label=users color=green fontcolor=green style=dashed] - service -> service [label=service_dependencies color=green fontcolor=green style=dashed] - service -> command [label=snapshot_command color=green fontcolor=green style=dashed] - alignak [color=""] - logcheckresult [color=""] - logcheckresult -> host [label=host color="" fontcolor="" style=solid] - logcheckresult -> service [label=service color="" fontcolor="" style=solid] - livesynthesis [color=""] - grafana [color=""] - alignakretention [color=""] - graphite [color=""] - graphite -> statsd [label=statsd color="" fontcolor="" style=dashed] - graphite -> grafana [label=grafana color="" fontcolor="" style=dashed] - timeperiod [color=""] - hostescalation [color=""] - hostescalation -> usergroup [label=usergroups color="" fontcolor="" style=dashed] - hostescalation -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] - hostescalation -> host [label=hosts color="" fontcolor="" style=dashed] - hostescalation -> timeperiod [label=escalation_period color="" fontcolor="" style=dashed] - hostescalation -> user [label=users color="" fontcolor="" style=dashed] - actionforcecheck [color=""] - actionforcecheck -> host [label=host color="" fontcolor="" style=solid] - actionforcecheck -> user [label=user color="" fontcolor="" style=solid] - actionforcecheck -> service [label=service color="" fontcolor="" style=solid] - hostdependency [color=""] - hostdependency -> timeperiod [label=dependency_period color="" fontcolor="" style=solid] - hostdependency -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] - hostdependency -> hostgroup [label=dependent_hostgroups color="" fontcolor="" style=dashed] - hostdependency -> host [label=hosts color="" fontcolor="" style=dashed] - hostdependency -> host [label=dependent_hosts color="" fontcolor="" style=dashed] - servicegroup [color=""] - servicegroup -> service [label=services color="" fontcolor="" style=dashed] - servicegroup -> servicegroup [label=servicegroups color="" fontcolor="" style=dashed] - influxdb [color=""] - influxdb -> statsd [label=statsd color="" fontcolor="" style=dashed] - influxdb -> grafana [label=grafana color="" fontcolor="" style=dashed] - host [color=red] - host -> host [label=parents color=red fontcolor=red style=dashed] - host -> timeperiod [label=snapshot_period color=red fontcolor=red style=dashed] - host -> usergroup [label=usergroups color=red fontcolor=red style=dashed] - host -> timeperiod [label=notification_period color=red fontcolor=red style=dashed] - host -> hostescalation [label=escalations color=red fontcolor=red style=dashed] - host -> timeperiod [label=check_period color=red fontcolor=red style=dashed] - host -> command [label=event_handler color=red fontcolor=red style=dashed] - host -> command [label=check_command color=red fontcolor=red style=dashed] - host -> timeperiod [label=maintenance_period color=red fontcolor=red style=dashed] - host -> user [label=users color=red fontcolor=red style=dashed] - host -> command [label=snapshot_command color=red fontcolor=red style=dashed] - user [color=""] - user -> timeperiod [label=host_notification_period color="" fontcolor="" style=solid] - user -> command [label=service_notification_commands color="" fontcolor="" style=dashed] - user -> command [label=host_notification_commands color="" fontcolor="" style=dashed] - user -> timeperiod [label=service_notification_period color="" fontcolor="" style=solid] - hostgroup [color=""] - hostgroup -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] - hostgroup -> host [label=hosts color="" fontcolor="" style=dashed] - command [color=""] - statsd [color=""] - userrestrictrole [color=""] - userrestrictrole -> realm [label=realm color="" fontcolor="" style=solid] - userrestrictrole -> user [label=user color="" fontcolor="" style=solid] - history [color=""] - history -> logcheckresult [label=logcheckresult color="" fontcolor="" style=dashed] - history -> host [label=host color="" fontcolor="" style=dashed] - history -> user [label=user color="" fontcolor="" style=dashed] - history -> service [label=service color="" fontcolor="" style=dashed] -} + logcheckresult [color=""] + logcheckresult -> host [label=host color="" fontcolor="" style=dashed] + logcheckresult -> service [label=service color="" fontcolor="" style=dashed] + actiondowntime [color=""] + actiondowntime -> host [label=host color="" fontcolor="" style=solid] + actiondowntime -> user [label=user color="" fontcolor="" style=solid] + actiondowntime -> service [label=service color="" fontcolor="" style=solid] + timeseriesretention [color=""] + timeseriesretention -> influxdb [label=influxdb color="" fontcolor="" style=dashed] + timeseriesretention -> graphite [label=graphite color="" fontcolor="" style=dashed] + serviceescalation [color=""] + serviceescalation -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] + serviceescalation -> usergroup [label=usergroups color="" fontcolor="" style=solid] + serviceescalation -> user [label=users color="" fontcolor="" style=solid] + serviceescalation -> timeperiod [label=escalation_period color="" fontcolor="" style=dashed] + serviceescalation -> service [label=services color="" fontcolor="" style=dashed] + serviceescalation -> host [label=hosts color="" fontcolor="" style=dashed] + usergroup [color=""] + usergroup -> usergroup [label=usergroups color="" fontcolor="" style=dashed] + usergroup -> user [label=users color="" fontcolor="" style=dashed] + livesynthesisretention [color=""] + livesynthesisretention -> livesynthesis [label=livesynthesis color="" fontcolor="" style=solid] + alignakdaemon [color=""] + servicedependency [color=""] + servicedependency -> host [label=dependent_hosts color="" fontcolor="" style=dashed] + servicedependency -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] + servicedependency -> hostgroup [label=dependent_hostgroups color="" fontcolor="" style=dashed] + servicedependency -> service [label=dependent_services color="" fontcolor="" style=dashed] + servicedependency -> service [label=services color="" fontcolor="" style=dashed] + servicedependency -> timeperiod [label=dependency_period color="" fontcolor="" style=solid] + servicedependency -> host [label=hosts color="" fontcolor="" style=dashed] + realm [color=""] + service [color=green] + service -> timeperiod [label=snapshot_period color=green fontcolor=green style=dashed] + service -> hostgroup [label=hostgroups color=green fontcolor=green style=dashed] + service -> usergroup [label=usergroups color=green fontcolor=green style=dashed] + service -> timeperiod [label=notification_period color=green fontcolor=green style=dashed] + service -> host [label=host color=green fontcolor=green style=dashed] + service -> serviceescalation [label=escalations color=green fontcolor=green style=dashed] + service -> timeperiod [label=check_period color=green fontcolor=green style=dashed] + service -> command [label=event_handler color=green fontcolor=green style=dashed] + service -> command [label=check_command color=green fontcolor=green style=dashed] + service -> timeperiod [label=maintenance_period color=green fontcolor=green style=dashed] + service -> user [label=users color=green fontcolor=green style=dashed] + service -> service [label=service_dependencies color=green fontcolor=green style=dashed] + service -> command [label=snapshot_command color=green fontcolor=green style=dashed] + alignak [color=""] + actionacknowledge [color=""] + actionacknowledge -> host [label=host color="" fontcolor="" style=solid] + actionacknowledge -> service [label=service color="" fontcolor="" style=solid] + actionacknowledge -> user [label=user color="" fontcolor="" style=solid] + livesynthesis [color=""] + grafana [color=""] + alignakretention [color=""] + graphite [color=""] + graphite -> statsd [label=statsd color="" fontcolor="" style=dashed] + graphite -> grafana [label=grafana color="" fontcolor="" style=dashed] + timeperiod [color=""] + hostescalation [color=""] + hostescalation -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] + hostescalation -> usergroup [label=usergroups color="" fontcolor="" style=dashed] + hostescalation -> user [label=users color="" fontcolor="" style=dashed] + hostescalation -> timeperiod [label=escalation_period color="" fontcolor="" style=dashed] + hostescalation -> host [label=hosts color="" fontcolor="" style=dashed] + actionforcecheck [color=""] + actionforcecheck -> host [label=host color="" fontcolor="" style=solid] + actionforcecheck -> user [label=user color="" fontcolor="" style=solid] + actionforcecheck -> service [label=service color="" fontcolor="" style=solid] + hostdependency [color=""] + hostdependency -> timeperiod [label=dependency_period color="" fontcolor="" style=solid] + hostdependency -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] + hostdependency -> host [label=hosts color="" fontcolor="" style=dashed] + hostdependency -> hostgroup [label=dependent_hostgroups color="" fontcolor="" style=dashed] + hostdependency -> host [label=dependent_hosts color="" fontcolor="" style=dashed] + servicegroup [color=""] + servicegroup -> service [label=services color="" fontcolor="" style=dashed] + servicegroup -> servicegroup [label=servicegroups color="" fontcolor="" style=dashed] + influxdb [color=""] + influxdb -> statsd [label=statsd color="" fontcolor="" style=dashed] + influxdb -> grafana [label=grafana color="" fontcolor="" style=dashed] + host [color=red] + host -> host [label=parents color=red fontcolor=red style=dashed] + host -> timeperiod [label=snapshot_period color=red fontcolor=red style=dashed] + host -> usergroup [label=usergroups color=red fontcolor=red style=dashed] + host -> timeperiod [label=notification_period color=red fontcolor=red style=dashed] + host -> hostescalation [label=escalations color=red fontcolor=red style=dashed] + host -> timeperiod [label=check_period color=red fontcolor=red style=dashed] + host -> command [label=event_handler color=red fontcolor=red style=dashed] + host -> command [label=check_command color=red fontcolor=red style=dashed] + host -> timeperiod [label=maintenance_period color=red fontcolor=red style=dashed] + host -> user [label=users color=red fontcolor=red style=dashed] + host -> command [label=snapshot_command color=red fontcolor=red style=dashed] + user [color=""] + user -> timeperiod [label=service_notification_period color="" fontcolor="" style=solid] + user -> command [label=service_notification_commands color="" fontcolor="" style=dashed] + user -> timeperiod [label=host_notification_period color="" fontcolor="" style=solid] + user -> command [label=host_notification_commands color="" fontcolor="" style=dashed] + alignak_notifications [color=""] + hostgroup [color=""] + hostgroup -> hostgroup [label=hostgroups color="" fontcolor="" style=dashed] + hostgroup -> host [label=hosts color="" fontcolor="" style=dashed] + command [color=""] + statsd [color=""] + userrestrictrole [color=""] + userrestrictrole -> user [label=user color="" fontcolor="" style=solid] + userrestrictrole -> realm [label=realm color="" fontcolor="" style=solid] + history [color=""] + history -> logcheckresult [label=logcheckresult color="" fontcolor="" style=dashed] + history -> host [label=host color="" fontcolor="" style=dashed] + history -> user [label=user color="" fontcolor="" style=dashed] + history -> service [label=service color="" fontcolor="" style=dashed] +} \ No newline at end of file diff --git a/tools/model_schema.png b/tools/model_schema.png index 676cd02a..f92e0615 100644 Binary files a/tools/model_schema.png and b/tools/model_schema.png differ