[MM-13895] Implement config migration command (#10508)

* [MM-13895] Implement config migration command

* Discarding unused error
Этот коммит содержится в:
d28park
2019-04-03 23:15:51 -07:00
коммит произвёл Jesús Espino
родитель 7272864bea
Коммит 0edad1c3fa
2 изменённых файлов: 85 добавлений и 0 удалений

Просмотреть файл

@@ -68,8 +68,19 @@ var ConfigSetCmd = &cobra.Command{
RunE: configSetCmdF,
}
var MigrateConfigCmd = &cobra.Command{
Use: "migrate",
Short: "Migrate existing config between backends",
Long: "Migrate a file-based configuration to (or from) a database-based configuration. Point the Mattermost server at the target configuration to start using it",
Example: `config migrate --from=path/to/config.json --to="postgres://mmuser:mostest@dockerhost:5432/mattermost_test?sslmode=disable&connect_timeout=10"`,
RunE: configMigrateCmdF,
}
func init() {
ConfigSubpathCmd.Flags().String("path", "", "Optional subpath; defaults to value in SiteURL")
MigrateConfigCmd.Flags().String("from", "", "Config from which to migrate")
MigrateConfigCmd.Flags().String("to", "", "Config to which to migrate")
MigrateConfigCmd.MarkFlagRequired("to")
ConfigCmd.AddCommand(
ValidateConfigCmd,
@@ -77,6 +88,7 @@ func init() {
ConfigGetCmd,
ConfigShowCmd,
ConfigSetCmd,
MigrateConfigCmd,
)
RootCmd.AddCommand(ConfigCmd)
}
@@ -217,6 +229,40 @@ func configSetCmdF(command *cobra.Command, args []string) error {
return nil
}
func configMigrateCmdF(command *cobra.Command, args []string) error {
// Parse source config; defaults to global --config unless overwritten by --from
from, err := command.Flags().GetString("from")
if err != nil {
return errors.Wrap(err, "failed reading source config parameter")
}
if from == "" {
from = viper.GetString("config")
}
// Parse destination config store - MarkFlagRequired handles errors here
to, _ := command.Flags().GetString("to")
// Get source config store - invalid config will throw error here
fromConfigStore, err := config.NewStore(from, false)
if err != nil {
return errors.Wrap(err, "failed to read --from config")
}
// Get destination config store
toConfigStore, err := config.NewStore(to, false)
if err != nil {
return errors.Wrap(err, "failed to read --to config")
}
// Copy config from source to destination
_, err = toConfigStore.Set(fromConfigStore.Get())
if err != nil {
return errors.Wrap(err, "failed to migrate config")
}
return nil
}
func updateConfigValue(configSetting string, newVal []string, oldConfig, newConfig *model.Config) func(*model.Config) {
return func(update *model.Config) {

Просмотреть файл

@@ -4,6 +4,8 @@
package commands
import (
"fmt"
"github.com/mattermost/mattermost-server/config"
"io/ioutil"
"os"
"reflect"
@@ -435,6 +437,43 @@ func TestUpdateMap(t *testing.T) {
}
func TestConfigMigrate(t *testing.T) {
th := Setup()
defer th.TearDown()
sqlSettings := mainHelper.GetSqlSettings()
sqlDSN := fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)
fileDSN := "config.json"
ds, err := config.NewStore(sqlDSN, false)
require.NoError(t, err)
fs, err := config.NewStore(fileDSN, false)
require.NoError(t, err)
defer ds.Close()
defer fs.Close()
t.Run("Should error without --to parameter", func(t *testing.T) {
assert.Error(t, th.RunCommand(t, "config", "migrate", "--from", fileDSN))
})
t.Run("Should work passing the --to and the --from", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "migrate", "--from", fileDSN, "--to", sqlDSN))
})
t.Run("Should work passing --to and no --from (taking the default config file)", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "migrate", "--to", sqlDSN))
})
t.Run("Should fail passing an invalid --to", func(t *testing.T) {
assert.Error(t, th.RunCommand(t, "config", "migrate", "--from", fileDSN, "--to", "mysql://asd"))
})
t.Run("Should fail passing an invalid --from", func(t *testing.T) {
assert.Error(t, th.RunCommand(t, "config", "migrate", "--from", "invalid/path", "--to", sqlDSN))
})
}
func contains(configMap map[string]interface{}, v interface{}, configSettings []string) bool {
res := configMap[configSettings[0]]