Skip to content

Commit 7212853

Browse files
authored
Merge pull request #127 from consideRatio/pr/cleanup-global
Replace global dashboard with activity dashboard
2 parents dfd56e4 + 924e4de commit 7212853

File tree

9 files changed

+154
-184
lines changed

9 files changed

+154
-184
lines changed

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ jobs:
4343
- name: Render dashboards
4444
run: |
4545
mkdir rendered-dashboards
46-
dashboard_folders="dashboards global-dashboards"
46+
dashboard_folders="dashboards"
4747
for file in `find $dashboard_folders -name '*.jsonnet'`
4848
do
49-
jsonnet -J vendor --tla-code 'datasources=["prometheus-test"]' --output-file rendered-dashboards/`basename $file` $file
49+
jsonnet -J vendor --output-file rendered-dashboards/`basename $file` $file
5050
done
5151
5252
- name: Install dashboard-linter

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ repos:
1616
- id: jsonnet-format
1717
# To workaround https://github.com/google/go-jsonnet/issues/591, we run
1818
# the jsonnet-lint hook once per .jsonnet / .libsonnet file.
19+
- id: jsonnet-lint
20+
pass_filenames: false
21+
name: jsonnet-lint cluster.jsonnet
22+
args: [-J, vendor, dashboards/activity.jsonnet]
1923
- id: jsonnet-lint
2024
pass_filenames: false
2125
name: jsonnet-lint cluster.jsonnet
@@ -44,10 +48,6 @@ repos:
4448
pass_filenames: false
4549
name: jsonnet-lint user.jsonnet
4650
args: [-J, vendor, dashboards/user.jsonnet]
47-
- id: jsonnet-lint
48-
pass_filenames: false
49-
name: jsonnet-lint global-usage-stats.jsonnet
50-
args: [-J, vendor, global-dashboards/global-usage-stats.jsonnet]
5151

5252
# Autoformat: Python code, syntax patterns are modernized
5353
- repo: https://github.com/asottile/pyupgrade

dashboards/activity.jsonnet

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env -S jsonnet -J ../vendor
2+
local grafonnet = import 'grafonnet/main.libsonnet';
3+
local dashboard = grafonnet.dashboard;
4+
local ts = grafonnet.panel.timeSeries;
5+
local prometheus = grafonnet.query.prometheus;
6+
local row = grafonnet.panel.row;
7+
local var = grafonnet.dashboard.variable;
8+
9+
local common = import './common.libsonnet';
10+
11+
local activeUserTsOptions =
12+
common.tsOptions
13+
+ ts.standardOptions.withDecimals(0)
14+
// stacking is used here as the total number of users is as relevant as the
15+
// number of users per hub
16+
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
17+
// stepAfter is used here as these metrics indicate what has happened the time
18+
// before the metric is read
19+
+ ts.fieldConfig.defaults.custom.withLineInterpolation('stepAfter')
20+
+ ts.panelOptions.withDescription(
21+
|||
22+
Number of unique users who were active within the preceding period.
23+
|||
24+
)
25+
;
26+
27+
local runningServers =
28+
common.tsOptions
29+
+ ts.new('Running Servers')
30+
+ ts.standardOptions.withDecimals(0)
31+
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
32+
+ ts.fieldConfig.defaults.custom.withLineInterpolation('stepBefore')
33+
+ ts.panelOptions.withDescription(
34+
|||
35+
Number of running user servers at any given time.
36+
37+
Note that a single user could have multiple servers running if the
38+
JupyterHub is configured with `c.JupyterHub.allow_named_servers = True`.
39+
|||
40+
)
41+
+ ts.queryOptions.withTargets([
42+
prometheus.new(
43+
'$PROMETHEUS_DS',
44+
|||
45+
max(
46+
jupyterhub_running_servers{namespace=~"$hub"}
47+
) by (namespace)
48+
|||
49+
)
50+
+ prometheus.withLegendFormat('{{ namespace }}'),
51+
]);
52+
53+
local dailyActiveUsers =
54+
activeUserTsOptions
55+
+ ts.new('Daily Active Users')
56+
+ ts.queryOptions.withTargets([
57+
prometheus.new(
58+
'$PROMETHEUS_DS',
59+
|||
60+
max(
61+
jupyterhub_active_users{period="24h", namespace=~"$hub"}
62+
) by (namespace)
63+
|||
64+
)
65+
+ prometheus.withLegendFormat('{{ namespace }}'),
66+
]);
67+
68+
local weeklyActiveUsers =
69+
activeUserTsOptions
70+
+ ts.new('Weekly Active Users')
71+
+ ts.queryOptions.withTargets([
72+
prometheus.new(
73+
'$PROMETHEUS_DS',
74+
|||
75+
max(
76+
jupyterhub_active_users{period="7d", namespace=~"$hub"}
77+
) by (namespace)
78+
|||
79+
)
80+
+ prometheus.withLegendFormat('{{ namespace }}'),
81+
]);
82+
83+
local monthlyActiveUsers =
84+
activeUserTsOptions
85+
+ ts.new('Monthly Active Users')
86+
+ ts.queryOptions.withTargets([
87+
prometheus.new(
88+
'$PROMETHEUS_DS',
89+
|||
90+
max(
91+
jupyterhub_active_users{period="30d", namespace=~"$hub"}
92+
) by (namespace)
93+
|||,
94+
)
95+
+ prometheus.withLegendFormat('{{ namespace }}'),
96+
]);
97+
98+
99+
dashboard.new('Activity')
100+
+ dashboard.withTags(['jupyterhub'])
101+
+ dashboard.withUid('jhgd-activity')
102+
+ dashboard.withEditable(true)
103+
+ dashboard.time.withFrom('now-90d')
104+
+ dashboard.withVariables([
105+
/*
106+
* This dashboard repeats the single row it defines once per datasource, due
107+
* to that we allow multiple or all datasources to be selected in this
108+
* dashboard but not in others. This repeating is only usable for repeating
109+
* panels or rows, as individual panels can't repeat queries based on the
110+
* available datasources.
111+
*/
112+
common.variables.prometheus
113+
+ var.query.selectionOptions.withMulti()
114+
+ var.query.selectionOptions.withIncludeAll(),
115+
/*
116+
* The hub variable will behave weirdly when multiple datasources are selected,
117+
* only showing hubs from one datasource. This is currently an accepted issue.
118+
* Many deployments of these dashboard will only be in a Grafana instance with
119+
* a single prometheus datasource.
120+
*/
121+
common.variables.hub,
122+
])
123+
+ dashboard.withPanels(
124+
grafonnet.util.grid.makeGrid(
125+
[
126+
row.new('Activity ($PROMETHEUS_DS)')
127+
+ row.withPanels([
128+
runningServers,
129+
dailyActiveUsers,
130+
weeklyActiveUsers,
131+
monthlyActiveUsers,
132+
])
133+
+ row.withRepeat('PROMETHEUS_DS'),
134+
],
135+
panelWidth=6,
136+
panelHeight=8,
137+
)
138+
)

dashboards/jupyterhub.jsonnet

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -12,100 +12,6 @@ local row = grafonnet.panel.row;
1212
local common = import './common.libsonnet';
1313
local jupyterhub = import 'jupyterhub.libsonnet';
1414

15-
// Hub usage stats
16-
local currentActiveUsers =
17-
common.tsOptions
18-
+ ts.new('Currently Active Users')
19-
+ ts.standardOptions.withDecimals(0)
20-
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
21-
+ ts.queryOptions.withTargets([
22-
prometheus.new(
23-
'$PROMETHEUS_DS',
24-
|||
25-
sum(
26-
group(
27-
kube_pod_status_phase{phase="Running"}
28-
) by (label_component, pod, namespace)
29-
%s
30-
) by (namespace)
31-
|||
32-
% jupyterhub.onComponentLabel('singleuser-server', group_right=''),
33-
)
34-
+ prometheus.withLegendFormat('{{ namespace }}'),
35-
]);
36-
37-
local dailyActiveUsers =
38-
common.tsOptions
39-
+ ts.new('Daily Active Users')
40-
+ ts.panelOptions.withDescription(
41-
|||
42-
Number of unique users who were active within the preceding 24h period.
43-
44-
Requires JupyterHub 3.1.
45-
|||,
46-
)
47-
+ ts.standardOptions.withDecimals(0)
48-
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
49-
+ ts.queryOptions.withTargets([
50-
prometheus.new(
51-
'$PROMETHEUS_DS',
52-
|||
53-
max(
54-
jupyterhub_active_users{period="24h", namespace=~"$hub"}
55-
) by (namespace)
56-
|||
57-
)
58-
+ prometheus.withLegendFormat('{{ namespace }}'),
59-
]);
60-
61-
local weeklyActiveUsers =
62-
common.tsOptions
63-
+ ts.new('Weekly Active Users')
64-
+ ts.panelOptions.withDescription(
65-
|||
66-
Number of unique users who were active within the preceeding 7d period.
67-
68-
Requires JupyterHub 3.1.
69-
|||
70-
)
71-
+ ts.standardOptions.withDecimals(0)
72-
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
73-
+ ts.queryOptions.withTargets([
74-
prometheus.new(
75-
'$PROMETHEUS_DS',
76-
|||
77-
max(
78-
jupyterhub_active_users{period="7d", namespace=~"$hub"}
79-
) by (namespace)
80-
|||
81-
)
82-
+ prometheus.withLegendFormat('{{ namespace }}'),
83-
]);
84-
85-
local monthlyActiveUsers =
86-
common.tsOptions
87-
+ ts.new('Monthly Active Users')
88-
+ ts.panelOptions.withDescription(
89-
|||
90-
Number of unique users who were active within the preceeding 7d period.
91-
92-
Requires JupyterHub 3.1.
93-
|||
94-
)
95-
+ ts.standardOptions.withDecimals(0)
96-
+ ts.fieldConfig.defaults.custom.stacking.withMode('normal')
97-
+ ts.queryOptions.withTargets([
98-
prometheus.new(
99-
'$PROMETHEUS_DS',
100-
|||
101-
max(
102-
jupyterhub_active_users{period="30d", namespace=~"$hub"}
103-
) by (namespace)
104-
|||,
105-
)
106-
+ prometheus.withLegendFormat('{{ namespace }}'),
107-
]);
108-
10915
local userMemoryDistribution =
11016
common.heatmapOptions
11117
+ heatmap.new('User memory usage distribution')
@@ -597,13 +503,6 @@ dashboard.new('JupyterHub Dashboard')
597503
+ dashboard.withPanels(
598504
grafonnet.util.grid.makeGrid(
599505
[
600-
row.new('Hub usage stats')
601-
+ row.withPanels([
602-
currentActiveUsers,
603-
dailyActiveUsers,
604-
weeklyActiveUsers,
605-
monthlyActiveUsers,
606-
]),
607506
row.new('Container Images')
608507
+ row.withPanels([
609508
notebookImagesUsed,

deploy.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,16 @@ def build_dashboard(dashboard_path, api):
6565
Returns JSON representing a Grafana dashboard by rendering an individual
6666
`.jsonnet` dashboard template with `jsonnet`.
6767
"""
68-
# global-dashboards/global-usage-stats.json needs to be rendered with
69-
# information about the grafana instance's datasources in order to show info
70-
# about all datasources in a single panel. Due to that, we also ask the
71-
# Grafana instance we are to deploy to about its datasources and then pass
72-
# them to `jsonnet` when rendering via the `--tla-code` flag.
73-
datasources = api("/datasources")
74-
datasources_names = [ds["name"] for ds in datasources]
75-
7668
dashboard = json.loads(
7769
subprocess.check_output(
7870
[
7971
"jsonnet",
8072
"-J",
8173
"vendor",
8274
dashboard_path,
83-
"--tla-code",
84-
f"datasources={datasources_names}",
85-
]
86-
).decode()
75+
],
76+
text=True,
77+
)
8778
)
8879
if not dashboard:
8980
raise ValueError(f"jsonnet render of {dashboard_path} led to an empty object")

docs/contributing.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ Dashboards are `.json` files generated from `.jsonnet` files using `jsonnet`
3232
like this:
3333

3434
```shell
35-
# --tla-code flag is currently only relevant for global-dashboards
36-
jsonnet -J vendor --tla-code 'datasources=["prometheus-test"]' dashboards/cluster.json
35+
jsonnet -J vendor dashboards/cluster.json
3736
```
3837

3938
To tweak dashboard settings in the `.jsonnet` files can be tricky. One way to do

docs/tutorials/deploy.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,21 +226,18 @@ You will likely only need to adjust the `claimName` above to use this example.
226226
There's a helper `deploy.py` script that can deploy the dashboards to any grafana installation.
227227

228228
```bash
229-
export GRAFANA_TOKEN="<API-TOKEN-FOR-YOUR-GRAFANA>
229+
# note the leading space in the command below, it makes the
230+
# sensitive command not be stored in your shell history
231+
export GRAFANA_TOKEN="<API-TOKEN-FOR-YOUR-GRAFANA>
232+
230233
./deploy.py <your-grafana-url>
231234
```
232235

233236
This creates a folder called 'JupyterHub Default Dashboards' in your grafana, and adds
234237
a couple of dashboards to it.
235238

236-
If your Grafana deployment supports more than one datasource, then apart from the default dashboards in the [`dashboards` directory](https://github.com/jupyterhub/grafana-dashboards/tree/main/dashboards), you should also consider deploying apart the dashboards in [`global-dashboards` directory](https://github.com/jupyterhub/grafana-dashboards/tree/main/global-dashboards).
237-
238-
```bash
239-
export GRAFANA_TOKEN="<API-TOKEN-FOR-YOUR-GRAFANA>
240-
./deploy.py <your-grafana-url> --dashboards-dir global-dashboards
241-
```
242-
243-
The global dashboards will use the list of available dashboards in your Grafana provided to them and will build dashboards across all of them.
239+
The Activity dashboard is unique because it repeats rows of panels for every
240+
prometheus datasource accessible by Grafana.
244241

245242
If your Grafana instance uses a self-signed certificate, use the `--no-tls-verify` flag when executing the `deploy.py` script. For example:
246243

global-dashboards/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)