mirror of
https://github.com/davidallendj/magellan.git
synced 2025-12-20 03:27:03 -07:00
Added initial round of comments for API documentation
This commit is contained in:
parent
796a67d5ab
commit
1ab5c8a7df
5 changed files with 114 additions and 13 deletions
|
|
@ -18,6 +18,9 @@ var (
|
|||
forceUpdate bool
|
||||
)
|
||||
|
||||
// The `collect` command fetches data from a collection of BMC nodes.
|
||||
// This command should be ran after the `scan` to find available hosts
|
||||
// on a subnet.
|
||||
var collectCmd = &cobra.Command{
|
||||
Use: "collect",
|
||||
Short: "Query information about BMC",
|
||||
|
|
|
|||
39
cmd/root.go
39
cmd/root.go
|
|
@ -1,3 +1,17 @@
|
|||
// The cmd package implements the interface for the magellan CLI. The files
|
||||
// contained in this package only contains implementations for handling CLI
|
||||
// arguments and passing them to functions within magellan's internal API.
|
||||
//
|
||||
// Each CLI subcommand will have at least one corresponding internal file
|
||||
// with an API routine that implements the command's functionality. The main
|
||||
// API routine will usually be the first function defined in the fill.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// cmd/scan.go --> internal/scan.go ( magellan.ScanForAssets() )
|
||||
// cmd/collect.go --> internal/collect.go ( magellan.CollectAll() )
|
||||
// cmd/list.go --> none (doesn't have API call since it's simple)
|
||||
// cmd/update.go --> internal/update.go ( magellan.UpdateFirmware() )
|
||||
package cmd
|
||||
|
||||
import (
|
||||
|
|
@ -30,11 +44,8 @@ var (
|
|||
verbose bool
|
||||
)
|
||||
|
||||
// TODO: discover bmc's on network (dora)
|
||||
// TODO: query bmc component information and store in db (?)
|
||||
// TODO: send bmc component information to smd
|
||||
// TODO: set ports to scan automatically with set driver
|
||||
|
||||
// The `root` command doesn't do anything on it's own except display
|
||||
// a help message and then exits.
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "magellan",
|
||||
Short: "Tool for BMC discovery",
|
||||
|
|
@ -47,6 +58,7 @@ var rootCmd = &cobra.Command{
|
|||
},
|
||||
}
|
||||
|
||||
// This Execute() function is called from main to run the CLI.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
|
@ -54,6 +66,14 @@ func Execute() {
|
|||
}
|
||||
}
|
||||
|
||||
// LoadAccessToken() tries to load a JWT string from an environment
|
||||
// variable, file, or config in that order. If loading the token
|
||||
// fails with one options, it will fallback to the next option until
|
||||
// all options are exhausted.
|
||||
//
|
||||
// Returns a token as a string with no error if successful.
|
||||
// Alternatively, returns an empty string with an error if a token is
|
||||
// not able to be loaded.
|
||||
func LoadAccessToken() (string, error) {
|
||||
// try to load token from env var
|
||||
testToken := os.Getenv("MAGELLAN_ACCESS_TOKEN")
|
||||
|
|
@ -93,12 +113,21 @@ func init() {
|
|||
viper.BindPFlags(rootCmd.Flags())
|
||||
}
|
||||
|
||||
// InitializeConfig() initializes a new config object by loading it
|
||||
// from a file given a non-empty string.
|
||||
//
|
||||
// See the 'LoadConfig' function in 'internal/config' for details.
|
||||
func InitializeConfig() {
|
||||
if configPath != "" {
|
||||
magellan.LoadConfig(configPath)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDefaults() resets all of the viper properties back to their
|
||||
// default values.
|
||||
//
|
||||
// TODO: This function should probably be moved to 'internal/config.go'
|
||||
// instead of in this file.
|
||||
func SetDefaults() {
|
||||
viper.SetDefault("threads", 1)
|
||||
viper.SetDefault("timeout", 30)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ var (
|
|||
disableProbing bool
|
||||
)
|
||||
|
||||
// The `scan` command is usually the first step to using the CLI tool.
|
||||
// This command will perform a network scan over a subnet by supplying
|
||||
// a list of subnets, subnet masks, and additional IP address to probe.
|
||||
//
|
||||
// See the `ScanForAssets()` function in 'internal/scan.go' for details
|
||||
// related to the implementation.
|
||||
var scanCmd = &cobra.Command{
|
||||
Use: "scan",
|
||||
Short: "Scan for BMC nodes on a network",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Package magellan implements the core routines for the tools.
|
||||
package magellan
|
||||
|
||||
import (
|
||||
|
|
@ -50,6 +51,11 @@ type QueryParams struct {
|
|||
AccessToken string
|
||||
}
|
||||
|
||||
// This is the main function used to collect information from the BMC nodes via Redfish.
|
||||
// The function expects a list of hosts found using the `ScanForAssets()` function.
|
||||
//
|
||||
// Requests can be made to several of the nodes using a goroutine by setting the q.Concurrency
|
||||
// property value between 1 and 255.
|
||||
func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) error {
|
||||
// check for available probe states
|
||||
if probeStates == nil {
|
||||
|
|
@ -102,6 +108,7 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err
|
|||
if err != nil {
|
||||
l.Log.Errorf("failed to connect to BMC (%v:%v): %v", q.Host, q.Port, err)
|
||||
}
|
||||
defer gofishClient.Logout()
|
||||
|
||||
// data to be sent to smd
|
||||
data := map[string]any{
|
||||
|
|
@ -218,6 +225,7 @@ func CollectAll(probeStates *[]ScannedResult, l *log.Logger, q *QueryParams) err
|
|||
return nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectMetadata(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
||||
// open BMC session and update driver registry
|
||||
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout))
|
||||
|
|
@ -275,6 +283,7 @@ func CollectInventory(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectPowerState(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
||||
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout))
|
||||
client.Registry.FilterForCompatible(ctx)
|
||||
|
|
@ -303,6 +312,7 @@ func CollectPowerState(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
|||
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectUsers(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
||||
// open BMC session and update driver registry
|
||||
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*time.Duration(q.Timeout))
|
||||
|
|
@ -333,11 +343,18 @@ func CollectUsers(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!q
|
||||
|
||||
func CollectBios(client *bmclib.Client, q *QueryParams) ([]byte, error) {
|
||||
b, err := makeRequest(client, client.GetBiosConfiguration, q.Timeout)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// CollectEthernetInterfaces() collects all of the ethernet interfaces found
|
||||
// from all systems from under the "/redfish/v1/Systems" endpoint.
|
||||
//
|
||||
// TODO: This function needs to be refactored entirely...if not deleted
|
||||
// in favor of using crawler.CrawlBM() instead.
|
||||
func CollectEthernetInterfaces(c *gofish.APIClient, q *QueryParams, systemID string) ([]byte, error) {
|
||||
// TODO: add more endpoints to test for ethernet interfaces
|
||||
// /redfish/v1/Chassis/{ChassisID}/NetworkAdapters/{NetworkAdapterId}/NetworkDeviceFunctions/{NetworkDeviceFunctionId}/EthernetInterfaces/{EthernetInterfaceId}
|
||||
|
|
@ -380,6 +397,7 @@ func CollectEthernetInterfaces(c *gofish.APIClient, q *QueryParams, systemID str
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectChassis(c *gofish.APIClient, q *QueryParams) ([]map[string]any, error) {
|
||||
rfChassis, err := c.Service.Chassis()
|
||||
if err != nil {
|
||||
|
|
@ -402,6 +420,7 @@ func CollectChassis(c *gofish.APIClient, q *QueryParams) ([]map[string]any, erro
|
|||
return chassis, nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectStorage(c *gofish.APIClient, q *QueryParams) ([]byte, error) {
|
||||
systems, err := c.Service.StorageSystems()
|
||||
if err != nil {
|
||||
|
|
@ -427,19 +446,23 @@ func CollectStorage(c *gofish.APIClient, q *QueryParams) ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// CollectSystems pulls system information from each BMC node via Redfish using the
|
||||
// `gofish` library.
|
||||
//
|
||||
// The process of collecting this info is as follows:
|
||||
// 1. check if system has ethernet interfaces
|
||||
// 1.a. if yes, create system data and ethernet interfaces JSON
|
||||
// 1.b. if no, try to get data using manager instead
|
||||
// 2. check if manager has "ManagerForServices" and "EthernetInterfaces" properties
|
||||
// 2.a. if yes, query both properties to use in next step
|
||||
// 2.b. for each service, query its data and add the ethernet interfaces
|
||||
// 2.c. add the system to list of systems to marshal and return
|
||||
func CollectSystems(c *gofish.APIClient, q *QueryParams) ([]map[string]any, error) {
|
||||
rfSystems, err := c.Service.Systems()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get systems (%v:%v): %v", q.Host, q.Port, err)
|
||||
}
|
||||
|
||||
// 1. check if system has ethernet interfaces
|
||||
// 1.a. if yes, create system data and ethernet interfaces JSON
|
||||
// 1.b. if no, try to get data using manager instead
|
||||
// 2. check if manager has "ManagerForServices" and "EthernetInterfaces" properties
|
||||
// 2.a. if yes, query both properties to use in next step
|
||||
// 2.b. for each service, query its data and add the ethernet interfaces
|
||||
// 2.c. add the system to list of systems to marshal and return
|
||||
var systems []map[string]any
|
||||
|
||||
for _, system := range rfSystems {
|
||||
|
|
@ -605,6 +628,7 @@ func CollectSystems(c *gofish.APIClient, q *QueryParams) ([]map[string]any, erro
|
|||
return systems, nil
|
||||
}
|
||||
|
||||
// TODO: DELETE ME!!!
|
||||
func CollectRegisteries(c *gofish.APIClient, q *QueryParams) ([]byte, error) {
|
||||
registries, err := c.Service.Registries()
|
||||
if err != nil {
|
||||
|
|
@ -620,6 +644,7 @@ func CollectRegisteries(c *gofish.APIClient, q *QueryParams) ([]byte, error) {
|
|||
return b, nil
|
||||
}
|
||||
|
||||
// TODO: MAYBE DELETE???
|
||||
func CollectProcessors(q *QueryParams) ([]byte, error) {
|
||||
url := baseRedfishUrl(q) + "/Systems"
|
||||
res, body, err := util.MakeRequest(nil, url, "GET", nil, nil)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// PathExists() is a wrapper function that simplifies checking
|
||||
// if a file or directory already exists at the provided path.
|
||||
//
|
||||
// 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 {
|
||||
|
|
@ -24,6 +29,8 @@ func PathExists(path string) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
|
||||
// GetNextIP() returns the next IP address, but does not account
|
||||
// for net masks.
|
||||
func GetNextIP(ip *net.IP, inc uint) *net.IP {
|
||||
if ip == nil {
|
||||
return &net.IP{}
|
||||
|
|
@ -40,7 +47,14 @@ func GetNextIP(ip *net.IP, inc uint) *net.IP {
|
|||
return &r
|
||||
}
|
||||
|
||||
// Generic convenience function used to make HTTP requests.
|
||||
// MakeRequest() is a wrapper function that condenses simple HTTP
|
||||
// requests done to a single call. It expects an optional HTTP client,
|
||||
// URL, HTTP method, request body, and request headers. This function
|
||||
// is useful when making many requests where only these few arguments
|
||||
// are changing.
|
||||
//
|
||||
// Returns a HTTP response object, response body as byte array, and any
|
||||
// error that may have occurred with making the request.
|
||||
func MakeRequest(client *http.Client, url string, httpMethod string, body []byte, headers map[string]string) (*http.Response, []byte, error) {
|
||||
// use defaults if no client provided
|
||||
if client == nil {
|
||||
|
|
@ -69,6 +83,12 @@ func MakeRequest(client *http.Client, url string, httpMethod string, body []byte
|
|||
return res, b, err
|
||||
}
|
||||
|
||||
// MakeOutputDirectory() creates a new directory at the path argument if
|
||||
// the path does not exist
|
||||
//
|
||||
// TODO: Refactor this function for hive partitioning or possibly move into
|
||||
// the logging package.
|
||||
// TODO: Add an option to force overwriting the path.
|
||||
func MakeOutputDirectory(path string) (string, error) {
|
||||
// get the current data + time using Go's stupid formatting
|
||||
t := time.Now()
|
||||
|
|
@ -93,12 +113,27 @@ func MakeOutputDirectory(path string) (string, error) {
|
|||
return final, nil
|
||||
}
|
||||
|
||||
// SplitPathForViper() is an utility function to split a path into 3 parts:
|
||||
// - directory
|
||||
// - filename
|
||||
// - extension
|
||||
// The intent was to break a path into a format that's more easily consumable
|
||||
// by spf13/viper's API. See the "LoadConfig()" function in internal/config.go
|
||||
// for more details.
|
||||
//
|
||||
// TODO: Rename function to something more generalized.
|
||||
func SplitPathForViper(path string) (string, string, string) {
|
||||
filename := filepath.Base(path)
|
||||
ext := filepath.Ext(filename)
|
||||
return filepath.Dir(path), strings.TrimSuffix(filename, ext), strings.TrimPrefix(ext, ".")
|
||||
}
|
||||
|
||||
// FormatErrorList() is a wrapper function that unifies error list formatting
|
||||
// and makes printing error lists consistent.
|
||||
//
|
||||
// NOTE: The error returned IS NOT an error in itself and may be a bit misleading.
|
||||
// Instead, it is a single condensed error composed of all of the errors included
|
||||
// in the errList argument.
|
||||
func FormatErrorList(errList []error) error {
|
||||
var err error
|
||||
for i, e := range errList {
|
||||
|
|
@ -108,6 +143,9 @@ func FormatErrorList(errList []error) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// HasErrors() is a simple wrapper function to check if an error list contains
|
||||
// errors. Having a function that clearly states its purpose helps to improve
|
||||
// readibility although it may seem pointless.
|
||||
func HasErrors(errList []error) bool {
|
||||
return len(errList) > 0
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue