From 5524b7df1676aaef11395689a32786d8e00d445e Mon Sep 17 00:00:00 2001 From: Samir Faci Date: Fri, 8 Nov 2024 14:02:34 -0500 Subject: [PATCH] Removing default configuration. GDG will now require a valid config for backup/tools functionality. --- cli/commandeer.go | 9 +-- cli/support/init_cfg.go | 13 +---- .../backup/alerting_contactpoints_test.go | 9 ++- cli/test/backup/conections_test.go | 3 +- cli/test/tools/devel_test.go | 10 ++-- cli/test/version_test.go | 7 +-- cli/version.go | 20 ++++++- cmd/gdg-generate/cli/root.go | 11 ++-- cmd/gdg/main.go | 2 +- internal/config/config_loader.go | 55 +++++++++---------- internal/config/config_loader_test.go | 12 ++-- internal/config/template_config.go | 9 ++- internal/service/common_test.go | 4 +- internal/templating/templating_test.go | 2 +- pkg/test_tooling/common.go | 2 +- pkg/test_tooling/support.go | 13 ++--- 16 files changed, 90 insertions(+), 91 deletions(-) diff --git a/cli/commandeer.go b/cli/commandeer.go index ac2f92a3..016fc007 100644 --- a/cli/commandeer.go +++ b/cli/commandeer.go @@ -2,22 +2,16 @@ package cli import ( "context" - "log/slog" "github.com/bep/simplecobra" "github.com/esnet/gdg/cli/backup" "github.com/esnet/gdg/cli/support" "github.com/esnet/gdg/cli/tools" - assets "github.com/esnet/gdg/config" ) // Execute executes a command. -func Execute(defaultCfg string, args []string, options ...support.RootOption) error { +func Execute(args []string, options ...support.RootOption) error { var err error - support.DefaultConfig, err = assets.GetFile(defaultCfg) - if err != nil { - slog.Warn("unable to find load default configuration", "err", err) - } rootCmd := support.NewRootCmd(getNewRootCmd(), options...) x, err := simplecobra.New(rootCmd) if err != nil { @@ -41,6 +35,7 @@ func getNewRootCmd() *support.RootCommand { NameP: "gdg", CommandEntries: []simplecobra.Commander{ newVersionCmd(), + newDefaultConfig(), tools.NewToolsCommand(), backup.NewBackupCommand(), }, diff --git a/cli/support/init_cfg.go b/cli/support/init_cfg.go index dbaf8944..c94cebea 100644 --- a/cli/support/init_cfg.go +++ b/cli/support/init_cfg.go @@ -11,17 +11,10 @@ import ( // InitConfiguration Loads configuration, and setups fail over case func InitConfiguration(cmd *cobra.Command) { configOverride, _ := cmd.Flags().GetString("config") - if DefaultConfig == "" { - raw, err := os.ReadFile("config/importer-example.yml") - if err == nil { - DefaultConfig = string(raw) - } else { - DefaultConfig = "" - } - } - // Registers sub CommandsList - config.InitGdgConfig(configOverride, DefaultConfig) + if config.Config() == nil { + config.InitGdgConfig(configOverride) + } appconfig.InitializeAppLogger(os.Stdout, os.Stderr, config.Config().IsDebug()) // Validate current configuration diff --git a/cli/test/backup/alerting_contactpoints_test.go b/cli/test/backup/alerting_contactpoints_test.go index 146924e4..1734f962 100644 --- a/cli/test/backup/alerting_contactpoints_test.go +++ b/cli/test/backup/alerting_contactpoints_test.go @@ -13,7 +13,6 @@ import ( "github.com/esnet/gdg/cli" "github.com/esnet/gdg/internal/service/mocks" "github.com/esnet/gdg/pkg/test_tooling" - "github.com/esnet/gdg/pkg/test_tooling/common" "github.com/stretchr/testify/assert" ) @@ -66,7 +65,7 @@ func TestUploadContactPoints(t *testing.T) { r, w, cleanup := test_tooling.InterceptStdout() defer cleanup() - err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + err := cli.Execute(listCmd, optionMockSvc()) if tc.expectErr { assert.NotNil(t, err) } else { @@ -129,7 +128,7 @@ func TestDownloadContactPoints(t *testing.T) { r, w, cleanup := test_tooling.InterceptStdout() defer cleanup() - err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + err := cli.Execute(listCmd, optionMockSvc()) if tc.expectErr { assert.NotNil(t, err) } else { @@ -210,7 +209,7 @@ func TestListContactPoints(t *testing.T) { r, w, cleanup := test_tooling.InterceptStdout() defer cleanup() - err := cli.Execute(common.DefaultTestConfig, listCmd, optionMockSvc()) + err := cli.Execute(listCmd, optionMockSvc()) if tc.expectErr { assert.NotNil(t, err) } else { @@ -285,7 +284,7 @@ func TestClearContactPoints(t *testing.T) { r, w, cleanup := test_tooling.InterceptStdout() defer cleanup() - err := cli.Execute(common.DefaultTestConfig, clearCmd, optionMockSvc()) + err := cli.Execute(clearCmd, optionMockSvc()) assert.Nil(t, err) defer cleanup() assert.NoError(t, w.Close()) diff --git a/cli/test/backup/conections_test.go b/cli/test/backup/conections_test.go index 32641d41..e4e5c568 100644 --- a/cli/test/backup/conections_test.go +++ b/cli/test/backup/conections_test.go @@ -11,7 +11,6 @@ import ( "github.com/esnet/gdg/cli/support" "github.com/esnet/gdg/internal/service" "github.com/esnet/gdg/internal/service/mocks" - "github.com/esnet/gdg/pkg/test_tooling/common" "github.com/grafana/grafana-openapi-client-go/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -42,7 +41,7 @@ func TestConnectionCommand(t *testing.T) { } r, w, cleanup := test_tooling.InterceptStdout() - err := cli.Execute(common.DefaultTestConfig, []string{"backup", "connections", "list"}, optionMockSvc()) + err := cli.Execute([]string{"backup", "connections", "list"}, optionMockSvc()) assert.Nil(t, err) defer cleanup() assert.NoError(t, w.Close()) diff --git a/cli/test/tools/devel_test.go b/cli/test/tools/devel_test.go index 82010609..37e29209 100644 --- a/cli/test/tools/devel_test.go +++ b/cli/test/tools/devel_test.go @@ -13,14 +13,14 @@ import ( ) func TestDevelSrvInfo(t *testing.T) { - execMe := func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error { + execMe := func(mock *mocks.GrafanaService, optionMockSvc func() support.RootOption) error { expected := make(map[string]interface{}) expected["Database"] = "db" expected["Commit"] = "commit" expected["Version"] = "version" mock.EXPECT().GetServerInfo().Return(expected) - err := cli.Execute(string(data), []string{"tools", "devel", "srvinfo"}, optionMockSvc()) + err := cli.Execute([]string{"tools", "devel", "srvinfo"}, optionMockSvc()) return err } outStr, closeReader := test_tooling.SetupAndExecuteMockingServices(t, execMe) @@ -32,9 +32,9 @@ func TestDevelSrvInfo(t *testing.T) { } func TestDevelSrvCompletion(t *testing.T) { - fn := func(args []string) func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error { - return func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error { - err := cli.Execute(string(data), args, optionMockSvc()) + fn := func(args []string) func(mock *mocks.GrafanaService, optionMockSvc func() support.RootOption) error { + return func(mock *mocks.GrafanaService, optionMockSvc func() support.RootOption) error { + err := cli.Execute(args, optionMockSvc()) return err } } diff --git a/cli/test/version_test.go b/cli/test/version_test.go index 7dc076c6..99156fd3 100644 --- a/cli/test/version_test.go +++ b/cli/test/version_test.go @@ -13,14 +13,13 @@ import ( "github.com/esnet/gdg/internal/service" "github.com/esnet/gdg/internal/service/mocks" "github.com/esnet/gdg/internal/version" - "github.com/esnet/gdg/pkg/test_tooling/common" "github.com/stretchr/testify/assert" ) func TestVersionCommand(t *testing.T) { assert.NoError(t, path.FixTestDir("test", "../..")) - execMe := func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error { - err := cli.Execute(string(data), []string{"version"}, optionMockSvc()) + execMe := func(mock *mocks.GrafanaService, optionMockSvc func() support.RootOption) error { + err := cli.Execute([]string{"version"}, optionMockSvc()) return err } outStr, closeReader := test_tooling.SetupAndExecuteMockingServices(t, execMe) @@ -49,7 +48,7 @@ func TestVersionErrCommand(t *testing.T) { } r, w, cleanup := test_tooling.InterceptStdout() defer cleanup() - err := cli.Execute(common.DefaultTestConfig, []string{"dumb", "dumb"}, optionMockSvc()) + err := cli.Execute([]string{"dumb", "dumb"}, optionMockSvc()) assert.NotNil(t, err) assert.NoError(t, w.Close()) diff --git a/cli/version.go b/cli/version.go index f95a6bde..b932360b 100644 --- a/cli/version.go +++ b/cli/version.go @@ -2,9 +2,11 @@ package cli import ( "context" + "fmt" "github.com/bep/simplecobra" "github.com/esnet/gdg/cli/support" + "github.com/esnet/gdg/internal/config" "github.com/esnet/gdg/internal/version" "github.com/spf13/cobra" ) @@ -20,6 +22,22 @@ func newVersionCmd() simplecobra.Commander { cmd.Aliases = []string{"v"} }, Short: "Print the version number of generated code example", - Long: "All software has versions. This is generated code example", + Long: "Print the version number of generated code example", + } +} + +func newDefaultConfig() simplecobra.Commander { + return &support.SimpleCommand{ + NameP: "default-config", + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, r *support.RootCommand, args []string) error { + o := config.Configuration{} + fmt.Print(o.DefaultConfig()) + return nil + }, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"v"} + }, + Short: "Prints an example configuration", + Long: "Prints an example configuration", } } diff --git a/cmd/gdg-generate/cli/root.go b/cmd/gdg-generate/cli/root.go index d464faaa..7d38c679 100644 --- a/cmd/gdg-generate/cli/root.go +++ b/cmd/gdg-generate/cli/root.go @@ -5,7 +5,8 @@ import ( "log/slog" "os" - assets "github.com/esnet/gdg/config" + "github.com/esnet/gdg/internal/version" + "github.com/esnet/gdg/internal/config" appconfig "github.com/esnet/gdg/internal/log" "github.com/esnet/gdg/internal/templating" @@ -33,6 +34,7 @@ func init() { func initConfig() { var err error + slog.Info("Running gdg-generate", slog.Any("version", version.Version)) cfgFile, err = rootCmd.Flags().GetString("config") if err != nil { log.Fatal("unable to get config file") @@ -42,12 +44,7 @@ func initConfig() { log.Fatal("unable to get template config file") } - defaultConfiguration, err := assets.GetFile("importer-example.yml") - if err != nil { - slog.Warn("unable to load default configuration, no fallback") - } - - config.InitGdgConfig(cfgFile, defaultConfiguration) + config.InitGdgConfig(cfgFile) config.InitTemplateConfig(tplCfgFile) cfg := config.Config() appconfig.InitializeAppLogger(os.Stdout, os.Stderr, cfg.IsDebug()) diff --git a/cmd/gdg/main.go b/cmd/gdg/main.go index 8fa328bc..348972d2 100644 --- a/cmd/gdg/main.go +++ b/cmd/gdg/main.go @@ -21,7 +21,7 @@ func main() { } } - err := cli.Execute("importer-example.yml", os.Args[1:], setGrafanaSvc()) + err := cli.Execute(os.Args[1:], setGrafanaSvc()) if err != nil { log.Fatalf("Error: %s", err) } diff --git a/internal/config/config_loader.go b/internal/config/config_loader.go index 4e22eb04..14a3df0f 100644 --- a/internal/config/config_loader.go +++ b/internal/config/config_loader.go @@ -1,7 +1,6 @@ package config import ( - "errors" "fmt" "log" "log/slog" @@ -9,6 +8,7 @@ import ( "path/filepath" "strings" + assets "github.com/esnet/gdg/config" "github.com/esnet/gdg/internal/tools" "github.com/spf13/viper" "gopkg.in/yaml.v3" @@ -21,6 +21,14 @@ func (s *Configuration) GetViperConfig(name string) *viper.Viper { return s.viperConfiguration[name] } +func (s *Configuration) DefaultConfig() string { + cfg, err := assets.GetFile("importer-example.yml") + if err != nil { + slog.Warn("unable to find load default configuration", "err", err) + } + return cfg +} + func (s *Configuration) ClearContexts() { newContext := make(map[string]*GrafanaConfig) newContext["example"] = &GrafanaConfig{ @@ -143,7 +151,7 @@ func (s *Configuration) SaveToDisk(useViper bool) error { } var ( - configData = new(Configuration) + configData *Configuration configSearchPaths = []string{"config", ".", "../config", "../../config", "/etc/gdg"} ) @@ -208,8 +216,10 @@ func (s *TemplatingConfig) GetTemplate(name string) (*TemplateDashboards, bool) } // buildConfigSearchPath common pattern used when loading configuration for both CLI tools. -func buildConfigSearchPath(configFile string, appName string) ([]string, string, string) { +func buildConfigSearchPath(configFile string) ([]string, string, string) { ext := filepath.Ext(configFile) + appName := filepath.Base(configFile) + var configDirs []string if configFile != "" { configFileDir := filepath.Dir(configFile) @@ -230,37 +240,26 @@ func buildConfigSearchPath(configFile string, appName string) ([]string, string, return configDirs, appName, ext } -func InitGdgConfig(override, defaultConfig string) { +func InitGdgConfig(override string) { + if override == "" && configData != nil { + return + } configData = &Configuration{} - appName := "importer" - configDirs, appName, ext := buildConfigSearchPath(override, appName) + var configDirs []string + var ext, appName string + if override == "" { + configDirs, appName, ext = buildConfigSearchPath("config/importer.yml") + } else { + configDirs, appName, ext = buildConfigSearchPath(override) + } var err error var v *viper.Viper configData.gdgConfig = new(GDGAppConfiguration) v, err = readViperConfig[GDGAppConfiguration](appName, configDirs, configData.gdgConfig, ext) - var configFileNotFoundError viper.ConfigFileNotFoundError - ok := errors.As(err, &configFileNotFoundError) - - if err != nil && ok { - slog.Info("No configuration file has been found, creating a default configuration") - err = os.MkdirAll("config", 0o750) - if err != nil { - log.Fatal("unable to create configuration folder: 'config'") - } - err = os.WriteFile("config/importer.yml", []byte(defaultConfig), 0o600) - if err != nil { - log.Panic("Could not persist default config locally") - } - appName = "importer" - - v, err = readViperConfig[GDGAppConfiguration](appName, configDirs, configData.gdgConfig, "") - if err != nil { - log.Panic(err) - } - - } else if err != nil { // config is found but is invalid - log.Fatal("Invalid configuration detected, please fix your configuration and try again.") + if err != nil { + log.Fatal("No configuration file has been found or config is invalid. Expected a file named 'importer.yml' in one of the following folders: ['.', 'config', '/etc/gdg']. " + + "Try using `gdg default-config > config/importer.yml` go use the default example") } if configData.viperConfiguration == nil { configData.viperConfiguration = make(map[string]*viper.Viper) diff --git a/internal/config/config_loader_test.go b/internal/config/config_loader_test.go index 6acbc13b..c37382e1 100644 --- a/internal/config/config_loader_test.go +++ b/internal/config/config_loader_test.go @@ -43,7 +43,7 @@ func TestSetup(t *testing.T) { } os.Setenv("GDG_CONTEXT_NAME", "qa") - config.InitGdgConfig(common.DefaultTestConfig, "") + config.InitGdgConfig(common.DefaultTestConfig) conf := config.Config().GetViperConfig(config.ViperGdgConfig) slog.Info(conf.ConfigFileUsed()) @@ -65,8 +65,8 @@ func TestWatchedFoldersConfig(t *testing.T) { } } - os.Setenv("GDG_CONTEXT_NAME", "qa") - config.InitGdgConfig(common.DefaultTestConfig, "") + assert.NoError(t, os.Setenv("GDG_CONTEXT_NAME", "qa")) + config.InitGdgConfig(common.DefaultTestConfig) conf := config.Config().GetViperConfig(config.ViperGdgConfig) slog.Info(conf.ConfigFileUsed()) @@ -97,7 +97,7 @@ func TestWatchedFoldersConfig(t *testing.T) { // Ensures that if the config is on a completely different path, the searchPath is updated accordingly func TestSetupDifferentPath(t *testing.T) { cfgFile := DuplicateConfig(t) - config.InitGdgConfig(cfgFile, "") + config.InitGdgConfig(cfgFile) conf := config.Config().GetViperConfig(config.ViperGdgConfig) assert.NotNil(t, conf) context := conf.GetString("context_name") @@ -110,7 +110,7 @@ func TestSetupDifferentPath(t *testing.T) { func TestConfigEnv(t *testing.T) { os.Setenv("GDG_CONTEXT_NAME", "testing") os.Setenv("GDG_CONTEXTS__TESTING__URL", "www.google.com") - config.InitGdgConfig(common.DefaultTestConfig, "") + config.InitGdgConfig(common.DefaultTestConfig) conf := config.Config().GetViperConfig(config.ViperGdgConfig) context := conf.GetString("context_name") assert.Equal(t, context, "testing") @@ -120,7 +120,7 @@ func TestConfigEnv(t *testing.T) { assert.Equal(t, grafanaConfig.URL, url) os.Setenv("GDG_CONTEXT_NAME", "production") os.Setenv("GDG_CONTEXTS__PRODUCTION__URL", "grafana.com") - config.InitGdgConfig(common.DefaultTestConfig, "") + config.InitGdgConfig(common.DefaultTestConfig) conf = config.Config().GetViperConfig(config.ViperGdgConfig) url = conf.GetString("contexts.production.url") assert.Equal(t, url, "grafana.com") diff --git a/internal/config/template_config.go b/internal/config/template_config.go index 30ff852d..931f642b 100644 --- a/internal/config/template_config.go +++ b/internal/config/template_config.go @@ -30,8 +30,13 @@ func InitTemplateConfig(override string) { if configData == nil { log.Fatal("GDG configuration was not able to be loaded, cannot continue") } - appName := "templates" - configDirs, appName, ext := buildConfigSearchPath(override, appName) + var ext, appName string + var configDirs []string + if override == "" { + configDirs, appName, ext = buildConfigSearchPath("config/templates.yml") + } else { + configDirs, appName, ext = buildConfigSearchPath(override) + } configData.templatingConfig = new(TemplatingConfig) v, err := readViperConfig[TemplatingConfig](appName, configDirs, configData.templatingConfig, ext) diff --git a/internal/service/common_test.go b/internal/service/common_test.go index 7caa6e79..2aea26ec 100644 --- a/internal/service/common_test.go +++ b/internal/service/common_test.go @@ -15,14 +15,14 @@ func fixEnvironment(t *testing.T) { assert.NoError(t, path.FixTestDir("service", "../..")) err := os.Setenv("GDG_CONTEXT_NAME", "qa") assert.Nil(t, err) - config.InitGdgConfig(common.DefaultTestConfig, "'") + config.InitGdgConfig(common.DefaultTestConfig) } func TestRelativePathLogin(t *testing.T) { envKey := "GDG_CONTEXTS__QA__URL" assert.NoError(t, os.Setenv(envKey, "http://localhost:3000/grafana/")) fixEnvironment(t) - config.InitGdgConfig(common.DefaultTestConfig, "'") + config.InitGdgConfig(common.DefaultTestConfig) defer assert.NoError(t, os.Unsetenv(envKey)) svc := NewApiService("dummy") diff --git a/internal/templating/templating_test.go b/internal/templating/templating_test.go index 3184a059..1893311b 100644 --- a/internal/templating/templating_test.go +++ b/internal/templating/templating_test.go @@ -20,7 +20,7 @@ func TestGenerate(t *testing.T) { if strings.Contains(dir, "templating") { os.Chdir("../..") } - config.InitGdgConfig(common.DefaultTestConfig, "") + config.InitGdgConfig(common.DefaultTestConfig) config.InitTemplateConfig("templates-example") template := NewTemplate() data, err := template.Generate("template_example") diff --git a/pkg/test_tooling/common.go b/pkg/test_tooling/common.go index 3500bb76..101e4531 100644 --- a/pkg/test_tooling/common.go +++ b/pkg/test_tooling/common.go @@ -100,7 +100,7 @@ func CreateSimpleClient(t *testing.T, cfgName *string, container testcontainers. slog.Info("Grafana Test container running", slog.String("host", grafanaHost+"/login"), slog.String("imageVersion", dockerContainer.Image)) } - config.InitGdgConfig(*cfgName, "'") + config.InitGdgConfig(*cfgName) conf := config.Config().GetViperConfig(config.ViperGdgConfig) assert.NotNil(t, conf) // Hack for Local testing diff --git a/pkg/test_tooling/support.go b/pkg/test_tooling/support.go index e318fedf..8809b989 100644 --- a/pkg/test_tooling/support.go +++ b/pkg/test_tooling/support.go @@ -12,14 +12,12 @@ import ( applog "github.com/esnet/gdg/internal/log" "github.com/esnet/gdg/internal/service" "github.com/esnet/gdg/internal/service/mocks" - "github.com/esnet/gdg/pkg/test_tooling/common" - "github.com/stretchr/testify/assert" ) // SetupAndExecuteMockingServices will create a mock for varous required entities allowing to test the CLI flag parsing // process: function that setups mocks and invokes the Execute command -func SetupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.GrafanaService, data []byte, optionMockSvc func() support.RootOption) error) (string, func()) { +func SetupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.GrafanaService, optionMockSvc func() support.RootOption) error) (string, func()) { testSvc := new(mocks.GrafanaService) getMockSvc := func() service.GrafanaService { return testSvc @@ -32,10 +30,7 @@ func SetupAndExecuteMockingServices(t *testing.T, process func(mock *mocks.Grafa } r, w, cleanup := InterceptStdout() - data, err := os.ReadFile("config/" + common.DefaultTestConfig) - assert.Nil(t, err) - - err = process(testSvc, data, optionMockSvc) + err := process(testSvc, optionMockSvc) assert.Nil(t, err) defer cleanup() err = w.Close() @@ -60,7 +55,7 @@ func InterceptStdout() (*os.File, *os.File, context.CancelFunc) { panic(e) } // Restore streams - config.InitGdgConfig("testing", "") + config.InitGdgConfig("testing") cleanup := func() { os.Stdout = backupStd os.Stderr = backupErr @@ -68,7 +63,7 @@ func InterceptStdout() (*os.File, *os.File, context.CancelFunc) { } os.Stdout = w os.Stderr = w - applog.InitializeAppLogger(os.Stdout, os.Stderr, true) + applog.InitializeAppLogger(os.Stdout, os.Stderr, false) return r, w, cleanup }