171 lines
4.5 KiB
Go
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)
|
|
}
|
|
}
|