Skip to content

Commit 4bb049a

Browse files
committed
Merge branch 'FEAT/web-dashboard' of https://github.com/bisohns/saido into FEAT/web-dashboard
2 parents f95b218 + 7317336 commit 4bb049a

20 files changed

+174
-82
lines changed

client/controller.go

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,61 @@ func (hosts *HostsController) setReadOnlyHost(hostlist config.HostList) {
6969
hosts.ReadOnlyHosts = hostlist
7070
}
7171

72-
func (hosts *HostsController) sendMetric(host config.Host, client *Client) {
72+
func (hosts *HostsController) handleError(err error, metric string, host config.Host, client *Client) {
73+
var errorContent string
74+
if !strings.Contains(fmt.Sprintf("%s", err), "127") {
75+
errorContent = fmt.Sprintf("Could not retrieve metric %s from driver %s with error %s", metric, host.Address, err)
76+
} else {
77+
errorContent = fmt.Sprintf("Command %s not found on driver %s", metric, host.Address)
78+
}
79+
log.Debug(errorContent)
80+
//FIXME: what kind of errors do we especially want to reset driver for
81+
if _, ok := err.(*driver.SSHConnectError); ok {
82+
hosts.resetDriver(host)
83+
}
84+
message := &SendMessage{
85+
Message: ErrorMessage{
86+
Error: errorContent,
87+
Host: host.Address,
88+
Name: metric,
89+
},
90+
Error: true,
91+
}
92+
client.Send <- message
93+
}
94+
95+
func (hosts *HostsController) sendMetric(host config.Host, metrics map[string]string, client *Client) {
96+
var (
97+
err error
98+
data []byte
99+
initializedMetric inspector.Inspector
100+
platformDetails driver.SystemDetails
101+
)
73102
if hosts.getDriver(host.Address) == nil {
74103
hosts.resetDriver(host)
75104
}
76-
for metric, custom := range hosts.Info.Metrics {
105+
for metric, custom := range metrics {
77106
inspectorDriver := hosts.getDriver(host.Address)
78-
initializedMetric, err := inspector.Init(metric, inspectorDriver, custom)
107+
initializedMetric, err = inspector.Init(metric, inspectorDriver, custom)
108+
if err != nil {
109+
log.Error(err)
110+
hosts.handleError(err, metric, host, client)
111+
continue
112+
}
113+
platformDetails, err = (*inspectorDriver).GetDetails()
79114
if err != nil {
80115
log.Error(err)
116+
hosts.handleError(err, metric, host, client)
117+
continue
81118
}
82-
data, err := initializedMetric.Execute()
119+
data, err = initializedMetric.Execute()
83120
if err == nil {
84121
var unmarsh interface{}
85122
json.Unmarshal(data, &unmarsh)
86123
message := &SendMessage{
87124
Message: Message{
88125
Host: host.Address,
89-
Platform: (*inspectorDriver).GetDetails().Name,
126+
Platform: platformDetails.Name,
90127
Name: metric,
91128
Data: unmarsh,
92129
},
@@ -96,27 +133,7 @@ func (hosts *HostsController) sendMetric(host config.Host, client *Client) {
96133
client.Send <- message
97134
}
98135
} else {
99-
// check for error 127 which means command was not found
100-
var errorContent string
101-
if !strings.Contains(fmt.Sprintf("%s", err), "127") {
102-
errorContent = fmt.Sprintf("Could not retrieve metric %s from driver %s with error %s", metric, host.Address, err)
103-
} else {
104-
errorContent = fmt.Sprintf("Command %s not found on driver %s", metric, host.Address)
105-
}
106-
log.Debug(errorContent)
107-
//FIXME: what kind of errors do we especially want to reset driver for
108-
if _, ok := err.(*driver.SSHConnectError); ok {
109-
hosts.resetDriver(host)
110-
}
111-
message := &SendMessage{
112-
Message: ErrorMessage{
113-
Error: errorContent,
114-
Host: host.Address,
115-
Name: metric,
116-
},
117-
Error: true,
118-
}
119-
client.Send <- message
136+
hosts.handleError(err, metric, host, client)
120137
}
121138
}
122139
}
@@ -128,7 +145,10 @@ func (hosts *HostsController) Poll(client *Client) {
128145
return
129146
}
130147
if config.Contains(hosts.ReadOnlyHosts, host) {
131-
go hosts.sendMetric(host, client)
148+
// TODO: Decide if we want an override or a merge
149+
// For now we use a merge
150+
metrics := config.MergeMetrics(hosts.Info.Metrics, host.Metrics)
151+
go hosts.sendMetric(host, metrics, client)
132152
}
133153
}
134154
log.Debugf("Delaying for %d seconds", hosts.Info.PollInterval)
@@ -175,11 +195,18 @@ func (hosts *HostsController) ServeHTTP(w http.ResponseWriter, req *http.Request
175195
// NewHostsController : initialze host controller with config file
176196
func NewHostsController(cfg *config.Config) *HostsController {
177197
dashboardInfo := config.GetDashboardInfoConfig(cfg)
178-
for metric, _ := range dashboardInfo.Metrics {
198+
for metric := range dashboardInfo.Metrics {
179199
if !inspector.Valid(metric) {
180200
log.Fatalf("%s is not a valid metric", metric)
181201
}
182202
}
203+
for _, host := range dashboardInfo.Hosts {
204+
for metric := range host.Metrics {
205+
if !inspector.Valid(metric) {
206+
log.Fatalf("%s is not a valid metric", metric)
207+
}
208+
}
209+
}
183210

184211
hosts := &HostsController{
185212
Info: dashboardInfo,

config.example.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ hosts:
1616
username: root
1717
password: somethingSecret
1818
port: 2222
19+
metrics:
20+
process:
1921
"192.0.1.4":
2022
# local driver
2123
connection:

config/config.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import (
1212
"gopkg.in/yaml.v2"
1313
)
1414

15+
type HostList = []string
16+
type Metrics = map[string]string
17+
1518
type DashboardInfo struct {
1619
Hosts []Host
17-
Metrics map[string]string
20+
Metrics Metrics
1821
Title string
1922
PollInterval int
2023
}
2124

22-
type HostList = []string
23-
2425
func Contains(hostList HostList, host Host) bool {
2526
for _, compare := range hostList {
2627
if host.Address == compare {
@@ -30,6 +31,17 @@ func Contains(hostList HostList, host Host) bool {
3031
return false
3132
}
3233

34+
func MergeMetrics(a, b Metrics) (metrics Metrics) {
35+
metrics = Metrics{}
36+
inputs := [2]Metrics{a, b}
37+
for _, metric := range inputs {
38+
for k, v := range metric {
39+
metrics[k] = v
40+
}
41+
}
42+
return
43+
}
44+
3345
// GetAllHostAddresses : returns list of all hosts in the dashboard
3446
func (dashboardInfo *DashboardInfo) GetAllHostAddresses() (addresses HostList) {
3547
addresses = []string{}
@@ -53,6 +65,8 @@ type Host struct {
5365
Address string
5466
Alias string
5567
Connection *Connection
68+
// Metrics : extend global metrics with single metrics
69+
Metrics Metrics
5670
}
5771

5872
type Config struct {
@@ -75,22 +89,25 @@ func LoadConfig(configPath string) *Config {
7589
return config
7690
}
7791

92+
func coerceMetrics(rawMetrics map[interface{}]interface{}) map[string]string {
93+
metrics := make(map[string]string)
94+
for metric, customCommand := range rawMetrics {
95+
metric := fmt.Sprintf("%v", metric)
96+
metrics[metric] = fmt.Sprintf("%v", customCommand)
97+
}
98+
return metrics
99+
}
100+
78101
func GetDashboardInfoConfig(config *Config) *DashboardInfo {
79102
dashboardInfo := &DashboardInfo{
80103
Title: "Saido",
81104
}
82105
if config.Title != "" {
83106
dashboardInfo.Title = config.Title
84107
}
85-
metrics := make(map[string]string)
86108

87109
dashboardInfo.Hosts = parseConfig("root", "", config.Hosts, &Connection{})
88-
for metric, customCommand := range config.Metrics {
89-
metric := fmt.Sprintf("%v", metric)
90-
metrics[metric] = fmt.Sprintf("%v", customCommand)
91-
92-
}
93-
dashboardInfo.Metrics = metrics
110+
dashboardInfo.Metrics = coerceMetrics(config.Metrics)
94111
for _, host := range dashboardInfo.Hosts {
95112
log.Debugf("%s: %v", host.Address, host.Connection)
96113
}
@@ -116,12 +133,12 @@ func parseConnection(conn map[interface{}]interface{}) *Connection {
116133
func parseConfig(name string, host string, group map[interface{}]interface{}, currentConnection *Connection) []Host {
117134
currentConn := currentConnection
118135
allHosts := []Host{}
119-
log.Infof("Loading config for %s and host: %s with Connection: %+v", name, host, currentConn)
136+
log.Debugf("Loading config for %s and host: %s with Connection: %+v", name, host, currentConn)
120137
isParent := false // Set to true for groups that contain just children data i.e children
121138
if conn, ok := group["connection"]; ok {
122139
v, ok := conn.(map[interface{}]interface{})
123140
if !ok {
124-
log.Errorf("Failed to parse connection for %s", name)
141+
log.Fatalf("Failed to parse connection for %s", name)
125142
}
126143

127144
currentConn = parseConnection(v)
@@ -147,13 +164,22 @@ func parseConfig(name string, host string, group map[interface{}]interface{}, cu
147164

148165
if !isParent {
149166
currentConn.Host = host
167+
150168
newHost := Host{
151169
Address: host,
152170
Connection: currentConn,
153171
}
154172
if alias, ok := group["alias"]; ok {
155173
newHost.Alias = alias.(string)
156174
}
175+
if metrics, ok := group["metrics"]; ok {
176+
rawMetrics, ok := metrics.(map[interface{}]interface{})
177+
if !ok {
178+
log.Fatalf("Failed to parse metrics for %s", name)
179+
}
180+
individualMetrics := coerceMetrics(rawMetrics)
181+
newHost.Metrics = individualMetrics
182+
}
157183

158184
allHosts = append(allHosts, newHost)
159185
}

driver/driver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type Driver interface {
2626
ReadFile(path string) (string, error)
2727
RunCommand(command string) (string, error)
2828
// shows the driver details, not sure if we should be showing OS name
29-
GetDetails() SystemDetails
29+
GetDetails() (SystemDetails, error)
3030
}
3131

3232
func ToDriver(conn config.Connection) Driver {

driver/local.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ func (d *Local) RunCommand(command string) (string, error) {
3636
var cmd *exec.Cmd
3737
log.Debugf("Running command `%s` ", command)
3838
if d.Info == nil {
39-
d.GetDetails()
39+
_, err := d.GetDetails()
40+
if err != nil {
41+
return ``, err
42+
}
4043
}
4144
if d.Info.IsLinux || d.Info.IsDarwin {
4245
cmd = exec.Command("bash", "-c", command)
@@ -58,7 +61,7 @@ func (d *Local) RunCommand(command string) (string, error) {
5861
return string(out), nil
5962
}
6063

61-
func (d *Local) GetDetails() SystemDetails {
64+
func (d *Local) GetDetails() (SystemDetails, error) {
6265
if d.Info == nil {
6366
details := &SystemDetails{}
6467
details.Name = strings.Title(runtime.GOOS)
@@ -73,5 +76,5 @@ func (d *Local) GetDetails() SystemDetails {
7376
details.Extra = runtime.GOARCH
7477
d.Info = details
7578
}
76-
return *d.Info
79+
return *d.Info, nil
7780
}

driver/local_unix_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build !windows
12
// +build !windows
23

34
package driver
@@ -17,8 +18,8 @@ func TestUnixLocalRunCommand(t *testing.T) {
1718

1819
func TestUnixLocalSystemDetails(t *testing.T) {
1920
d := Local{}
20-
details := d.GetDetails()
21-
if !(details.IsLinux || details.IsDarwin) {
21+
details, err := d.GetDetails()
22+
if err != nil || !(details.IsLinux || details.IsDarwin) {
2223
t.Errorf("Expected Darwin or Linux on unix test, got %s", details.Name)
2324
}
2425
}

driver/local_windows_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ func TestWindowsRunCommand(t *testing.T) {
1515

1616
func TestWindowsLocalSystemDetails(t *testing.T) {
1717
d := Local{}
18-
details := d.GetDetails()
19-
if !details.IsWindows {
18+
details, err := d.GetDetails()
19+
if err != nil || !details.IsWindows {
2020
t.Errorf("Expected windows got %s", details.Name)
2121
}
2222
}

driver/ssh.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (d *SSH) RunCommand(command string) (string, error) {
129129
return string(out), nil
130130
}
131131

132-
func (d *SSH) GetDetails() SystemDetails {
132+
func (d *SSH) GetDetails() (SystemDetails, error) {
133133
if d.Info == nil {
134134
// TODO: Check for goph specific errors
135135
// within RunCommand and only return errors that are not
@@ -145,7 +145,8 @@ func (d *SSH) GetDetails() SystemDetails {
145145
}
146146
} else {
147147
//FIXME: Fix issue with establishing connection on SSH
148-
panic(fmt.Sprintf("Could not find platform details for %s: %s", d.Host, err))
148+
log.Errorf("Could not find platform details for %s: %s", d.Host, err)
149+
return SystemDetails{}, err
149150
}
150151
}
151152
details := &SystemDetails{}
@@ -160,5 +161,5 @@ func (d *SSH) GetDetails() SystemDetails {
160161
}
161162
d.Info = details
162163
}
163-
return *d.Info
164+
return *d.Info, nil
164165
}

driver/ssh_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ func TestSSHSystemDetails(t *testing.T) {
5858
return
5959
}
6060
d := NewSSHForTest()
61-
details := d.GetDetails()
62-
if !details.IsLinux {
61+
details, err := d.GetDetails()
62+
if err != nil || !details.IsLinux {
6363
t.Errorf("Expected linux server for ssh test got %#v", details)
6464
}
6565
}

driver/web.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (d *Web) RunCommand(command string) (string, error) {
6262
return ``, errors.New("Cannot read file on web driver")
6363
}
6464

65-
func (d *Web) GetDetails() SystemDetails {
65+
func (d *Web) GetDetails() (SystemDetails, error) {
6666
if d.Info == nil {
6767
details := &SystemDetails{
6868
Name: "web",
@@ -71,5 +71,5 @@ func (d *Web) GetDetails() SystemDetails {
7171
}
7272
d.Info = details
7373
}
74-
return *d.Info
74+
return *d.Info, nil
7575
}

driver/web_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ func TestWebRunCommand(t *testing.T) {
2727

2828
func TestWebSystemDetails(t *testing.T) {
2929
d := NewWebForTest()
30-
details := d.GetDetails()
31-
if !details.IsWeb {
30+
details, err := d.GetDetails()
31+
if err != nil || !details.IsWeb {
3232
t.Errorf("Expected web driver for web test got %s", details.Name)
3333
}
3434
}

0 commit comments

Comments
 (0)