mirror of
https://github.com/davidallendj/magellan.git
synced 2025-12-19 19:17:02 -07:00
Add support for storage command and crawler output
Partially addresses issue #3 by adding a simple `magellan list devices` command to list storage devices. To close the issue, this PR still requires including storage device information in the `crawler`'s output. Reviewed-on: towk/magellan-ng#5
This commit is contained in:
parent
d236649b05
commit
b2111ddcb2
20 changed files with 450 additions and 18 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,9 +1,11 @@
|
|||
magellan
|
||||
emulator/rf-emulator
|
||||
dist/*
|
||||
**/*.db
|
||||
**.tar.gz
|
||||
**.tar.zst
|
||||
**.part
|
||||
dist/*
|
||||
**.txt
|
||||
**.json
|
||||
**coverage.out**
|
||||
magellan.1
|
||||
magellan.1
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
"github.com/cznic/mathutil"
|
||||
"github.com/davidallendj/magellan/internal/cache/sqlite"
|
||||
urlx "github.com/davidallendj/magellan/internal/url"
|
||||
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||
magellan "github.com/davidallendj/magellan/pkg"
|
||||
"github.com/davidallendj/magellan/pkg/auth"
|
||||
"github.com/davidallendj/magellan/pkg/bmc"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
urlx "github.com/davidallendj/magellan/internal/url"
|
||||
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||
"github.com/davidallendj/magellan/pkg/bmc"
|
||||
"github.com/davidallendj/magellan/pkg/crawler"
|
||||
"github.com/davidallendj/magellan/pkg/secrets"
|
||||
|
|
|
|||
34
cmd/list.go
34
cmd/list.go
|
|
@ -1,13 +1,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/davidallendj/magellan/internal/cache/sqlite"
|
||||
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||
magellan "github.com/davidallendj/magellan/pkg"
|
||||
"github.com/davidallendj/magellan/pkg/crawler"
|
||||
"github.com/davidallendj/magellan/pkg/secrets"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
|
|
@ -34,15 +37,17 @@ var ListCmd = &cobra.Command{
|
|||
"See the 'scan' command on how to perform a scan.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// check if we just want to show cache-related info and exit
|
||||
if showCache {
|
||||
fmt.Printf("cache: %s\n", cachePath)
|
||||
return
|
||||
if showCacheInfo {
|
||||
magellan.PrintMapFormat(map[string]any{
|
||||
"path": cachePath,
|
||||
}, format)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// load the assets found from scan
|
||||
scannedResults, err := sqlite.GetScannedAssets(cachePath)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to get scanned assets")
|
||||
log.Error().Err(err).Str("path", cachePath).Msg("failed to get scanned assets from cache")
|
||||
}
|
||||
switch strings.ToLower(listOutputFormat) {
|
||||
case FORMAT_JSON:
|
||||
|
|
@ -65,6 +70,25 @@ var ListCmd = &cobra.Command{
|
|||
log.Error().Msg("unrecognized format")
|
||||
os.Exit(1)
|
||||
}
|
||||
args[0], err = urlx.Sanitize(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sanitize URI: %w", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
store := secrets.NewStaticStore(listUsername, listPassword)
|
||||
drives, err := magellan.ListDrives(&crawler.CrawlerConfig{
|
||||
URI: args[0],
|
||||
CredentialStore: store, //initSecretsStore(args[0]),
|
||||
Insecure: insecure,
|
||||
UseDefault: false,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to get drives")
|
||||
os.Exit(1)
|
||||
}
|
||||
magellan.PrintDrives(drives)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
43
cmd/root.go
43
cmd/root.go
|
|
@ -21,6 +21,8 @@ import (
|
|||
|
||||
magellan "github.com/davidallendj/magellan/internal"
|
||||
"github.com/davidallendj/magellan/internal/util"
|
||||
"github.com/davidallendj/magellan/pkg/bmc"
|
||||
"github.com/davidallendj/magellan/pkg/secrets"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
|
@ -150,3 +152,44 @@ func SetDefaults() {
|
|||
viper.SetDefault("update.status", false)
|
||||
|
||||
}
|
||||
|
||||
func initSecretsStore(uri string) secrets.SecretStore {
|
||||
var (
|
||||
store secrets.SecretStore
|
||||
err error
|
||||
)
|
||||
if username != "" && password != "" {
|
||||
// First, try and load credentials from --username and --password if both are set.
|
||||
log.Debug().Str("id", uri).Msgf("--username and --password specified, using them for BMC credentials")
|
||||
store = secrets.NewStaticStore(username, password)
|
||||
} else {
|
||||
// Alternatively, locate specific credentials (falling back to default) and override those
|
||||
// with --username or --password if either are passed.
|
||||
log.Debug().Str("id", uri).Msgf("one or both of --username and --password NOT passed, attempting to obtain missing credentials from secret store at %s", secretsFile)
|
||||
if store, err = secrets.OpenStore(secretsFile); err != nil {
|
||||
log.Error().Str("id", uri).Err(err).Msg("failed to open local secrets store")
|
||||
}
|
||||
|
||||
// Either none of the flags were passed or only one of them were; get
|
||||
// credentials from secrets store to fill in the gaps.
|
||||
bmcCreds, _ := bmc.GetBMCCredentials(store, uri)
|
||||
nodeCreds := secrets.StaticStore{
|
||||
Username: bmcCreds.Username,
|
||||
Password: bmcCreds.Password,
|
||||
}
|
||||
|
||||
// If either of the flags were passed, override the fetched
|
||||
// credentials with them.
|
||||
if username != "" {
|
||||
log.Info().Str("id", uri).Msg("--username was set, overriding username for this BMC")
|
||||
nodeCreds.Username = username
|
||||
}
|
||||
if password != "" {
|
||||
log.Info().Str("id", uri).Msg("--password was set, overriding password for this BMC")
|
||||
nodeCreds.Password = password
|
||||
}
|
||||
|
||||
store = &nodeCreds
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/cznic/mathutil"
|
||||
urlx "github.com/davidallendj/magellan/internal/url"
|
||||
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -128,9 +128,7 @@ func init() {
|
|||
checkBindFlagError(viper.BindPFlag("update.username", UpdateCmd.Flags().Lookup("username")))
|
||||
checkBindFlagError(viper.BindPFlag("update.password", UpdateCmd.Flags().Lookup("password")))
|
||||
checkBindFlagError(viper.BindPFlag("update.scheme", UpdateCmd.Flags().Lookup("scheme")))
|
||||
checkBindFlagError(viper.BindPFlag("update.firmware-url", UpdateCmd.Flags().Lookup("firmware-url")))
|
||||
checkBindFlagError(viper.BindPFlag("update.firmware-version", UpdateCmd.Flags().Lookup("firmware-version")))
|
||||
checkBindFlagError(viper.BindPFlag("update.component", UpdateCmd.Flags().Lookup("component")))
|
||||
checkBindFlagError(viper.BindPFlag("update.firmware-uri", UpdateCmd.Flags().Lookup("firmware-uri")))
|
||||
checkBindFlagError(viper.BindPFlag("update.status", UpdateCmd.Flags().Lookup("status")))
|
||||
|
||||
rootCmd.AddCommand(UpdateCmd)
|
||||
|
|
|
|||
24
go.mod
24
go.mod
|
|
@ -1,6 +1,8 @@
|
|||
module github.com/davidallendj/magellan
|
||||
|
||||
go 1.21
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.2
|
||||
|
||||
require (
|
||||
github.com/Cray-HPE/hms-xname v1.3.0
|
||||
|
|
@ -17,6 +19,9 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/charmbracelet/bubbles v0.21.0
|
||||
github.com/charmbracelet/bubbletea v1.3.4
|
||||
github.com/charmbracelet/lipgloss v1.1.0
|
||||
github.com/rs/zerolog v1.33.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
|
@ -28,7 +33,13 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
|
|
@ -39,11 +50,18 @@ require (
|
|||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
|
|
@ -51,9 +69,11 @@ require (
|
|||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
|
|
|||
49
go.sum
49
go.sum
|
|
@ -2,6 +2,26 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
|||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Cray-HPE/hms-xname v1.3.0 h1:DQmetMniubqcaL6Cxarz9+7KFfWGSEizIhfPHIgC3Gw=
|
||||
github.com/Cray-HPE/hms-xname v1.3.0/go.mod h1:XKdjQSzoTps5KDOE8yWojBTAWASGaS6LfRrVDxwTQO8=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
|
||||
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
|
||||
|
|
@ -13,6 +33,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc
|
|||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
|
|
@ -54,6 +76,8 @@ github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNB
|
|||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
|
|
@ -62,10 +86,20 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
|
|
@ -77,6 +111,9 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
|||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
|
|
@ -114,6 +151,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
|||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
|
|
@ -177,9 +216,12 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -192,6 +234,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
=======
|
||||
|
|
@ -233,6 +276,10 @@ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
>>>>>>> d34ba3f (chore: update references and imports)
|
||||
=======
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
>>>>>>> 05e5c4b (Add support for storage command and crawler output)
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
|
|
@ -281,6 +328,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
1
internal/cache/edit/modify.go
vendored
Normal file
1
internal/cache/edit/modify.go
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
package cache
|
||||
48
internal/cache/edit/table.go
vendored
Normal file
48
internal/cache/edit/table.go
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/bubbles/table"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var baseStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.NormalBorder()).
|
||||
BorderForeground(lipgloss.Color("240"))
|
||||
|
||||
type Model struct {
|
||||
selected int
|
||||
Table table.Model
|
||||
}
|
||||
|
||||
func (m Model) Init() tea.Cmd { return nil }
|
||||
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
// m.Table = m.Table.Width(msg.Width)
|
||||
// m.Table = m.Table.Height(msg.Height)
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "esc":
|
||||
if m.Table.Focused() {
|
||||
m.Table.Blur()
|
||||
} else {
|
||||
m.Table.Focus()
|
||||
}
|
||||
case "q", "ctrl+c":
|
||||
return m, tea.Quit
|
||||
case "enter":
|
||||
return m, tea.Batch(
|
||||
tea.Printf("Selected host '%s'", m.Table.SelectedRow()[0]),
|
||||
)
|
||||
}
|
||||
}
|
||||
m.Table, cmd = m.Table.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
func (m Model) View() string {
|
||||
return baseStyle.Render(m.Table.View()) + "\n"
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package url
|
||||
package urlx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package util
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// FormatErrorList() is a wrapper function that unifies error list formatting
|
||||
// and makes printing error lists consistent.
|
||||
|
|
|
|||
25
internal/util/print.go
Normal file
25
internal/util/print.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func PrintJSON(data any) {
|
||||
b, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("failed to marshal scanned results to JSON")
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
func PrintYAML(data any) {
|
||||
b, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("failed to marshal scanned results to JSON")
|
||||
}
|
||||
fmt.Printf("%s\n", string(b))
|
||||
}
|
||||
10
internal/util/strings.go
Normal file
10
internal/util/strings.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package util
|
||||
|
||||
import "strings"
|
||||
|
||||
func TidyJSON(s string) string {
|
||||
s = strings.ReplaceAll(s, "\n", "")
|
||||
s = strings.ReplaceAll(s, "\t", "")
|
||||
s = strings.ReplaceAll(s, " ", "")
|
||||
return strings.ReplaceAll(s, "\"", "'")
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@ type BMCCredentials struct {
|
|||
|
||||
func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error) {
|
||||
var creds BMCCredentials
|
||||
if store == nil {
|
||||
return creds, fmt.Errorf("invalid secrets store")
|
||||
}
|
||||
if strCreds, err := store.GetSecretByID(secrets.DEFAULT_KEY); err != nil {
|
||||
return creds, fmt.Errorf("get default BMC credentials from secret store: %w", err)
|
||||
} else {
|
||||
|
|
@ -27,6 +30,9 @@ func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error)
|
|||
|
||||
func GetBMCCredentials(store secrets.SecretStore, id string) (BMCCredentials, error) {
|
||||
var creds BMCCredentials
|
||||
if store == nil {
|
||||
return creds, fmt.Errorf("invalid secrets store")
|
||||
}
|
||||
if strCreds, err := store.GetSecretByID(id); err != nil {
|
||||
return creds, fmt.Errorf("get BMC credentials from secret store: %w", err)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams, store secret
|
|||
var (
|
||||
systems []crawler.InventoryDetail
|
||||
managers []crawler.Manager
|
||||
storage []crawler.Storage
|
||||
config = crawler.CrawlerConfig{
|
||||
URI: uri,
|
||||
CredentialStore: params.SecretStore,
|
||||
|
|
@ -116,6 +117,11 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams, store secret
|
|||
log.Error().Err(err).Str("uri", uri).Msg("failed to crawl BMC for managers")
|
||||
}
|
||||
|
||||
storage, err = crawler.CrawlBMCForStorage(config)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("uri", uri).Msg("failed to crawl BMC for storage")
|
||||
}
|
||||
|
||||
// we didn't find anything so do not proceed
|
||||
if util.IsEmpty(systems) && util.IsEmpty(managers) {
|
||||
continue
|
||||
|
|
@ -144,6 +150,7 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams, store secret
|
|||
"RediscoverOnUpdate": false,
|
||||
"Systems": systems,
|
||||
"Managers": managers,
|
||||
"Storage": storage,
|
||||
"SchemaVersion": 1,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,26 @@ type InventoryDetail struct {
|
|||
Chassis_Model string `json:"chassis_model,omitempty"` // Model of the Chassis
|
||||
}
|
||||
|
||||
type Storage struct {
|
||||
URI string `json:"uri"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
DrivesCount int `json:"drives_count"`
|
||||
Controllers []StorageController `json:"controllers"`
|
||||
}
|
||||
|
||||
type StorageController struct {
|
||||
Identifiers []string `json:"identifiers"`
|
||||
FirmwareVersion string `json:"firmware_version"`
|
||||
Location string `json:"location"`
|
||||
Manufacturer string `json:"manufacturer"`
|
||||
Model string `json:"model"`
|
||||
PartNumber string `json:"part_number"`
|
||||
SerialNumber string `json:"serial_number"`
|
||||
SpeedGbps float32 `json:"speed_gbps"`
|
||||
}
|
||||
|
||||
// CrawlBMCForSystems pulls all pertinent information from a BMC. It accepts a CrawlerConfig and returns a list of InventoryDetail structs.
|
||||
func CrawlBMCForSystems(config CrawlerConfig) ([]InventoryDetail, error) {
|
||||
var (
|
||||
|
|
@ -207,6 +227,49 @@ func CrawlBMCForManagers(config CrawlerConfig) ([]Manager, error) {
|
|||
return walkManagers(rf_managers, config.URI)
|
||||
}
|
||||
|
||||
func CrawlBMCForStorage(config CrawlerConfig) ([]Storage, error) {
|
||||
// get username and password from secret store
|
||||
bmc_creds, err := loadBMCCreds(config)
|
||||
if err != nil {
|
||||
event := log.Error()
|
||||
event.Err(err)
|
||||
event.Msg("failed to load BMC credentials")
|
||||
return nil, err
|
||||
}
|
||||
// initialize gofish client
|
||||
var storage []Storage
|
||||
client, err := gofish.Connect(gofish.ClientConfig{
|
||||
Endpoint: config.URI,
|
||||
Username: bmc_creds.Username,
|
||||
Password: bmc_creds.Password,
|
||||
Insecure: config.Insecure,
|
||||
BasicAuth: true,
|
||||
})
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "404:") {
|
||||
err = fmt.Errorf("no ServiceRoot found. This is probably not a BMC: %s", config.URI)
|
||||
}
|
||||
if strings.HasPrefix(err.Error(), "401:") {
|
||||
err = fmt.Errorf("authentication failed. Check your username and password: %s", config.URI)
|
||||
}
|
||||
event := log.Error()
|
||||
event.Err(err)
|
||||
event.Msg("failed to connect to BMC")
|
||||
return storage, err
|
||||
}
|
||||
defer client.Logout()
|
||||
|
||||
// Obtain the ServiceRoot
|
||||
rf_service := client.GetService()
|
||||
log.Debug().Msgf("found ServiceRoot %s. Redfish Version %s", rf_service.ID, rf_service.RedfishVersion)
|
||||
|
||||
rf_storage, err := rf_service.Storage()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to get managers from ServiceRoot")
|
||||
}
|
||||
return walkStorage(rf_storage, config.URI)
|
||||
}
|
||||
|
||||
// walkSystems processes a list of Redfish computer systems and their associated chassis,
|
||||
// and returns a list of inventory details for each system.
|
||||
//
|
||||
|
|
@ -369,6 +432,40 @@ func walkManagers(rf_managers []*redfish.Manager, baseURI string) ([]Manager, er
|
|||
return managers, nil
|
||||
}
|
||||
|
||||
func walkStorage(rf_storage []*redfish.Storage, baseURI string) ([]Storage, error) {
|
||||
var storage []Storage
|
||||
for _, rf_storage := range rf_storage {
|
||||
var controllers []StorageController
|
||||
var rf_storage_controllers, err = rf_storage.Controllers()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to get storage controllers")
|
||||
} else {
|
||||
for _, controller := range rf_storage_controllers {
|
||||
controllers = append(controllers, StorageController{
|
||||
// Identifiers: controller.Identifiers,
|
||||
FirmwareVersion: controller.FirmwareVersion,
|
||||
Location: controller.Location.Info,
|
||||
Manufacturer: controller.Manufacturer,
|
||||
Model: controller.Model,
|
||||
PartNumber: controller.PartNumber,
|
||||
SerialNumber: controller.SerialNumber,
|
||||
SpeedGbps: controller.SpeedGbps,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
storage = append(storage, Storage{
|
||||
URI: baseURI + "/redfish/v1/Storage/" + rf_storage.ID,
|
||||
ID: rf_storage.ID,
|
||||
Name: rf_storage.Name,
|
||||
Description: rf_storage.Description,
|
||||
DrivesCount: rf_storage.DrivesCount,
|
||||
Controllers: controllers,
|
||||
})
|
||||
}
|
||||
return storage, nil
|
||||
}
|
||||
|
||||
func loadBMCCreds(config CrawlerConfig) (bmc.BMCCredentials, error) {
|
||||
// NOTE: it is possible for the SecretStore to be nil, so we need a check
|
||||
if config.CredentialStore == nil {
|
||||
|
|
|
|||
100
pkg/list.go
Normal file
100
pkg/list.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package magellan
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/davidallendj/magellan/internal/util"
|
||||
"github.com/davidallendj/magellan/pkg/crawler"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stmcginnis/gofish"
|
||||
"github.com/stmcginnis/gofish/redfish"
|
||||
)
|
||||
|
||||
func PrintRemoteAssets(data []RemoteAsset, format string) {
|
||||
switch strings.ToLower(format) {
|
||||
case "json":
|
||||
util.PrintJSON(data)
|
||||
case "yaml":
|
||||
util.PrintYAML(data)
|
||||
case "none":
|
||||
for _, r := range data {
|
||||
fmt.Printf("%s:%d (%s) @%s\n", r.Host, r.Port, r.Protocol, r.Timestamp.Format(time.UnixDate))
|
||||
}
|
||||
default:
|
||||
log.Error().Msg("unrecognized format")
|
||||
}
|
||||
}
|
||||
|
||||
func PrintMapFormat(data map[string]any, format string) {
|
||||
switch strings.ToLower(format) {
|
||||
case "json":
|
||||
util.PrintJSON(data)
|
||||
case "yaml":
|
||||
util.PrintYAML(data)
|
||||
case "none":
|
||||
for k, v := range data {
|
||||
fmt.Printf("%s: %v\n", k, v)
|
||||
}
|
||||
default:
|
||||
log.Error().Msg("unrecognized format")
|
||||
}
|
||||
}
|
||||
|
||||
func ListDrives(cc *crawler.CrawlerConfig) ([]*redfish.Drive, error) {
|
||||
user, err := cc.GetUserPass()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get username and password: %v", err)
|
||||
}
|
||||
log.Info().Str("username", user.Username).Str("password", user.Password).Str("host", cc.URI).Msg("credentials used")
|
||||
// Create a new instance of gofish client, ignoring self-signed certs
|
||||
c, err := gofish.Connect(gofish.ClientConfig{
|
||||
Endpoint: cc.URI,
|
||||
Username: user.Username,
|
||||
Password: user.Password,
|
||||
Insecure: cc.Insecure,
|
||||
BasicAuth: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to host: %v", util.TidyJSON(err.Error()))
|
||||
}
|
||||
defer c.Logout()
|
||||
|
||||
// Retrieve the service root
|
||||
systems, err := c.Service.Systems()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve systems: %v", err)
|
||||
}
|
||||
|
||||
// aggregate all of the drives together
|
||||
foundDrives := []*redfish.Drive{}
|
||||
for _, system := range systems {
|
||||
storage, err := system.Storage()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ss := range storage {
|
||||
drives, err := ss.Drives()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
foundDrives = append(foundDrives, drives...)
|
||||
}
|
||||
}
|
||||
return foundDrives, nil
|
||||
}
|
||||
|
||||
func PrintDrives(drives []*redfish.Drive) {
|
||||
for i, drive := range drives {
|
||||
fmt.Printf("Drive %d\n", i)
|
||||
fmt.Printf("\tManufacturer: %s\n", drive.Manufacturer)
|
||||
fmt.Printf("\tModel: %s\n", drive.Model)
|
||||
fmt.Printf("\tSize: %d GiB\n", (drive.CapacityBytes / 1024 / 1024 / 1024))
|
||||
fmt.Printf("\tSerial number: %s\n", drive.SerialNumber)
|
||||
fmt.Printf("\tPart number: %s\n", drive.PartNumber)
|
||||
fmt.Printf("\tLocation: %s %d\n", drive.PhysicalLocation.PartLocation.LocationType, drive.PhysicalLocation.PartLocation.LocationOrdinalValue)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
urlx "github.com/davidallendj/magellan/internal/url"
|
||||
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||
"github.com/davidallendj/magellan/pkg/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue