diff --git a/pkg/bmc/bmc.go b/pkg/bmc/bmc.go index c451543..c338009 100644 --- a/pkg/bmc/bmc.go +++ b/pkg/bmc/bmc.go @@ -8,8 +8,15 @@ import ( ) type BMCCredentials struct { - Username string `json:"username"` - Password string `json:"password"` + Username string `json:"username"` + Password string `json:"password"` + SessionTokens map[string]string `json:"session-tokens"` +} + +func (c BMCCredentials) IsEmpty() bool { + return c.Username == "" && + c.Password == "" && + len(c.SessionTokens) == 0 } func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error) { diff --git a/pkg/collect.go b/pkg/collect.go index 0be1cf7..dd4ff1a 100644 --- a/pkg/collect.go +++ b/pkg/collect.go @@ -31,17 +31,18 @@ import ( // CollectParams is a collection of common parameters passed to the CLI // for the 'collect' subcommand. type CollectParams struct { - URI string // set by the 'host' flag - Concurrency int // set the of concurrent jobs with the 'concurrency' flag - Timeout int // set the timeout with the 'timeout' flag - CaCertPath string // set the cert path with the 'cacert' flag - Verbose bool // set whether to include verbose output with 'verbose' flag - OutputPath string // set the path to save output with 'output' flag - OutputDir string // set the directory path to save output with `output-dir` flag - Format string // set the output format - ForceUpdate bool // set whether to force updating SMD with 'force-update' flag - AccessToken string // set the access token to include in request with 'access-token' flag - SecretStore secrets.SecretStore // set BMC credentials + URI string // set by the 'host' flag + Concurrency int // set the of concurrent jobs with the 'concurrency' flag + Timeout int // set the timeout with the 'timeout' flag + CaCertPath string // set the cert path with the 'cacert' flag + Verbose bool // set whether to include verbose output with 'verbose' flag + OutputPath string // set the path to save output with 'output' flag + OutputDir string // set the directory path to save output with `output-dir` flag + Format string // set the output format + ForceUpdate bool // set whether to force updating SMD with 'force-update' flag + AccessToken string // set the access token to include in request with 'access-token' flag + SessionToken string // set the session token to use for auth + SecretStore secrets.SecretStore // set BMC credentials } // This is the main function used to collect information from the BMC nodes via Redfish. @@ -71,7 +72,7 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams, store secret // set the client's params from CLI wg.Add(params.Concurrency) - for i := 0; i < params.Concurrency; i++ { + for _ = range params.Concurrency { go func() { for { sr, ok := <-chanAssets @@ -129,7 +130,7 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams, store secret // get BMC username to send bmcCreds := bmc.GetBMCCredentialsOrDefault(params.SecretStore, config.URI) - if bmcCreds == (bmc.BMCCredentials{}) { + if bmcCreds.IsEmpty() { log.Warn().Str("id", config.URI).Msg("username will be blank") } diff --git a/pkg/crawler/main.go b/pkg/crawler/main.go index 522279e..2283e89 100644 --- a/pkg/crawler/main.go +++ b/pkg/crawler/main.go @@ -16,11 +16,13 @@ type CrawlerConfig struct { URI string // URI of the BMC Insecure bool // Whether to ignore SSL errors CredentialStore secrets.SecretStore + SessionID string + SessionToken string UseDefault bool } func (cc *CrawlerConfig) GetUserPass() (bmc.BMCCredentials, error) { - return loadBMCCreds(*cc) + return LoadBMCCreds(*cc) } type EthernetInterface struct { @@ -124,7 +126,7 @@ func CrawlBMCForSystems(config CrawlerConfig) ([]InventoryDetail, error) { rf_systems []*redfish.ComputerSystem ) // get username and password from secret store - bmc_creds, err := loadBMCCreds(config) + bmc_creds, err := LoadBMCCreds(config) if err != nil { event := log.Error() event.Err(err) @@ -134,12 +136,17 @@ func CrawlBMCForSystems(config CrawlerConfig) ([]InventoryDetail, error) { // initialize gofish client client, err := gofish.Connect(gofish.ClientConfig{ - Endpoint: config.URI, - Username: bmc_creds.Username, - Password: bmc_creds.Password, - Insecure: config.Insecure, + Endpoint: config.URI, + Username: bmc_creds.Username, + Password: bmc_creds.Password, + Insecure: config.Insecure, + Session: &gofish.Session{ + ID: config.SessionID, + Token: bmc_creds.SessionTokens[config.SessionID], + }, 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) @@ -219,7 +226,7 @@ func CrawlBMCForSystems(config CrawlerConfig) ([]InventoryDetail, error) { func CrawlBMCForManagers(config CrawlerConfig) ([]Manager, error) { // get username and password from secret store - bmc_creds, err := loadBMCCreds(config) + bmc_creds, err := LoadBMCCreds(config) if err != nil { event := log.Error() event.Err(err) @@ -262,7 +269,7 @@ func CrawlBMCForManagers(config CrawlerConfig) ([]Manager, error) { func CrawlBMCForStorage(config CrawlerConfig) ([]Storage, error) { // get username and password from secret store - bmc_creds, err := loadBMCCreds(config) + bmc_creds, err := LoadBMCCreds(config) if err != nil { event := log.Error() event.Err(err) @@ -591,12 +598,12 @@ func walkStorage(rf_storage []*redfish.Storage, baseURI string) ([]Storage, erro return storage, nil } -func loadBMCCreds(config CrawlerConfig) (bmc.BMCCredentials, error) { +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 { return bmc.BMCCredentials{}, fmt.Errorf("credential store is invalid") } - if creds := util.GetBMCCredentials(config.CredentialStore, config.URI); creds == (bmc.BMCCredentials{}) { + if creds := util.GetBMCCredentials(config.CredentialStore, config.URI); creds.IsEmpty() { return creds, fmt.Errorf("%s: credentials blank for BMC", config.URI) } else { return creds, nil diff --git a/pkg/list.go b/pkg/list.go index 5b2e5fa..3e7ea0b 100644 --- a/pkg/list.go +++ b/pkg/list.go @@ -18,27 +18,27 @@ func PrintRemoteAssets(data []RemoteAsset, format string) { util.PrintJSON(data) case "yaml": util.PrintYAML(data) - case "none": + case "list": 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") + log.Error().Msg("PrintRemoteAssets: unrecognized format") } } -func PrintMapFormat(data map[string]any, format string) { +func PrintMapWithFormat(data map[string]any, format string) { switch strings.ToLower(format) { case "json": util.PrintJSON(data) case "yaml": util.PrintYAML(data) - case "none": + case "list": for k, v := range data { fmt.Printf("%s: %v\n", k, v) } default: - log.Error().Msg("unrecognized format") + log.Error().Msg("PrintMapWithFormat: unrecognized format") } } diff --git a/pkg/secrets/localstore.go b/pkg/secrets/localstore.go index f426320..ab50eca 100644 --- a/pkg/secrets/localstore.go +++ b/pkg/secrets/localstore.go @@ -95,7 +95,11 @@ func (l *LocalSecretStore) ListSecrets() (map[string]string, error) { defer l.mu.RUnlock() secretsCopy := make(map[string]string) - for key, value := range l.Secrets { + for key, _ := range l.Secrets { + value, err := l.GetSecretByID(key) + if err != nil { + continue + } secretsCopy[key] = value } return secretsCopy, nil diff --git a/pkg/secrets/main.go b/pkg/secrets/main.go index 983f159..5672eef 100644 --- a/pkg/secrets/main.go +++ b/pkg/secrets/main.go @@ -1,7 +1,13 @@ package secrets +import "errors" + const DEFAULT_KEY = "default" +var ( + ErrLoadFailedCreds = errors.New("failed to load BMC credentials") +) + type SecretStore interface { GetSecretByID(secretID string) (string, error) StoreSecretByID(secretID, secret string) error