diff --git a/.gitignore b/.gitignore index 84ea2e1aa..77de4f2fd 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ coverage.txt *.tfstate* *terraform.tfvars* .golangci.yml +config.yml diff --git a/client/config.go b/client/config.go index 98e38926c..52c11ded3 100644 --- a/client/config.go +++ b/client/config.go @@ -25,12 +25,24 @@ type Config struct { // Enable self-signed certificates, allowing MiTM vector attacks. Insecure bool + + // Seconds to wait for an established connection. + TimeoutSeconds int + + // Seconds to wait for the connection to be established. + DialTimeoutSeconds int + + // Seconds to wait for a handshake negotiation. + HandshakeTimeoutSeconds int } func DefaultConfig() *Config { return &Config{ - Endpoint: "localhost:8080", - APIKey: "my-key", - Insecure: true, + Endpoint: "localhost:8080", + APIKey: "my-key", + Insecure: true, + TimeoutSeconds: 10, + DialTimeoutSeconds: 5, + HandshakeTimeoutSeconds: 5, } } diff --git a/cmd/agent.go b/cmd/agent.go index ec7f83fb5..90f2aa30d 100644 --- a/cmd/agent.go +++ b/cmd/agent.go @@ -17,8 +17,10 @@ package cmd import ( - "github.com/bbva/qed/gossip" "github.com/spf13/cobra" + v "github.com/spf13/viper" + + "github.com/bbva/qed/gossip" ) func newAgentCommand(cmdCtx *cmdContext) *cobra.Command { @@ -28,27 +30,41 @@ func newAgentCommand(cmdCtx *cmdContext) *cobra.Command { cmd := &cobra.Command{ Use: "agent", Short: "Start a gossip agent for the verifiable log QED", - Long: ``, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - config.EnableCompression = true - }, - TraverseChildren: true, } - cmd.PersistentFlags().StringVar(&config.NodeName, "node", "", "Unique name for node. If not set, fallback to hostname") - cmd.PersistentFlags().StringVar(&config.BindAddr, "bind", "", "Bind address for TCP/UDP gossip on (host:port)") - cmd.PersistentFlags().StringVar(&config.AdvertiseAddr, "advertise", "", "Address to advertise to cluster") - cmd.PersistentFlags().StringSliceVar(&config.StartJoin, "join", []string{}, "Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") - cmd.Flags().StringSliceVar(&config.AlertsUrls, "alertsUrls", []string{}, "Comma-delimited list of Alert servers ([host]:port), through which an agent can post alerts") + f := cmd.PersistentFlags() + f.StringVar(&config.NodeName, "node", "", "Unique name for node. If not set, fallback to hostname") + f.StringVar(&config.BindAddr, "bind", "", "Bind address for TCP/UDP gossip on (host:port)") + f.StringVar(&config.AdvertiseAddr, "advertise", "", "Address to advertise to cluster") + f.StringSliceVar(&config.StartJoin, "join", []string{}, "Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") + f.StringSliceVar(&config.AlertsUrls, "alertsUrls", []string{}, "Comma-delimited list of Alert servers ([host]:port), through which an agent can post alerts") + + agentPreRun := func(cmd *cobra.Command, args []string) { + config.EnableCompression = true + config.NodeName = v.GetString("agent.node") + config.BindAddr = v.GetString("agent.bind") + config.AdvertiseAddr = v.GetString("agent.advertise") + config.StartJoin = v.GetStringSlice("agent.join") + config.AlertsUrls = v.GetStringSlice("agent.alert_urls") + + markStringRequired(config.NodeName, "node") + markStringRequired(config.BindAddr, "bind") + markSliceStringRequired(config.StartJoin, "join") + markSliceStringRequired(config.AlertsUrls, "alertsUrls") + } - cmd.MarkPersistentFlagRequired("node") - cmd.MarkPersistentFlagRequired("bind") - cmd.MarkPersistentFlagRequired("join") - cmd.MarkFlagRequired("alertUrls") + cmd.AddCommand( + newAgentMonitorCommand(cmdCtx, config, agentPreRun), + newAgentAuditorCommand(cmdCtx, config, agentPreRun), + newAgentPublisherCommand(cmdCtx, config, agentPreRun), + ) - cmd.AddCommand(newAgentMonitorCommand(cmdCtx, config)) - cmd.AddCommand(newAgentAuditorCommand(cmdCtx, config)) - cmd.AddCommand(newAgentPublisherCommand(cmdCtx, config)) + // Lookups + v.BindPFlag("agent.node", f.Lookup("node")) + v.BindPFlag("agent.bind", f.Lookup("bind")) + v.BindPFlag("agent.advertise", f.Lookup("advertise")) + v.BindPFlag("agent.join", f.Lookup("join")) + v.BindPFlag("agent.alert_urls", f.Lookup("alertsUrls")) return cmd diff --git a/cmd/agent_auditor.go b/cmd/agent_auditor.go index a1faffb67..ffd0acb0c 100644 --- a/cmd/agent_auditor.go +++ b/cmd/agent_auditor.go @@ -14,15 +14,17 @@ package cmd import ( + "github.com/spf13/cobra" + v "github.com/spf13/viper" + "github.com/bbva/qed/gossip" "github.com/bbva/qed/gossip/auditor" "github.com/bbva/qed/gossip/member" "github.com/bbva/qed/log" "github.com/bbva/qed/util" - "github.com/spf13/cobra" ) -func newAgentAuditorCommand(ctx *cmdContext, config *gossip.Config) *cobra.Command { +func newAgentAuditorCommand(ctx *cmdContext, config *gossip.Config, agentPreRun func(*cobra.Command, []string)) *cobra.Command { auditorConfig := auditor.DefaultConfig() @@ -30,9 +32,22 @@ func newAgentAuditorCommand(ctx *cmdContext, config *gossip.Config) *cobra.Comma Use: "auditor", Short: "Start a QED auditor", Long: `Start a QED auditor that reacts to snapshot batches propagated by QED servers and periodically executes membership queries to verify the inclusion of events`, - Run: func(cmd *cobra.Command, args []string) { + PreRun: func(cmd *cobra.Command, args []string) { + + log.SetLogger("QEDAuditor", ctx.logLevel) - log.SetLogger("QedAuditor", ctx.logLevel) + // WARN: PersitentPreRun can't be nested and we're using it in cmd/root so inbetween preRuns + // must be curried. + agentPreRun(cmd, args) + + // Bindings + auditorConfig.QEDUrls = v.GetStringSlice("agent.server_urls") + auditorConfig.PubUrls = v.GetStringSlice("agent.publish_urls") + markSliceStringRequired(auditorConfig.QEDUrls, "qedUrls") + markSliceStringRequired(auditorConfig.PubUrls, "pubUrls") + + }, + Run: func(cmd *cobra.Command, args []string) { config.Role = member.Auditor auditorConfig.APIKey = ctx.apiKey @@ -58,10 +73,13 @@ func newAgentAuditorCommand(ctx *cmdContext, config *gossip.Config) *cobra.Comma }, } - cmd.Flags().StringSliceVarP(&auditorConfig.QEDUrls, "qedUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an auditor can make queries") - cmd.Flags().StringSliceVarP(&auditorConfig.PubUrls, "pubUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an auditor can make queries") - cmd.MarkFlagRequired("qedUrls") - cmd.MarkFlagRequired("pubUrls") + f := cmd.Flags() + f.StringSliceVarP(&auditorConfig.QEDUrls, "qedUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an auditor can make queries") + f.StringSliceVarP(&auditorConfig.PubUrls, "pubUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an auditor can make queries") + + // Lookups + v.BindPFlag("agent.server_urls", f.Lookup("qedUrls")) + v.BindPFlag("agent.publish_urls", f.Lookup("pubUrls")) return cmd } diff --git a/cmd/agent_monitor.go b/cmd/agent_monitor.go index 70028f295..c9f154cd3 100644 --- a/cmd/agent_monitor.go +++ b/cmd/agent_monitor.go @@ -14,26 +14,40 @@ package cmd import ( + "github.com/spf13/cobra" + v "github.com/spf13/viper" + "github.com/bbva/qed/gossip" "github.com/bbva/qed/gossip/member" "github.com/bbva/qed/gossip/monitor" "github.com/bbva/qed/log" "github.com/bbva/qed/util" - "github.com/spf13/cobra" ) -func newAgentMonitorCommand(ctx *cmdContext, config *gossip.Config) *cobra.Command { +func newAgentMonitorCommand(ctx *cmdContext, config *gossip.Config, agentPreRun func(*cobra.Command, []string)) *cobra.Command { monitorConfig := monitor.DefaultConfig() cmd := &cobra.Command{ Use: "monitor", Short: "Start a QED monitor", - Long: `Start a QED monitor that reacts to snapshot batches - propagated by QED servers and periodically executes incremental - queries to verify the consistency between snaphots`, + Long: `Start a QED monitor that reacts to snapshot batches propagated by QED servers and periodically executes incremental queries to verify the consistency between snaphots`, + PreRun: func(cmd *cobra.Command, args []string) { + + log.SetLogger("QEDMonitor", ctx.logLevel) + + // WARN: PersitentPreRun can't be nested and we're using it in cmd/root so inbetween preRuns + // must be curried. + agentPreRun(cmd, args) + + // Bindings + monitorConfig.QedUrls = v.GetStringSlice("agent.server_urls") + monitorConfig.PubUrls = v.GetStringSlice("agent.publish_urls") + markSliceStringRequired(monitorConfig.QedUrls, "qedUrls") + markSliceStringRequired(monitorConfig.PubUrls, "pubUrls") + + }, Run: func(cmd *cobra.Command, args []string) { - log.SetLogger("QedMonitor", ctx.logLevel) config.Role = member.Monitor monitorConfig.APIKey = ctx.apiKey @@ -60,10 +74,13 @@ func newAgentMonitorCommand(ctx *cmdContext, config *gossip.Config) *cobra.Comma }, } - cmd.Flags().StringSliceVarP(&monitorConfig.QedUrls, "qedUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which a monitor can make queries") - cmd.Flags().StringSliceVarP(&monitorConfig.PubUrls, "pubUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an monitor can publish alerts") - cmd.MarkFlagRequired("qedUrls") - cmd.MarkFlagRequired("pubUrls") + f := cmd.Flags() + f.StringSliceVarP(&monitorConfig.QedUrls, "qedUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which a monitor can make queries") + f.StringSliceVarP(&monitorConfig.PubUrls, "pubUrls", "", []string{}, "Comma-delimited list of QED servers ([host]:port), through which an monitor can publish alerts") + + // Lookups + v.BindPFlag("agent.server_urls", f.Lookup("qedUrls")) + v.BindPFlag("agent.publish_urls", f.Lookup("pubUrls")) return cmd } diff --git a/cmd/agent_publisher.go b/cmd/agent_publisher.go index 3dfb6f77d..d81a6575f 100644 --- a/cmd/agent_publisher.go +++ b/cmd/agent_publisher.go @@ -14,15 +14,17 @@ package cmd import ( + "github.com/spf13/cobra" + v "github.com/spf13/viper" + "github.com/bbva/qed/gossip" "github.com/bbva/qed/gossip/member" "github.com/bbva/qed/gossip/publisher" "github.com/bbva/qed/log" "github.com/bbva/qed/util" - "github.com/spf13/cobra" ) -func newAgentPublisherCommand(ctx *cmdContext, config *gossip.Config) *cobra.Command { +func newAgentPublisherCommand(ctx *cmdContext, config *gossip.Config, agentPreRun func(*cobra.Command, []string)) *cobra.Command { var endpoints []string @@ -30,9 +32,20 @@ func newAgentPublisherCommand(ctx *cmdContext, config *gossip.Config) *cobra.Com Use: "publisher", Short: "Start a QED publisher", Long: `Start a QED publisher that reacts to snapshot batches propagated by QED servers and periodically publishes them to a certain log storage.`, - Run: func(cmd *cobra.Command, args []string) { + PreRun: func(cmd *cobra.Command, args []string) { + + log.SetLogger("QEDPublisher", ctx.logLevel) - log.SetLogger("QedPublisher", ctx.logLevel) + // WARN: PersitentPreRun can't be nested and we're using it in + // cmd/root so inbetween preRuns must be curried. + agentPreRun(cmd, args) + + // Bindings + endpoints = v.GetStringSlice("agent.publish_urls") + markSliceStringRequired(endpoints, "pubUrls") + + }, + Run: func(cmd *cobra.Command, args []string) { config.Role = member.Publisher publisherConfig := publisher.NewConfig(endpoints) @@ -58,10 +71,12 @@ func newAgentPublisherCommand(ctx *cmdContext, config *gossip.Config) *cobra.Com }, } - cmd.Flags().StringSliceVarP(&endpoints, "endpoints", "", []string{}, + f := cmd.Flags() + f.StringSliceVarP(&endpoints, "pubUrls", "", []string{}, "Comma-delimited list of end-publishers ([host]:port), through which an publisher can send requests") - cmd.MarkFlagRequired("endpoints") + // Lookups + v.BindPFlag("agent.publish_urls", f.Lookup("pubUrls")) return cmd } diff --git a/cmd/client.go b/cmd/client.go index 4a05e590b..61aee5add 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -17,36 +17,59 @@ package cmd import ( + "fmt" + + "github.com/spf13/cobra" + v "github.com/spf13/viper" + "github.com/bbva/qed/client" "github.com/bbva/qed/log" - "github.com/spf13/cobra" ) func newClientCommand(ctx *cmdContext) *cobra.Command { clientCtx := &clientContext{} + clientCtx.config = client.DefaultConfig() cmd := &cobra.Command{ Use: "client", Short: "Client mode for qed", Long: `Client process for emitting events to a qed server`, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - log.SetLogger("QedClient", ctx.logLevel) - - clientCtx.client = client.NewHTTPClient(client.Config{ - Endpoint: clientCtx.endpoint, - APIKey: ctx.apiKey, - Insecure: clientCtx.insecure, - }) - }, - TraverseChildren: true, } - cmd.PersistentFlags().StringVarP(&clientCtx.endpoint, "endpoint", "e", "localhost:8080", "Endpoint for REST requests on (host:port)") - cmd.PersistentFlags().BoolVar(&clientCtx.insecure, "insecure", false, "Disable TLS transport") + f := cmd.PersistentFlags() + f.StringVarP(&clientCtx.config.Endpoint, "endpoint", "e", "127.0.0.1:8080", "Endpoint for REST requests on (host:port)") + f.BoolVar(&clientCtx.config.Insecure, "insecure", false, "Allow self signed certificates") + f.IntVar(&clientCtx.config.TimeoutSeconds, "timeout-seconds", 10, "Seconds to cut the connection") + f.IntVar(&clientCtx.config.DialTimeoutSeconds, "dial-timeout-seconds", 5, "Seconds to cut the dialing") + f.IntVar(&clientCtx.config.HandshakeTimeoutSeconds, "handshake-timeout-seconds", 5, "Seconds to cut the handshaking") + + // Lookups + v.BindPFlag("client.endpoint", f.Lookup("endpoint")) + v.BindPFlag("client.insecure", f.Lookup("insecure")) + v.BindPFlag("client.timeout.connection", f.Lookup("timeout-seconds")) + v.BindPFlag("client.timeout.dial", f.Lookup("dial-timeout-seconds")) + v.BindPFlag("client.timeout.handshake", f.Lookup("handshake-timeout-seconds")) + + clientPreRun := func(cmd *cobra.Command, args []string) { + fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>", "client.customprerun") + log.SetLogger("QEDClient", ctx.logLevel) + + clientCtx.config.APIKey = ctx.apiKey + clientCtx.config.Endpoint = v.GetString("client.endpoint") + clientCtx.config.Insecure = v.GetBool("client.insecure") + clientCtx.config.TimeoutSeconds = v.GetInt("client.timeout.connection") + clientCtx.config.DialTimeoutSeconds = v.GetInt("client.timeout.dial") + clientCtx.config.HandshakeTimeoutSeconds = v.GetInt("client.timeout.handshake") + + clientCtx.client = client.NewHTTPClient(*clientCtx.config) + + } - cmd.AddCommand(newAddCommand(clientCtx)) - cmd.AddCommand(newMembershipCommand(clientCtx)) - cmd.AddCommand(newIncrementalCommand(clientCtx)) + cmd.AddCommand( + newAddCommand(clientCtx, clientPreRun), + newMembershipCommand(clientCtx, clientPreRun), + newIncrementalCommand(clientCtx, clientPreRun), + ) return cmd } diff --git a/cmd/client_add.go b/cmd/client_add.go index 64cb9068e..d764fba75 100644 --- a/cmd/client_add.go +++ b/cmd/client_add.go @@ -22,7 +22,7 @@ import ( "github.com/bbva/qed/log" ) -func newAddCommand(ctx *clientContext) *cobra.Command { +func newAddCommand(ctx *clientContext, clientPreRun func(*cobra.Command, []string)) *cobra.Command { var key, value string @@ -30,6 +30,11 @@ func newAddCommand(ctx *clientContext) *cobra.Command { Use: "add", Short: "Add an event", Long: `Add an event to the authenticated data structure`, + PreRun: func(cmd *cobra.Command, args []string) { + // WARN: PersitentPreRun can't be nested and we're using it in + // cmd/root so inbetween preRuns must be curried. + clientPreRun(cmd, args) + }, RunE: func(cmd *cobra.Command, args []string) error { log.Infof("Adding key [ %s ] with value [ %s ]\n", key, value) diff --git a/cmd/client_incremental.go b/cmd/client_incremental.go index d9bcb127d..94ab07c21 100644 --- a/cmd/client_incremental.go +++ b/cmd/client_incremental.go @@ -27,7 +27,7 @@ import ( "github.com/bbva/qed/log" ) -func newIncrementalCommand(ctx *clientContext) *cobra.Command { +func newIncrementalCommand(ctx *clientContext, clientPreRun func(*cobra.Command, []string)) *cobra.Command { var start, end uint64 var verify bool @@ -39,6 +39,10 @@ func newIncrementalCommand(ctx *clientContext) *cobra.Command { Long: `Query for an incremental proof to the authenticated data structure. It also verifies the proofs provided by the server if flag enabled.`, PreRunE: func(cmd *cobra.Command, args []string) error { + // WARN: PersitentPreRun can't be nested and we're using it in + // cmd/root so inbetween preRuns must be curried. + clientPreRun(cmd, args) + if verify { if startDigest == "" { log.Errorf("Error: trying to verify proof without start digest") diff --git a/cmd/client_membership.go b/cmd/client_membership.go index dd51914d2..a17d6850d 100644 --- a/cmd/client_membership.go +++ b/cmd/client_membership.go @@ -26,7 +26,7 @@ import ( "github.com/bbva/qed/protocol" ) -func newMembershipCommand(ctx *clientContext) *cobra.Command { +func newMembershipCommand(ctx *clientContext, clientPreRun func(*cobra.Command, []string)) *cobra.Command { hasherF := hashing.NewSha256Hasher var version uint64 @@ -39,6 +39,10 @@ func newMembershipCommand(ctx *clientContext) *cobra.Command { Long: `Query for membership of an event to the authenticated data structure. It also verifies the proofs provided by the server if flag enabled.`, PreRunE: func(cmd *cobra.Command, args []string) error { + // WARN: PersitentPreRun can't be nested and we're using it in + // cmd/root so inbetween preRuns must be curried. + clientPreRun(cmd, args) + if key == "" && eventDigest == "" { log.Errorf("Error: trying to get membership without either key or eventDigest") } diff --git a/cmd/context.go b/cmd/context.go index 36c9abfc3..61313fec9 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -19,18 +19,31 @@ package cmd import ( "github.com/bbva/qed/client" "github.com/bbva/qed/gossip" + "github.com/bbva/qed/log" ) type cmdContext struct { - apiKey, logLevel string + apiKey, logLevel, configFile, path string + disableConfig bool } type clientContext struct { - endpoint string - insecure bool - client *client.HTTPClient + config *client.Config + client *client.HTTPClient } type agentContext struct { config *gossip.Config } + +func markStringRequired(value, name string) { + if value == "" { + log.Fatalf("Argument `%s` is required", name) + } +} + +func markSliceStringRequired(value []string, name string) { + if len(value) == 0 { + log.Fatalf("Argument `%s` is required", name) + } +} diff --git a/cmd/root.go b/cmd/root.go index 1f0d9fafa..2f88fd413 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,7 +18,12 @@ package cmd import ( + "fmt" + + "github.com/bbva/qed/log" + homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" + v "github.com/spf13/viper" ) // NewRootCommand is the main Parser for the qed cli. @@ -29,15 +34,60 @@ func NewRootCommand() *cobra.Command { Use: "qed", Short: "QED is a client for the verifiable log server", TraverseChildren: true, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>", "root.persistentprerun", ctx.path) + + if ctx.configFile != "" { + v.SetConfigFile(ctx.configFile) + } else { + v.SetConfigName("config") + v.AddConfigPath(ctx.path) + v.AddConfigPath(".") + } + + if !ctx.disableConfig { + // read in environment variables that match. + // ex: `QED_API_KEY=environ-key` + v.SetEnvPrefix("QED") + v.AutomaticEnv() + + err := v.ReadInConfig() + if _, ok := err.(v.ConfigFileNotFoundError); err != nil && !ok { + log.Error("Can't read config file.", err) + } + + // Runtime Binding + ctx.logLevel = v.GetString("log") + ctx.apiKey = v.GetString("api_key") + ctx.path, err = homedir.Expand(v.GetString("path")) + if err != nil { + log.Fatalf("Can't expand global path: %v", err) + } + + } + + markStringRequired(ctx.apiKey, "apikey") + + }, } - cmd.PersistentFlags().StringVarP(&ctx.logLevel, "log", "l", "error", "Choose between log levels: silent, error, info and debug") - cmd.PersistentFlags().StringVarP(&ctx.apiKey, "apikey", "k", "", "Server api key") - cmd.MarkPersistentFlagRequired("apikey") + f := cmd.PersistentFlags() + f.StringVarP(&ctx.configFile, "config-file", "c", "", "Qed config file") + f.BoolVarP(&ctx.disableConfig, "no-conf", "n", false, "Disable config file loading") + f.StringVarP(&ctx.logLevel, "log", "l", "error", "Choose between log levels: silent, error, info and debug") + f.StringVarP(&ctx.apiKey, "apikey", "k", "", "Server api key") + f.StringVarP(&ctx.path, "path", "p", "/var/tmp/qed", "Qed root path for storage configuration and credentials") + + // Lookups + v.BindPFlag("log", f.Lookup("log")) + v.BindPFlag("api_key", f.Lookup("apikey")) + v.BindPFlag("path", f.Lookup("path")) - cmd.AddCommand(newStartCommand(ctx)) - cmd.AddCommand(newClientCommand(ctx)) - cmd.AddCommand(newAgentCommand(ctx)) + cmd.AddCommand( + newStartCommand(ctx), + newClientCommand(ctx), + newAgentCommand(ctx), + ) return cmd } diff --git a/cmd/start.go b/cmd/start.go index 8799b3a97..c0ef2b2f8 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -19,35 +19,53 @@ package cmd import ( "fmt" "os" - "os/user" "github.com/spf13/cobra" + v "github.com/spf13/viper" "github.com/bbva/qed/log" "github.com/bbva/qed/server" ) func newStartCommand(ctx *cmdContext) *cobra.Command { - const defaultKeyPath = "~/.ssh/id_ed25519" - var disableTLS bool conf := server.DefaultConfig() cmd := &cobra.Command{ Use: "start", Short: "Start the server for the verifiable log QED", - Long: ``, - // Args: cobra.NoArgs(), - PersistentPreRun: func(cmd *cobra.Command, args []string) { - log.SetLogger("QedServer", ctx.logLevel) - }, Run: func(cmd *cobra.Command, args []string) { - conf.EnableTLS = !disableTLS - - if conf.PrivateKeyPath == defaultKeyPath { - usr, _ := user.Current() - conf.PrivateKeyPath = fmt.Sprintf("%s/.ssh/id_ed25519", usr.HomeDir) + fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>", "start.run", ctx.path) + var err error + + log.SetLogger("QEDServer", ctx.logLevel) + + // Bindings + conf.APIKey = ctx.apiKey + conf.NodeID = v.GetString("server.node-id") + conf.EnableProfiling = v.GetBool("server.profiling") + conf.PrivateKeyPath = v.GetString("server.key") + conf.SSLCertificate = v.GetString("server.tls.certificate") + conf.SSLCertificateKey = v.GetString("server.tls.certificate_key") + conf.HTTPAddr = v.GetString("server.addr.http") + conf.RaftAddr = v.GetString("server.addr.raft") + conf.MgmtAddr = v.GetString("server.addr.mgmt") + conf.RaftJoinAddr = v.GetStringSlice("server.addr.join") + conf.GossipAddr = v.GetString("server.addr.gossip") + conf.GossipJoinAddr = v.GetStringSlice("server.addr.gossip_join") + conf.DBPath = fmt.Sprintf("%s/%s", ctx.path, "db") + conf.RaftPath = fmt.Sprintf("%s/%s", ctx.path, "wal") + + if conf.SSLCertificate != "" && conf.SSLCertificateKey != "" { + if _, err := os.Stat(conf.SSLCertificate); os.IsNotExist(err) { + log.Fatalf("Can't find certificate .crt file: %v", err) + } else if _, err := os.Stat(conf.SSLCertificateKey); os.IsNotExist(err) { + log.Fatalf("Can't find certificate .key file: %v", err) + } else { + conf.EnableTLS = true + } } + // cmd.DisableSuggestions = true srv, err := server.NewServer(conf) if err != nil { log.Fatalf("Can't start QED server: %v", err) @@ -61,23 +79,41 @@ func newStartCommand(ctx *cmdContext) *cobra.Command { }, } + f := cmd.Flags() hostname, _ := os.Hostname() - cmd.Flags().StringVar(&conf.NodeID, "node-id", hostname, "Unique name for node. If not set, fallback to hostname") - cmd.Flags().StringVar(&conf.HTTPAddr, "http-addr", ":8080", "Endpoint for REST requests on (host:port)") - cmd.Flags().StringVar(&conf.RaftAddr, "raft-addr", ":9000", "Raft bind address (host:port)") - cmd.Flags().StringVar(&conf.MgmtAddr, "mgmt-addr", ":8090", "Management endpoint bind address (host:port)") - cmd.Flags().StringSliceVar(&conf.RaftJoinAddr, "join-addr", []string{}, "Raft: Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") - cmd.Flags().StringVar(&conf.GossipAddr, "gossip-addr", ":9100", "Gossip: management endpoint bind address (host:port)") - cmd.Flags().StringSliceVar(&conf.GossipJoinAddr, "gossip-join-addr", []string{}, "Gossip: Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") - cmd.Flags().StringVarP(&conf.DBPath, "dbpath", "p", "/var/tmp/qed/data", "Set default storage path") - cmd.Flags().StringVar(&conf.RaftPath, "raftpath", "/var/tmp/qed/raft", "Set raft storage path") - cmd.Flags().StringVarP(&conf.PrivateKeyPath, "keypath", "y", defaultKeyPath, "Path to the ed25519 key file") - cmd.Flags().BoolVarP(&conf.EnableProfiling, "profiling", "f", false, "Allow a pprof url (localhost:6060) for profiling purposes") - cmd.Flags().BoolVar(&disableTLS, "insecure", false, "Disable TLS service") + f.StringVar(&conf.NodeID, "node-id", hostname, "Unique name for node. If not set, fallback to hostname") + f.BoolVarP(&conf.EnableProfiling, "profiling", "f", false, "Allow a pprof url (localhost:6060) for profiling purposes") + f.StringVar(&conf.PrivateKeyPath, "keypath", fmt.Sprintf("%s/%s", ctx.path, "id_ed25519"), "Server Singning private key file path") + f.StringVar(&conf.SSLCertificate, "certificate", fmt.Sprintf("%s/%s", ctx.path, "server.crt"), "Server crt file") + f.StringVar(&conf.SSLCertificateKey, "certificate-key", fmt.Sprintf("%s/%s", ctx.path, "server.key"), "Server key file") + + f.StringVar(&conf.HTTPAddr, "http-addr", ":8080", "Endpoint for REST requests on (host:port)") + f.StringVar(&conf.RaftAddr, "raft-addr", "9000", "Raft bind address (host:port)") + f.StringVar(&conf.MgmtAddr, "mgmt-addr", "8090", "Management endpoint bind address (host:port)") + f.StringSliceVar(&conf.RaftJoinAddr, "join-addr", []string{}, "Raft: Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") + f.StringVar(&conf.GossipAddr, "gossip-addr", ":9100", "Gossip: management endpoint bind address (host:port)") + f.StringSliceVar(&conf.GossipJoinAddr, "gossip-join-addr", []string{}, "Gossip: Comma-delimited list of nodes ([host]:port), through which a cluster can be joined") // INFO: testing purposes - cmd.Flags().BoolVar(&conf.EnableTampering, "tampering", false, "Allow tampering api for proof demostrations") - cmd.Flags().MarkHidden("tampering") // nolint: errcheck + f.BoolVar(&conf.EnableTampering, "tampering", false, "Allow tampering api for proof demostrations") + f.MarkHidden("tampering") + + // Lookups + v.BindPFlag("server.node-id", f.Lookup("node-id")) + v.BindPFlag("server.profiling", f.Lookup("profiling")) + v.BindPFlag("server.key", f.Lookup("keypath")) + v.BindPFlag("server.tls.certificate", f.Lookup("certificate")) + v.BindPFlag("server.tls.certificate_key", f.Lookup("certificate-key")) + + v.BindPFlag("server.addr.http", f.Lookup("http-addr")) + v.BindPFlag("server.addr.raft", f.Lookup("raft-addr")) + v.BindPFlag("server.addr.mgmt", f.Lookup("mgmt-addr")) + v.BindPFlag("server.addr.join", f.Lookup("join-addr")) + v.BindPFlag("server.addr.gossip", f.Lookup("gossip-addr")) + v.BindPFlag("server.addr.gossip_join", f.Lookup("gossip-join-addr")) + + v.BindPFlag("server.path.db", f.Lookup("dbpath")) + v.BindPFlag("server.path.wal", f.Lookup("raftpath")) return cmd } diff --git a/config.example.yml b/config.example.yml new file mode 100644 index 000000000..65aa6c96e --- /dev/null +++ b/config.example.yml @@ -0,0 +1,75 @@ +--- +# Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################################################### +# Example configuration file for teaching porpouses +############################################################################### + + +log: error # Choose between log levels: silent, error, info and debug. +api_key: "my-key" # The application namespace used in all the nodes. + +############################################################################### +# Server Configuration (where it collect and processes events). +############################################################################### +server: + node_id: "hostname" # Unique name for node. If not set, fallback to hostname. + profiling: false # Allow a pprof url (localhost:6060) for profiling purposes. + key: "~/.ssh/id_ed25519" # Path to the ed25519 key file. + tls: + certificate: "~/.ssh/server.crt" # Server certificate file + certificate_key: "~/.ssh/server.key" # Server certificate key file + addr: + http: ":8080" # Endpoint for REST requests on (host:port). + mgmt: ":8090" # Management endpoint bind address (host:port). + raft: ":9000" # Raft bind address (host:port). + join: # Raft: list of nodes ([host]:port), through which a cluster can be joined. + - "127.0.0.1:9000" + gossip: "9100" # Gossip: management endpoint bind address (host:port). + gossip_join: # Gossip: list of nodes ([host]:port), through which a cluster can be joined. + - "127.0.0.0.1:9100" + path: + db: "/var/tmp/qed/data" # Set default storage path. + wal: "/var/tmp/qed/raft" # Set raft storage path. + + +############################################################################### +# Cient Configuration (cli commands `add` `incremental` and `verify`) +############################################################################### +client: + endpoint: "127.0.0.1:8080" # Endpoint for REST requests on (host:port) + insecure: false # Allow self signed certificates + timeout: + connection: 10 # time in seconds to cut the ongoing connection + dial: 5 # time in seconds to cut the dialing of the connection + handshake: 5 # time in seconds to cut the handshakeing of the connection + + +############################################################################### +# Agent Configuration +############################################################################### +agent: + node: "nodeName" # Unique name for node. If not set, fallback to hostname + bind: ":9200" # Bind address for TCP/UDP gossip on (host:port) + advertise: "" # Address to advertise to cluster + join: # Comma-delimited list of nodes ([host]:port), through which a cluster can be joined + - "127.0.0.1:9100" + alert_urls: # List of Alert servers ([host]:port), through which an agent can post alerts + - "127.0.0.1:8888" + server_urls: # List of QED servers ([host]:port), through which an auditor can make queries + - "127.0.0.1:8080" + snapshots_store_urls: # List of end-publishers ([host]:port), through which an agent can send signedSnapshots or alerts + - "127.0.0.1:8888"