Merge pull request #107 from bmcdonald3/scan-pdus

Scan pdus
This commit is contained in:
Ben McDonald 2025-07-10 14:14:03 -07:00 committed by GitHub
commit 7e8011ce29
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 34 deletions

View file

@ -10,6 +10,7 @@ import (
"github.com/OpenCHAMI/magellan/internal/cache/sqlite"
magellan "github.com/OpenCHAMI/magellan/pkg"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v3"
urlx "github.com/OpenCHAMI/magellan/internal/url"
"github.com/cznic/mathutil"
@ -24,6 +25,8 @@ var (
targetHosts [][]string
disableProbing bool
disableCache bool
format string
include []string
)
// The `scan` command is usually the first step to using the CLI tool.
@ -66,7 +69,7 @@ var ScanCmd = &cobra.Command{
"specified. The `--scheme` flag works similarly and the default value is 'https' in the host URL or with the\n" +
"'--protocol' flag.\n\n" +
"If the '--disable-probe` flag is used, the tool will not send another request to probe for available.\n" +
"Redfish services. This is not recommended, since the extra request makes the scan a bit more reliable\n" +
"Redfish and JAWS services. This is not recommended, since the extra request makes the scan a bit more reliable\n" +
"for determining which hosts to collect inventory data.\n\n",
Run: func(cmd *cobra.Command, args []string) {
// add default ports for hosts if none are specified with flag
@ -138,32 +141,61 @@ var ScanCmd = &cobra.Command{
DisableProbing: disableProbing,
Verbose: verbose,
Debug: debug,
Insecure: insecure,
Include: include,
})
if len(foundAssets) > 0 && debug {
log.Info().Any("assets", foundAssets).Msgf("found assets from scan")
}
if !disableCache && cachePath != "" {
// make the cache directory path if needed
err := os.MkdirAll(path.Dir(cachePath), 0755)
if err != nil {
log.Printf("failed to make cache directory: %v", err)
if len(foundAssets) == 0 {
log.Warn().Msg("Scan complete. No responsive assets were found.")
return
}
switch format {
case "json", "yaml":
var output []byte
var err error
if format == "json" {
output, err = json.MarshalIndent(foundAssets, "", " ")
} else {
output, err = yaml.Marshal(foundAssets)
}
// TODO: change this to use an extensible plugin system for storage solutions
// (i.e. something like cache.InsertScannedAssets(path, assets) which implements a Cache interface)
if len(foundAssets) > 0 {
if err != nil {
log.Error().Err(err).Msgf("Failed to marshal output to %s", format)
return
}
if outputPath != "" {
err := os.WriteFile(outputPath, output, 0644)
if err != nil {
log.Error().Err(err).Msgf("Failed to write to file: %s", outputPath)
} else {
log.Info().Msgf("Scan results successfully written to %s", outputPath)
}
} else {
fmt.Println(string(output))
}
case "db":
if !disableCache && cachePath != "" {
err := os.MkdirAll(path.Dir(cachePath), 0755)
if err != nil {
log.Printf("failed to make cache directory: %v", err)
}
err = sqlite.InsertScannedAssets(cachePath, foundAssets...)
if err != nil {
log.Error().Err(err).Msg("failed to write scanned assets to cache")
} else if verbose {
log.Info().Msgf("Saved assets to cache: %s", cachePath)
}
if verbose {
log.Info().Msgf("saved assets to cache: %s", cachePath)
}
} else {
log.Warn().Msg("no assets found to save")
}
default:
log.Error().Msgf("unknown format specified: %s. Please use 'db', 'json', or 'yaml'.", format)
}
},
@ -177,6 +209,10 @@ func init() {
ScanCmd.Flags().IPMaskVar(&subnetMask, "subnet-mask", net.IPv4Mask(255, 255, 255, 0), "Set the default subnet mask to use for with all subnets not using CIDR notation.")
ScanCmd.Flags().BoolVar(&disableProbing, "disable-probing", false, "Disable probing found assets for Redfish service(s) running on BMC nodes")
ScanCmd.Flags().BoolVar(&disableCache, "disable-cache", false, "Disable saving found assets to a cache database specified with 'cache' flag")
ScanCmd.Flags().BoolVar(&insecure, "insecure", true, "Skip TLS certificate verification during probe")
ScanCmd.Flags().StringVarP(&format, "format", "F", "db", "Output format (db, json, yaml)")
ScanCmd.Flags().StringVarP(&outputPath, "output", "o", "", "Output file path (for json/yaml formats)")
ScanCmd.Flags().StringSliceVar(&include, "include", []string{"bmcs"}, "Asset types to scan for (bmcs, pdus)")
checkBindFlagError(viper.BindPFlag("scan.ports", ScanCmd.Flags().Lookup("port")))
checkBindFlagError(viper.BindPFlag("scan.scheme", ScanCmd.Flags().Lookup("scheme")))