forked from rockyluke/drac-kvm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdrac.go
127 lines (107 loc) · 2.98 KB
/
drac.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"bytes"
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"net/http"
"strings"
"text/template"
"time"
)
// DRAC contains all of the information required
// to connect to a Dell DRAC KVM
type DRAC struct {
Host string
Username string
Password string
Version int
}
// Templates is a map of each viewer.jnlp template for
// the various Dell iDRAC versions, keyed by version number
var Templates = map[int]string{
1: ikvm169,
6: viewer6,
7: viewer7,
}
// GetVersion attempts to detect the iDRAC version by checking
// if various known libraries are available via HTTP GET requests.
// Retursn the version if found, or -1 if unknown
func (d *DRAC) GetVersion() int {
log.Print("Detecting iDRAC version...")
version := -1
transport := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
Dial: func(netw, addr string) (net.Conn, error) {
deadline := time.Now().Add(5 * time.Second)
c, err := net.DialTimeout(netw, addr, time.Second*5)
if err != nil {
return nil, err
}
c.SetDeadline(deadline)
return c, nil
},
}
client := &http.Client{
Transport: transport,
}
// Check for iDRAC7 specific libs
if response, err := client.Head("https://" + d.Host + "/software/avctKVMIOMac64.jar"); err == nil {
defer response.Body.Close()
if response.StatusCode == 200 {
return 7
}
}
// Check for iDRAC6 specific libs
if response, err := client.Head("https://" + d.Host + "/software/jpcsc.jar"); err == nil {
defer response.Body.Close()
if response.StatusCode == 200 {
return 6
}
}
// SuperMicro login, if we can post to the path, its probably supermicro
// further we will then use the Cookie SID for the jnlp file
data := fmt.Sprintf("name=%s&pwd=%s", d.Username, d.Password)
if response, err := client.Post("https://"+d.Host+"/cgi/login.cgi", "text/plain", strings.NewReader(data)); err == nil {
defer response.Body.Close()
if response.StatusCode == 200 {
for _, c := range response.Cookies() {
if "SID" == c.Name && c.Value != "" {
log.Print("Setting username/password to cookie SID")
d.Username = c.Value
d.Password = c.Value
}
}
return 1
}
}
return version
}
// Viewer returns a viewer.jnlp template filled out with the
// necessary details to connect to a particular DRAC host
func (d *DRAC) Viewer() (string, error) {
var version int
// Check we have a valid DRAC viewer template for this DRAC version
if d.Version < 0 {
version = d.GetVersion()
} else {
version = d.Version
}
if version < 0 {
return "", errors.New("unable to detect DRAC version")
}
log.Printf("Found iDRAC version %d", version)
if _, ok := Templates[version]; !ok {
msg := fmt.Sprintf("no support for DRAC v%d", version)
return "", errors.New(msg)
}
// Generate a JNLP viewer from the template
// Injecting the host/user/pass information
buff := bytes.NewBufferString("")
err := template.Must(template.New("viewer").Parse(Templates[version])).Execute(buff, d)
return buff.String(), err
}