Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java console #1

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.vscode
credentials.json
dracli
dracli
viewer.jnlp
.DS_Store
drac
34 changes: 34 additions & 0 deletions .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: v1.0
name: Drac Pipeline
agent:
machine:
type: e1-standard-2
os_image: ubuntu1804

blocks:
- name: "Vet"
task:
jobs:
- name: Test
commands:
- checkout
- make setup
- echo "make test"

- name: Lint code
commands:
- checkout
- make setup
- echo "make lint"

- name: "Build"
task:
env_vars:
- name: APP_ENV
value: prod
jobs:
- name: build
commands:
- checkout
- make setup
- make dev
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# DRACLI

[![GoDoc](https://godoc.org/github.com/adamveld12/dracli?status.svg)](http://godoc.org/github.com/adamveld12/dracli)
[![Go Walker](http://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/adamveld12/dracli)
[![Gocover](http://gocover.io/_badge/github.com/adamveld12/dracli)](http://gocover.io/github.com/adamveld12/dracli)
[![Go Report Card](https://goreportcard.com/badge/github.com/adamveld12/dracli)](https://goreportcard.com/report/github.com/adamveld12/dracli)
[![Build Status](https://semaphoreci.com/api/v1/adamveld12/dracli/branches/master/badge.svg)](https://semaphoreci.com/adamveld12/dracli)

A quick and dirty CLI/client library for the Integrated Dell Remote Access Controller v6.

## CLI Usage
Expand Down
165 changes: 105 additions & 60 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,68 +14,10 @@ import (
xj "github.com/basgys/goxml2json"
)

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)
NonMaskingInterrupt = PowerState(2)
GracefulShutdown = PowerState(3)
ColdReboot = PowerState(4)
WarmReboot = PowerState(5)
NoOverride = BootDevice(0)
PXE = BootDevice(1)
HardDrive = BootDevice(2)
BIOS = BootDevice(6)
VirtualCD = BootDevice(8)
LocalSD = BootDevice(16)
LocalCD = BootDevice(5)
)

type Attribute string
type PowerState uint8
type BootDevice uint8

type SensorType struct {
}

//Client is an http client that talks to the iDRAC
type Client struct {
client *http.Client
Username string
AuthToken string
Host string
}
Expand Down Expand Up @@ -111,16 +53,52 @@ func (c *Client) doHTTP(path, qs string, body io.Reader) (string, []*http.Cookie
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 {
Expand All @@ -134,6 +112,7 @@ func (c *Client) Query(ds ...Attribute) (string, error) {
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 {
Expand All @@ -148,10 +127,12 @@ func NewFromCredentials(path string) (*Client, error) {
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,
Expand All @@ -173,6 +154,7 @@ func NewClient(host string, skipVerify bool) (*Client, error) {
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)
Expand All @@ -190,3 +172,66 @@ func (c *Client) Login(username, password string) (string, error) {

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
4 changes: 4 additions & 0 deletions credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"os"
)

//Credential represents credentials for the credentials json
type Credential struct {
Host string
Username string
AuthToken string
}

//LoadCredentials from a credentials json file
func LoadCredentials(path string) (*Credential, error) {
fp := fmt.Sprintf("%s/credentials.json", path)
f, err := os.Open(fp)
Expand All @@ -28,6 +31,7 @@ func LoadCredentials(path string) (*Credential, error) {
return credential, nil
}

//SaveCredentials saves credentials to a json file
func SaveCredentials(path string, c Credential) error {
f, err := os.Create(fmt.Sprintf("%s/credentials.json", path))
if err != nil {
Expand Down
30 changes: 20 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (

var (
commands = map[string]func(map[string][]string) error{
"login": loginAction,
"logout": logoutAction,
"power": powerStateAction,
"query": queryAction,
"help": helpAction,
"login": loginAction,
"logout": logoutAction,
"console": consoleAction,
"power": powerStateAction,
"query": queryAction,
"help": helpAction,
}

queryHelp = []Attribute{
Expand Down Expand Up @@ -60,7 +61,7 @@ var (
)

func main() {
c, err := ToCommand(os.Args[1:]...)
c, err := toCommand(os.Args[1:]...)
if err != nil {
log.Println(err)
os.Exit(-1)
Expand Down Expand Up @@ -172,6 +173,15 @@ func queryAction(args map[string][]string) error {
return nil
}

func consoleAction(args map[string][]string) error {
c, err := NewFromCredentials(".")
if err != nil || os.IsNotExist(err) {
return errors.New("you are already logged in")
}

return c.OpenConsole()
}

func loginAction(args map[string][]string) error {
u, ok1 := args["u"]
p, ok2 := args["p"]
Expand Down Expand Up @@ -236,17 +246,17 @@ func helpAction(args map[string][]string) error {
return nil
}

type Command struct {
type command struct {
Name string
Arguments map[string][]string
}

func ToCommand(args ...string) (Command, error) {
func toCommand(args ...string) (command, error) {
if len(args) < 1 {
return Command{}, nil
return command{}, nil

}
c := Command{
c := command{
Name: args[0],
Arguments: map[string][]string{},
}
Expand Down
Loading