my own modifications, part 1

This commit is contained in:
Wolfgang Hottgenroth 2024-01-25 12:35:27 +01:00
parent b68e929c57
commit 5b77a6a059
Signed by: wn
GPG Key ID: 836E9E1192A6B132
20 changed files with 402 additions and 543 deletions

View File

@ -1,61 +0,0 @@
name: Build and Test
on:
push:
branches:
- master
pull_request:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code
uses: actions/checkout@v1
- name: Lint Go Code
run: |
export PATH=$PATH:$(go env GOPATH)/bin # temporary fix. See https://github.com/actions/setup-go/issues/14
go get -u golang.org/x/lint/golint
make lint
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code
uses: actions/checkout@v1
- name: Run Unit tests
run: |
export PATH=$PATH:$(go env GOPATH)/bin
make test-coverage
build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.13
- name: Check out code
uses: actions/checkout@v1
- name: Build Everything
run: |
export PATH=$PATH:$(go env GOPATH)/bin
make build

View File

@ -1,25 +0,0 @@
name: Release
on:
create:
tags:
- v*
jobs:
release:
name: Publish Release
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Validates GO releaser config
uses: docker://goreleaser/goreleaser:latest
with:
args: check
- name: Create release on GitHub
uses: docker://goreleaser/goreleaser:latest
with:
args: release
env:
GITHUB_TOKEN: ${{secrets.GORELEASER_GITHUB_TOKEN}}

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
build build
.DS_Store .DS_Store
snmp-mqtt snmp-mqtt
src/smq/smq

View File

@ -1,13 +0,0 @@
env:
- GO111MODULE=on
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
goarch:
- arm
- amd64

View File

@ -1,45 +0,0 @@
PROJECT_NAME := "snmp-mqtt"
PKG := "github.com/dchote/$(PROJECT_NAME)"
PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/)
GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go)
.PHONY: all dep lint vet test test-coverage build clean
all: build
dep: ## Get the dependencies
@echo Installing dependencies
@go mod download
lint: ## Lint Golang files
@golint -set_exit_status ${PKG_LIST}
vet: ## Run go vet
@go vet ${PKG_LIST}
test: ## Run unittests
@go test -short ${PKG_LIST}
test-coverage: ## Run tests with coverage
@go test -short -coverprofile cover.out -covermode=atomic ${PKG_LIST}
@cat cover.out >> coverage.txt
build: dep ## Build the binary file
@echo Building native binary
@go build -i -o build/snmp-mqtt $(PKG)
linux: build
@echo Building Linux binary
@env CC=x86_64-linux-musl-gcc GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static" -o build/snmp-mqtt
raspi: build
@echo Building Rasperry Pi Linux binary
@env GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=0 go build -o build/snmp-mqtt
clean: ## Remove previous build
@rm -f $(PROJECT_NAME)/build
help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -1,65 +0,0 @@
package config
import (
"encoding/json"
"os"
"strconv"
)
// OIDTopicObject maps OIDs to MQTT topics
type OIDTopicObject struct {
OID string `json:"oid"`
Topic string `json:"topic"`
}
// SNMPEndpointObject is the SNMP Endpoint definition
type SNMPEndpointObject struct {
Endpoint string `json:"endpoint"`
Community string `json:"community"`
OIDTopics []OIDTopicObject `json:"oidTopics"`
}
// SNMPMapObject basic map of endpoints
type SNMPMapObject struct {
SNMPEndpoints []SNMPEndpointObject `json:"snmpEndpoints"`
}
var (
// SNMPMap is the loaded JSON configuration
SNMPMap *SNMPMapObject
// Server is the MQTT server address
Server string
// Port is the MQTT server listen port
Port int
// ClientID is how the name of the client
ClientID string
// Interval is the poll interval in seconds
Interval int
)
// ConnectionString returns the MQTT connection string
func ConnectionString() string {
return "tcp://" + Server + ":" + strconv.Itoa(Port)
}
// LoadMap loads the file in to the struct
func LoadMap(file string) error {
configFile, err := os.Open(file)
defer configFile.Close()
if err != nil {
return err
}
jsonParser := json.NewDecoder(configFile)
err = jsonParser.Decode(&SNMPMap)
if err != nil {
return err
}
return nil
}

View File

@ -1,122 +0,0 @@
{
"snmpEndpoints": [
{
"endpoint": "172.18.0.1",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.4",
"topic": "network/router/interfaces/wan/bytesIn"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.4",
"topic": "network/router/interfaces/wan/bytesOut"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.2",
"topic": "network/router/interfaces/lan/bytesIn"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.2",
"topic": "network/router/interfaces/lan/bytesOut"
}
]
},
{
"endpoint": "172.18.0.50",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.4.1.318.1.1.12.2.3.1.1.2.1",
"topic": "power/rackPDU/outputCurrentX10"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.12.1.16.0",
"topic": "power/rackPDU/watts"
}
]
},
{
"endpoint": "172.18.0.51",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.4.1.318.1.1.1.3.2.1.0",
"topic": "power/rackUPS/lineVoltage"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.4.2.4.0",
"topic": "power/rackUPS/outputCurrent"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.1.0",
"topic": "power/rackUPS/batteryCapacity"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.3.0",
"topic": "power/rackUPS/batteryRuntime"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.2.0",
"topic": "power/rackUPS/batteryTemperature"
}
]
},
{
"endpoint": "172.18.0.52",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.4.1.318.1.1.1.3.2.1.0",
"topic": "power/printerUPS/lineVoltage"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.4.2.4.0",
"topic": "power/printerUPS/outputCurrent"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.1.0",
"topic": "power/printerUPS/batteryCapacity"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.3.0",
"topic": "power/printerUPS/batteryRuntime"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.2.0",
"topic": "power/printerUPS/batteryTemperature"
}
]
},
{
"endpoint": "172.18.0.53",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.4.1.318.1.1.1.3.2.1.0",
"topic": "power/dansDesk/lineVoltage"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.4.2.4.0",
"topic": "power/dansDesk/outputCurrent"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.1.0",
"topic": "power/dansDesk/batteryCapacity"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.3.0",
"topic": "power/dansDesk/batteryRuntime"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.1.2.2.2.0",
"topic": "power/dansDesk/batteryTemperature"
},
{
"oid": ".1.3.6.1.4.1.318.1.1.10.2.3.2.1.4.1",
"topic": "power/dansDesk/temperatureProbe"
}
]
}
]
}

10
go.mod
View File

@ -1,10 +0,0 @@
module github.com/dchote/snmp-mqtt
go 1.13
require (
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/eclipse/paho.mqtt.golang v1.2.0
github.com/soniah/gosnmp v1.22.0
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect
)

20
go.sum
View File

@ -1,20 +0,0 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/soniah/gosnmp v1.22.0 h1:jVJi8+OGvR+JHIaZKMmnyNP0akJd2vEgNatybwhZvxg=
github.com/soniah/gosnmp v1.22.0/go.mod h1:DuEpAS0az51+DyVBQwITDsoq4++e3LTNckp2GoasF2I=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -1,84 +0,0 @@
package main
import (
"log"
"os"
"os/signal"
"syscall"
"github.com/dchote/snmp-mqtt/config"
"github.com/dchote/snmp-mqtt/snmp"
"github.com/docopt/docopt-go"
)
var exitChan = make(chan int)
// VERSION beause...
const VERSION = "0.0.1"
func cliArguments() {
usage := `
Usage: snmp-mqtt [options]
Options:
--endpoints_map=<endpoints_map> SNMP Endpoints Map File [default: ./endpoints.json]
--server=<server> MQTT server host/IP [default: 127.0.0.1]
--port=<port> MQTT server port [default: 1883]
--clientid=<clientid> MQTT client identifier [default: snmp]
--interval=<interval> Poll interval (seconds) [default: 5]
-h, --help Show this screen.
-v, --version Show version.
`
args, _ := docopt.ParseArgs(usage, os.Args[1:], VERSION)
mapFile, _ := args.String("--endpoints_map")
err := config.LoadMap(mapFile)
if err != nil {
log.Println(err)
log.Fatal("error opening " + mapFile)
}
config.Server, _ = args.String("--server")
config.Port, _ = args.Int("--port")
config.ClientID, _ = args.String("--clientid")
config.Interval, _ = args.Int("--interval")
log.Printf("server: %s, port: %d, client identifier: %s, poll interval: %d", config.Server, config.Port, config.ClientID, config.Interval)
}
// sigChannelListen basic handlers for inbound signals
func sigChannelListen() {
signalChan := make(chan os.Signal, 1)
code := 0
signal.Notify(signalChan, os.Interrupt)
signal.Notify(signalChan, os.Kill)
signal.Notify(signalChan, syscall.SIGTERM)
select {
case sig := <-signalChan:
log.Printf("Received signal %s. shutting down", sig)
case code = <-exitChan:
switch code {
case 0:
log.Println("Shutting down")
default:
log.Println("*Shutting down")
}
}
os.Exit(code)
}
func main() {
cliArguments()
// catch signals
go sigChannelListen()
// run sensor poll loop
snmp.Init()
os.Exit(0)
}

View File

@ -1,98 +0,0 @@
package snmp
import (
"fmt"
"log"
"strings"
"sync"
"time"
"github.com/dchote/snmp-mqtt/config"
"github.com/eclipse/paho.mqtt.golang"
"github.com/soniah/gosnmp"
)
var ()
// Init contains the generic read/publish loop
func Init() {
opts := mqtt.NewClientOptions().AddBroker(config.ConnectionString()).SetClientID(config.ClientID)
opts.SetKeepAlive(2 * time.Second)
opts.SetPingTimeout(1 * time.Second)
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
var wg sync.WaitGroup
for {
wg.Add(1)
go func() {
defer wg.Done()
for _, endpoint := range config.SNMPMap.SNMPEndpoints {
log.Println("Polling endpoint " + endpoint.Endpoint)
snmp := gosnmp.GoSNMP{}
snmp.Target = endpoint.Endpoint
snmp.Port = 161
snmp.Version = gosnmp.Version2c
snmp.Community = endpoint.Community
snmp.Timeout = time.Duration(5 * time.Second)
err := snmp.Connect()
if err != nil {
log.Fatal("SNMP Connect error\n")
}
oids := []string{}
for _, oidTopic := range endpoint.OIDTopics {
oids = append(oids, oidTopic.OID)
}
result, err := snmp.Get(oids)
if err != nil {
log.Printf("error in Get: %s", err)
} else {
for _, variable := range result.Variables {
for _, oidTopic := range endpoint.OIDTopics {
if strings.Compare(oidTopic.OID, variable.Name) == 0 {
convertedValue := ""
switch variable.Type {
case gosnmp.OctetString:
convertedValue = string(variable.Value.([]byte))
default:
convertedValue = fmt.Sprintf("%d", gosnmp.ToBigInt(variable.Value))
}
log.Printf("%s = %s", oidTopic.Topic, convertedValue)
token := client.Publish(oidTopic.Topic, 0, false, convertedValue)
token.Wait()
if token.Error() != nil {
log.Fatal(token.Error())
}
}
}
}
}
snmp.Conn.Close()
}
}()
time.Sleep(time.Duration(config.Interval) * time.Second)
}
wg.Wait()
client.Disconnect(250)
time.Sleep(1 * time.Second)
}

37
src/smq/config-test.json Normal file
View File

@ -0,0 +1,37 @@
{
"mqtt": {
"broker": "mqtt://172.23.1.102:1883",
"tlsEnable": "false",
"topic": "snmp"
},
"interval": 10,
"snmpEndpoints": [
{
"endpoint": "172.16.3.1",
"label": "router",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.4",
"label": "wan-in",
"diff": "true"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.4",
"label": "wan-out",
"diff": "true"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.2",
"label": "lan-in",
"diff": "true"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.2",
"label": "lan-out",
"diff": "true"
}
]
}
]
}

33
src/smq/config.json Normal file
View File

@ -0,0 +1,33 @@
{
"mqtt": {
"broker": "mqtt://emqx01-anonymous-cluster-internal.broker.svc.cluster.local:1883",
"tlsEnable": "false",
"topicPre": "snmp"
},
"interval": 60,
"snmpEndpoints": [
{
"endpoint": "172.16.3.1",
"label": "router",
"community": "public",
"oidTopics": [
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.4",
"label": "wan-in"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.4",
"label": "wan-out"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.6.2",
"label": "lan-in"
},
{
"oid": ".1.3.6.1.2.1.31.1.1.1.10.2",
"label": "lan-out"
}
]
}
]
}

47
src/smq/config/config.go Normal file
View File

@ -0,0 +1,47 @@
package config
import (
"encoding/json"
"os"
"log"
)
type OIDTopicObject struct {
OID string `json:"oid"`
Label string `json:"label"`
Diff string `json:"diff"`
}
// SNMPEndpointObject is the SNMP Endpoint definition
type SNMPEndpointObject struct {
Endpoint string `json:"endpoint"`
Label string `json:"label"`
Community string `json:"community"`
OIDTopics []OIDTopicObject `json:"oidTopics"`
}
type MQTTConfigObject struct {
Broker string `json:"broker"`
Username string `json:"username"`
Password string `json:"password"`
TlsEnable string `json:"tlsEnable"`
Topic string `json:"topic"`
}
type ConfigObject struct {
Mqtt MQTTConfigObject `json:"mqtt"`
Interval int `json:"interval"`
SNMPEndpoints []SNMPEndpointObject `json:"snmpEndpoints"`
}
var Config ConfigObject
func LoadConfiguration() {
cfg := os.Getenv("SNMP_MQTT_CONF")
log.Printf("cfg: %s", cfg)
err := json.Unmarshal([]byte(cfg), &Config)
if err != nil {
log.Fatalf("Unable to parse configuration: %v", err)
}
}

15
src/smq/go.mod Normal file
View File

@ -0,0 +1,15 @@
module smq
go 1.21.3
require (
github.com/eclipse/paho.mqtt.golang v1.4.3
github.com/google/uuid v1.6.0
github.com/gosnmp/gosnmp v1.37.0
)
require (
github.com/gorilla/websocket v1.5.0 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sync v0.1.0 // indirect
)

20
src/smq/go.sum Normal file
View File

@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosnmp/gosnmp v1.37.0 h1:/Tf8D3b9wrnNuf/SfbvO+44mPrjVphBhRtcGg22V07Y=
github.com/gosnmp/gosnmp v1.37.0/go.mod h1:GDH9vNqpsD7f2HvZhKs5dlqSEcAS6s6Qp099oZRCR+M=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

113
src/smq/mqtt/mqtt.go Normal file
View File

@ -0,0 +1,113 @@
package mqtt
import "log"
import "fmt"
import MQTT "github.com/eclipse/paho.mqtt.golang"
import "github.com/google/uuid"
import "crypto/tls"
import "smq/config"
// import "smq/counter"
type Message struct {
Topic string
Payload []byte
}
var OutputChannel chan Message = make(chan Message, 100)
var mqttClient MQTT.Client
func onConnectionLost(client MQTT.Client, error error) {
log.Printf("Connection lost, error %s", error)
}
func onReconnecting(client MQTT.Client, clientOpts *MQTT.ClientOptions) {
log.Println("Oops, connection lost, already reconnecting ...")
}
func onConnect(client MQTT.Client) {
log.Println("Connected")
}
func outputDispatcher(client MQTT.Client) {
for {
select {
case message := <- OutputChannel:
log.Printf("Message arrived in outputDispatcher, topic: %s, payload: %s\n", message.Topic, message.Payload)
if token := client.Publish(message.Topic, 0, false, message.Payload); token.Wait() && token.Error() != nil {
log.Printf("Unable to publish, error %s", token.Error())
}
log.Println("Successfully published")
}
}
}
func Publish(msg []byte) {
message := Message {
Topic: config.Config.Mqtt.Topic,
Payload: msg,
}
select {
case OutputChannel <- message:
{}
default:
log.Printf("Channel full, message %s lost")
}
}
func Start() {
broker := config.Config.Mqtt.Broker
if broker == "" {
log.Fatal("No broker given")
}
prefix := "SMQ"
uuid := uuid.New()
clientId := fmt.Sprintf("%s-%s", prefix, uuid)
opts := MQTT.NewClientOptions().
AddBroker(broker).
SetClientID(clientId).
SetConnectionLostHandler(onConnectionLost).
SetOnConnectHandler(onConnect).
SetReconnectingHandler(onReconnecting).
SetConnectRetry(true)
username := config.Config.Mqtt.Username
if username != "" {
opts.SetUsername(username)
}
password := config.Config.Mqtt.Password
if password != "" {
opts.SetPassword(password)
}
enableTls := config.Config.Mqtt.TlsEnable
if enableTls == "true" {
//log.Println("Enabling TLS connection")
tlsConfig := &tls.Config {
InsecureSkipVerify: true,
}
opts.SetTLSConfig(tlsConfig)
}
log.Println("Broker connecting")
mqttClient = MQTT.NewClient(opts)
if token := mqttClient.Connect(); token.Wait() && token.Error() != nil {
log.Fatalf("Unable to connect to broker %s, error %s", broker, token.Error())
}
//log.Printf("Successfully connected to broker %s", broker)
go outputDispatcher(mqttClient)
return
}
func Stop() {
log.Println("Disconnecting from broker")
mqttClient.Disconnect(250)
}

BIN
src/smq/smq Executable file

Binary file not shown.

33
src/smq/snmp-mqtt.go Normal file
View File

@ -0,0 +1,33 @@
package main
import (
"log"
"os"
"os/signal"
"smq/config"
"smq/mqtt"
"smq/snmp"
)
func main() {
log.SetPrefix("SMQ: ")
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("starting")
config.LoadConfiguration()
mqtt.Start()
defer mqtt.Stop()
snmp.Start()
defer snmp.Stop()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
<- c
log.Println("terminating")
}

103
src/smq/snmp/snmp.go Normal file
View File

@ -0,0 +1,103 @@
package snmp
import (
"fmt"
"log"
"time"
"encoding/json"
"smq/config"
"smq/mqtt"
"github.com/gosnmp/gosnmp"
)
type variable_t struct {
Label string `json:"label"`
Variable string `json:"variable"`
Value string `json:"value"`
}
type message_t struct {
Device string `json:"device"`
Label string `json:"label"`
Variables map[string]variable_t `json:"variables"`
}
func Start() {
for {
for _, endpoint := range config.Config.SNMPEndpoints {
log.Println("Polling endpoint " + endpoint.Endpoint)
snmp := gosnmp.GoSNMP{}
snmp.Target = endpoint.Endpoint
snmp.Port = 161
snmp.Version = gosnmp.Version2c
snmp.Community = endpoint.Community
snmp.Timeout = time.Duration(5 * time.Second)
err := snmp.Connect()
if err != nil {
log.Fatal("SNMP Connect error\n")
}
oids := []string{}
for _, oidTopic := range endpoint.OIDTopics {
oids = append(oids, oidTopic.OID)
}
result, err := snmp.Get(oids)
if err != nil {
log.Printf("error in Get: %s", err)
} else {
message := message_t {
Device: endpoint.Endpoint,
Label: endpoint.Label,
Variables: make(map[string]variable_t),
}
for _, variable := range result.Variables {
for _, oidTopic := range endpoint.OIDTopics {
if oidTopic.OID == variable.Name {
convertedValue := ""
switch variable.Type {
case gosnmp.OctetString:
convertedValue = string(variable.Value.([]byte))
default:
convertedValue = fmt.Sprintf("%d", gosnmp.ToBigInt(variable.Value))
}
log.Printf("%s = %s", oidTopic.OID, convertedValue)
v := variable_t {
Label: oidTopic.Label,
Variable: oidTopic.OID,
Value: convertedValue,
}
message.Variables[oidTopic.Label] = v
// build topic and payload and push into the mqtt.OutputChannel
}
}
}
j, err := json.Marshal(message)
if err != nil {
log.Printf("Unable to marshal message, it is lost: %s, %v", message, err)
} else {
mqtt.Publish(j)
}
}
snmp.Conn.Close()
}
time.Sleep(time.Duration(config.Config.Interval) * time.Second)
}
}
func Stop() {
}