Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
mv omil-$(git rev-parse --short HEAD).tar.gz build-binary

- name: Upload
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: omil-build
path: build
Expand Down
96 changes: 86 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package config

import (
"fmt"
"sync"

"github.com/jinzhu/configor"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

Expand All @@ -12,7 +14,8 @@ type Target struct {
Name string `yaml:"Name"`
}

type configStruct struct {
type ConfigStruct struct {
mu sync.RWMutex
Hostname string `yaml:"Hostname"`
// Deprecated: InfluxDB 1.* sever configs.
InfluxDBv1 struct {
Expand All @@ -31,22 +34,95 @@ type configStruct struct {
Targets []Target `yaml:"Targets"`
}

type configStruct = ConfigStruct

var (
configFilePath string
initConfigOnce sync.Once
config *configStruct
globalConfig *ConfigStruct
globalConfigOnce sync.Once
globalFilePath string
)

func SetConfigFilePath(filepath string) {
configFilePath = filepath
globalFilePath = filepath
}

func Config() *configStruct {
initConfigOnce.Do(func() {
config = new(configStruct)
if err := configor.Load(config, configFilePath, "conf/config.yml"); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这一句能不能拆解成其他更简单的写法

func Config() *ConfigStruct {
globalConfigOnce.Do(func() {
var err error
globalConfig, err = LoadConfig(globalFilePath, "conf/config.yml")
if err != nil {
logrus.WithError(err).Fatal("failed to load config from file")
}
})
return config
return globalConfig
}

func LoadConfig(filePaths ...string) (*ConfigStruct, error) {
config := &ConfigStruct{}
if err := configor.Load(config, filePaths...); err != nil {
return nil, err
}
return config, nil
}

func (c *ConfigStruct) GetHostname() string {
c.mu.RLock()
defer c.mu.RUnlock()
return c.Hostname
}

func (c *ConfigStruct) GetTargets() []Target {
c.mu.RLock()
defer c.mu.RUnlock()
targets := make([]Target, len(c.Targets))
copy(targets, c.Targets)
return targets
}

func (c *ConfigStruct) GetInfluxDBv2() struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
} {
c.mu.RLock()
defer c.mu.RUnlock()
return c.InfluxDBv2
}

func (c *ConfigStruct) Validate() error {
c.mu.RLock()
defer c.mu.RUnlock()

if c.Hostname == "" {
return errors.New("hostname is required")
}

if len(c.Targets) == 0 {
return errors.New("at least one target is required")
}

for i, target := range c.Targets {
if target.Host == "" {
return fmt.Errorf("target[%d]: host is required", i)
}
if target.Name == "" {
return fmt.Errorf("target[%d]: name is required", i)
}
}

if c.InfluxDBv2.Addr == "" {
return errors.New("InfluxDBv2.Addr is required")
}
if c.InfluxDBv2.Org == "" {
return errors.New("InfluxDBv2.Org is required")
}
if c.InfluxDBv2.Bucket == "" {
return errors.New("InfluxDBv2.Bucket is required")
}
if c.InfluxDBv2.Token == "" {
return errors.New("InfluxDBv2.Token is required")
}

return nil
}
240 changes: 240 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package config

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func TestLoadConfig(t *testing.T) {
testCases := []struct {
name string
configYAML string
expectError bool
}{
{
name: "valid config",
configYAML: `
Hostname: "test-host"
InfluxDBv2:
Addr: "http://localhost:8086"
Org: "test-org"
Bucket: "test-bucket"
Token: "test-token"
Targets:
- Host: "8.8.8.8"
Name: "google-dns"
- Host: "1.1.1.1"
Name: "cloudflare-dns"
`,
expectError: false,
},
{
name: "invalid yaml",
configYAML: `
invalid: yaml: content
- missing
`,
expectError: true,
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
tmpDir := t.TempDir()
configFile := filepath.Join(tmpDir, "config.yml")

err := os.WriteFile(configFile, []byte(testCase.configYAML), 0644)
require.NoError(t, err)

config, err := LoadConfig(configFile)

if testCase.expectError {
require.Error(t, err)
require.Nil(t, config)
} else {
require.NoError(t, err)
require.NotNil(t, config)
require.Equal(t, "test-host", config.GetHostname())
targets := config.GetTargets()
require.Len(t, targets, 2)
require.Equal(t, "8.8.8.8", targets[0].Host)
require.Equal(t, "google-dns", targets[0].Name)
}
})
}
}

func TestConfigStruct_Validate(t *testing.T) {
testCases := []struct {
name string
config *ConfigStruct
expectError bool
errorMsg string
}{
{
name: "valid config",
config: &ConfigStruct{
Hostname: "test-host",
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Addr: "http://localhost:8086",
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{
{Host: "8.8.8.8", Name: "google-dns"},
},
},
expectError: false,
},
{
name: "missing hostname",
config: &ConfigStruct{
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Addr: "http://localhost:8086",
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{
{Host: "8.8.8.8", Name: "google-dns"},
},
},
expectError: true,
errorMsg: "hostname is required",
},
{
name: "no targets",
config: &ConfigStruct{
Hostname: "test-host",
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Addr: "http://localhost:8086",
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{},
},
expectError: true,
errorMsg: "at least one target is required",
},
{
name: "target missing host",
config: &ConfigStruct{
Hostname: "test-host",
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Addr: "http://localhost:8086",
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{
{Name: "test-target"},
},
},
expectError: true,
errorMsg: "target[0]: host is required",
},
{
name: "missing influxdb addr",
config: &ConfigStruct{
Hostname: "test-host",
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{
{Host: "8.8.8.8", Name: "google-dns"},
},
},
expectError: true,
errorMsg: "InfluxDBv2.Addr is required",
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
err := testCase.config.Validate()

if testCase.expectError {
require.Error(t, err)
require.Contains(t, err.Error(), testCase.errorMsg)
} else {
require.NoError(t, err)
}
})
}
}

func TestConfigStruct_GetMethods(t *testing.T) {
config := &ConfigStruct{
Hostname: "test-host",
InfluxDBv2: struct {
Addr string `yaml:"Addr"`
Org string `yaml:"Org"`
Bucket string `yaml:"Bucket"`
Token string `yaml:"Token"`
}{
Addr: "http://localhost:8086",
Org: "test-org",
Bucket: "test-bucket",
Token: "test-token",
},
Targets: []Target{
{Host: "8.8.8.8", Name: "google-dns"},
{Host: "1.1.1.1", Name: "cloudflare-dns"},
},
}

require.Equal(t, "test-host", config.GetHostname())

targets := config.GetTargets()
require.Len(t, targets, 2)
require.Equal(t, "8.8.8.8", targets[0].Host)
require.Equal(t, "google-dns", targets[0].Name)

influxConfig := config.GetInfluxDBv2()
require.Equal(t, "http://localhost:8086", influxConfig.Addr)
require.Equal(t, "test-org", influxConfig.Org)
require.Equal(t, "test-bucket", influxConfig.Bucket)
require.Equal(t, "test-token", influxConfig.Token)
}

func TestTarget(t *testing.T) {
target := Target{
Host: "example.com",
Name: "test-target",
}

require.Equal(t, "example.com", target.Host)
require.Equal(t, "test-target", target.Name)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/jinzhu/configor v1.2.0
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.7.0
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.2.0
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb // indirect
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
Expand Down
Loading
Loading