infra/scripts/server_safe_poweroff/main.go
2025-10-11 17:14:59 +00:00

107 lines
3 KiB
Go

package main
import (
"flag"
"log"
"github.com/golang/glog"
"github.com/nightlyone/lockfile"
)
const upsMinutesRemainingThreshold = 20
type idracCredentials = struct {
url string
username string
password string
}
func main() {
idracUsername := flag.String("idracUsername", "root", "iDRAC username")
idracPassword := flag.String("idracPassword", "calvin", "iDRAC password")
idracHost := flag.String("idracHost", "192.168.1.4", "iDRAC host")
flag.Parse()
defer glog.Flush()
// lock, err := tryGetLock()
// if err != nil {
// glog.Fatalf("Failed to acquire lock: %v", err)
// }
// defer lock.Unlock()
glog.Info("Checking server power state")
idracCredentials := idracCredentials{
url: "https://" + *idracHost,
username: *idracUsername,
password: *idracPassword,
}
powerState, err := checkPowerState(idracCredentials)
if err != nil {
glog.Fatalf("Failed to check power state: %v", err)
}
glog.Infof("Server power state: %s", powerState)
glog.Info("Checking UPS state")
snmp := getSNMPClient()
// Connect to the SNMP agent
err = snmp.Connect()
if err != nil {
log.Fatalf("Failed to connect to UPS SNMP agent: %v", err)
}
defer snmp.Conn.Close()
upsState, err := getPowerState(snmp)
if err != nil {
glog.Fatalf("Failed to get UPS power state: %v", err)
}
if powerState == "On" {
handleWhenServerOn(upsState, idracCredentials)
} else if powerState == "Off" {
handleWhenServerOff(upsState, idracCredentials)
} else {
glog.Fatalf("Unknown server state %s", powerState)
}
}
func handleWhenServerOn(upsState UPSPowerState, idracCredentials idracCredentials) {
if upsState.inputVoltage > 0 {
glog.Infof("UPS is on AC power: %d. Nothing to do.\n", upsState.inputVoltage)
return
} else {
glog.Warningln("UPS is on Battery power")
if upsState.minutesRemaining < upsMinutesRemainingThreshold {
glog.Warningf("Minutes remaining is too low - %d Turning off server.", upsState.minutesRemaining)
// Perform a graceful shutdown of the server
performGracefulShutdown(idracCredentials)
} else {
glog.Warningf("Minutes remaining is %d. Server will not be shutdown yet.", upsState.minutesRemaining)
return
}
}
}
func handleWhenServerOff(upsState UPSPowerState, idracCredentials idracCredentials) {
if upsState.inputVoltage > 0 {
glog.Infof("UPS is on AC power: %d\n", upsState.inputVoltage)
if upsState.minutesRemaining < upsMinutesRemainingThreshold {
glog.Infof("UPS battery is still too low - %d minutes remaining. Not turning on server yet.\n", upsState.minutesRemaining)
} else {
glog.Infof("UPS is on AC power and battery has charged - %d minutes remaining. Turning on server...\n", upsState.minutesRemaining)
// Perform startup of the server
performPowerOn(idracCredentials)
}
} else {
glog.Warningln("UPS is still on battery power")
return
}
}
func tryGetLock() (*lockfile.Lockfile, error) {
lock, err := lockfile.New("/tmp/server_safe_poweroff.pid")
if err != nil {
log.Fatalf("Failed to create lock file: %v", err)
}
err = lock.TryLock()
if err != nil {
return nil, err
}
return &lock, nil
}