wip
This commit is contained in:
parent
82d76f776b
commit
71bc767533
17 changed files with 303 additions and 14 deletions
|
@ -1,9 +1,11 @@
|
|||
assert node.has_bundle('redis')
|
||||
assert node.has_bundle('postgresql')
|
||||
|
||||
from mako.template import Template
|
||||
from shlex import quote
|
||||
from copy import deepcopy
|
||||
import yaml
|
||||
|
||||
import json
|
||||
|
||||
svc_systemd['grafana-server'] = {
|
||||
'needs': [
|
||||
|
@ -29,6 +31,11 @@ directories = {
|
|||
'/etc/grafana/provisioning/datasources': {
|
||||
'purge': True,
|
||||
},
|
||||
'/etc/grafana/provisioning/dashboards': {
|
||||
'purge': True,
|
||||
},
|
||||
'/var/lib/grafana': {},
|
||||
'/var/lib/grafana/dashboards': {},
|
||||
}
|
||||
|
||||
files = {
|
||||
|
@ -47,4 +54,61 @@ files = {
|
|||
'svc_systemd:grafana-server:restart',
|
||||
],
|
||||
},
|
||||
'/etc/grafana/provisioning/dashboards/managed.yaml': {
|
||||
'content': yaml.dump({
|
||||
'apiVersion': 1,
|
||||
'providers': [{
|
||||
'name': 'Default',
|
||||
'folder': 'Generated',
|
||||
'type': 'file',
|
||||
'options': {
|
||||
'path': '/var/lib/grafana/dashboards',
|
||||
},
|
||||
}],
|
||||
}),
|
||||
'triggers': [
|
||||
'svc_systemd:grafana-server:restart',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
# DASHBOARDS
|
||||
|
||||
with open(repo.path.join([f'data/grafana/dashboard.py'])) as file:
|
||||
dashboard_template = eval(file.read())
|
||||
with open(repo.path.join([f'data/grafana/panel.py'])) as file:
|
||||
panel_template = eval(file.read())
|
||||
with open(repo.path.join([f'data/grafana/flux.mako'])) as file:
|
||||
flux_template = Template(file.read())
|
||||
|
||||
bucket = repo.get_node(node.metadata.get('grafana/influxdb_node')).metadata.get('influxdb/bucket')
|
||||
|
||||
for dashboard_id, (node_name, panels) in enumerate(node.metadata.get('grafana/dashboards').items(), start=1):
|
||||
dashboard = deepcopy(dashboard_template)
|
||||
dashboard['id'] = dashboard_id
|
||||
|
||||
for panel_id, (panel_name, panel_config) in enumerate(panels.items(), start=1):
|
||||
panel = deepcopy(panel_template)
|
||||
panel['id'] = panel_id
|
||||
panel['title'] = panel_name
|
||||
|
||||
for target_name, target_config in panel_config.items():
|
||||
panel['targets'].append({
|
||||
'refId': target_name,
|
||||
'query': flux_template.render(
|
||||
bucket=bucket,
|
||||
host=node_name,
|
||||
field=target_name,
|
||||
filters=target_config,
|
||||
).strip()
|
||||
})
|
||||
|
||||
dashboard['panels'].append(panel)
|
||||
|
||||
files[f'/var/lib/grafana/dashboards/{node_name}.json'] = {
|
||||
'content': json.dumps(dashboard, sort_keys=True, indent=4),
|
||||
'triggers': [
|
||||
'svc_systemd:grafana-server:restart',
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from mako.template import Template
|
||||
|
||||
postgres_password = repo.vault.password_for(f'{node.name} postgres role grafana')
|
||||
|
||||
defaults = {
|
||||
|
@ -29,16 +31,8 @@ defaults = {
|
|||
'allow_signup': False,
|
||||
},
|
||||
},
|
||||
'panels': {
|
||||
'CPU': {
|
||||
'usage_user': {
|
||||
'filter': {
|
||||
'_measurement': 'cpu',
|
||||
'cpu': 'cpu-total',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'dashboards': {},
|
||||
'datasources': {},
|
||||
},
|
||||
'postgresql': {
|
||||
'databases': {
|
||||
|
@ -62,6 +56,26 @@ defaults = {
|
|||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'grafana/dashboards',
|
||||
)
|
||||
def dashboards(metadata):
|
||||
dashboards = {}
|
||||
|
||||
for monitored_node in repo.nodes:
|
||||
if monitored_node.metadata.get('telegraf/influxdb_node', None) == metadata.get('grafana/influxdb_node'):
|
||||
for telegraf_input in monitored_node.metadata.get('telegraf/config/inputs'):
|
||||
with open(repo.path.join([f'data/grafana/panels/{telegraf_input}.py'])) as file:
|
||||
dashboards.setdefault(monitored_node.name, {})[telegraf_input] = \
|
||||
eval(Template(file.read()).render(metadata=monitored_node.metadata))
|
||||
|
||||
return {
|
||||
'grafana': {
|
||||
'dashboards': dashboards,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'grafana/datasources',
|
||||
)
|
||||
|
|
|
@ -18,14 +18,14 @@ defaults = {
|
|||
'metric_batch_size': 1000,
|
||||
'metric_buffer_limit': 10000,
|
||||
'omit_hostname': False,
|
||||
'round_interval': True
|
||||
'round_interval': True,
|
||||
},
|
||||
'inputs': {
|
||||
'cpu': [{
|
||||
'collect_cpu_time': False,
|
||||
'percpu': True,
|
||||
'report_active': False,
|
||||
'totalcpu': True
|
||||
'totalcpu': True,
|
||||
}],
|
||||
'disk': [{
|
||||
'ignore_fs': [
|
||||
|
@ -35,7 +35,7 @@ defaults = {
|
|||
'iso9660',
|
||||
'overlay',
|
||||
'aufs',
|
||||
'squashfs'
|
||||
'squashfs',
|
||||
],
|
||||
}],
|
||||
'diskio': [{}],
|
||||
|
|
|
@ -38,6 +38,13 @@ defaults = {
|
|||
},
|
||||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'zfs': [{}],
|
||||
},
|
||||
},
|
||||
},
|
||||
'zfs': {
|
||||
'datasets': {},
|
||||
'pools': {},
|
||||
|
|
64
data/grafana/dashboard.py
Normal file
64
data/grafana/dashboard.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
# "id": 1,
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": True,
|
||||
"hide": True,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": True,
|
||||
"gnetId": None,
|
||||
"graphTooltip": 0,
|
||||
"iteration": 1625410820978,
|
||||
"links": [],
|
||||
"panels": [],
|
||||
"refresh": False,
|
||||
"schemaVersion": 30,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"allValue": None,
|
||||
"current": {
|
||||
"isNone": True,
|
||||
"selected": False,
|
||||
"text": "None",
|
||||
"value": ""
|
||||
},
|
||||
"datasource": None,
|
||||
"definition": "",
|
||||
"description": None,
|
||||
"error": None,
|
||||
"hide": 0,
|
||||
"includeAll": False,
|
||||
"label": None,
|
||||
"multi": False,
|
||||
"name": "query0",
|
||||
"options": [],
|
||||
"query": "",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": False,
|
||||
"sort": 0,
|
||||
"type": "query"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "2021-07-01T19:00:00.201Z",
|
||||
"to": "2021-07-01T19:03:10.018Z"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "New dashboard Copy",
|
||||
"uid": "IBPgYBznk",
|
||||
"version": 15
|
||||
}
|
8
data/grafana/flux.mako
Normal file
8
data/grafana/flux.mako
Normal file
|
@ -0,0 +1,8 @@
|
|||
from(bucket: "${bucket}")
|
||||
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|
||||
|> filter(fn: (r) => r["host"] == "${host}")
|
||||
% for key, value in filters.items():
|
||||
|> filter(fn: (r) => r["_field"] == "${field}")
|
||||
% endfor
|
||||
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|
||||
|> yield(name: "mean")
|
75
data/grafana/panel.py
Normal file
75
data/grafana/panel.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
# 'id': 1,
|
||||
# 'title': 'TBD',
|
||||
'type': 'timeseries',
|
||||
'transformations': [],
|
||||
'description': '',
|
||||
'fieldConfig': {
|
||||
'defaults': {
|
||||
'custom': {
|
||||
'drawStyle': 'line',
|
||||
'lineInterpolation': 'smooth',
|
||||
'barAlignment': 0,
|
||||
'lineWidth': 1,
|
||||
'fillOpacity': 40,
|
||||
'gradientMode': 'opacity',
|
||||
'spanNulls': False,
|
||||
'showPoints': 'never',
|
||||
'pointSize': 5,
|
||||
'stacking': {
|
||||
'mode': 'normal',
|
||||
'group': 'A'
|
||||
},
|
||||
'axisPlacement': 'hidden',
|
||||
'axisLabel': '',
|
||||
'scaleDistribution': {
|
||||
'type': 'linear'
|
||||
},
|
||||
'hideFrom': {
|
||||
'tooltip': False,
|
||||
'viz': False,
|
||||
'legend': False
|
||||
},
|
||||
'thresholdsStyle': {
|
||||
'mode': 'off',
|
||||
},
|
||||
'lineStyle': {
|
||||
'fill': 'solid',
|
||||
},
|
||||
},
|
||||
'color': {
|
||||
'mode': 'palette-classic',
|
||||
},
|
||||
'thresholds': {
|
||||
'mode': 'percentage',
|
||||
'steps': [
|
||||
{
|
||||
'color': 'green',
|
||||
'value': None,
|
||||
},
|
||||
{
|
||||
'color': 'dark-red',
|
||||
'value': 80,
|
||||
},
|
||||
],
|
||||
},
|
||||
'mappings': [],
|
||||
'displayName': '${__field.name}',
|
||||
'unit': 'percent',
|
||||
},
|
||||
'overrides': [],
|
||||
},
|
||||
'options': {
|
||||
'tooltip': {
|
||||
'mode': 'none',
|
||||
},
|
||||
'legend': {
|
||||
'displayMode': 'list',
|
||||
'placement': 'bottom',
|
||||
'calcs': [],
|
||||
},
|
||||
},
|
||||
'targets': [],
|
||||
'transparent': True,
|
||||
'datasource': None,
|
||||
}
|
20
data/grafana/panels/cpu.py
Normal file
20
data/grafana/panels/cpu.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
'usage_system': {
|
||||
'filter': {
|
||||
'_measurement': 'cpu',
|
||||
'cpu': 'cpu-total',
|
||||
},
|
||||
},
|
||||
'usage_iowait': {
|
||||
'filter': {
|
||||
'_measurement': 'cpu',
|
||||
'cpu': 'cpu-total',
|
||||
},
|
||||
},
|
||||
'usage_user': {
|
||||
'filter': {
|
||||
'_measurement': 'cpu',
|
||||
'cpu': 'cpu-total',
|
||||
},
|
||||
},
|
||||
}
|
1
data/grafana/panels/disk.py
Normal file
1
data/grafana/panels/disk.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/diskio.py
Normal file
1
data/grafana/panels/diskio.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/kernel.py
Normal file
1
data/grafana/panels/kernel.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/mem.py
Normal file
1
data/grafana/panels/mem.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/processes.py
Normal file
1
data/grafana/panels/processes.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/swap.py
Normal file
1
data/grafana/panels/swap.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/system.py
Normal file
1
data/grafana/panels/system.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
1
data/grafana/panels/zfs.py
Normal file
1
data/grafana/panels/zfs.py
Normal file
|
@ -0,0 +1 @@
|
|||
{}
|
29
libs/grafana.py
Normal file
29
libs/grafana.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
from mako.template import Template
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
def generate_flux(bucket, host, field, data):
|
||||
return Template(flux_template).render(
|
||||
bucket=bucket,
|
||||
host=host,
|
||||
field=field,
|
||||
data=data
|
||||
).strip()
|
||||
|
||||
|
||||
def generate_panel(bucket, host, title, targets, min=None, max=None):
|
||||
panel = deepcopy(panel_template)
|
||||
panel['title'] = title
|
||||
|
||||
if min:
|
||||
panel['fieldConfig']['defaults']['min'] = min
|
||||
if max:
|
||||
panel['fieldConfig']['defaults']['max'] = max
|
||||
|
||||
panel['targets'] = [
|
||||
{
|
||||
'hide': False,
|
||||
'refId': field,
|
||||
'query': generate_flux(bucket, host, field, data),
|
||||
} for field, data in targets.items()
|
||||
]
|
Loading…
Reference in a new issue