my own modifications, part 1
This commit is contained in:
parent
b68e929c57
commit
5b77a6a059
61
.github/workflows/main.yml
vendored
61
.github/workflows/main.yml
vendored
@ -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
|
|
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@ -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
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
build
|
build
|
||||||
.DS_Store
|
.DS_Store
|
||||||
snmp-mqtt
|
snmp-mqtt
|
||||||
|
src/smq/smq
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
before:
|
|
||||||
hooks:
|
|
||||||
- go mod tidy
|
|
||||||
builds:
|
|
||||||
- env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
goos:
|
|
||||||
- linux
|
|
||||||
goarch:
|
|
||||||
- arm
|
|
||||||
- amd64
|
|
45
Makefile
45
Makefile
@ -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}'
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
122
endpoints.json
122
endpoints.json
@ -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
10
go.mod
@ -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
20
go.sum
@ -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=
|
|
84
snmp-mqtt.go
84
snmp-mqtt.go
@ -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)
|
|
||||||
}
|
|
98
snmp/snmp.go
98
snmp/snmp.go
@ -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
37
src/smq/config-test.json
Normal 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
33
src/smq/config.json
Normal 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
47
src/smq/config/config.go
Normal 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
15
src/smq/go.mod
Normal 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
20
src/smq/go.sum
Normal 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
113
src/smq/mqtt/mqtt.go
Normal 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
BIN
src/smq/smq
Executable file
Binary file not shown.
33
src/smq/snmp-mqtt.go
Normal file
33
src/smq/snmp-mqtt.go
Normal 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
103
src/smq/snmp/snmp.go
Normal 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() {
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user