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

Feature: SNMP Federated #488

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions conf/sample.config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# more than one running on the same server, this ID will be shown in the WebUI.
# could be set also with SNMPCOL_GENERAL_INSTANCE_ID env var
instanceID = "WAN Communicactions"
location = "my_location"
description = "SNMP Instance running at localhost"

# datadir set the directory where the data will be placed , also sqlite db if set as db engine
# if not set the default datadir will be placed in the configuration directory
Expand Down
2 changes: 1 addition & 1 deletion conf/snmpcollector_schema.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
CREATE TABLE `influx_cfg` (`id` TEXT NULL, `host` TEXT NULL, `port` INTEGER NULL, `db` TEXT NULL, `user` TEXT NULL, `password` TEXT NULL, `retention` TEXT NULL);
CREATE UNIQUE INDEX `UQE_influx_cfg_id` ON `influx_cfg` (`id`);
CREATE TABLE `snmp_device_cfg` (`id` TEXT NULL, `host` TEXT NULL, `port` INTEGER NULL, `retries` INTEGER NULL, `timeout` INTEGER NULL, `repeat` INTEGER NULL, `snmpversion` TEXT NULL, `community` TEXT NULL, `v3seclevel` TEXT NULL, `v3authuser` TEXT NULL, `v3authpass` TEXT NULL, `v3authprot` TEXT NULL, `v3privpass` TEXT NULL, `v3privprot` TEXT NULL, `freq` INTEGER NULL, `outdb` TEXT NULL, `loglevel` TEXT NULL, `logfile` TEXT NULL, `snmpdebug` INTEGER NULL, `devicetagname` TEXT NULL, `devicetagvalue` TEXT NULL, `extra-tags` TEXT NULL);
CREATE TABLE `snmp_device_cfg` (`id` TEXT NULL, `host` TEXT NULL, `port` INTEGER NULL, `retries` INTEGER NULL, `timeout` INTEGER NULL, `repeat` INTEGER NULL, `snmpversion` TEXT NULL, `community` TEXT NULL, `v3seclevel` TEXT NULL, `v3authuser` TEXT NULL, `v3authpass` TEXT NULL, `v3authprot` TEXT NULL, `v3privpass` TEXT NULL, `v3privprot` TEXT NULL, `freq` INTEGER NULL, `outdb` TEXT NULL, `loglevel` TEXT NULL, `logfile` TEXT NULL, `snmpdebug` INTEGER NULL, `devicetagname` TEXT NULL, `devicetagvalue` TEXT NULL, `extra-tags` TEXT NULL, `location` TEXT NULL);
CREATE UNIQUE INDEX `UQE_snmp_device_cfg_id` ON `snmp_device_cfg` (`id`);
CREATE TABLE `snmp_metric_cfg` (`id` TEXT NULL, `field_name` TEXT NULL, `description` TEXT NULL, `baseoid` TEXT NULL, `datasrctype` TEXT NULL, `getrate` INTEGER NULL, `scale` REAL NULL, `shift` REAL NULL, `istag` INTEGER NULL DEFAULT 0);
CREATE UNIQUE INDEX `UQE_snmp_metric_cfg_id` ON `snmp_metric_cfg` (`id`);
Expand Down
2 changes: 1 addition & 1 deletion pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ func AddDeviceInRuntime(k string, cfg *config.SnmpDeviceCfg) {

// LoadConf loads the DB conf and initializes the device metric config.
func LoadConf() {
MainConfig.Database.LoadDbConfig(&DBConfig)
MainConfig.Database.LoadDbConfig(&DBConfig, MainConfig.General.Location)
influxdb = PrepareInfluxDBs()

// begin self monitoring process if needed, before all goroutines
Expand Down
119 changes: 115 additions & 4 deletions pkg/config/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"fmt"
"net"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -43,7 +44,7 @@ type DbObjAction struct {
}

//InitDB initialize de BD configuration
func (dbc *DatabaseCfg) InitDB() error {
func (dbc *DatabaseCfg) InitDB(cfg *GeneralConfig) error {
// Create ORM engine and database
var err error
var dbtype string
Expand Down Expand Up @@ -159,6 +160,103 @@ func (dbc *DatabaseCfg) InitDB() error {
if err = dbc.x.Sync(new(OidConditionCfg)); err != nil {
log.Fatalf("Fail to sync database OidConditionCfg: %v\n", err)
}
if err = dbc.x.Sync(new(PollerLocationCfg)); err != nil {
log.Fatalf("Fail to sync database PollerLocationCfg: %v\n", err)
}
//Lookup if PollerLocation if got Instance_ID else create one
var locationsFound []*PollerLocationCfg
if err = dbc.x.Where("Instance_ID = '" + cfg.InstanceID + "'").Find(&locationsFound); err != nil {
log.Fatalf("There were an error when looking for %s in PollerLocationCfg. Error: %+v", cfg.InstanceID, err)
} else {
if len(locationsFound) == 0 {
//Create Location

//Get Hostname
hostname, err := os.Hostname()
if err != nil {
hostname = cfg.InstanceID
}
//Get external IP
ip := getExternalIp()
//Get Location or assign InstanceID
loc := cfg.Location
if len(loc) == 0 {
loc = cfg.InstanceID
}

var location = PollerLocationCfg{
ID: cfg.InstanceID,
Location: loc,
Instance_ID: cfg.InstanceID,
Active: true,
Hostname: hostname,
IP: ip.String(),
Description: cfg.Description,
}

var affected int64
session := dbc.x.NewSession()
defer session.Close()
affected, err = session.Insert(&location)
if err != nil {
log.Fatalf("There were an error when creating default PollerLocationCfg Error: %+v", err)
session.Rollback()
} else {
log.Infof("PollerLocationCfg created succefully. %+v", affected)
}
} else {
log.Debug("Instance_ID founded on PollerLocationCfg. Checking if any param was changed")
for _, instance := range locationsFound {
log.Debugf("--> %+v\n", instance)
}
//Check if instance params was changed
instance := locationsFound[0]
hasChanges := false
//IP
if instance.IP != getExternalIp().String() {
instance.IP = getExternalIp().String()
hasChanges = true
}
//Description
if instance.Description != cfg.Description {
instance.Description = cfg.Description
hasChanges = true
}
//Hostname
hostname, err := os.Hostname()
if err != nil {
hostname = cfg.InstanceID
}
if instance.Hostname != hostname {
instance.Description = hostname
hasChanges = true
}
//Location
loc := cfg.Location
if len(loc) == 0 {
loc = cfg.InstanceID
}
if instance.Location != loc {
instance.Location = loc
hasChanges = true
}

if hasChanges {
log.Debug("Updating with newer values...")
var affected int64
session := dbc.x.NewSession()
defer session.Close()
//affected, err := session.ID(instance.ID).AllCols().Update()
affected, err = session.Where("Instance_ID ='" + instance.Instance_ID + "'").AllCols().Update(instance)
if err != nil {
log.Fatalf("There were an error when updating PollerLocationCfg Error: %+v", err)
session.Rollback()
} else {
log.Infof("PollerLocationCfg updated succefully. %+v", affected)
}
}
}
}
return nil
}

Expand Down Expand Up @@ -189,7 +287,7 @@ func CatalogVar2Map(cv map[string]*VarCatalogCfg) map[string]interface{} {
}

//LoadDbConfig get data from database
func (dbc *DatabaseCfg) LoadDbConfig(cfg *DBConfig) {
func (dbc *DatabaseCfg) LoadDbConfig(cfg *DBConfig, Location string) {
var err error
//Load Global Variables
VarCatalog := make(map[string]*VarCatalogCfg)
Expand Down Expand Up @@ -232,10 +330,23 @@ func (dbc *DatabaseCfg) LoadDbConfig(cfg *DBConfig) {
}

//Device

cfg.SnmpDevice, err = dbc.GetSnmpDeviceCfgMap("")
//Parameters inside GetSnmpDeviceCfgMap are filter to get devices. All devices who match with location will be returned
cfg.SnmpDevice, err = dbc.GetSnmpDeviceCfgMap("location = '" + Location + "'")
if err != nil {
log.Warningf("Some errors on get SnmpDeviceConf :%v", err)
}
dbc.resetChanges()
}

//Utils
func getExternalIp() net.IP {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()

localAddr := conn.LocalAddr().(*net.UDPAddr)

return localAddr.IP
}
14 changes: 14 additions & 0 deletions pkg/config/dbconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type SnmpDeviceCfg struct {
//Filters for measurements
MeasurementGroups []string `xorm:"-"`
MeasFilters []string `xorm:"-"`
//Federated SNMPC
Location string `xorm:"'location' default 'Collector1'"`
}

// InfluxCfg is the main configuration for any InfluxDB TSDB
Expand Down Expand Up @@ -131,13 +133,25 @@ type SnmpDevMGroups struct {
IDMGroupCfg string `xorm:"id_mgroup_cfg"`
}

// SnmpDevMGroups Mgroups defined on each SnmpDevice
type PollerLocationCfg struct {
ID string `xorm:"'id' unique" binding:"Required"`
Location string `xorm:"location"`
Instance_ID string `xorm:"instance_id"`
Active bool `xorm:"active"`
Hostname string `xorm:"hostname"`
IP string `xorm:"ip"`
Description string `xorm:"description"`
}

// DBConfig read from DB
type DBConfig struct {
Metrics map[string]*SnmpMetricCfg
Measurements map[string]*MeasurementCfg
MFilters map[string]*MeasFilterCfg
GetGroups map[string]*MGroupsCfg
SnmpDevice map[string]*SnmpDeviceCfg
Location map[string]*PollerLocationCfg
Influxdb map[string]*InfluxCfg
VarCatalog map[string]interface{}
}
Expand Down
14 changes: 8 additions & 6 deletions pkg/config/mainconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (

// GeneralConfig has miscellaneous configuration options
type GeneralConfig struct {
InstanceID string `mapstructure:"instanceID" envconfig:"SNMPCOL_GENERAL_INSTANCE_ID"`
LogDir string `mapstructure:"logdir" envconfig:"SNMPCOL_GENERAL_LOG_DIR"`
HomeDir string `mapstructure:"homedir" envconfig:"SNMPCOL_GENERAL_HOME_DIR"`
DataDir string `mapstructure:"datadir" envconfig:"SNMPCOL_GENERAL_DATA_DIR" `
LogLevel string `mapstructure:"loglevel" envconfig:"SNMPCOL_GENERAL_LOG_LEVEL"`
LogMode string `mapstructure:"log_mode" envconfig:"SNMPCOL_GENERAL_LOG_MODE"`
InstanceID string `mapstructure:"instanceID" envconfig:"SNMPCOL_GENERAL_INSTANCE_ID"`
LogDir string `mapstructure:"logdir" envconfig:"SNMPCOL_GENERAL_LOG_DIR"`
HomeDir string `mapstructure:"homedir" envconfig:"SNMPCOL_GENERAL_HOME_DIR"`
DataDir string `mapstructure:"datadir" envconfig:"SNMPCOL_GENERAL_DATA_DIR" `
LogLevel string `mapstructure:"loglevel" envconfig:"SNMPCOL_GENERAL_LOG_LEVEL"`
LogMode string `mapstructure:"log_mode" envconfig:"SNMPCOL_GENERAL_LOG_MODE"`
Location string `mapstructure:"location" envconfig:"SNMPCOL_GENERAL_LOCATION"`
Description string `mapstructure:"description" envconfig:"SNMPCOL_GENERAL_DESCRIPTION"`
}

//DatabaseCfg de configuration for the database
Expand Down
Loading