Skip to content
This repository was archived by the owner on Apr 10, 2020. It is now read-only.
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
4,691 changes: 211 additions & 4,480 deletions bindata.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ func setupOptions() (sweet.SweetOptions, error) {
if ok {
Opts.DefaultMethod = defaultMethod
}
// Add config var for unlocking gimped hp/comware switches
cmwPass, ok := section["comware-unlock-pass"]
if ok {
Opts.CmwPass = cmwPass
}

} else { // device-specific config
device := sweet.DeviceConfig{Hostname: name, Method: section["method"], Config: section}
Expand Down
71 changes: 71 additions & 0 deletions comware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package sweet

import (
"fmt"
"time"
)
// HP/Comware
type Cmw struct {
}

func newCmwCollector() Collector {
return Cmw{}
}

func (collector Cmw) Collect(device DeviceConfig) (map[string]string, error) {
result := make(map[string]string)

c, err := newSSHCollector(device)
if err != nil {
return result, fmt.Errorf("Error connecting to %s: %s", device.Hostname, err.Error())
}
if err := expect("assword:", c.Receive); err != nil {
return result, fmt.Errorf("Missing password prompt: %s", err.Error())
}
c.Send <- device.Config["pass"] + "\n"
multi := []string{"#", ">", "assword:", "[Y/N]:"}
m, err := expectMulti(multi, c.Receive)
if err != nil {
return result, fmt.Errorf("Invalid response to password: %s", err.Error())
}
if m == "assword:" {
return result, fmt.Errorf("Bad username or password.")
} else if m == ">" {
// Check for comware unlock pass - unlock if present
if len(device.Config["comware-unlock-pass"]) > 0 {
c.Send <- "xtd-cli-mode\n"
if err := expect("Y/N]:", c.Receive); err != nil {
return result, fmt.Errorf("No Y/N prompt")
}
c.Send <- "y\n"
if err := expect("assword:", c.Receive); err !=nil{
return result, fmt.Errorf("Missing password prompt for Extented CLI")
}
c.Send <- device.Config["comware-unlock-pass"] + "\n"
if err := expect(">", c.Receive); err !=nil{
return result, fmt.Errorf("Problem with CLI unlock password")
}
}
// Turn off terminal paging
c.Send <- "screen-length disable\n"
if err := expect(">", c.Receive); err !=nil {
return result, fmt.Errorf("Unable to disable pager")
}
c.Send <- "system-view\n"
if err := expect("]", c.Receive); err !=nil{
return result, fmt.Errorf("Unable to enter system-view")
}
// Dump config
c.Send <- "display current-configuration\n"
result["config"], err = expectSaveTimeout("]", c.Receive, device.CommandTimeout)
if err != nil {
return result, fmt.Errorf("Command 'display current-configuration' failed: %s", err.Error())
}

}

c.Send <- "quit\n"
time.Sleep(1 * time.Second)
c.Send <- "quit\n"
return result, nil
}
43 changes: 43 additions & 0 deletions comware_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sweet

import (
"os"
"strings"
"testing"
"time"
)

func TestCmwGood(t *testing.T) {
d := new(DeviceConfig)
d.Config = make(map[string]string)
d.Method = "cmw"
d.Timeout = 10 * time.Second

if os.Getenv("SWEET_COMWARE_HOST") == "" {
t.Error("Test requries SWEET_COMWARE_HOST environment variable")
return
}
if os.Getenv("SWEET_COMWARE_USER") == "" {
t.Error("Test requries SWEET_COMWARE_USER environment variable")
return
}
if os.Getenv("SWEET_COMWARE_PASS") == "" {
t.Error("Test requries SWEET_COMWARE_PASS environment variable")
return
}

d.Hostname = os.Getenv("SWEET_COMWARE_HOST")
d.Config["user"] = os.Getenv("SWEET_COMWARE_USER")
d.Config["pass"] = os.Getenv("SWEET_COMWARE_PASS")

d.Target = d.Hostname

s := CollectCmw(*d)
if !strings.Contains(s["config"], "aaa authorization commands") {
t.Errorf("Config missing aaa line")
}
if !strings.Contains(s["config"], "ntp access-group peer") {
t.Errorf("Config missing ntp line close to end")
}

}
65 changes: 65 additions & 0 deletions csb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package sweet

import (
"fmt"
"strings"
)
// Cisco SBS (Built for Cisco SG300)
type Csb struct {
}

func newCsbCollector() Collector {
return Csb{}
}

func (collector Csb) Collect(device DeviceConfig) (map[string]string, error) {
result := make(map[string]string)

c, err := newSSHCollector(device)
if err != nil {
return result, fmt.Errorf("Error connecting to %s: %s", device.Hostname, err.Error())
}
if err := expect("ser Name:", c.Receive); err != nil {
return result, fmt.Errorf("Missing Username prompt: %s", err.Error())
}
c.Send <- device.Config["user"] + "\n"
if err := expect("assword:", c.Receive); err != nil {
return result, fmt.Errorf("Missing password prompt: %s", err.Error())
}
c.Send <- device.Config["pass"] + "\n"
multi := []string{"#", ">", "assword:"}
m, err := expectMulti(multi, c.Receive)
if err != nil {
return result, fmt.Errorf("Invalid response to password: %s", err.Error())
}
if m == "assword:" {
return result, fmt.Errorf("Bad username or password.")
}

// Turn off terminal paging

c.Send <- "terminal datadump\n"
if err := expect("#", c.Receive); err != nil {
return result, fmt.Errorf("Command 'terminal datadump' failed: %s", err.Error())
}
// Dump config
c.Send <- "show running-config\n"
result["config"], err = expectSaveTimeout("#", c.Receive, device.CommandTimeout)
if err != nil {
return result, fmt.Errorf("Command 'show running-config' failed: %s", err.Error())
}
// Dump Version
c.Send <- "show version\n"
result["version"], err = expectSaveTimeout("#", c.Receive, device.CommandTimeout)
if err != nil {
return result, fmt.Errorf("Command 'show version' failed: %s", err.Error())
}

// cleanup config results
result["config"] = strings.TrimSpace(strings.TrimPrefix(result["config"], "show running-config"))
result["config"] = strings.TrimSpace(strings.TrimPrefix(result["config"], "config-file-header"))

c.Send <- "exit\n"

return result, nil
}
43 changes: 43 additions & 0 deletions csb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sweet

import (
"os"
"strings"
"testing"
"time"
)

func TestCsbGood(t *testing.T) {
d := new(DeviceConfig)
d.Config = make(map[string]string)
d.Method = "cmw"
d.Timeout = 10 * time.Second

if os.Getenv("SWEET_CSB_HOST") == "" {
t.Error("Test requries SWEET_CSB_HOST environment variable")
return
}
if os.Getenv("SWEET_CSB_USER") == "" {
t.Error("Test requries SWEET_CSB_USER environment variable")
return
}
if os.Getenv("SWEET_CSB_PASS") == "" {
t.Error("Test requries SWEET_CSB_PASS environment variable")
return
}

d.Hostname = os.Getenv("SWEET_CSB_HOST")
d.Config["user"] = os.Getenv("SWEET_CSB_USER")
d.Config["pass"] = os.Getenv("SWEET_CSB_PASS")

d.Target = d.Hostname

s := CollectCsb(*d)
if !strings.Contains(s["config"], "aaa authorization commands") {
t.Errorf("Config missing aaa line")
}
if !strings.Contains(s["config"], "ntp access-group peer") {
t.Errorf("Config missing ntp line close to end")
}

}
58 changes: 58 additions & 0 deletions pfsense.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package sweet

import (
"fmt"
"regexp"
"strings"
"time"
)
// pfSense
type Pfs struct {
}

func newPfsCollector() Collector {
return Pfs{}
}

func (collector Pfs) Collect(device DeviceConfig) (map[string]string, error) {
result := make(map[string]string)
tail := regexp.MustCompile("(?m)[\r\n]+^.*-RELEASE.*$")
c, err := newSSHCollector(device)
if err != nil {
return result, fmt.Errorf("Error connecting to %s: %s", device.Hostname, err.Error())
}else {
}
if err := expect("Password", c.Receive); err != nil {
return result, fmt.Errorf("Missing password prompt: %s", err.Error())
}else {
}
c.Send <- device.Config["pass"] + "\n"
multi := []string{"option:", "root:", "Password", }
m, err := expectMulti(multi, c.Receive)
if err != nil {
return result, fmt.Errorf("Invalid response to password: %s", err.Error())
}
if m == "Password" {
return result, fmt.Errorf("Bad username or password.")
}else if m == "option:" {
c.Send <- "8\n"
if err := expect("-RELEASE", c.Receive); err !=nil {
return result, fmt.Errorf("Unable to activate Shell")
}
// Dump config
var conf string
conf = "cat /conf/config.xml"
c.Send <- conf + "\n"
result["config"], err = expectSaveTimeout("-RELEASE", c.Receive, device.CommandTimeout)
if err != nil {
return result, fmt.Errorf("Unable to dump config.xml", err.Error())
}

}
result["config"] = strings.TrimSpace(strings.TrimPrefix(result["config"], "cat /conf/config.xml\r"))
result["config"] = tail.ReplaceAllString(result["config"], "")
c.Send <- "exit\n"
time.Sleep(1 * time.Second)
c.Send <- "0\n"
return result, nil
}
43 changes: 43 additions & 0 deletions pfsense_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package sweet

import (
"os"
"strings"
"testing"
"time"
)

func TestPfsGood(t *testing.T) {
d := new(DeviceConfig)
d.Config = make(map[string]string)
d.Method = "pfsense"
d.Timeout = 10 * time.Second

if os.Getenv("SWEET_PFSENSE_HOST") == "" {
t.Error("Test requries SWEET_PFSENSE_HOST environment variable")
return
}
if os.Getenv("SWEET_PFSENSE_USER") == "" {
t.Error("Test requries SWEET_PFSENSE_USER environment variable")
return
}
if os.Getenv("SWEET_PFSENSE_PASS") == "" {
t.Error("Test requries SWEET_PFSENSE_PASS environment variable")
return
}

d.Hostname = os.Getenv("SWEET_PFSENSE_HOST")
d.Config["user"] = os.Getenv("SWEET_PFSENSE_USER")
d.Config["pass"] = os.Getenv("SWEET_PFSENSE_PASS")

d.Target = d.Hostname

s := CollectPfs(*d)
if !strings.Contains(s["config"], "aaa authorization commands") {
t.Errorf("Config missing aaa line")
}
if !strings.Contains(s["config"], "ntp access-group peer") {
t.Errorf("Config missing ntp line close to end")
}

}
14 changes: 9 additions & 5 deletions reporting.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ func runReporter(Opts *SweetOptions) error {
Opts.LogInfo("Starting reporter.")
changeReport := ""
changeDiffs := ""

var send int
send = 0
// print changes to log
for _, device := range Opts.Devices {
stat := Opts.Status.Get(device.Hostname)
if stat.State == StateSuccess {
if len(stat.Diffs) < 1 {
changeReport += fmt.Sprintf("%s: no changes\n", device.Hostname)
} else {
send += 1
changeReport += fmt.Sprintf("%s: changes!\n", device.Hostname)
for name, d := range stat.Diffs {
if d.NewFile {
Expand All @@ -45,10 +47,12 @@ func runReporter(Opts *SweetOptions) error {
return fmt.Errorf("Error getting my hostname: %s", err.Error())
}
emailSubject := fmt.Sprintf("Change notification from Sweet on %s", hostname)
err = sendEmail(Opts, emailSubject, changeReport+changeDiffs)
if err != nil {
return fmt.Errorf("Error sending notification email: %s", err.Error())
}
if send >= 1 {
err = sendEmail(Opts, emailSubject, changeReport+changeDiffs)
if err != nil {
return fmt.Errorf("Error sending notification email: %s", err.Error())
}
}
}

Opts.LogInfo("Finished reporter.")
Expand Down
Loading