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

Commit

Permalink
Fixes #799: Exposes collector plugin defaults to the framework (#959)
Browse files Browse the repository at this point in the history
* Switched ctypes.ConfigValueX to pass by value instead of reference

* Adds GetAll to config policy tree

* Fixes #799: Exposes collector plugin defaults to the framework
  • Loading branch information
tiffanyfay authored Jun 17, 2016
1 parent 57b3124 commit cc6189c
Show file tree
Hide file tree
Showing 18 changed files with 177 additions and 33 deletions.
28 changes: 28 additions & 0 deletions control/control_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,32 @@ func TestMetricConfig(t *testing.T) {
time.Sleep(100 * time.Millisecond)
})

Convey("config provided by defaults", t, func() {
c := New(GetDefaultConfig())
c.Config.Plugins.All.AddItem("password", ctypes.ConfigValueStr{Value: "pwd"})
c.Start()
lpe := newListenToPluginEvent()
c.eventManager.RegisterHandler("Control.PluginLoaded", lpe)
_, err := load(c, fixtures.JSONRPCPluginPath)
So(err, ShouldBeNil)
<-lpe.done
cd := cdata.NewNode()
m1 := fixtures.MockMetricType{
Namespace_: core.NewNamespace("intel", "mock", "foo"),
}

Convey("So metric should be valid with config", func() {
errs := c.validateMetricTypeSubscription(m1, cd)
So(errs, ShouldBeNil)
})
Convey("So mock should have name: bob config from defaults", func() {
So(c.Config.Plugins.pluginCache["0:mock:1"].Table()["name"], ShouldResemble, ctypes.ConfigValueStr{Value: "bob"})
})

c.Stop()
time.Sleep(100 * time.Millisecond)
})

Convey("nil config provided by task", t, func() {
config := GetDefaultConfig()
config.Plugins.All.AddItem("password", ctypes.ConfigValueStr{Value: "testval"})
Expand Down Expand Up @@ -1234,6 +1260,8 @@ func TestCollectMetrics(t *testing.T) {
for i := range cr {
So(cr[i].Data(), ShouldContainSubstring, "The mock collected data!")
So(cr[i].Data(), ShouldContainSubstring, "test=true")
So(cr[i].Data(), ShouldContainSubstring, "name={bob}")
So(cr[i].Data(), ShouldContainSubstring, "password={testval}")
}
}
ap := c.AvailablePlugins()
Expand Down
2 changes: 1 addition & 1 deletion control/plugin/client/httpjsonrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func TestHTTPJSONRPC(t *testing.T) {
cpn, cserrs := node.Process(mts[0].Config().Table())
So(cpn, ShouldNotBeNil)
So((*cpn)["somefloat"].Type(), ShouldResemble, "float")
So((*cpn)["somefloat"].(*ctypes.ConfigValueFloat).Value, ShouldResemble, 3.14)
So((*cpn)["somefloat"].(ctypes.ConfigValueFloat).Value, ShouldResemble, 3.14)
So(cserrs.Errors(), ShouldBeEmpty)
})
})
Expand Down
2 changes: 1 addition & 1 deletion control/plugin/cpolicy/bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (b *BoolRule) Validate(cv ctypes.ConfigValue) error {
// Default returns a default value is it exists.
func (b *BoolRule) Default() ctypes.ConfigValue {
if b.default_ != nil {
return &ctypes.ConfigValueBool{Value: *b.default_}
return ctypes.ConfigValueBool{Value: *b.default_}
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestConfigPolicyRuleBool(t *testing.T) {
r, e := NewBoolRule("thekey", true, true)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "bool")
So(r.Default().(*ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(r.Default().(ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(e, ShouldBeNil)
})

Expand All @@ -69,7 +69,7 @@ func TestConfigPolicyRuleBool(t *testing.T) {
Convey("passes with string config value", func() {
r, e := NewBoolRule("thekey", true, true)
So(r.Default().Type(), ShouldEqual, "bool")
So(r.Default().(*ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(r.Default().(ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(e, ShouldBeNil)

v := ctypes.ConfigValueBool{Value: true}
Expand All @@ -81,7 +81,7 @@ func TestConfigPolicyRuleBool(t *testing.T) {
Convey("errors with non-string config value", func() {
r, e := NewBoolRule("thekey", true, true)
So(r.Default().Type(), ShouldEqual, "bool")
So(r.Default().(*ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(r.Default().(ctypes.ConfigValueBool).Value, ShouldEqual, true)
So(e, ShouldBeNil)

v := ctypes.ConfigValueInt{Value: 1}
Expand Down
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func (f *FloatRule) Validate(cv ctypes.ConfigValue) error {
// Default returns the rule's default value
func (f *FloatRule) Default() ctypes.ConfigValue {
if f.default_ != nil {
return &ctypes.ConfigValueFloat{Value: *f.default_}
return ctypes.ConfigValueFloat{Value: *f.default_}
}
return nil
}
Expand All @@ -198,14 +198,14 @@ func (f *FloatRule) SetMaximum(m float64) {

func (i *FloatRule) Minimum() ctypes.ConfigValue {
if i.minimum != nil {
return &ctypes.ConfigValueFloat{Value: *i.minimum}
return ctypes.ConfigValueFloat{Value: *i.minimum}
}
return nil
}

func (i *FloatRule) Maximum() ctypes.ConfigValue {
if i.maximum != nil {
return &ctypes.ConfigValueFloat{Value: *i.maximum}
return ctypes.ConfigValueFloat{Value: *i.maximum}
}
return nil
}
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestConfigPolicyRuleFloat(t *testing.T) {
r, e := NewFloatRule("thekey", true, 7)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "float")
So(r.Default().(*ctypes.ConfigValueFloat).Value, ShouldEqual, 7)
So(r.Default().(ctypes.ConfigValueFloat).Value, ShouldEqual, 7)
So(e, ShouldBeNil)
})

Expand Down Expand Up @@ -84,7 +84,7 @@ func TestConfigPolicyRuleFloat(t *testing.T) {
r, e := NewFloatRule("thekey", true, 7)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "float")
So(r.Default().(*ctypes.ConfigValueFloat).Value, ShouldEqual, 7)
So(r.Default().(ctypes.ConfigValueFloat).Value, ShouldEqual, 7)
So(e, ShouldBeNil)

v := ctypes.ConfigValueFloat{Value: 1}
Expand All @@ -105,7 +105,7 @@ func TestConfigPolicyRuleFloat(t *testing.T) {
r, e := NewFloatRule("thekey", true, 2)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "float")
So(r.Default().(*ctypes.ConfigValueFloat).Value, ShouldEqual, 2)
So(r.Default().(ctypes.ConfigValueFloat).Value, ShouldEqual, 2)
So(e, ShouldBeNil)

v := ctypes.ConfigValueStr{Value: "wat"}
Expand Down
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/integer.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (i *IntRule) Validate(cv ctypes.ConfigValue) error {
// Default return this rules default value
func (i *IntRule) Default() ctypes.ConfigValue {
if i.default_ != nil {
return &ctypes.ConfigValueInt{Value: *i.default_}
return ctypes.ConfigValueInt{Value: *i.default_}
}
return nil
}
Expand All @@ -201,14 +201,14 @@ func (i *IntRule) SetMaximum(m int) {

func (i *IntRule) Minimum() ctypes.ConfigValue {
if i.minimum != nil {
return &ctypes.ConfigValueInt{Value: *i.minimum}
return ctypes.ConfigValueInt{Value: *i.minimum}
}
return nil
}

func (i *IntRule) Maximum() ctypes.ConfigValue {
if i.maximum != nil {
return &ctypes.ConfigValueInt{Value: *i.maximum}
return ctypes.ConfigValueInt{Value: *i.maximum}
}
return nil
}
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/integer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestConfigPolicyRuleInteger(t *testing.T) {
r, e := NewIntegerRule("thekey", true, 7)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "integer")
So(r.Default().(*ctypes.ConfigValueInt).Value, ShouldEqual, 7)
So(r.Default().(ctypes.ConfigValueInt).Value, ShouldEqual, 7)
So(e, ShouldBeNil)
})

Expand Down Expand Up @@ -84,7 +84,7 @@ func TestConfigPolicyRuleInteger(t *testing.T) {
r, e := NewIntegerRule("thekey", true, 7)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "integer")
So(r.Default().(*ctypes.ConfigValueInt).Value, ShouldEqual, 7)
So(r.Default().(ctypes.ConfigValueInt).Value, ShouldEqual, 7)
So(e, ShouldBeNil)

v := ctypes.ConfigValueInt{Value: 1}
Expand All @@ -105,7 +105,7 @@ func TestConfigPolicyRuleInteger(t *testing.T) {
r, e := NewIntegerRule("thekey", true, 2)
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "integer")
So(r.Default().(*ctypes.ConfigValueInt).Value, ShouldEqual, 2)
So(r.Default().(ctypes.ConfigValueInt).Value, ShouldEqual, 2)
So(e, ShouldBeNil)

v := ctypes.ConfigValueStr{Value: "wat"}
Expand Down
30 changes: 29 additions & 1 deletion control/plugin/cpolicy/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (c *ConfigPolicyNode) Process(m map[string]ctypes.ConfigValue) (*map[string
} else {
// If it was required add error
if rule.Required() {
e := errors.New(fmt.Sprintf("required key missing (%s)", key))
e := fmt.Errorf("required key missing (%s)", key)
pErrors.AddError(e)
} else {
// If default returns we should add it
Expand All @@ -189,6 +189,34 @@ func (c *ConfigPolicyNode) Process(m map[string]ctypes.ConfigValue) (*map[string
return &m, pErrors
}

// AddDefaults validates and returns a processed policy node or nil and error if validation has failed
func (c *ConfigPolicyNode) AddDefaults(m map[string]ctypes.ConfigValue) (*map[string]ctypes.ConfigValue, *ProcessingErrors) {
c.mutex.Lock()
defer c.mutex.Unlock()
pErrors := NewProcessingErrors()
// Loop through each rule and process
for key, rule := range c.rules {
// items exists for rule
if _, ok := m[key]; ok {
pErrors.AddError(fmt.Errorf("The key \"%v\" already has a default policy for this plugin", key))
} else {
// If it was required add error
if !rule.Required() {
// If default returns we should add it
cv := rule.Default()
if cv != nil {
m[key] = cv
}
}
}
}

if pErrors.HasErrors() {
return nil, pErrors
}
return &m, pErrors
}

// Merges a ConfigPolicyNode on top of this one (overwriting items where it occurs).
func (c ConfigPolicyNode) Merge(n ctree.Node) ctree.Node {
// Because Add only allows the ConfigPolicyNode type we
Expand Down
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ func TestConfigPolicyNode(t *testing.T) {
m2, pe := n.Process(m)

So(len(pe.Errors()), ShouldEqual, 0)
So((*m2)["username"].(*ctypes.ConfigValueStr).Value, ShouldEqual, "root")
So((*m2)["port"].(*ctypes.ConfigValueInt).Value, ShouldEqual, 8080)
So((*m2)["nova"].(*ctypes.ConfigValueBool).Value, ShouldEqual, true)
So((*m2)["username"].(ctypes.ConfigValueStr).Value, ShouldEqual, "root")
So((*m2)["port"].(ctypes.ConfigValueInt).Value, ShouldEqual, 8080)
So((*m2)["nova"].(ctypes.ConfigValueBool).Value, ShouldEqual, true)
})

Convey("defaults don't fix missing values on required", t, func() {
Expand Down
2 changes: 1 addition & 1 deletion control/plugin/cpolicy/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (s *StringRule) Validate(cv ctypes.ConfigValue) error {
// Returns a default value is it exists.
func (s *StringRule) Default() ctypes.ConfigValue {
if s.default_ != nil {
return &ctypes.ConfigValueStr{Value: *s.default_}
return ctypes.ConfigValueStr{Value: *s.default_}
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions control/plugin/cpolicy/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestConfigPolicyRuleString(t *testing.T) {
r, e := NewStringRule("thekey", true, "wat")
So(r.Default(), ShouldNotBeNil)
So(r.Default().Type(), ShouldEqual, "string")
So(r.Default().(*ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(r.Default().(ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(e, ShouldBeNil)
})

Expand All @@ -69,7 +69,7 @@ func TestConfigPolicyRuleString(t *testing.T) {
Convey("passes with string config value", func() {
r, e := NewStringRule("thekey", true, "wat")
So(r.Default().Type(), ShouldEqual, "string")
So(r.Default().(*ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(r.Default().(ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(e, ShouldBeNil)

v := ctypes.ConfigValueStr{Value: "foo"}
Expand All @@ -81,7 +81,7 @@ func TestConfigPolicyRuleString(t *testing.T) {
Convey("errors with non-string config value", func() {
r, e := NewStringRule("thekey", true, "wat")
So(r.Default().Type(), ShouldEqual, "string")
So(r.Default().(*ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(r.Default().(ctypes.ConfigValueStr).Value, ShouldEqual, "wat")
So(e, ShouldBeNil)

v := ctypes.ConfigValueInt{Value: 1}
Expand Down
16 changes: 16 additions & 0 deletions control/plugin/cpolicy/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,22 @@ func (c *ConfigPolicy) Get(ns []string) *ConfigPolicyNode {
}
}

func (c *ConfigPolicy) GetAll() map[string]*ConfigPolicyNode {
// Automatically freeze on first Get
if !c.config.Frozen() {
c.config.Freeze()
}

ret := map[string]*ConfigPolicyNode{}
for key, node := range c.config.GetAll() {
switch t := node.(type) {
case *ConfigPolicyNode:
ret[key] = t
}
}
return ret
}

// Freezes the ConfigPolicy from future writes (adds) and triggers compression
// of tree into read-performant version.
func (c *ConfigPolicy) Freeze() {
Expand Down
4 changes: 2 additions & 2 deletions control/plugin/cpolicy/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestConfigPolicy(t *testing.T) {
Convey("retrieves store policy", func() {
gc := cp.Get(ns)
So(gc.rules["username"].Required(), ShouldEqual, false)
So(gc.rules["username"].Default().(*ctypes.ConfigValueStr).Value, ShouldEqual, "root")
So(gc.rules["username"].Default().(ctypes.ConfigValueStr).Value, ShouldEqual, "root")
So(gc.rules["password"].Required(), ShouldEqual, true)
})
Convey("encode & decode", func() {
Expand All @@ -69,7 +69,7 @@ func TestConfigPolicy(t *testing.T) {
So(gc.rules["password"].Required(), ShouldEqual, true)
So(gc.rules["username"].Default(), ShouldNotBeNil)
So(gc.rules["password"].Default(), ShouldBeNil)
So(gc.rules["username"].Default().(*ctypes.ConfigValueStr).Value, ShouldEqual, "root")
So(gc.rules["username"].Default().(ctypes.ConfigValueStr).Value, ShouldEqual, "root")
})

})
Expand Down
42 changes: 41 additions & 1 deletion control/plugin_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/intelsdi-x/snap/control/plugin/client"
"github.com/intelsdi-x/snap/control/plugin/cpolicy"
"github.com/intelsdi-x/snap/core"
"github.com/intelsdi-x/snap/core/cdata"
"github.com/intelsdi-x/snap/core/serror"
)

Expand Down Expand Up @@ -356,10 +357,49 @@ func (p *pluginManager) LoadPlugin(details *pluginDetails, emitter gomit.Emitter
lPlugin.ConfigPolicy = cp

if resp.Type == plugin.CollectorPluginType {
cfgNode := p.pluginConfig.getPluginConfigDataNode(core.PluginType(resp.Type), resp.Meta.Name, resp.Meta.Version)

if lPlugin.ConfigPolicy != nil {
// Get plugin config defaults
defaults := cdata.NewNode()
cpolicies := lPlugin.ConfigPolicy.GetAll()
for _, cpolicy := range cpolicies {
_, errs := cpolicy.AddDefaults(defaults.Table())
if len(errs.Errors()) > 0 {
for _, err := range errs.Errors() {
pmLogger.WithFields(log.Fields{
"_block": "load-plugin",
"plugin-type": "collector",
"plugin-name": ap.Name(),
"plugin-version": ap.Version(),
"plugin-id": ap.ID(),
}).Error(err.Error())
}
return nil, serror.New(errors.New("error getting default config"))
}
}

// Update config policy with defaults
cfgNode.ReverseMerge(defaults)
cp, err = c.GetConfigPolicy()
if err != nil {
pmLogger.WithFields(log.Fields{
"_block": "load-plugin",
"plugin-type": "collector",
"error": err.Error(),
"plugin-name": ap.Name(),
"plugin-version": ap.Version(),
"plugin-id": ap.ID(),
}).Error("error in getting config policy")
return nil, serror.New(err)
}
lPlugin.ConfigPolicy = cp
}

colClient := ap.client.(client.PluginCollectorClient)

cfg := plugin.ConfigType{
ConfigDataNode: p.pluginConfig.getPluginConfigDataNode(core.PluginType(resp.Type), resp.Meta.Name, resp.Meta.Version),
ConfigDataNode: cfgNode,
}

metricTypes, err := colClient.GetMetricTypes(cfg)
Expand Down
Loading

0 comments on commit cc6189c

Please sign in to comment.