tacticalrmm/natsapi/api.go

197 lines
4.4 KiB
Go

package api
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"runtime"
"strings"
"time"
"github.com/go-resty/resty/v2"
nats "github.com/nats-io/nats.go"
"github.com/ugorji/go/codec"
rmm "github.com/wh1te909/rmmagent/shared"
)
var rClient = resty.New()
func getAPI(apihost, natshost string) (string, string, error) {
if apihost != "" && natshost != "" {
return apihost, natshost, nil
}
f, err := os.Open(`/etc/nginx/sites-available/rmm.conf`)
if err != nil {
return "", "", err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "server_name") && !strings.Contains(scanner.Text(), "301") {
r := strings.NewReplacer("server_name", "", ";", "")
s := strings.ReplaceAll(r.Replace(scanner.Text()), " ", "")
return fmt.Sprintf("https://%s/natsapi", s), fmt.Sprintf("tls://%s:4222", s), nil
}
}
return "", "", errors.New("unable to parse api from nginx conf")
}
func Listen(apihost, natshost, version string, debug bool) {
api, natsurl, err := getAPI(apihost, natshost)
if err != nil {
log.Fatalln(err)
}
log.Printf("Tactical Nats API Version %s\n", version)
log.Println("Api base url: ", api)
log.Println("Nats connection url: ", natsurl)
rClient.SetHostURL(api)
rClient.SetTimeout(30 * time.Second)
natsinfo, err := rClient.R().SetResult(&NatsInfo{}).Get("/natsinfo/")
if err != nil {
log.Fatalln(err)
}
if natsinfo.IsError() {
log.Fatalln(natsinfo.String())
}
opts := []nats.Option{
nats.Name("TacticalRMM"),
nats.UserInfo(natsinfo.Result().(*NatsInfo).User,
natsinfo.Result().(*NatsInfo).Password),
nats.ReconnectWait(time.Second * 5),
nats.RetryOnFailedConnect(true),
nats.MaxReconnects(-1),
nats.ReconnectBufSize(-1),
}
nc, err := nats.Connect(natsurl, opts...)
if err != nil {
log.Fatalln(err)
}
go getWMI(rClient, nc)
go monitorAgents(rClient, nc)
nc.Subscribe("*", func(msg *nats.Msg) {
var mh codec.MsgpackHandle
mh.RawToString = true
dec := codec.NewDecoderBytes(msg.Data, &mh)
switch msg.Reply {
case "hello":
go func() {
var p *rmm.CheckIn
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Patch("/checkin/")
}
}()
case "startup":
go func() {
var p *rmm.CheckIn
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Post("/checkin/")
}
}()
case "osinfo":
go func() {
var p *rmm.CheckInOS
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "winservices":
go func() {
var p *rmm.CheckInWinServices
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "publicip":
go func() {
var p *rmm.CheckInPublicIP
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "disks":
go func() {
var p *rmm.CheckInDisk
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "loggedonuser":
go func() {
var p *rmm.CheckInLoggedUser
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "software":
go func() {
var p *rmm.CheckInSW
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/checkin/")
}
}()
case "syncmesh":
go func() {
var p *rmm.MeshNodeID
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Post("/syncmesh/")
}
}()
case "getwinupdates":
go func() {
var p *rmm.WinUpdateResult
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Post("/winupdates/")
}
}()
case "winupdateresult":
go func() {
var p *rmm.WinUpdateInstallResult
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Patch("/winupdates/")
}
}()
case "superseded":
go func() {
var p *rmm.SupersededUpdate
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Post("/superseded/")
}
}()
case "needsreboot":
go func() {
var p *rmm.AgentNeedsReboot
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Put("/winupdates/")
}
}()
case "chocoinstall":
go func() {
var p *rmm.ChocoInstalled
if err := dec.Decode(&p); err == nil {
rClient.R().SetBody(p).Post("/choco/")
}
}()
}
})
nc.Flush()
if err := nc.LastError(); err != nil {
fmt.Println(err)
os.Exit(1)
}
runtime.Goexit()
}