diff --git a/controllers/nginx/nginx/template.go b/controllers/nginx/nginx/template.go index fc67cfd1c..b7ad6f418 100644 --- a/controllers/nginx/nginx/template.go +++ b/controllers/nginx/nginx/template.go @@ -48,10 +48,6 @@ func (ngx *Manager) loadTemplate() { } func (ngx *Manager) writeCfg(cfg nginxConfiguration, ingressCfg IngressConfig) (bool, error) { - fromMap := structs.Map(cfg) - toMap := structs.Map(ngx.defCfg) - curNginxCfg := merge(toMap, fromMap) - conf := make(map[string]interface{}) conf["upstreams"] = ingressCfg.Upstreams conf["servers"] = ingressCfg.Servers @@ -59,7 +55,7 @@ func (ngx *Manager) writeCfg(cfg nginxConfiguration, ingressCfg IngressConfig) ( conf["udpUpstreams"] = ingressCfg.UDPUpstreams conf["defResolver"] = ngx.defResolver conf["sslDHParam"] = ngx.sslDHParam - conf["cfg"] = fixKeyNames(curNginxCfg) + conf["cfg"] = fixKeyNames(structs.Map(cfg)) buffer := new(bytes.Buffer) err := ngx.template.Execute(buffer, conf) diff --git a/controllers/nginx/nginx/utils.go b/controllers/nginx/nginx/utils.go index 7c8656192..c4bfa8d8c 100644 --- a/controllers/nginx/nginx/utils.go +++ b/controllers/nginx/nginx/utils.go @@ -59,18 +59,36 @@ func getDNSServers() []string { return nameservers } +// getConfigKeyToStructKeyMap returns a map with the ConfigMapKey as key and the StructName as value. +func getConfigKeyToStructKeyMap() map[string]string { + keyMap := map[string]string{} + n := &nginxConfiguration{} + val := reflect.Indirect(reflect.ValueOf(n)) + for i := 0; i < val.Type().NumField(); i++ { + fieldSt := val.Type().Field(i) + configMapKey := strings.Split(fieldSt.Tag.Get("structs"), ",")[0] + structKey := fieldSt.Name + keyMap[configMapKey] = structKey + } + return keyMap +} + // ReadConfig obtains the configuration defined by the user merged with the defaults. func (ngx *Manager) ReadConfig(config *api.ConfigMap) nginxConfiguration { if len(config.Data) == 0 { return newDefaultNginxCfg() } - cfg := newDefaultNginxCfg() + cfgCM := nginxConfiguration{} + cfgDefault := newDefaultNginxCfg() + + metadata := &mapstructure.Metadata{} decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ TagName: "structs", - Result: &cfg, + Result: &cfgCM, WeaklyTypedInput: true, + Metadata: metadata, }) err = decoder.Decode(config.Data) @@ -78,7 +96,26 @@ func (ngx *Manager) ReadConfig(config *api.ConfigMap) nginxConfiguration { glog.Infof("%v", err) } - return cfg + keyMap := getConfigKeyToStructKeyMap() + + valCM := reflect.Indirect(reflect.ValueOf(cfgCM)) + + for _, key := range metadata.Keys { + fieldName, ok := keyMap[key] + if !ok { + continue + } + + valDefault := reflect.ValueOf(&cfgDefault).Elem().FieldByName(fieldName) + + fieldCM := valCM.FieldByName(fieldName) + + if valDefault.IsValid() { + valDefault.Set(fieldCM) + } + } + + return cfgDefault } func (ngx *Manager) needsReload(data *bytes.Buffer) (bool, error) { @@ -143,21 +180,6 @@ func diff(b1, b2 []byte) (data []byte, err error) { return } -func merge(dst, src map[string]interface{}) map[string]interface{} { - for key, srcVal := range src { - if dstVal, ok := dst[key]; ok { - srcMap, srcMapOk := toMap(srcVal) - dstMap, dstMapOk := toMap(dstVal) - if srcMapOk && dstMapOk { - srcVal = merge(dstMap, srcMap) - } - } - dst[key] = srcVal - } - - return dst -} - func toMap(iface interface{}) (map[string]interface{}, bool) { value := reflect.ValueOf(iface) if value.Kind() == reflect.Map { diff --git a/controllers/nginx/nginx/utils_test.go b/controllers/nginx/nginx/utils_test.go new file mode 100644 index 000000000..fc7008a1e --- /dev/null +++ b/controllers/nginx/nginx/utils_test.go @@ -0,0 +1,89 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package nginx + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" +) + +func getConfigNginxBool(data map[string]string) nginxConfiguration { + manager := &Manager{} + configMap := &api.ConfigMap{ + Data: data, + } + return manager.ReadConfig(configMap) +} + +func TestManagerReadConfigBoolFalse(t *testing.T) { + configNginx := getConfigNginxBool(map[string]string{ + "hts-include-subdomains": "false", + "use-proxy-protocol": "false", + }) + if configNginx.HTSIncludeSubdomains { + t.Error("Failed to config boolean value (default true) to false") + } + if configNginx.UseProxyProtocol { + t.Error("Failed to config boolean value (default false) to false") + } +} + +func TestManagerReadConfigBoolTrue(t *testing.T) { + configNginx := getConfigNginxBool(map[string]string{ + "hts-include-subdomains": "true", + "use-proxy-protocol": "true", + }) + if !configNginx.HTSIncludeSubdomains { + t.Error("Failed to config boolean value (default true) to true") + } + if !configNginx.UseProxyProtocol { + t.Error("Failed to config boolean value (default false) to true") + } +} + +func TestManagerReadConfigBoolNothing(t *testing.T) { + configNginx := getConfigNginxBool(map[string]string{ + "invaild-key": "true", + }) + if !configNginx.HTSIncludeSubdomains { + t.Error("Failed to get default boolean value true") + } + if configNginx.UseProxyProtocol { + t.Error("Failed to get default boolean value false") + } +} + +func TestManagerReadConfigStringSet(t *testing.T) { + configNginx := getConfigNginxBool(map[string]string{ + "ssl-protocols": "TLSv1.2", + }) + exp := "TLSv1.2" + if configNginx.SSLProtocols != exp { + t.Error("Failed to set string value true actual='%s' expected='%s'", configNginx.SSLProtocols, exp) + } +} + +func TestManagerReadConfigStringNothing(t *testing.T) { + configNginx := getConfigNginxBool(map[string]string{ + "not-existing": "TLSv1.2", + }) + exp := "10m" + if configNginx.SSLSessionTimeout != exp { + t.Error("Failed to set string value true actual='%s' expected='%s'", configNginx.SSLSessionTimeout, exp) + } +}