From 0299b5d08bac1ab5326b8e8734ce19c8130ec42c Mon Sep 17 00:00:00 2001 From: David Newhall Date: Thu, 25 Mar 2021 21:55:15 -0700 Subject: [PATCH] Plex webhook fixes. (#25) --- .travis.yml | 4 +- go.mod | 2 +- main.go | 8 ++-- pkg/client/start.go | 1 + pkg/snapshot/smartctl.go | 20 ++++++++- pkg/snapshot/snapshot.go | 15 ++++++- pkg/snapshot/synology.go | 89 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 pkg/snapshot/synology.go diff --git a/.travis.yml b/.travis.yml index da94e95a0..70128f657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,12 @@ jobs: - os: osx osx_image: xcode12 language: go - go: 1.15.x + go: 1.16.x - os: linux dist: bionic services: docker language: go - go: 1.15.x + go: 1.16.x git: depth: false addons: diff --git a/go.mod b/go.mod index 1f7a27fca..3513a8e88 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Go-Lift-TV/discordnotifier-client -go 1.15 +go 1.16 require ( github.com/BurntSushi/toml v0.3.1 diff --git a/main.go b/main.go index df266c491..3d6fb9ffd 100644 --- a/main.go +++ b/main.go @@ -11,12 +11,14 @@ import ( ) func main() { - if err := run(); err != nil { + setup() + + if err := client.Start(); err != nil { log.Fatal(err) } } -func run() error { +func setup() { ui.HideConsoleWindow() // setup log package in case we throw an error for main.go before logging is setup. log.SetFlags(log.LstdFlags) @@ -26,8 +28,6 @@ func run() error { if err := setTimeZone(os.Getenv("TZ")); err != nil { log.Print(err) } - - return client.Start() } func setTimeZone(tz string) (err error) { diff --git a/pkg/client/start.go b/pkg/client/start.go index a253679c4..5f8770015 100644 --- a/pkg/client/start.go +++ b/pkg/client/start.go @@ -153,6 +153,7 @@ func start() error { func (c *Client) run(newConfig bool) error { if c.Flags.testSnaps { c.checkPlex() + c.Config.Snapshot.Validate() c.logSnaps() return nil diff --git a/pkg/snapshot/smartctl.go b/pkg/snapshot/smartctl.go index 01ac5e512..a8d969c9e 100644 --- a/pkg/snapshot/smartctl.go +++ b/pkg/snapshot/smartctl.go @@ -89,7 +89,17 @@ func getParts(ctx context.Context) ([]string, error) { } func (s *Snapshot) getDiskData(ctx context.Context, disk string, useSudo bool) error { //nolint: cyclop - cmd, stdout, wg, err := readyCommand(ctx, useSudo, "smartctl", "-A", disk) + if strings.HasPrefix(disk, "/dev/md") || strings.HasPrefix(disk, "/dev/ram") || + strings.HasPrefix(disk, "/dev/zram") || strings.HasPrefix(disk, "/dev/synoboot") { + return nil + } + + args := []string{"-A", disk} + if s.synology { + args = []string{"-d", "sat", "-a", disk} + } + + cmd, stdout, wg, err := readyCommand(ctx, useSudo, "smartctl", args...) if err != nil { return err } @@ -117,6 +127,11 @@ func (s *Snapshot) getDiskData(ctx context.Context, disk string, useSudo bool) e } func (s *Snapshot) getDiskHealth(ctx context.Context, disk string, useSudo bool) error { + if strings.HasPrefix(disk, "/dev/md") || strings.HasPrefix(disk, "/dev/ram") || + strings.HasPrefix(disk, "/dev/zram") || strings.HasPrefix(disk, "/dev/synoboot") { + return nil + } + cmd, stdout, wg, err := readyCommand(ctx, useSudo, "smartctl", "-H", disk) if err != nil { return err @@ -124,7 +139,8 @@ func (s *Snapshot) getDiskHealth(ctx context.Context, disk string, useSudo bool) go func() { for stdout.Scan() { - if text := stdout.Text(); strings.Contains(text, "self-assessment ") { + if text := stdout.Text(); strings.Contains(text, "self-assessment ") || + strings.Contains(text, "SMART Health Status:") { s.DiskHealth[disk] = text[strings.LastIndex(text, " ")+1:] } } diff --git a/pkg/snapshot/snapshot.go b/pkg/snapshot/snapshot.go index 91d7a6ee8..0f8808eb8 100644 --- a/pkg/snapshot/snapshot.go +++ b/pkg/snapshot/snapshot.go @@ -5,6 +5,7 @@ import ( "bytes" "context" "fmt" + "os" "os/exec" "sync" "time" @@ -24,6 +25,7 @@ const ( type Config struct { Timeout cnfg.Duration `toml:"timeout"` // total run time allowed. Interval cnfg.Duration `toml:"interval"` // how often to send snaps (cron). + ZFSPools []string `toml:"zfs_pools"` // zfs pools to monitor. UseSudo bool `toml:"use_sudo"` // use sudo for smartctl commands. Raid bool `toml:"monitor_raid"` // include mdstat and/or megaraid. DriveData bool `toml:"monitor_drives"` // smartctl commands. @@ -31,7 +33,7 @@ type Config struct { Uptime bool `toml:"monitor_uptime"` // all system stats. CPUMem bool `toml:"monitor_cpuMemory"` // cpu perct and memory used/free. CPUTemp bool `toml:"monitor_cpuTemp"` // not everything supports temps. - ZFSPools []string `toml:"zfs_pools"` // zfs pools to monitor. + synology bool } // Errors this package generates. @@ -60,6 +62,7 @@ type Snapshot struct { DiskUsage map[string]*Partition `json:"diskUsage,omitempty"` DiskHealth map[string]string `json:"driveHealth,omitempty"` ZFSPool map[string]*Partition `json:"zfsPools,omitempty"` + synology bool } // RaidData contains raid information from mdstat and/or megacli. @@ -85,6 +88,10 @@ func (c *Config) Validate() { } else if c.Interval.Duration < minimumInterval { c.Interval.Duration = minimumInterval } + + if _, err := os.Stat(synologyConf); err == nil { + c.synology = true + } } // GetSnapshot returns a system snapshot based on requested data in the config. @@ -98,7 +105,7 @@ func (c *Config) GetSnapshot() (*Snapshot, []error, []error) { ctx, cancel := context.WithTimeout(context.Background(), c.Timeout.Duration) defer cancel() - s := &Snapshot{} + s := &Snapshot{synology: c.synology} errs, debug := c.getSnapshot(ctx, s) return s, errs, debug @@ -111,6 +118,10 @@ func (c *Config) getSnapshot(ctx context.Context, s *Snapshot) ([]error, []error errs = append(errs, err...) } + if err := s.GetSynology(c.Uptime); err != nil { + errs = append(errs, err) + } + if err := s.getDisksUsage(ctx, c.DiskUsage); len(err) != 0 { errs = append(errs, err...) } diff --git a/pkg/snapshot/synology.go b/pkg/snapshot/synology.go new file mode 100644 index 000000000..19e13fb17 --- /dev/null +++ b/pkg/snapshot/synology.go @@ -0,0 +1,89 @@ +package snapshot + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" +) + +const synologyConf = "/etc/synoinfo.conf" + +type Synology struct { + Build string `json:"last_admin_login_build"` // 254263 + Manager string `json:"manager"` // Synology DiskStation + Vendor string `json:"vender"` // Synology Inc. + Model string `json:"upnpmodelname"` // DS1517+ + Version string `json:"udc_check_state"` // 6.2.3 +} + +/* + "platform": "Synology Inc.", + "platformFamily": "Synology DiskStation DS1517+", + "platformVersion": "6.2.3-254263", +*/ + +func (s *Snapshot) GetSynology(run bool) error { //nolint:cyclop + if !run || !s.synology { + return nil + } + + file, err := os.Open(synologyConf) + if err != nil { + return fmt.Errorf("opening synology conf: %w", err) + } + defer file.Close() + + // Start reading from the file with a reader. + var ( + reader = bufio.NewReader(file) + syn = &Synology{} + ) + + for { + line, err := reader.ReadString('\n') + if errors.Is(err, io.EOF) { + break + } else if err != nil { + return fmt.Errorf("reading synology conf: %w", err) + } + + lsplit := strings.Split(line, "=") + if len(lsplit) < 2 { //nolint:gomnd + continue + } + + switch lsplit[0] { + case "last_admin_login_build": + syn.Build = strings.Trim(lsplit[1], "\n\"") + case "manager": + syn.Manager = strings.Trim(lsplit[1], "\n\"") + case "vender": + syn.Vendor = strings.Trim(lsplit[1], "\n\"") + case "upnpmodelname": + syn.Model = strings.Trim(lsplit[1], "\n\"") + case "udc_check_state": + syn.Version = strings.Trim(lsplit[1], "\n\"") + } + } + + s.setSynology(syn) + + return nil +} + +func (s *Snapshot) setSynology(syn *Synology) { + if s.System.InfoStat.Platform == "" && syn.Vendor != "" { + s.System.InfoStat.Platform = syn.Vendor + } + + if s.System.InfoStat.PlatformFamily == "" && syn.Manager != "" { + s.System.InfoStat.PlatformFamily = syn.Manager + " " + syn.Model + } + + if s.System.InfoStat.PlatformVersion == "" && syn.Version != "" { + s.System.InfoStat.PlatformVersion = syn.Version + "-" + syn.Build + } +}