From bc6a20e1229a7c44ac256ca4b356a1e86ef259a5 Mon Sep 17 00:00:00 2001 From: "Arvid E. Picciani" Date: Wed, 13 Jul 2022 15:09:50 +0200 Subject: [PATCH] implement a log of events queriable from the metrics endpoint fixes #304 Signed-off-by: Arvid E. Picciani --- cmd/coordinator/run.go | 6 +++-- coordinator/core/core.go | 7 +++-- coordinator/core/marbleapi.go | 6 +++++ coordinator/events/eventlog.go | 47 ++++++++++++++++++++++++++++++++++ coordinator/server/server.go | 4 ++- 5 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 coordinator/events/eventlog.go diff --git a/cmd/coordinator/run.go b/cmd/coordinator/run.go index 92a89d0be..166a9779f 100644 --- a/cmd/coordinator/run.go +++ b/cmd/coordinator/run.go @@ -13,6 +13,7 @@ import ( "github.com/edgelesssys/marblerun/coordinator/config" "github.com/edgelesssys/marblerun/coordinator/core" + "github.com/edgelesssys/marblerun/coordinator/events" "github.com/edgelesssys/marblerun/coordinator/quote" "github.com/edgelesssys/marblerun/coordinator/recovery" "github.com/edgelesssys/marblerun/coordinator/seal" @@ -57,6 +58,7 @@ func run(validator quote.Validator, issuer quote.Issuer, sealDir string, sealer promServerAddr := os.Getenv(config.PromAddr) // Create Prometheus resources and start the Prometheus server. + var eventlog = events.NewLog() var promRegistry *prometheus.Registry var promFactoryPtr *promauto.Factory if promServerAddr != "" { @@ -72,7 +74,7 @@ func run(validator quote.Validator, issuer quote.Issuer, sealDir string, sealer "commit": GitCommit, }, }) - go server.RunPrometheusServer(promServerAddr, zapLogger, promRegistry) + go server.RunPrometheusServer(promServerAddr, zapLogger, promRegistry, eventlog) } // creating core @@ -80,7 +82,7 @@ func run(validator quote.Validator, issuer quote.Issuer, sealDir string, sealer if err := os.MkdirAll(sealDir, 0o700); err != nil { zapLogger.Fatal("Cannot create or access sealdir. Please check the permissions for the specified path.", zap.Error(err)) } - co, err := core.NewCore(dnsNames, validator, issuer, sealer, recovery, zapLogger, promFactoryPtr) + co, err := core.NewCore(dnsNames, validator, issuer, sealer, recovery, zapLogger, promFactoryPtr, eventlog) if err != nil { if _, ok := err.(core.QuoteError); !ok || !devMode { zapLogger.Fatal("Cannot create Coordinator core", zap.Error(err)) diff --git a/coordinator/core/core.go b/coordinator/core/core.go index 196b9f0bd..fd7f44d40 100644 --- a/coordinator/core/core.go +++ b/coordinator/core/core.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/edgelesssys/marblerun/coordinator/events" "github.com/edgelesssys/marblerun/coordinator/manifest" "github.com/edgelesssys/marblerun/coordinator/quote" "github.com/edgelesssys/marblerun/coordinator/recovery" @@ -55,6 +56,7 @@ type Core struct { updateLogger *updatelog.Logger zaplogger *zap.Logger metrics *coreMetrics + eventlog *events.Log rpc.UnimplementedMarbleServer } @@ -112,7 +114,7 @@ func (c *Core) advanceState(newState state, tx store.Transaction) error { } // NewCore creates and initializes a new Core object. -func NewCore(dnsNames []string, qv quote.Validator, qi quote.Issuer, sealer seal.Sealer, recovery recovery.Recovery, zapLogger *zap.Logger, promFactory *promauto.Factory) (*Core, error) { +func NewCore(dnsNames []string, qv quote.Validator, qi quote.Issuer, sealer seal.Sealer, recovery recovery.Recovery, zapLogger *zap.Logger, promFactory *promauto.Factory, eventlog *events.Log) (*Core, error) { stor := store.NewStdStore(sealer) c := &Core{ qv: qv, @@ -122,6 +124,7 @@ func NewCore(dnsNames []string, qv quote.Validator, qi quote.Issuer, sealer seal data: storeWrapper{store: stor}, sealer: sealer, zaplogger: zapLogger, + eventlog: eventlog, } c.metrics = newCoreMetrics(promFactory, c, "coordinator") @@ -207,7 +210,7 @@ func NewCoreWithMocks() *Core { issuer := quote.NewMockIssuer() sealer := &seal.MockSealer{} recovery := recovery.NewSinglePartyRecovery() - core, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil) + core, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil) if err != nil { panic(err) } diff --git a/coordinator/core/marbleapi.go b/coordinator/core/marbleapi.go index dead0e74a..cf950b993 100644 --- a/coordinator/core/marbleapi.go +++ b/coordinator/core/marbleapi.go @@ -145,6 +145,12 @@ func (c *Core) Activate(ctx context.Context, req *rpc.ActivationReq) (*rpc.Activ c.metrics.marbleAPI.activationSuccess.WithLabelValues(req.GetMarbleType(), req.GetUUID()).Inc() c.zaplogger.Info("Successfully activated new Marble", zap.String("MarbleType", req.MarbleType), zap.String("UUID", marbleUUID.String())) + + if c.eventlog != nil { + c.eventlog.Activation(req.GetMarbleType(), req.GetUUID(), req.GetQuote()) + } + + return resp, nil } diff --git a/coordinator/events/eventlog.go b/coordinator/events/eventlog.go new file mode 100644 index 000000000..7dfad0c01 --- /dev/null +++ b/coordinator/events/eventlog.go @@ -0,0 +1,47 @@ +// Copyright (c) Edgeless Systems GmbH. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +package events + +import ( + "time" + "net/http" + "encoding/json" +) + +type ActivationEvent struct { + MarbleType string `json:"marbleType"` + UUID string `json:"uuid"` + Quote []byte `json:"quote"` +} + +type Event struct { + Timestamp time.Time `json:"time"` + Activation *ActivationEvent `json:"activation"` +} + +type Log struct { + events []Event +} + +func NewLog() *Log { + return &Log{} +} + +func (ev *Log) Activation(marbleType string, uuid string, quote []byte) { + ev.events = append(ev.events, Event{ + Timestamp: time.Now(), + Activation: &ActivationEvent{MarbleType: marbleType, UUID: uuid, Quote: quote}, + }) +} + +func (ev *Log) Handler() http.HandlerFunc { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(ev.events) + }) +} diff --git a/coordinator/server/server.go b/coordinator/server/server.go index c3c5218e9..af2db6b48 100644 --- a/coordinator/server/server.go +++ b/coordinator/server/server.go @@ -14,6 +14,7 @@ import ( "os" "github.com/edgelesssys/marblerun/coordinator/core" + "github.com/edgelesssys/marblerun/coordinator/events" "github.com/edgelesssys/marblerun/coordinator/rpc" "github.com/gorilla/handlers" "github.com/gorilla/mux" @@ -112,9 +113,10 @@ func RunClientServer(mux http.Handler, address string, tlsConfig *tls.Config, za } // RunPrometheusServer runs a HTTP server handling the prometheus metrics endpoint. -func RunPrometheusServer(address string, zapLogger *zap.Logger, reg *prometheus.Registry) { +func RunPrometheusServer(address string, zapLogger *zap.Logger, reg *prometheus.Registry, eventlog *events.Log) { mux := http.NewServeMux() mux.Handle("/metrics", promhttp.InstrumentMetricHandler(reg, promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))) + mux.Handle("/events", eventlog.Handler()) zapLogger.Info("starting prometheus /metrics endpoint", zap.String("address", address)) err := http.ListenAndServe(address, mux) zapLogger.Warn(err.Error())