You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2022/02/18 13:04:45 UTC

[dubbo-go] branch 3.0 updated: config merge (#1754)

This is an automated email from the ASF dual-hosted git repository.

alexstocks pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 074eac7  config merge (#1754)
074eac7 is described below

commit 074eac796f597ee8b0c1388b00c372617e244e1b
Author: zhaoyunxing <zh...@apache.org>
AuthorDate: Fri Feb 18 21:04:36 2022 +0800

    config merge (#1754)
    
    * config merge
    
    * fmt
    
    * add license
    
    * fix npe
    
    * up test
    
    * 代码优化
    
    * add active ut
---
 common/constant/key.go                             |  1 +
 config/config_loader.go                            |  1 +
 config/config_loader_options.go                    | 80 ++++++++++++++++++----
 config/config_loader_options_test.go               | 36 ++++++++++
 config/profiles_config.go                          | 44 ++++++++++++
 config/profiles_config_test.go                     | 75 ++++++++++++++++++++
 config/root_config.go                              |  3 +
 .../testdata/config/active/application-local.yaml  | 16 +++++
 config/testdata/config/active/application.yaml     |  7 ++
 9 files changed, 251 insertions(+), 12 deletions(-)

diff --git a/common/constant/key.go b/common/constant/key.go
index 6480841..2b7ef46 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -220,6 +220,7 @@ const (
 	TracingConfigPrefix        = "dubbo.tracing"
 	LoggerConfigPrefix         = "dubbo.logger"
 	CustomConfigPrefix         = "dubbo.custom"
+	ProfilesConfigPrefix       = "dubbo.profiles"
 )
 
 const (
diff --git a/config/config_loader.go b/config/config_loader.go
index 8b8b09a..99c35b2 100644
--- a/config/config_loader.go
+++ b/config/config_loader.go
@@ -45,6 +45,7 @@ func Load(opts ...LoaderConfOption) error {
 	conf := NewLoaderConf(opts...)
 	if conf.rc == nil {
 		koan := GetConfigResolver(conf)
+		koan = conf.MergeConfig(koan)
 		if err := koan.UnmarshalWithConf(rootConfig.Prefix(),
 			rootConfig, koanf.UnmarshalConf{Tag: "yaml"}); err != nil {
 			return err
diff --git a/config/config_loader_options.go b/config/config_loader_options.go
index d2cd1b7..0cd062f 100644
--- a/config/config_loader_options.go
+++ b/config/config_loader_options.go
@@ -26,19 +26,22 @@ import (
 )
 
 import (
+	"github.com/knadh/koanf"
+
 	"github.com/pkg/errors"
 )
 
 import (
 	"dubbo.apache.org/dubbo-go/v3/common/constant"
 	"dubbo.apache.org/dubbo-go/v3/common/file"
+	"dubbo.apache.org/dubbo-go/v3/common/logger"
 )
 
 type loaderConf struct {
 	// loaderConf file extension default yaml
 	suffix string
 
-	// loaderConf file path default ./conf
+	// loaderConf file path default ./conf/dubbogo.yaml
 	path string
 
 	// loaderConf file delim default .
@@ -49,18 +52,22 @@ type loaderConf struct {
 
 	// user provide rootConfig built by config api
 	rc *RootConfig
+
+	// config file name
+	name string
 }
 
 func NewLoaderConf(opts ...LoaderConfOption) *loaderConf {
-	configFilePath := "../conf/dubbogo.yaml"
+	configFilePath := "./conf/dubbogo.yaml"
 	if configFilePathFromEnv := os.Getenv(constant.ConfigFileEnvKey); configFilePathFromEnv != "" {
 		configFilePath = configFilePathFromEnv
 	}
-	suffix := strings.Split(configFilePath, ".")
+	name, suffix := resolverFilePath(configFilePath)
 	conf := &loaderConf{
-		suffix: suffix[len(suffix)-1],
+		suffix: suffix,
 		path:   absolutePath(configFilePath),
 		delim:  ".",
+		name:   name,
 	}
 	for _, opt := range opts {
 		opt.apply(conf)
@@ -69,11 +76,11 @@ func NewLoaderConf(opts ...LoaderConfOption) *loaderConf {
 		return conf
 	}
 	if len(conf.bytes) <= 0 {
-		bytes, err := ioutil.ReadFile(conf.path)
-		if err != nil {
+		if bytes, err := ioutil.ReadFile(conf.path); err != nil {
 			panic(err)
+		} else {
+			conf.bytes = bytes
 		}
-		conf.bytes = bytes
 	}
 	return conf
 }
@@ -111,13 +118,14 @@ func WithSuffix(suffix file.Suffix) LoaderConfOption {
 func WithPath(path string) LoaderConfOption {
 	return loaderConfigFunc(func(conf *loaderConf) {
 		conf.path = absolutePath(path)
-		bytes, err := ioutil.ReadFile(path)
-		if err != nil {
+		if bytes, err := ioutil.ReadFile(path); err != nil {
 			panic(err)
+		} else {
+			conf.bytes = bytes
 		}
-		conf.bytes = bytes
-		genre := strings.Split(path, ".")
-		conf.suffix = genre[len(genre)-1]
+		name, suffix := resolverFilePath(path)
+		conf.suffix = suffix
+		conf.name = name
 	})
 }
 
@@ -180,3 +188,51 @@ func checkFileSuffix(suffix string) error {
 	}
 	return errors.Errorf("no support file suffix: %s", suffix)
 }
+
+//resolverFilePath resolver file path
+// eg: give a ./conf/dubbogo.yaml return dubbogo and yaml
+func resolverFilePath(path string) (name, suffix string) {
+	paths := strings.Split(path, "/")
+	fileName := strings.Split(paths[len(paths)-1], ".")
+	if len(fileName) < 2 {
+		return fileName[0], string(file.YAML)
+	}
+	return fileName[0], fileName[1]
+}
+
+//MergeConfig merge config file
+func (conf *loaderConf) MergeConfig(koan *koanf.Koanf) *koanf.Koanf {
+	var (
+		activeKoan *koanf.Koanf
+		activeConf *loaderConf
+	)
+	active := koan.String("dubbo.profiles.active")
+	active = getLegalActive(active)
+	logger.Infof("The following profiles are active: %s", active)
+	if defaultActive != active {
+		path := conf.getActiveFilePath(active)
+		if !pathExists(path) {
+			logger.Debugf("Config file:%s not exist skip config merge", path)
+			return koan
+		}
+		activeConf = NewLoaderConf(WithPath(path))
+		activeKoan = GetConfigResolver(activeConf)
+		if err := koan.Merge(activeKoan); err != nil {
+			logger.Debugf("Config merge err %s", err)
+		}
+	}
+	return koan
+}
+
+func (conf *loaderConf) getActiveFilePath(active string) string {
+	suffix := constant.DotSeparator + conf.suffix
+	return strings.ReplaceAll(conf.path, suffix, "") + "-" + active + suffix
+}
+
+func pathExists(path string) bool {
+	if _, err := os.Stat(path); err == nil {
+		return true
+	} else {
+		return !os.IsNotExist(err)
+	}
+}
diff --git a/config/config_loader_options_test.go b/config/config_loader_options_test.go
index 01b517a..2ace22b 100644
--- a/config/config_loader_options_test.go
+++ b/config/config_loader_options_test.go
@@ -18,6 +18,7 @@
 package config
 
 import (
+	"strings"
 	"testing"
 )
 
@@ -71,3 +72,38 @@ func TestNewLoaderConf_WithSuffix(t *testing.T) {
 
 	assert.Equal(t, conf.suffix, string(file.PROPERTIES))
 }
+
+func TestResolverFilePath(t *testing.T) {
+	name, suffix := resolverFilePath("../config/application.properties")
+	assert.Equal(t, name, "application")
+	assert.Equal(t, suffix, "properties")
+}
+
+func TestResolverFilePath_Illegal_Path(t *testing.T) {
+	name, suffix := resolverFilePath("application.properties")
+	assert.Equal(t, name, "application")
+	assert.Equal(t, suffix, "properties")
+}
+
+func TestResolverFilePath_Illegal_Path_Name(t *testing.T) {
+	name, suffix := resolverFilePath("application")
+	assert.Equal(t, name, "application")
+	assert.Equal(t, suffix, string(file.YAML))
+}
+
+func Test_getActiveFilePath(t *testing.T) {
+	conf := NewLoaderConf(
+		WithSuffix(file.JSON),
+		WithPath("../config/testdata/config/properties/application.properties"),
+	)
+
+	filePath := conf.getActiveFilePath("dev")
+
+	assert.Equal(t, strings.HasSuffix(filePath, "application-dev.properties"), true)
+
+	exists := pathExists(filePath)
+	assert.Equal(t, exists, false)
+	exists = pathExists("application.properties")
+	assert.Equal(t, exists, false)
+
+}
diff --git a/config/profiles_config.go b/config/profiles_config.go
new file mode 100644
index 0000000..a47c8a7
--- /dev/null
+++ b/config/profiles_config.go
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 config
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+var (
+	defaultActive = "default"
+)
+
+type ProfilesConfig struct {
+	// active profiles
+	Active string
+}
+
+// Prefix dubbo.profiles
+func (ProfilesConfig) Prefix() string {
+	return constant.ProfilesConfigPrefix
+}
+
+// getLegalActive if active is null return default
+func getLegalActive(active string) string {
+	if len(active) == 0 {
+		return defaultActive
+	}
+	return active
+}
diff --git a/config/profiles_config_test.go b/config/profiles_config_test.go
new file mode 100644
index 0000000..45e31f4
--- /dev/null
+++ b/config/profiles_config_test.go
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 config
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/knadh/koanf"
+
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+func TestProfilesConfig_Prefix(t *testing.T) {
+	profiles := &ProfilesConfig{}
+	assert.Equal(t, profiles.Prefix(), constant.ProfilesConfigPrefix)
+}
+
+func TestLoaderConf_MergeConfig(t *testing.T) {
+	rc := NewRootConfigBuilder().Build()
+	conf := NewLoaderConf(WithPath("./testdata/config/active/application.yaml"))
+	koan := GetConfigResolver(conf)
+	koan = conf.MergeConfig(koan)
+
+	err := koan.UnmarshalWithConf(rc.Prefix(), rc, koanf.UnmarshalConf{Tag: "yaml"})
+	assert.Nil(t, err)
+
+	registries := rc.Registries
+	assert.NotNil(t, registries)
+	assert.Equal(t, registries["nacos"].Timeout, "10s")
+	assert.Equal(t, registries["nacos"].Address, "nacos://127.0.0.1:8848")
+
+	protocols := rc.Protocols
+	assert.NotNil(t, protocols)
+	assert.Equal(t, protocols["dubbo"].Name, "dubbo")
+	assert.Equal(t, protocols["dubbo"].Port, "20000")
+
+	consumer := rc.Consumer
+	assert.NotNil(t, consumer)
+	assert.Equal(t, consumer.References["helloService"].Protocol, "dubbo")
+	assert.Equal(t, consumer.References["helloService"].InterfaceName, "org.github.dubbo.HelloService")
+}
+
+func Test_getLegalActive(t *testing.T) {
+
+	t.Run("default", func(t *testing.T) {
+		active := getLegalActive("")
+		assert.Equal(t, active, "default")
+	})
+
+	t.Run("normal", func(t *testing.T) {
+		active := getLegalActive("active")
+		assert.Equal(t, active, "active")
+	})
+}
diff --git a/config/root_config.go b/config/root_config.go
index 4a4807a..8a7a01c 100644
--- a/config/root_config.go
+++ b/config/root_config.go
@@ -85,6 +85,9 @@ type RootConfig struct {
 	CacheFile string `yaml:"cache_file" json:"cache_file,omitempty" property:"cache_file"`
 
 	Custom *CustomConfig `yaml:"custom" json:"custom,omitempty" property:"custom"`
+
+	// Profiles config
+	Profiles *ProfilesConfig `yaml:"profiles" json:"profiles,omitempty" property:"profiles"`
 }
 
 func SetRootConfig(r RootConfig) {
diff --git a/config/testdata/config/active/application-local.yaml b/config/testdata/config/active/application-local.yaml
new file mode 100644
index 0000000..0d87a9e
--- /dev/null
+++ b/config/testdata/config/active/application-local.yaml
@@ -0,0 +1,16 @@
+dubbo:
+  profiles:
+    active: local
+  registries:
+    nacos:
+      timeout: 10s
+      address: nacos://127.0.0.1:8848
+  protocols:
+    dubbo:
+      name: dubbo
+      port: 20000
+  consumer:
+    references:
+      helloService:
+        protocol: dubbo
+        interface: org.github.dubbo.HelloService
\ No newline at end of file
diff --git a/config/testdata/config/active/application.yaml b/config/testdata/config/active/application.yaml
new file mode 100644
index 0000000..1f51654
--- /dev/null
+++ b/config/testdata/config/active/application.yaml
@@ -0,0 +1,7 @@
+dubbo:
+  profiles:
+    active: local
+  registries:
+    nacos:
+      timeout: 3s
+      address: nacos://127.0.0.1:8848
\ No newline at end of file