mirror of https://github.com/adamveld12/dracli
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
5.0 KiB
277 lines
5.0 KiB
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
commands = map[string]func(map[string][]string) error{
|
|
"login": loginAction,
|
|
"logout": logoutAction,
|
|
"power": powerStateAction,
|
|
"query": queryAction,
|
|
"help": helpAction,
|
|
}
|
|
|
|
queryHelp = []Attribute{
|
|
PowerStatus,
|
|
SystemDescription,
|
|
SystemRevision,
|
|
HostName,
|
|
OSName,
|
|
OSVersion,
|
|
ServiceTag,
|
|
ExpServiceCode,
|
|
BiosVersion,
|
|
FirmwareVersion,
|
|
LCCFirmwareVersion,
|
|
IPV4Enabled,
|
|
IPV4Address,
|
|
IPV6Enabled,
|
|
IPV6LinkLocal,
|
|
IPV6Address,
|
|
IPV6SiteLocal,
|
|
MacAddress,
|
|
Batteries,
|
|
FanRedundancy,
|
|
Fans,
|
|
Intrusion,
|
|
PowerSupplyRedundancy,
|
|
PowerSupplies,
|
|
RMVRedundancy,
|
|
RemovableStorage,
|
|
Temperatures,
|
|
Voltages,
|
|
KVMEnabled,
|
|
PowerBudgetData,
|
|
EventLog,
|
|
BootOnce,
|
|
FirstBootDevice,
|
|
VFKLicense,
|
|
User,
|
|
IDRACLog,
|
|
}
|
|
)
|
|
|
|
func main() {
|
|
c, err := ToCommand(os.Args[1:]...)
|
|
if err != nil {
|
|
log.Println(err)
|
|
os.Exit(-1)
|
|
}
|
|
|
|
action, ok := commands[c.Name]
|
|
if !ok {
|
|
fmt.Printf("The command \"%s\" was not found.\n", c.Name)
|
|
os.Exit(-1)
|
|
}
|
|
|
|
if err := action(c.Arguments); err != nil {
|
|
fmt.Printf("The command exited with an error:\n%v\n", err)
|
|
os.Exit(-1)
|
|
}
|
|
}
|
|
|
|
func powerStateAction(args map[string][]string) error {
|
|
c, err := NewFromCredentials(".")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rawPs, ok := args[""]
|
|
if !ok || len(rawPs) == 0 {
|
|
return errors.New("specify a power state (on|off|cold_reboot|warm_reboot)")
|
|
}
|
|
|
|
var ps PowerState
|
|
switch rawPs[0] {
|
|
case "on":
|
|
ps = PowerOn
|
|
case "off":
|
|
ps = PowerOff
|
|
case "cold_reboot":
|
|
ps = ColdReboot
|
|
case "warm_reboot":
|
|
ps = WarmReboot
|
|
case "nmi":
|
|
ps = NonMaskingInterrupt
|
|
case "graceful_shutdown":
|
|
ps = GracefulShutdown
|
|
default:
|
|
return errors.New("specify a power state (on|off|cold_reboot|warm_reboot)")
|
|
}
|
|
|
|
res, err := c.SetPowerState(ps)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("%s\n", res)
|
|
|
|
return nil
|
|
}
|
|
|
|
func queryAction(args map[string][]string) error {
|
|
c, err := NewFromCredentials(".")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
queryParams, ok := args[""]
|
|
if !ok {
|
|
return errors.New("you should pass query parameters")
|
|
}
|
|
|
|
qps := []Attribute{}
|
|
for _, qp := range queryParams {
|
|
qps = append(qps, Attribute(qp))
|
|
}
|
|
|
|
output, err := c.Query(qps...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("%s", output)
|
|
|
|
watch, watchOk := args["watch"]
|
|
if watchOk && len(watch) > 0 {
|
|
duration, err := time.ParseDuration(watch[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-time.After(duration):
|
|
output, err := c.Query(qps...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("%s", output)
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
notifChan := make(chan os.Signal)
|
|
signal.Notify(notifChan, os.Interrupt)
|
|
<-notifChan
|
|
cancel()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func loginAction(args map[string][]string) error {
|
|
u, ok1 := args["u"]
|
|
p, ok2 := args["p"]
|
|
h, ok3 := args["h"]
|
|
|
|
if !ok1 || !ok2 || !ok3 {
|
|
return errors.New("username (-u), password (-p), and a host (-h) must be defined")
|
|
}
|
|
|
|
username, password, host := u[0], p[0], h[0]
|
|
|
|
credential, err := LoadCredentials(".")
|
|
if (err == nil || os.IsExist(err)) && credential.Host == host {
|
|
return errors.New("you are already logged in")
|
|
}
|
|
|
|
fmt.Printf("logging in to %s:%s@%s\n", username, password, host)
|
|
client, err := NewClient(host, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
authToken, err := client.Login(username, password)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := SaveCredentials(".", Credential{
|
|
Host: host,
|
|
AuthToken: authToken,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func logoutAction(args map[string][]string) error {
|
|
_, err := LoadCredentials(".")
|
|
if err == nil && os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
|
|
if err := os.Remove("./credentials.json"); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func helpAction(args map[string][]string) error {
|
|
fmt.Println("login -u [username] -p [password] -h [host]: logs you in")
|
|
fmt.Println("logout: logs you out")
|
|
fmt.Println("power [on|off|nmi|graceful_shutdown|cold_reboot|warm_reboot]: manage power state of the server")
|
|
fmt.Printf("query [-watch 1[s|m|h]] <attribute>,<attribute2>...: gets info about the server's various sensors and attributes\nPossible attributes:")
|
|
for idx, q := range queryHelp {
|
|
if idx%10 == 0 {
|
|
fmt.Println()
|
|
}
|
|
fmt.Printf("%s ", q)
|
|
}
|
|
fmt.Println()
|
|
return nil
|
|
}
|
|
|
|
type Command struct {
|
|
Name string
|
|
Arguments map[string][]string
|
|
}
|
|
|
|
func ToCommand(args ...string) (Command, error) {
|
|
if len(args) < 1 {
|
|
return Command{}, nil
|
|
|
|
}
|
|
c := Command{
|
|
Name: args[0],
|
|
Arguments: map[string][]string{},
|
|
}
|
|
|
|
for i := 1; i < len(args); i++ {
|
|
arg := args[i]
|
|
if arg[0] == '-' {
|
|
argumentV := "true"
|
|
if len(args) > i+1 && arg[1:] != "once" {
|
|
argumentV = args[i+1]
|
|
i++
|
|
}
|
|
|
|
c.Arguments[arg[1:]] = []string{argumentV}
|
|
} else {
|
|
v, ok := c.Arguments[""]
|
|
if ok {
|
|
v = append(v, arg)
|
|
c.Arguments[""] = v
|
|
} else {
|
|
c.Arguments[""] = []string{arg}
|
|
}
|
|
}
|
|
}
|
|
|
|
return c, nil
|
|
}
|