aboutsummaryrefslogtreecommitdiff
path: root/server/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/main.go')
-rw-r--r--server/main.go157
1 files changed, 115 insertions, 42 deletions
diff --git a/server/main.go b/server/main.go
index 8f5ab48..7402fb3 100644
--- a/server/main.go
+++ b/server/main.go
@@ -2,13 +2,19 @@
package main
import (
+ "context"
"flag"
+ "fmt"
+ "os"
"strings"
+ "sync"
+ "syscall"
"time"
"crypto/ed25519"
"encoding/base64"
"net/http"
+ "os/signal"
"github.com/golang/glog"
"github.com/google/trillian"
@@ -23,78 +29,145 @@ var (
rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients")
prefix = flag.String("prefix", "st/v1", "a prefix that proceeds each endpoint path")
trillianID = flag.Int64("trillian_id", 5991359069696313945, "log identifier in the Trillian database")
- rpcDeadline = flag.Duration("rpc_deadline", time.Second*10, "deadline for backend RPC requests")
+ deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests")
key = flag.String("key", "8gzezwrU/2eTrO6tEYyLKsoqn5V54URvKIL9cTE7jUYUqXVX4neJvcBq/zpSAYPsZFG1woh0OGBzQbi9UP9MZw==", "base64-encoded Ed25519 signing key")
- namespaces = flag.String("namespaces", "AAEgHOQFUkKNWpjYAhNKTyWCzahlI7RDtf5123kHD2LACj0=,AAEgLqrWb9JwQUTk/SwTNDdMH8aRmy3mbmhwEepO5WSgb+A=", "comma-separated list of trusted namespaces in base64 (default: testdata.Ed25519{Vk,Vk2})")
+ submitters = flag.String("submitters", "AAEgHOQFUkKNWpjYAhNKTyWCzahlI7RDtf5123kHD2LACj0=,AAEgLqrWb9JwQUTk/SwTNDdMH8aRmy3mbmhwEepO5WSgb+A=", "comma-separated list of trusted submitter namespaces in base64 (default: testdata.Ed25519{Vk,Vk2})")
+ witnesses = flag.String("witnesses", "", "comma-separated list of trusted submitter namespaces in base64 (default: none")
maxRange = flag.Int64("max_range", 2, "maximum number of entries that can be retrived in a single request")
+ interval = flag.Duration("interval", time.Second*30, "interval used to rotate the log's cosigned STH")
)
func main() {
flag.Parse()
+ defer glog.Flush()
- glog.Info("Dialling Trillian gRPC log server")
- dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(*rpcDeadline)}
+ // wait for clean-up before exit
+ var wg sync.WaitGroup
+ defer wg.Wait()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ glog.V(3).Infof("configuring stfe instance...")
+ instance, err := setupInstanceFromFlags()
+ if err != nil {
+ glog.Errorf("setupInstance: %v", err)
+ return
+ }
+
+ glog.V(3).Infof("spawning SthSource")
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ instance.SthSource.Run(ctx)
+ glog.Errorf("SthSource shutdown")
+ cancel() // must have SthSource running
+ }()
+
+ glog.V(3).Infof("spawning await")
+ server := http.Server{Addr: *httpEndpoint}
+ go await(ctx, func() {
+ wg.Add(1)
+ defer wg.Done()
+ ctxInner, _ := context.WithTimeout(ctx, time.Second*60)
+ glog.Infof("Shutting down HTTP server...")
+ server.Shutdown(ctxInner)
+ glog.V(3).Infof("HTTP server shutdown")
+ glog.Infof("Shutting down spawned go routines...")
+ cancel()
+ })
+
+ glog.Infof("Serving on %v/%v", *httpEndpoint, *prefix)
+ if err = server.ListenAndServe(); err != http.ErrServerClosed {
+ glog.Errorf("ListenAndServe: %v", err)
+ }
+}
+
+// SetupInstance sets up a new STFE instance from flags
+func setupInstanceFromFlags() (*stfe.Instance, error) {
+ // Trillian gRPC connection
+ dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(*deadline)}
conn, err := grpc.Dial(*rpcBackend, dialOpts...)
if err != nil {
- glog.Fatal(err)
+ return nil, fmt.Errorf("Dial: %v", err)
}
client := trillian.NewTrillianLogClient(conn)
-
- glog.Info("Creating HTTP request multiplexer")
+ // HTTP multiplexer
mux := http.NewServeMux()
http.Handle("/", mux)
-
- glog.Info("Adding prometheus handler on path: /metrics")
+ // Prometheus metrics
+ glog.V(3).Infof("Adding prometheus handler on path: /metrics")
http.Handle("/metrics", promhttp.Handler())
-
- glog.Infof("Creating namespace pool")
- var anchors []*namespace.Namespace
- for _, b64 := range strings.Split(*namespaces, ",") {
- b, err := base64.StdEncoding.DecodeString(b64)
- if err != nil {
- glog.Fatalf("invalid namespace: %s: %v", b64, err)
- }
- var namespace namespace.Namespace
- if err := namespace.Unmarshal(b); err != nil {
- glog.Fatalf("invalid namespace: %s: %v", b64, err)
- }
- anchors = append(anchors, &namespace)
+ // Trusted submitters
+ submitters, err := newNamespacePoolFromString(*submitters)
+ if err != nil {
+ return nil, fmt.Errorf("submitters: newNamespacePoolFromString: %v", err)
}
- pool, err := namespace.NewNamespacePool(anchors)
+ // Trusted witnesses
+ witnesses, err := newNamespacePoolFromString(*witnesses)
if err != nil {
- glog.Fatalf("invalid namespace pool: %v", err)
+ return nil, fmt.Errorf("witnesses: NewNamespacePool: %v", err)
}
-
- glog.Infof("Creating log signer and identifier")
+ // Log identity
sk, err := base64.StdEncoding.DecodeString(*key)
if err != nil {
- glog.Fatalf("invalid signing key: %v", err)
+ return nil, fmt.Errorf("sk: DecodeString: %v", err)
}
signer := ed25519.PrivateKey(sk)
logId, err := namespace.NewNamespaceEd25519V1([]byte(ed25519.PrivateKey(sk).Public().(ed25519.PublicKey)))
if err != nil {
- glog.Fatalf("failed creating log id from secret key: %v", err)
+ return nil, fmt.Errorf("NewNamespaceEd25519V1: %v", err)
}
-
- glog.Infof("Initializing log parameters")
- lp, err := stfe.NewLogParameters(signer, logId, *trillianID, *prefix, pool, *maxRange)
+ // Setup log parameters
+ lp, err := stfe.NewLogParameters(signer, logId, *trillianID, *prefix, submitters, witnesses, *maxRange, *interval, *deadline)
if err != nil {
- glog.Fatalf("failed setting up log parameters: %v", err)
+ return nil, fmt.Errorf("NewLogParameters: %v", err)
}
-
- i := stfe.NewInstance(lp, client, *rpcDeadline)
+ // Setup STH source
+ source, err := stfe.NewActiveSthSource(client, lp)
+ if err != nil {
+ return nil, fmt.Errorf("NewActiveSthSource: %v", err)
+ }
+ // Setup log instance
+ i := stfe.NewInstance(lp, client, source)
for _, handler := range i.Handlers() {
- glog.Infof("adding handler: %s", handler.Path())
+ glog.V(3).Infof("adding handler: %s", handler.Path())
mux.Handle(handler.Path(), handler)
}
- glog.Infof("Configured: %s", i)
+ return i, nil
+}
- glog.Infof("Serving on %v/%v", *httpEndpoint, *prefix)
- srv := http.Server{Addr: *httpEndpoint}
- err = srv.ListenAndServe()
- if err != http.ErrServerClosed {
- glog.Warningf("Server exited: %v", err)
+// newNamespacePoolFromString creates a new namespace pool from a
+// comma-separated list of serialized and base64-encoded namespaces.
+func newNamespacePoolFromString(str string) (*namespace.NamespacePool, error) {
+ var namespaces []*namespace.Namespace
+ if len(str) > 0 {
+ for _, b64 := range strings.Split(str, ",") {
+ b, err := base64.StdEncoding.DecodeString(b64)
+ if err != nil {
+ return nil, fmt.Errorf("DecodeString: %v", err)
+ }
+ var namespace namespace.Namespace
+ if err := namespace.Unmarshal(b); err != nil {
+ return nil, fmt.Errorf("Unmarshal: %v", err)
+ }
+ namespaces = append(namespaces, &namespace)
+ }
}
+ pool, err := namespace.NewNamespacePool(namespaces)
+ if err != nil {
+ return nil, fmt.Errorf("NewNamespacePool: %v", err)
+ }
+ return pool, nil
+}
- glog.Flush()
+// await waits for a shutdown signal and then runs a clean-up function
+func await(ctx context.Context, done func()) {
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+ select {
+ case <-sigs:
+ case <-ctx.Done():
+ }
+ glog.V(3).Info("received shutdown signal")
+ done()
}