Support global ENV setting. (#293)

* Support global ENV setting.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* add viper package

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix typo

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix testing.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* fix testing.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu
2017-10-22 22:06:30 -05:00
committed by GitHub
parent e2d4d9db18
commit f3480d2dd8
165 changed files with 36925 additions and 157 deletions

View File

@@ -1,12 +1,85 @@
package config
import (
"bytes"
"fmt"
"io/ioutil"
"runtime"
"strings"
"gopkg.in/yaml.v2"
"github.com/spf13/viper"
)
var defaultConf = []byte(`
core:
enabled: true # enabale httpd server
address: "" # ip address to bind (default: any)
port: "8088" # ignore this port number if auto_tls is enabled (listen 443).
worker_num: 0 # default worker number is runtime.NumCPU()
queue_num: 0 # default queue number is 8192
max_notification: 100
sync: false # set true if you need get error message from fail push notification in API response.
mode: "release"
ssl: false
cert_path: "cert.pem"
key_path: "key.pem"
http_proxy: "" # only working for FCM server
pid:
enabled: false
path: "gorush.pid"
override: true
auto_tls:
enabled: false # Automatically install TLS certificates from Let's Encrypt.
folder: ".cache" # folder for storing TLS certificates
host: "" # which domains the Let's Encrypt will attempt
grpc:
enabled: false # enabale gRPC server
port: 9000
api:
push_uri: "/api/push"
stat_go_uri: "/api/stat/go"
stat_app_uri: "/api/stat/app"
config_uri: "/api/config"
sys_stat_uri: "/sys/stats"
metric_uri: "/metrics"
android:
enabled: true
apikey: "YOUR_API_KEY"
max_retry: 0 # resend fail notification, default value zero is disabled
ios:
enabled: false
key_path: "key.pem"
password: "" # certificate password, default as empty string.
production: false
max_retry: 0 # resend fail notification, default value zero is disabled
log:
format: "string" # string or json
access_log: "stdout" # stdout: output to console, or define log path like "log/access_log"
access_level: "debug"
error_log: "stderr" # stderr: output to console, or define log path like "log/error_log"
error_level: "error"
hide_token: true
stat:
engine: "memory" # support memory, redis, boltdb, buntdb or leveldb
redis:
addr: "localhost:6379"
password: ""
db: 0
boltdb:
path: "bolt.db"
bucket: "gorush"
buntdb:
path: "bunt.db"
leveldb:
path: "level.db"
`)
// ConfYaml is config structure.
type ConfYaml struct {
Core SectionCore `yaml:"core"`
@@ -124,97 +197,108 @@ type SectionGRPC struct {
Port string `yaml:"port"`
}
// BuildDefaultPushConf is default config setting.
func BuildDefaultPushConf() ConfYaml {
// LoadConf load config from file and read in environment variables that match
func LoadConf(confPath string) (ConfYaml, error) {
var conf ConfYaml
viper.SetConfigType("yaml")
viper.AutomaticEnv() // read in environment variables that match
viper.SetEnvPrefix("gorush") // will be uppercased automatically
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
if confPath != "" {
content, err := ioutil.ReadFile(confPath)
if err != nil {
return conf, err
}
viper.ReadConfig(bytes.NewBuffer(content))
} else {
// Search config in home directory with name ".gorush" (without extension).
viper.AddConfigPath("/etc/gorush/")
viper.AddConfigPath("$HOME/.gorush")
viper.AddConfigPath(".")
viper.SetConfigName("config")
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
} else {
// load default config
viper.ReadConfig(bytes.NewBuffer(defaultConf))
}
}
// Core
conf.Core.Address = ""
conf.Core.Port = "8088"
conf.Core.Enabled = true
conf.Core.WorkerNum = int64(runtime.NumCPU())
conf.Core.QueueNum = int64(8192)
conf.Core.Mode = "release"
conf.Core.Sync = false
conf.Core.SSL = false
conf.Core.CertPath = "cert.pem"
conf.Core.KeyPath = "key.pem"
conf.Core.MaxNotification = int64(100)
conf.Core.HTTPProxy = ""
conf.Core.PID.Enabled = false
conf.Core.PID.Path = "gorush.pid"
conf.Core.PID.Override = false
conf.Core.AutoTLS.Enabled = false
conf.Core.AutoTLS.Folder = ".cache"
conf.Core.AutoTLS.Host = ""
conf.Core.Address = viper.GetString("core.address")
conf.Core.Port = viper.GetString("core.port")
conf.Core.Enabled = viper.GetBool("core.enabled")
conf.Core.WorkerNum = int64(viper.GetInt("core.worker_num"))
conf.Core.QueueNum = int64(viper.GetInt("core.queue_num"))
conf.Core.Mode = viper.GetString("core.mode")
conf.Core.Sync = viper.GetBool("core.sync")
conf.Core.SSL = viper.GetBool("core.ssl")
conf.Core.CertPath = viper.GetString("core.cert_path")
conf.Core.KeyPath = viper.GetString("core.key_path")
conf.Core.MaxNotification = int64(viper.GetInt("core.max_notification"))
conf.Core.HTTPProxy = viper.GetString("core.http_proxy")
conf.Core.PID.Enabled = viper.GetBool("core.pid.enabled")
conf.Core.PID.Path = viper.GetString("core.pid.path")
conf.Core.PID.Override = viper.GetBool("core.pid.override")
conf.Core.AutoTLS.Enabled = viper.GetBool("core.auto_tls.enabled")
conf.Core.AutoTLS.Folder = viper.GetString("core.auto_tls.folder")
conf.Core.AutoTLS.Host = viper.GetString("core.auto_tls.host")
// Api
conf.API.PushURI = "/api/push"
conf.API.StatGoURI = "/api/stat/go"
conf.API.StatAppURI = "/api/stat/app"
conf.API.ConfigURI = "/api/config"
conf.API.SysStatURI = "/sys/stats"
conf.API.MetricURI = "/metrics"
conf.API.PushURI = viper.GetString("api.push_uri")
conf.API.StatGoURI = viper.GetString("api.stat_go_uri")
conf.API.StatAppURI = viper.GetString("api.stat_app_uri")
conf.API.ConfigURI = viper.GetString("api.config_uri")
conf.API.SysStatURI = viper.GetString("api.sys_stat_uri")
conf.API.MetricURI = viper.GetString("api.metric_uri")
// Android
conf.Android.Enabled = false
conf.Android.APIKey = ""
conf.Android.MaxRetry = 0
conf.Android.Enabled = viper.GetBool("android.enabled")
conf.Android.APIKey = viper.GetString("android.apikey")
conf.Android.MaxRetry = viper.GetInt("android.max_retry")
// iOS
conf.Ios.Enabled = false
conf.Ios.KeyPath = "key.pem"
conf.Ios.Password = ""
conf.Ios.Production = false
conf.Ios.MaxRetry = 0
conf.Ios.Enabled = viper.GetBool("ios.enabled")
conf.Ios.KeyPath = viper.GetString("ios.key_path")
conf.Ios.Password = viper.GetString("ios.password")
conf.Ios.Production = viper.GetBool("ios.production")
conf.Ios.MaxRetry = viper.GetInt("ios.max_retry")
// log
conf.Log.Format = "string"
conf.Log.AccessLog = "stdout"
conf.Log.AccessLevel = "debug"
conf.Log.ErrorLog = "stderr"
conf.Log.ErrorLevel = "error"
conf.Log.HideToken = true
conf.Log.Format = viper.GetString("log.format")
conf.Log.AccessLog = viper.GetString("log.access_log")
conf.Log.AccessLevel = viper.GetString("log.access_level")
conf.Log.ErrorLog = viper.GetString("log.error_log")
conf.Log.ErrorLevel = viper.GetString("log.error_level")
conf.Log.HideToken = viper.GetBool("log.hide_token")
// Stat Engine
conf.Stat.Engine = "memory"
conf.Stat.Redis.Addr = "localhost:6379"
conf.Stat.Redis.Password = ""
conf.Stat.Redis.DB = 0
conf.Stat.BoltDB.Path = "bolt.db"
conf.Stat.BoltDB.Bucket = "gorush"
conf.Stat.BuntDB.Path = "bunt.db"
conf.Stat.LevelDB.Path = "level.db"
conf.Stat.Engine = viper.GetString("stat.engine")
conf.Stat.Redis.Addr = viper.GetString("stat.redis.addr")
conf.Stat.Redis.Password = viper.GetString("stat.redis.password")
conf.Stat.Redis.DB = viper.GetInt("stat.redis.db")
conf.Stat.BoltDB.Path = viper.GetString("stat.boltdb.path")
conf.Stat.BoltDB.Bucket = viper.GetString("stat.boltdb.bucket")
conf.Stat.BuntDB.Path = viper.GetString("stat.buntdb.path")
conf.Stat.LevelDB.Path = viper.GetString("stat.leveldb.path")
// gRPC Server
conf.GRPC.Enabled = false
conf.GRPC.Port = "9000"
return conf
}
// LoadConfYaml provide load yml config.
func LoadConfYaml(confPath string) (ConfYaml, error) {
var config ConfYaml
configFile, err := ioutil.ReadFile(confPath)
if err != nil {
return config, err
}
err = yaml.Unmarshal(configFile, &config)
if err != nil {
return config, err
}
if config.Core.WorkerNum == int64(0) {
config.Core.WorkerNum = int64(runtime.NumCPU())
}
if config.Core.QueueNum == int64(0) {
config.Core.QueueNum = int64(8192)
}
return config, nil
conf.GRPC.Enabled = viper.GetBool("grpc.enabled")
conf.GRPC.Port = viper.GetString("grpc.port")
if conf.Core.WorkerNum == int64(0) {
conf.Core.WorkerNum = int64(runtime.NumCPU())
}
if conf.Core.QueueNum == int64(0) {
conf.Core.QueueNum = int64(8192)
}
return conf, nil
}

View File

@@ -1,8 +1,6 @@
package config
import (
"io/ioutil"
"log"
"os"
"runtime"
"testing"
@@ -14,29 +12,7 @@ import (
// Test file is missing
func TestMissingFile(t *testing.T) {
filename := "test"
_, err := LoadConfYaml(filename)
assert.NotNil(t, err)
}
// Test wrong json format
func TestWrongYAMLormat(t *testing.T) {
content := []byte(`Wrong format`)
filename := "tempfile"
if err := ioutil.WriteFile(filename, content, 0644); err != nil {
log.Fatalf("WriteFile %s: %v", filename, err)
}
// clean up
defer func() {
err := os.Remove(filename)
assert.Nil(t, err)
}()
// parse JSON format error
_, err := LoadConfYaml(filename)
_, err := LoadConf(filename)
assert.NotNil(t, err)
}
@@ -48,11 +24,14 @@ type ConfigTestSuite struct {
}
func (suite *ConfigTestSuite) SetupTest() {
suite.ConfGorushDefault = BuildDefaultPushConf()
var err error
suite.ConfGorush, err = LoadConfYaml("config.yml")
suite.ConfGorushDefault, err = LoadConf("")
if err != nil {
panic("failed to load config.yml")
panic("failed to load default config.yml")
}
suite.ConfGorush, err = LoadConf("config.yml")
if err != nil {
panic("failed to load config.yml from file")
}
}
@@ -73,7 +52,7 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
// Pid
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.PID.Enabled)
assert.Equal(suite.T(), "gorush.pid", suite.ConfGorushDefault.Core.PID.Path)
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.PID.Override)
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Core.PID.Override)
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Core.AutoTLS.Enabled)
assert.Equal(suite.T(), ".cache", suite.ConfGorushDefault.Core.AutoTLS.Folder)
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Core.AutoTLS.Host)
@@ -87,8 +66,8 @@ func (suite *ConfigTestSuite) TestValidateConfDefault() {
assert.Equal(suite.T(), "/metrics", suite.ConfGorushDefault.API.MetricURI)
// Android
assert.Equal(suite.T(), false, suite.ConfGorushDefault.Android.Enabled)
assert.Equal(suite.T(), "", suite.ConfGorushDefault.Android.APIKey)
assert.Equal(suite.T(), true, suite.ConfGorushDefault.Android.Enabled)
assert.Equal(suite.T(), "YOUR_API_KEY", suite.ConfGorushDefault.Android.APIKey)
assert.Equal(suite.T(), 0, suite.ConfGorushDefault.Android.MaxRetry)
// iOS
@@ -190,3 +169,16 @@ func (suite *ConfigTestSuite) TestValidateConf() {
func TestConfigTestSuite(t *testing.T) {
suite.Run(t, new(ConfigTestSuite))
}
func TestLoadConfigFromEnv(t *testing.T) {
os.Setenv("GORUSH_CORE_PORT", "9001")
os.Setenv("GORUSH_GRPC_ENABLED", "true")
os.Setenv("GORUSH_CORE_MAX_NOTIFICATION", "200")
ConfGorush, err := LoadConf("config.yml")
if err != nil {
panic("failed to load config.yml from file")
}
assert.Equal(t, "9001", ConfGorush.Core.Port)
assert.Equal(t, int64(200), ConfGorush.Core.MaxNotification)
assert.True(t, ConfGorush.GRPC.Enabled)
}