diff --git a/cmd/osbuild-composer/config.go b/cmd/osbuild-composer/config.go index 8b9648f78..dd70dfcd9 100644 --- a/cmd/osbuild-composer/config.go +++ b/cmd/osbuild-composer/config.go @@ -6,6 +6,7 @@ import ( "os" "reflect" "strconv" + "strings" "github.com/BurntSushi/toml" ) @@ -14,7 +15,7 @@ type ComposerConfigFile struct { Koji KojiAPIConfig `toml:"koji"` Worker WorkerAPIConfig `toml:"worker"` WeldrAPI WeldrAPIConfig `toml:"weldr_api"` - DistroAliases map[string]string `toml:"distro_aliases"` + DistroAliases map[string]string `toml:"distro_aliases" env:"DISTRO_ALIASES"` LogLevel string `toml:"log_level"` LogFormat string `toml:"log_format"` DNFJson string `toml:"dnf-json"` @@ -143,6 +144,24 @@ func LoadConfig(name string) (*ComposerConfigFile, error) { return c, nil } +// envStrToMap converts map string to map[string]string +func envStrToMap(s string) (map[string]string, error) { + result := map[string]string{} + if s == "" { + return result, nil + } + + parts := strings.Split(s, ",") + for _, part := range parts { + keyValue := strings.Split(part, "=") + if len(keyValue) != 2 { + return nil, fmt.Errorf("Invalid key-value pair in map string: %s", part) + } + result[keyValue[0]] = keyValue[1] + } + return result, nil +} + func loadConfigFromEnv(intf interface{}) error { t := reflect.TypeOf(intf).Elem() v := reflect.ValueOf(intf).Elem() @@ -184,8 +203,23 @@ func loadConfigFromEnv(intf interface{}) error { // no-op continue case reflect.Map: - // no-op - continue + key, ok := fieldT.Tag.Lookup("env") + if !ok { + continue + } + // handle only map[string]string + if fieldV.Type().Key().Kind() != reflect.String || fieldV.Type().Elem().Kind() != reflect.String { + return fmt.Errorf("Unsupported map type for loading from ENV: %s", kind) + } + confV, ok := os.LookupEnv(key) + if !ok { + continue + } + value, err := envStrToMap(confV) + if err != nil { + return err + } + fieldV.Set(reflect.ValueOf(value)) case reflect.Struct: err := loadConfigFromEnv(fieldV.Addr().Interface()) if err != nil { diff --git a/cmd/osbuild-composer/config_test.go b/cmd/osbuild-composer/config_test.go index 1c4fe2bcf..4671becd0 100644 --- a/cmd/osbuild-composer/config_test.go +++ b/cmd/osbuild-composer/config_test.go @@ -3,6 +3,7 @@ package main import ( "bytes" "os" + "strings" "testing" "github.com/stretchr/testify/require" @@ -142,3 +143,39 @@ func TestDumpConfig(t *testing.T) { // DumpConfig takes a copy require.Equal(t, "sensitive", config.Worker.PGPassword) } + +func TestEnvStrToMap(t *testing.T) { + env := "key1=value1,key2=value2,key3=value3" + expected := map[string]string{ + "key1": "value1", + "key2": "value2", + "key3": "value3", + } + got, err := envStrToMap(env) + require.NoError(t, err) + require.Equal(t, expected, got) +} + +func TestConfigFromEnv(t *testing.T) { + // simulate the environment variables + currentEnv := os.Environ() + defer func() { + os.Clearenv() + for _, env := range currentEnv { + pair := strings.SplitN(env, "=", 2) + _ = os.Setenv(pair[0], pair[1]) + } + }() + + os.Setenv("DISTRO_ALIASES", "rhel-7=rhel-7.9,rhel-8=rhel-8.9,rhel-9=rhel-9.3,rhel-10.0=rhel-9.5") + expectedDistroAliases := map[string]string{ + "rhel-7": "rhel-7.9", + "rhel-8": "rhel-8.9", + "rhel-9": "rhel-9.3", + "rhel-10.0": "rhel-9.5", + } + + config, err := LoadConfig("") + require.NoError(t, err) + require.Equal(t, expectedDistroAliases, config.DistroAliases) +}