Refractor config_load.go (#158)
* Refractor config_load.go
* Refractor pixiu_start.go
* Refractor pixiu_start.go
* bug fix about read yml file. some key with _ can't read in object.
* Change DiscoverService to DiscoveryService.
Co-authored-by: zhangxun <18721825717@163.com>
Former-commit-id: b3940bbbba10a2995de75661a02d603c044ed38c [formerly 51bb439739edaed119434c13b213ab7e8f3d4a99]
Former-commit-id: 15c079b1e75694c42ade63456239870aa2526453
diff --git a/pkg/common/constant/pixiu.go b/pkg/common/constant/pixiu.go
index 43b3ad2..c9c6b10 100644
--- a/pkg/common/constant/pixiu.go
+++ b/pkg/common/constant/pixiu.go
@@ -35,3 +35,23 @@
ResponseStrategyNormal = "normal"
ResponseStrategyHump = "hump"
)
+
+const (
+ // DefaultDiscoveryType Set up default discovery type.
+ DefaultDiscoveryType = "EDS"
+ // DefaultLoadBalanceType Set up default load balance type.
+ DefaultLoadBalanceType = "RoundRobin"
+ // DefaultFilterType Set up default filter type.
+ DefaultFilterType = "dgp.filters.http_connect_manager"
+ // DefaultHTTPType Set up default HTTP Type.
+ DefaultHTTPType = "net/http"
+ // DefaultProtocolType Set up default protocol type.
+ DefaultProtocolType = "HTTP"
+)
+
+const (
+ // YAML .yaml
+ YAML = ".yaml"
+ //YML .yml
+ YML = ".yml"
+)
diff --git a/pkg/config/conf_test.yaml b/pkg/config/conf_test.yaml
index 12515f5..c79be62 100644
--- a/pkg/config/conf_test.yaml
+++ b/pkg/config/conf_test.yaml
@@ -78,7 +78,9 @@
timeout: "60s"
step_timeout: "10s"
reject_policy: "immediacy"
-
pprofConf:
enable: true
- addr: "0.0.0.0:6060"
\ No newline at end of file
+ address:
+ socket_address:
+ address: "0.0.0.0"
+ port: 6060
\ No newline at end of file
diff --git a/pkg/config/config_load.go b/pkg/config/config_load.go
index 476ac68..4dffb46 100644
--- a/pkg/config/config_load.go
+++ b/pkg/config/config_load.go
@@ -18,7 +18,7 @@
package config
import (
- "encoding/json"
+ "github.com/apache/dubbo-go-pixiu/pkg/common/constant"
"io/ioutil"
"log"
"path/filepath"
@@ -37,9 +37,12 @@
var (
configPath string
config *model.Bootstrap
- configLoadFunc ConfigLoadFunc = DefaultConfigLoad
+ configLoadFunc LoadFunc = LoadYAMLConfig
)
+// LoadFunc ConfigLoadFunc parse a input(usually file path) into a pixiu config
+type LoadFunc func(path string) *model.Bootstrap
+
// GetBootstrap get config global, need a better name
func GetBootstrap() *model.Bootstrap {
return config
@@ -48,142 +51,162 @@
// Load config file and parse
func Load(path string) *model.Bootstrap {
logger.Infof("[dubbopixiu go] load path:%s", path)
-
configPath, _ = filepath.Abs(path)
- if yamlFormat(path) {
- RegisterConfigLoadFunc(YAMLConfigLoad)
+ if configPath != "" && CheckYamlFormat(configPath) {
+ RegisterConfigLoadFunc(LoadYAMLConfig)
}
- if cfg := configLoadFunc(path); cfg != nil {
+ if cfg := configLoadFunc(configPath); cfg != nil {
config = cfg
}
-
return config
}
-// ConfigLoadFunc parse a input(usually file path) into a pixiu config
-type ConfigLoadFunc func(path string) *model.Bootstrap
-
// RegisterConfigLoadFunc can replace a new config load function instead of default
-func RegisterConfigLoadFunc(f ConfigLoadFunc) {
+func RegisterConfigLoadFunc(f LoadFunc) {
configLoadFunc = f
}
-func yamlFormat(path string) bool {
+func CheckYamlFormat(path string) bool {
ext := filepath.Ext(path)
- if ext == ".yaml" || ext == ".yml" {
+ if ext == constant.YAML || ext == constant.YML {
return true
}
return false
}
-// YAMLConfigLoad config load yaml
-func YAMLConfigLoad(path string) *model.Bootstrap {
+// LoadYAMLConfig YAMLConfigLoad config load yaml
+func LoadYAMLConfig(path string) *model.Bootstrap {
log.Println("load config in YAML format from : ", path)
content, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalln("[config] [yaml load] load config failed, ", err)
}
cfg := &model.Bootstrap{}
-
- bytes, err := yaml.YAMLToJSON(content)
+ err = yaml.Unmarshal(content, cfg)
if err != nil {
log.Fatalln("[config] [yaml load] convert YAML to JSON failed, ", err)
}
-
- err = json.Unmarshal(bytes, cfg)
+ err = Adapter(cfg)
if err != nil {
log.Fatalln("[config] [yaml load] yaml unmarshal config failed, ", err)
}
+ return cfg
+}
- // other adapter
+func Adapter(cfg *model.Bootstrap) (err error) {
+ if GetFilterChain(cfg) != nil || GetHttpConfig(cfg) != nil || GetProtocol(cfg) != nil ||
+ GetLoadBalance(cfg) != nil || GetDiscoveryType(cfg) != nil {
+ return err
+ }
+ return nil
+}
- for i, l := range cfg.StaticResources.Listeners {
+func GetProtocol(cfg *model.Bootstrap) (err error) {
+ if cfg == nil {
+ logger.Error("Bootstrap configuration is null")
+ return err
+ }
+ for _, l := range cfg.StaticResources.Listeners {
if l.Address.SocketAddress.ProtocolStr == "" {
- l.Address.SocketAddress.ProtocolStr = "HTTP"
+ l.Address.SocketAddress.ProtocolStr = constant.DefaultProtocolType
}
l.Address.SocketAddress.Protocol = model.ProtocolType(model.ProtocolTypeValue[l.Address.SocketAddress.ProtocolStr])
+ }
+ return nil
+}
+func GetHttpConfig(cfg *model.Bootstrap) (err error) {
+ if cfg == nil {
+ logger.Error("Bootstrap configuration is null")
+ return err
+ }
+ for i, l := range cfg.StaticResources.Listeners {
hc := &model.HttpConfig{}
if l.Config != nil {
if v, ok := l.Config.(map[string]interface{}); ok {
switch l.Name {
- case "net/http":
+ case constant.DefaultHTTPType:
if err := mapstructure.Decode(v, hc); err != nil {
logger.Error(err)
}
-
- cfg.StaticResources.Listeners[i].Config = hc
+ cfg.StaticResources.Listeners[i].Config = *hc
}
}
}
+ }
+ return nil
+}
+func GetFilterChain(cfg *model.Bootstrap) (err error) {
+ if cfg == nil {
+ logger.Error("Bootstrap configuration is null")
+ return err
+ }
+ for _, l := range cfg.StaticResources.Listeners {
for _, fc := range l.FilterChains {
if fc.Filters != nil {
for i, fcf := range fc.Filters {
hcm := &model.HttpConnectionManager{}
if fcf.Config != nil {
switch fcf.Name {
- case "dgp.filters.http_connect_manager":
+ case constant.DefaultFilterType:
if v, ok := fcf.Config.(map[string]interface{}); ok {
if err := mapstructure.Decode(v, hcm); err != nil {
logger.Error(err)
}
-
- fc.Filters[i].Config = hcm
+ fc.Filters[i].Config = *hcm
}
}
}
}
}
}
-
}
-
- for _, c := range cfg.StaticResources.Clusters {
- var discoverType int32
- if c.TypeStr != "" {
- if t, ok := model.DiscoveryTypeValue[c.TypeStr]; ok {
- discoverType = t
- } else {
- c.TypeStr = "EDS"
- discoverType = model.DiscoveryTypeValue[c.TypeStr]
- }
- } else {
- c.TypeStr = "EDS"
- discoverType = model.DiscoveryTypeValue[c.TypeStr]
- }
- c.Type = model.DiscoveryType(discoverType)
-
- var lbPolicy int32
- if c.LbStr != "" {
- if lb, ok := model.LbPolicyValue[c.LbStr]; ok {
- lbPolicy = lb
- } else {
- c.LbStr = "RoundRobin"
- lbPolicy = model.LbPolicyValue[c.LbStr]
- }
- } else {
- c.LbStr = "RoundRobin"
- lbPolicy = model.LbPolicyValue[c.LbStr]
- }
- c.Lb = model.LbPolicy(lbPolicy)
- }
-
- return cfg
+ return nil
}
-// DefaultConfigLoad if not config, will load this
-func DefaultConfigLoad(path string) *model.Bootstrap {
- log.Println("load config from : ", path)
- content, err := ioutil.ReadFile(path)
- if err != nil {
- log.Fatalln("[config] [default load] load config failed, ", err)
+func GetLoadBalance(cfg *model.Bootstrap) (err error) {
+ if cfg == nil {
+ logger.Error("Bootstrap configuration is null")
+ return err
}
- cfg := &model.Bootstrap{}
- // translate to lower case
- err = json.Unmarshal(content, cfg)
- if err != nil {
- log.Fatalln("[config] [default load] json unmarshal config failed, ", err)
+ var lbPolicy int32
+ for _, c := range cfg.StaticResources.Clusters {
+ flag := true
+ if c.TypeStr != "" {
+ if t, ok := model.LbPolicyValue[c.LbStr]; ok {
+ lbPolicy = t
+ flag = false
+ }
+ }
+ if flag {
+ c.LbStr = constant.DefaultLoadBalanceType
+ lbPolicy = model.LbPolicyValue[c.LbStr]
+ }
+ c.Type = model.DiscoveryType(lbPolicy)
}
- return cfg
+ return nil
+}
+
+func GetDiscoveryType(cfg *model.Bootstrap) (err error) {
+ if cfg == nil {
+ logger.Error("Bootstrap configuration is null")
+ return err
+ }
+ var discoveryType int32
+ for _, c := range cfg.StaticResources.Clusters {
+ flag := true
+ if c.TypeStr != "" {
+ if t, ok := model.DiscoveryTypeValue[c.TypeStr]; ok {
+ discoveryType = t
+ flag = false
+ }
+ }
+ if flag {
+ c.TypeStr = constant.DefaultDiscoveryType
+ discoveryType = model.DiscoveryTypeValue[c.TypeStr]
+ }
+ c.Type = model.DiscoveryType(discoveryType)
+ }
+ return nil
}
diff --git a/pkg/config/config_load_test.go b/pkg/config/config_load_test.go
index 35b4da4..375ef92 100644
--- a/pkg/config/config_load_test.go
+++ b/pkg/config/config_load_test.go
@@ -19,6 +19,8 @@
import (
"encoding/json"
+ "log"
+ "os"
"testing"
)
@@ -30,15 +32,11 @@
"github.com/apache/dubbo-go-pixiu/pkg/model"
)
-func TestLoad(t *testing.T) {
- conf := Load("conf_test.yaml")
+var b model.Bootstrap
- assert.Equal(t, 1, len(conf.StaticResources.Listeners))
- assert.Equal(t, 1, len(conf.StaticResources.Clusters))
-}
-
-func TestStruct2JSON(t *testing.T) {
- b := model.Bootstrap{
+func TestMain(m *testing.M) {
+ log.Println("Prepare Bootstrap")
+ b = model.Bootstrap{
StaticResources: model.StaticResources{
Listeners: []model.Listener{
{
@@ -46,8 +44,8 @@
Address: model.Address{
SocketAddress: model.SocketAddress{
ProtocolStr: "HTTP",
- Address: "127.0.0.0",
- Port: 8899,
+ Address: "0.0.0.0",
+ Port: 8888,
},
},
Config: model.HttpConfig{
@@ -72,13 +70,20 @@
{
Match: model.RouterMatch{
Prefix: "/api/v1",
+ Headers: []model.HeaderMatcher{
+ {Name: "X-DGP-WAY",
+ Value: "dubbo",
+ },
+ },
},
Route: model.RouteAction{
- Cluster: "test_dubbo",
+ Cluster: "test_dubbo",
+ ClusterNotFoundResponseCode: 505,
Cors: model.CorsPolicy{
AllowOrigin: []string{
"*",
},
+ Enabled: true,
},
},
},
@@ -86,12 +91,20 @@
},
HTTPFilters: []model.HTTPFilter{
{
- Name: "dgp.filters.http.cors",
+ Name: "dgp.filters.http.api",
+ Config: interface{}(nil),
},
{
- Name: "dgp.filters.http.router",
+ Name: "dgp.filters.http.router",
+ Config: interface{}(nil),
+ },
+ {
+ Name: "dgp.filters.http_transfer_dubbo",
+ Config: interface{}(nil),
},
},
+ ServerName: "test_http_dubbo",
+ GenerateRequestID: false,
},
},
},
@@ -99,17 +112,56 @@
},
},
},
- Clusters: []model.Cluster{
+ Clusters: []*model.Cluster{
{
Name: "test_dubbo",
TypeStr: "EDS",
+ Type: model.EDS,
LbStr: "RoundRobin",
ConnectTimeoutStr: "5s",
+ RequestTimeoutStr: "10s",
+ Registries: map[string]model.Registry{
+ "zookeeper": {
+ Timeout: "3s",
+ Address: "127.0.0.1:2182",
+ Username: "",
+ Password: "",
+ },
+ "consul": {
+ Timeout: "3s",
+ Address: "127.0.0.1:8500",
+ },
+ },
+ },
+ },
+ ShutdownConfig: &model.ShutdownConfig{
+ Timeout: "60s",
+ StepTimeout: "10s",
+ RejectPolicy: "immediacy",
+ },
+ PprofConf: model.PprofConf{
+ Enable: true,
+ Address: model.Address{
+ SocketAddress: model.SocketAddress{
+ Address: "0.0.0.0",
+ Port: 6060,
+ },
},
},
},
}
+ retCode := m.Run()
+ os.Exit(retCode)
+}
+func TestLoad(t *testing.T) {
+ conf := Load("conf_test.yaml")
+ assert.Equal(t, 1, len(conf.StaticResources.Listeners))
+ assert.Equal(t, 1, len(conf.StaticResources.Clusters))
+ assert.Equal(t, *conf, b)
+}
+
+func TestStruct2JSON(t *testing.T) {
if bytes, err := json.Marshal(b); err != nil {
t.Fatal(err)
} else {
diff --git a/pkg/model/bootstrap.go b/pkg/model/bootstrap.go
index 8fa4d48..1c99c3d 100644
--- a/pkg/model/bootstrap.go
+++ b/pkg/model/bootstrap.go
@@ -55,7 +55,7 @@
// StaticResources
type StaticResources struct {
Listeners []Listener `yaml:"listeners" json:"listeners" mapstructure:"listeners"`
- Clusters []Cluster `yaml:"clusters" json:"clusters" mapstructure:"clusters"`
+ Clusters []*Cluster `yaml:"clusters" json:"clusters" mapstructure:"clusters"`
ShutdownConfig *ShutdownConfig `yaml:"shutdown_config" json:"shutdown_config" mapstructure:"shutdown_config"`
PprofConf PprofConf `yaml:"pprofConf" json:"pprofConf" mapstructure:"pprofConf"`
AccessLogConfig AccessLogConfig `yaml:"accessLog" json:"accessLog" mapstructure:"accessLog"`
diff --git a/pkg/model/cluster.go b/pkg/model/cluster.go
index f4acc97..ee53b6f 100644
--- a/pkg/model/cluster.go
+++ b/pkg/model/cluster.go
@@ -22,7 +22,7 @@
Name string `yaml:"name" json:"name"` // Name the cluster unique name
TypeStr string `yaml:"type" json:"type"` // Type the cluster discovery type string value
Type DiscoveryType `yaml:",omitempty" json:",omitempty"` // Type the cluster discovery type
- EdsClusterConfig EdsClusterConfig `yaml:"eds_cluster_config" json:"eds_cluster_config"`
+ EdsClusterConfig EdsClusterConfig `yaml:"eds_cluster_config" json:"eds_cluster_config" mapstructure:"eds_cluster_config"`
LbStr string `yaml:"lb_policy" json:"lb_policy"` // Lb the cluster select node used loadBalance policy
Lb LbPolicy `yaml:",omitempty" json:",omitempty"` // Lb the cluster select node used loadBalance policy
ConnectTimeoutStr string `yaml:"connect_timeout" json:"connect_timeout"` // ConnectTimeout timeout for connect to cluster node
diff --git a/pkg/model/match.go b/pkg/model/match.go
index 2f046ea..72f8c0a 100644
--- a/pkg/model/match.go
+++ b/pkg/model/match.go
@@ -54,7 +54,7 @@
// HeaderMatcher header matcher struct
// Name header key, Value header value, Regex header value is regex
type HeaderMatcher struct {
- Name string `yaml:"name" json:"name"`
- Value string `yaml:"value" json:"value"`
- Regex bool `yaml:"regex" json:"regex"`
+ Name string `yaml:"name" json:"name" mapstructure:"name"`
+ Value string `yaml:"value" json:"value" mapstructure:"value"`
+ Regex bool `yaml:"regex" json:"regex" mapstructure:"regex"`
}
diff --git a/pkg/model/router.go b/pkg/model/router.go
index 5fa8906..ab3d7e2 100644
--- a/pkg/model/router.go
+++ b/pkg/model/router.go
@@ -19,41 +19,41 @@
// Router struct
type Router struct {
- Match RouterMatch `yaml:"match" json:"match"`
- Route RouteAction `yaml:"route" json:"route"`
- Redirect RouteAction `yaml:"redirect" json:"redirect"`
+ Match RouterMatch `yaml:"match" json:"match" mapstructure:"match"`
+ Route RouteAction `yaml:"route" json:"route" mapstructure:"route"`
+ Redirect RouteAction `yaml:"redirect" json:"redirect" mapstructure:"redirect"`
//"metadata": "{...}",
//"decorator": "{...}"
}
// RouterMatch
type RouterMatch struct {
- Prefix string `yaml:"prefix" json:"prefix"`
- Path string `yaml:"path" json:"path"`
- Regex string `yaml:"regex" json:"regex"`
+ Prefix string `yaml:"prefix" json:"prefix" mapstructure:"prefix"`
+ Path string `yaml:"path" json:"path" mapstructure:"path"`
+ Regex string `yaml:"regex" json:"regex" mapstructure:"regex"`
CaseSensitive bool // CaseSensitive default true
- Headers []HeaderMatcher `yaml:"headers" json:"headers"`
+ Headers []HeaderMatcher `yaml:"headers" json:"headers" mapstructure:"headers"`
}
// RouteAction match route should do
type RouteAction struct {
- Cluster string `yaml:"cluster" json:"cluster"` // Cluster cluster name
- ClusterNotFoundResponseCode int `yaml:"cluster_not_found_response_code" json:"cluster_not_found_response_code"`
- PrefixRewrite string `yaml:"prefix_rewrite" json:"prefix_rewrite"`
- HostRewrite string `yaml:"host_rewrite" json:"host_rewrite"`
- Timeout string `yaml:"timeout" json:"timeout"`
- Priority int8 `yaml:"priority" json:"priority"`
- ResponseHeadersToAdd HeaderValueOption `yaml:"response_headers_to_add" json:"response_headers_to_add"` // ResponseHeadersToAdd add response head
- ResponseHeadersToRemove []string `yaml:"response_headers_to_remove" json:"response_headers_to_remove"` // ResponseHeadersToRemove remove response head
- RequestHeadersToAdd HeaderValueOption `yaml:"request_headers_to_add" json:"request_headers_to_add"` // RequestHeadersToAdd add request head
- Cors CorsPolicy `yaml:"cors" json:"cors"`
+ Cluster string `yaml:"cluster" json:"cluster" mapstructure:"cluster"`
+ ClusterNotFoundResponseCode int `yaml:"cluster_not_found_response_code" json:"cluster_not_found_response_code" mapstructure:"cluster_not_found_response_code"`
+ PrefixRewrite string `yaml:"prefix_rewrite" json:"prefix_rewrite" mapstructure:"prefix_rewrite"`
+ HostRewrite string `yaml:"host_rewrite" json:"host_rewrite" mapstructure:"host_rewrite"`
+ Timeout string `yaml:"timeout" json:"timeout" mapstructure:"timeout"`
+ Priority int8 `yaml:"priority" json:"priority" mapstructure:"priority"`
+ ResponseHeadersToAdd HeaderValueOption `yaml:"response_headers_to_add" json:"response_headers_to_add" mapstructure:"response_headers_to_add"` // ResponseHeadersToAdd add response head
+ ResponseHeadersToRemove []string `yaml:"response_headers_to_remove" json:"response_headers_to_remove" mapstructure:"response_headers_to_remove"` // ResponseHeadersToRemove remove response head
+ RequestHeadersToAdd HeaderValueOption `yaml:"request_headers_to_add" json:"request_headers_to_add" mapstructure:"request_headers_to_add"` // RequestHeadersToAdd add request head
+ Cors CorsPolicy `yaml:"cors" json:"cors" mapstructure:"cors"`
}
// RouteConfiguration
type RouteConfiguration struct {
- InternalOnlyHeaders []string `yaml:"internal_only_headers" json:"internal_only_headers"` // InternalOnlyHeaders used internal, clear http request head
- ResponseHeadersToAdd HeaderValueOption `yaml:"response_headers_to_add" json:"response_headers_to_add"` // ResponseHeadersToAdd add response head
- ResponseHeadersToRemove []string `yaml:"response_headers_to_remove" json:"response_headers_to_remove"` // ResponseHeadersToRemove remove response head
- RequestHeadersToAdd HeaderValueOption `yaml:"request_headers_to_add" json:"request_headers_to_add"` // RequestHeadersToAdd add request head
- Routes []Router `yaml:"routes" json:"routes"`
+ InternalOnlyHeaders []string `yaml:"internal_only_headers" json:"internal_only_headers" mapstructure:"internal_only_headers"` // InternalOnlyHeaders used internal, clear http request head
+ ResponseHeadersToAdd HeaderValueOption `yaml:"response_headers_to_add" json:"response_headers_to_add" mapstructure:"response_headers_to_add"` // ResponseHeadersToAdd add response head
+ ResponseHeadersToRemove []string `yaml:"response_headers_to_remove" json:"response_headers_to_remove" mapstructure:"response_headers_to_remove"` // ResponseHeadersToRemove remove response head
+ RequestHeadersToAdd HeaderValueOption `yaml:"request_headers_to_add" json:"request_headers_to_add" mapstructure:"request_headers_to_add"` // RequestHeadersToAdd add request head
+ Routes []Router `yaml:"routes" json:"routes" mapstructure:"routes"`
}