Skip to content

Commit 2b1be37

Browse files
committed
feat: migrate accelerators dashboard to use the perses go sdk
Signed-off-by: Gabriel Bernal <gbernal@redhat.com>
1 parent 90ffa04 commit 2b1be37

File tree

2 files changed

+99
-133
lines changed

2 files changed

+99
-133
lines changed
Lines changed: 92 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
package uiplugin
22

33
import (
4+
"encoding/json"
5+
6+
"github.com/perses/perses/go-sdk/common"
7+
"github.com/perses/perses/go-sdk/dashboard"
8+
"github.com/perses/perses/go-sdk/panel"
9+
panelgroup "github.com/perses/perses/go-sdk/panel-group"
10+
listvariable "github.com/perses/perses/go-sdk/variable/list-variable"
11+
"github.com/perses/perses/pkg/model/api/v1/variable"
12+
"github.com/perses/plugins/prometheus/sdk/go/query"
13+
labelvalues "github.com/perses/plugins/prometheus/sdk/go/variable/label-values"
14+
timeseries "github.com/perses/plugins/timeserieschart/sdk/go"
415
persesv1alpha2 "github.com/rhobs/perses-operator/api/v1alpha2"
516
persesv1 "github.com/rhobs/perses/pkg/model/api/v1"
6-
"github.com/rhobs/perses/pkg/model/api/v1/common"
7-
"github.com/rhobs/perses/pkg/model/api/v1/dashboard"
8-
"github.com/rhobs/perses/pkg/model/api/v1/variable"
17+
persescommon "github.com/rhobs/perses/pkg/model/api/v1/common"
918
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1019
"k8s.io/utils/ptr"
1120
)
@@ -26,11 +35,11 @@ func newAcceleratorsDatasource(namespace string) *persesv1alpha2.PersesDatasourc
2635
Spec: persesv1alpha2.DatasourceSpec{
2736
Config: persesv1alpha2.Datasource{
2837
DatasourceSpec: persesv1.DatasourceSpec{
29-
Display: &common.Display{
30-
Name: "acceelerators datasource",
38+
Display: &persescommon.Display{
39+
Name: "Accelerators Datasource",
3140
},
3241
Default: true,
33-
Plugin: common.Plugin{
42+
Plugin: persescommon.Plugin{
3443
Kind: "PrometheusDatasource",
3544
Spec: map[string]interface{}{
3645
"proxy": map[string]interface{}{
@@ -59,7 +68,81 @@ func newAcceleratorsDatasource(namespace string) *persesv1alpha2.PersesDatasourc
5968
}
6069
}
6170

62-
func newAcceleratorsDashboard(namespace string) *persesv1alpha2.PersesDashboard {
71+
func acceleratorPanel(panelName, targetMetric string) panelgroup.Option {
72+
return panelgroup.AddPanel(panelName,
73+
timeseries.Chart(
74+
timeseries.WithLegend(timeseries.Legend{
75+
Mode: timeseries.ListMode,
76+
Position: timeseries.BottomPosition,
77+
Values: []common.Calculation{},
78+
}),
79+
timeseries.WithVisual(timeseries.Visual{
80+
AreaOpacity: 1,
81+
ConnectNulls: false,
82+
Display: timeseries.LineDisplay,
83+
LineWidth: 0.25,
84+
Stack: timeseries.AllStack,
85+
}),
86+
timeseries.WithYAxis(timeseries.YAxis{
87+
Format: &common.Format{
88+
Unit: ptr.To(string(common.DecimalUnit)),
89+
},
90+
Min: 0,
91+
}),
92+
),
93+
panel.AddQuery(
94+
query.PromQL(targetMetric,
95+
query.SeriesNameFormat("{{vendor_id}}"),
96+
),
97+
),
98+
)
99+
}
100+
101+
func buildAcceleratorsDashboard() (dashboard.Builder, error) {
102+
return dashboard.New("accelerators-dashboard",
103+
dashboard.Name("Accelerators common metrics"),
104+
dashboard.AddVariable("cluster",
105+
listvariable.List(
106+
listvariable.DisplayName("Cluster"),
107+
listvariable.Hidden(false),
108+
listvariable.AllowAllValue(false),
109+
listvariable.AllowMultiple(false),
110+
listvariable.SortingBy(variable.SortAlphabeticalAsc),
111+
labelvalues.PrometheusLabelValues("cluster",
112+
labelvalues.Matchers("up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}"),
113+
),
114+
),
115+
),
116+
dashboard.AddPanelGroup("Accelerators",
117+
panelgroup.PanelsPerLine(2),
118+
acceleratorPanel("GPU Utilization", "accelerator_gpu_utilization"),
119+
acceleratorPanel("Memory Used Bytes", "accelerator_memory_used_bytes"),
120+
acceleratorPanel("Memory Total Bytes", "accelerator_memory_total_bytes"),
121+
acceleratorPanel("Power Usage (Watts)", "accelerator_power_usage_watts"),
122+
acceleratorPanel("Temperature (Celsius)", "accelerator_temperature_celsius"),
123+
acceleratorPanel("SM Clock (Hertz)", "accelerator_sm_clock_hertz"),
124+
acceleratorPanel("Memory Clock (Hertz)", "accelerator_memory_clock_hertz"),
125+
),
126+
)
127+
}
128+
129+
func newAcceleratorsDashboard(namespace string) (*persesv1alpha2.PersesDashboard, error) {
130+
builder, err := buildAcceleratorsDashboard()
131+
if err != nil {
132+
return nil, err
133+
}
134+
135+
// Workaround because of type conflict between Perses plugin types and Perses fork in rhobs org
136+
rhobsDashboard := persesv1.Dashboard{}
137+
bytes, err := json.Marshal(builder.Dashboard)
138+
if err != nil {
139+
return nil, err
140+
}
141+
err = rhobsDashboard.UnmarshalJSON(bytes)
142+
if err != nil {
143+
return nil, err
144+
}
145+
63146
return &persesv1alpha2.PersesDashboard{
64147
TypeMeta: metav1.TypeMeta{
65148
APIVersion: persesv1alpha2.GroupVersion.String(),
@@ -74,131 +157,8 @@ func newAcceleratorsDashboard(namespace string) *persesv1alpha2.PersesDashboard
74157
},
75158
Spec: persesv1alpha2.PersesDashboardSpec{
76159
Config: persesv1alpha2.Dashboard{
77-
DashboardSpec: persesv1.DashboardSpec{
78-
Display: &common.Display{
79-
Name: "Accelerators common metrics",
80-
},
81-
Variables: []dashboard.Variable{
82-
{
83-
Kind: variable.KindList,
84-
Spec: &dashboard.ListVariableSpec{
85-
Name: "cluster",
86-
ListSpec: variable.ListSpec{
87-
Display: &variable.Display{
88-
Hidden: false,
89-
},
90-
AllowAllValue: false,
91-
AllowMultiple: false,
92-
Sort: ptr.To(variable.SortAlphabeticalAsc),
93-
Plugin: common.Plugin{
94-
Kind: "PrometheusLabelValuesVariable",
95-
Spec: map[string]interface{}{
96-
"labelName": "cluster",
97-
"matchers": []interface{}{
98-
"up{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\"}",
99-
},
100-
},
101-
},
102-
},
103-
},
104-
},
105-
},
106-
Panels: map[string]*persesv1.Panel{
107-
"0_0": getPanel("GPU Utilization", "accelerator_gpu_utilization"),
108-
"0_1": getPanel("Memory Used Bytes", "accelerator_memory_used_bytes"),
109-
"0_2": getPanel("Memory Total Bytes", "accelerator_memory_total_bytes"),
110-
"0_3": getPanel("Power Usage (Watts)", "accelerator_power_usage_watts"),
111-
"0_4": getPanel("Temperature (Celsius)", "accelerator_temperature_celsius"),
112-
"0_5": getPanel("SM Clock (Hertz)", "accelerator_sm_clock_hertz"),
113-
"0_6": getPanel("Memory Clock (Hertz)", "accelerator_memory_clock_hertz"),
114-
},
115-
Layouts: []dashboard.Layout{
116-
{
117-
Kind: dashboard.KindGridLayout,
118-
Spec: dashboard.GridLayoutSpec{
119-
Display: &dashboard.GridLayoutDisplay{
120-
Title: "Accelerators",
121-
Collapse: &dashboard.GridLayoutCollapse{
122-
Open: true,
123-
},
124-
},
125-
Items: []dashboard.GridItem{
126-
getGridItem(0, 0, "#/spec/panels/0_0"),
127-
getGridItem(12, 0, "#/spec/panels/0_1"),
128-
getGridItem(0, 7, "#/spec/panels/0_2"),
129-
getGridItem(12, 7, "#/spec/panels/0_3"),
130-
getGridItem(0, 14, "#/spec/panels/0_4"),
131-
getGridItem(12, 14, "#/spec/panels/0_5"),
132-
getGridItem(0, 21, "#/spec/panels/0_6"),
133-
},
134-
},
135-
},
136-
},
137-
},
160+
DashboardSpec: rhobsDashboard.Spec,
138161
},
139162
},
140-
}
141-
}
142-
143-
func getPanel(panelName, targetMetric string) *persesv1.Panel {
144-
return &persesv1.Panel{
145-
Kind: "Panel",
146-
Spec: persesv1.PanelSpec{
147-
Display: &persesv1.PanelDisplay{
148-
Name: panelName,
149-
},
150-
Plugin: common.Plugin{
151-
Kind: "TimeSeriesChart",
152-
Spec: map[string]interface{}{
153-
"legend": map[string]interface{}{
154-
"mode": "list",
155-
"position": "bottom",
156-
"values": []interface{}{}, // Empty array
157-
},
158-
"visual": map[string]interface{}{
159-
"areaOpacity": 1,
160-
"connectNulls": false,
161-
"display": "line",
162-
"lineWidth": 0.25,
163-
"stack": "all",
164-
},
165-
"yAxis": map[string]interface{}{
166-
"format": map[string]interface{}{
167-
"unit": "decimal",
168-
},
169-
"min": 0,
170-
},
171-
},
172-
},
173-
Queries: []persesv1.Query{
174-
{
175-
Kind: "TimeSeriesQuery",
176-
Spec: persesv1.QuerySpec{
177-
Plugin: common.Plugin{
178-
Kind: "PrometheusTimeSeriesQuery",
179-
Spec: map[string]interface{}{
180-
"datasource": map[string]interface{}{
181-
"kind": "PrometheusDatasource",
182-
},
183-
"query": targetMetric,
184-
"seriesNameFormat": "{{vendor_id}}",
185-
},
186-
},
187-
},
188-
},
189-
},
190-
},
191-
}
192-
}
193-
194-
func getGridItem(xPos, yPos int, ref string) dashboard.GridItem {
195-
return dashboard.GridItem{
196-
X: xPos,
197-
Y: yPos,
198-
Width: 12,
199-
Height: 7,
200-
Content: &common.JSONRef{
201-
Ref: ref,
202-
},
203-
}
163+
}, nil
204164
}

pkg/controllers/uiplugin/components.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,15 @@ func pluginComponentReconcilers(plugin *uiv1alpha1.UIPlugin, pluginInfo UIPlugin
156156
reconciler.NewOptionalUpdater(newClusterRoleBinding(namespace, persesServiceAccountName, "perses-cr", persesServiceAccountName+"-perses-cr"), plugin, persesEnabled),
157157
reconciler.NewOptionalUpdater(newPerses(namespace, pluginInfo.PersesImage), plugin, persesEnabled),
158158
reconciler.NewOptionalUpdater(newAcceleratorsDatasource(namespace), plugin, persesEnabled),
159-
reconciler.NewOptionalUpdater(newAcceleratorsDashboard(namespace), plugin, persesEnabled),
160159
)
161160

161+
acceleratorsDashboard, err := newAcceleratorsDashboard(namespace)
162+
if err != nil {
163+
logger.Error(err, "Cannot build Accelerators dashboard")
164+
} else {
165+
components = append(components, reconciler.NewOptionalUpdater(acceleratorsDashboard, plugin, persesEnabled))
166+
}
167+
162168
apmDashboard, err := newAPMDashboard(namespace)
163169
if err != nil {
164170
logger.Error(err, "Cannot build APM dashboard")

0 commit comments

Comments
 (0)