updated for unix build
This commit is contained in:
parent
66aca05028
commit
e20edcc9ad
37 changed files with 1001 additions and 257 deletions
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
rmm "github.com/amidaware/rmmagent/shared"
|
rmm "github.com/amidaware/rmmagent/shared"
|
||||||
|
|
@ -85,15 +84,15 @@ func New(logger *logrus.Logger, version string) *Agent {
|
||||||
restyC.SetRootCertificate(ac.Cert)
|
restyC.SetRootCertificate(ac.Cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
var MeshSysBin string
|
var MeshSysExe string
|
||||||
if len(ac.CustomMeshDir) > 0 {
|
if len(ac.CustomMeshDir) > 0 {
|
||||||
MeshSysBin = filepath.Join(ac.CustomMeshDir, "MeshAgent.exe")
|
MeshSysExe = filepath.Join(ac.CustomMeshDir, "MeshAgent.exe")
|
||||||
} else {
|
} else {
|
||||||
MeshSysBin = filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe")
|
MeshSysExe = filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe")
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
MeshSysBin = "/opt/tacticalmesh/meshagent"
|
MeshSysExe = "/opt/tacticalmesh/meshagent"
|
||||||
}
|
}
|
||||||
|
|
||||||
svcConf := &service.Config{
|
svcConf := &service.Config{
|
||||||
|
|
@ -112,7 +111,6 @@ func New(logger *logrus.Logger, version string) *Agent {
|
||||||
|
|
||||||
return &Agent{
|
return &Agent{
|
||||||
Hostname: info.Hostname,
|
Hostname: info.Hostname,
|
||||||
Arch: info.Architecture,
|
|
||||||
BaseURL: ac.BaseURL,
|
BaseURL: ac.BaseURL,
|
||||||
AgentID: ac.AgentID,
|
AgentID: ac.AgentID,
|
||||||
ApiURL: ac.APIURL,
|
ApiURL: ac.APIURL,
|
||||||
|
|
@ -123,7 +121,7 @@ func New(logger *logrus.Logger, version string) *Agent {
|
||||||
EXE: exe,
|
EXE: exe,
|
||||||
SystemDrive: sd,
|
SystemDrive: sd,
|
||||||
MeshInstaller: "meshagent.exe",
|
MeshInstaller: "meshagent.exe",
|
||||||
MeshSystemBin: MeshSysBin,
|
MeshSystemBin: MeshSysExe,
|
||||||
MeshSVC: meshSvcName,
|
MeshSVC: meshSvcName,
|
||||||
PyBin: pybin,
|
PyBin: pybin,
|
||||||
Headers: headers,
|
Headers: headers,
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
package agent
|
|
||||||
|
|
||||||
func New(logger *logrus.Logger, version string) *Agent {
|
|
||||||
host, _ := ps.Host()
|
|
||||||
info := host.Info()
|
|
||||||
pd := filepath.Join(os.Getenv("ProgramFiles"), progFilesName)
|
|
||||||
exe := filepath.Join(pd, winExeName)
|
|
||||||
sd := os.Getenv("SystemDrive")
|
|
||||||
|
|
||||||
var pybin string
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "amd64":
|
|
||||||
pybin = filepath.Join(pd, "py38-x64", "python.exe")
|
|
||||||
case "386":
|
|
||||||
pybin = filepath.Join(pd, "py38-x32", "python.exe")
|
|
||||||
}
|
|
||||||
|
|
||||||
ac := NewAgentConfig()
|
|
||||||
|
|
||||||
headers := make(map[string]string)
|
|
||||||
if len(ac.Token) > 0 {
|
|
||||||
headers["Content-Type"] = "application/json"
|
|
||||||
headers["Authorization"] = fmt.Sprintf("Token %s", ac.Token)
|
|
||||||
}
|
|
||||||
|
|
||||||
restyC := resty.New()
|
|
||||||
restyC.SetBaseURL(ac.BaseURL)
|
|
||||||
restyC.SetCloseConnection(true)
|
|
||||||
restyC.SetHeaders(headers)
|
|
||||||
restyC.SetTimeout(15 * time.Second)
|
|
||||||
restyC.SetDebug(logger.IsLevelEnabled(logrus.DebugLevel))
|
|
||||||
|
|
||||||
if len(ac.Proxy) > 0 {
|
|
||||||
restyC.SetProxy(ac.Proxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ac.Cert) > 0 {
|
|
||||||
restyC.SetRootCertificate(ac.Cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
var MeshSysBin string
|
|
||||||
if len(ac.CustomMeshDir) > 0 {
|
|
||||||
MeshSysBin = filepath.Join(ac.CustomMeshDir, "MeshAgent.exe")
|
|
||||||
} else {
|
|
||||||
MeshSysBin = filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe")
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
MeshSysBin = "/opt/tacticalmesh/meshagent"
|
|
||||||
}
|
|
||||||
|
|
||||||
svcConf := &service.Config{
|
|
||||||
Executable: exe,
|
|
||||||
Name: winSvcName,
|
|
||||||
DisplayName: "TacticalRMM Agent Service",
|
|
||||||
Arguments: []string{"-m", "svc"},
|
|
||||||
Description: "TacticalRMM Agent Service",
|
|
||||||
Option: service.KeyValue{
|
|
||||||
"StartType": "automatic",
|
|
||||||
"OnFailure": "restart",
|
|
||||||
"OnFailureDelayDuration": "5s",
|
|
||||||
"OnFailureResetPeriod": 10,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Agent{
|
|
||||||
Hostname: info.Hostname,
|
|
||||||
Arch: info.Architecture,
|
|
||||||
BaseURL: ac.BaseURL,
|
|
||||||
AgentID: ac.AgentID,
|
|
||||||
ApiURL: ac.APIURL,
|
|
||||||
Token: ac.Token,
|
|
||||||
AgentPK: ac.PK,
|
|
||||||
Cert: ac.Cert,
|
|
||||||
ProgramDir: pd,
|
|
||||||
EXE: exe,
|
|
||||||
SystemDrive: sd,
|
|
||||||
MeshInstaller: "meshagent.exe",
|
|
||||||
MeshSystemBin: MeshSysBin,
|
|
||||||
MeshSVC: meshSvcName,
|
|
||||||
PyBin: pybin,
|
|
||||||
Headers: headers,
|
|
||||||
Logger: logger,
|
|
||||||
Version: version,
|
|
||||||
Debug: logger.IsLevelEnabled(logrus.DebugLevel),
|
|
||||||
rClient: restyC,
|
|
||||||
Proxy: ac.Proxy,
|
|
||||||
Platform: runtime.GOOS,
|
|
||||||
GoArch: runtime.GOARCH,
|
|
||||||
ServiceConfig: svcConf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
499
agent/agent_unix.go
Normal file
499
agent/agent_unix.go
Normal file
|
|
@ -0,0 +1,499 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2022 AmidaWare LLC.
|
||||||
|
|
||||||
|
Licensed under the Tactical RMM License Version 1.0 (the “License”).
|
||||||
|
You may only use the Licensed Software in accordance with the License.
|
||||||
|
A copy of the License is available at:
|
||||||
|
|
||||||
|
https://license.tacticalrmm.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
rmm "github.com/amidaware/rmmagent/shared"
|
||||||
|
ps "github.com/elastic/go-sysinfo"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/jaypipes/ghw"
|
||||||
|
"github.com/kardianos/service"
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
|
psHost "github.com/shirou/gopsutil/v3/host"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
trmm "github.com/wh1te909/trmm-shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ShowStatus(version string) {
|
||||||
|
fmt.Println(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) GetDisks() []trmm.Disk {
|
||||||
|
ret := make([]trmm.Disk, 0)
|
||||||
|
partitions, err := disk.Partitions(false)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Debugln(err)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range partitions {
|
||||||
|
if strings.Contains(p.Device, "dev/loop") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
usage, err := disk.Usage(p.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Debugln(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d := trmm.Disk{
|
||||||
|
Device: p.Device,
|
||||||
|
Fstype: p.Fstype,
|
||||||
|
Total: ByteCountSI(usage.Total),
|
||||||
|
Used: ByteCountSI(usage.Used),
|
||||||
|
Free: ByteCountSI(usage.Free),
|
||||||
|
Percent: int(usage.UsedPercent),
|
||||||
|
}
|
||||||
|
ret = append(ret, d)
|
||||||
|
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) SystemRebootRequired() (bool, error) {
|
||||||
|
// deb
|
||||||
|
paths := [2]string{"/var/run/reboot-required", "/run/reboot-required"}
|
||||||
|
for _, p := range paths {
|
||||||
|
if trmm.FileExists(p) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// rhel
|
||||||
|
bins := [2]string{"/usr/bin/needs-restarting", "/bin/needs-restarting"}
|
||||||
|
for _, bin := range bins {
|
||||||
|
if trmm.FileExists(bin) {
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
// https://man7.org/linux/man-pages/man1/needs-restarting.1.html
|
||||||
|
// -r Only report whether a full reboot is required (exit code 1) or not (exit code 0).
|
||||||
|
opts.Command = fmt.Sprintf("%s -r", bin)
|
||||||
|
out := a.CmdV2(opts)
|
||||||
|
|
||||||
|
if out.Status.Error != nil {
|
||||||
|
a.Logger.Debugln("SystemRebootRequired(): ", out.Status.Error.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if out.Status.Exit == 1 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) LoggedOnUser() string {
|
||||||
|
var ret string
|
||||||
|
users, err := psHost.Users()
|
||||||
|
if err != nil {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the first logged in user
|
||||||
|
for _, user := range users {
|
||||||
|
if user.User != "" {
|
||||||
|
ret = user.User
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) osString() string {
|
||||||
|
h, err := psHost.Info()
|
||||||
|
if err != nil {
|
||||||
|
return "error getting host info"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s %s %s %s", strings.Title(h.Platform), h.PlatformVersion, h.KernelArch, h.KernelVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAgentConfig() *rmm.AgentConfig {
|
||||||
|
viper.SetConfigName("tacticalagent")
|
||||||
|
viper.SetConfigType("json")
|
||||||
|
viper.AddConfigPath("/etc/")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
err := viper.ReadInConfig()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &rmm.AgentConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
agentpk := viper.GetString("agentpk")
|
||||||
|
pk, _ := strconv.Atoi(agentpk)
|
||||||
|
|
||||||
|
ret := &rmm.AgentConfig{
|
||||||
|
BaseURL: viper.GetString("baseurl"),
|
||||||
|
AgentID: viper.GetString("agentid"),
|
||||||
|
APIURL: viper.GetString("apiurl"),
|
||||||
|
Token: viper.GetString("token"),
|
||||||
|
AgentPK: agentpk,
|
||||||
|
PK: pk,
|
||||||
|
Cert: viper.GetString("cert"),
|
||||||
|
Proxy: viper.GetString("proxy"),
|
||||||
|
CustomMeshDir: viper.GetString("meshdir"),
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) RunScript(code string, shell string, args []string, timeout int) (stdout, stderr string, exitcode int, e error) {
|
||||||
|
code = removeWinNewLines(code)
|
||||||
|
content := []byte(code)
|
||||||
|
|
||||||
|
f, err := createTmpFile()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("RunScript createTmpFile()", err)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
|
if _, err := f.Write(content); err != nil {
|
||||||
|
a.Logger.Errorln(err)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
a.Logger.Errorln(err)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chmod(f.Name(), 0770); err != nil {
|
||||||
|
a.Logger.Errorln(err)
|
||||||
|
return "", err.Error(), 85, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
opts.IsScript = true
|
||||||
|
opts.Shell = f.Name()
|
||||||
|
opts.Args = args
|
||||||
|
opts.Timeout = time.Duration(timeout)
|
||||||
|
out := a.CmdV2(opts)
|
||||||
|
retError := ""
|
||||||
|
if out.Status.Error != nil {
|
||||||
|
retError += CleanString(out.Status.Error.Error())
|
||||||
|
retError += "\n"
|
||||||
|
}
|
||||||
|
if len(out.Stderr) > 0 {
|
||||||
|
retError += out.Stderr
|
||||||
|
}
|
||||||
|
return out.Stdout, retError, out.Status.Exit, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDetached() *syscall.SysProcAttr {
|
||||||
|
return &syscall.SysProcAttr{Setpgid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) AgentUpdate(url, inno, version string) {
|
||||||
|
|
||||||
|
self, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("AgentUpdate() os.Executable():", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := createTmpFile()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("AgentUpdate createTmpFile()", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
|
||||||
|
a.Logger.Infof("Agent updating from %s to %s", a.Version, version)
|
||||||
|
a.Logger.Infoln("Downloading agent update from", url)
|
||||||
|
|
||||||
|
rClient := resty.New()
|
||||||
|
rClient.SetCloseConnection(true)
|
||||||
|
rClient.SetTimeout(15 * time.Minute)
|
||||||
|
rClient.SetDebug(a.Debug)
|
||||||
|
if len(a.Proxy) > 0 {
|
||||||
|
rClient.SetProxy(a.Proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := rClient.R().SetOutput(f.Name()).Get(url)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("AgentUpdate() download:", err)
|
||||||
|
f.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.IsError() {
|
||||||
|
a.Logger.Errorln("AgentUpdate() status code:", r.StatusCode())
|
||||||
|
f.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Close()
|
||||||
|
os.Chmod(f.Name(), 0755)
|
||||||
|
err = os.Rename(f.Name(), self)
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("AgentUpdate() os.Rename():", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
opts.Detached = true
|
||||||
|
opts.Command = "systemctl restart tacticalagent.service"
|
||||||
|
a.CmdV2(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) AgentUninstall(code string) {
|
||||||
|
f, err := createTmpFile()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("AgentUninstall createTmpFile():", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Write([]byte(code))
|
||||||
|
f.Close()
|
||||||
|
os.Chmod(f.Name(), 0770)
|
||||||
|
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
opts.IsScript = true
|
||||||
|
opts.Shell = f.Name()
|
||||||
|
opts.Args = []string{"uninstall"}
|
||||||
|
opts.Detached = true
|
||||||
|
a.CmdV2(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) NixMeshNodeID() string {
|
||||||
|
var meshNodeID string
|
||||||
|
meshSuccess := false
|
||||||
|
a.Logger.Debugln("Getting mesh node id")
|
||||||
|
|
||||||
|
if !trmm.FileExists(a.MeshSystemBin) {
|
||||||
|
a.Logger.Debugln(a.MeshSystemBin, "does not exist. Skipping.")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
opts.IsExecutable = true
|
||||||
|
opts.Shell = a.MeshSystemBin
|
||||||
|
opts.Command = "-nodeid"
|
||||||
|
|
||||||
|
for !meshSuccess {
|
||||||
|
out := a.CmdV2(opts)
|
||||||
|
meshNodeID = out.Stdout
|
||||||
|
a.Logger.Debugln("Stdout:", out.Stdout)
|
||||||
|
a.Logger.Debugln("Stderr:", out.Stderr)
|
||||||
|
if meshNodeID == "" {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
} else if strings.Contains(strings.ToLower(meshNodeID), "graphical version") || strings.Contains(strings.ToLower(meshNodeID), "zenity") {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
meshSuccess = true
|
||||||
|
}
|
||||||
|
return meshNodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) getMeshNodeID() (string, error) {
|
||||||
|
return a.NixMeshNodeID(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) RecoverMesh() {
|
||||||
|
a.Logger.Infoln("Attempting mesh recovery")
|
||||||
|
opts := a.NewCMDOpts()
|
||||||
|
opts.Command = "systemctl restart meshagent.service"
|
||||||
|
a.CmdV2(opts)
|
||||||
|
a.SyncMeshNodeID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) GetWMIInfo() map[string]interface{} {
|
||||||
|
wmiInfo := make(map[string]interface{})
|
||||||
|
ips := make([]string, 0)
|
||||||
|
disks := make([]string, 0)
|
||||||
|
cpus := make([]string, 0)
|
||||||
|
gpus := make([]string, 0)
|
||||||
|
|
||||||
|
// local ips
|
||||||
|
host, err := ps.Host()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("GetWMIInfo() ps.Host()", err)
|
||||||
|
} else {
|
||||||
|
for _, ip := range host.Info().IPs {
|
||||||
|
if strings.Contains(ip, "127.0.") || strings.Contains(ip, "::1/128") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ips = append(ips, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wmiInfo["local_ips"] = ips
|
||||||
|
|
||||||
|
// disks
|
||||||
|
block, err := ghw.Block(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ghw.Block()", err)
|
||||||
|
} else {
|
||||||
|
for _, disk := range block.Disks {
|
||||||
|
if disk.IsRemovable || strings.Contains(disk.Name, "ram") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret := fmt.Sprintf("%s %s %s %s %s %s", disk.Vendor, disk.Model, disk.StorageController, disk.DriveType, disk.Name, ByteCountSI(disk.SizeBytes))
|
||||||
|
ret = strings.TrimSpace(strings.ReplaceAll(ret, "unknown", ""))
|
||||||
|
disks = append(disks, ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wmiInfo["disks"] = disks
|
||||||
|
|
||||||
|
// cpus
|
||||||
|
cpuInfo, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("cpu.Info()", err)
|
||||||
|
} else {
|
||||||
|
if len(cpuInfo) > 0 {
|
||||||
|
if cpuInfo[0].ModelName != "" {
|
||||||
|
cpus = append(cpus, cpuInfo[0].ModelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wmiInfo["cpus"] = cpus
|
||||||
|
|
||||||
|
// make/model
|
||||||
|
wmiInfo["make_model"] = ""
|
||||||
|
chassis, err := ghw.Chassis(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ghw.Chassis()", err)
|
||||||
|
} else {
|
||||||
|
if chassis.Vendor != "" || chassis.Version != "" {
|
||||||
|
wmiInfo["make_model"] = fmt.Sprintf("%s %s", chassis.Vendor, chassis.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfx cards
|
||||||
|
|
||||||
|
gpu, err := ghw.GPU(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
a.Logger.Errorln("ghw.GPU()", err)
|
||||||
|
} else {
|
||||||
|
for _, i := range gpu.GraphicsCards {
|
||||||
|
if i.DeviceInfo != nil {
|
||||||
|
ret := fmt.Sprintf("%s %s", i.DeviceInfo.Vendor.Name, i.DeviceInfo.Product.Name)
|
||||||
|
gpus = append(gpus, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wmiInfo["gpus"] = gpus
|
||||||
|
|
||||||
|
// temp hack for ARM cpu/make/model if rasp pi
|
||||||
|
var makeModel string
|
||||||
|
if strings.Contains(runtime.GOARCH, "arm") {
|
||||||
|
file, _ := os.Open("/proc/cpuinfo")
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
if strings.Contains(strings.ToLower(scanner.Text()), "raspberry") {
|
||||||
|
model := strings.Split(scanner.Text(), ":")
|
||||||
|
if len(model) == 2 {
|
||||||
|
makeModel = strings.TrimSpace(model[1])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cpus) == 0 {
|
||||||
|
wmiInfo["cpus"] = []string{makeModel}
|
||||||
|
}
|
||||||
|
if makeModel != "" && (wmiInfo["make_model"] == "" || wmiInfo["make_model"] == "unknown unknown") {
|
||||||
|
wmiInfo["make_model"] = makeModel
|
||||||
|
}
|
||||||
|
if len(gpus) == 1 && gpus[0] == "unknown unknown" {
|
||||||
|
wmiInfo["gpus"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return wmiInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// windows only below TODO add into stub file
|
||||||
|
|
||||||
|
func (a *Agent) PlatVer() (string, error) { return "", nil }
|
||||||
|
|
||||||
|
func (a *Agent) SendSoftware() {}
|
||||||
|
|
||||||
|
func (a *Agent) UninstallCleanup() {}
|
||||||
|
|
||||||
|
func (a *Agent) RunMigrations() {}
|
||||||
|
|
||||||
|
func GetServiceStatus(name string) (string, error) { return "", nil }
|
||||||
|
|
||||||
|
func (a *Agent) GetPython(force bool) {}
|
||||||
|
|
||||||
|
type SchedTask struct{ Name string }
|
||||||
|
|
||||||
|
func (a *Agent) PatchMgmnt(enable bool) error { return nil }
|
||||||
|
|
||||||
|
func (a *Agent) CreateSchedTask(st SchedTask) (bool, error) { return false, nil }
|
||||||
|
|
||||||
|
func DeleteSchedTask(name string) error { return nil }
|
||||||
|
|
||||||
|
func ListSchedTasks() []string { return []string{} }
|
||||||
|
|
||||||
|
func (a *Agent) GetEventLog(logName string, searchLastDays int) []rmm.EventLogMsg {
|
||||||
|
return []rmm.EventLogMsg{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) GetServiceDetail(name string) trmm.WindowsService { return trmm.WindowsService{} }
|
||||||
|
|
||||||
|
func (a *Agent) ControlService(name, action string) rmm.WinSvcResp {
|
||||||
|
return rmm.WinSvcResp{Success: false, ErrorMsg: "/na"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) EditService(name, startupType string) rmm.WinSvcResp {
|
||||||
|
return rmm.WinSvcResp{Success: false, ErrorMsg: "/na"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) GetInstalledSoftware() []trmm.WinSoftwareList { return []trmm.WinSoftwareList{} }
|
||||||
|
|
||||||
|
func (a *Agent) ChecksRunning() bool { return false }
|
||||||
|
|
||||||
|
func (a *Agent) RunTask(id int) error { return nil }
|
||||||
|
|
||||||
|
func (a *Agent) InstallChoco() {}
|
||||||
|
|
||||||
|
func (a *Agent) InstallWithChoco(name string) (string, error) { return "", nil }
|
||||||
|
|
||||||
|
func (a *Agent) GetWinUpdates() {}
|
||||||
|
|
||||||
|
func (a *Agent) InstallUpdates(guids []string) {}
|
||||||
|
|
||||||
|
func (a *Agent) installMesh(meshbin, exe, proxy string) (string, error) {
|
||||||
|
return "not implemented", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CMDShell(shell string, cmdArgs []string, command string, timeout int, detached bool) (output [2]string, e error) {
|
||||||
|
return [2]string{"", ""}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CMD(exe string, args []string, timeout int, detached bool) (output [2]string, e error) {
|
||||||
|
return [2]string{"", ""}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Agent) GetServices() []trmm.WindowsService { return []trmm.WindowsService{} }
|
||||||
|
|
||||||
|
func (a *Agent) Start(_ service.Service) error { return nil }
|
||||||
|
|
||||||
|
func (a *Agent) Stop(_ service.Service) error { return nil }
|
||||||
|
|
||||||
|
func (a *Agent) InstallService() error { return nil }
|
||||||
|
|
@ -48,7 +48,6 @@ var (
|
||||||
|
|
||||||
func NewAgentConfig() *rmm.AgentConfig {
|
func NewAgentConfig() *rmm.AgentConfig {
|
||||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\TacticalRMM`, registry.ALL_ACCESS)
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\TacticalRMM`, registry.ALL_ACCESS)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &rmm.AgentConfig{}
|
return &rmm.AgentConfig{}
|
||||||
}
|
}
|
||||||
|
|
@ -798,7 +797,7 @@ func (a *Agent) RecoverMesh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Agent) getMeshNodeID() (string, error) {
|
func (a *Agent) getMeshNodeID() (string, error) {
|
||||||
out, err := CMD(a.MeshSystemBin, []string{"-nodeid"}, 10, false)
|
out, err := CMD(a.MeshSystemEXE, []string{"-nodeid"}, 10, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Logger.Debugln(err)
|
a.Logger.Debugln(err)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
||||||
12
agent/choco/choco_unix.go
Normal file
12
agent/choco/choco_unix.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package choco
|
||||||
|
|
||||||
|
//stubbed out for rpc
|
||||||
|
func InstallChoco() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func InstallWithChoco(name string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package disk
|
package disk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
d "github.com/shirou/gopsutil/v3/disk"
|
d "github.com/shirou/gopsutil/v3/disk"
|
||||||
trmm "github.com/wh1te909/trmm-shared"
|
|
||||||
"github.com/amidaware/rmmagent/agent/utils"
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetDisks() []trmm.Disk {
|
func GetDisks() ([]Disk, error) {
|
||||||
ret := make([]trmm.Disk, 0)
|
ret := make([]Disk, 0)
|
||||||
partitions, err := d.Partitions(false)
|
partitions, err := d.Partitions(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return []Disk{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range partitions {
|
for _, p := range partitions {
|
||||||
|
|
@ -24,7 +26,7 @@ func GetDisks() []trmm.Disk {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
d := trmm.Disk{
|
d := Disk{
|
||||||
Device: p.Device,
|
Device: p.Device,
|
||||||
Fstype: p.Fstype,
|
Fstype: p.Fstype,
|
||||||
Total: utils.ByteCountSI(usage.Total),
|
Total: utils.ByteCountSI(usage.Total),
|
||||||
|
|
@ -36,5 +38,5 @@ func GetDisks() []trmm.Disk {
|
||||||
ret = append(ret, d)
|
ret = append(ret, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package events
|
package events
|
||||||
|
|
||||||
func GetEventLog(logName string, searchLastDays int) ([]EventLogMsg, error) {
|
func GetEventLog(logName string, searchLastDays int) ([]EventLogMsg, error) {
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package patching
|
package patching
|
||||||
|
|
||||||
func PatchMgmnt(enable bool) error { return nil }
|
func PatchMgmnt(enable bool) error { return nil }
|
||||||
|
|
||||||
func GetUpdates() {}
|
func GetUpdates()(PackageList, error) {
|
||||||
|
return PackageList{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func InstallUpdates(guids []string) {}
|
func InstallUpdates(guids []string) {}
|
||||||
|
|
@ -36,7 +36,7 @@ func PatchMgmnt(enable bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageList []Package
|
|
||||||
|
|
||||||
func GetUpdates() (PackageList, error) {
|
func GetUpdates() (PackageList, error) {
|
||||||
wuaupdates, err := wua.WUAUpdates("IsInstalled=1 or IsInstalled=0 and Type='Software' and IsHidden=0")
|
wuaupdates, err := wua.WUAUpdates("IsInstalled=1 or IsInstalled=0 and Type='Software' and IsHidden=0")
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,5 @@ type AgentNeedsReboot struct {
|
||||||
AgentID string `json:"agent_id"`
|
AgentID string `json:"agent_id"`
|
||||||
NeedsReboot bool `json:"needs_reboot"`
|
NeedsReboot bool `json:"needs_reboot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PackageList []Package
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
trmm "github.com/wh1te909/trmm-shared"
|
|
||||||
rmm "github.com/amidaware/rmmagent/shared"
|
|
||||||
"github.com/kardianos/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetServiceDetail(name string) trmm.WindowsService { return trmm.WindowsService{} }
|
|
||||||
|
|
||||||
func ControlService(name, action string) rmm.WinSvcResp {
|
|
||||||
return rmm.WinSvcResp{Success: false, ErrorMsg: "/na"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditService(name, startupType string) rmm.WinSvcResp {
|
|
||||||
return rmm.WinSvcResp{Success: false, ErrorMsg: "/na"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetServices() []trmm.WindowsService { return []trmm.WindowsService{} }
|
|
||||||
|
|
||||||
func Start(_ service.Service) error { return nil }
|
|
||||||
|
|
||||||
func Stop(_ service.Service) error { return nil }
|
|
||||||
|
|
||||||
func InstallService() error { return nil }
|
|
||||||
32
agent/services/services_unix.go
Normal file
32
agent/services/services_unix.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kardianos/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetServiceDetail(name string) Service { return Service{} }
|
||||||
|
|
||||||
|
func ControlService(name, action string) WinSvcResp {
|
||||||
|
return WinSvcResp{Success: false, ErrorMsg: "/na"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EditService(name, startupType string) WinSvcResp {
|
||||||
|
return WinSvcResp{Success: false, ErrorMsg: "/na"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetServices() ([]Service, []error, error) {
|
||||||
|
return []Service{}, []error{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Start(_ service.Service) error { return nil }
|
||||||
|
|
||||||
|
func Stop(_ service.Service) error { return nil }
|
||||||
|
|
||||||
|
func InstallService() error { return nil }
|
||||||
|
|
||||||
|
func GetServiceStatus(name string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package software
|
|
||||||
|
|
||||||
import (
|
|
||||||
trmm "github.com/wh1te909/trmm-shared"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetInstalledSoftware() []SoftwareList { return []WinSoftwareList{} }
|
|
||||||
|
|
||||||
func InstallChoco() {}
|
|
||||||
|
|
||||||
func InstallWithChoco(name string) (string, error) { return "", nil }
|
|
||||||
12
agent/software/software_unix.go
Normal file
12
agent/software/software_unix.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package software
|
||||||
|
|
||||||
|
func GetInstalledSoftware() ([]Software, error) {
|
||||||
|
return []Software{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstallChoco() {}
|
||||||
|
|
||||||
|
func InstallWithChoco(name string) (string, error) { return "", nil }
|
||||||
|
|
@ -1,22 +1,30 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/amidaware/rmmagent/agent/events"
|
||||||
"github.com/amidaware/rmmagent/agent/utils"
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
ps "github.com/elastic/go-sysinfo"
|
ps "github.com/elastic/go-sysinfo"
|
||||||
"github.com/jaypipes/ghw"
|
"github.com/jaypipes/ghw"
|
||||||
"github.com/shirou/gopsutil/cpu"
|
"github.com/shirou/gopsutil/cpu"
|
||||||
"github.com/shirou/gopsutil/process"
|
"github.com/shirou/gopsutil/process"
|
||||||
psHost "github.com/shirou/gopsutil/v3/host"
|
psHost "github.com/shirou/gopsutil/v3/host"
|
||||||
rmm "github.com/amidaware/rmmagent/shared"
|
)
|
||||||
trmm "github.com/wh1te909/trmm-shared"
|
|
||||||
|
const (
|
||||||
|
ProgFilesName = "TacticalAgent"
|
||||||
|
winExeName = "tacticalrmm.exe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetDetached() *syscall.SysProcAttr {
|
func SetDetached() *syscall.SysProcAttr {
|
||||||
|
|
@ -31,14 +39,14 @@ func SystemRebootRequired() (bool, error) {
|
||||||
// deb
|
// deb
|
||||||
paths := [2]string{"/var/run/reboot-required", "/run/reboot-required"}
|
paths := [2]string{"/var/run/reboot-required", "/run/reboot-required"}
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
if trmm.FileExists(p) {
|
if utils.FileExists(p) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// rhel
|
// rhel
|
||||||
bins := [2]string{"/usr/bin/needs-restarting", "/bin/needs-restarting"}
|
bins := [2]string{"/usr/bin/needs-restarting", "/bin/needs-restarting"}
|
||||||
for _, bin := range bins {
|
for _, bin := range bins {
|
||||||
if trmm.FileExists(bin) {
|
if utils.FileExists(bin) {
|
||||||
opts := NewCMDOpts()
|
opts := NewCMDOpts()
|
||||||
// https://man7.org/linux/man-pages/man1/needs-restarting.1.html
|
// https://man7.org/linux/man-pages/man1/needs-restarting.1.html
|
||||||
// -r Only report whether a full reboot is required (exit code 1) or not (exit code 0).
|
// -r Only report whether a full reboot is required (exit code 1) or not (exit code 0).
|
||||||
|
|
@ -269,8 +277,8 @@ func DeleteSchedTask(name string) error { return nil }
|
||||||
|
|
||||||
func ListSchedTasks() []string { return []string{} }
|
func ListSchedTasks() []string { return []string{} }
|
||||||
|
|
||||||
func GetEventLog(logName string, searchLastDays int) []rmm.EventLogMsg {
|
func GetEventLog(logName string, searchLastDays int) []events.EventLogMsg {
|
||||||
return []rmm.EventLogMsg{}
|
return []events.EventLogMsg{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CMDShell(shell string, cmdArgs []string, command string, timeout int, detached bool) (output [2]string, e error) {
|
func CMDShell(shell string, cmdArgs []string, command string, timeout int, detached bool) (output [2]string, e error) {
|
||||||
|
|
@ -280,3 +288,20 @@ func CMDShell(shell string, cmdArgs []string, command string, timeout int, detac
|
||||||
func CMD(exe string, args []string, timeout int, detached bool) (output [2]string, e error) {
|
func CMD(exe string, args []string, timeout int, detached bool) (output [2]string, e error) {
|
||||||
return [2]string{"", ""}, nil
|
return [2]string{"", ""}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPythonBin() string {
|
||||||
|
opts := NewCMDOpts()
|
||||||
|
opts.Command = "which python"
|
||||||
|
out := CmdV2(opts)
|
||||||
|
return out.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProgramDirectory() string {
|
||||||
|
pd := filepath.Join(os.Getenv("ProgramFiles"), ProgFilesName)
|
||||||
|
return pd
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProgramBin() string {
|
||||||
|
exe := filepath.Join(GetProgramDirectory(), winExeName)
|
||||||
|
return exe
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -255,7 +255,7 @@ func GetProgramDirectory() string {
|
||||||
return pd
|
return pd
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetProgramEXE() string {
|
func GetProgramBin() string {
|
||||||
exe := filepath.Join(GetProgramDirectory(), winExeName)
|
exe := filepath.Join(GetProgramDirectory(), winExeName)
|
||||||
return exe
|
return exe
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ func CheckRunner(agentID string) error {
|
||||||
for {
|
for {
|
||||||
interval, err := GetCheckInterval(agentID)
|
interval, err := GetCheckInterval(agentID)
|
||||||
if err == nil && !ChecksRunning() {
|
if err == nil && !ChecksRunning() {
|
||||||
_, err = system.CMD(system.GetProgramEXE(), []string{"-m", "checkrunner"}, 600, false)
|
_, err = system.CMD(system.GetProgramBin(), []string{"-m", "checkrunner"}, 600, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ Out:
|
||||||
if p.PID == 0 {
|
if p.PID == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.Exe != system.GetProgramEXE() {
|
if p.Exe != system.GetProgramBin() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
38
agent/tactical/config/config_unix.go
Normal file
38
agent/tactical/config/config_unix.go
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewAgentConfig() *AgentConfig {
|
||||||
|
viper.SetConfigName("tacticalagent")
|
||||||
|
viper.SetConfigType("json")
|
||||||
|
viper.AddConfigPath("/etc/")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
err := viper.ReadInConfig()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return &AgentConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
agentpk := viper.GetString("agentpk")
|
||||||
|
pk, _ := strconv.Atoi(agentpk)
|
||||||
|
|
||||||
|
ret := &AgentConfig{
|
||||||
|
BaseURL: viper.GetString("baseurl"),
|
||||||
|
AgentID: viper.GetString("agentid"),
|
||||||
|
APIURL: viper.GetString("apiurl"),
|
||||||
|
Token: viper.GetString("token"),
|
||||||
|
AgentPK: agentpk,
|
||||||
|
PK: pk,
|
||||||
|
Cert: viper.GetString("cert"),
|
||||||
|
Proxy: viper.GetString("proxy"),
|
||||||
|
CustomMeshDir: viper.GetString("meshdir"),
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
package mesh
|
package mesh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/amidaware/rmmagent/agent/system"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/api"
|
"github.com/amidaware/rmmagent/agent/tactical/api"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/config"
|
"github.com/amidaware/rmmagent/agent/tactical/config"
|
||||||
"github.com/amidaware/rmmagent/agent/utils"
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
|
|
@ -26,3 +30,23 @@ func SyncMeshNodeID() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMeshNodeID() (string, error) {
|
||||||
|
out, err := system.CMD(GetMeshBinLocation(), []string{"-nodeid"}, 10, false)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout := out[0]
|
||||||
|
stderr := out[1]
|
||||||
|
|
||||||
|
if stderr != "" {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if stdout == "" || strings.Contains(strings.ToLower(utils.StripAll(stdout)), "not defined") {
|
||||||
|
return "", errors.New("failed to get mesh node id")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout, nil
|
||||||
|
}
|
||||||
24
agent/tactical/mesh/mesh_unix.go
Normal file
24
agent/tactical/mesh/mesh_unix.go
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package mesh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/amidaware/rmmagent/agent/tactical/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMeshBinLocation() string {
|
||||||
|
ac := config.NewAgentConfig()
|
||||||
|
var MeshSysBin string
|
||||||
|
if len(ac.CustomMeshDir) > 0 {
|
||||||
|
MeshSysBin = filepath.Join(ac.CustomMeshDir, "meshagent")
|
||||||
|
} else {
|
||||||
|
MeshSysBin = "/opt/tacticalmesh/meshagent"
|
||||||
|
}
|
||||||
|
|
||||||
|
return MeshSysBin
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecoverMesh() { }
|
||||||
|
|
@ -41,27 +41,7 @@ func ForceKillMesh() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMeshNodeID() (string, error) {
|
func GetMeshBinLocation() string {
|
||||||
out, err := system.CMD(getMeshBinLocation(), []string{"-nodeid"}, 10, false)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout := out[0]
|
|
||||||
stderr := out[1]
|
|
||||||
|
|
||||||
if stderr != "" {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if stdout == "" || strings.Contains(strings.ToLower(utils.StripAll(stdout)), "not defined") {
|
|
||||||
return "", errors.New("failed to get mesh node id")
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdout, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMeshBinLocation() string {
|
|
||||||
ac := config.NewAgentConfig()
|
ac := config.NewAgentConfig()
|
||||||
var MeshSysBin string
|
var MeshSysBin string
|
||||||
if len(ac.CustomMeshDir) > 0 {
|
if len(ac.CustomMeshDir) > 0 {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,6 @@ func RunRPC(version string) {
|
||||||
var resp []byte
|
var resp []byte
|
||||||
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
|
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
|
||||||
procs := system.GetProcsRPC()
|
procs := system.GetProcsRPC()
|
||||||
//a.Logger.Debugln(procs)
|
|
||||||
ret.Encode(procs)
|
ret.Encode(procs)
|
||||||
msg.Respond(resp)
|
msg.Respond(resp)
|
||||||
}()
|
}()
|
||||||
|
|
@ -365,7 +364,7 @@ func RunRPC(version string) {
|
||||||
} else {
|
} else {
|
||||||
ret.Encode("ok")
|
ret.Encode("ok")
|
||||||
msg.Respond(resp)
|
msg.Respond(resp)
|
||||||
_, checkerr := system.CMD(system.GetProgramEXE(), []string{"-m", "runchecks"}, 600, false)
|
_, checkerr := system.CMD(system.GetProgramBin(), []string{"-m", "runchecks"}, 600, false)
|
||||||
if checkerr != nil {
|
if checkerr != nil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package rpc
|
|
||||||
|
|
||||||
func RunRPC(version string) {
|
|
||||||
}
|
|
||||||
|
|
@ -2,23 +2,16 @@ package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/amidaware/rmmagent/agent/disk"
|
|
||||||
"github.com/amidaware/rmmagent/agent/network"
|
|
||||||
"github.com/amidaware/rmmagent/agent/services"
|
|
||||||
"github.com/amidaware/rmmagent/agent/system"
|
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/api"
|
"github.com/amidaware/rmmagent/agent/tactical/api"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/checks"
|
"github.com/amidaware/rmmagent/agent/tactical/checks"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/config"
|
"github.com/amidaware/rmmagent/agent/tactical/config"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/mesh"
|
"github.com/amidaware/rmmagent/agent/tactical/mesh"
|
||||||
"github.com/amidaware/rmmagent/agent/tactical/shared"
|
"github.com/amidaware/rmmagent/agent/tactical/shared"
|
||||||
"github.com/amidaware/rmmagent/agent/utils"
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
"github.com/amidaware/rmmagent/agent/wmi"
|
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
"github.com/ugorji/go/codec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var natsCheckin = []string{"agent-hello", "agent-agentinfo", "agent-disks", "agent-winsvc", "agent-publicip", "agent-wmi"}
|
var natsCheckin = []string{"agent-hello", "agent-agentinfo", "agent-disks", "agent-winsvc", "agent-publicip", "agent-wmi"}
|
||||||
|
|
@ -98,65 +91,6 @@ func SetupNatsOptions() []nats.Option {
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func NatsMessage(version string, nc *nats.Conn, mode string) {
|
|
||||||
config := config.NewAgentConfig()
|
|
||||||
var resp []byte
|
|
||||||
var payload interface{}
|
|
||||||
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case "agent-hello":
|
|
||||||
payload = CheckInNats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
Version: version,
|
|
||||||
}
|
|
||||||
case "agent-winsvc":
|
|
||||||
svcs, _, _ := services.GetServices()
|
|
||||||
payload = WinSvcNats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
WinSvcs: svcs,
|
|
||||||
}
|
|
||||||
case "agent-agentinfo":
|
|
||||||
osinfo := system.OsString()
|
|
||||||
reboot, err := system.SystemRebootRequired()
|
|
||||||
if err != nil {
|
|
||||||
reboot = false
|
|
||||||
}
|
|
||||||
payload = AgentInfoNats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
Username: system.LoggedOnUser(),
|
|
||||||
Hostname: system.GetHostname(),
|
|
||||||
OS: osinfo,
|
|
||||||
Platform: runtime.GOOS,
|
|
||||||
TotalRAM: system.TotalRAM(),
|
|
||||||
BootTime: system.BootTime(),
|
|
||||||
RebootNeeded: reboot,
|
|
||||||
GoArch: runtime.GOARCH,
|
|
||||||
}
|
|
||||||
case "agent-wmi":
|
|
||||||
wmiinfo, _ := wmi.GetWMIInfo()
|
|
||||||
payload = WinWMINats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
WMI: wmiinfo,
|
|
||||||
}
|
|
||||||
case "agent-disks":
|
|
||||||
disks, _ := disk.GetDisks()
|
|
||||||
payload = WinDisksNats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
Disks: disks,
|
|
||||||
}
|
|
||||||
case "agent-publicip":
|
|
||||||
payload = PublicIPNats{
|
|
||||||
Agentid: config.AgentID,
|
|
||||||
PublicIP: network.PublicIP(config.Proxy),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//a.Logger.Debugln(mode, payload)
|
|
||||||
ret.Encode(payload)
|
|
||||||
nc.PublishRequest(config.AgentID, mode, resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DoNatsCheckIn(version string) {
|
func DoNatsCheckIn(version string) {
|
||||||
opts := SetupNatsOptions()
|
opts := SetupNatsOptions()
|
||||||
server := fmt.Sprintf("tls://%s:4222", config.NewAgentConfig().APIURL)
|
server := fmt.Sprintf("tls://%s:4222", config.NewAgentConfig().APIURL)
|
||||||
|
|
|
||||||
75
agent/tactical/service/service_unix.go
Normal file
75
agent/tactical/service/service_unix.go
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/amidaware/rmmagent/agent/disk"
|
||||||
|
"github.com/amidaware/rmmagent/agent/network"
|
||||||
|
"github.com/amidaware/rmmagent/agent/services"
|
||||||
|
"github.com/amidaware/rmmagent/agent/system"
|
||||||
|
"github.com/amidaware/rmmagent/agent/tactical/config"
|
||||||
|
"github.com/amidaware/rmmagent/agent/umi"
|
||||||
|
"github.com/nats-io/nats.go"
|
||||||
|
"github.com/ugorji/go/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NatsMessage(version string, nc *nats.Conn, mode string) {
|
||||||
|
config := config.NewAgentConfig()
|
||||||
|
var resp []byte
|
||||||
|
var payload interface{}
|
||||||
|
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
|
||||||
|
|
||||||
|
switch mode {
|
||||||
|
case "agent-hello":
|
||||||
|
payload = CheckInNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
case "agent-winsvc":
|
||||||
|
svcs, _, _ := services.GetServices()
|
||||||
|
payload = WinSvcNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
WinSvcs: svcs,
|
||||||
|
}
|
||||||
|
case "agent-agentinfo":
|
||||||
|
osinfo := system.OsString()
|
||||||
|
reboot, err := system.SystemRebootRequired()
|
||||||
|
if err != nil {
|
||||||
|
reboot = false
|
||||||
|
}
|
||||||
|
payload = AgentInfoNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Username: system.LoggedOnUser(),
|
||||||
|
Hostname: system.GetHostname(),
|
||||||
|
OS: osinfo,
|
||||||
|
Platform: runtime.GOOS,
|
||||||
|
TotalRAM: system.TotalRAM(),
|
||||||
|
BootTime: system.BootTime(),
|
||||||
|
RebootNeeded: reboot,
|
||||||
|
GoArch: runtime.GOARCH,
|
||||||
|
}
|
||||||
|
case "agent-wmi":
|
||||||
|
wmiinfo, _ := umi.GetInfo()
|
||||||
|
payload = WinWMINats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
WMI: wmiinfo,
|
||||||
|
}
|
||||||
|
case "agent-disks":
|
||||||
|
disks, _ := disk.GetDisks()
|
||||||
|
payload = WinDisksNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Disks: disks,
|
||||||
|
}
|
||||||
|
case "agent-publicip":
|
||||||
|
payload = PublicIPNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
PublicIP: network.PublicIP(config.Proxy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.Encode(payload)
|
||||||
|
nc.PublishRequest(config.AgentID, mode, resp)
|
||||||
|
}
|
||||||
60
agent/tactical/service/service_windows.go
Normal file
60
agent/tactical/service/service_windows.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
func NatsMessage(version string, nc *nats.Conn, mode string) {
|
||||||
|
config := config.NewAgentConfig()
|
||||||
|
var resp []byte
|
||||||
|
var payload interface{}
|
||||||
|
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
|
||||||
|
|
||||||
|
switch mode {
|
||||||
|
case "agent-hello":
|
||||||
|
payload = CheckInNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
case "agent-winsvc":
|
||||||
|
svcs, _, _ := services.GetServices()
|
||||||
|
payload = WinSvcNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
WinSvcs: svcs,
|
||||||
|
}
|
||||||
|
case "agent-agentinfo":
|
||||||
|
osinfo := system.OsString()
|
||||||
|
reboot, err := system.SystemRebootRequired()
|
||||||
|
if err != nil {
|
||||||
|
reboot = false
|
||||||
|
}
|
||||||
|
payload = AgentInfoNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Username: system.LoggedOnUser(),
|
||||||
|
Hostname: system.GetHostname(),
|
||||||
|
OS: osinfo,
|
||||||
|
Platform: runtime.GOOS,
|
||||||
|
TotalRAM: system.TotalRAM(),
|
||||||
|
BootTime: system.BootTime(),
|
||||||
|
RebootNeeded: reboot,
|
||||||
|
GoArch: runtime.GOARCH,
|
||||||
|
}
|
||||||
|
case "agent-wmi":
|
||||||
|
wmiinfo, _ := wmi.GetWMIInfo()
|
||||||
|
payload = WinWMINats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
WMI: wmiinfo,
|
||||||
|
}
|
||||||
|
case "agent-disks":
|
||||||
|
disks, _ := disk.GetDisks()
|
||||||
|
payload = WinDisksNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
Disks: disks,
|
||||||
|
}
|
||||||
|
case "agent-publicip":
|
||||||
|
payload = PublicIPNats{
|
||||||
|
Agentid: config.AgentID,
|
||||||
|
PublicIP: network.PublicIP(config.Proxy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//a.Logger.Debugln(mode, payload)
|
||||||
|
ret.Encode(payload)
|
||||||
|
nc.PublishRequest(config.AgentID, mode, resp)
|
||||||
|
}
|
||||||
8
agent/tactical/shared/shared_unix.go
Normal file
8
agent/tactical/shared/shared_unix.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package shared
|
||||||
|
|
||||||
|
func GetPython(force bool) {}
|
||||||
|
|
||||||
|
func RunMigrations() {}
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/amidaware/rmmagent/agent/system"
|
"github.com/amidaware/rmmagent/agent/system"
|
||||||
|
"github.com/amidaware/rmmagent/agent/tactical/mesh"
|
||||||
"github.com/amidaware/rmmagent/agent/utils"
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
"github.com/amidaware/rmmagent/shared"
|
"github.com/amidaware/rmmagent/shared"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
|
@ -166,7 +167,7 @@ func RecoverMesh(agentID string) {
|
||||||
opts := system.NewCMDOpts()
|
opts := system.NewCMDOpts()
|
||||||
opts.Command = "systemctl restart meshagent.service"
|
opts.Command = "systemctl restart meshagent.service"
|
||||||
system.CmdV2(opts)
|
system.CmdV2(opts)
|
||||||
SyncMeshNodeID()
|
mesh.SyncMeshNodeID()
|
||||||
}
|
}
|
||||||
|
|
||||||
func UninstallCleanup() {}
|
func UninstallCleanup() {}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
package tasks
|
package tasks
|
||||||
|
|
||||||
type SchedTask struct {
|
type SchedTask struct {
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package tasks
|
|
||||||
|
|
||||||
func CreateSchedTask(st SchedTask) (bool, error) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
16
agent/tasks/tasks_unix.go
Normal file
16
agent/tasks/tasks_unix.go
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package tasks
|
||||||
|
|
||||||
|
func CreateSchedTask(st SchedTask) (bool, error) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSchedTask(name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListSchedTasks() ([]string, error) {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
123
agent/umi/umi_linux.go
Normal file
123
agent/umi/umi_linux.go
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package umi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/amidaware/rmmagent/agent/utils"
|
||||||
|
ps "github.com/elastic/go-sysinfo"
|
||||||
|
"github.com/jaypipes/ghw"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetInfo() (map[string]interface{}, []error) {
|
||||||
|
info := make(map[string]interface{})
|
||||||
|
errs := []error{}
|
||||||
|
ips := make([]string, 0)
|
||||||
|
disks := make([]string, 0)
|
||||||
|
cpus := make([]string, 0)
|
||||||
|
gpus := make([]string, 0)
|
||||||
|
|
||||||
|
// local ips
|
||||||
|
host, err := ps.Host()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else {
|
||||||
|
for _, ip := range host.Info().IPs {
|
||||||
|
if strings.Contains(ip, "127.0.") || strings.Contains(ip, "::1/128") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ips = append(ips, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info["local_ips"] = ips
|
||||||
|
// disks
|
||||||
|
block, err := ghw.Block(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else {
|
||||||
|
for _, disk := range block.Disks {
|
||||||
|
if disk.IsRemovable || strings.Contains(disk.Name, "ram") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret := fmt.Sprintf("%s %s %s %s %s %s", disk.Vendor, disk.Model, disk.StorageController, disk.DriveType, disk.Name, utils.ByteCountSI(disk.SizeBytes))
|
||||||
|
ret = strings.TrimSpace(strings.ReplaceAll(ret, "unknown", ""))
|
||||||
|
disks = append(disks, ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info["disks"] = disks
|
||||||
|
// cpus
|
||||||
|
cpuInfo, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else {
|
||||||
|
if len(cpuInfo) > 0 {
|
||||||
|
if cpuInfo[0].ModelName != "" {
|
||||||
|
cpus = append(cpus, cpuInfo[0].ModelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info["cpus"] = cpus
|
||||||
|
// make/model
|
||||||
|
info["make_model"] = ""
|
||||||
|
chassis, err := ghw.Chassis(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else {
|
||||||
|
if chassis.Vendor != "" || chassis.Version != "" {
|
||||||
|
info["make_model"] = fmt.Sprintf("%s %s", chassis.Vendor, chassis.Version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gfx cards
|
||||||
|
gpu, err := ghw.GPU(ghw.WithDisableWarnings())
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else {
|
||||||
|
for _, i := range gpu.GraphicsCards {
|
||||||
|
if i.DeviceInfo != nil {
|
||||||
|
ret := fmt.Sprintf("%s %s", i.DeviceInfo.Vendor.Name, i.DeviceInfo.Product.Name)
|
||||||
|
gpus = append(gpus, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info["gpus"] = gpus
|
||||||
|
// temp hack for ARM cpu/make/model if rasp pi
|
||||||
|
var makeModel string
|
||||||
|
if strings.Contains(runtime.GOARCH, "arm") {
|
||||||
|
file, _ := os.Open("/proc/cpuinfo")
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
if strings.Contains(strings.ToLower(scanner.Text()), "raspberry") {
|
||||||
|
model := strings.Split(scanner.Text(), ":")
|
||||||
|
if len(model) == 2 {
|
||||||
|
makeModel = strings.TrimSpace(model[1])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cpus) == 0 {
|
||||||
|
info["cpus"] = []string{makeModel}
|
||||||
|
}
|
||||||
|
if makeModel != "" && (info["make_model"] == "" || info["make_model"] == "unknown unknown") {
|
||||||
|
info["make_model"] = makeModel
|
||||||
|
}
|
||||||
|
if len(gpus) == 1 && gpus[0] == "unknown unknown" {
|
||||||
|
info["gpus"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, errs
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
goDebug "runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -138,10 +139,13 @@ func GenerateAgentID() string {
|
||||||
func ShowVersionInfo(ver string) {
|
func ShowVersionInfo(ver string) {
|
||||||
fmt.Println("Tactical RMM Agent:", ver)
|
fmt.Println("Tactical RMM Agent:", ver)
|
||||||
fmt.Println("Arch:", runtime.GOARCH)
|
fmt.Println("Arch:", runtime.GOARCH)
|
||||||
fmt.Println("Go version:", runtime.Version())
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
fmt.Println("Program Directory:", filepath.Join(os.Getenv("ProgramFiles"), progFilesName))
|
fmt.Println("Program Directory:", filepath.Join(os.Getenv("ProgramFiles"), progFilesName))
|
||||||
}
|
}
|
||||||
|
bi, ok := goDebug.ReadBuildInfo()
|
||||||
|
if ok {
|
||||||
|
fmt.Println(bi.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalRAM returns total RAM in GB
|
// TotalRAM returns total RAM in GB
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue