Skip to content

Commit

Permalink
api: add an InfluxDB API endpoint
Browse files Browse the repository at this point in the history
This provides a new InfluxDB-compatible endpoint to write data to Gnocchi at
`/v1/influxdb'.
  • Loading branch information
jd committed Nov 16, 2017
1 parent 814ea9d commit 790ff33
Show file tree
Hide file tree
Showing 12 changed files with 708 additions and 30 deletions.
2 changes: 2 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Gnocchi's main features are:
- Nagios/Icinga support
- Statsd protocol support
- Collectd plugin support
- InfluxDB line protocol ingestion support

Community
---------
Expand Down Expand Up @@ -123,6 +124,7 @@ Documentation
grafana
nagios
collectd
influxdb
glossary
releasenotes/index.rst
contributing
Expand Down
43 changes: 43 additions & 0 deletions doc/source/influxdb.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
============================
InfluxDB ingestion support
============================

Gnocchi implements some part of the InfluxDB REST API. That allows tool that
are used to write to InfluxDB to write directly to Gnocchi instead, such as
`Telegraf`_.

The endpoint is available at `/v1/influxdb`. It supports:

* `GET /v1/influxdb/ping`
* `POST /v1/influxdb/query` where the only query that is handled is `CREATE
DATABASE <db>`. That will create a new resource type named after the database
handle.
* `POST /v1/influxdb/write?db=<db>`. The `db` parameter should be an existing
resource type that does not require any attributes to be set. The body should
follow the `InfluxDB line protocol`_.

In order to map InfluxDB data to Gnocchi data model, the following
transformation happen when writing metrics:

* For each measure sent, one of the tag value is used as the original resource
id. By default the `host` tag is used. This can be overriden by passing the
`X-Gnocchi-InfluxDB-Tag-Resource-ID` HTTP header.

* The metric names associated to the resource have the format:
`<measurement>.<field_key>[@<tag_key>=<tag_value>,…]`. The tag are sorted
by keys.


Telegraf configuration
======================

In order to use `Telegraf`_ with Gnocchi, you can use the following
configuration example::

[[outputs.influxdb]]
urls = ["http://admin:localhost:8041/v1/influxdb"]
http_headers = {"X-Gnocchi-InfluxDB-Tag-Resource-ID" = "host"}


.. _`Telegraf`: https://github.com/influxdata/telegraf
.. _`InfluxDB line protocol`: https://docs.influxdata.com/influxdb/v1.3/write_protocols/line_protocol_reference/
5 changes: 3 additions & 2 deletions gnocchi/incoming/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ def add_measures(self, metric, measures):
def add_measures_batch(self, metrics_and_measures):
"""Add a batch of measures for some metrics.
:param metrics_and_measures: A dict where keys
are metrics and value are measure.
:param metrics_and_measures: A dict where keys are metric objects
and values are a list of
:py:class:`gnocchi.incoming.Measure`.
"""
utils.parallel_map(
self._store_new_measures,
Expand Down
10 changes: 10 additions & 0 deletions gnocchi/indexer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ def __init__(self, type):
"Resource type %s does not exist" % type)
self.type = type

def jsonify(self):
return {
"cause": "Resource type does not exist",
"detail": self.type,
}


class NoSuchMetric(IndexerException):
"""Error raised when a metric does not exist."""
Expand Down Expand Up @@ -224,6 +230,10 @@ def __init__(self, resource):
"Resource %s already exists" % resource)
self.resource = resource

def jsonify(self):
return {"cause": "Resource already exists",
"detail": self.resource}


class ResourceTypeAlreadyExists(IndexerException):
"""Error raised when a resource type already exists."""
Expand Down
2 changes: 2 additions & 0 deletions gnocchi/rest/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,7 @@ class V1Controller(object):
def __init__(self):
# FIXME(sileht): split controllers to avoid lazy loading
from gnocchi.rest.aggregates import api as agg_api
from gnocchi.rest import influxdb

self.sub_controllers = {
"search": SearchController(),
Expand All @@ -1908,6 +1909,7 @@ def __init__(self):
"capabilities": CapabilityController(),
"status": StatusController(),
"aggregates": agg_api.AggregatesController(),
"influxdb": influxdb.InfluxDBController(),
}
for name, ctrl in self.sub_controllers.items():
setattr(self, name, ctrl)
Expand Down
Loading

0 comments on commit 790ff33

Please sign in to comment.