aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2022-05-24 23:33:38 +0200
committerRasmus Dahlberg <rasmus@mullvad.net>2022-06-23 11:33:17 +0200
commit559bccccd40d028e412d9f11709ded0250ba6dcd (patch)
tree50f3193dbe70fec21357963c11e5f663013f4b4c /cmd
parent4b20ef0c1732bcef633c0ed7104501898aa84e2c (diff)
implement primary and secondary role, for replicationv0.5.0
Diffstat (limited to 'cmd')
-rw-r--r--cmd/sigsum-log-primary/README.md (renamed from cmd/sigsum_log_go/README.md)18
-rw-r--r--cmd/sigsum-log-primary/main.go233
-rw-r--r--cmd/sigsum-log-secondary/main.go175
-rw-r--r--cmd/sigsum_log_go/.gitignore1
-rw-r--r--cmd/sigsum_log_go/main.go223
5 files changed, 416 insertions, 234 deletions
diff --git a/cmd/sigsum_log_go/README.md b/cmd/sigsum-log-primary/README.md
index 5c363f7..a824173 100644
--- a/cmd/sigsum_log_go/README.md
+++ b/cmd/sigsum-log-primary/README.md
@@ -1,11 +1,11 @@
-# Run Trillian + sigsum-log-go locally
+# Run Trillian + sigsum-log-primary locally
Trillian uses a database. So, we will need to set that up. It is documented
[here](https://github.com/google/trillian#mysql-setup), and how to check that it
is setup properly
[here](https://github.com/google/certificate-transparency-go/blob/master/trillian/docs/ManualDeployment.md#data-storage).
Other than the database we need Trillian log signer, Trillian log server, and
-sigsum-log-go. sigsum-log-go has been tested with trillian v.1.3.13.
+sigsum-log-primary. sigsum-log-primary has been tested with trillian v.1.3.13.
```
$ go install github.com/google/trillian/cmd/trillian_log_signer@v1.3.13
$ go install github.com/google/trillian/cmd/trillian_log_server@v1.3.13
@@ -30,25 +30,23 @@ $ createtree --admin_server localhost:6962
<tree id>
```
-Hang on to `<tree id>`. Our sigsum-log-go instance will use it when talking to
+Hang on to `<tree id>`. Our sigsum-log-primary instance will use it when talking to
the Trillian log server to specify which Merkle tree we are working against.
(If you take a look in the `Trees` table you will see that the tree has been
provisioned.)
-We will also need a public key-pair for sigsum-log-go.
+We will also need a public key-pair for sigsum-log-primary.
```
-$ go install git.sigsum.org/sigsum-log-go/cmd/tmp/keygen
-$ ./keygen
-sk: <sk>
-vk: <vk>
+$ go install git.sigsum.org/sigsum-go/cmd/sigsum-debug@latest
+$ sigsum-debug key private | tee sk | sigsum-debug key public > vk
```
-Start sigsum-log-go:
+Start sigsum-log-primary:
```
$ tree_id=<tree_id>
$ sk=<sk>
-$ sigsum_log_go --logtostderr -v 9 --http_endpoint localhost:6965 --log_rpc_server localhost:6962 --trillian_id $tree_id --key $sk
+$ sigsum-log-primary --logtostderr -v 9 --http_endpoint localhost:6965 --log_rpc_server localhost:6962 --trillian_id $tree_id --key <(echo sk)
```
Quick test:
diff --git a/cmd/sigsum-log-primary/main.go b/cmd/sigsum-log-primary/main.go
new file mode 100644
index 0000000..f64643a
--- /dev/null
+++ b/cmd/sigsum-log-primary/main.go
@@ -0,0 +1,233 @@
+// Package main provides a sigsum-log-primary binary
+package main
+
+import (
+ "context"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "os/signal"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/google/trillian"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "google.golang.org/grpc"
+
+ "git.sigsum.org/log-go/internal/db"
+ "git.sigsum.org/log-go/internal/node/primary"
+ "git.sigsum.org/log-go/internal/state"
+ "git.sigsum.org/log-go/internal/utils"
+ "git.sigsum.org/sigsum-go/pkg/client"
+ "git.sigsum.org/sigsum-go/pkg/dns"
+ "git.sigsum.org/sigsum-go/pkg/log"
+ "git.sigsum.org/sigsum-go/pkg/merkle"
+ "git.sigsum.org/sigsum-go/pkg/types"
+)
+
+var (
+ externalEndpoint = flag.String("external-endpoint", "localhost:6965", "host:port specification of where sigsum-log-primary serves clients")
+ internalEndpoint = flag.String("internal-endpoint", "localhost:6967", "host:port specification of where sigsum-log-primary serves other log nodes")
+ rpcBackend = flag.String("trillian-rpc-server", "localhost:6962", "host:port specification of where Trillian serves clients")
+ prefix = flag.String("url-prefix", "", "a prefix that precedes /sigsum/v0/<endpoint>")
+ trillianID = flag.Int64("tree-id", 0, "tree identifier in the Trillian database")
+ deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests")
+ key = flag.String("key", "", "path to file with hex-encoded Ed25519 private key")
+ witnesses = flag.String("witnesses", "", "comma-separated list of trusted witness public keys in hex")
+ maxRange = flag.Int64("max-range", 10, "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")
+ shardStart = flag.Int64("shard-interval-start", 0, "start of shard interval since the UNIX epoch in seconds")
+ testMode = flag.Bool("test-mode", false, "run in test mode (Default: false)")
+ logFile = flag.String("log-file", "", "file to write logs to (Default: stderr)")
+ logLevel = flag.String("log-level", "info", "log level (Available options: debug, info, warning, error. Default: info)")
+ logColor = flag.Bool("log-color", false, "colored logging output (Default: false)")
+ secondaryURL = flag.String("secondary-url", "", "secondary node endpoint for fetching latest replicated tree head")
+ secondaryPubkey = flag.String("secondary-pubkey", "", "hex-encoded Ed25519 public key for secondary node")
+
+ gitCommit = "unknown"
+)
+
+func main() {
+ flag.Parse()
+
+ if err := utils.SetupLogging(*logFile, *logLevel, *logColor); err != nil {
+ log.Fatal("setup logging: %v", err)
+ }
+ log.Info("log-go git-commit %s", gitCommit)
+
+ // wait for clean-up before exit
+ var wg sync.WaitGroup
+ defer wg.Wait()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ log.Debug("configuring log-go-primary")
+ node, err := setupPrimaryFromFlags()
+ if err != nil {
+ log.Fatal("setup primary: %v", err)
+ }
+
+ log.Debug("starting primary state manager routine")
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ node.Stateman.Run(ctx)
+ log.Debug("state manager shutdown")
+ cancel() // must have state manager running
+ }()
+
+ server := &http.Server{Addr: *externalEndpoint, Handler: node.PublicHTTPMux}
+ intserver := &http.Server{Addr: *internalEndpoint, Handler: node.InternalHTTPMux}
+ log.Debug("starting await routine")
+ go await(ctx, func() {
+ wg.Add(1)
+ defer wg.Done()
+ ctxInner, _ := context.WithTimeout(ctx, time.Second*60)
+ log.Info("stopping http server, please wait...")
+ server.Shutdown(ctxInner)
+ log.Info("... done")
+ log.Info("stopping internal api server, please wait...")
+ intserver.Shutdown(ctxInner)
+ log.Info("... done")
+ log.Info("stopping go routines, please wait...")
+ cancel()
+ log.Info("... done")
+ })
+
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ log.Info("serving log nodes on %v/%v", *internalEndpoint, *prefix)
+ if err = intserver.ListenAndServe(); err != http.ErrServerClosed {
+ log.Error("serve(intserver): %v", err)
+ }
+ log.Debug("internal endpoints server shut down")
+ cancel()
+ }()
+
+ log.Info("serving clients on %v/%v", *externalEndpoint, *prefix)
+ if err = server.ListenAndServe(); err != http.ErrServerClosed {
+ log.Error("serve(server): %v", err)
+ }
+
+}
+
+// setupPrimaryFromFlags() sets up a new sigsum primary node from flags.
+func setupPrimaryFromFlags() (*primary.Primary, error) {
+ var p primary.Primary
+ var err error
+
+ // Setup logging configuration.
+ p.Signer, p.Config.LogID, err = utils.NewLogIdentity(*key)
+ if err != nil {
+ return nil, fmt.Errorf("newLogIdentity: %v", err)
+ }
+
+ p.Config.TreeID = *trillianID
+ p.Config.Prefix = *prefix
+ p.Config.MaxRange = *maxRange
+ p.Config.Deadline = *deadline
+ p.Config.Interval = *interval
+ p.Config.ShardStart = uint64(*shardStart)
+ if *shardStart < 0 {
+ return nil, fmt.Errorf("shard start must be larger than zero")
+ }
+ p.Config.Witnesses, err = newWitnessMap(*witnesses)
+ if err != nil {
+ return nil, fmt.Errorf("newWitnessMap: %v", err)
+ }
+
+ // Setup trillian client.
+ dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(p.Config.Deadline)}
+ conn, err := grpc.Dial(*rpcBackend, dialOpts...)
+ if err != nil {
+ return nil, fmt.Errorf("Dial: %v", err)
+ }
+ p.TrillianClient = &db.TrillianClient{
+ TreeID: p.TreeID,
+ GRPC: trillian.NewTrillianLogClient(conn),
+ }
+
+ // Setup secondary node configuration.
+ if *secondaryURL != "" && *secondaryPubkey != "" {
+ pubkey, err := utils.PubkeyFromHexString(*secondaryPubkey)
+ if err != nil {
+ return nil, fmt.Errorf("invalid secondary node pubkey: %v", err)
+ }
+ p.Secondary = client.New(client.Config{
+ LogURL: *secondaryURL,
+ LogPub: *pubkey,
+ })
+ } else {
+ p.Secondary = client.New(client.Config{})
+ }
+
+ // Setup state manager.
+ p.Stateman, err = state.NewStateManagerSingle(p.TrillianClient, p.Signer, p.Config.Interval, p.Config.Deadline, p.Secondary)
+ if err != nil {
+ return nil, fmt.Errorf("NewStateManagerSingle: %v", err)
+ }
+ if *testMode == false {
+ p.DNS = dns.NewDefaultResolver()
+ } else {
+ p.DNS = dns.NewDummyResolver()
+ }
+
+ // TODO: verify that GRPC.TreeType() == LOG.
+
+ // Register HTTP endpoints.
+ mux := http.NewServeMux()
+ for _, h := range p.PublicHTTPHandlers() {
+ log.Debug("adding external handler: %s", h.Path())
+ mux.Handle(h.Path(), h)
+ }
+ p.PublicHTTPMux = mux
+
+ mux = http.NewServeMux()
+ for _, h := range p.InternalHTTPHandlers() {
+ log.Debug("adding internal handler: %s", h.Path())
+ mux.Handle(h.Path(), h)
+ }
+ p.InternalHTTPMux = mux
+
+ log.Debug("adding prometheus handler to internal mux, on path: /metrics")
+ http.Handle("/metrics", promhttp.Handler())
+
+ return &p, nil
+}
+
+// newWitnessMap creates a new map of trusted witnesses
+func newWitnessMap(witnesses string) (map[merkle.Hash]types.PublicKey, error) {
+ w := make(map[merkle.Hash]types.PublicKey)
+ if len(witnesses) > 0 {
+ for _, witness := range strings.Split(witnesses, ",") {
+ b, err := hex.DecodeString(witness)
+ if err != nil {
+ return nil, fmt.Errorf("DecodeString: %v", err)
+ }
+
+ var vk types.PublicKey
+ if n := copy(vk[:], b); n != types.PublicKeySize {
+ return nil, fmt.Errorf("Invalid public key size: %v", n)
+ }
+ w[*merkle.HashFn(vk[:])] = vk
+ }
+ }
+ return w, nil
+}
+
+// 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():
+ }
+ log.Debug("received shutdown signal")
+ done()
+}
diff --git a/cmd/sigsum-log-secondary/main.go b/cmd/sigsum-log-secondary/main.go
new file mode 100644
index 0000000..7306d4c
--- /dev/null
+++ b/cmd/sigsum-log-secondary/main.go
@@ -0,0 +1,175 @@
+// Package main provides a sigsum-log-secondary binary
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/google/trillian"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "google.golang.org/grpc"
+
+ "git.sigsum.org/log-go/internal/db"
+ "git.sigsum.org/log-go/internal/node/secondary"
+ "git.sigsum.org/log-go/internal/utils"
+ "git.sigsum.org/sigsum-go/pkg/client"
+ "git.sigsum.org/sigsum-go/pkg/log"
+)
+
+var (
+ externalEndpoint = flag.String("external-endpoint", "localhost:6965", "host:port specification of where sigsum-log-secondary serves clients")
+ internalEndpoint = flag.String("internal-endpoint", "localhost:6967", "host:port specification of where sigsum-log-secondary serves other log nodes")
+ rpcBackend = flag.String("trillian-rpc-server", "localhost:6962", "host:port specification of where Trillian serves clients")
+ prefix = flag.String("url-prefix", "", "a prefix that proceeds /sigsum/v0/<endpoint>")
+ trillianID = flag.Int64("tree-id", 0, "log identifier in the Trillian database")
+ deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests")
+ key = flag.String("key", "", "path to file with hex-encoded Ed25519 private key")
+ interval = flag.Duration("interval", time.Second*30, "interval used to rotate the node's STH")
+ testMode = flag.Bool("test-mode", false, "run in test mode (Default: false)")
+ logFile = flag.String("log-file", "", "file to write logs to (Default: stderr)")
+ logLevel = flag.String("log-level", "info", "log level (Available options: debug, info, warning, error. Default: info)")
+ logColor = flag.Bool("log-color", false, "colored logging output (Default: false)")
+ primaryURL = flag.String("primary-url", "", "primary node endpoint for fetching leaves")
+ primaryPubkey = flag.String("primary-pubkey", "", "hex-encoded Ed25519 public key for primary node")
+
+ gitCommit = "unknown"
+)
+
+func main() {
+ flag.Parse()
+
+ if err := utils.SetupLogging(*logFile, *logLevel, *logColor); err != nil {
+ log.Fatal("setup logging: %v", err)
+ }
+ log.Info("log-go git-commit %s", gitCommit)
+
+ // wait for clean-up before exit
+ var wg sync.WaitGroup
+ defer wg.Wait()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ log.Debug("configuring log-go-secondary")
+ node, err := setupSecondaryFromFlags()
+ if err != nil {
+ log.Fatal("setup secondary: %v", err)
+ }
+
+ log.Debug("starting periodic routine")
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ node.Run(ctx)
+ log.Debug("periodic routine shutdown")
+ cancel() // must have periodic running
+ }()
+
+ server := &http.Server{Addr: *externalEndpoint, Handler: node.PublicHTTPMux}
+ intserver := &http.Server{Addr: *internalEndpoint, Handler: node.InternalHTTPMux}
+ log.Debug("starting await routine")
+ go await(ctx, func() {
+ wg.Add(1)
+ defer wg.Done()
+ ctxInner, _ := context.WithTimeout(ctx, time.Second*60)
+ log.Info("stopping http server, please wait...")
+ server.Shutdown(ctxInner)
+ log.Info("... done")
+ log.Info("stopping internal api server, please wait...")
+ intserver.Shutdown(ctxInner)
+ log.Info("... done")
+ log.Info("stopping go routines, please wait...")
+ cancel()
+ log.Info("... done")
+ })
+
+ go func() {
+ wg.Add(1)
+ defer wg.Done()
+ log.Info("serving log nodes on %v/%v", *internalEndpoint, *prefix)
+ if err = intserver.ListenAndServe(); err != http.ErrServerClosed {
+ log.Error("serve(intserver): %v", err)
+ }
+ log.Debug("internal endpoints server shut down")
+ cancel()
+ }()
+
+ log.Info("serving clients on %v/%v", *externalEndpoint, *prefix)
+ if err = server.ListenAndServe(); err != http.ErrServerClosed {
+ log.Error("serve(server): %v", err)
+ }
+
+}
+
+// setupSecondaryFromFlags() sets up a new sigsum secondary node from flags.
+func setupSecondaryFromFlags() (*secondary.Secondary, error) {
+ var s secondary.Secondary
+ var err error
+
+ // Setup logging configuration.
+ s.Signer, s.Config.LogID, err = utils.NewLogIdentity(*key)
+ if err != nil {
+ return nil, fmt.Errorf("newLogIdentity: %v", err)
+ }
+ s.Config.TreeID = *trillianID
+ s.Config.Prefix = *prefix
+ s.Config.Deadline = *deadline
+ s.Config.Interval = *interval
+
+ // Setup trillian client.
+ dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(s.Config.Deadline)}
+ conn, err := grpc.Dial(*rpcBackend, dialOpts...)
+ if err != nil {
+ return nil, fmt.Errorf("Dial: %v", err)
+ }
+ s.TrillianClient = &db.TrillianClient{
+ TreeID: s.TreeID,
+ GRPC: trillian.NewTrillianLogClient(conn),
+ }
+
+ // Setup primary node configuration.
+ pubkey, err := utils.PubkeyFromHexString(*primaryPubkey)
+ if err != nil {
+ return nil, fmt.Errorf("invalid primary node pubkey: %v", err)
+ }
+ s.Primary = client.New(client.Config{
+ LogURL: *primaryURL,
+ LogPub: *pubkey,
+ })
+
+ // TODO: verify that GRPC.TreeType() == PREORDERED_LOG.
+
+ // Register HTTP endpoints.
+ mux := http.NewServeMux()
+ s.PublicHTTPMux = mux // No external endpoints but we want to return 404.
+
+ mux = http.NewServeMux()
+ for _, h := range s.InternalHTTPHandlers() {
+ log.Debug("adding internal handler: %s", h.Path())
+ mux.Handle(h.Path(), h)
+ }
+ s.InternalHTTPMux = mux
+
+ log.Debug("adding prometheus handler to internal mux, on path: /metrics")
+ http.Handle("/metrics", promhttp.Handler())
+
+ return &s, nil
+}
+
+// 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():
+ }
+ log.Debug("received shutdown signal")
+ done()
+}
diff --git a/cmd/sigsum_log_go/.gitignore b/cmd/sigsum_log_go/.gitignore
deleted file mode 100644
index 254defd..0000000
--- a/cmd/sigsum_log_go/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-server
diff --git a/cmd/sigsum_log_go/main.go b/cmd/sigsum_log_go/main.go
deleted file mode 100644
index c8e1692..0000000
--- a/cmd/sigsum_log_go/main.go
+++ /dev/null
@@ -1,223 +0,0 @@
-// Package main provides a sigsum-log-go binary
-package main
-
-import (
- "context"
- "crypto"
- "crypto/ed25519"
- "encoding/hex"
- "flag"
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
- "os/signal"
- "strings"
- "sync"
- "syscall"
- "time"
-
- "github.com/google/trillian"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- "google.golang.org/grpc"
-
- "git.sigsum.org/sigsum-go/pkg/log"
- "git.sigsum.org/sigsum-go/pkg/types"
- "git.sigsum.org/sigsum-go/pkg/dns"
- "git.sigsum.org/log-go/pkg/db"
- "git.sigsum.org/log-go/pkg/instance"
- "git.sigsum.org/log-go/pkg/state"
-)
-
-var (
- httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where sigsum-log-go serves clients")
- rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients")
- prefix = flag.String("prefix", "", "a prefix that proceeds /sigsum/v0/<endpoint>")
- trillianID = flag.Int64("trillian_id", 0, "log identifier in the Trillian database")
- deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests")
- key = flag.String("key", "", "path to file with hex-encoded Ed25519 private key")
- witnesses = flag.String("witnesses", "", "comma-separated list of trusted witness public keys in hex")
- maxRange = flag.Int64("max_range", 10, "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")
- shardStart = flag.Int64("shard_interval_start", 0, "start of shard interval since the UNIX epoch in seconds")
- logFile = flag.String("log-file", "", "file to write logs to (Default: stderr)")
- logLevel = flag.String("log-level", "info", "log level (Available options: debug, info, warning, error. Default: info)")
- logColor = flag.Bool("log-color", false, "colored logging output (Default: off)")
-
- gitCommit = "unknown"
-)
-
-func main() {
- flag.Parse()
-
- if err := setupLogging(*logFile, *logLevel, *logColor); err != nil {
- log.Fatal("setup logging: %v", err)
- }
- log.Info("log-go git-commit %s", gitCommit)
-
- // wait for clean-up before exit
- var wg sync.WaitGroup
- defer wg.Wait()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- log.Debug("configuring log-go instance")
- instance, err := setupInstanceFromFlags()
- if err != nil {
- log.Fatal("setup instance: %v", err)
- }
-
- log.Debug("starting state manager routine")
- go func() {
- wg.Add(1)
- defer wg.Done()
- instance.Stateman.Run(ctx)
- log.Debug("state manager shutdown")
- cancel() // must have state manager running
- }()
-
- log.Debug("starting await routine")
- server := http.Server{Addr: *httpEndpoint}
- go await(ctx, func() {
- wg.Add(1)
- defer wg.Done()
- ctxInner, _ := context.WithTimeout(ctx, time.Second*60)
- log.Info("stopping http server, please wait...")
- server.Shutdown(ctxInner)
- log.Info("stopping go routines, please wait...")
- cancel()
- })
-
- log.Info("serving on %v/%v", *httpEndpoint, *prefix)
- if err = server.ListenAndServe(); err != http.ErrServerClosed {
- log.Error("serve: %v", err)
- }
-}
-
-func setupLogging(logFile, logLevel string, logColor bool) error {
- if len(logFile) != 0 {
- f, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
- if err != nil {
- return err
- }
- log.SetOutput(f)
- }
-
- switch logLevel {
- case "debug":
- log.SetLevel(log.DebugLevel)
- case "info":
- log.SetLevel(log.InfoLevel)
- case "warning":
- log.SetLevel(log.WarningLevel)
- case "error":
- log.SetLevel(log.ErrorLevel)
- default:
- return fmt.Errorf("invalid logging level %s", logLevel)
- }
-
- log.SetColor(logColor)
- return nil
-}
-
-// SetupInstance sets up a new sigsum-log-go instance from flags
-func setupInstanceFromFlags() (*instance.Instance, error) {
- var i instance.Instance
- var err error
-
- // Setup log configuration
- i.Signer, i.LogID, err = newLogIdentity(*key)
- if err != nil {
- return nil, fmt.Errorf("newLogIdentity: %v", err)
- }
- i.TreeID = *trillianID
- i.Prefix = *prefix
- i.MaxRange = *maxRange
- i.Deadline = *deadline
- i.Interval = *interval
- i.ShardStart = uint64(*shardStart)
- if *shardStart < 0 {
- return nil, fmt.Errorf("shard start must be larger than zero")
- }
- i.Witnesses, err = newWitnessMap(*witnesses)
- if err != nil {
- return nil, fmt.Errorf("newWitnessMap: %v", err)
- }
-
- // Setup log client
- dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(i.Deadline)}
- conn, err := grpc.Dial(*rpcBackend, dialOpts...)
- if err != nil {
- return nil, fmt.Errorf("Dial: %v", err)
- }
- i.Client = &db.TrillianClient{
- TreeID: i.TreeID,
- GRPC: trillian.NewTrillianLogClient(conn),
- }
-
- // Setup state manager
- i.Stateman, err = state.NewStateManagerSingle(i.Client, i.Signer, i.Interval, i.Deadline)
- if err != nil {
- return nil, fmt.Errorf("NewStateManagerSingle: %v", err)
- }
-
- // Setup DNS verifier
- i.DNS = dns.NewDefaultResolver()
-
- // Register HTTP endpoints
- mux := http.NewServeMux()
- http.Handle("/", mux)
- for _, handler := range i.Handlers() {
- log.Debug("adding handler: %s", handler.Path())
- mux.Handle(handler.Path(), handler)
- }
- log.Debug("adding prometheus handler on path: /metrics")
- http.Handle("/metrics", promhttp.Handler())
-
- return &i, nil
-}
-
-func newLogIdentity(keyFile string) (crypto.Signer, string, error) {
- buf, err := ioutil.ReadFile(keyFile)
- if err != nil {
- return nil, "", err
- }
- if buf, err = hex.DecodeString(strings.TrimSpace(string(buf))); err != nil {
- return nil, "", fmt.Errorf("DecodeString: %v", err)
- }
- sk := crypto.Signer(ed25519.NewKeyFromSeed(buf))
- vk := sk.Public().(ed25519.PublicKey)
- return sk, hex.EncodeToString([]byte(vk[:])), nil
-}
-
-// newWitnessMap creates a new map of trusted witnesses
-func newWitnessMap(witnesses string) (map[types.Hash]types.PublicKey, error) {
- w := make(map[types.Hash]types.PublicKey)
- if len(witnesses) > 0 {
- for _, witness := range strings.Split(witnesses, ",") {
- b, err := hex.DecodeString(witness)
- if err != nil {
- return nil, fmt.Errorf("DecodeString: %v", err)
- }
-
- var vk types.PublicKey
- if n := copy(vk[:], b); n != types.PublicKeySize {
- return nil, fmt.Errorf("Invalid public key size: %v", n)
- }
- w[*types.HashFn(vk[:])] = vk
- }
- }
- return w, nil
-}
-
-// 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():
- }
- log.Debug("received shutdown signal")
- done()
-}