diff --git a/.gitignore b/.gitignore index 1b68f99..775bbbb 100644 --- a/.gitignore +++ b/.gitignore @@ -28,5 +28,6 @@ dist/ builds/ # Config files +/lagoon *.lagoon-sync *.lagoon-sync-defaults \ No newline at end of file diff --git a/README.md b/README.md index 4aedeba..cc1b700 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ The order of configuration precedence is as follows: 1. `--config` argument (e.g. `lagoon-sync [command] --config ./.custom-lagoon-sync-config.yaml`). 2. `.lagoon.yaml` files (i.e. in project root, or `lagoon` directory). If an `.lagoon.yml` is available within the project, then this file will be used as the active configuration file by default. 3. `LAGOON_SYNC_PATH` or `LAGOON_SYNC_DEFAULTS_PATH` environment variables. - +4. Finally, if no config file can be found the default configuration will be used a safely written to a new '.lagoon.yml` There are some configuration examples in the `examples` directory of this repo. diff --git a/assets/lagoon.yml b/assets/lagoon.yml new file mode 100644 index 0000000..ac58245 --- /dev/null +++ b/assets/lagoon.yml @@ -0,0 +1,44 @@ +lagoon-sync: + ssh: + host: "ssh.lagoon.amazeeio.cloud" + port: "32222" + mariadb: + config: + hostname: "${MARIADB_HOST:-mariadb}" + username: "${MARIADB_USERNAME:-drupal}" + password: "${MARIADB_PASSWORD:-drupal}" + port: "${MARIADB_PORT:-3306}" + database: "${MARIADB_DATABASE:-drupal}" + postgres: + config: + hostname: "${POSTGRES_HOST:-postgres}" + username: "${POSTGRES_USERNAME:-drupal}" + password: "${POSTGRES_PASSWORD:-drupal}" + port: "5432" + database: "${POSTGRES_DATABASE:-drupal}" + local: + config: + port: "3306" + mongodb: + config: + hostname: "$MONGODB_HOST" + port: "$MONGODB_SERVICE_PORT" + database: "MONGODB_DATABASE" + local: + config: + hostname: "$MONGODB_HOST" + port: "27017" + database: "local" + files: + config: + sync-directory: "/app/web/sites/default/files" + local: + config: + sync-directory: "/app/web/sites/default/files" + drupalconfig: + config: + syncpath: "./config/sync" + local: + overrides: + config: + syncpath: "./config/sync" diff --git a/assets/main.go b/assets/main.go index 73c3cdd..0572f71 100644 --- a/assets/main.go +++ b/assets/main.go @@ -8,6 +8,9 @@ import ( //go:embed .version var Version []byte +//go:embed lagoon.yml +var DefaultConfigData []byte + //go:embed rsync var RsyncLinuxBinBytes []byte @@ -15,6 +18,10 @@ func GetVersion() string { return strings.TrimSuffix(string(Version), "\n") } +func GetDefaultConfig() ([]byte, error) { + return DefaultConfigData, nil +} + func RsyncBin() []byte { return RsyncLinuxBinBytes -} \ No newline at end of file +} diff --git a/cmd/config.go b/cmd/config.go index a2ae8b2..cafbf05 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -3,6 +3,7 @@ package cmd import ( "encoding/json" "fmt" + "io/ioutil" "log" "os" @@ -39,6 +40,14 @@ var configCmd = &cobra.Command{ }, } +func LoadLagoonConfig(lagoonYamlPath string) ([]byte, error) { + var data, err = ioutil.ReadFile(lagoonYamlPath) + if err != nil { + return []byte{}, err + } + return data, nil +} + func PrintConfigOut() []byte { lagoonSyncDefaultsFile, exists := os.LookupEnv("LAGOON_SYNC_DEFAULTS_PATH") if !exists { @@ -53,7 +62,7 @@ func PrintConfigOut() []byte { activeLagoonYmlFile := viper.ConfigFileUsed() // Gather lagoon.yml configuration - lagoonConfigBytestream, err := LoadLagoonConfig(cfgFile) + lagoonConfigBytestream, err := LoadLagoonConfig(activeLagoonYmlFile) if err != nil { utils.LogFatalError("Couldn't load lagoon config file - ", err.Error()) } diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 5ad86c8..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package cmd - -import "io/ioutil" - -func LoadLagoonConfig(lagoonYamlPath string) ([]byte, error) { - var data, err = ioutil.ReadFile(lagoonYamlPath) - if err != nil { - return []byte{}, err - } - return data, nil -} diff --git a/cmd/root.go b/cmd/root.go index 43ed380..aba0074 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,8 +1,10 @@ package cmd import ( + "bytes" "fmt" "os" + "path/filepath" "github.com/uselagoon/lagoon-sync/assets" @@ -48,7 +50,7 @@ func init() { // Cobra supports persistent flags, which, if defined here, // will be global for your application. - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "./.lagoon.yml", "config file (default is .lagoon.yaml)") + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Path to the file used to set lagoon-sync configuration") rootCmd.PersistentFlags().BoolVar(&ShowDebug, "show-debug", false, "Shows debug information") viper.BindPFlag("show-debug", rootCmd.PersistentFlags().Lookup("show-debug")) @@ -58,77 +60,103 @@ func init() { } func initConfig() { - // Find home directory. - home, err := homedir.Dir() + err := processConfig(cfgFile) if err != nil { - fmt.Println(err) + utils.LogFatalError("Unable to read in config file", err) os.Exit(1) } +} - paths := []string{home, "/lagoon", "/tmp"} +func processConfig(cfgFile string) error { + // If cfgFile arg given, return early + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + viper.AutomaticEnv() - cfgFile, err = processConfigEnv(paths, cfgFile) - if err != nil { - utils.LogFatalError("Unable to read in config file", err) - os.Exit(1) + if err := viper.ReadInConfig(); err == nil { + utils.LogDebugInfo("Using config file", viper.ConfigFileUsed()) + } else { + return fmt.Errorf("failed to read config file: %v", err) + } + + return nil } -} -// initConfig reads in config file and ENV variables if set. -func processConfigEnv(paths []string, DefaultConfigFileName string) (string, error) { + home, err := homedir.Dir() + if err != nil { + return fmt.Errorf("unable to find home directory: %v", err) + } - // Search config in home directory with name ".lagoon-sync" (without extension). + paths := []string{".", "./lagoon", "/tmp", home} for _, path := range paths { viper.AddConfigPath(path) } - viper.SetConfigName(DefaultConfigFileName) + viper.SetConfigName(cfgFile) viper.SetConfigType("yaml") - // Find default config file for env vars (e.g. 'lagoon-sync-defaults') - lagoonSyncDefaultsFile, exists := os.LookupEnv("LAGOON_SYNC_DEFAULTS_PATH") - if exists { - utils.LogDebugInfo("LAGOON_SYNC_DEFAULTS_PATH env var found", lagoonSyncDefaultsFile) - } else { - lagoonSyncDefaultsFile = "/lagoon/.lagoon-sync-defaults" + // Find config file from env vars (e.g., 'LAGOON_SYNC_DEFAULTS_PATH' and 'LAGOON_SYNC_PATH') + defaultFiles := map[string]string{ + "LAGOON_SYNC_DEFAULTS_PATH": "/lagoon/.lagoon-sync-defaults", + "LAGOON_SYNC_PATH": "/lagoon/.lagoon-sync", } - // Find lagoon-sync config file (e.g. 'lagoon-sync') - lagoonSyncCfgFile, exists := os.LookupEnv("LAGOON_SYNC_PATH") - if exists { - utils.LogDebugInfo("LAGOON_SYNC_PATH env var found", lagoonSyncCfgFile) - } else { - lagoonSyncCfgFile = "/lagoon/.lagoon-sync" + for envVar, defaultFile := range defaultFiles { + filePath, exists := os.LookupEnv(envVar) + if exists { + utils.LogDebugInfo(envVar+" env var found", filePath) + if utils.FileExists(filePath) { + viper.SetConfigFile(filePath) + cfgFile = filePath + break + } + } else { + if utils.FileExists(defaultFile) { + viper.SetConfigFile(defaultFile) + cfgFile = defaultFile + break + } + } } - if DefaultConfigFileName != "" { - // Use config file from the flag, default for this is '.lagoon.yml' - if utils.FileExists(DefaultConfigFileName) { - viper.SetConfigName(DefaultConfigFileName) - viper.SetConfigFile(DefaultConfigFileName) + // Next, check for 'lagoon.yml' files in the default locations and override. + for _, path := range paths { + filePath := filepath.Join(path, ".lagoon.yml") + if utils.FileExists(filePath) { + cfgFile = filePath + break } + } - // Set '.lagoon-sync-defaults' as config file is it exists. - if utils.FileExists(lagoonSyncDefaultsFile) { - viper.SetConfigName(lagoonSyncDefaultsFile) - viper.SetConfigFile(lagoonSyncDefaultsFile) - DefaultConfigFileName = lagoonSyncDefaultsFile - } + // Set the config file if found + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + viper.AutomaticEnv() - // Set '.lagoon-sync' as config file is it exists. - if utils.FileExists(lagoonSyncCfgFile) { - viper.SetConfigName(lagoonSyncCfgFile) - viper.SetConfigFile(lagoonSyncCfgFile) - DefaultConfigFileName = lagoonSyncCfgFile + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + utils.LogDebugInfo("Using config file", viper.ConfigFileUsed()) + } else { + return fmt.Errorf("failed to read config file: %v", err) + } + } else { + // If no config file is found, load the default config + defaultConfigData, err := assets.GetDefaultConfig() + if err != nil { + return fmt.Errorf("failed to load default config: %v", err) } - } - viper.AutomaticEnv() // read in environment variables that match + viper.SetConfigType("yaml") + viper.SetConfigName("default") - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - utils.LogDebugInfo("Using config file", viper.ConfigFileUsed()) - } else { - return "", err + err = viper.ReadConfig(bytes.NewBuffer(defaultConfigData)) + if err != nil { + return fmt.Errorf("failed to read default config: %v", err) + } + + // Then safe-write config to '.lagoon.yml' when it doesn't exist + viper.SafeWriteConfigAs(".lagoon.yml") + viper.SetConfigFile(".lagoon.yml") } - return DefaultConfigFileName, nil + + return nil } diff --git a/examples/.drupal-example.yml b/examples/.drupal-example.yml new file mode 100644 index 0000000..9287127 --- /dev/null +++ b/examples/.drupal-example.yml @@ -0,0 +1,33 @@ +lagoon-sync: + mariadb: + config: + hostname: "$MARIADB_HOST" + username: "$MARIADB_USERNAME" + password: "$MARIADB_PASSWORD" + port: "$MARIADB_PORT" + database: "$MARIADB_DATABASE" + ignore-table: + - "table_to_ignore" + ignore-table-data: + - "cache_data" + - "cache_menu" + local: + config: + hostname: "mariadb" + username: "drupal" + password: "drupal" + port: "3306" + database: "drupal" + files: + config: + sync-directory: "/app/web/sites/default/files" + local: + config: + sync-directory: "/app/web/sites/default/files" + drupalconfig: + config: + syncpath: "./config/sync" + local: + overrides: + config: + syncpath: "./config/sync" \ No newline at end of file diff --git a/.example-lagoon-sync b/examples/.lagoon.yml similarity index 88% rename from .example-lagoon-sync rename to examples/.lagoon.yml index bff6322..6735aa3 100644 --- a/.example-lagoon-sync +++ b/examples/.lagoon.yml @@ -1,3 +1,8 @@ +# Example .lagoon.yml file with lagoon-sync config added which is used by the sync tool. +docker-compose-yaml: docker-compose.yml + +project: "lagoon-sync" + lagoon-sync: mariadb: config: @@ -59,4 +64,4 @@ lagoon-sync: local: overrides: config: - syncpath: "./config/sync" \ No newline at end of file + syncpath: "./config/sync"