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

Commit

Permalink
expose a metric's config policy via the catalog
Browse files Browse the repository at this point in the history
  • Loading branch information
pittma committed Sep 9, 2015
1 parent 2de9772 commit 012297b
Show file tree
Hide file tree
Showing 19 changed files with 318 additions and 245 deletions.
9 changes: 9 additions & 0 deletions cmd/pulsectl/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ var (
flMetricNamespace,
},
},
{
Name: "get",
Usage: "get details on a single metric",
Action: getMetric,
Flags: []cli.Flag{
flMetricVersion,
flMetricNamespace,
},
},
},
},
}
Expand Down
77 changes: 54 additions & 23 deletions cmd/pulsectl/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package main
import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"text/tabwriter"
"time"

"github.com/codegangsta/cli"
)
Expand All @@ -33,35 +33,66 @@ func listMetrics(ctx *cli.Context) {
}

/*
NAMESPACE VERSION
/intel/dummy/foo 1,2
/intel/dummy/bar 1
NAMESPACE VERSION
/intel/dummy/foo 1,2
/intel/dummy/bar 1
*/
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
printFields(w, false, 0, "NAMESPACE", "VERSION")
metsByVer := make(map[string][]string)
for _, mt := range mts.Catalog {
v := make([]string, 0)
for k, _ := range mt.Versions {
v = append(v, k)
}
printFields(w, false, 0, mt.Namespace, strings.Join(sortVersions(v), ","))
metsByVer[mt.Namespace] = append(metsByVer[mt.Namespace], strconv.Itoa(mt.Version))
}
printFields(w, false, 0, "NAMESPACE", "VERSIONS")
for ns, vers := range metsByVer {
printFields(w, false, 0, ns, strings.Join(vers, ","))
}
w.Flush()
return
}

func sortVersions(vers []string) []string {
ivers := make([]int, len(vers))
svers := make([]string, len(vers))
var err error
for i, v := range vers {
if ivers[i], err = strconv.Atoi(v); err != nil {
fmt.Printf("Error metric version err: %v", err)
os.Exit(1)
}
func getMetric(ctx *cli.Context) {
ns := ctx.String("metric-namespace")
ver := ctx.Int("metric-version")
if ns == "" {
fmt.Println("namespace is required")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
return
}
sort.Ints(ivers)
for i, v := range ivers {
svers[i] = fmt.Sprintf("%d", v)
if ver == 0 {
ver = -1
}
return svers
metrics := pClient.FetchMetrics(ns, ver)
if metrics.Err != nil {
fmt.Println(metrics.Err)
return
}
metric := metrics.Catalog[0]

/*
NAMESPACE VERSION LAST ADVERTISED TIME
/intel/dummy/foo 2 Wed, 09 Sep 2015 10:01:04 PDT
Rules for collecting /intel/dummy/foo:
NAME TYPE DEFAULT REQUIRED
name string bob false
password string true
*/

w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
printFields(w, false, 0, "NAMESPACE", "VERSION", "LAST ADVERTISED TIME")
printFields(w, false, 0, metric.Namespace, metric.Version, time.Unix(metric.LastAdvertisedTimestamp, 0).Format(time.RFC1123))
w.Flush()
fmt.Printf("\n Rules for collecting %s:\n\n", metric.Namespace)
printFields(w, true, 4, "NAME", "TYPE", "DEFAULT", "REQUIRED")
for _, rule := range metric.Policy {
defMap, ok := rule.Default.(map[string]interface{})
if ok {
def := defMap["Value"]
printFields(w, true, 4, rule.Name, rule.Type, def, rule.Required)
} else {
printFields(w, true, 4, rule.Name, rule.Type, "", rule.Required)
}
}
w.Flush()
}
35 changes: 8 additions & 27 deletions control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,43 +554,24 @@ func (p *pluginControl) MetricCatalog() ([]core.CatalogedMetric, error) {
// FetchMetrics returns the metrics which fall under the given namespace
// NOTE: The returned data from this function should be considered constant and read only
func (p *pluginControl) FetchMetrics(ns []string, version int) ([]core.CatalogedMetric, error) {
cat := make([]*metricCatalogItem, 0)

mts, err := p.metricCatalog.Fetch(ns)
if err != nil {
return nil, err
}

// probably can be serious optimized later
cmt := make([]core.CatalogedMetric, 0, len(mts))
for _, mt := range mts {
if version > 0 && mt.Version() != version {
continue
}
f := false
for _, mci := range cat {
if mci.namespace == mt.NamespaceAsString() {
mci.versions[mt.version] = mt
f = true
if version > 0 {
if mt.version == version {
cmt = append(cmt, mt)
}
} else {
cmt = append(cmt, mt)
}
if !f {
mci := &metricCatalogItem{
namespace: mt.NamespaceAsString(),
versions: make(map[int]core.Metric),
}
mci.versions[mt.version] = mt
cat = append(cat, mci)
}
}

ncat := make([]core.CatalogedMetric, len(cat))
for i, _ := range cat {
ncat[i] = cat[i]
}
return ncat, nil
return cmt, nil
}

func (p *pluginControl) GetMetric(ns []string, ver int) (core.Metric, error) {
func (p *pluginControl) GetMetric(ns []string, ver int) (core.CatalogedMetric, error) {
return p.metricCatalog.Get(ns, ver)
}

Expand Down
2 changes: 1 addition & 1 deletion control/control_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ func TestExportedMetricCatalog(t *testing.T) {
t, err := c.MetricCatalog()
So(err, ShouldBeNil)
So(len(t), ShouldEqual, 1)
So(t[0].Namespace(), ShouldResemble, "/foo/bar")
So(t[0].Namespace(), ShouldResemble, []string{"foo", "bar"})
})
Convey("If metric catalog fetch fails", func() {
c.metricCatalog = &mc{e: 2}
Expand Down
6 changes: 5 additions & 1 deletion control/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ func (m *metricType) Config() *cdata.ConfigDataNode {
return m.config
}

func (m *metricType) Policy() *cpolicy.ConfigPolicyNode {
return m.policy.(*cpolicy.ConfigPolicyNode)
}

func (m *metricType) Source() string {
return m.source
}
Expand Down Expand Up @@ -180,7 +184,7 @@ func (mc *metricCatalog) Get(ns []string, version int) (*metricType, perror.Puls
return mc.get(ns, version)
}

// Fetch transactionally retrieves all loadedPlugins
// Fetch transactionally retrieves all metrics which fall under namespace ns
func (mc *metricCatalog) Fetch(ns []string) ([]*metricType, perror.PulseError) {
mc.mutex.Lock()
defer mc.mutex.Unlock()
Expand Down
4 changes: 4 additions & 0 deletions control/plugin/cpolicy/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func (f *FloatRule) MarshalJSON() ([]byte, error) {
})
}

func (s *FloatRule) Type() string {
return "float"
}

// GobEncode encodes a FloatRule into a GOB
func (f *FloatRule) GobEncode() ([]byte, error) {
w := new(bytes.Buffer)
Expand Down
4 changes: 4 additions & 0 deletions control/plugin/cpolicy/integer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func NewIntegerRule(key string, req bool, opts ...int) (*IntRule, error) {
}, nil
}

func (i *IntRule) Type() string {
return "integer"
}

// MarshalJSON marshals a IntRule into JSON
func (i *IntRule) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Expand Down
23 changes: 23 additions & 0 deletions control/plugin/cpolicy/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,29 @@ func (p *ConfigPolicyNode) Add(rules ...Rule) {
}
}

type RuleTable struct {
Name string
Type string
Default interface{}
Required bool
}

func (p *ConfigPolicyNode) RulesAsTable() []RuleTable {
p.mutex.Lock()
defer p.mutex.Unlock()

rt := make([]RuleTable, 0, len(p.rules))
for _, r := range p.rules {
rt = append(rt, RuleTable{
Name: r.Key(),
Type: r.Type(),
Default: r.Default(),
Required: r.Required(),
})
}
return rt
}

// Validates and returns a processed policy node or nil and error if validation has failed
func (c *ConfigPolicyNode) Process(m map[string]ctypes.ConfigValue) (*map[string]ctypes.ConfigValue, *ProcessingErrors) {
c.mutex.Lock()
Expand Down
1 change: 1 addition & 0 deletions control/plugin/cpolicy/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Rule interface {
Validate(ctypes.ConfigValue) error
Default() ctypes.ConfigValue
Required() bool
Type() string
}

type rule struct {
Expand Down
4 changes: 4 additions & 0 deletions control/plugin/cpolicy/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func NewStringRule(key string, req bool, opts ...string) (*StringRule, error) {
}, nil
}

func (s *StringRule) Type() string {
return "string"
}

// MarshalJSON marshals a StringRule into JSON
func (s *StringRule) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Expand Down
8 changes: 5 additions & 3 deletions core/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import (
"strings"
"time"

"github.com/intelsdi-x/pulse/control/plugin/cpolicy"
"github.com/intelsdi-x/pulse/core/cdata"
)

// Metric represents a Pulse metric collected or to be collected
type Metric interface {
RequestedMetric
LastAdvertisedTime() time.Time
Config() *cdata.ConfigDataNode
LastAdvertisedTime() time.Time
Data() interface{}
Source() string
Timestamp() time.Time
Expand All @@ -24,8 +25,9 @@ type RequestedMetric interface {
}

type CatalogedMetric interface {
Namespace() string
Versions() map[int]Metric
RequestedMetric
LastAdvertisedTime() time.Time
Policy() *cpolicy.ConfigPolicyNode
}

func JoinNamespace(ns []string) string {
Expand Down
2 changes: 1 addition & 1 deletion mgmt/rest/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func httpRespToAPIResp(rsp *http.Response) (*rest.APIResponse, error) {

jErr := json.Unmarshal(b, resp)
if jErr != nil {
return nil, err
return nil, jErr
}
if resp == nil {
// Catch corner case where JSON gives no error but resp is nil
Expand Down
Loading

0 comments on commit 012297b

Please sign in to comment.