Skip to content

Commit

Permalink
implement a log of events queriable from the metrics endpoint
Browse files Browse the repository at this point in the history
fixes #304

Signed-off-by: Arvid E. Picciani <[email protected]>
  • Loading branch information
aep committed Jul 14, 2022
1 parent 96c6be1 commit e77791d
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 19 deletions.
6 changes: 4 additions & 2 deletions cmd/coordinator/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 != "" {
Expand All @@ -72,15 +74,15 @@ 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
zapLogger.Info("creating the Core object")
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))
Expand Down
7 changes: 5 additions & 2 deletions coordinator/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -55,6 +56,7 @@ type Core struct {
updateLogger *updatelog.Logger
zaplogger *zap.Logger
metrics *coreMetrics
eventlog *events.Log
rpc.UnimplementedMarbleServer
}

Expand Down Expand Up @@ -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,
Expand All @@ -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")

Expand Down Expand Up @@ -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)
}
Expand Down
12 changes: 6 additions & 6 deletions coordinator/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestSeal(t *testing.T) {
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()

c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)

// Set manifest. This will seal the state.
Expand All @@ -90,7 +90,7 @@ func TestSeal(t *testing.T) {
assert.NoError(err)

// Check sealing with a new core initialized with the sealed state.
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
c2State, err := c2.data.getState()
assert.NoError(err)
Expand Down Expand Up @@ -127,7 +127,7 @@ func TestRecover(t *testing.T) {
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()

c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)

// new core does not allow recover
Expand All @@ -145,7 +145,7 @@ func TestRecover(t *testing.T) {

// Initialize new core and let unseal fail
sealer.UnsealError = seal.ErrEncryptionKey
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
sealer.UnsealError = nil
require.NoError(err)
c2State, err := c2.data.getState()
Expand Down Expand Up @@ -367,7 +367,7 @@ func TestUnsetRestart(t *testing.T) {
recovery := recovery.NewSinglePartyRecovery()

// create a new core, this seals the state with only certificate and keys
c1, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c1, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
c1State, err := c1.data.getState()
assert.NoError(err)
Expand All @@ -376,7 +376,7 @@ func TestUnsetRestart(t *testing.T) {
assert.NoError(err)

// create a second core, this should overwrite the previously sealed certificate and keys since no manifest was set
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
c2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
c2State, err := c2.data.getState()
assert.NoError(err)
Expand Down
6 changes: 6 additions & 0 deletions coordinator/core/marbleapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
8 changes: 4 additions & 4 deletions coordinator/core/marbleapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestActivate(t *testing.T) {
issuer := quote.NewMockIssuer()
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
require.NotNil(coreServer)

Expand Down Expand Up @@ -461,7 +461,7 @@ func TestSecurityLevelUpdate(t *testing.T) {
issuer := quote.NewMockIssuer()
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
require.NotNil(coreServer)

Expand Down Expand Up @@ -491,7 +491,7 @@ func TestSecurityLevelUpdate(t *testing.T) {
spawner.newMarble("frontend", "Azure", false)

// Use a new core and test if updated manifest persisted after restart
coreServer2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
coreServer2, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
coreServer2State, err := coreServer2.data.getState()
assert.NoError(err)
Expand Down Expand Up @@ -572,7 +572,7 @@ func TestActivateWithMissingParameters(t *testing.T) {
issuer := quote.NewMockIssuer()
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
require.NotNil(coreServer)

Expand Down
6 changes: 3 additions & 3 deletions coordinator/core/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestStoreWrapperMetrics(t *testing.T) {
//
reg := prometheus.NewRegistry()
fac := promauto.With(reg)
c, _ := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &fac)
c, _ := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &fac, nil)
assert.Equal(1, promtest.CollectAndCount(c.metrics.coordinatorState))
assert.Equal(float64(stateAcceptingManifest), promtest.ToFloat64(c.metrics.coordinatorState))

Expand All @@ -49,7 +49,7 @@ func TestStoreWrapperMetrics(t *testing.T) {
reg = prometheus.NewRegistry()
fac = promauto.With(reg)
sealer.UnsealError = seal.ErrEncryptionKey
c, err = NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &fac)
c, err = NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &fac, nil)
sealer.UnsealError = nil
require.NoError(err)
assert.Equal(1, promtest.CollectAndCount(c.metrics.coordinatorState))
Expand Down Expand Up @@ -84,7 +84,7 @@ func TestMarbleAPIMetrics(t *testing.T) {
recovery := recovery.NewSinglePartyRecovery()
promRegistry := prometheus.NewRegistry()
promFactory := promauto.With(promRegistry)
c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &promFactory)
c, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, &promFactory, nil)
require.NoError(err)
require.NotNil(c)

Expand Down
2 changes: 1 addition & 1 deletion coordinator/core/openssl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func TestOpenSSLVerify(t *testing.T) {
issuer := quote.NewMockIssuer()
sealer := &seal.MockSealer{}
recovery := recovery.NewSinglePartyRecovery()
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil)
coreServer, err := NewCore([]string{"localhost"}, validator, issuer, sealer, recovery, zapLogger, nil, nil)
require.NoError(err)
require.NotNil(coreServer)

Expand Down
54 changes: 54 additions & 0 deletions coordinator/events/eventlog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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 implements a log of coordinator events.
package events

import (
"encoding/json"
"net/http"
"time"
)

// ActivationEvent is an event that is logged when a marble is activated.
type ActivationEvent struct {
MarbleType string `json:"marbleType"`
UUID string `json:"uuid"`
Quote []byte `json:"quote"`
}

// Event represents a single event in the event log.
type Event struct {
Timestamp time.Time `json:"time"`
Activation *ActivationEvent `json:"activation"`
}

// Log is a log of coordinator events.
type Log struct {
events []Event
}

// NewLog creates a new log.
func NewLog() *Log {
return &Log{}
}

// Activation adds an activation event to the log.
func (l *Log) Activation(marbleType string, uuid string, quote []byte) {
l.events = append(l.events, Event{
Timestamp: time.Now(),
Activation: &ActivationEvent{MarbleType: marbleType, UUID: uuid, Quote: quote},
})
}

// The http handler retutns the log as JSON array
func (l *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(l.events)
})
}
4 changes: 3 additions & 1 deletion coordinator/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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())
Expand Down

0 comments on commit e77791d

Please sign in to comment.