From 195310282f88db88676b70d48ce60ef44541bf1d Mon Sep 17 00:00:00 2001 From: = Date: Wed, 8 Dec 2021 09:42:12 +0100 Subject: [PATCH 1/4] Add validation to config --- actions/serve.go | 23 ++--- config/config.go | 89 +++++++++++++++++- config/config_test.go | 209 ++++++++++++++++++++++++++++++++++++++++++ ezshare.example.toml | 7 +- store/store.go | 6 ++ 5 files changed, 313 insertions(+), 21 deletions(-) create mode 100644 config/config_test.go diff --git a/actions/serve.go b/actions/serve.go index 6e1dc1a..f7c1ebb 100644 --- a/actions/serve.go +++ b/actions/serve.go @@ -62,30 +62,23 @@ func ActionServe(c *cli.Context) error { defer fileCloseFunc() // Setup user store - userStore, userCloseFunc, err := cfg.Server.UserStoreConfig.GetStore() + dataStore, userCloseFunc, err := cfg.Server.DataStoreConfig.GetStore() if err != nil { return fmt.Errorf("unable to initialize user store: %w", err) } defer userCloseFunc() // Create initial admin-user if neccessary - if err := initializeUsers(userStore, serverLogger); err != nil { + if err := initializeUsers(dataStore, serverLogger); err != nil { return fmt.Errorf("error initializing store: %w", err) } - // Setup cert store - // TODO: User proper store - certStore := store.NewMemoryStore() - // Setup cert-service - certSvc, err := certs.NewCertService(certStore, caCertBytes, caKeyBytes) + certSvc, err := certs.NewCertService(dataStore, caCertBytes, caKeyBytes) if err != nil { return fmt.Errorf("error initializing certificate service: %w", err) } - // Setup binary store - binaryStore := store.NewMemoryStore() - // Setup shutdown-handling rootCtx, rootCancel := signal.NotifyContext(context.Background(), os.Interrupt) defer rootCancel() @@ -114,14 +107,14 @@ func ActionServe(c *cli.Context) error { } // Setup cert-service - certServiceServer := server.NewCertServiceServer(certSvc, certStore, userStore) + certServiceServer := server.NewCertServiceServer(certSvc, dataStore, dataStore) certServiceServer.Logger = certLogger // Setup user-service - grpcUserServer := server.NewGRPCUserServiceServer(userStore, certSvc) + grpcUserServer := server.NewGRPCUserServiceServer(dataStore, certSvc) grpcUserServer.Logger = logger.Named("USER") - binaryServer := server.NewBinaryServiceServer(binaryStore) + binaryServer := server.NewBinaryServiceServer(dataStore) binaryServer.Logger = binsLogger lis, err := net.Listen("tcp", grpcAddr) @@ -150,7 +143,7 @@ func ActionServe(c *cli.Context) error { grpc.MaxRecvMsgSize(100*1024*1024), grpc.MaxSendMsgSize(100*1024*1024), grpc.Creds(creds), - grpc.ChainUnaryInterceptor(interceptors.NewAuthInterceptor(userStore, certSvc, authLogger)), + grpc.ChainUnaryInterceptor(interceptors.NewAuthInterceptor(dataStore, certSvc, authLogger)), ) pb.RegisterFileServiceServer(grpcServer, grpcFileServer) pb.RegisterUserServiceServer(grpcServer, grpcUserServer) @@ -183,7 +176,7 @@ func ActionServe(c *cli.Context) error { if c.IsSet("http-addr") { httpAddr = c.String("http-addr") } - httpServer := server.NewHTTPSever(s, binaryStore, srvCertBytes, cfg.Server.GRPCEndpoint) + httpServer := server.NewHTTPSever(s, dataStore, srvCertBytes, cfg.Server.GRPCEndpoint) httpServer.Logger = httpLogger httpServer.Addr = httpAddr diff --git a/config/config.go b/config/config.go index b822995..37cd6bb 100644 --- a/config/config.go +++ b/config/config.go @@ -35,7 +35,7 @@ type ServerConfig struct { LogLevel string `toml:"LogLevel"` Hostname string `toml:"Hostname"` GRPCEndpoint string `toml:"GRPCEndpoint"` - UserStoreConfig *ServerUserStoreConfig `toml:"UserStore"` + DataStoreConfig *ServerDataStoreConfig `toml:"DataStore"` FileStoreConfig *ServerFileStoreConfig `toml:"FileStore"` GRPC *ServerGRPCConfig `toml:"GRPC"` HTTP *ServerHTTPConfig `toml:"HTTP"` @@ -47,7 +47,7 @@ type ServerFileStoreConfig struct { BoltStoreConfig *BoltStoreConfig `toml:"Bolt"` } -type ServerUserStoreConfig struct { +type ServerDataStoreConfig struct { Type string `toml:"Type"` BoltStoreConfig *BoltStoreConfig `toml:"Bolt"` } @@ -88,6 +88,8 @@ func FromDefault() *Config { HTTP: &ServerHTTPConfig{ ListenAddr: ":8089", }, + DataStoreConfig: &ServerDataStoreConfig{}, + FileStoreConfig: &ServerFileStoreConfig{}, }, Client: &ClientConfig{ Certs: &CertificatePaths{}, @@ -142,6 +144,87 @@ func FromDefaultLocations() (*Config, error) { return nil, fmt.Errorf("config not found") } +func (c *Config) ValidForServer() error { + // Verify that grpc-endpoint is set + if c.Server.GRPCEndpoint == "" { + return fmt.Errorf("missing require config-value Server.GRPCEndpoint") + } + + // Verify loglevel + switch strings.ToUpper(c.Server.LogLevel) { + case "DEBUG", "INFO", "WARN", "ERROR", "FATAL": + break + default: + return fmt.Errorf("config-value Server.LogLevel is invalid") + } + + // Verify datastore config + switch strings.ToLower(c.Server.DataStoreConfig.Type) { + case "memory": + break + case "bolt": + if c.Server.DataStoreConfig.BoltStoreConfig == nil || c.Server.DataStoreConfig.BoltStoreConfig.Path == "" { + return fmt.Errorf("server datastore is bolt, missing required config value Server.DataStore.Bolt.Path") + } + default: + return fmt.Errorf("config-value Server.DataStore.Type is invalid") + } + + // Verify filestore config + switch strings.ToLower(c.Server.FileStoreConfig.Type) { + case "memory": + break + case "filesystem": + if c.Server.FileStoreConfig.FSStoreConfig == nil || c.Server.FileStoreConfig.FSStoreConfig.Dir == "" { + return fmt.Errorf("server datastore is bolt, missing required config value Server.FileStore.FSStore.Path") + } + case "bolt": + if c.Server.FileStoreConfig.BoltStoreConfig == nil || c.Server.FileStoreConfig.BoltStoreConfig.Path == "" { + return fmt.Errorf("server datastore is bolt, missing required config value Server.DataStore.Bolt.Path") + } + } + + // Verify grpc-config + if c.Server.GRPC.ListenAddr == "" { + return fmt.Errorf("missing required config-value Server.GRPC.ListenAddr") + } + if c.Server.GRPC.CACerts.CertificateKeyPath == "" { + // TODO: Maybe return custom error, so we can create certs if missing + return fmt.Errorf("missing require value Server.GRPC.CACerts.CertificateKeyPath") + } + if c.Server.GRPC.CACerts.CertificatePath == "" { + // TODO: Maybe return custom error, so we can create certs if missing + return fmt.Errorf("missing require value Server.GRPC.CACerts.CertificatePath") + } + if c.Server.GRPC.Certs.CertificatePath == "" { + // TODO: Maybe return custom error, so we can create certs if missing + return fmt.Errorf("missing require value Server.GRPC.Certs.CertificatePath") + } + if c.Server.GRPC.Certs.CertificateKeyPath == "" { + // TODO: Maybe return custom error, so we can create certs if missing + return fmt.Errorf("missing require value Server.GRPC.Certs.CertificateKeyPath") + } + + return nil +} +func (c *Config) ValidForClient() error { + if c.Client.Certs.CertificateKeyPath == "" { + return fmt.Errorf("missing required value Client.Certs.CertificateKeyPath") + } + if c.Client.Certs.CertificatePath == "" { + return fmt.Errorf("missing required value Client.Certs.CertificatePath") + } + if c.Client.DefaultServer == "" { + // TODO: Should probably have its own custom error + return fmt.Errorf("missing required value Client.DefaultServer") + } + if c.Client.ServerCertPath == "" { + // TODO: Should probably have its own custom error + return fmt.Errorf("missing required value Client.ServerCertPath") + } + return nil +} + func (c *Config) Location() string { return c.location } @@ -293,7 +376,7 @@ func (sc *ServerFileStoreConfig) GetStore() (store.FileStore, func() error, erro return nil, nil, fmt.Errorf("invalid store config") } -func (sc *ServerUserStoreConfig) GetStore() (store.UserStore, func() error, error) { +func (sc *ServerDataStoreConfig) GetStore() (store.DataStore, func() error, error) { nopCloseFunc := func() error { return nil } if strings.EqualFold(sc.Type, "bolt") { s, err := store.NewBoltStore(sc.BoltStoreConfig.Path) diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..449c9f1 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,209 @@ +package config_test + +import ( + "strings" + "testing" + + "gitea.benny.dog/torjus/ezshare/config" +) + +var configStrExample = ` +######################## +# Server configuration # +######################## +[Server] +# Set server log-level +# Must be one of: DEBUG, INFO, WARN, ERROR +# Default: INFO +LogLevel = "INFO" + +# Server hostname +# Used for generating links +# Required +Hostname = "localhost" + +# Endpoint reachable by clients +# Fetched by clients for automatic setup +# Required +GRPCEndpoint = "localhost:50051" + +# File store configuration +[Server.FileStore] +# How server stores file +# Must be one of: filesystem, memory, bolt +# Required +Type = "bolt" + +[Server.FileStore.Bolt] +# Where the bolt-db is stored +# Required if store-type is bolt +Path = "/data/files.db" + +[Server.FileStore.Filesystem] +# Where files are stored +# Required if store-type is filesystem +Dir = "/data" + +[Server.DataStore] +# What store to use for users, certs and binaries +# Must be one of: memory, bolt +# Required +Type = "bolt" + +[Server.DataStore.Bolt] +# Path to bolt database-file +# Required if Server.Datastore is bolt +Path = "/data/users.db" + +# GRPC Configuration +[Server.GRPC] +# Address to listen to +# Default: :50051 +ListenAddr = ":50051" + +# GRPC Certificate Configuration +[Server.GRPC.CACerts] +# Path of PEM-encoded certificate file +CertificatePath = "/data/ca.pem" +# Path of PEM-encoded private key +# Must be of type ecdsa +CertificateKeyPath = "/data/ca.key" + +[Server.GRPC.Certs] +# Path of PEM-encoded certificate file +CertificatePath = "/data/server.pem" +# Path of PEM-encoded private key +# Must be of type ecdsa +CertificateKeyPath = "/data/server.key" + +[Server.HTTP] +# Address to listen to +# Default: :8089 +ListenAddr = ":8089" + + +######################## +# Client configuration # +######################## +[Client] +# Server used if not specified using command-line +DefaultServer = "localhost:50051" +# Path to PEM-encoder server-certificate +ServerCertPath = "/data/server.pem" + +[Client.Certs] +# Path of PEM-encoded certificate file +CertificatePath = "/data/client.pem" +# Path of PEM-encoded private key +# Must be of type ecdsa +CertificateKeyPath = "/data/client.key" +` + +var configStrValidClient = ` +[Client] +DefaultServer = "localhost:50051" +ServerCertPath = "/data/server.pem" +[Client.Certs] +CertificatePath = "/data/client.pem" +CertificateKeyPath = "/data/client.key" +` + +var configStrValidServerMinimal = ` +[Server] +LogLevel = "INFO" +Hostname = "localhost" +GRPCEndpoint = "localhost:50051" +[Server.FileStore] +Type = "memory" +[Server.DataStore] +Type = "memory" +[Server.GRPC] +ListenAddr = ":50051" +[Server.GRPC.CACerts] +CertificatePath = "/data/ca.pem" +CertificateKeyPath = "/data/ca.key" +[Server.GRPC.Certs] +CertificatePath = "/data/server.pem" +CertificateKeyPath = "/data/server.key" +[Server.HTTP] +ListenAddr = ":8089" +` + +var configStrInvalidServerMissingStoreConfig = ` +[Server] +LogLevel = "INFO" +Hostname = "localhost" +GRPCEndpoint = "localhost:50051" +[Server.FileStore] +Type = "bolt" +[Server.DataStore] +Type = "memory" +[Server.GRPC] +ListenAddr = ":50051" +[Server.GRPC.CACerts] +CertificatePath = "/data/ca.pem" +CertificateKeyPath = "/data/ca.key" +[Server.GRPC.Certs] +CertificatePath = "/data/server.pem" +CertificateKeyPath = "/data/server.key" +[Server.HTTP] +ListenAddr = ":8089" +` + +func TestConfig(t *testing.T) { + t.Run("TestValid", func(t *testing.T) { + + testCases := []struct { + Name string + ConfigString string + ValidForClient bool + ValidForServer bool + }{ + { + Name: "ExampleConfig", + ConfigString: configStrExample, + ValidForClient: true, + ValidForServer: true, + }, + { + Name: "ServerValidMinimal", + ConfigString: configStrValidServerMinimal, + ValidForServer: true, + }, + { + Name: "ClientValidMinimal", + ConfigString: configStrValidClient, + ValidForClient: true, + }, + { + Name: "ServerInvalidMissingStoreConfig", + ConfigString: configStrInvalidServerMissingStoreConfig, + }, + } + + for _, c := range testCases { + t.Run(c.Name, func(t *testing.T) { + sr := strings.NewReader(c.ConfigString) + cfg, err := config.FromReader(sr) + if err != nil { + t.Fatalf("Error reading config: %s", err) + } + clientErr := cfg.ValidForClient() + serverErr := cfg.ValidForServer() + + if c.ValidForClient && !(clientErr == nil) { + t.Errorf("Valid config ValidClientConfig returned wrong result: %s", clientErr) + } + if !c.ValidForClient && (clientErr == nil) { + t.Errorf("Invalid config ValidClientConfig returned wrong result: %s", clientErr) + } + if c.ValidForServer && !(serverErr == nil) { + t.Errorf("Valid config ValidServerConfig returned wrong result: %s", clientErr) + } + if !c.ValidForServer && (serverErr == nil) { + t.Errorf("Invalid config ValidServerConfig returned wrong result: %s", clientErr) + } + }) + } + }) +} diff --git a/ezshare.example.toml b/ezshare.example.toml index 584877d..d1b410e 100644 --- a/ezshare.example.toml +++ b/ezshare.example.toml @@ -34,14 +34,15 @@ Path = "/data/files.db" # Required if store-type is filesystem Dir = "/data" -[Server.UserStore] -# What store to use for users +[Server.DataStore] +# What store to use for users, certs and binaries # Must be one of: memory, bolt # Required Type = "bolt" -[Server.UserStore.Bolt] +[Server.DataStore.Bolt] # Path to bolt database-file +# Required if Server.Datastore is bolt Path = "/data/users.db" # GRPC Configuration diff --git a/store/store.go b/store/store.go index b4d5e48..f21eb3a 100644 --- a/store/store.go +++ b/store/store.go @@ -17,6 +17,12 @@ type FileStore interface { ListFiles() ([]*pb.ListFilesResponse_ListFileInfo, error) } +type DataStore interface { + BinaryStore + CertificateStore + UserStore +} + type CertificateStore interface { GetCertificate(serial string) (*x509.Certificate, error) StoreCertificate(cert *x509.Certificate) error From 94b5b45396060dc6ebccf147554898235c946fc6 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 8 Dec 2021 11:43:41 +0100 Subject: [PATCH 2/4] Allow updating config from env --- config/config.go | 62 ++++++++++++++++++++++++++++++++++++++++++++ ezshare.example.toml | 18 +++++++++++++ 2 files changed, 80 insertions(+) diff --git a/config/config.go b/config/config.go index 37cd6bb..229485d 100644 --- a/config/config.go +++ b/config/config.go @@ -144,6 +144,68 @@ func FromDefaultLocations() (*Config, error) { return nil, fmt.Errorf("config not found") } +func (c *Config) UpdateFromEnv() error { + // Server stuff + if val, found := os.LookupEnv("EZSHARE_SERVER_LOGLEVEL"); found { + c.Server.LogLevel = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_HOSTNAME"); found { + c.Server.Hostname = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPCENDPOINT"); found { + c.Server.GRPCEndpoint = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_DATASTORE_TYPE"); found { + c.Server.DataStoreConfig.Type = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_DATASTORE_BOLT_PATH"); found { + c.Server.DataStoreConfig.BoltStoreConfig.Path = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_FILESTORE_TYPE"); found { + c.Server.FileStoreConfig.Type = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_FILESTORE_BOLT_PATH"); found { + c.Server.FileStoreConfig.BoltStoreConfig.Path = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_FILESTORE_FILESYSTEM_DIR"); found { + c.Server.FileStoreConfig.FSStoreConfig.Dir = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPC_CACERTS_CERTIFICATEKEYPATH"); found { + c.Server.GRPC.CACerts.CertificateKeyPath = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPC_CACERTS_CERTIFICATEPATH"); found { + c.Server.GRPC.CACerts.CertificatePath = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPC_CERTS_CERTIFICATEKEYPATH"); found { + c.Server.GRPC.Certs.CertificateKeyPath = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPC_CERTS_CERTIFICATEPATH"); found { + c.Server.GRPC.Certs.CertificatePath = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_GRPC_LISTENADDR"); found { + c.Server.GRPC.ListenAddr = val + } + if val, found := os.LookupEnv("EZSHARE_SERVER_HTTP_LISTENADDR"); found { + c.Server.HTTP.ListenAddr = val + } + + // Client stuff + if val, found := os.LookupEnv("EZSHARE_CLIENT_DEFAULTSERVER"); found { + c.Client.DefaultServer = val + } + if val, found := os.LookupEnv("EZSHARE_CLIENT_CERTS_CERTIFICATEKEYPATH"); found { + c.Client.Certs.CertificateKeyPath = val + } + if val, found := os.LookupEnv("EZSHARE_CLIENT_CERTS_CERTIFICATEPATH"); found { + c.Client.Certs.CertificatePath = val + } + if val, found := os.LookupEnv("EZSHARE_CLIENT_SERVERCERTPATH"); found { + c.Client.ServerCertPath = val + } + + return nil +} + func (c *Config) ValidForServer() error { // Verify that grpc-endpoint is set if c.Server.GRPCEndpoint == "" { diff --git a/ezshare.example.toml b/ezshare.example.toml index d1b410e..f469913 100644 --- a/ezshare.example.toml +++ b/ezshare.example.toml @@ -5,16 +5,19 @@ # Set server log-level # Must be one of: DEBUG, INFO, WARN, ERROR # Default: INFO +# ENV: EZSHARE_SERVER_LOGLEVEL LogLevel = "INFO" # Server hostname # Used for generating links # Required +# ENV: EZSHARE_SERVER_HOSTNAME Hostname = "localhost" # Endpoint reachable by clients # Fetched by clients for automatic setup # Required +# ENV: EZSHARE_SERVER_GRPCENDPOINT GRPCEndpoint = "localhost:50051" # File store configuration @@ -22,53 +25,64 @@ GRPCEndpoint = "localhost:50051" # How server stores file # Must be one of: filesystem, memory, bolt # Required +# ENV: EZSHARE_SERVER_FILESTORE_TYPE Type = "bolt" [Server.FileStore.Bolt] # Where the bolt-db is stored # Required if store-type is bolt +# ENV: EZSHARE_SERVER_FILESTORE_BOLT_PATH Path = "/data/files.db" [Server.FileStore.Filesystem] # Where files are stored # Required if store-type is filesystem +# ENV: EZSHARE_SERVER_FILESTORE_FILESYSTEM_DIR Dir = "/data" [Server.DataStore] # What store to use for users, certs and binaries # Must be one of: memory, bolt # Required +# ENV: EZSHARE_SERVER_DATASTORE_TYPE Type = "bolt" [Server.DataStore.Bolt] # Path to bolt database-file # Required if Server.Datastore is bolt +# ENV: EZSHARE_SERVER_DATASTORE_BOLT_PATH Path = "/data/users.db" # GRPC Configuration [Server.GRPC] # Address to listen to # Default: :50051 +# ENV: EZSHARE_SERVER_GRPC_LISTENADDR ListenAddr = ":50051" # GRPC Certificate Configuration [Server.GRPC.CACerts] # Path of PEM-encoded certificate file +# ENV: EZSHARE_SERVER_GRPC_CACERTS_CERTIFICATEPATH CertificatePath = "" # Path of PEM-encoded private key # Must be of type ecdsa CertificateKeyPath = "" +# ENV: EZSHARE_SERVER_GRPC_CACERTS_CERTIFICATEKEYPATH [Server.GRPC.Certs] # Path of PEM-encoded certificate file +# ENV: EZSHARE_SERVER_GRPC_CERTS_CERTIFICATEPATH CertificatePath = "" # Path of PEM-encoded private key # Must be of type ecdsa +# ENV: EZSHARE_SERVER_GRPC_CERTS_CERTIFICATEKEYPATH CertificateKeyPath = "" [Server.HTTP] # Address to listen to # Default: :8089 +# ENV: EZSHARE_SERVER_HTTP_LISTENADDR ListenAddr = ":8089" @@ -77,13 +91,17 @@ ListenAddr = ":8089" ######################## [Client] # Server used if not specified using command-line +# ENV: EZSHARE_CLIENT_DEFAULTSERVER DefaultServer = "localhost:50051" # Path to PEM-encoder server-certificate +# ENV: EZSHARE_CLIENT_SERVERCERTPATH ServerCertPath = "" [Client.Certs] # Path of PEM-encoded certificate file +# ENV: EZSHARE_CLIENT_CERTS_CERTIFICATEPATH CertificatePath = "" # Path of PEM-encoded private key # Must be of type ecdsa +# ENV: EZSHARE_CLIENT_CERTS_CERTIFICATEKEYPATH CertificateKeyPath = "" From 84fc2d6667b0b4c8aa81ca3e2632c479c51ef37c Mon Sep 17 00:00:00 2001 From: = Date: Wed, 8 Dec 2021 13:07:08 +0100 Subject: [PATCH 3/4] Add some tests for config update from env --- config/config.go | 9 ++++++-- config/config_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 229485d..4c1f3d4 100644 --- a/config/config.go +++ b/config/config.go @@ -88,8 +88,13 @@ func FromDefault() *Config { HTTP: &ServerHTTPConfig{ ListenAddr: ":8089", }, - DataStoreConfig: &ServerDataStoreConfig{}, - FileStoreConfig: &ServerFileStoreConfig{}, + DataStoreConfig: &ServerDataStoreConfig{ + BoltStoreConfig: &BoltStoreConfig{}, + }, + FileStoreConfig: &ServerFileStoreConfig{ + BoltStoreConfig: &BoltStoreConfig{}, + FSStoreConfig: &FSStoreConfig{}, + }, }, Client: &ClientConfig{ Certs: &CertificatePaths{}, diff --git a/config/config_test.go b/config/config_test.go index 449c9f1..7f8414d 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,6 +1,7 @@ package config_test import ( + "os" "strings" "testing" @@ -206,4 +207,55 @@ func TestConfig(t *testing.T) { }) } }) + t.Run("FromEnv", func(t *testing.T) { + // Unset any existing ezshare env vars + for _, env := range os.Environ() { + if strings.HasPrefix(env, "EZSHARE") { + os.Unsetenv(env) + } + } + + cfg := config.FromDefault() + // Test Server.LogLevel + if cfg.Server.LogLevel == "WARN" { + t.Errorf("Loglevel is WARN before updating from env.") + } + os.Setenv("EZSHARE_SERVER_LOGLEVEL", "WARN") + if err := cfg.UpdateFromEnv(); err != nil { + t.Fatalf("Error updating config from environment: %s", err) + } + if cfg.Server.LogLevel != "WARN" { + t.Errorf("Loglevel is not WARN after updating from env.") + } + + // Test Server.Hostname + hostname := "https://share.example.org" + os.Setenv("EZSHARE_SERVER_HOSTNAME", hostname) + if err := cfg.UpdateFromEnv(); err != nil { + t.Fatalf("Error updating config from environment: %s", err) + } + if cfg.Server.Hostname != hostname { + t.Errorf("Hostname is incorrect after updating from env.") + } + + // Test Server.Datastore.Bolt.Path + boltPath := "/data/bolt.db" + os.Setenv("EZSHARE_SERVER_DATASTORE_BOLT_PATH", boltPath) + if err := cfg.UpdateFromEnv(); err != nil { + t.Fatalf("Error updating config from environment: %s", err) + } + if cfg.Server.DataStoreConfig.BoltStoreConfig.Path != boltPath { + t.Errorf("Bolt path is incorrect after updating from env.") + } + + // Test Server.Datastore.Bolt.Path + caCertPath := "/data/cert.pem" + os.Setenv("EZSHARE_SERVER_GRPC_CACERTS_CERTIFICATEKEYPATH", caCertPath) + if err := cfg.UpdateFromEnv(); err != nil { + t.Fatalf("Error updating config from environment: %s", err) + } + if cfg.Server.GRPC.CACerts.CertificateKeyPath != caCertPath { + t.Errorf("GPRC CA Cert path is incorrect after updating from env.") + } + }) } From 6558c63096736873f5b5cba0e34522f6c85e07ea Mon Sep 17 00:00:00 2001 From: = Date: Wed, 8 Dec 2021 13:12:16 +0100 Subject: [PATCH 4/4] Change valid-function for config --- config/config.go | 36 ++++++++++++++++++------------------ config/config_test.go | 18 ++++++++---------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/config/config.go b/config/config.go index 4c1f3d4..d21f00c 100644 --- a/config/config.go +++ b/config/config.go @@ -211,14 +211,14 @@ func (c *Config) UpdateFromEnv() error { return nil } -func (c *Config) ValidForServer() error { +func (sc *ServerConfig) Valid() error { // Verify that grpc-endpoint is set - if c.Server.GRPCEndpoint == "" { + if sc.GRPCEndpoint == "" { return fmt.Errorf("missing require config-value Server.GRPCEndpoint") } // Verify loglevel - switch strings.ToUpper(c.Server.LogLevel) { + switch strings.ToUpper(sc.LogLevel) { case "DEBUG", "INFO", "WARN", "ERROR", "FATAL": break default: @@ -226,11 +226,11 @@ func (c *Config) ValidForServer() error { } // Verify datastore config - switch strings.ToLower(c.Server.DataStoreConfig.Type) { + switch strings.ToLower(sc.DataStoreConfig.Type) { case "memory": break case "bolt": - if c.Server.DataStoreConfig.BoltStoreConfig == nil || c.Server.DataStoreConfig.BoltStoreConfig.Path == "" { + if sc.DataStoreConfig.BoltStoreConfig == nil || sc.DataStoreConfig.BoltStoreConfig.Path == "" { return fmt.Errorf("server datastore is bolt, missing required config value Server.DataStore.Bolt.Path") } default: @@ -238,54 +238,54 @@ func (c *Config) ValidForServer() error { } // Verify filestore config - switch strings.ToLower(c.Server.FileStoreConfig.Type) { + switch strings.ToLower(sc.FileStoreConfig.Type) { case "memory": break case "filesystem": - if c.Server.FileStoreConfig.FSStoreConfig == nil || c.Server.FileStoreConfig.FSStoreConfig.Dir == "" { + if sc.FileStoreConfig.FSStoreConfig == nil || sc.FileStoreConfig.FSStoreConfig.Dir == "" { return fmt.Errorf("server datastore is bolt, missing required config value Server.FileStore.FSStore.Path") } case "bolt": - if c.Server.FileStoreConfig.BoltStoreConfig == nil || c.Server.FileStoreConfig.BoltStoreConfig.Path == "" { + if sc.FileStoreConfig.BoltStoreConfig == nil || sc.FileStoreConfig.BoltStoreConfig.Path == "" { return fmt.Errorf("server datastore is bolt, missing required config value Server.DataStore.Bolt.Path") } } // Verify grpc-config - if c.Server.GRPC.ListenAddr == "" { + if sc.GRPC.ListenAddr == "" { return fmt.Errorf("missing required config-value Server.GRPC.ListenAddr") } - if c.Server.GRPC.CACerts.CertificateKeyPath == "" { + if sc.GRPC.CACerts.CertificateKeyPath == "" { // TODO: Maybe return custom error, so we can create certs if missing return fmt.Errorf("missing require value Server.GRPC.CACerts.CertificateKeyPath") } - if c.Server.GRPC.CACerts.CertificatePath == "" { + if sc.GRPC.CACerts.CertificatePath == "" { // TODO: Maybe return custom error, so we can create certs if missing return fmt.Errorf("missing require value Server.GRPC.CACerts.CertificatePath") } - if c.Server.GRPC.Certs.CertificatePath == "" { + if sc.GRPC.Certs.CertificatePath == "" { // TODO: Maybe return custom error, so we can create certs if missing return fmt.Errorf("missing require value Server.GRPC.Certs.CertificatePath") } - if c.Server.GRPC.Certs.CertificateKeyPath == "" { + if sc.GRPC.Certs.CertificateKeyPath == "" { // TODO: Maybe return custom error, so we can create certs if missing return fmt.Errorf("missing require value Server.GRPC.Certs.CertificateKeyPath") } return nil } -func (c *Config) ValidForClient() error { - if c.Client.Certs.CertificateKeyPath == "" { +func (cc *ClientConfig) Valid() error { + if cc.Certs.CertificateKeyPath == "" { return fmt.Errorf("missing required value Client.Certs.CertificateKeyPath") } - if c.Client.Certs.CertificatePath == "" { + if cc.Certs.CertificatePath == "" { return fmt.Errorf("missing required value Client.Certs.CertificatePath") } - if c.Client.DefaultServer == "" { + if cc.DefaultServer == "" { // TODO: Should probably have its own custom error return fmt.Errorf("missing required value Client.DefaultServer") } - if c.Client.ServerCertPath == "" { + if cc.ServerCertPath == "" { // TODO: Should probably have its own custom error return fmt.Errorf("missing required value Client.ServerCertPath") } diff --git a/config/config_test.go b/config/config_test.go index 7f8414d..b53040e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -189,20 +189,18 @@ func TestConfig(t *testing.T) { if err != nil { t.Fatalf("Error reading config: %s", err) } - clientErr := cfg.ValidForClient() - serverErr := cfg.ValidForServer() - if c.ValidForClient && !(clientErr == nil) { - t.Errorf("Valid config ValidClientConfig returned wrong result: %s", clientErr) + if c.ValidForClient && !(cfg.Client.Valid() == nil) { + t.Errorf("Valid config ValidClientConfig returned wrong result: %s", cfg.Client.Valid()) } - if !c.ValidForClient && (clientErr == nil) { - t.Errorf("Invalid config ValidClientConfig returned wrong result: %s", clientErr) + if !c.ValidForClient && (cfg.Client.Valid() == nil) { + t.Errorf("Invalid config ValidClientConfig returned wrong result: %s", cfg.Client.Valid()) } - if c.ValidForServer && !(serverErr == nil) { - t.Errorf("Valid config ValidServerConfig returned wrong result: %s", clientErr) + if c.ValidForServer && !(cfg.Server.Valid() == nil) { + t.Errorf("Valid config ValidServerConfig returned wrong result: %s", cfg.Server.Valid()) } - if !c.ValidForServer && (serverErr == nil) { - t.Errorf("Invalid config ValidServerConfig returned wrong result: %s", clientErr) + if !c.ValidForServer && (cfg.Server.Valid() == nil) { + t.Errorf("Invalid config ValidServerConfig returned wrong result: %s", cfg.Server.Valid()) } }) }