sysinfo/internal/sysinfo/helpers.go
2025-05-01 03:07:12 -07:00

171 lines
4.5 KiB
Go

package sysinfo
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
)
const (
rootDir = "/etc/sysinfo"
snapshotJSON = "snapshot.json"
debianFrontEnv = "DEBIAN_FRONTEND=noninteractive"
)
/* ------------------------------------------------------------------ */
/* platform check */
/* ------------------------------------------------------------------ */
func (a *App) ensureUbuntu() error {
out, err := a.runCmd("lsb_release", "-is")
if err != nil {
return fmt.Errorf("unsupported OS: lsb_release not found")
}
if strings.ToLower(strings.TrimSpace(string(out))) != "ubuntu" {
return fmt.Errorf("unsupported OS: %s",
strings.TrimSpace(string(out)))
}
return nil
}
/* ------------------------------------------------------------------ */
/* command helpers */
/* ------------------------------------------------------------------ */
func (a *App) runCmd(name string, args ...string) ([]byte, error) {
cmd := exec.Command(name, args...)
var buf bytes.Buffer
cmd.Stdout, cmd.Stderr = &buf, &buf
err := cmd.Run()
return buf.Bytes(), err
}
func (a *App) safeRun(name string, args ...string) string {
out, _ := a.runCmd(name, args...)
return string(out)
}
func (a *App) runJSON(dst *json.RawMessage,
name string, args ...string) []byte {
out, _ := a.runCmd(name, args...)
*dst = json.RawMessage(out)
return out
}
func (a *App) safeRead(path string) string {
b, _ := ioutil.ReadFile(path)
return string(b)
}
/* ------------------------------------------------------------------ */
/* JSON emitter */
/* ------------------------------------------------------------------ */
func (a *App) emitJSON(f *os.File, s *Snapshot) error {
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
return enc.Encode(s)
}
/* ------------------------------------------------------------------ */
/* network helpers */
/* ------------------------------------------------------------------ */
func (a *App) readNetStats(iface string) (json.RawMessage, error) {
dir := filepath.Join("/sys/class/net", iface, "statistics")
ent, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
}
m := map[string]int64{}
for _, f := range ent {
b, _ := ioutil.ReadFile(filepath.Join(dir, f.Name()))
n, _ := strconv.ParseInt(strings.TrimSpace(string(b)), 10, 64)
m[f.Name()] = n
}
j, _ := json.Marshal(m)
return j, nil
}
func (a *App) defaultIfaceSet() (map[string]bool, error) {
out, err := a.runCmd("ip", "-j", "route", "show", "default")
if err != nil {
return nil, err
}
var routes []struct{ Dev string `json:"dev"` }
_ = json.Unmarshal(out, &routes)
m := map[string]bool{}
for _, r := range routes {
m[r.Dev] = true
}
return m, nil
}
func (a *App) primaryMAC() string {
ifs, _ := ioutil.ReadDir("/sys/class/net")
for _, f := range ifs {
if f.Name() == "lo" {
continue
}
mac := a.safeRead(filepath.Join(
"/sys/class/net", f.Name(), "address"))
mac = strings.ToLower(strings.ReplaceAll(
strings.TrimSpace(mac), ":", ""))
if mac != "" {
return mac
}
}
return ""
}
/* ------------------------------------------------------------------ */
/* apt helpers */
/* ------------------------------------------------------------------ */
func (a *App) aptInstall(pkg string) error {
if !a.aptUpdated {
if err := a.runApt("apt-get", "update"); err != nil {
return err
}
a.aptUpdated = true
}
return a.runApt("apt-get", "-y", "install", pkg)
}
func (a *App) runApt(name string, args ...string) error {
cmd := exec.Command(name, args...)
cmd.Env = append(os.Environ(), debianFrontEnv)
if a.verbose {
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
}
return cmd.Run()
}
/* ------------------------------------------------------------------ */
/* file helpers */
/* ------------------------------------------------------------------ */
func (a *App) mustWriteText(dir, name, content string) {
if err := ioutil.WriteFile(
filepath.Join(dir, name),
[]byte(content), 0644); err != nil {
panic(err)
}
}
func (a *App) mustWriteJSON(dir, name string, raw json.RawMessage) {
if len(raw) == 0 {
return
}
if err := ioutil.WriteFile(
filepath.Join(dir, name), raw, 0644); err != nil {
panic(err)
}
}