|
1 | 1 | """Client to retrieve data from a Netdata instance."""
|
2 |
| -import asyncio |
3 | 2 | import logging
|
4 |
| -import socket |
| 3 | +from typing import Dict |
5 | 4 |
|
6 |
| -import aiohttp |
7 |
| -import async_timeout |
| 5 | +import httpx |
8 | 6 | from yarl import URL
|
9 | 7 |
|
10 | 8 | from . import exceptions
|
11 | 9 |
|
12 | 10 | _LOGGER = logging.getLogger(__name__)
|
13 |
| -_DATA_ENDPOINT = "data?chart={resource}&before=0&after=-1&options=seconds" |
14 |
| -_ALARMS_ENDPOINT = "alarms?all&format=json" |
15 |
| -_ALL_METRIC_ENDPOINT = ( |
| 11 | +DATA_ENDPOINT = "data?chart={resource}&before=0&after=-1&options=seconds" |
| 12 | +ALARMS_ENDPOINT = "alarms?all&format=json" |
| 13 | +ALL_METRIC_ENDPOINT = ( |
16 | 14 | "allmetrics?format=json&help=no&types=no&" "timestamps=yes&names=yes&data=average"
|
17 | 15 | )
|
| 16 | +ALARM_COUNT = "alarm_count?context={resource}&status=RAISED" |
18 | 17 |
|
19 | 18 | API_VERSION = 1
|
20 | 19 |
|
21 | 20 |
|
22 | 21 | class Netdata(object):
|
23 | 22 | """A class for handling connections with a Netdata instance."""
|
24 | 23 |
|
25 |
| - def __init__(self, host, loop, session, port=19999, path=None): |
| 24 | + def __init__(self, host, port=19999, tls=None, path=None): |
26 | 25 | """Initialize the connection to the Netdata instance."""
|
27 |
| - self._loop = loop |
28 |
| - self._session = session |
29 | 26 | self.host = host
|
30 | 27 | self.port = port
|
31 | 28 | self.values = self.alarms = self.metrics = None
|
32 |
| - if path is None: |
33 |
| - self.base_url = URL.build(scheme="http", host=host, port=port, path=f"/api/v{API_VERSION}/") |
34 |
| - else: |
35 |
| - self.base_url = URL.build(scheme="http", host=host, port=port, path=path) |
36 | 29 |
|
| 30 | + self.scheme = "http" if tls is None or not False else "https" |
37 | 31 |
|
38 |
| - async def get_data(self, resource): |
39 |
| - """Get detail for a resource from the data endpoint.""" |
40 |
| - self.endpoint = _DATA_ENDPOINT |
41 |
| - url = "{}{}".format(self.base_url, self.endpoint.format(resource=resource)) |
| 32 | + if path is None: |
| 33 | + self.base_url = URL.build( |
| 34 | + scheme=self.scheme, host=host, port=port, path=f"/api/v{API_VERSION}/" |
| 35 | + ) |
| 36 | + else: |
| 37 | + self.base_url = URL.build( |
| 38 | + scheme=self.scheme, host=host, port=port, path=path |
| 39 | + ) |
42 | 40 |
|
| 41 | + async def get_data(self, url) -> Dict: |
| 42 | + """Execute a request to a data endpoint.""" |
43 | 43 | try:
|
44 |
| - with async_timeout.timeout(5, loop=self._loop): |
45 |
| - response = await self._session.get(url) |
| 44 | + async with httpx.AsyncClient() as client: |
| 45 | + response = await client.get(str(url)) |
| 46 | + except httpx.ConnectError: |
| 47 | + raise exceptions.NetdataConnectionError( |
| 48 | + f"Connection to {self.scheme}://{self.host}:{self.port} failed" |
| 49 | + ) |
| 50 | + |
| 51 | + if response.status_code == httpx.codes.OK: |
| 52 | + _LOGGER.debug(response.json()) |
| 53 | + try: |
| 54 | + return response.json() |
| 55 | + except TypeError: |
| 56 | + _LOGGER.error("Can not load data from Netdata") |
| 57 | + raise exceptions.NetdataError("Unable to get the data from Netdata") |
| 58 | + |
| 59 | + async def get_chart(self, resource): |
| 60 | + """Get the details about a chart.""" |
| 61 | + url = URL(self.base_url) / DATA_ENDPOINT.format(resource=resource) |
| 62 | + data = await self.get_data(url) |
46 | 63 |
|
47 |
| - _LOGGER.info("Response from Netdata: %s", response.status) |
48 |
| - data = await response.json() |
49 |
| - _LOGGER.debug(data) |
| 64 | + try: |
50 | 65 | self.values = {k: v for k, v in zip(data["labels"], data["data"][0])}
|
51 |
| - |
52 |
| - except (asyncio.TimeoutError, aiohttp.ClientError, socket.gaierror): |
53 |
| - _LOGGER.error("Can not load data from Netdata") |
54 |
| - raise exceptions.NetdataConnectionError() |
| 66 | + except TypeError: |
| 67 | + raise exceptions.NetdataError("Format of data doesn't match") |
55 | 68 |
|
56 | 69 | async def get_alarms(self):
|
57 | 70 | """Get alarms for a Netdata instance."""
|
58 |
| - self.endpoint = _ALARMS_ENDPOINT |
59 |
| - url = "{}{}".format(self.base_url, self.endpoint) |
60 |
| - |
61 |
| - try: |
62 |
| - with async_timeout.timeout(5, loop=self._loop): |
63 |
| - response = await self._session.get(url) |
64 |
| - |
65 |
| - _LOGGER.debug("Response from Netdata: %s", response.status) |
66 |
| - data = await response.json() |
67 |
| - _LOGGER.debug(data) |
68 |
| - self.alarms = data |
69 |
| - |
70 |
| - except (asyncio.TimeoutError, aiohttp.ClientError, socket.gaierror): |
71 |
| - _LOGGER.error("Can not load data from Netdata") |
72 |
| - raise exceptions.NetdataConnectionError() |
| 71 | + url = URL(self.base_url) / ALARMS_ENDPOINT |
| 72 | + self.alarms = await self.get_data(url) |
73 | 73 |
|
74 | 74 | async def get_allmetrics(self):
|
75 | 75 | """Get all available metrics from a Netdata instance."""
|
76 |
| - self.endpoint = _ALL_METRIC_ENDPOINT |
77 |
| - url = "{}{}".format(self.base_url, self.endpoint) |
78 |
| - |
79 |
| - try: |
80 |
| - with async_timeout.timeout(5, loop=self._loop): |
81 |
| - response = await self._session.get(url) |
82 |
| - |
83 |
| - _LOGGER.debug("Response from Netdata: %s", response.status) |
84 |
| - data = await response.json() |
85 |
| - _LOGGER.debug(data) |
86 |
| - self.metrics = data |
| 76 | + url = URL(self.base_url) / ALL_METRIC_ENDPOINT |
| 77 | + self.metrics = await self.get_data(url) |
87 | 78 |
|
88 |
| - except (asyncio.TimeoutError, aiohttp.ClientError, socket.gaierror): |
89 |
| - _LOGGER.error("Can not load data from Netdata") |
90 |
| - raise exceptions.NetdataConnectionError() |
| 79 | + async def get_info(self): |
| 80 | + """Get information about the Netdata instance.""" |
| 81 | + url = URL(self.base_url) / "info" |
| 82 | + self.info = await self.get_data(url) |
0 commit comments