Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit 7b01c63

Browse files
Support global tags in global config
The tags will be applied in the order global tags < task manifest tags
1 parent 3e2dd25 commit 7b01c63

11 files changed

Lines changed: 236 additions & 122 deletions

control/config.go

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,18 @@ type pluginConfigItem struct {
7171
// UnmarshalJSON method in this same file needs to be modified to
7272
// match the field mapping that is defined here
7373
type Config struct {
74-
MaxRunningPlugins int `json:"max_running_plugins"yaml:"max_running_plugins"`
75-
PluginLoadTimeout int `json:"plugin_load_timeout"yaml:"plugin_load_timeout"`
76-
PluginTrust int `json:"plugin_trust_level"yaml:"plugin_trust_level"`
77-
AutoDiscoverPath string `json:"auto_discover_path"yaml:"auto_discover_path"`
78-
KeyringPaths string `json:"keyring_paths"yaml:"keyring_paths"`
79-
CacheExpiration jsonutil.Duration `json:"cache_expiration"yaml:"cache_expiration"`
80-
Plugins *pluginConfig `json:"plugins"yaml:"plugins"`
81-
ListenAddr string `json:"listen_addr,omitempty"yaml:"listen_addr"`
82-
ListenPort int `json:"listen_port,omitempty"yaml:"listen_port"`
83-
Pprof bool `json:"pprof"yaml:"pprof"`
84-
MaxPluginRestarts int `json:"max_plugin_restarts"yaml:"max_plugin_restarts"`
74+
MaxRunningPlugins int `json:"max_running_plugins"yaml:"max_running_plugins"`
75+
PluginLoadTimeout int `json:"plugin_load_timeout"yaml:"plugin_load_timeout"`
76+
PluginTrust int `json:"plugin_trust_level"yaml:"plugin_trust_level"`
77+
AutoDiscoverPath string `json:"auto_discover_path"yaml:"auto_discover_path"`
78+
KeyringPaths string `json:"keyring_paths"yaml:"keyring_paths"`
79+
CacheExpiration jsonutil.Duration `json:"cache_expiration"yaml:"cache_expiration"`
80+
Plugins *pluginConfig `json:"plugins"yaml:"plugins"`
81+
Tags map[string]map[string]string `json:"tags,omitempty"yaml:"tags"`
82+
ListenAddr string `json:"listen_addr,omitempty"yaml:"listen_addr"`
83+
ListenPort int `json:"listen_port,omitempty"yaml:"listen_port"`
84+
Pprof bool `json:"pprof"yaml:"pprof"`
85+
MaxPluginRestarts int `json:"max_plugin_restarts"yaml:"max_plugin_restarts"`
8586
}
8687

8788
const (
@@ -117,6 +118,11 @@ const (
117118
"properties" : {},
118119
"additionalProperties": true
119120
},
121+
"tags": {
122+
"type": ["object", "null"],
123+
"properties" : {},
124+
"additionalProperties": true
125+
},
120126
"listen_addr": {
121127
"type": "string"
122128
},
@@ -147,6 +153,7 @@ func GetDefaultConfig() *Config {
147153
KeyringPaths: defaultKeyringPaths,
148154
CacheExpiration: jsonutil.Duration{defaultCacheExpiration},
149155
Plugins: newPluginConfig(),
156+
Tags: newPluginTags(),
150157
Pprof: defaultPprof,
151158
MaxPluginRestarts: MaxPluginRestartCount,
152159
}
@@ -182,6 +189,10 @@ func newPluginConfig() *pluginConfig {
182189
}
183190
}
184191

192+
func newPluginTags() map[string]map[string]string {
193+
return make(map[string]map[string]string)
194+
}
195+
185196
func (p *Config) GetPluginConfigDataNode(pluginType core.PluginType, name string, ver int) cdata.ConfigDataNode {
186197
return *p.Plugins.getPluginConfigDataNode(pluginType, name, ver)
187198
}
@@ -295,14 +306,16 @@ func (p *pluginConfig) switchPluginConfigType(pluginType core.PluginType) *plugi
295306
case core.PublisherPluginType:
296307
return p.Publisher
297308
}
298-
// never happens
299309
return nil
300310
}
301311

302312
func (p *pluginConfig) mergePluginConfigDataNode(pluginType core.PluginType, name string, ver int, cdn *cdata.ConfigDataNode) {
303313
// clear cache
304314
p.pluginCache = make(map[string]*cdata.ConfigDataNode)
305315
configItem := p.switchPluginConfigType(pluginType)
316+
if configItem == nil {
317+
return
318+
}
306319

307320
// merge new config into existing
308321
if res, ok := configItem.Plugins[name]; ok {
@@ -331,6 +344,9 @@ func (p *pluginConfig) deletePluginConfigDataNodeField(pluginType core.PluginTyp
331344
// clear cache
332345
p.pluginCache = make(map[string]*cdata.ConfigDataNode)
333346
configItem := p.switchPluginConfigType(pluginType)
347+
if configItem == nil {
348+
return
349+
}
334350

335351
if res, ok := configItem.Plugins[name]; ok {
336352
if res2, ok2 := res.Versions[ver]; ok2 {
@@ -340,7 +356,7 @@ func (p *pluginConfig) deletePluginConfigDataNodeField(pluginType core.PluginTyp
340356
res.DeleteItem(key)
341357
return
342358
}
343-
p.Collector.All.DeleteItem(key)
359+
configItem.All.DeleteItem(key)
344360

345361
}
346362

@@ -358,6 +374,9 @@ func (p *pluginConfig) getPluginConfigDataNode(pluginType core.PluginType, name
358374

359375
// check for plugin config
360376
configItem := p.switchPluginConfigType(pluginType)
377+
if configItem == nil {
378+
return nil
379+
}
361380
p.pluginCache[key].Merge(configItem.All)
362381
if res, ok := configItem.Plugins[name]; ok {
363382
p.pluginCache[key].Merge(res.ConfigDataNode)

control/config_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ func TestPluginConfig(t *testing.T) {
101101
So(cfg.Plugins.Collector.Plugins["pcm"].Versions[1].Table()["user"], ShouldResemble, ctypes.ConfigValueStr{Value: "john"})
102102
So(cfg.Plugins.Processor, ShouldNotBeNil)
103103
So(cfg.Plugins.Processor.Plugins["movingaverage"].Table()["user"], ShouldResemble, ctypes.ConfigValueStr{Value: "jane"})
104+
So(cfg.Tags["/intel/psutil"], ShouldNotBeNil)
105+
So(cfg.Tags["/intel/psutil"]["context"], ShouldNotBeNil)
106+
So(cfg.Tags["/intel/psutil"]["context"], ShouldEqual, "config_example")
107+
So(cfg.Tags["/"], ShouldNotBeNil)
108+
So(cfg.Tags["/"]["color"], ShouldNotBeNil)
109+
So(cfg.Tags["/"]["color"], ShouldEqual, "green")
104110

105111
Convey("We can access the config for plugins", func() {
106112
Convey("Getting the values of a specific version of a plugin", func() {

control/control.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ type managesPlugins interface {
127127
SetMetricCatalog(catalogsMetrics)
128128
GenerateArgs(logLevel int) plugin.Arg
129129
SetPluginConfig(*pluginConfig)
130+
SetPluginTags(map[string]map[string]string)
131+
AddStandardAndWorkflowTags(core.Metric, map[string]map[string]string) core.Metric
130132
SetPluginLoadTimeout(int)
131133
}
132134

@@ -174,6 +176,13 @@ func OptSetConfig(cfg *Config) PluginControlOpt {
174176
}
175177
}
176178

179+
// OptSetTags sets the plugin control tags.
180+
func OptSetTags(tags map[string]map[string]string) PluginControlOpt {
181+
return func(c *pluginControl) {
182+
c.pluginManager.SetPluginTags(tags)
183+
}
184+
}
185+
177186
// MaximumPluginRestarts
178187
func MaxPluginRestarts(cfg *Config) PluginControlOpt {
179188
return func(*pluginControl) {
@@ -188,6 +197,7 @@ func New(cfg *Config) *pluginControl {
188197
MaxRunningPlugins(cfg.MaxRunningPlugins),
189198
CacheExpiration(cfg.CacheExpiration.Duration),
190199
OptSetConfig(cfg),
200+
OptSetTags(cfg.Tags),
191201
MaxPluginRestarts(cfg),
192202
}
193203
c := &pluginControl{}
@@ -977,7 +987,7 @@ func (p *pluginControl) CollectMetrics(id string, allTags map[string]map[string]
977987
// plugin authors to inadvertently overwrite or not pass along the data
978988
// passed to CollectMetrics so we will help them out here.
979989
for i := range m {
980-
m[i] = addStandardAndWorkflowTags(m[i], allTags)
990+
m[i] = p.pluginManager.AddStandardAndWorkflowTags(m[i], allTags)
981991
}
982992
metrics = append(metrics, m...)
983993
wg.Done()

control/control_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,17 @@ func (m *MockPluginManagerBadSwap) LoadPlugin(*pluginDetails, gomit.Emitter) (*l
7171
func (m *MockPluginManagerBadSwap) UnloadPlugin(c core.Plugin) (*loadedPlugin, serror.SnapError) {
7272
return nil, serror.New(errors.New("fake"))
7373
}
74-
func (m *MockPluginManagerBadSwap) get(string) (*loadedPlugin, error) { return nil, nil }
75-
func (m *MockPluginManagerBadSwap) teardown() {}
76-
func (m *MockPluginManagerBadSwap) SetPluginConfig(*pluginConfig) {}
77-
func (m *MockPluginManagerBadSwap) SetPluginLoadTimeout(int) {}
78-
func (m *MockPluginManagerBadSwap) SetMetricCatalog(catalogsMetrics) {}
79-
func (m *MockPluginManagerBadSwap) SetEmitter(gomit.Emitter) {}
80-
func (m *MockPluginManagerBadSwap) GenerateArgs(int) plugin.Arg { return plugin.Arg{} }
74+
func (m *MockPluginManagerBadSwap) get(string) (*loadedPlugin, error) { return nil, nil }
75+
func (m *MockPluginManagerBadSwap) teardown() {}
76+
func (m *MockPluginManagerBadSwap) SetPluginConfig(*pluginConfig) {}
77+
func (m *MockPluginManagerBadSwap) SetPluginTags(map[string]map[string]string) {}
78+
func (m *MockPluginManagerBadSwap) AddStandardAndWorkflowTags(met core.Metric, allTags map[string]map[string]string) core.Metric {
79+
return nil
80+
}
81+
func (m *MockPluginManagerBadSwap) SetPluginLoadTimeout(int) {}
82+
func (m *MockPluginManagerBadSwap) SetMetricCatalog(catalogsMetrics) {}
83+
func (m *MockPluginManagerBadSwap) SetEmitter(gomit.Emitter) {}
84+
func (m *MockPluginManagerBadSwap) GenerateArgs(int) plugin.Arg { return plugin.Arg{} }
8185

8286
func (m *MockPluginManagerBadSwap) all() map[string]*loadedPlugin {
8387
return m.loadedPlugins.table

control/metrics.go

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -618,39 +618,6 @@ func appendIfMissing(keys []string, ns string) []string {
618618
return append(keys, ns)
619619
}
620620

621-
func addStandardAndWorkflowTags(m core.Metric, allTags map[string]map[string]string) core.Metric {
622-
hostname := hostnameReader.Hostname()
623-
624-
tags := m.Tags()
625-
if tags == nil {
626-
tags = map[string]string{}
627-
}
628-
// apply standard tag
629-
tags[core.STD_TAG_PLUGIN_RUNNING_ON] = hostname
630-
631-
// apply tags from workflow
632-
for ns, nsTags := range allTags {
633-
if strings.HasPrefix(m.Namespace().String(), ns) {
634-
for k, v := range nsTags {
635-
tags[k] = v
636-
}
637-
}
638-
}
639-
640-
metric := plugin.MetricType{
641-
Namespace_: m.Namespace(),
642-
Version_: m.Version(),
643-
LastAdvertisedTime_: m.LastAdvertisedTime(),
644-
Config_: m.Config(),
645-
Data_: m.Data(),
646-
Tags_: tags,
647-
Description_: m.Description(),
648-
Unit_: m.Unit(),
649-
Timestamp_: m.Timestamp(),
650-
}
651-
return metric
652-
}
653-
654621
// isTuple returns true when incoming namespace's element has been recognized as a tuple, otherwise returns false
655622
// notice, that the tuple is a string which starts with `core.TuplePrefix`, ends with `core.TupleSuffix`
656623
// and contains at least one `core.TupleSeparator`, e.g. (host0;host1)

control/metrics_small_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ func TestAddTagsFromWorkflow(t *testing.T) {
4040
hostnameReader = &mockHostnameReader{}
4141
tcs := prepareTestCases()
4242
Convey("Adding tags to metric type", t, func() {
43+
p := newPluginManager()
4344
for _, tc := range tcs {
44-
outputTags := addStandardAndWorkflowTags(tc.Metric, tc.InputTags).Tags()
45+
outputTags := p.AddStandardAndWorkflowTags(tc.Metric, tc.InputTags).Tags()
4546
So(outputTags, ShouldNotBeNil)
4647
So(outputTags, ShouldResemble, tc.ExpectedTags)
4748
}

control/plugin_manager.go

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ type pluginManager struct {
236236
loadedPlugins *loadedPlugins
237237
logPath string
238238
pluginConfig *pluginConfig
239+
pluginTags map[string]map[string]string
239240
pprof bool
240241
}
241242

@@ -249,6 +250,7 @@ func newPluginManager(opts ...pluginManagerOpt) *pluginManager {
249250
loadedPlugins: newLoadedPlugins(),
250251
logPath: logPath,
251252
pluginConfig: newPluginConfig(),
253+
pluginTags: newPluginTags(),
252254
}
253255

254256
for _, opt := range opts {
@@ -274,6 +276,13 @@ func OptSetPluginConfig(cf *pluginConfig) pluginManagerOpt {
274276
}
275277
}
276278

279+
// OptSetPluginTags sets the tags on the plugin manager
280+
func OptSetPluginTags(tags map[string]map[string]string) pluginManagerOpt {
281+
return func(p *pluginManager) {
282+
p.pluginTags = tags
283+
}
284+
}
285+
277286
// SetPluginLoadTimeout sets plugin load timeout
278287
func (p *pluginManager) SetPluginLoadTimeout(to int) {
279288
p.pluginLoadTimeout = to
@@ -284,6 +293,11 @@ func (p *pluginManager) SetPluginConfig(cf *pluginConfig) {
284293
p.pluginConfig = cf
285294
}
286295

296+
// SetPluginTags sets plugin tags
297+
func (p *pluginManager) SetPluginTags(tags map[string]map[string]string) {
298+
p.pluginTags = tags
299+
}
300+
287301
// SetMetricCatalog sets metric catalog
288302
func (p *pluginManager) SetMetricCatalog(mc catalogsMetrics) {
289303
p.metricCatalog = mc
@@ -481,7 +495,7 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter
481495
}
482496

483497
//Add standard tags
484-
nmt = addStandardAndWorkflowTags(nmt, nil)
498+
nmt = p.AddStandardAndWorkflowTags(nmt, nil)
485499

486500
if err := p.metricCatalog.AddLoadedMetricType(lPlugin, nmt); err != nil {
487501
pmLogger.WithFields(log.Fields{
@@ -624,3 +638,65 @@ func (p *pluginManager) all() map[string]*loadedPlugin {
624638
defer p.loadedPlugins.RUnlock()
625639
return p.loadedPlugins.table
626640
}
641+
642+
func hasPrefix(ns1 []string, ns2 []string) bool {
643+
for i := range ns2 {
644+
if i > len(ns1)-1 || ns1[i] != ns2[i] {
645+
return false
646+
}
647+
}
648+
return true
649+
}
650+
651+
func split(ns string) []string {
652+
// the first character is the separator
653+
if len(ns) <= 1 {
654+
return nil
655+
}
656+
sep := string(ns[0])
657+
ns = strings.TrimSuffix(ns, sep)
658+
ns = strings.TrimPrefix(ns, sep)
659+
660+
return strings.Split(ns, sep)
661+
}
662+
663+
func (p *pluginManager) AddStandardAndWorkflowTags(m core.Metric, allTags map[string]map[string]string) core.Metric {
664+
hostname := hostnameReader.Hostname()
665+
666+
tags := m.Tags()
667+
if tags == nil {
668+
tags = map[string]string{}
669+
}
670+
// apply standard tag
671+
tags[core.STD_TAG_PLUGIN_RUNNING_ON] = hostname
672+
673+
// apply tags from global tags
674+
for ns, nsTags := range p.pluginTags {
675+
if hasPrefix(m.Namespace().Strings(), split(ns)) {
676+
for k, v := range nsTags {
677+
tags[k] = v
678+
}
679+
}
680+
}
681+
// apply tags from workflow
682+
for ns, nsTags := range allTags {
683+
if hasPrefix(m.Namespace().Strings(), split(ns)) {
684+
for k, v := range nsTags {
685+
tags[k] = v
686+
}
687+
}
688+
}
689+
690+
metric := plugin.MetricType{
691+
Namespace_: m.Namespace(),
692+
Version_: m.Version(),
693+
LastAdvertisedTime_: m.LastAdvertisedTime(),
694+
Config_: m.Config(),
695+
Data_: m.Data(),
696+
Tags_: tags,
697+
Description_: m.Description(),
698+
Unit_: m.Unit(),
699+
Timestamp_: m.Timestamp(),
700+
}
701+
return metric
702+
}

control/plugin_manager_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ func TestLoadPlugin(t *testing.T) {
113113
Convey("with a plugin config a plugin loads successfully", func() {
114114
cfg := GetDefaultConfig()
115115
cfg.Plugins.Collector.Plugins["mock"] = newPluginConfigItem(optAddPluginConfigItem("test", ctypes.ConfigValueBool{Value: true}))
116-
p := newPluginManager(OptSetPluginConfig(cfg.Plugins))
116+
tags := newPluginTags()
117+
tags["/intel/mock"] = make(map[string]string)
118+
tags["/intel/mock"]["context"] = "plugin_manager_test"
119+
p := newPluginManager(OptSetPluginConfig(cfg.Plugins), OptSetPluginTags(tags))
117120
p.SetMetricCatalog(newMetricCatalog())
118121
lp, serr := loadPlugin(p, fixtures.PluginPathMock2)
119122

@@ -127,7 +130,9 @@ func TestLoadPlugin(t *testing.T) {
127130
So(mts[0].Description(), ShouldResemble, "mock description")
128131
So(mts[0].Unit(), ShouldResemble, "mock unit")
129132
So(mts[0].Tags(), ShouldContainKey, "plugin_running_on")
133+
So(mts[0].Tags(), ShouldContainKey, "context")
130134
So(mts[0].Tags()["plugin_running_on"], ShouldNotResemble, "")
135+
So(mts[0].Tags()["context"], ShouldResemble, "plugin_manager_test")
131136
})
132137

133138
Convey("for a plugin requiring a config an incomplete config will result in a load failure", func() {

docs/SNAPTELD_CONFIGURATION.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ control:
134134
1:
135135
user: tiffany
136136
password: new password
137+
138+
# tags section contains global tags that will be applied on collected metrics
139+
# across tasks.
140+
tags:
141+
/intel/psutil:
142+
datacenter: rennes
143+
# tags all metrics
144+
/:
145+
country: france
137146
```
138147
139148
### snapteld scheduler configurations

0 commit comments

Comments
 (0)