mirror of
https://github.com/rwinkhart/unifi-shutd.git
synced 2026-09-01 14:37:23 -04:00
125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"github.com/rwinkhart/go-boilerplate/front"
|
|
"github.com/rwinkhart/go-boilerplate/other"
|
|
nut "github.com/rwinkhart/uni-nut"
|
|
)
|
|
|
|
const configPath = "/etc/unifi-shutd.json"
|
|
|
|
type configT struct {
|
|
IP string `json:"ip"`
|
|
Port string `json:"port"`
|
|
Username *string `json:"username"`
|
|
Password *string `json:"password"`
|
|
ScanIntervalSeconds int `json:"scan_interval_seconds"`
|
|
BadScanLimit int `json:"bad_scan_limit"`
|
|
}
|
|
|
|
func main() {
|
|
var config configT
|
|
if len(os.Args) < 2 {
|
|
printUsageInfo()
|
|
}
|
|
switch os.Args[1] {
|
|
case "start":
|
|
configBytes, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
other.PrintError("Failed to read ("+configPath+"): "+err.Error(), 1)
|
|
}
|
|
err = json.Unmarshal(configBytes, &config)
|
|
if err != nil {
|
|
other.PrintError("Failed to unmarshal config file: "+err.Error(), 2)
|
|
}
|
|
case "config":
|
|
if os.Geteuid() != 0 {
|
|
fmt.Printf("\"%s config\" must be run as root\n", os.Args[0])
|
|
os.Exit(0)
|
|
}
|
|
var username, password *string
|
|
if front.InputBinary("Does your NUT server use authentication (username/password)?") {
|
|
usernameStr := front.Input("NUT Username:")
|
|
passwordStr := string(front.InputHidden("NUT Password:"))
|
|
username = &usernameStr
|
|
password = &passwordStr
|
|
}
|
|
config = configT{
|
|
IP: front.Input("NUT IP:"),
|
|
Port: front.Input("NUT Port:"),
|
|
Username: username,
|
|
Password: password,
|
|
ScanIntervalSeconds: front.InputInt("Scan Interval (seconds):", 1, -1),
|
|
BadScanLimit: front.InputInt("Bad Scan Limit:", 1, -1),
|
|
}
|
|
configBytes, err := json.Marshal(config)
|
|
if err != nil {
|
|
other.PrintError("Failed to marshal config file: "+err.Error(), 3)
|
|
}
|
|
err = os.WriteFile(configPath, configBytes, 0600)
|
|
if err != nil {
|
|
other.PrintError("Failed to write ("+configPath+"): "+err.Error(), 4)
|
|
}
|
|
os.Exit(0)
|
|
default:
|
|
printUsageInfo()
|
|
}
|
|
|
|
intervalDur := time.Duration(config.ScanIntervalSeconds) * time.Second
|
|
client, err := nut.Dial(config.IP + ":" + config.Port)
|
|
if err != nil {
|
|
other.PrintError("Failed to dial NUT server ("+os.Args[1]+"): "+err.Error(), 7)
|
|
}
|
|
|
|
if config.Username != nil {
|
|
err = client.Authenticate(*config.Username, *config.Password)
|
|
if err != nil {
|
|
other.PrintError("Failed to authenticate with NUT server: "+err.Error(), 8)
|
|
}
|
|
}
|
|
|
|
err = client.AutomaticallySetID()
|
|
if err != nil {
|
|
other.PrintError("Failed to detect UPS ID: "+err.Error(), 9)
|
|
}
|
|
|
|
log.Println("Starting NUT monitoring loop...")
|
|
cmd := exec.Command("/sbin/poweroff")
|
|
var value string
|
|
var badCycles int
|
|
for {
|
|
time.Sleep(intervalDur)
|
|
value, err = client.GetVar("ups.status")
|
|
if err != nil {
|
|
other.PrintError("Failed to get status from \""+os.Args[2]+"\": "+err.Error(), 10)
|
|
}
|
|
|
|
switch value {
|
|
case "OB DISCHRG":
|
|
badCycles++
|
|
log.Printf("BAD cycle: %d", badCycles)
|
|
default:
|
|
badCycles = 0
|
|
}
|
|
if badCycles >= config.BadScanLimit {
|
|
log.Println("Bad scan limit reached; initiating shutdown...")
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
other.PrintError("Failed to execute shutdown command: "+err.Error(), 11)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func printUsageInfo() {
|
|
fmt.Printf("Usage: %s [start | config]\n", os.Args[0])
|
|
os.Exit(0)
|
|
}
|