Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more data source health check adapters: Jaeger, Loki, Microsoft SQL Server, Tempo, Zipkin #27

Merged
merged 5 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,15 @@ implemented as of June 2022.
- Elasticsearch
- Graphite
- InfluxDB
- Jaeger
- Loki
- Microsoft SQL Server
- OpenTSDB
- PostgreSQL
- Prometheus
- Tempo
- Testdata
- Zipkin

We are humbly asking the community to contribute adapters for other data
sources.
Expand Down
5 changes: 0 additions & 5 deletions docs/datasource-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ stackdriver
testdata

### UNKNOWN
jaeger
loki
mssql
tempo
zipkin

### TODO
alertmanager
Expand Down
51 changes: 51 additions & 0 deletions examples/datasource-health-probe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,21 @@ InfluxDB 2.x
influx bucket list --org=example


Jaeger
======
::

docker run --rm -it --name=jaeger --publish=16686:16686 jaegertracing/all-in-one:1
python examples/datasource-health-probe.py --type=jaeger --url=http://host.docker.internal:16686


Loki
====
::

docker run --rm -it --name=loki --publish=3100:3100 grafana/loki:2.5.0
python examples/datasource-health-probe.py --type=loki --url=http://host.docker.internal:3100

MariaDB / MySQL
===============
::
Expand All @@ -142,6 +157,26 @@ MariaDB / MySQL
python examples/datasource-health-probe.py --type=mysql --url=host.docker.internal:3306


Microsoft SQL Server
====================
::

# Start service.
docker run --rm -it --publish=1433:1433 \
--env="ACCEPT_EULA=Y" --env="SA_PASSWORD=root123?" \
mcr.microsoft.com/mssql/server:2022-latest

# Create database `testdrive`.
docker run --rm -it --network=host mcr.microsoft.com/mssql/server:2022-latest /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "root123?" -Q "CREATE DATABASE testdrive;"

# Invoke Grafana database probe.
python examples/datasource-health-probe.py --type=mssql --url=host.docker.internal:1433

Interactive client console::

docker run --rm -it --network=host mcr.microsoft.com/mssql/server:2022-latest /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P root123?


OpenTSDB
========
::
Expand All @@ -166,9 +201,25 @@ Prometheus
python examples/datasource-health-probe.py --type=prometheus --url=http://host.docker.internal:9090


Tempo
=====
::

docker run --rm -it --name=tempo --publish=3200:80 grafana/tempo:1.4.1 \
--target=all --storage.trace.backend=local --storage.trace.local.path=/var/tempo --auth.enabled=false
python examples/datasource-health-probe.py --type=tempo --url=http://host.docker.internal:3200


Testdata
========
::

python examples/datasource-health-probe.py --type=testdata


Zipkin
======
::

docker run --rm -it --publish=9411:9411 openzipkin/zipkin:2.23
python examples/datasource-health-probe.py --type=zipkin --url=http://host.docker.internal:9411
6 changes: 5 additions & 1 deletion grafana_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ def __request_runner(url, json=None, data=None, headers=None):
response,
"Client Error {0}: {1}".format(r.status_code, message),
)
return r.json()
# The "Tempo" data source responds with text/plain.
if r.headers.get("Content-Type", "").startswith("text/plain"):
return r.text
else:
return r.json()

return __request_runner
42 changes: 42 additions & 0 deletions grafana_client/elements/datasource.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,36 @@ def health_check(self, datasource: Union[DatasourceIdentifier, Dict]) -> Datasou
reason = f"{ex.__class__.__name__}: {ex}"
message = f"Invalid response. {reason}"

elif datasource_type == "loki":
if "status" in response and response["status"] == "success":
message = "Success"
success = True
else:
message = response["message"]

# With OpenTSDB, a 200 OK response with empty body is just fine.
elif datasource_type == "opentsdb":
message = "Success"
success = True

# With Tempo, a 200 OK response with a non-empty body is probably just fine.
elif datasource_type == "tempo":
if len(response) >= 0:
message = "Success"
success = True

# With Zipkin, a 200 OK response with a JSON body containing an empty array is probably just fine.
elif datasource_type == "zipkin":
if response == []:
message = "Success"
success = True

# Generic case, where the response has a top-level `results` or `data` key.
else:
if "results" in response:
success, message = self.parse_health_response_results(response=response)
elif "data" in response:
success, message = self.parse_health_response_data(response=response)
else:
message = f"Response lacks expected keys 'results' or 'data'"

Expand Down Expand Up @@ -542,3 +563,24 @@ def parse_health_response_results(response: Dict) -> Tuple[bool, str]:
message = f"FATAL: Unknown response type '{type(results)}'. Expected: dictionary or list."

return success, message

@staticmethod
def parse_health_response_data(response: Dict) -> Tuple[bool, str]:
"""
Response from Jaeger::

{"data":["jaeger-query"],"total":1,"limit":0,"offset":0,"errors":null}

Response from Loki::

{"status":"success","data":["__name__"]}

"""
success = False
message = str(response["data"])
if "errors" in response and response["errors"]:
message = str(response["errors"])
else:
success = True

return success, message
45 changes: 45 additions & 0 deletions grafana_client/knowledge.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,28 @@ def datasource_factory(datasource: DatasourceModel) -> DatasourceModel:
datasource.secureJsonFields = {
"token": False,
}
elif datasource.type == "jaeger":
datasource.access = "proxy"
elif datasource.type == "opentsdb":
datasource.access = "proxy"
datasource.jsonData = {
"tsdbVersion": 3,
}
elif datasource.type == "loki":
datasource.access = "proxy"
elif datasource.type == "mssql":
datasource.access = "proxy"
datasource.database = "testdrive"
datasource.user = "sa"
datasource.jsonData = {
"authenticationType": "SQL Server Authentication",
}
datasource.secureJsonData = {
"password": "root123?",
}
datasource.secureJsonFields = {
"password": False,
}
elif datasource.type == "mysql":
datasource.user = "root"
datasource.secureJsonData = {
Expand All @@ -86,8 +103,12 @@ def datasource_factory(datasource: DatasourceModel) -> DatasourceModel:
}
elif datasource.type == "prometheus":
datasource.access = "proxy"
elif datasource.type == "tempo":
datasource.access = "proxy"
elif datasource.type == "testdata":
pass
elif datasource.type == "zipkin":
datasource.access = "proxy"
else:
raise NotImplementedError(f"Unknown data source type: {datasource.type}")
return datasource
Expand Down Expand Up @@ -139,6 +160,21 @@ def query_factory(datasource, expression: str, store: Optional[str] = None) -> U
)
else:
raise KeyError(f"InfluxDB dialect '{dialect}' unknown")
elif datasource_type == "jaeger":
query = {}
elif datasource_type == "loki":
query = {}
elif datasource_type == "mssql":
query = {
"refId": "test",
"datasource": {
"type": datasource["type"],
"uid": datasource.get("uid"),
},
"datasourceId": datasource.get("id"),
"format": "table",
"rawSql": expression,
}
elif datasource_type == "mysql":
query = {
"refId": "test",
Expand Down Expand Up @@ -188,8 +224,12 @@ def query_factory(datasource, expression: str, store: Optional[str] = None) -> U
}
elif datasource_type == "simpod-json-datasource":
query = expression
elif datasource_type == "tempo":
query = {}
elif datasource_type == "testdata":
query = expression
elif datasource_type == "zipkin":
query = {}
else:
raise NotImplementedError(f"Unknown data source type: {datasource_type}")
return query
Expand All @@ -205,12 +245,17 @@ def query_factory(datasource, expression: str, store: Optional[str] = None) -> U
"influxdb": "SHOW RETENTION POLICIES on _internal",
"influxdb+influxql": "SHOW RETENTION POLICIES on _internal",
"influxdb+flux": "buckets()",
"jaeger": "url:///datasources/proxy/{datasource_id}/api/services",
"loki": "url:///datasources/{datasource_id}/resources/labels?start=1656274994383000000&end=1656275594383000000",
"mssql": "SELECT 1",
"mysql": "SELECT 1",
"opentsdb": "url:///datasources/proxy/{datasource_id}/api/suggest?type=metrics&q=cpu&max=100",
"postgres": "SELECT 1",
"prometheus": "1+1",
"simpod-json-datasource": "url:///datasources/proxy/{datasource_id}",
"tempo": "url:///datasources/proxy/{datasource_id}/api/echo",
"testdata": "url:///datasources/uid/{datasource_uid}",
"zipkin": "url:///datasources/proxy/{datasource_id}/api/v2/services",
}


Expand Down
40 changes: 40 additions & 0 deletions test/elements/test_datasource_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@
"jsonData": {"httpMode": "POST", "version": "InfluxQL"},
}

JAEGER_DATASOURCE = {
"id": 53,
"uid": "DbtFe237k",
"name": "Jaeger",
"type": "jaeger",
"access": "proxy",
}

LOKI_DATASOURCE = {
"id": 54,
"uid": "vCyglaq7z",
"name": "Loki",
"type": "loki",
"access": "proxy",
}

MSSQL_DATASOURCE = {
"id": 56,
"uid": "0pueH83nz",
"name": "MSSQL",
"type": "mssql",
"access": "proxy",
}

MYSQL_DATASOURCE = {
"id": 51,
"uid": "7CpzLp37z",
Expand Down Expand Up @@ -111,6 +135,14 @@
SUNANDMOON_DATASOURCE_INCOMPLETE = deepcopy(SUNANDMOON_DATASOURCE)
del SUNANDMOON_DATASOURCE_INCOMPLETE["jsonData"]["latitude"]

TEMPO_DATASOURCE = {
"id": 55,
"uid": "aTk86s3nk",
"name": "Tempo",
"type": "tempo",
"access": "proxy",
}

TESTDATA_DATASOURCE = {
"id": 45,
"uid": "439fngqr2",
Expand All @@ -119,6 +151,14 @@
"access": "proxy",
}

ZIPKIN_DATASOURCE = {
"id": 57,
"uid": "3sXIv8q7k",
"name": "Zipkin",
"type": "zipkin",
"access": "proxy",
}


PROMETHEUS_DATA_RESPONSE = {
"status": "success",
Expand Down
Loading