dracli/client.go

238 lines
6.4 KiB
Go

package main
import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
xj "github.com/basgys/goxml2json"
)
//Client is an http client that talks to the iDRAC
type Client struct {
client *http.Client
Username string
AuthToken string
Host string
}
func (c *Client) doHTTP(path, qs string, body io.Reader) (string, []*http.Cookie, error) {
method := "GET"
if strings.ContainsAny(qs, "set") {
method = "POST"
}
uri := fmt.Sprintf("https://%s/data/%s?%s", c.Host, path, qs)
req, _ := http.NewRequest(method, uri, body)
req.AddCookie(&http.Cookie{
Name: "_appwebSessionId_",
Value: c.AuthToken,
})
res, err := c.client.Do(req)
if err != nil {
return "", nil, errors.New("could not make request")
}
defer res.Body.Close()
jsonData, err := xj.Convert(res.Body)
if err != nil {
return "", nil, err
}
if res.StatusCode >= 300 || res.StatusCode < 200 {
return jsonData.String(), res.Cookies(), fmt.Errorf("got a non 200 status: %d", res.StatusCode)
}
return jsonData.String(), res.Cookies(), nil
}
//OpenConsole downloads the jnlp that opens the console
func (c *Client) OpenConsole() error {
//https://192.168.0.228/viewer.jnlp(192.168.0.228@0@root@1548390931405)
uri := fmt.Sprintf("https://%s/viewer.jnlp(%s@0@%s@%d)", c.Host, c.Host, c.Username, time.Now().Unix())
req, _ := http.NewRequest("GET", uri, nil)
req.AddCookie(&http.Cookie{
Name: "_appwebSessionId_",
Value: c.AuthToken,
})
res, err := c.client.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return errors.New("bad status")
}
f, err := os.Create("./viewer.jnlp")
if err != nil {
return errors.New("could not download")
}
defer f.Close()
if _, err := io.Copy(f, res.Body); err != nil {
return err
}
return nil
}
//SetPowerState changes the power state of the server (ie turn off or on)
func (c *Client) SetPowerState(ps PowerState) (string, error) {
res, _, err := c.doHTTP("", fmt.Sprintf("set=pwState:%d", ps), nil)
return res, err
}
//SetBootOverride changes the boot override settings
func (c *Client) SetBootOverride(bo BootDevice, bootOnce bool) (string, error) {
res, _, err := c.doHTTP("", fmt.Sprintf("set=vmBootOnce:%v,firstBootDevice:%d", bootOnce, bo), nil)
return res, err
}
//Query queries attributes and returns them to json
func (c *Client) Query(ds ...Attribute) (string, error) {
bufs := bytes.NewBufferString("")
for idx, attr := range ds {
bufs.WriteString(string(attr))
if idx < len(ds)-1 {
bufs.WriteString(",")
}
}
res, _, err := c.doHTTP("", fmt.Sprintf("get=%s", bufs.String()), nil)
return res, err
}
//NewFromCredentials creates a new client from a credentials file at the specified path
func NewFromCredentials(path string) (*Client, error) {
credential, err := LoadCredentials(path)
if err != nil {
if os.IsNotExist(err) {
return nil, errors.New("You should log in first")
}
return nil, err
}
c, err := NewClient(credential.Host, true)
if err != nil {
return nil, err
}
c.AuthToken = credential.AuthToken
c.Username = credential.Username
return c, nil
}
//NewClient creates a new Client
func NewClient(host string, skipVerify bool) (*Client, error) {
c := &http.Client{
Timeout: time.Second * 5,
Transport: &http.Transport{
IdleConnTimeout: time.Second,
TLSHandshakeTimeout: time.Second * 5,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: skipVerify,
},
},
}
client := &Client{client: c, Host: host}
// err := client.Login(host, username, password)
// if err != nil {
// return nil, err
// }
return client, nil
}
//Login sends a login http request to the iDRAC
func (c *Client) Login(username, password string) (string, error) {
body := bytes.NewBufferString(fmt.Sprintf("user=%s&password=%s", username, password))
_, cookies, err := c.doHTTP("login", "", body)
if err != nil {
return "", err
}
for _, cookie := range cookies {
if cookie.Name == "_appwebSessionId_" {
c.AuthToken = cookie.Value
return cookie.Value, nil
}
}
return "", errors.New("could not find auth token in cookie")
}
var (
PowerStatus = Attribute("pwState")
SystemDescription = Attribute("sysDesc")
SystemRevision = Attribute("sysRev")
HostName = Attribute("hostName")
OSName = Attribute("osName")
OSVersion = Attribute("osVersion")
ServiceTag = Attribute("svcTag")
ExpServiceCode = Attribute("expSvcCode")
BiosVersion = Attribute("biosVer")
FirmwareVersion = Attribute("fwVersion")
LCCFirmwareVersion = Attribute("LCCfwVersion")
IPV4Enabled = Attribute("v4Enabled")
IPV4Address = Attribute("v4IPAddr")
IPV6Enabled = Attribute("v6Enabled")
IPV6LinkLocal = Attribute("v6LinkLocal")
IPV6Address = Attribute("v6Addr")
IPV6SiteLocal = Attribute("v6SiteLocal")
MacAddress = Attribute("macAddr")
Batteries = Attribute("batteries")
FanRedundancy = Attribute("fansRedundancy")
Fans = Attribute("fans")
Intrusion = Attribute("intrusion")
PowerSupplyRedundancy = Attribute("psRedundancy")
PowerSupplies = Attribute("powerSupplies")
RMVRedundancy = Attribute("rmvsRedundancy")
RemovableStorage = Attribute("removableStorage")
Temperatures = Attribute("temperatures")
Voltages = Attribute("voltages")
KVMEnabled = Attribute("kvmEnabled")
PowerBudgetData = Attribute("budgetpowerdata")
EventLog = Attribute("eventLogEntries")
BootOnce = Attribute("vmBootOnce")
FirstBootDevice = Attribute("firstBootDevice")
VFKLicense = Attribute("vfkLicense")
User = Attribute("user")
IDRACLog = Attribute("racLogEntries")
PowerOff = PowerState(0)
PowerOn = PowerState(1)
ColdReboot = PowerState(2)
WarmReboot = PowerState(3)
NonMaskingInterrupt = PowerState(4)
GracefulShutdown = PowerState(5)
NoOverride = BootDevice(0)
PXE = BootDevice(1)
HardDrive = BootDevice(2)
BIOS = BootDevice(6)
VirtualCD = BootDevice(8)
LocalSD = BootDevice(16)
LocalCD = BootDevice(5)
)
//Attribute is an attribute that can be queried
type Attribute string
//PowerState represents a powerstate option
type PowerState uint8
//BootDevice represents a bootdevice option
type BootDevice uint8