Skip to content

Commit 9a80da6

Browse files
committed
[timeseries] Add initial support for elasticsearch #99
1 parent 5beb089 commit 9a80da6

26 files changed

+1314
-159
lines changed

.travis.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,30 @@ addons:
2424

2525
services:
2626
- docker
27-
- redis-server
2827

2928
branches:
3029
only:
3130
- master
3231
- dev
3332

3433
before_install:
35-
- docker run -d --name influxdb -e INFLUXDB_DB=openwisp2 -p 8086:8086 influxdb:alpine
34+
- docker-compose up -d
3635
- pip install -U pip wheel setuptools
3736
- pip install $DJANGO
3837
- pip install -U -r requirements-test.txt
3938

4039
install:
41-
- pip install -e .
40+
- pip install -e .[influxdb,elasticsearch]
4241
- sh install-dev.sh
4342

4443
script:
4544
- ./run-qa-checks
46-
- SAMPLE_APP=1 coverage run --source=openwisp_monitoring runtests.py
47-
- coverage run -a --source=openwisp_monitoring runtests.py
45+
- SAMPLE_APP=1 coverage run -p --source=openwisp_monitoring runtests.py
46+
- coverage run -p --source=openwisp_monitoring runtests.py
47+
- elasticsearch=1 SAMPLE_APP=1 coverage run -p --source=openwisp_monitoring runtests.py
48+
- elasticsearch=1 coverage run -p --source=openwisp_monitoring runtests.py
49+
- coverage combine
50+
- coverage report -m
4851

4952
jobs:
5053
include:

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ WORKDIR /opt/openwisp/tests/
1919
ENV NAME=openwisp-monitoring \
2020
PYTHONBUFFERED=1 \
2121
INFLUXDB_HOST=influxdb \
22-
REDIS_HOST=redis
22+
REDIS_HOST=redis \
23+
ELASTICSEARCH_HOST=es01
2324
CMD ["sh", "docker-entrypoint.sh"]
2425
EXPOSE 8000

README.rst

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Available Features
2525
* Collects and displays device status information like uptime, RAM status, CPU load averages,
2626
Interface properties and addresses, WiFi interface status and associated clients,
2727
Neighbors information, DHCP Leases, Disk/Flash status
28-
* Collection of monitoring information in a timeseries database (currently only influxdb is supported)
28+
* Collection of monitoring information in a timeseries database (`InfluxDB <https://www.influxdata.com/>`_ and `Elasticsearch <https://www.elastic.co/elasticsearch/>`_ are currently supported)
2929
* Monitoring charts for uptime, packet loss, round trip time (latency), associated wifi clients, interface traffic,
3030
RAM usage, CPU load, flash/disk usage
3131
* Charts can be viewed at resolutions of 1 day, 3 days, a week, a month and a year
@@ -47,6 +47,8 @@ beforehand.
4747
In case you prefer not to use Docker you can `install InfluxDB <https://docs.influxdata.com/influxdb/v1.8/introduction/install/>`_
4848
and Redis from your repositories, but keep in mind that the version packaged by your distribution may be different.
4949

50+
If you wish to use ``Elasticsearch`` for storing and retrieving timeseries data then `install Elasticsearch <https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html>`_.
51+
5052
Install spatialite and sqlite:
5153

5254
.. code-block:: shell
@@ -107,6 +109,19 @@ Follow the setup instructions of `openwisp-controller
107109
'PORT': '8086',
108110
}
109111
112+
In case, you wish to use ``Elasticsearch`` for timeseries data storage and retrieval,
113+
make use of the following settings
114+
115+
.. code-block:: python
116+
TIMESERIES_DATABASE = {
117+
'BACKEND': 'openwisp_monitoring.db.backends.elasticsearch',
118+
'USER': 'openwisp',
119+
'PASSWORD': 'openwisp',
120+
'NAME': 'openwisp2',
121+
'HOST': 'localhost',
122+
'PORT': '9200',
123+
}
124+
110125
``urls.py``:
111126

112127
.. code-block:: python
@@ -246,6 +261,9 @@ This data is only used to assess the recent status of devices, keeping
246261
it for a long time would not add much benefit and would cost a lot more
247262
in terms of disk space.
248263

264+
**Note**: In case you use ``Elasticsearch`` then time shall be taken as integral multiple of a day.
265+
That means the time ``36h0m0s`` shall be interpreted as ``24h0m0s`` (integral multiple of a day).
266+
249267
``OPENWISP_MONITORING_AUTO_PING``
250268
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251269

@@ -402,18 +420,30 @@ MB (megabytes) instead of GB (Gigabytes) you can use:
402420
"SUM(rx_bytes) / 1000000 AS download FROM {key} "
403421
"WHERE time >= '{time}' AND content_type = '{content_type}' "
404422
"AND object_id = '{object_id}' GROUP BY time(1d)"
405-
)
423+
),
424+
'elasticsearch': _make_query({
425+
'upload': {'sum': {'field': 'points.fields.tx_bytes'}},
426+
'download': {'avg': {'field': 'points.fields.rx_bytes'}},
427+
})
406428
},
407429
}
408430
}
409431
432+
# Please declare the operations separately in case you use elasticsearch as done below
433+
OPENWISP_MONITORING_ADDITIONAL_CHART_OPERATIONS = {
434+
'upload': {'operator': '/', 'value': 1000000},
435+
'download': {'operator': '/', 'value': 1000000},
436+
}
437+
410438
Or if you want to define a new chart configuration, which you can then
411439
call in your custom code (eg: a custom check class), you can do so as follows:
412440

413441
.. code-block:: python
414442
415443
from django.utils.translation import gettext_lazy as _
416444
445+
from openwisp_monitoring.db.backends.elasticsearch import _make_query
446+
417447
OPENWISP_MONITORING_CHARTS = {
418448
'ram': {
419449
'type': 'line',
@@ -427,7 +457,12 @@ call in your custom code (eg: a custom check class), you can do so as follows:
427457
"MEAN(buffered) AS buffered FROM {key} WHERE time >= '{time}' AND "
428458
"content_type = '{content_type}' AND object_id = '{object_id}' "
429459
"GROUP BY time(1d)"
430-
)
460+
),
461+
'elasticsearch': _make_query({
462+
'total': {'avg': {'field': 'points.fields.total'}},
463+
'free': {'avg': {'field': 'points.fields.free'}},
464+
'buffered': {'avg': {'field': 'points.fields.buffered'}},
465+
})
431466
},
432467
}
433468
}

docker-compose.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ services:
1111
depends_on:
1212
- influxdb
1313
- redis
14+
- es01
15+
- es02
1416

1517
influxdb:
1618
image: influxdb:1.8-alpine
@@ -22,6 +24,45 @@ services:
2224
INFLUXDB_DB: openwisp2
2325
INFLUXDB_USER: openwisp
2426
INFLUXDB_USER_PASSWORD: openwisp
27+
# clustered version of elasticsearch is used as that might be used in production
28+
es01:
29+
image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
30+
container_name: es01
31+
environment:
32+
- "node.name=es01"
33+
- "discovery.seed_hosts=es02"
34+
- "cluster.initial_master_nodes=es01,es02"
35+
- "cluster.name=openwisp2"
36+
- "bootstrap.memory_lock=true"
37+
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
38+
ulimits:
39+
memlock:
40+
soft: -1
41+
hard: -1
42+
volumes:
43+
- esdata01:/usr/share/elasticsearch/data
44+
ports:
45+
- 9200:9200
46+
networks:
47+
- esnet
48+
es02:
49+
image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
50+
container_name: es02
51+
environment:
52+
- "node.name=es02"
53+
- "discovery.seed_hosts=es01"
54+
- "cluster.initial_master_nodes=es01,es02"
55+
- "cluster.name=openwisp2"
56+
- "bootstrap.memory_lock=true"
57+
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
58+
ulimits:
59+
memlock:
60+
soft: -1
61+
hard: -1
62+
volumes:
63+
- esdata02:/usr/share/elasticsearch/data
64+
networks:
65+
- esnet
2566

2667
redis:
2768
image: redis:5.0-alpine
@@ -31,3 +72,10 @@ services:
3172

3273
volumes:
3374
influxdb-data: {}
75+
esdata01:
76+
driver: local
77+
esdata02:
78+
driver: local
79+
80+
networks:
81+
esnet:

openwisp_monitoring/db/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
from .backends import timeseries_db
22

33
chart_query = timeseries_db.queries.chart_query
4-
default_chart_query = timeseries_db.queries.default_chart_query
5-
device_data_query = timeseries_db.queries.device_data_query
64

7-
__all__ = ['timeseries_db', 'chart_query', 'default_chart_query', 'device_data_query']
5+
__all__ = ['timeseries_db', 'chart_query']

openwisp_monitoring/db/backends/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ def load_backend_module(backend_name=TIMESERIES_DB['BACKEND'], module=None):
4848
except ImportError as e:
4949
# The database backend wasn't found. Display a helpful error message
5050
# listing all built-in database backends.
51-
builtin_backends = ['influxdb']
51+
builtin_backends = ['influxdb', 'elasticsearch']
52+
raise e
5253
if backend_name not in [
5354
f'openwisp_monitoring.db.backends.{b}' for b in builtin_backends
5455
]:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .queries import _make_query
2+
3+
__all__ = ['_make_query']

0 commit comments

Comments
 (0)