forked from ligato/cn-infra
/
plugin_config.go
158 lines (134 loc) · 4.25 KB
/
plugin_config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package config
import (
"os"
"path"
"strings"
"sync"
"github.com/ligato/cn-infra/logging/logrus"
"github.com/namsral/flag"
)
// FlagSuffix is added to plugin name while loading plugins configuration.
const FlagSuffix = "-config"
// EnvSuffix is added to plugin name while loading plugins configuration from ENV variable.
const EnvSuffix = "_CONFIG"
// DirFlag as flag name (see implementation in declareFlags())
// is used to define default directory where config files reside.
// This flag name is derived from the name of the plugin.
const DirFlag = "config-dir"
// DirDefault holds a default value "." for flag, which represents current working directory.
const DirDefault = "."
// DirUsage used as a flag (see implementation in declareFlags()).
const DirUsage = "Location of the configuration files; also set via 'CONFIG_DIR' env variable."
// PluginConfig is API for plugins to access configuration.
//
// Aim of this API is to let a particular plugin to bind it's configuration
// without knowing a particular key name. The key name is injected in flavor (Plugin Name).
type PluginConfig interface {
// GetValue parses configuration for a plugin and stores the results in data.
// The argument data is a pointer to an instance of a go structure.
GetValue(data interface{}) (found bool, err error)
// GetConfigName returns config name derived from plugin name:
// flag = PluginName + FlagSuffix (evaluated most often as absolute path to a config file)
GetConfigName() string
}
// ForPlugin returns API that is injectable to a particular Plugin
// and is used to read it's configuration.
//
// It tries to lookup `plugin + "-config"` in flags and declare
// the flag if it still not exists. It uses the following
// opts (used to define flag (if it was not already defined)):
// - default value
// - usage
func ForPlugin(pluginName string, opts ...string) PluginConfig {
flgName := pluginName + FlagSuffix
flg := flag.CommandLine.Lookup(flgName)
if flg == nil && len(opts) > 0 {
var flagDefault, flagUsage string
if len(opts) > 0 && opts[0] != "" {
flagDefault = opts[0]
} else {
flagDefault = pluginName + ".conf"
}
if len(opts) > 1 && opts[1] != "" {
flagUsage = opts[1]
} else {
flagUsage = "Location of the " + pluginName +
" Client configuration file; also set via '" +
strings.ToUpper(pluginName) + EnvSuffix + "' env variable."
}
flag.String(flgName, flagDefault, flagUsage)
}
return &pluginConfig{pluginName: pluginName}
}
type pluginConfig struct {
pluginName string
access sync.Mutex
cfg string
}
// GetValue binds the configuration to config method argument.
func (p *pluginConfig) GetValue(config interface{}) (found bool, err error) {
cfgName := p.GetConfigName()
if cfgName == "" {
return false, nil
}
err = ParseConfigFromYamlFile(cfgName, config) //TODO switch to Viper (possible to have one huge config file)
if err != nil {
return false, err
}
return true, nil
}
// GetConfigName looks up flag value and uses it to:
// 1. Find config in flag value location.
// 2. Alternatively, it tries to find it in config dir
// (see also Dir() comments).
func (p *pluginConfig) GetConfigName() string {
p.access.Lock()
defer p.access.Unlock()
if p.cfg == "" {
p.cfg = p.getConfigName()
}
return p.cfg
}
func (p *pluginConfig) getConfigName() string {
flgName := p.pluginName + FlagSuffix
flg := flag.CommandLine.Lookup(flgName)
if flg != nil {
flgVal := flg.Value.String()
if flgVal != "" {
// if exist value from flag
if _, err := os.Stat(flgVal); !os.IsNotExist(err) {
return flgVal
}
cfgDir, err := Dir()
if err != nil {
logrus.DefaultLogger().Error(err)
return ""
}
// if exist flag value in config dir
flgValInConfigDir := path.Join(cfgDir, flgVal)
if _, err := os.Stat(flgValInConfigDir); !os.IsNotExist(err) {
return flgValInConfigDir
}
}
}
return ""
}
// Dir evaluates the flag DirFlag. It interprets "." as current working directory.
func Dir() (string, error) {
flg := flag.CommandLine.Lookup(DirFlag)
if flg != nil {
val := flg.Value.String()
if strings.HasPrefix(val, ".") {
cwd, err := os.Getwd()
if err != nil {
return cwd, err
}
if len(val) > 1 {
return cwd + val[1:], nil
}
return cwd, nil
}
return val, nil
}
return "", nil
}