Merge branch 'main' into manager-data

Signed-off-by: David Allen <16520934+davidallendj@users.noreply.github.com>
This commit is contained in:
David Allen 2024-10-24 17:57:00 -06:00 committed by GitHub
commit 9e289b4946
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 50 additions and 64 deletions

View file

@ -60,6 +60,9 @@ release: ## goreleaser build
$(call print-target)
$(GOPATH)/bin/goreleaser build --clean --single-target --snapshot
.PHONY: binaries
binaries: build
.PHONY: build
build: ## go build
go build -v --tags=all -ldflags=$(LDFLAGS) -o $(NAME) main.go

View file

@ -101,7 +101,7 @@ This should return a JSON response with general information. The output below ha
### Running the Tool
There are three main commands to use with the tool: `scan`, `list`, and `collect`. To see all of the available commands, run `magellan` with the `help` subcommand:
There are three main commands to use with the tool: `scan`, `list`, and `collect`. To see all of the available commands, run `magellan` with the `help` subcommand which will print this output:
```bash
Redfish-based BMC discovery tool
@ -119,16 +119,17 @@ Available Commands:
login Log in with identity provider for access token
scan Scan to discover BMC nodes on a network
update Update BMC node firmware
version Print version info and exit
Flags:
--access-token string set the access token
--cache string set the scanning result cache path (default "/tmp/allend/magellan/assets.db")
--concurrency int set the number of concurrent processes (default -1)
-c, --config string set the config file path
-d, --debug set to enable/disable debug messages
--access-token string Set the access token
--cache string Set the scanning result cache path (default "/tmp/allend/magellan/assets.db")
--concurrency int Set the number of concurrent processes (default -1)
-c, --config string Set the config file path
-d, --debug Set to enable/disable debug messages
-h, --help help for magellan
--timeout int set the timeout (default 5)
-v, --verbose set to enable/disable verbose output
--timeout int Set the timeout for requests (default 5)
-v, --verbose Set to enable/disable verbose output
Use "magellan [command] --help" for more information about a command.
```
@ -143,23 +144,19 @@ To start a network scan for BMC nodes, use the `scan` command. If the port is no
--cache data/assets.db \
```
This will scan the `172.16.0.0` subnet returning the host and port that return a response and store the results in a local cache with at the `data/assets.db` path. Additional flags can be set such as `--host` to add more hosts to scan not included on the subnet, `--timeout` to set how long to wait for a response from the BMC node, or `--concurrency` to set the number of requests to make concurrently. Setting the `--format=json` will format the output in JSON. Try using `./magellan help scan` for a complete set of options this subcommand. Alternatively, the same scan can be started using CIDR notation and with additional hosts:
This will scan the `172.16.0.0` subnet returning the host and port that return a response and store the results in a local cache with at the `data/assets.db` path. Additional flags can be set such as `--host` to add more hosts to scan that are not included on the subnet, `--timeout` to set how long to wait for a response from the BMC node, or `--concurrency` to set the number of requests to make concurrently with goroutines. Try using `./magellan help scan` for a complete set of options this subcommand. Alternatively, the same scan can be started using CIDR notation and with additional hosts:
```bash
./magellan scan https://10.0.0.100:5000 --subnet 172.16.0.0/24
```
Check the help for each subcommand for more examples for specifying arguments.
To inspect the cache, use the `list` command. Make sure to point to the same database used before:
Once the scan is complete, inspect the cache to see a list of found hosts with the `list` command. Make sure to point to the same database used before if you set the `--cache` flag.
```bash
./magellan list --cache data/assets.db --format json
./magellan list --cache data/assets.db
```
This will print a list of node info found and stored from the scan. Like the `scan` subcommand, the output format can be set using the `--format` flag.
Finally, set the `ACCESS_TOKEN`run the `collect` command to query the node from cache and send the info to be stored into SMD:
This will print a list of host information needed for the `collect` step. Set the `ACCESS_TOKEN` if necessary and invoke `magellan` again with the `collect` subcommand to query the node BMCs stored in cache. If the `--host` flag is set, then an additional request will be made to send the output to the specified URL. The `--userame` and `--password` flags must be set if the BMC requires basic authentication.
```bash
./magellan collect \
@ -167,14 +164,14 @@ Finally, set the `ACCESS_TOKEN`run the `collect` command to query the node from
--timeout 5 \
--username $USERNAME \
--password $PASSWORD \
--host https://example.openchami.cluster:27779 \
--host https://example.openchami.cluster:8443 \
--output logs/
--cacert cacert.pem
```
This uses the info stored in cache to request information about each BMC node if possible. Like with the scan, the time to wait for a response can be set with the `--timeout` flag as well. This command also requires the `--user` and `--pass` flags to be set if access the Redfish service requires basic authentication. Additionally, it may be necessary to set the `--host` and `--port` flags for `magellan` to find the SMD API (not the root API endpoint "/hsm/v2"). The output of the `collect` can be saved by using the `--output`
This will initiate a crawler that will find as much inventory data as possible. The data can be viewed from standard output by setting the `--verbose` flag. This output can also be saved by using the `--output` flag and providing a path argument.
Note: If the `cache` flag is not set, `magellan` will use "/tmp/$USER/magellan.db" by default.
Note: If the `cache` flag is not set, `magellan` will use `/tmp/$USER/magellan.db` by default.
### Updating Firmware

View file

@ -74,13 +74,13 @@ func Execute() {
func init() {
currentUser, _ = user.Current()
cobra.OnInitialize(InitializeConfig)
rootCmd.PersistentFlags().IntVar(&concurrency, "concurrency", -1, "set the number of concurrent processes")
rootCmd.PersistentFlags().IntVar(&timeout, "timeout", 5, "set the timeout")
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "set the config file path")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "set to enable/disable verbose output")
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "set to enable/disable debug messages")
rootCmd.PersistentFlags().StringVar(&accessToken, "access-token", "", "set the access token")
rootCmd.PersistentFlags().StringVar(&cachePath, "cache", fmt.Sprintf("/tmp/%s/magellan/assets.db", currentUser.Username), "set the scanning result cache path")
rootCmd.PersistentFlags().IntVar(&concurrency, "concurrency", -1, "Set the number of concurrent processes")
rootCmd.PersistentFlags().IntVar(&timeout, "timeout", 5, "Set the timeout for requests")
rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "Set the config file path")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Set to enable/disable verbose output")
rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Set to enable/disable debug messages")
rootCmd.PersistentFlags().StringVar(&accessToken, "access-token", "", "Set the access token")
rootCmd.PersistentFlags().StringVar(&cachePath, "cache", fmt.Sprintf("/tmp/%s/magellan/assets.db", currentUser.Username), "Set the scanning result cache path")
// bind viper config flags with cobra
checkBindFlagError(viper.BindPFlag("concurrency", rootCmd.PersistentFlags().Lookup("concurrency")))

View file

@ -14,16 +14,17 @@ var (
)
var versionCmd = &cobra.Command{
Use: "version",
Use: "version",
Short: "Print version info and exit",
Run: func(cmd *cobra.Command, args []string) {
if cmd.Flag("commit").Value.String() == "true" {
output = commit
if date != "" {
output += " built @ " + date
output += " built on " + date
}
fmt.Println(output)
} else {
fmt.Println(version)
fmt.Printf("%s-%s\n", version, commit)
}
},
}

View file

@ -85,11 +85,9 @@ func DeleteScannedAssets(path string, results ...magellan.RemoteAsset) error {
func GetScannedAssets(path string) ([]magellan.RemoteAsset, error) {
// check if path exists first to prevent creating the database
exists, err := util.PathExists(path)
_, exists := util.PathExists(path)
if !exists {
return nil, fmt.Errorf("no file found")
} else if err != nil {
return nil, err
}
// now check if the file is the SQLite database

View file

@ -11,13 +11,13 @@ import (
"os"
"path"
"strings"
"path/filepath"
"sync"
"time"
"github.com/OpenCHAMI/magellan/pkg/client"
"github.com/OpenCHAMI/magellan/pkg/crawler"
"github.com/OpenCHAMI/magellan/internal/util"
"github.com/rs/zerolog/log"
"github.com/Cray-HPE/hms-xname/xnames"
@ -171,25 +171,20 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams) error {
// write JSON data to file if output path is set using hive partitioning strategy
if outputPath != "" {
// make directory if it does exists
exists, err := util.PathExists(outputPath)
if err == nil && !exists {
err = os.MkdirAll(outputPath, 0o644)
var (
finalPath = fmt.Sprintf("./%s/%s/%d.json", outputPath, data["ID"], time.Now().Unix())
finalDir = filepath.Dir(finalPath)
)
// if it doesn't, make the directory and write file
err = os.MkdirAll(finalDir, 0o777)
if err == nil { // no error
err = os.WriteFile(path.Clean(finalPath), body, os.ModePerm)
if err != nil {
log.Error().Err(err).Msg("failed to make directory for output")
} else {
// make the output directory to store files
outputPath, err := util.MakeOutputDirectory(outputPath, false)
if err != nil {
log.Error().Err(err).Msg("failed to make output directory")
} else {
// write the output to the final path
err = os.WriteFile(path.Clean(fmt.Sprintf("%s/%s/%d.json", params.URI, outputPath, time.Now().Unix())), body, os.ModePerm)
if err != nil {
log.Error().Err(err).Msgf("failed to write data to file")
}
}
log.Error().Err(err).Msgf("failed to write collect output to file")
}
} else { // error is set
log.Error().Err(err).Msg("failed to make directory for collect output")
}
}

View file

@ -2,6 +2,7 @@ package util
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
@ -13,15 +14,9 @@ import (
//
// Returns whether the path exists and no error if successful,
// otherwise, it returns false with an error.
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
func PathExists(path string) (fs.FileInfo, bool) {
fi, err := os.Stat(path)
return fi, !os.IsNotExist(err)
}
// SplitPathForViper() is an utility function to split a path into 3 parts:
@ -51,17 +46,14 @@ func MakeOutputDirectory(path string, overwrite bool) (string, error) {
final := path + "/" + dirname
// check if path is valid and directory
pathExists, err := PathExists(final)
if err != nil {
return "", fmt.Errorf("failed to check for existing path: %v", err)
}
_, pathExists := PathExists(final)
if pathExists && !overwrite {
// make sure it is directory with 0o644 permissions
return "", fmt.Errorf("found existing path: %v", final)
}
// create directory with data + time
err = os.MkdirAll(final, 0766)
err := os.MkdirAll(final, 0766)
if err != nil {
return "", fmt.Errorf("failed to make directory: %v", err)
}