Skip to content

Commit

Permalink
coordinator: add manifest generation metric
Browse files Browse the repository at this point in the history
  • Loading branch information
davidweisse committed May 22, 2024
1 parent e417db2 commit 77e12fe
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
17 changes: 17 additions & 0 deletions coordinator/userapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/edgelesssys/contrast/internal/userapi"
grpcprometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
Expand All @@ -33,13 +34,18 @@ import (
"google.golang.org/grpc/status"
)

type userAPIMetrics struct {
manifestGeneration prometheus.Gauge
}

type userAPIServer struct {
grpc *grpc.Server
policyTextStore store[manifest.HexString, manifest.Policy]
manifSetGetter manifestSetGetter
caChainGetter certChainGetter
logger *slog.Logger
mux sync.RWMutex
metrics userAPIMetrics

userapi.UnimplementedUserAPIServer
}
Expand All @@ -54,6 +60,12 @@ func newUserAPIServer(mSGetter manifestSetGetter, caGetter certChainGetter, reg
),
)

manifestGeneration := promauto.With(reg).NewGauge(prometheus.GaugeOpts{
Subsystem: "coordinator",
Name: "manifest_generation",
Help: "Current manifest generation.",
})

grpcServer := grpc.NewServer(
grpc.Creds(credentials),
grpc.KeepaliveParams(keepalive.ServerParameters{Time: 15 * time.Second}),
Expand All @@ -70,6 +82,9 @@ func newUserAPIServer(mSGetter manifestSetGetter, caGetter certChainGetter, reg
manifSetGetter: mSGetter,
caChainGetter: caGetter,
logger: log.WithGroup("userapi"),
metrics: userAPIMetrics{
manifestGeneration: manifestGeneration,
},
}
userapi.RegisterUserAPIServer(s.grpc, s)

Expand Down Expand Up @@ -122,6 +137,8 @@ func (s *userAPIServer) SetManifest(ctx context.Context, req *userapi.SetManifes
return nil, status.Errorf(codes.Internal, "setting manifest: %v", err)
}

s.metrics.manifestGeneration.Set(float64(len(s.manifSetGetter.GetManifests())))

resp := &userapi.SetManifestResponse{
RootCA: s.caChainGetter.GetRootCACert(),
MeshCA: s.caChainGetter.GetMeshCACert(),
Expand Down
41 changes: 40 additions & 1 deletion coordinator/userapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,32 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"log/slog"
"strings"
"sync"
"testing"

"github.com/edgelesssys/contrast/internal/appendable"
"github.com/edgelesssys/contrast/internal/manifest"
"github.com/edgelesssys/contrast/internal/memstore"
"github.com/edgelesssys/contrast/internal/userapi"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/peer"
)

const (
manifestGenerationExpected = `
# HELP coordinator_manifest_generation Current manifest generation.
# TYPE coordinator_manifest_generation gauge
coordinator_manifest_generation %d
`
)

func TestManifestSet(t *testing.T) {
newBaseManifest := func() manifest.Manifest {
return manifest.Default()
Expand Down Expand Up @@ -215,11 +227,20 @@ func TestManifestSet(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

manifestPrometheusGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Subsystem: "coordinator",
Name: "manifest_generation",
Help: "Current manifest generation.",
})

coordinator := userAPIServer{
manifSetGetter: tc.mSGetter,
caChainGetter: tc.caGetter,
policyTextStore: memstore.New[manifest.HexString, manifest.Policy](),
logger: slog.Default(),
metrics: userAPIMetrics{
manifestGeneration: manifestPrometheusGauge,
},
}

ctx := rpcContext(tc.workloadOwnerKey)
Expand All @@ -233,6 +254,9 @@ func TestManifestSet(t *testing.T) {
assert.Equal([]byte("root"), resp.RootCA)
assert.Equal([]byte("mesh"), resp.MeshCA)
assert.Equal(1, tc.mSGetter.setManifestCount)

expected := fmt.Sprintf(manifestGenerationExpected, 1)
assert.NoError(testutil.CollectAndCompare(manifestPrometheusGauge, strings.NewReader(expected)))
})
}
}
Expand Down Expand Up @@ -319,11 +343,20 @@ func TestUserAPIConcurrent(t *testing.T) {
return b
}

manifestPrometheusGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Subsystem: "coordinator",
Name: "manifest_generation",
Help: "Current manifest generation.",
})

coordinator := userAPIServer{
manifSetGetter: &stubManifestSetGetter{},
caChainGetter: &stubCertChainGetter{},
policyTextStore: memstore.New[manifest.HexString, manifest.Policy](),
logger: slog.Default(),
metrics: userAPIMetrics{
manifestGeneration: manifestPrometheusGauge,
},
}
setReq := &userapi.SetManifestRequest{
Manifest: newManifestBytes(func(m *manifest.Manifest) {
Expand All @@ -334,7 +367,7 @@ func TestUserAPIConcurrent(t *testing.T) {
}),
Policies: [][]byte{
[]byte("a"),
[]byte("c"),
[]byte("b"),
},
}

Expand Down Expand Up @@ -364,6 +397,9 @@ func TestUserAPIConcurrent(t *testing.T) {
go get()
go get()
wg.Wait()

expected := fmt.Sprintf(manifestGenerationExpected, 6)
assert.NoError(t, testutil.CollectAndCompare(manifestPrometheusGauge, strings.NewReader(expected)))
}

type stubManifestSetGetter struct {
Expand All @@ -383,6 +419,9 @@ func (s *stubManifestSetGetter) SetManifest(*manifest.Manifest) error {
func (s *stubManifestSetGetter) GetManifests() []*manifest.Manifest {
s.mux.RLock()
defer s.mux.RUnlock()
if s.getManifestResp == nil {
return make([]*manifest.Manifest, s.setManifestCount)
}
return s.getManifestResp
}

Expand Down
5 changes: 5 additions & 0 deletions docs/docs/architecture/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ For the mesh API, the metric names are prefixed with `meshapi_grpc_server_`. The
metrics include similar data to the user API for the method `NewMeshCert` which
gets called by the [Initializer](../components#the-initializer) when starting a
new workload.

The current manifest generation is exposed as a
[gauge](https://prometheus.io/docs/concepts/metric_types/#gauge) with the metric
name `coordinator_manifest_generation`. If no manifest is set at the
Coordinator, this counter will be zero.

0 comments on commit 77e12fe

Please sign in to comment.