Skip to content

Commit 24dbb39

Browse files
committed
Make Pyrra work based on labels and matchers
This is the Portugal commit. It was a fun small holiday project. 🎉
1 parent 133d1cf commit 24dbb39

22 files changed

+611
-732
lines changed

.editorconfig

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# top-most EditorConfig file
2+
root = true
3+
4+
# Unix-style newlines with a newline ending every file
5+
[*]
6+
end_of_line = lf
7+
insert_final_newline = true
8+
9+
[ui/**.{js,tsx}]
10+
charset = utf-8
11+
indent_style = space
12+
indent_size = 2
13+
14+
# Matches the exact files either package.json or .travis.yml
15+
[ui/package.json]
16+
indent_style = space
17+
indent_size = 2

api.yaml

+13-27
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,28 @@ paths:
99
get:
1010
summary: List Objectives
1111
operationId: ListObjectives
12-
tags:
13-
- objectives
14-
responses:
15-
'200':
16-
description: List Objectives
17-
content:
18-
application/json:
19-
schema:
20-
$ref: "#/components/schemas/Objectives"
21-
/objectives/{expr}:
22-
get:
23-
summary: Get Objective
24-
operationId: GetObjective
2512
tags:
2613
- objectives
2714
parameters:
28-
- in: path
15+
- in: query
2916
name: expr
30-
required: true
3117
schema:
3218
type: string
3319
responses:
3420
'200':
35-
description: Get Objective
21+
description: List Objectives
3622
content:
3723
application/json:
3824
schema:
39-
$ref: '#/components/schemas/Objective'
40-
/objectives/{expr}/status:
25+
$ref: "#/components/schemas/Objectives"
26+
/objectives/status:
4127
get:
4228
summary: Get objective status
4329
operationId: GetObjectiveStatus
4430
tags:
4531
- objectives
4632
parameters:
47-
- in: path
33+
- in: query
4834
name: expr
4935
required: true
5036
schema:
@@ -56,14 +42,14 @@ paths:
5642
application/json:
5743
schema:
5844
$ref: '#/components/schemas/ObjectiveStatus'
59-
/objectives/{expr}/errorbudget:
45+
/objectives/errorbudget:
6046
get:
6147
summary: Get ErrorBudget graph sample pairs
6248
operationId: GetObjectiveErrorBudget
6349
tags:
6450
- objectives
6551
parameters:
66-
- in: path
52+
- in: query
6753
name: expr
6854
required: true
6955
schema:
@@ -85,14 +71,14 @@ paths:
8571
application/json:
8672
schema:
8773
$ref: '#/components/schemas/QueryRange'
88-
/objectives/{expr}/alerts:
74+
/objectives/alerts:
8975
get:
9076
summary: Get the MultiBurnrateAlerts for the Objective
9177
operationId: GetMultiBurnrateAlerts
9278
tags:
9379
- objectives
9480
parameters:
95-
- in: path
81+
- in: query
9682
name: expr
9783
required: true
9884
schema:
@@ -106,14 +92,14 @@ paths:
10692
type: array
10793
items:
10894
$ref: '#/components/schemas/MultiBurnrateAlert'
109-
/objectives/{expr}/red/requests:
95+
/objectives/red/requests:
11096
get:
11197
summary: Get a matrix of requests by label
11298
operationId: GetREDRequests
11399
tags:
114100
- objectives
115101
parameters:
116-
- in: path
102+
- in: query
117103
name: expr
118104
required: true
119105
schema:
@@ -135,14 +121,14 @@ paths:
135121
application/json:
136122
schema:
137123
$ref: '#/components/schemas/QueryRange'
138-
/objectives/{expr}/red/errors:
124+
/objectives/red/errors:
139125
get:
140126
summary: Get a matrix of error percentage by label
141127
operationId: GetREDErrors
142128
tags:
143129
- objectives
144130
parameters:
145-
- in: path
131+
- in: query
146132
name: expr
147133
required: true
148134
schema:

filesystem.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ func (os *Objectives) Match(ms []*labels.Matcher) []slo.Objective {
5050

5151
var objectives []slo.Objective
5252

53+
Objectives:
5354
for _, o := range os.objectives {
5455
for _, m := range ms {
5556
v := o.Labels.Get(m.Name)
5657
if !m.Matches(v) {
57-
continue
58+
continue Objectives
5859
}
59-
objectives = append(objectives, o)
6060
}
61+
objectives = append(objectives, o)
6162
}
6263

6364
return objectives

filesystem_test.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import (
1111
func TestMatchObjectives(t *testing.T) {
1212
o1 := slo.Objective{Labels: labels.FromStrings("foo", "bar")}
1313
o2 := slo.Objective{Labels: labels.FromStrings("foo", "bar", "ying", "yang")}
14-
o3 := slo.Objective{Labels: labels.FromStrings("foo", "baz")}
14+
o3 := slo.Objective{Labels: labels.FromStrings("foo", "bar", "yes", "no")}
15+
o4 := slo.Objective{Labels: labels.FromStrings("foo", "baz")}
1516

1617
objectives := Objectives{objectives: map[string]slo.Objective{}}
1718
objectives.Set(o1)
1819
objectives.Set(o2)
1920
objectives.Set(o3)
21+
objectives.Set(o4)
2022

2123
matches := objectives.Match([]*labels.Matcher{
2224
labels.MustNewMatcher(labels.MatchEqual, "foo", "foo"),
@@ -26,24 +28,30 @@ func TestMatchObjectives(t *testing.T) {
2628
matches = objectives.Match([]*labels.Matcher{
2729
labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"),
2830
})
31+
require.Len(t, matches, 3)
2932
require.Contains(t, matches, o1)
3033
require.Contains(t, matches, o2)
34+
require.Contains(t, matches, o3)
3135

3236
matches = objectives.Match([]*labels.Matcher{
3337
labels.MustNewMatcher(labels.MatchEqual, "foo", "baz"),
3438
})
35-
require.Contains(t, matches, o3)
39+
require.Len(t, matches, 1)
40+
require.Contains(t, matches, o4)
3641

3742
matches = objectives.Match([]*labels.Matcher{
3843
labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"),
3944
labels.MustNewMatcher(labels.MatchEqual, "ying", "yang"),
4045
})
46+
require.Len(t, matches, 1)
4147
require.Contains(t, matches, o2)
4248

4349
matches = objectives.Match([]*labels.Matcher{
4450
labels.MustNewMatcher(labels.MatchRegexp, "foo", "ba."),
4551
})
52+
require.Len(t, matches, 4)
4653
require.Contains(t, matches, o1)
4754
require.Contains(t, matches, o2)
4855
require.Contains(t, matches, o3)
56+
require.Contains(t, matches, o4)
4957
}

kubernetes.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ type ObjectiveServer struct {
106106
client client.Client
107107
}
108108

109-
func (o *ObjectiveServer) ListObjectives(ctx context.Context) (openapiserver.ImplResponse, error) {
109+
func (o *ObjectiveServer) ListObjectives(ctx context.Context, expr string) (openapiserver.ImplResponse, error) {
110110
var list pyrrav1alpha1.ServiceLevelObjectiveList
111111
if err := o.client.List(context.Background(), &list); err != nil {
112112
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err

main.go

+24-30
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ func (o *ObjectivesServer) ListObjectives(ctx context.Context, query string) (op
286286
}
287287
}
288288

289-
objectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx, query).Execute()
289+
objectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(query).Execute()
290290
if err != nil {
291291
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
292292
}
@@ -302,38 +302,19 @@ func (o *ObjectivesServer) ListObjectives(ctx context.Context, query string) (op
302302
}, nil
303303
}
304304

305-
func (o *ObjectivesServer) GetObjective(ctx context.Context, expr string) (openapiserver.ImplResponse, error) {
306-
objective, _, err := o.apiclient.ObjectivesApi.GetObjective(ctx, expr).Execute()
307-
if err != nil {
308-
var apiErr openapiclient.GenericOpenAPIError
309-
if errors.As(err, &apiErr) {
310-
if strings.HasPrefix(apiErr.Error(), strconv.Itoa(http.StatusNotFound)) {
311-
return openapiserver.ImplResponse{Code: http.StatusNotFound}, apiErr
312-
}
313-
}
314-
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
315-
}
316-
317-
return openapiserver.ImplResponse{
318-
Code: http.StatusCreated,
319-
Body: openapi.ServerFromClient(objective),
320-
}, nil
321-
}
322-
323305
func (o *ObjectivesServer) GetObjectiveStatus(ctx context.Context, expr string) (openapiserver.ImplResponse, error) {
324-
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx, expr).Execute()
306+
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
325307
if err != nil {
326308
var apiErr openapiclient.GenericOpenAPIError
327309
if errors.As(err, &apiErr) {
328310
if strings.HasPrefix(apiErr.Error(), strconv.Itoa(http.StatusNotFound)) {
329311
return openapiserver.ImplResponse{Code: http.StatusNotFound}, apiErr
330312
}
331313
}
332-
333314
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
334315
}
335316
if len(clientObjectives) != 1 {
336-
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches not exactly one SLO, it matches: %d", len(clientObjectives))
317+
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches more than one SLO, it matches: %d", len(clientObjectives))
337318
}
338319

339320
objective := openapi.InternalFromClient(clientObjectives[0])
@@ -383,11 +364,14 @@ func (o *ObjectivesServer) GetObjectiveStatus(ctx context.Context, expr string)
383364
}
384365

385366
func (o *ObjectivesServer) GetObjectiveErrorBudget(ctx context.Context, expr string, startTimestamp int32, endTimestamp int32) (openapiserver.ImplResponse, error) {
386-
clientObjective, _, err := o.apiclient.ObjectivesApi.GetObjective(ctx, expr).Execute()
367+
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
387368
if err != nil {
388369
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
389370
}
390-
objective := openapi.InternalFromClient(clientObjective)
371+
if len(clientObjectives) != 1 {
372+
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches more than one SLO, it matches: %d", len(clientObjectives))
373+
}
374+
objective := openapi.InternalFromClient(clientObjectives[0])
391375

392376
now := time.Now()
393377
start := now.Add(-1 * time.Hour)
@@ -450,11 +434,15 @@ const (
450434
)
451435

452436
func (o *ObjectivesServer) GetMultiBurnrateAlerts(ctx context.Context, expr string) (openapiserver.ImplResponse, error) {
453-
clientObjective, _, err := o.apiclient.ObjectivesApi.GetObjective(ctx, expr).Execute()
437+
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
454438
if err != nil {
455439
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
456440
}
457-
objective := openapi.InternalFromClient(clientObjective)
441+
if len(clientObjectives) != 1 {
442+
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches not exactly one SLO")
443+
}
444+
445+
objective := openapi.InternalFromClient(clientObjectives[0])
458446

459447
baseAlerts, err := objective.Alerts()
460448
if err != nil {
@@ -574,11 +562,14 @@ func (o *ObjectivesServer) GetMultiBurnrateAlerts(ctx context.Context, expr stri
574562
}
575563

576564
func (o *ObjectivesServer) GetREDRequests(ctx context.Context, expr string, startTimestamp int32, endTimestamp int32) (openapiserver.ImplResponse, error) {
577-
clientObjective, _, err := o.apiclient.ObjectivesApi.GetObjective(ctx, expr).Execute()
565+
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
578566
if err != nil {
579567
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
580568
}
581-
objective := openapi.InternalFromClient(clientObjective)
569+
if len(clientObjectives) != 1 {
570+
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches not exactly one SLO")
571+
}
572+
objective := openapi.InternalFromClient(clientObjectives[0])
582573

583574
now := time.Now()
584575
start := now.Add(-1 * time.Hour)
@@ -651,11 +642,14 @@ func (o *ObjectivesServer) GetREDRequests(ctx context.Context, expr string, star
651642
}
652643

653644
func (o *ObjectivesServer) GetREDErrors(ctx context.Context, expr string, startTimestamp int32, endTimestamp int32) (openapiserver.ImplResponse, error) {
654-
clientObjective, _, err := o.apiclient.ObjectivesApi.GetObjective(ctx, expr).Execute()
645+
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
655646
if err != nil {
656647
return openapiserver.ImplResponse{Code: http.StatusInternalServerError}, err
657648
}
658-
objective := openapi.InternalFromClient(clientObjective)
649+
if len(clientObjectives) != 1 {
650+
return openapiserver.ImplResponse{Code: http.StatusBadRequest}, fmt.Errorf("expr matches not exactly one SLO")
651+
}
652+
objective := openapi.InternalFromClient(clientObjectives[0])
659653

660654
now := time.Now()
661655
start := now.Add(-1 * time.Hour)

0 commit comments

Comments
 (0)