From bad8d57f4b60f5d8e0b8c0349f7df73de5027f07 Mon Sep 17 00:00:00 2001 From: Chris Grindstaff Date: Fri, 25 Oct 2024 15:06:56 -0400 Subject: [PATCH] feat: log cluster name and version with poller metadata --- cmd/collectors/ems/ems.go | 4 +- cmd/collectors/keyperf/keyperf.go | 4 +- cmd/collectors/power.go | 2 +- cmd/collectors/rest/plugins/health/health.go | 4 +- cmd/collectors/rest/plugins/volume/volume.go | 2 +- .../volumeanalytics/volumeanalytics.go | 2 +- cmd/collectors/rest/rest.go | 23 +++++---- cmd/collectors/rest/templating.go | 2 +- cmd/collectors/restperf/restperf.go | 2 +- cmd/collectors/storagegrid/rest/client.go | 21 ++++----- .../storagegrid/rest/dummyclient.go | 8 ++-- cmd/collectors/storagegrid/storagegrid.go | 14 ++++-- cmd/collectors/zapi/collector/zapi.go | 25 ++++++---- cmd/poller/collector/asup.go | 8 ++++ cmd/poller/collector/collector.go | 21 +++------ cmd/poller/collector/helpers.go | 6 ++- cmd/poller/poller.go | 47 +++++++++++++++---- cmd/tools/generate/counter.go | 5 +- cmd/tools/generate/generate.go | 4 +- cmd/tools/rest/client.go | 31 ++++-------- cmd/tools/rest/rest.go | 4 +- integration/test/counter_test.go | 2 +- pkg/conf/remotes.go | 8 ++++ pkg/util/util.go | 9 ++++ 24 files changed, 153 insertions(+), 105 deletions(-) create mode 100644 pkg/conf/remotes.go diff --git a/cmd/collectors/ems/ems.go b/cmd/collectors/ems/ems.go index b394a4a78..019d55249 100644 --- a/cmd/collectors/ems/ems.go +++ b/cmd/collectors/ems/ems.go @@ -124,8 +124,8 @@ func (e *Ems) InitMatrix() error { // overwrite from abstract collector mat.Object = e.Object // Add system (cluster) name - mat.SetGlobalLabel("cluster", e.Client.Cluster().Name) - mat.SetGlobalLabel("cluster_uuid", e.Client.Cluster().UUID) + mat.SetGlobalLabel("cluster", e.Client.Remote().Name) + mat.SetGlobalLabel("cluster_uuid", e.Client.Remote().UUID) if e.Params.HasChildS("labels") { for _, l := range e.Params.GetChildS("labels").GetChildren() { diff --git a/cmd/collectors/keyperf/keyperf.go b/cmd/collectors/keyperf/keyperf.go index ebfb6298a..5b91fd852 100644 --- a/cmd/collectors/keyperf/keyperf.go +++ b/cmd/collectors/keyperf/keyperf.go @@ -65,6 +65,8 @@ func (kp *KeyPerf) Init(a *collector.AbstractCollector) error { return err } + kp.Remote = kp.Client.Remote() + if kp.Prop.TemplatePath, err = kp.LoadTemplate(); err != nil { return err } @@ -105,7 +107,7 @@ func (kp *KeyPerf) InitMatrix() error { // overwrite from abstract collector mat.Object = kp.Prop.Object // Add system (cluster) name - mat.SetGlobalLabel("cluster", kp.Client.Cluster().Name) + mat.SetGlobalLabel("cluster", kp.Remote.Name) if kp.Params.HasChildS("labels") { for _, l := range kp.Params.GetChildS("labels").GetChildren() { mat.SetGlobalLabel(l.GetNameS(), l.GetContentS()) diff --git a/cmd/collectors/power.go b/cmd/collectors/power.go index 82628bd22..bdd39e687 100644 --- a/cmd/collectors/power.go +++ b/cmd/collectors/power.go @@ -50,7 +50,7 @@ func collectChassisFRU(client *rest.Client, logger *slog.Logger) (map[string]int if !cn.Exists() { logger.Warn( "fru has no connected nodes", - slog.String("cluster", client.Cluster().Name), + slog.String("cluster", client.Remote().Name), slog.String("fru", r.Get("fru_name").String()), ) continue diff --git a/cmd/collectors/rest/plugins/health/health.go b/cmd/collectors/rest/plugins/health/health.go index c612a96bd..3aaedce27 100644 --- a/cmd/collectors/rest/plugins/health/health.go +++ b/cmd/collectors/rest/plugins/health/health.go @@ -109,7 +109,7 @@ func (h *Health) initMatrix(name string, prefix string, inputMat map[string]*mat func (h *Health) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, *util.Metadata, error) { data := dataMap[h.Object] h.client.Metadata.Reset() - clusterVersion := h.client.Cluster().GetVersion() + clusterVersion := h.client.Remote().Version ontapVersion, err := goversion.NewVersion(clusterVersion) if err != nil { h.SLogger.Error( @@ -270,7 +270,7 @@ func (h *Health) collectVolumeRansomwareAlerts() int { instance *matrix.Instance ) volumeRansomwareAlertCount := 0 - clusterVersion := h.client.Cluster().GetVersion() + clusterVersion := h.client.Remote().Version ontapVersion, err := goversion.NewVersion(clusterVersion) if err != nil { h.SLogger.Error("Failed to parse version", slogx.Err(err), slog.String("version", clusterVersion)) diff --git a/cmd/collectors/rest/plugins/volume/volume.go b/cmd/collectors/rest/plugins/volume/volume.go index 6b1832cdf..d5b42a9f1 100644 --- a/cmd/collectors/rest/plugins/volume/volume.go +++ b/cmd/collectors/rest/plugins/volume/volume.go @@ -90,7 +90,7 @@ func (v *Volume) Init() error { // Read template to decide inclusion of flexgroup constituents v.includeConstituents = collectors.ReadPluginKey(v.Params, "include_constituents") // ARW feature is supported from 9.10 onwards, If we ask this field in Rest call in plugin, then it will be failed. - v.isArwSupportedVersion, err = util.VersionAtLeast(v.client.Cluster().GetVersion(), ARWSupportedVersion) + v.isArwSupportedVersion, err = util.VersionAtLeast(v.client.Remote().Version, ARWSupportedVersion) if err != nil { return fmt.Errorf("unable to get version %w", err) } diff --git a/cmd/collectors/rest/plugins/volumeanalytics/volumeanalytics.go b/cmd/collectors/rest/plugins/volumeanalytics/volumeanalytics.go index 835b95631..197e50464 100644 --- a/cmd/collectors/rest/plugins/volumeanalytics/volumeanalytics.go +++ b/cmd/collectors/rest/plugins/volumeanalytics/volumeanalytics.go @@ -99,7 +99,7 @@ func (v *VolumeAnalytics) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matr v.client.Metadata.Reset() cluster := data.GetGlobalLabels()["cluster"] - clusterVersion := v.client.Cluster().GetVersion() + clusterVersion := v.client.Remote().Version ontapVersion, err := goversion.NewVersion(clusterVersion) if err != nil { v.SLogger.Error("Failed to parse version", diff --git a/cmd/collectors/rest/rest.go b/cmd/collectors/rest/rest.go index 95ee382a4..fdc4d5528 100644 --- a/cmd/collectors/rest/rest.go +++ b/cmd/collectors/rest/rest.go @@ -37,8 +37,8 @@ import ( "log/slog" "os" "regexp" + "slices" "sort" - "strconv" "strings" "time" ) @@ -201,6 +201,8 @@ func (r *Rest) InitClient() error { } r.Client.TraceLogSet(r.Name, r.Params) + r.Remote = r.Client.Remote() + return nil } @@ -209,7 +211,7 @@ func (r *Rest) InitMatrix() error { // overwrite from abstract collector mat.Object = r.Prop.Object // Add system (cluster) name - mat.SetGlobalLabel("cluster", r.Client.Cluster().Name) + mat.SetGlobalLabel("cluster", r.Remote.Name) if r.Params.HasChildS("labels") { for _, l := range r.Params.GetChildS("labels").GetChildren() { @@ -333,7 +335,7 @@ func (r *Rest) PollCounter() (map[string]*matrix.Matrix, error) { apiD := time.Since(startTime) startTime = time.Now() - v, err := util.VersionAtLeast(r.Client.Cluster().GetVersion(), "9.11.1") + v, err := util.VersionAtLeast(r.Remote.Version, "9.11.1") if err != nil { return nil, err } @@ -709,6 +711,7 @@ func (r *Rest) CollectAutoSupport(p *collector.Payload) { for k := range r.Prop.Counters { counters = append(counters, k) } + slices.Sort(counters) var schedules = make([]collector.Schedule, 0) tasks := r.Params.GetChildS("schedule") @@ -745,14 +748,18 @@ func (r *Rest) CollectAutoSupport(p *collector.Payload) { InstanceInfo: &info, }) - if (r.Name == "Rest" && (r.Object == "Volume" || r.Object == "Node")) || r.Name == "Ems" { - version := r.Client.Cluster().Version - p.Target.Version = strconv.Itoa(version[0]) + "." + strconv.Itoa(version[1]) + "." + strconv.Itoa(version[2]) + isRest := r.Name == "Rest" + isKeyPerf := r.Name == "KeyPerf" + isEMS := r.Name == "Ems" + isOneOfVolumeNode := r.Object == "Volume" || r.Object == "Node" + + if ((isRest || isKeyPerf) && isOneOfVolumeNode) || isEMS { + p.Target.Version = r.Remote.Version p.Target.Model = "cdot" if p.Target.Serial == "" { - p.Target.Serial = r.Client.Cluster().UUID + p.Target.Serial = r.Remote.UUID } - p.Target.ClusterUUID = r.Client.Cluster().UUID + p.Target.ClusterUUID = r.Remote.UUID if r.Object == "Node" || r.Name == "ems" { var ( diff --git a/cmd/collectors/rest/templating.go b/cmd/collectors/rest/templating.go index 421e5c7ab..0e29bc9c8 100644 --- a/cmd/collectors/rest/templating.go +++ b/cmd/collectors/rest/templating.go @@ -18,7 +18,7 @@ import ( func (r *Rest) LoadTemplate() (string, error) { jitter := r.Params.GetChildContentS("jitter") - template, path, err := r.ImportSubTemplate("", TemplateFn(r.Params, r.Object), jitter, r.Client.Cluster().Version) + template, path, err := r.ImportSubTemplate("", TemplateFn(r.Params, r.Object), jitter, r.Remote.Version) if err != nil { return "", err } diff --git a/cmd/collectors/restperf/restperf.go b/cmd/collectors/restperf/restperf.go index 84e482ff9..f7956d02a 100644 --- a/cmd/collectors/restperf/restperf.go +++ b/cmd/collectors/restperf/restperf.go @@ -197,7 +197,7 @@ func (r *RestPerf) InitMatrix() error { // overwrite from abstract collector mat.Object = r.Prop.Object // Add system (cluster) name - mat.SetGlobalLabel("cluster", r.Client.Cluster().Name) + mat.SetGlobalLabel("cluster", r.Remote.Name) if r.Params.HasChildS("labels") { for _, l := range r.Params.GetChildS("labels").GetChildren() { mat.SetGlobalLabel(l.GetNameS(), l.GetContentS()) diff --git a/cmd/collectors/storagegrid/rest/client.go b/cmd/collectors/storagegrid/rest/client.go index f13b1f2d9..7f9144a7b 100644 --- a/cmd/collectors/storagegrid/rest/client.go +++ b/cmd/collectors/storagegrid/rest/client.go @@ -18,6 +18,7 @@ import ( "math" "net/http" "net/url" + "strconv" "strings" "time" ) @@ -35,7 +36,7 @@ type Client struct { buffer *bytes.Buffer Logger *slog.Logger baseURL string - Cluster Cluster + Remote conf.Remote token string Timeout time.Duration logRest bool // used to log Rest request/response @@ -44,13 +45,6 @@ type Client struct { Metadata *util.Metadata } -type Cluster struct { - Name string - Info string - UUID string - Version [3]int -} - func NewClient(pollerName string, clientTimeout string, c *auth.Credentials) (*Client, error) { var ( poller *conf.Poller @@ -303,13 +297,13 @@ func (c *Client) Init(retries int) error { } results = gjson.ParseBytes(content) - c.Cluster.Name = results.Get("data.name").String() + c.Remote.Name = results.Get("data.name").String() if content, err = c.GetGridRest("grid/license"); err != nil { continue } results = gjson.ParseBytes(content) - c.Cluster.UUID = results.Get("data.systemId").String() + c.Remote.UUID = results.Get("data.systemId").String() return nil } @@ -324,9 +318,10 @@ func (c *Client) SetVersion(v string) error { // e.g 11.6.0.3-20220802.2201.f58633a segments := newVersion.Segments() if len(segments) >= 3 { - c.Cluster.Version[0] = check(segments[0]) - c.Cluster.Version[1] = check(segments[1]) - c.Cluster.Version[2] = check(segments[2]) + v0 := check(segments[0]) + v1 := check(segments[1]) + v2 := check(segments[2]) + c.Remote.Version = strconv.Itoa(v0) + "." + strconv.Itoa(v1) + "." + strconv.Itoa(v2) } else { return fmt.Errorf("failed to parse version %s", v) } diff --git a/cmd/collectors/storagegrid/rest/dummyclient.go b/cmd/collectors/storagegrid/rest/dummyclient.go index 5977eff49..f0875a644 100644 --- a/cmd/collectors/storagegrid/rest/dummyclient.go +++ b/cmd/collectors/storagegrid/rest/dummyclient.go @@ -2,6 +2,7 @@ package rest import ( "bytes" + "github.com/netapp/harvest/v2/pkg/conf" "github.com/netapp/harvest/v2/pkg/util" "log/slog" @@ -20,11 +21,10 @@ func NewDummyClient() *Client { buffer := new(bytes.Buffer) - cluster := Cluster{ + remote := conf.Remote{ Name: "TestCluster", - Info: "TestInfo", UUID: "TestUUID", - Version: [3]int{1, 2, 3}, + Version: "1.2.3", } client := &Client{ @@ -33,7 +33,7 @@ func NewDummyClient() *Client { buffer: buffer, Logger: slog.Default(), baseURL: "http://example.com", - Cluster: cluster, + Remote: remote, token: "TestToken", Timeout: time.Second * 10, logRest: true, diff --git a/cmd/collectors/storagegrid/storagegrid.go b/cmd/collectors/storagegrid/storagegrid.go index cdff8d2cb..0eb215388 100644 --- a/cmd/collectors/storagegrid/storagegrid.go +++ b/cmd/collectors/storagegrid/storagegrid.go @@ -15,6 +15,7 @@ import ( "github.com/netapp/harvest/v2/pkg/util" "github.com/tidwall/gjson" "log/slog" + "slices" "sort" "strconv" "strings" @@ -91,7 +92,7 @@ func (s *StorageGrid) InitMatrix() error { // overwrite from abstract collector mat.Object = s.Props.Object // Add system (cluster) name - mat.SetGlobalLabel("cluster", s.client.Cluster.Name) + mat.SetGlobalLabel("cluster", s.client.Remote.Name) if s.Params.HasChildS("labels") { for _, l := range s.Params.GetChildS("labels").GetChildren() { @@ -441,6 +442,8 @@ func (s *StorageGrid) initClient() error { } s.client.TraceLogSet(s.Name, s.Params) + s.Remote = s.client.Remote + return nil } @@ -492,7 +495,7 @@ func (s *StorageGrid) LoadTemplate() (string, error) { jitter := s.Params.GetChildContentS("jitter") - template, path, err = s.ImportSubTemplate("", rest.TemplateFn(s.Params, s.Object), jitter, s.client.Cluster.Version) + template, path, err = s.ImportSubTemplate("", rest.TemplateFn(s.Params, s.Object), jitter, s.Remote.Version) if err != nil { return "", err } @@ -540,6 +543,7 @@ func (s *StorageGrid) CollectAutoSupport(p *collector.Payload) { for k := range s.Props.Counters { counters = append(counters, k) } + slices.Sort(counters) var schedules = make([]collector.Schedule, 0) tasks := s.Params.GetChildS("schedule") @@ -576,10 +580,10 @@ func (s *StorageGrid) CollectAutoSupport(p *collector.Payload) { InstanceInfo: &info, }) - version := s.client.Cluster.Version - p.Target.Version = strconv.Itoa(version[0]) + "." + strconv.Itoa(version[1]) + "." + strconv.Itoa(version[2]) + version := s.Remote.Version + p.Target.Version = version p.Target.Model = "storagegrid" - p.Target.ClusterUUID = s.client.Cluster.UUID + p.Target.ClusterUUID = s.Remote.UUID if p.Nodes == nil { nodeIDs, err := s.getNodeUuids() diff --git a/cmd/collectors/zapi/collector/zapi.go b/cmd/collectors/zapi/collector/zapi.go index 7556f2b27..33fbbd6be 100644 --- a/cmd/collectors/zapi/collector/zapi.go +++ b/cmd/collectors/zapi/collector/zapi.go @@ -25,6 +25,7 @@ import ( "github.com/netapp/harvest/v2/pkg/slogx" "github.com/netapp/harvest/v2/pkg/util" "log/slog" + "slices" "sort" "strconv" "strings" @@ -93,7 +94,7 @@ func (z *Zapi) InitVars() error { if z.Options.IsTest { z.Client = client.NewTestClient() templateName := z.Params.GetChildS("objects").GetChildContentS(z.Object) - template, path, err := z.ImportSubTemplate("cdot", templateName, jitter, [3]int{9, 8, 0}) + template, path, err := z.ImportSubTemplate("cdot", templateName, jitter, "9.8.0") if err != nil { return err } @@ -119,13 +120,16 @@ func (z *Zapi) InitVars() error { } // save for ASUP messaging - z.HostUUID = z.Client.Serial() - version := z.Client.Version() - z.HostVersion = strconv.Itoa(version[0]) + "." + strconv.Itoa(version[1]) + "." + strconv.Itoa(version[2]) - z.HostModel = model - templateName := z.Params.GetChildS("objects").GetChildContentS(z.Object) + versionT := z.Client.Version() + z.Remote = conf.Remote{ + Name: z.Client.Name(), + UUID: z.Client.Serial(), + Model: model, + Version: strconv.Itoa(versionT[0]) + "." + strconv.Itoa(versionT[1]) + "." + strconv.Itoa(versionT[2]), + } - template, path, err := z.ImportSubTemplate(model, templateName, jitter, z.Client.Version()) + templateName := z.Params.GetChildS("objects").GetChildContentS(z.Object) + template, path, err := z.ImportSubTemplate(model, templateName, jitter, z.Remote.Version) if err != nil { return err } @@ -436,6 +440,7 @@ func (z *Zapi) CollectAutoSupport(p *collector.Payload) { c := z.Params.GetChildS("counters") c.FlatList(&counters, "") } + slices.Sort(counters) var schedules = make([]collector.Schedule, 0) tasks := z.Params.GetChildS("schedule") @@ -480,10 +485,10 @@ func (z *Zapi) CollectAutoSupport(p *collector.Payload) { }) if z.Name == "Zapi" && (z.Object == "Volume" || z.Object == "Node" || z.Object == "Qtree") { - p.Target.Version = z.GetHostVersion() - p.Target.Model = z.GetHostModel() + p.Target.Version = z.Remote.Version + p.Target.Model = z.Remote.Model if p.Target.Serial == "" { - p.Target.Serial = z.GetHostUUID() + p.Target.Serial = z.Remote.UUID } p.Target.ClusterUUID = z.Client.ClusterUUID() diff --git a/cmd/poller/collector/asup.go b/cmd/poller/collector/asup.go index 0cfd3c5bd..4b312fd1f 100644 --- a/cmd/poller/collector/asup.go +++ b/cmd/poller/collector/asup.go @@ -226,6 +226,14 @@ func BuildAndWriteAutoSupport(collectors []Collector, status *matrix.Matrix, pol attachMemory(msg) // give each collector the opportunity to attach autosupport information + slices.SortStableFunc(collectors, func(a, b Collector) int { + nameCmp := cmp.Compare(a.GetName(), b.GetName()) + if nameCmp == 0 { + return cmp.Compare(a.GetObject(), b.GetObject()) + } + return nameCmp + }) + for _, c := range collectors { c.CollectAutoSupport(msg) } diff --git a/cmd/poller/collector/collector.go b/cmd/poller/collector/collector.go index 548215715..4984740fe 100644 --- a/cmd/poller/collector/collector.go +++ b/cmd/poller/collector/collector.go @@ -70,6 +70,7 @@ type Collector interface { LoadPlugins(*node.Node, Collector, string) error LoadPlugin(string, *plugin.AbstractPlugin) plugin.Plugin CollectAutoSupport(p *Payload) + GetRemote() conf.Remote } const ( @@ -106,11 +107,9 @@ type AbstractCollector struct { collectCount uint64 // count of collected data points // this is different from what the collector will have in its metadata, since this variable // holds count independent of the poll interval of the collector, used to give stats to Poller - countMux *sync.Mutex // used for atomic access to collectCount - Auth *auth.Credentials // used for authing the collector - HostVersion string - HostModel string - HostUUID string + countMux *sync.Mutex // used for atomic access to collectCount + Auth *auth.Credentials // used for authing the collector + Remote conf.Remote } func New(name, object string, o *options.Options, params *node.Node, credentials *auth.Credentials) *AbstractCollector { @@ -291,16 +290,8 @@ func (c *AbstractCollector) GetMetadata() *matrix.Matrix { return c.Metadata } -func (c *AbstractCollector) GetHostModel() string { - return c.HostModel -} - -func (c *AbstractCollector) GetHostVersion() string { - return c.HostVersion -} - -func (c *AbstractCollector) GetHostUUID() string { - return c.HostUUID +func (c *AbstractCollector) GetRemote() conf.Remote { + return c.Remote } // Start will run the collector in an infinite loop diff --git a/cmd/poller/collector/helpers.go b/cmd/poller/collector/helpers.go index 669866ef9..ce421fc35 100644 --- a/cmd/poller/collector/helpers.go +++ b/cmd/poller/collector/helpers.go @@ -54,7 +54,7 @@ var versionRegex = regexp.MustCompile(`\d+\.\d+\.\d+`) // are sorted, and we try to return the subtemplate that most closely matches the ONTAP version. // Model is cdot or 7mode, filename is the name of the subtemplate, and ver is the // ONTAP version triple (generation, major, minor) -func (c *AbstractCollector) ImportSubTemplate(model, filename, jitter string, ver [3]int) (*node.Node, string, error) { +func (c *AbstractCollector) ImportSubTemplate(model, filename, jitter string, verWithDots string) (*node.Node, string, error) { var ( selectedVersion, templatePath string @@ -72,7 +72,9 @@ func (c *AbstractCollector) ImportSubTemplate(model, filename, jitter string, ve // string like "volume.yaml,custom_volume.yaml" filenames := strings.Split(filename, ",") - verWithDots := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(ver)), "."), "[]") + if verWithDots == "" { + verWithDots = "0.0.0" + } ontapVersion, err := version.NewVersion(verWithDots) if err != nil { return nil, "", fmt.Errorf("no best-fit template found due to err=%w", err) diff --git a/cmd/poller/poller.go b/cmd/poller/poller.go index 87f38ba67..c0dfa40eb 100644 --- a/cmd/poller/poller.go +++ b/cmd/poller/poller.go @@ -135,6 +135,7 @@ type Poller struct { auth *auth.Credentials hasPromExporter bool maxRssBytes uint64 + startTime time.Time } // Init starts Poller, reads parameters, opens zeroLog handler, initializes metadata, @@ -148,6 +149,7 @@ func (p *Poller) Init() error { configPath string ) + p.startTime = time.Now() p.options = opts.SetDefaults() p.name = opts.Poller @@ -384,7 +386,7 @@ func (p *Poller) Init() error { if tools != nil && tools.AsupDisabled { logger.Info("Autosupport is disabled") } else { - if p.targetIsOntap() { + if p.collectorIsBuiltin() { // Write the payload after asupFirstWrite. // This is to examine the autosupport contents // Nothing is sent, sending happens based on the asupSchedule @@ -569,6 +571,7 @@ func (p *Poller) Run() { upe := 0 // up exporters // update status of collectors + var remote conf.Remote for _, c := range p.collectors { code, _, msg := c.GetStatus() @@ -587,8 +590,14 @@ func (p *Poller) Run() { instance.SetLabel("reason", strings.ReplaceAll(msg, "\"", "")) } } + + remote = c.GetRemote() } + // add remote version and name to metadata + p.status.GetInstance("remote").SetLabel("version", remote.Version) + p.status.GetInstance("remote").SetLabel("name", remote.Name) + // update status of exporters for _, ee := range p.exporters { code, status, msg := ee.GetStatus() @@ -1083,6 +1092,9 @@ func (p *Poller) loadMetadata() { instance, _ := p.metadataTarget.NewInstance("host") pInstance, _ := p.status.NewInstance("host") + pRemote, _ := p.status.NewInstance("remote") + pRemote.SetExportable(false) + instance.SetLabel("addr", p.target) pInstance.SetLabel("addr", p.target) @@ -1129,13 +1141,21 @@ var pollerCmd = &cobra.Command{ Run: startPoller, } -// Returns true if at least one collector is known -// to collect from an Ontap system (needs to be updated -// when we add other Ontap collectors, e.g. REST) +// Returns true if at least one collector is one of the builtin collectors. +func (p *Poller) collectorIsBuiltin() bool { + for _, c := range p.collectors { + _, ok := util.IsCollector[c.GetName()] + if ok { + return true + } + } + return false +} +// Returns true if at least one collector is known to collect from an Ontap system. func (p *Poller) targetIsOntap() bool { for _, c := range p.collectors { - _, ok := util.IsCollector[c.GetName()] + _, ok := util.IsONTAPCollector[c.GetName()] if ok { return true } @@ -1432,11 +1452,19 @@ func (p *Poller) logPollerMetadata() (map[string]*matrix.Matrix, error) { } rss, _ := p.status.LazyGetValueFloat64("memory.rss", "host") + remoteName := p.status.GetInstance("remote").GetLabel("name") + remoteVersion := p.status.GetInstance("remote").GetLabel("version") + slog.Info( "Metadata", - slog.Float64("rssKB", rss), - slog.Uint64("maxRssKB", p.maxRssBytes/1024), + slog.Float64("rssMB", rss/1024), + slog.Uint64("maxRssMB", p.maxRssBytes/1024/1024), slog.String("version", strings.TrimSpace(version.String())), + slog.Group("remote", + slog.String("name", remoteName), + slog.String("version", remoteVersion), + ), + slog.Uint64("uptimeSeconds", uint64(time.Since(p.startTime).Seconds())), ) return nil, nil @@ -1449,6 +1477,9 @@ func (p *Poller) sendHarvestVersion() error { err error ) + if !p.targetIsOntap() { + return nil + } // connect to the cluster and retrieve the system version if poller, err = conf.PollerNamed(opts.Poller); err != nil { return err @@ -1466,7 +1497,7 @@ func (p *Poller) sendHarvestVersion() error { // If it is, send a harvestTag to the cluster to indicate that Harvest is running // Otherwise, do nothing - ontapVersion, err := goversion.NewVersion(connection.Cluster().GetVersion()) + ontapVersion, err := goversion.NewVersion(connection.Remote().Version) if err != nil { return err } diff --git a/cmd/tools/generate/counter.go b/cmd/tools/generate/counter.go index e8f1cb3cd..9f18ac8b5 100644 --- a/cmd/tools/generate/counter.go +++ b/cmd/tools/generate/counter.go @@ -772,7 +772,7 @@ func updateDescription(description string) string { return s } -func generateCounterTemplate(counters map[string]Counter, version [3]int) { +func generateCounterTemplate(counters map[string]Counter, version string) { targetPath := "docs/ontap-metrics.md" t, err := template.New("counter.tmpl").ParseFiles("cmd/tools/generate/counter.tmpl") if err != nil { @@ -853,12 +853,11 @@ func generateCounterTemplate(counters map[string]Counter, version [3]int) { } } table.Render() - verWithDots := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(version)), "."), "[]") c := CounterTemplate{ Counters: values, CounterMetaData: CounterMetaData{ Date: time.Now().Format("2006-Jan-02"), - OntapVersion: verWithDots, + OntapVersion: version, }, } diff --git a/cmd/tools/generate/generate.go b/cmd/tools/generate/generate.go index 4559e0877..128b32f96 100644 --- a/cmd/tools/generate/generate.go +++ b/cmd/tools/generate/generate.go @@ -554,7 +554,7 @@ func writeAdminSystemd(configFp string) { println(color.Colorize("✓", color.Green) + " HTTP SD file: " + harvestAdminService + " created") } -func BuildMetrics(dir, configPath, pollerName string) (map[string]Counter, rest.Cluster) { +func BuildMetrics(dir, configPath, pollerName string) (map[string]Counter, conf.Remote) { var ( poller *conf.Poller err error @@ -612,7 +612,7 @@ func BuildMetrics(dir, configPath, pollerName string) (map[string]Counter, rest. } } - return counters, restClient.Cluster() + return counters, restClient.Remote() } func generateDescription(dPath string, data []byte, counters map[string]Counter) { diff --git a/cmd/tools/rest/client.go b/cmd/tools/rest/client.go index 4eef5dd77..613335f98 100644 --- a/cmd/tools/rest/client.go +++ b/cmd/tools/rest/client.go @@ -40,7 +40,7 @@ type Client struct { buffer *bytes.Buffer Logger *slog.Logger baseURL string - cluster Cluster + remote conf.Remote token string Timeout time.Duration logRest bool // used to log Rest request/response @@ -48,13 +48,6 @@ type Client struct { Metadata *util.Metadata } -type Cluster struct { - Name string - Info string - UUID string - Version [3]int -} - func New(poller *conf.Poller, timeout time.Duration, credentials *auth.Credentials) (*Client, error) { var ( client Client @@ -347,12 +340,12 @@ func (c *Client) UpdateClusterInfo(retries int) error { } results := gjson.ParseBytes(content) - c.cluster.Name = results.Get("name").String() - c.cluster.UUID = results.Get("uuid").String() - c.cluster.Info = results.Get("version.full").String() - c.cluster.Version[0] = int(results.Get("version.generation").Int()) - c.cluster.Version[1] = int(results.Get("version.major").Int()) - c.cluster.Version[2] = int(results.Get("version.minor").Int()) + c.remote.Name = results.Get("name").String() + c.remote.UUID = results.Get("uuid").String() + c.remote.Version = + results.Get("version.generation").String() + "." + + results.Get("version.major").String() + "." + + results.Get("version.minor").String() return nil } return err @@ -362,12 +355,6 @@ func (c *Client) Init(retries int) error { return c.UpdateClusterInfo(retries) } -func (c *Client) Cluster() Cluster { - return c.cluster -} - -func (cl Cluster) GetVersion() string { - ver := cl.Version - return fmt.Sprintf("%d.%d.%d", ver[0], ver[1], ver[2]) - +func (c *Client) Remote() conf.Remote { + return c.remote } diff --git a/cmd/tools/rest/rest.go b/cmd/tools/rest/rest.go index b2a7658f8..3ca87f141 100644 --- a/cmd/tools/rest/rest.go +++ b/cmd/tools/rest/rest.go @@ -217,8 +217,8 @@ func fetchData(poller *conf.Poller, timeout time.Duration) (*Results, error) { Poller: poller.Name, Addr: poller.Addr, API: args.API, - Version: client.Cluster().GetVersion(), - ClusterName: client.cluster.Name, + Version: client.remote.Version, + ClusterName: client.remote.Name, Records: records, NumRecords: len(records), PollDurationMs: time.Since(now).Milliseconds(), diff --git a/integration/test/counter_test.go b/integration/test/counter_test.go index a55a07536..c17f608a7 100644 --- a/integration/test/counter_test.go +++ b/integration/test/counter_test.go @@ -134,7 +134,7 @@ func visitRestTemplates(dir string, client *rest2.Client, eachTemp func(path str return nil } - r := eachTemp(path, client.Cluster().GetVersion(), client) + r := eachTemp(path, client.Remote().Version, client) for k, v := range r { result[k] = v } diff --git a/pkg/conf/remotes.go b/pkg/conf/remotes.go new file mode 100644 index 000000000..eac95f8a1 --- /dev/null +++ b/pkg/conf/remotes.go @@ -0,0 +1,8 @@ +package conf + +type Remote struct { + Name string + Model string + UUID string + Version string +} diff --git a/pkg/util/util.go b/pkg/util/util.go index 7356ea96e..b44ff2631 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -27,6 +27,15 @@ import ( var arrayRegex = regexp.MustCompile(`^([a-zA-Z][\w.]*)(\.[0-9#])`) +var IsONTAPCollector = map[string]struct{}{ + "ZapiPerf": {}, + "Zapi": {}, + "Rest": {}, + "RestPerf": {}, + "KeyPerf": {}, + "Ems": {}, +} + var IsCollector = map[string]struct{}{ "ZapiPerf": {}, "Zapi": {},