diff --git a/README.md b/README.md index beb27a3..e892d48 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ In summary, `magellan` needs at minimum the following configured to work on each Install Go, clone the repo, and then run the following in the project root: ```bash -clone https://github.com/bikeshack/magellan +git clone https://github.com/bikeshack/magellan cd magellan go mod tidy && go build ``` @@ -40,7 +40,7 @@ versions of Go may work, the project has only been tested with v1.20. There are three main commands to use with the tool: `scan`, `list`, and `collect`. To scan a network for BMC nodes, use the `scan` command. If the port is not specified, -`magellan` will probe ports 623, 22, 442, and 5000 by default similar to `dora`: +`magellan` will probe ports 623, 442 (redfish and IPMI) by default: ```bash ./magellan scan --subnet 192.168.0.0 --db.path data/assets.db --port 623 @@ -74,7 +74,7 @@ and `pass/password` flag to be set to use `ipmitool` (which must installed as we Additionally, it may be necessary to set the `host` and `port` flags for `magellan` to find the `hms-smd` API. -Note: If `db.path` is not set, `magellan` will use /tmp/magellan.db by default. +Note: If the `db.path` flag is not set, `magellan` will use /tmp/magellan.db by default. ## TODO diff --git a/bin/magellan.sh b/bin/magellan.sh index 99f1ce6..0850f87 100644 --- a/bin/magellan.sh +++ b/bin/magellan.sh @@ -4,14 +4,14 @@ function build(){ } function scan() { - ./magellan scan --subnet 172.16.0.0 --db.path data/assets.db --port 443,623,5000 + ./magellan scan --subnet 172.16.0.0 --port 443 } function list(){ - ./magellan list --db.path data/assets.db + ./magellan list } function collect() { - ./magellan collect --db.path data/assets.db --driver redfish --timeout 30 --user admin --pass password + ./magellan collect --user admin --pass password } diff --git a/cmd/collect.go b/cmd/collect.go index 3994bb0..ad71b4d 100644 --- a/cmd/collect.go +++ b/cmd/collect.go @@ -34,6 +34,7 @@ var collectCmd = &cobra.Command{ Threads: threads, Verbose: verbose, WithSecureTLS: withSecureTLS, + } magellan.CollectInfo(&probeStates, l, q) @@ -51,7 +52,6 @@ func init() { collectCmd.PersistentFlags().IntVar(&smd.Port, "port", smd.Port, "set the port to the smd API") collectCmd.PersistentFlags().StringVar(&user, "user", "", "set the BMC user") collectCmd.PersistentFlags().StringVar(&pass, "pass", "", "set the BMC password") - collectCmd.PersistentFlags().StringVar(&pass, "password", "", "set the BMC password") collectCmd.PersistentFlags().StringVar(&preferredDriver, "preferred-driver", "ipmi", "set the preferred driver to use") collectCmd.PersistentFlags().StringVar(&ipmitoolPath, "ipmitool.path", "/usr/bin/ipmitool", "set the path for ipmitool") collectCmd.PersistentFlags().BoolVar(&withSecureTLS, "secure-tls", false, "enable secure TLS") diff --git a/cmd/root.go b/cmd/root.go index ea661a7..cd727fa 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,7 +49,7 @@ func Execute() { func init() { rootCmd.PersistentFlags().IntVar(&threads, "threads", -1, "set the number of threads") - rootCmd.PersistentFlags().IntVar(&timeout, "timeout", 10, "set the timeout") + rootCmd.PersistentFlags().IntVar(&timeout, "timeout", 30, "set the timeout") rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", true, "set verbose flag") rootCmd.PersistentFlags().StringVar(&dbpath, "db.path", "/tmp/magellan.db", "set the probe storage path") } diff --git a/internal/collect.go b/internal/collect.go index f6b7a1e..73cd09f 100644 --- a/internal/collect.go +++ b/internal/collect.go @@ -2,9 +2,11 @@ package magellan import ( "context" + "crypto/tls" "crypto/x509" "encoding/json" "fmt" + "net/http" "os" "sync" "time" @@ -15,7 +17,6 @@ import ( bmclib "github.com/bmc-toolbox/bmclib/v2" "github.com/jacobweinstock/registrar" _ "github.com/mattn/go-sqlite3" - "github.com/sirupsen/logrus" "github.com/stmcginnis/gofish" _ "github.com/stmcginnis/gofish" "github.com/stmcginnis/gofish/redfish" @@ -26,7 +27,6 @@ const ( IPMI_PORT = 623 SSH_PORT = 22 HTTPS_PORT = 443 - REDFISH_PORT = 5000 ) type BMCProbeResult struct { @@ -56,20 +56,20 @@ func NewClient(l *Logger, q *QueryParams) (*bmclib.Client, error) { // NOTE: bmclib.NewClient(host, port, user, pass) // ...seems like the `port` params doesn't work like expected depending on interface - // tr := &http.Transport{ - // TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - // } - // httpClient := http.Client{ - // Transport: tr, - // } + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + httpClient := http.Client{ + Transport: tr, + } // init client clientOpts := []bmclib.Option{ // bmclib.WithSecureTLS(nil), - // bmclib.WithHTTPClient(&httpClient), + bmclib.WithHTTPClient(&httpClient), // bmclib.WithLogger(), - // bmclib.WithRedfishHTTPClient(&httpClient), - bmclib.WithDellRedfishUseBasicAuth(true), + bmclib.WithRedfishHTTPClient(&httpClient), + // bmclib.WithDellRedfishUseBasicAuth(true), bmclib.WithRedfishPort(fmt.Sprint(q.Port)), bmclib.WithRedfishUseBasicAuth(true), bmclib.WithIpmitoolPort(fmt.Sprint(IPMI_PORT)), @@ -90,16 +90,9 @@ func NewClient(l *Logger, q *QueryParams) (*bmclib.Client, error) { // a nil pool uses the system certs clientOpts = append(clientOpts, bmclib.WithSecureTLS(pool)) } - // url := fmt.Sprintf("https://%s:%s@%s", q.User, q.Pass, q.Host) url := "" - // if q.WithSecureTLS { - // url = "https://" - // } else { - // url = "http://" - // } - - if q.User == "" && q.Pass == "" { - url += fmt.Sprintf("%s:%s@%s", q.User, q.Pass, q.Host) + if q.User != "" && q.Pass != "" { + url += fmt.Sprintf("https://%s:%s@%s", q.User, q.Pass, q.Host) } else { url += q.Host } @@ -147,9 +140,7 @@ func CollectInfo(probeStates *[]BMCProbeResult, l *Logger, q *QueryParams) error } q.Host = ps.Host q.Port = ps.Port - - logrus.Printf("querying %v:%v (%v)\n", ps.Host, ps.Port, ps.Protocol) - + client, err := NewClient(l, q) if err != nil { l.Log.Errorf("could not make client: %v", err) @@ -190,6 +181,7 @@ func CollectInfo(probeStates *[]BMCProbeResult, l *Logger, q *QueryParams) error data["Inventory"] = inventory data["Chassis"] = chassis + b, err := json.MarshalIndent(data, "", " ") if err != nil { l.Log.Errorf("could not marshal JSON: %v", err) @@ -199,6 +191,8 @@ func CollectInfo(probeStates *[]BMCProbeResult, l *Logger, q *QueryParams) error err = smd.AddRedfishEndpoint(b, headers) if err != nil { l.Log.Errorf("could not add redfish endpoint: %v", err) + + // try updating instead } // users @@ -419,20 +413,27 @@ func QueryEthernetInterfaces(client *bmclib.Client, l *Logger, q *QueryParams) ( } func QueryChassis(q *QueryParams) ([]byte, error) { - config := gofish.ClientConfig{ - Endpoint: fmt.Sprintf("https://%s:%d", q.Host, q.Port), - Username: q.User, - Password: q.Pass, - Insecure: !q.WithSecureTLS, - TLSHandshakeTimeout: q.Timeout, + + url := "https://" + if q.User != "" && q.Pass != "" { + url += fmt.Sprintf("%s:%s@", q.User, q.Pass) + } + url += fmt.Sprintf("%s:%d", q.Host, q.Port) + config := gofish.ClientConfig { + Endpoint: url, + Username: q.User, + Password: q.Pass, + Insecure: !q.WithSecureTLS, + TLSHandshakeTimeout: q.Timeout, + } c, err := gofish.Connect(config) if err != nil { - return nil, fmt.Errorf("could not connect to bmc: %v", err) + return nil, fmt.Errorf("could not connect to bmc (%v:%v): %v", q.Host, q.Port, err) } chassis, err := c.Service.Chassis() if err != nil { - return nil, fmt.Errorf("could not query chassis: %v", err) + return nil, fmt.Errorf("could not query chassis (%v:%v): %v", q.Host, q.Port, err) } b, err := json.MarshalIndent(chassis, "", " ") diff --git a/internal/scan.go b/internal/scan.go index c373c40..55b2d6a 100644 --- a/internal/scan.go +++ b/internal/scan.go @@ -92,5 +92,5 @@ func ScanForAssets(hosts []string, ports []int, threads int, timeout int) []BMCP } func GetDefaultPorts() []int { - return []int{SSH_PORT, HTTPS_PORT, IPMI_PORT, REDFISH_PORT} + return []int{HTTPS_PORT, IPMI_PORT} } \ No newline at end of file