From 3a48f4e32754d1d6874bc906a3b3a552af172a2b Mon Sep 17 00:00:00 2001 From: Andre Sterba <andre.sterba@stud.h-da.de> Date: Wed, 24 Nov 2021 10:19:23 +0000 Subject: [PATCH] Use config package to handle all controller configurations --- .gitignore | 3 ++ api/initialise_test.go | 6 +-- cmd/root.go | 40 +++++++++++++-- config.go | 61 ---------------------- config/config.go | 114 +++++++++++++++++++++++++++++++++++++++++ config/config_test.go | 63 +++++++++++++++++++++++ config_test.go | 41 --------------- configs/.gitkeep | 0 controller.go | 10 ++-- initialise_test.go | 6 +-- nucleus/change_test.go | 5 +- 11 files changed, 231 insertions(+), 118 deletions(-) delete mode 100644 config.go create mode 100644 config/config.go create mode 100644 config/config_test.go delete mode 100644 config_test.go create mode 100644 configs/.gitkeep diff --git a/.gitignore b/.gitignore index 2dcac5e10..b53fc7aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ debug.test # Binary gosdn + +# Storage +stores/ diff --git a/api/initialise_test.go b/api/initialise_test.go index c6a00cc27..8da7ae364 100644 --- a/api/initialise_test.go +++ b/api/initialise_test.go @@ -5,11 +5,13 @@ import ( "net" "os" "testing" + "time" cpb "code.fbi.h-da.de/danet/api/go/gosdn/core" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" tpb "code.fbi.h-da.de/danet/api/go/gosdn/transport" + "code.fbi.h-da.de/danet/gosdn/config" "code.fbi.h-da.de/danet/gosdn/mocks" nbi "code.fbi.h-da.de/danet/gosdn/northbound/server" "code.fbi.h-da.de/danet/gosdn/nucleus" @@ -128,9 +130,7 @@ func TestMain(m *testing.M) { } func bootstrapIntegrationTest() { - if os.Getenv("GOSDN_LOG") == "nolog" { - log.SetLevel(log.PanicLevel) - } + log.SetLevel(config.LogLevel) addr := os.Getenv("GOSDN_TEST_ENDPOINT") if addr != "" { diff --git a/cmd/root.go b/cmd/root.go index e7465b44f..7559bde87 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -34,6 +34,7 @@ package cmd import ( "context" "os" + "path/filepath" "code.fbi.h-da.de/danet/gosdn" @@ -80,16 +81,22 @@ func init() { rootCmd.Flags().StringVar(&csbiOrchestrstor, "csbi-orchestrator", "localhost:55056", "csbi orchestrator address") } +const ( + configHome string = "./configs" + configName string = "gosdn" + configType string = "toml" +) + // initConfig reads in config file and ENV variables if set. func initConfig() { if cfgFile != "" { // Use config file from the flag. viper.SetConfigFile(cfgFile) } else { - viper.AddConfigPath("./configs") + viper.AddConfigPath(configHome) viper.AddConfigPath("/usr/local/etc/gosdn/") - viper.SetConfigType("toml") - viper.SetConfigName("gosdn") + viper.SetConfigType(configType) + viper.SetConfigName(configName) } viper.AutomaticEnv() // read in environment variables that match @@ -97,6 +104,8 @@ func initConfig() { // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { log.Debug("Using config file:", viper.ConfigFileUsed()) + } else { + ensureViperConfigFileExists() } viper.SetDefault("socket", ":55055") @@ -118,3 +127,28 @@ func initConfig() { log.SetReportCaller(false) } } + +func ensureFileSystemStoreExists(pathToStore string) error { + emptyString := []byte("") + err := os.WriteFile(pathToStore, emptyString, 0600) + if err != nil { + return err + } + + return nil +} + +func ensureViperConfigFileExists() { + // Viper will crash if you call 'WriteConfig()' and the file does + // not exists yet. + // Therefore we handle this case here. + // Inspired by //https://github.com/spf13/viper/issues/430#issuecomment-661945101 + configPath := filepath.Join(configHome, configName+"."+configType) + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + err := ensureFileSystemStoreExists(configPath) + if err != nil { + panic(err) + } + } +} diff --git a/config.go b/config.go deleted file mode 100644 index 9e09fcc91..000000000 --- a/config.go +++ /dev/null @@ -1,61 +0,0 @@ -package gosdn - -import ( - "github.com/google/uuid" - "github.com/spf13/viper" -) - -// Config represents the nucleus configuration -type Config struct { - BasePndUUID uuid.UUID - BaseSouthBoundType int32 - BaseSouthBoundUUID uuid.UUID -} - -func getUUIDFromViper(viperKey string) (uuid.UUID, error) { - UUIDAsString := viper.GetString(viperKey) - if UUIDAsString == "" { - newUUID := uuid.New() - viper.Set(viperKey, newUUID.String()) - viper.WriteConfig() - - return newUUID, nil - } - - parsedUUID, err := uuid.Parse(UUIDAsString) - if err != nil { - return uuid.Nil, err - } - - return parsedUUID, nil -} - -// InitializeConfig loads the configuration -func (c *Config) InitializeConfig() error { - var err error - basePNDUUIDKey := "basePNDUUID" - baseSouthBoundTypeKey := "baseSouthBoundType" - baseSouthBoundUUIDKey := "baseSouthBoundUUID" - - basePNDUUID, err := getUUIDFromViper(basePNDUUIDKey) - if err != nil { - return err - } - - c.BasePndUUID = basePNDUUID - - baseSouthBoundUUID, err := getUUIDFromViper(baseSouthBoundUUIDKey) - if err != nil { - return err - } - - c.BaseSouthBoundUUID = baseSouthBoundUUID - - c.BaseSouthBoundType = viper.GetInt32("BaseSouthBoundType") - if c.BaseSouthBoundType != 0 { - viper.Set(baseSouthBoundTypeKey, 0) - viper.WriteConfig() - } - - return nil -} diff --git a/config/config.go b/config/config.go new file mode 100644 index 000000000..86e39b687 --- /dev/null +++ b/config/config.go @@ -0,0 +1,114 @@ +package config + +import ( + "os" + "time" + + "github.com/google/uuid" + "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" +) + +const ( + defaultTimeOutDuration10minutes = time.Minute * 10 + basePNDUUIDKey = "basePNDUUID" + baseSouthBoundTypeKey = "baseSouthBoundType" + baseSouthBoundUUIDKey = "baseSouthBoundUUID" + changeTimeoutKey = "GOSDN_CHANGE_TIMEOUT" +) + +// BasePndUUID is an uuid for the base PND +var BasePndUUID uuid.UUID + +// BaseSouthBoundType is the type of the base SBI +var BaseSouthBoundType int32 + +// BaseSouthBoundUUID is an uuid for the base SBI +var BaseSouthBoundUUID uuid.UUID + +// ChangeTimeout is the default timeout for a change +var ChangeTimeout time.Duration + +// LogLevel ist the default log level +var LogLevel logrus.Level + +// Init gets called on module import +func Init() { + InitializeConfig() +} + +// InitializeConfig loads the configuration +func InitializeConfig() error { + var err error + + basePNDUUIDFromViper, err := getUUIDFromViper(basePNDUUIDKey) + if err != nil { + return err + } + + BasePndUUID = basePNDUUIDFromViper + + baseSouthBoundUUIDFromViper, err := getUUIDFromViper(baseSouthBoundUUIDKey) + if err != nil { + return err + } + + BaseSouthBoundUUID = baseSouthBoundUUIDFromViper + + BaseSouthBoundType = viper.GetInt32(baseSouthBoundTypeKey) + if BaseSouthBoundType != 0 { + viper.Set(baseSouthBoundTypeKey, 0) + viper.WriteConfig() + } + + err = setChangeTimeout() + if err != nil { + return err + } + + setLogLevel() + + return nil +} + +func getUUIDFromViper(viperKey string) (uuid.UUID, error) { + UUIDAsString := viper.GetString(viperKey) + if UUIDAsString == "" { + newUUID := uuid.New() + viper.Set(viperKey, newUUID.String()) + viper.WriteConfig() + + return newUUID, nil + } + + parsedUUID, err := uuid.Parse(UUIDAsString) + if err != nil { + return uuid.Nil, err + } + + return parsedUUID, nil +} + +func setChangeTimeout() error { + e := os.Getenv(changeTimeoutKey) + if e != "" { + changeTimeout, err := time.ParseDuration(e) + if err != nil { + log.Fatal(err) + } + ChangeTimeout = changeTimeout + } else { + ChangeTimeout = time.Minute * 10 + } + + return nil +} + +func setLogLevel() { + if os.Getenv("GOSDN_LOG") == "nolog" { + LogLevel = logrus.PanicLevel + } else { + LogLevel = logrus.InfoLevel + } +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 000000000..6a1afccee --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,63 @@ +package config + +import ( + "os" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/spf13/viper" +) + +func TestInit(t *testing.T) { + viper.SetConfigFile("./config_test.toml") + viper.Set("baseSouthBoundType", 0) + viper.Set("baseSouthBoundUUID", "bf8160d4-4659-4a1b-98fd-f409a04111eb") + viper.Set("basePNDUUID", "bf8160d4-4659-4a1b-98fd-f409a04111ec") + viper.Set("GOSDN_CHANGE_TIMEOUT", "10m") +} + +func TestUseExistingConfig(t *testing.T) { + TestInit(t) + + err := InitializeConfig() + if err != nil { + t.Error(err) + return + } + + if BasePndUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111ec" { + t.Fatalf("BasePndUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111ec. got=%s", + BasePndUUID.String()) + } + + if BaseSouthBoundUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111eb" { + t.Fatalf("BaseSouthBoundUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111eb. got=%s", + BaseSouthBoundUUID.String()) + } + + if BaseSouthBoundType != 0 { + t.Fatalf("BaseSouthBoundType is not 0. got=%d", + BaseSouthBoundType) + } + + testChangeTimeout, _ := time.ParseDuration("10m") + defaultChangeTimeout := defaultTimeOutDuration10minutes + if defaultChangeTimeout != testChangeTimeout { + t.Fatalf("ChangeTimeout is not 10ms. got=%v", + ChangeTimeout) + } + + if os.Getenv("GOSDN_LOG") == "nolog" { + if LogLevel != logrus.PanicLevel { + t.Fatalf("LogLevel is not %v. got=%v", + logrus.PanicLevel, LogLevel) + } + } else { + if LogLevel != logrus.InfoLevel { + t.Fatalf("LogLevel is not %v. got=%v", + logrus.InfoLevel, LogLevel) + } + } + +} diff --git a/config_test.go b/config_test.go deleted file mode 100644 index 89bc5f276..000000000 --- a/config_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package gosdn - -import ( - "testing" - - "github.com/spf13/viper" -) - -func Test_Init(t *testing.T) { - viper.SetConfigFile("./config_test.toml") - viper.Set("baseSouthBoundType", 0) - viper.Set("baseSouthBoundUUID", "bf8160d4-4659-4a1b-98fd-f409a04111eb") - viper.Set("basePNDUUID", "bf8160d4-4659-4a1b-98fd-f409a04111ec") -} - -func Test_UseExistingConfig(t *testing.T) { - Test_Init(t) - - testConfig := Config{} - - err := testConfig.InitializeConfig() - if err != nil { - t.Error(err) - return - } - - if testConfig.BasePndUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111ec" { - t.Fatalf("testConfig.BasePndUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111ec. got=%s", - testConfig.BasePndUUID.String()) - } - - if testConfig.BaseSouthBoundUUID.String() != "bf8160d4-4659-4a1b-98fd-f409a04111eb" { - t.Fatalf("testConfig.BaseSouthBoundUUID.String() is not bf8160d4-4659-4a1b-98fd-f409a04111eb. got=%s", - testConfig.BaseSouthBoundUUID.String()) - } - - if testConfig.BaseSouthBoundType != 0 { - t.Fatalf("testConfig.BaseSouthBoundType is not 0. got=%d", - testConfig.BaseSouthBoundType) - } -} diff --git a/configs/.gitkeep b/configs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/controller.go b/controller.go index d668c1753..748c7aa79 100644 --- a/controller.go +++ b/controller.go @@ -18,6 +18,7 @@ import ( cpb "code.fbi.h-da.de/danet/api/go/gosdn/csbi" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound" + "code.fbi.h-da.de/danet/gosdn/config" "code.fbi.h-da.de/danet/gosdn/interfaces/southbound" nbi "code.fbi.h-da.de/danet/gosdn/northbound/server" "code.fbi.h-da.de/danet/gosdn/store" @@ -61,13 +62,12 @@ func initialize() error { startHttpServer() coreLock.Unlock() - config := Config{} err := config.InitializeConfig() if err != nil { return err } - return createSouthboundInterfaces(config) + return createSouthboundInterfaces() } func startGrpc() error { @@ -98,13 +98,13 @@ func startGrpc() error { } // createSouthboundInterfaces initializes the controller with its supported SBIs -func createSouthboundInterfaces(config Config) error { +func createSouthboundInterfaces() error { sbi := nucleus.NewSBI(spb.Type(config.BaseSouthBoundType), config.BaseSouthBoundUUID) - return createPrincipalNetworkDomain(sbi, config) + return createPrincipalNetworkDomain(sbi) } // createPrincipalNetworkDomain initializes the controller with an initial PND -func createPrincipalNetworkDomain(s southbound.SouthboundInterface, config Config) error { +func createPrincipalNetworkDomain(s southbound.SouthboundInterface) error { pnd, err := nucleus.NewPND("base", "gosdn base pnd", config.BasePndUUID, s, c.csbiClient, callback) if err != nil { return err diff --git a/initialise_test.go b/initialise_test.go index d47822bbd..bba39814b 100644 --- a/initialise_test.go +++ b/initialise_test.go @@ -4,6 +4,8 @@ import ( "os" "testing" + "code.fbi.h-da.de/danet/gosdn/config" + "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -17,10 +19,8 @@ var cuid uuid.UUID func TestMain(m *testing.M) { log.SetReportCaller(true) + log.SetLevel(config.LogLevel) - if os.Getenv("GOSDN_LOG") == "nolog" { - log.SetLevel(log.PanicLevel) - } readTestUUIDs() os.Exit(m.Run()) } diff --git a/nucleus/change_test.go b/nucleus/change_test.go index fa4cf5b9c..6fdff64fc 100644 --- a/nucleus/change_test.go +++ b/nucleus/change_test.go @@ -8,6 +8,7 @@ import ( "time" ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd" + "code.fbi.h-da.de/danet/gosdn/config" "github.com/google/uuid" "github.com/openconfig/ygot/exampleoc" "github.com/openconfig/ygot/ygot" @@ -61,7 +62,7 @@ func TestChange_CommitRollback(t *testing.T) { if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 200) + time.Sleep(config.ChangeTimeout) }() got := <-callback if !reflect.DeepEqual(got, want) { @@ -103,7 +104,7 @@ func TestChange_CommitRollbackError(t *testing.T) { if err := c.Commit(); (err != nil) != wantErr { t.Errorf("Commit() error = %v, wantErr %v", err, wantErr) } - time.Sleep(time.Millisecond * 200) + time.Sleep(config.ChangeTimeout) }() got := <-c.errChan if !reflect.DeepEqual(got, want) { -- GitLab