Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting a TableNode #48

Open
stampflit opened this issue Nov 13, 2024 · 2 comments
Open

Getting a TableNode #48

stampflit opened this issue Nov 13, 2024 · 2 comments

Comments

@stampflit
Copy link

There are multiple types in the models package such as TableNode. There is no function that can be used to obtain them as far as I can see. TableNode looks useful, in particular for usage with https://github.com/sleepinggenius2/snmpquery/blob/master/table.go for multiple indices. I can manually construct the ScalarNodes, then RowNode, then ColumnNode and finally TableNode, but this functionality is centered around implementation specifics in gosmi and therefore fit to be offered by the module.

Maybe I'm missing something. But it looks to me like this is only halfways finished.

  • Are there some pointers on how to work with these types? Maybe even some examples / snippets
  • Are contributions to this functionality wanted / needed?

And somewhat related: What's the state of https://github.com/sleepinggenius2/snmpquery/ ? There aren't any examples or tests, so I have no idea whether the code in that repo is in a working state.

Thank you for all your work on the gosmi library. The whole golang snmp ecosystem relies on your work. I hope that this library will continue to exist and become more approachable to use. I don't intend to take up too much of your time with my question and appreciate your help.

@sleepinggenius2
Copy link
Owner

Those models are primarily used by the https://github.com/sleepinggenius2/mib2go repo to convert MIB files into Go code to be used by https://github.com/sleepinggenius2/snmpquery/. It was admittedly a bit of an afterthought, but a requirement at the time, as the gosmi types could not be used directly for codegen, due to their internal state. The original gosmi library was primarily written in one long weekend, so there are a number of design decisions that I would have made differently today. I use all three repos in all the SNMP code that I have written, so they are all in a working state, though could admittedly use some more love. Here's an example of some old monitoring code I had laying around that hopefully helps:

package bng

import (
	"fmt"
	"net"

	"github.com/sleepinggenius2/gosmi/models"
	"github.com/sleepinggenius2/snmpquery"

	"<repo>/common"
	"<repo>/mibs"
)

var PointTypeInterface = common.MustInt64(mibs.CiscoSubscriberSessionMib.CsubAggStatsPointType.Type.Enum.Value("interface"))

type SessionStat struct {
	Index string
	Type  string

	Authenticated   int64
	HighUp          int64
	Pending         int64
	Unauthenticated int64
	Up              int64

	PercentUp float64
}

type Device struct {
	host string
	ip   net.IP

	sessionStats []SessionStat
	totals       map[string]SessionStat
}

func (d *Device) IP() net.IP          { return d.ip }
func (d *Device) PingPayload() []byte { return nil }
func (d *Device) String() string      { return d.ip.String() }

func (d *Device) Points(acc *common.Accumulator) {
	acc.AddTag("host", d.host)
	for _, stat := range d.sessionStats {
		fields := map[string]interface{}{
			"authenticated":   stat.Authenticated,
			"high_up":         stat.HighUp,
			"pending":         stat.Pending,
			"unauthenticated": stat.Unauthenticated,
			"up":              stat.Up,
		}
		if stat.HighUp > 0 {
			fields["percent_up"] = float64(stat.Up) / float64(stat.HighUp)
		}
		acc.AddPoint("cisco_bng_agg_session_stats", map[string]string{"index": stat.Index, "type": stat.Type}, fields)
	}
	for t, stat := range d.totals {
		fields := map[string]interface{}{
			"authenticated":   stat.Authenticated,
			"high_up":         stat.HighUp,
			"pending":         stat.Pending,
			"unauthenticated": stat.Unauthenticated,
			"up":              stat.Up,
		}
		if stat.HighUp > 0 {
			fields["percent_up"] = float64(stat.Up) / float64(stat.HighUp)
		}
		acc.AddPoint("cisco_bng_agg_session_stats_total", map[string]string{"type": t}, fields)
	}
}

func (d *Device) SnmpQuery(client *snmpquery.Client) error {
	table := snmpquery.NewTable(mibs.CiscoSubscriberSessionMib.CsubAggStatsTable, models.FormatEnumName)
	table.NamedColumn("authenticated", mibs.CiscoSubscriberSessionMib.CsubAggStatsAuthSessions)
	table.NamedColumn("high_up", mibs.CiscoSubscriberSessionMib.CsubAggStatsHighUpSessions)
	table.NamedColumn("pending", mibs.CiscoSubscriberSessionMib.CsubAggStatsPendingSessions)
	table.NamedColumn("unauthenticated", mibs.CiscoSubscriberSessionMib.CsubAggStatsUnAuthSessions)
	table.NamedColumn("up", mibs.CiscoSubscriberSessionMib.CsubAggStatsUpSessions)

	rows, err := client.Table(table, PointTypeInterface)
	if err != nil {
		return fmt.Errorf("Aggregate session stats: %w", err)
	}

	d.sessionStats = make([]SessionStat, 0, len(rows))
	d.totals = make(map[string]SessionStat)
	for _, row := range rows {
		sessionStat := SessionStat{
			Index:           row.Index[0].Formatted,
			Type:            row.Index[1].Formatted,
			Authenticated:   row.Values["authenticated"].Int64(),
			HighUp:          row.Values["high_up"].Int64(),
			Pending:         row.Values["pending"].Int64(),
			Unauthenticated: row.Values["unauthenticated"].Int64(),
			Up:              row.Values["up"].Int64(),
		}
		d.sessionStats = append(d.sessionStats, sessionStat)

		total := d.totals[sessionStat.Type]
		total.Authenticated += sessionStat.Authenticated
		total.HighUp += sessionStat.HighUp
		total.Pending += sessionStat.Pending
		total.Unauthenticated += sessionStat.Unauthenticated
		total.Up += sessionStat.Up
		d.totals[sessionStat.Type] = total
	}
	return nil
}

@stampflit
Copy link
Author

Thank you, this is already quite helpful. Also I didn't make the connection, that snmpquery is expected to be used with mib2go. I only gave mib2go a brief glance as I have little use for it.

After looking at the above snippet and mib2go I'm still left confused though: Nowhere in all of this code is TableNode ever referenced.

I assume from

table := snmpquery.NewTable(mibs.CiscoSubscriberSessionMib.CsubAggStatsTable, models.FormatEnumName)

that you assemble the TableNode for CsubAggStatsTable (and probably other tables) in your mibs module.

I have to see how things develop, but hopefully I'll be able to share (some of) my code with similar functionality that builds on top of gosmi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants