[MM-59503] export: enable exporting configuration with mmctl (#28412)

Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2024-12-17 10:23:52 +01:00
коммит произвёл GitHub
родитель ca72cdb445
Коммит 424ce2b8db
15 изменённых файлов: 577 добавлений и 11 удалений

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

@@ -4576,6 +4576,66 @@ func (o *Config) Sanitize(pluginManifests []*Manifest) {
o.PluginSettings.Sanitize(pluginManifests)
}
type FilterTag struct {
TagType string
TagName string
}
type ConfigFilterOptions struct {
GetConfigOptions
TagFilters []FilterTag
}
type GetConfigOptions struct {
RemoveMasked bool
RemoveDefaults bool
}
// FilterConfig returns a map[string]any representation of the configuration.
// Also, the function can filter the configuration by the options passed
// in the argument. The options are used to remove the default values, the masked
// values and to filter the configuration by the tags passed in the TagFilters.
func FilterConfig(cfg *Config, opts ConfigFilterOptions) (map[string]any, error) {
if cfg == nil {
return nil, nil
}
defaultCfg := &Config{}
defaultCfg.SetDefaults()
filteredCfg, err := cfg.StringMap()
if err != nil {
return nil, err
}
filteredDefaultCfg, err := defaultCfg.StringMap()
if err != nil {
return nil, err
}
for i := range opts.TagFilters {
filteredCfg = structToMapFilteredByTag(filteredCfg, opts.TagFilters[i].TagType, opts.TagFilters[i].TagName)
filteredDefaultCfg = structToMapFilteredByTag(defaultCfg, opts.TagFilters[i].TagType, opts.TagFilters[i].TagName)
}
if opts.RemoveDefaults {
filteredCfg = stringMapDiff(filteredCfg, filteredDefaultCfg)
}
if opts.RemoveMasked {
removeFakeSettings(filteredCfg)
}
// only apply this if we applied some filters
// the alternative is to remove empty maps and slices during the filters
// but having this in a separate step makes it easier to understand
if opts.RemoveDefaults || opts.RemoveMasked || len(opts.TagFilters) > 0 {
removeEmptyMapsAndSlices(filteredCfg)
}
return filteredCfg, nil
}
// structToMapFilteredByTag converts a struct into a map removing those fields that has the tag passed
// as argument
func structToMapFilteredByTag(t any, typeOfTag, filterTag string) map[string]any {
@@ -4625,6 +4685,90 @@ func structToMapFilteredByTag(t any, typeOfTag, filterTag string) map[string]any
return out
}
// removeEmptyMapsAndSlices removes all the empty maps and slices from a map
func removeEmptyMapsAndSlices(m map[string]any) {
for k, v := range m {
switch vt := v.(type) {
case map[string]any:
removeEmptyMapsAndSlices(vt)
if len(vt) == 0 {
delete(m, k)
}
case []any:
if len(vt) == 0 {
delete(m, k)
}
}
}
}
// StringMap returns a map[string]any representation of the Config struct
func (o *Config) StringMap() (map[string]any, error) {
b, err := json.Marshal(o)
if err != nil {
return nil, err
}
var result map[string]any
err = json.Unmarshal(b, &result)
if err != nil {
return nil, err
}
return result, nil
}
// stringMapDiff returns the difference between two maps with string keys
func stringMapDiff(m1, m2 map[string]any) map[string]any {
result := make(map[string]any)
for k, v := range m1 {
if _, ok := m2[k]; !ok {
result[k] = v // ideally this should be never reached
}
if reflect.DeepEqual(v, m2[k]) {
continue
}
switch v.(type) {
case map[string]any:
// this happens during the serialization of the struct to map
// so we can safely assume that the type is not matching, there
// is a difference in the values
casted, ok := m2[k].(map[string]any)
if !ok {
result[k] = v
continue
}
res := stringMapDiff(v.(map[string]any), casted)
if len(res) > 0 {
result[k] = res
}
default:
result[k] = v
}
}
return result
}
// removeFakeSettings removes all the fields that have the value of FakeSetting
// it's necessary to remove the fields that have been masked to be able to
// export the configuration (and make it importable)
func removeFakeSettings(m map[string]any) {
for k, v := range m {
switch vt := v.(type) {
case map[string]any:
removeFakeSettings(vt)
case string:
if v == FakeSetting {
delete(m, k)
}
}
}
}
func isTagPresent(tag string, tags []string) bool {
for _, val := range tags {
tagValue := strings.TrimSpace(val)