[MM-13895] Implement config migration command (#10508)
* [MM-13895] Implement config migration command * Discarding unused error
Этот коммит содержится в:
коммит произвёл
Jesús Espino
родитель
7272864bea
Коммит
0edad1c3fa
@@ -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]]
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user