Skip to content

Commit 9b57101

Browse files
committed
Start adding connect-go for the API and backend API
1 parent 156b3af commit 9b57101

File tree

10 files changed

+636
-15
lines changed

10 files changed

+636
-15
lines changed

buf.gen.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: v1
2+
plugins:
3+
- name: go
4+
out: proto
5+
opt: paths=source_relative
6+
- name: connect-go
7+
out: proto
8+
opt: paths=source_relative

buf.work.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version: v1
2+
directories:
3+
- proto

filesystem.go

+53-11
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"io/ioutil"
87
"net/http"
8+
"os"
99
"path/filepath"
1010
"sync"
1111
"time"
1212

13+
"github.com/bufbuild/connect-go"
1314
"github.com/fsnotify/fsnotify"
1415
"github.com/go-kit/log"
1516
"github.com/go-kit/log/level"
@@ -20,11 +21,15 @@ import (
2021
"github.com/prometheus/client_golang/prometheus/promhttp"
2122
"github.com/prometheus/prometheus/model/labels"
2223
"github.com/prometheus/prometheus/promql/parser"
24+
"golang.org/x/net/http2"
25+
"golang.org/x/net/http2/h2c"
2326
"sigs.k8s.io/yaml"
2427

2528
"github.com/pyrra-dev/pyrra/kubernetes/api/v1alpha1"
2629
"github.com/pyrra-dev/pyrra/openapi"
2730
openapiserver "github.com/pyrra-dev/pyrra/openapi/server/go"
31+
"github.com/pyrra-dev/pyrra/proto/objectives/v1alpha1"
32+
"github.com/pyrra-dev/pyrra/proto/objectives/v1alpha1/objectivesv1alpha1connect"
2833
"github.com/pyrra-dev/pyrra/slo"
2934
)
3035

@@ -170,7 +175,7 @@ func cmdFilesystem(logger log.Logger, reg *prometheus.Registry, promClient api.C
170175
level.Debug(logger).Log("msg", "reading", "file", f)
171176
reconcilesTotal.Inc()
172177

173-
bytes, err := ioutil.ReadFile(f)
178+
bytes, err := os.ReadFile(f)
174179
if err != nil {
175180
reconcilesErrors.Inc()
176181
return fmt.Errorf("failed to read file %q: %w", f, err)
@@ -212,7 +217,7 @@ func cmdFilesystem(logger log.Logger, reg *prometheus.Registry, promClient api.C
212217
_, file := filepath.Split(f)
213218
path := filepath.Join(prometheusFolder, file)
214219

215-
if err := ioutil.WriteFile(path, bytes, 0o644); err != nil {
220+
if err := os.WriteFile(path, bytes, 0o644); err != nil {
216221
reconcilesErrors.Inc()
217222
return fmt.Errorf("failed to write file %q: %w", path, err)
218223
}
@@ -268,14 +273,21 @@ func cmdFilesystem(logger log.Logger, reg *prometheus.Registry, promClient api.C
268273
})
269274
}
270275
{
271-
router := openapiserver.NewRouter(
272-
openapiserver.NewObjectivesApiController(&FilesystemObjectiveServer{
273-
objectives: objectives,
274-
}),
275-
)
276-
router.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
277-
278-
server := http.Server{Addr: ":9444", Handler: router}
276+
//router := openapiserver.NewRouter(
277+
// openapiserver.NewObjectivesApiController(&FilesystemObjectiveServer{
278+
// objectives: objectives,
279+
// }),
280+
//)
281+
mux := http.NewServeMux()
282+
mux.Handle(objectivesv1alpha1connect.NewObjectiveBackendServiceHandler(&connectFilesystemObjectiveServer{
283+
objectives: objectives,
284+
}))
285+
mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
286+
287+
server := http.Server{
288+
Addr: ":9444",
289+
Handler: h2c.NewHandler(mux, &http2.Server{}),
290+
}
279291

280292
gr.Add(func() error {
281293
level.Info(logger).Log("msg", "starting up HTTP API", "address", server.Addr)
@@ -296,6 +308,36 @@ type FilesystemObjectiveServer struct {
296308
objectives *Objectives
297309
}
298310

311+
type connectFilesystemObjectiveServer struct {
312+
objectives *Objectives
313+
}
314+
315+
func (s *connectFilesystemObjectiveServer) ListObjectives(ctx context.Context, req *connect.Request[objectivesv1alpha1.ListObjectivesRequest]) (*connect.Response[objectivesv1alpha1.ListObjectivesResponse], error) {
316+
var matchers []*labels.Matcher
317+
if expr := req.Msg.Expr; expr != "" {
318+
var err error
319+
matchers, err = parser.ParseMetricSelector(expr)
320+
if err != nil {
321+
return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("failed to parse expr: %w", err))
322+
}
323+
}
324+
325+
matchingObjectives := s.objectives.Match(matchers)
326+
objectives := make([]*objectivesv1alpha1.Objective, 0, len(matchingObjectives))
327+
for _, o := range matchingObjectives {
328+
objectives = append(objectives, &objectivesv1alpha1.Objective{
329+
Labels: o.Labels.Map(),
330+
Description: o.Description,
331+
Target: o.Target,
332+
Window: time.Duration(o.Window).Milliseconds(),
333+
})
334+
}
335+
336+
return connect.NewResponse[objectivesv1alpha1.ListObjectivesResponse](&objectivesv1alpha1.ListObjectivesResponse{
337+
Objectives: objectives,
338+
}), nil
339+
}
340+
299341
func (f FilesystemObjectiveServer) ListObjectives(ctx context.Context, query string) (openapiserver.ImplResponse, error) {
300342
var matchers []*labels.Matcher
301343
if query != "" {

go.mod

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/pyrra-dev/pyrra
22

3-
go 1.17
3+
go 1.19
44

55
require (
66
github.com/alecthomas/kong v0.6.1
@@ -29,6 +29,7 @@ require (
2929
github.com/PuerkitoBio/purell v1.1.1 // indirect
3030
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
3131
github.com/beorn7/perks v1.0.1 // indirect
32+
github.com/bufbuild/connect-go v0.3.0 // indirect
3233
github.com/cespare/xxhash/v2 v2.1.2 // indirect
3334
github.com/davecgh/go-spew v1.1.1 // indirect
3435
github.com/dennwc/varint v1.0.0 // indirect
@@ -46,7 +47,7 @@ require (
4647
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
4748
github.com/golang/protobuf v1.5.2 // indirect
4849
github.com/google/gnostic v0.5.7-v3refs // indirect
49-
github.com/google/go-cmp v0.5.6 // indirect
50+
github.com/google/go-cmp v0.5.8 // indirect
5051
github.com/google/gofuzz v1.1.0 // indirect
5152
github.com/google/uuid v1.2.0 // indirect
5253
github.com/imdario/mergo v0.3.12 // indirect
@@ -75,7 +76,7 @@ require (
7576
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
7677
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
7778
google.golang.org/appengine v1.6.7 // indirect
78-
google.golang.org/protobuf v1.27.1 // indirect
79+
google.golang.org/protobuf v1.28.0 // indirect
7980
gopkg.in/inf.v0 v0.9.1 // indirect
8081
gopkg.in/yaml.v2 v2.4.0 // indirect
8182
gopkg.in/yaml.v3 v3.0.1 // indirect

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+Wji
208208
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
209209
github.com/bonitoo-io/go-sql-bigquery v0.3.4-1.4.0/go.mod h1:J4Y6YJm0qTWB9aFziB7cPeSyc6dOZFyJdteSeybVpXQ=
210210
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
211+
github.com/bufbuild/connect-go v0.3.0 h1:B0vyZrTR11SNEYpodL6P0NzluDCsuqmr8CNKblXvVto=
212+
github.com/bufbuild/connect-go v0.3.0/go.mod h1:4efZ2eXFENwd4p7tuLaL9m0qtTsCOzuBvrohvRGevDM=
211213
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
212214
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
213215
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
@@ -706,6 +708,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
706708
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
707709
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
708710
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
711+
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
712+
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
709713
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
710714
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
711715
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
@@ -2023,6 +2027,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
20232027
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
20242028
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
20252029
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
2030+
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
2031+
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
20262032
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
20272033
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
20282034
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

main.go

+41-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"time"
2121

2222
"github.com/alecthomas/kong"
23+
"github.com/bufbuild/connect-go"
2324
"github.com/dgraph-io/ristretto"
2425
"github.com/go-chi/chi/v5"
2526
"github.com/go-chi/cors"
@@ -34,10 +35,14 @@ import (
3435
"github.com/prometheus/common/model"
3536
"github.com/prometheus/prometheus/model/labels"
3637
"github.com/prometheus/prometheus/promql/parser"
38+
"golang.org/x/net/http2"
39+
"golang.org/x/net/http2/h2c"
3740

3841
"github.com/pyrra-dev/pyrra/openapi"
3942
openapiclient "github.com/pyrra-dev/pyrra/openapi/client"
4043
openapiserver "github.com/pyrra-dev/pyrra/openapi/server/go"
44+
objectivesv1alpha1 "github.com/pyrra-dev/pyrra/proto/objectives/v1alpha1"
45+
"github.com/pyrra-dev/pyrra/proto/objectives/v1alpha1/objectivesv1alpha1connect"
4146
"github.com/pyrra-dev/pyrra/slo"
4247
)
4348

@@ -242,7 +247,15 @@ func cmdAPI(logger log.Logger, reg *prometheus.Registry, promClient api.Client,
242247
})
243248
}
244249

245-
if err := http.ListenAndServe(":9099", r); err != nil {
250+
objectiveService := &connectObjectiveServer{
251+
logger: logger,
252+
promAPI: promAPI,
253+
client: objectivesv1alpha1connect.NewObjectiveBackendServiceClient(http.DefaultClient, apiURL.String()),
254+
}
255+
// TODO: move to route with routePrefix?
256+
r.Mount(objectivesv1alpha1connect.NewObjectiveServiceHandler(objectiveService))
257+
258+
if err := http.ListenAndServe(":9099", h2c.NewHandler(r, &http2.Server{})); err != nil {
246259
level.Error(logger).Log("msg", "failed to run HTTP server", "err", err)
247260
return 2
248261
}
@@ -397,6 +410,12 @@ type ObjectivesServer struct {
397410
apiclient *openapiclient.APIClient
398411
}
399412

413+
type connectObjectiveServer struct {
414+
logger log.Logger
415+
promAPI *promCache
416+
client objectivesv1alpha1connect.ObjectiveBackendServiceClient
417+
}
418+
400419
func (o *ObjectivesServer) ListObjectives(ctx context.Context, query string) (openapiserver.ImplResponse, error) {
401420
if query != "" {
402421
// We'll parse the query matchers already to make sure it's valid before passing on to the backend.
@@ -421,6 +440,27 @@ func (o *ObjectivesServer) ListObjectives(ctx context.Context, query string) (op
421440
}, nil
422441
}
423442

443+
func (c *connectObjectiveServer) ListObjectives(ctx context.Context, req *connect.Request[objectivesv1alpha1.ListObjectivesRequest]) (*connect.Response[objectivesv1alpha1.ListObjectivesResponse], error) {
444+
c.logger.Log("msg", "got request", "expr", req.Msg.Expr)
445+
446+
if expr := req.Msg.Expr; expr != "" {
447+
if _, err := parser.ParseMetricSelector(expr); err != nil {
448+
return nil, connect.NewError(connect.CodeFailedPrecondition, fmt.Errorf("failed to parse expr: %w", err))
449+
}
450+
}
451+
452+
resp, err := c.client.ListObjectives(ctx, connect.NewRequest[objectivesv1alpha1.ListObjectivesRequest](&objectivesv1alpha1.ListObjectivesRequest{
453+
Expr: req.Msg.Expr,
454+
}))
455+
if err != nil {
456+
return nil, err
457+
}
458+
459+
return connect.NewResponse[objectivesv1alpha1.ListObjectivesResponse](&objectivesv1alpha1.ListObjectivesResponse{
460+
Objectives: resp.Msg.Objectives,
461+
}), nil
462+
}
463+
424464
func (o *ObjectivesServer) GetObjectiveStatus(ctx context.Context, expr, grouping string, tsUnix int32) (openapiserver.ImplResponse, error) {
425465
clientObjectives, _, err := o.apiclient.ObjectivesApi.ListObjectives(ctx).Expr(expr).Execute()
426466
if err != nil {

proto/buf.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: v1
2+
breaking:
3+
use:
4+
- FILE
5+
lint:
6+
use:
7+
- DEFAULT

0 commit comments

Comments
 (0)