mirror of
https://github.com/davidallendj/magellan.git
synced 2025-12-20 03:27:03 -07:00
chore: small changes, fixes, and refactor
This commit is contained in:
parent
2491c6bd1c
commit
a62f74dbdd
11 changed files with 105 additions and 125 deletions
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/cznic/mathutil"
|
"github.com/cznic/mathutil"
|
||||||
"github.com/davidallendj/magellan/internal/cache/sqlite"
|
"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"
|
magellan "github.com/davidallendj/magellan/pkg"
|
||||||
"github.com/davidallendj/magellan/pkg/auth"
|
"github.com/davidallendj/magellan/pkg/auth"
|
||||||
"github.com/davidallendj/magellan/pkg/bmc"
|
"github.com/davidallendj/magellan/pkg/bmc"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
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/bmc"
|
||||||
"github.com/davidallendj/magellan/pkg/crawler"
|
"github.com/davidallendj/magellan/pkg/crawler"
|
||||||
"github.com/davidallendj/magellan/pkg/secrets"
|
"github.com/davidallendj/magellan/pkg/secrets"
|
||||||
|
|
@ -101,7 +101,7 @@ func init() {
|
||||||
CrawlCmd.Flags().StringVarP(&username, "username", "u", "", "Set the username for the BMC")
|
CrawlCmd.Flags().StringVarP(&username, "username", "u", "", "Set the username for the BMC")
|
||||||
CrawlCmd.Flags().StringVarP(&password, "password", "p", "", "Set the password for the BMC")
|
CrawlCmd.Flags().StringVarP(&password, "password", "p", "", "Set the password for the BMC")
|
||||||
CrawlCmd.Flags().BoolVarP(&insecure, "insecure", "i", false, "Ignore SSL errors")
|
CrawlCmd.Flags().BoolVarP(&insecure, "insecure", "i", false, "Ignore SSL errors")
|
||||||
CrawlCmd.Flags().StringVarP(&secretsFile, "file", "f", "nodes.json", "set the secrets file with BMC credentials")
|
CrawlCmd.Flags().StringVarP(&secretsFile, "secrets-file", "f", "secrets.json", "set the secrets file with BMC credentials")
|
||||||
|
|
||||||
checkBindFlagError(viper.BindPFlag("crawl.insecure", CrawlCmd.Flags().Lookup("insecure")))
|
checkBindFlagError(viper.BindPFlag("crawl.insecure", CrawlCmd.Flags().Lookup("insecure")))
|
||||||
|
|
||||||
|
|
|
||||||
43
cmd/root.go
43
cmd/root.go
|
|
@ -21,6 +21,8 @@ import (
|
||||||
"os/user"
|
"os/user"
|
||||||
|
|
||||||
magellan "github.com/davidallendj/magellan/internal"
|
magellan "github.com/davidallendj/magellan/internal"
|
||||||
|
"github.com/davidallendj/magellan/pkg/bmc"
|
||||||
|
"github.com/davidallendj/magellan/pkg/secrets"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
@ -147,3 +149,44 @@ func SetDefaults() {
|
||||||
viper.SetDefault("update.status", false)
|
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/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/cznic/mathutil"
|
"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/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -128,9 +128,7 @@ func init() {
|
||||||
checkBindFlagError(viper.BindPFlag("update.username", UpdateCmd.Flags().Lookup("username")))
|
checkBindFlagError(viper.BindPFlag("update.username", UpdateCmd.Flags().Lookup("username")))
|
||||||
checkBindFlagError(viper.BindPFlag("update.password", UpdateCmd.Flags().Lookup("password")))
|
checkBindFlagError(viper.BindPFlag("update.password", UpdateCmd.Flags().Lookup("password")))
|
||||||
checkBindFlagError(viper.BindPFlag("update.scheme", UpdateCmd.Flags().Lookup("scheme")))
|
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-uri", UpdateCmd.Flags().Lookup("firmware-uri")))
|
||||||
checkBindFlagError(viper.BindPFlag("update.firmware-version", UpdateCmd.Flags().Lookup("firmware-version")))
|
|
||||||
checkBindFlagError(viper.BindPFlag("update.component", UpdateCmd.Flags().Lookup("component")))
|
|
||||||
checkBindFlagError(viper.BindPFlag("update.status", UpdateCmd.Flags().Lookup("status")))
|
checkBindFlagError(viper.BindPFlag("update.status", UpdateCmd.Flags().Lookup("status")))
|
||||||
|
|
||||||
rootCmd.AddCommand(UpdateCmd)
|
rootCmd.AddCommand(UpdateCmd)
|
||||||
|
|
|
||||||
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,116 +0,0 @@
|
||||||
package url
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Sanitize(uri string) (string, error) {
|
|
||||||
// URL sanitanization for host argument
|
|
||||||
parsedURI, err := url.ParseRequestURI(uri)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to parse URI: %w", err)
|
|
||||||
}
|
|
||||||
// Remove any trailing slashes
|
|
||||||
parsedURI.Path = strings.TrimSuffix(parsedURI.Path, "/")
|
|
||||||
// Collapse any doubled slashes
|
|
||||||
parsedURI.Path = strings.ReplaceAll(parsedURI.Path, "//", "/")
|
|
||||||
return parsedURI.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatHosts() takes a list of hosts and ports and builds full URLs in the
|
|
||||||
// form of scheme://host:port. If no scheme is provided, it will use "https" by
|
|
||||||
// default.
|
|
||||||
//
|
|
||||||
// Returns a 2D string slice where each slice contains URL host strings for each
|
|
||||||
// port. The intention is to have all of the URLs for a single host combined into
|
|
||||||
// a single slice to initiate one goroutine per host, but making request to multiple
|
|
||||||
// ports.
|
|
||||||
func FormatHosts(hosts []string, ports []int, scheme string, verbose bool) [][]string {
|
|
||||||
// format each positional arg as a complete URL
|
|
||||||
var formattedHosts [][]string
|
|
||||||
for _, host := range hosts {
|
|
||||||
uri, err := url.ParseRequestURI(host)
|
|
||||||
if err != nil {
|
|
||||||
if verbose {
|
|
||||||
log.Warn().Msgf("invalid URI parsed: %s", host)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if scheme is set, if not set it with flag or default value ('https' if flag is not set)
|
|
||||||
if uri.Scheme == "" {
|
|
||||||
if scheme != "" {
|
|
||||||
uri.Scheme = scheme
|
|
||||||
} else {
|
|
||||||
// hardcoded assumption
|
|
||||||
uri.Scheme = "https"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tidy up slashes and update arg with new value
|
|
||||||
uri.Path = strings.TrimSuffix(uri.Path, "/")
|
|
||||||
uri.Path = strings.ReplaceAll(uri.Path, "//", "/")
|
|
||||||
|
|
||||||
// for hosts with unspecified ports, add ports to scan from flag
|
|
||||||
if uri.Port() == "" {
|
|
||||||
var tmp []string
|
|
||||||
for _, port := range ports {
|
|
||||||
uri.Host += fmt.Sprintf(":%d", port)
|
|
||||||
tmp = append(tmp, uri.String())
|
|
||||||
}
|
|
||||||
formattedHosts = append(formattedHosts, tmp)
|
|
||||||
} else {
|
|
||||||
formattedHosts = append(formattedHosts, []string{uri.String()})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return formattedHosts
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatIPs() takes a list of IP addresses and ports and builds full URLs in the
|
|
||||||
// form of scheme://host:port. If no scheme is provided, it will use "https" by
|
|
||||||
// default.
|
|
||||||
//
|
|
||||||
// Returns a 2D string slice where each slice contains URL host strings for each
|
|
||||||
// port. The intention is to have all of the URLs for a single host combined into
|
|
||||||
// a single slice to initiate one goroutine per host, but making request to multiple
|
|
||||||
// ports.
|
|
||||||
func FormatIPs(ips []string, ports []int, scheme string, verbose bool) [][]string {
|
|
||||||
// format each positional arg as a complete URL
|
|
||||||
var formattedHosts [][]string
|
|
||||||
for _, ip := range ips {
|
|
||||||
if scheme == "" {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
// make an entirely new object since we're expecting just IPs
|
|
||||||
uri := &url.URL{
|
|
||||||
Scheme: scheme,
|
|
||||||
Host: ip,
|
|
||||||
}
|
|
||||||
|
|
||||||
// tidy up slashes and update arg with new value
|
|
||||||
uri.Path = strings.ReplaceAll(uri.Path, "//", "/")
|
|
||||||
uri.Path = strings.TrimSuffix(uri.Path, "/")
|
|
||||||
|
|
||||||
// for hosts with unspecified ports, add ports to scan from flag
|
|
||||||
if uri.Port() == "" {
|
|
||||||
if len(ports) == 0 {
|
|
||||||
ports = append(ports, 443)
|
|
||||||
}
|
|
||||||
var tmp []string
|
|
||||||
for _, port := range ports {
|
|
||||||
uri.Host += fmt.Sprintf(":%d", port)
|
|
||||||
tmp = append(tmp, uri.String())
|
|
||||||
}
|
|
||||||
formattedHosts = append(formattedHosts, tmp)
|
|
||||||
} else {
|
|
||||||
formattedHosts = append(formattedHosts, []string{uri.String()})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return formattedHosts
|
|
||||||
}
|
|
||||||
|
|
@ -14,6 +14,9 @@ type BMCCredentials struct {
|
||||||
|
|
||||||
func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error) {
|
func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error) {
|
||||||
var creds BMCCredentials
|
var creds BMCCredentials
|
||||||
|
if store == nil {
|
||||||
|
return creds, fmt.Errorf("invalid secrets store")
|
||||||
|
}
|
||||||
if strCreds, err := store.GetSecretByID(secrets.DEFAULT_KEY); err != nil {
|
if strCreds, err := store.GetSecretByID(secrets.DEFAULT_KEY); err != nil {
|
||||||
return creds, fmt.Errorf("get default BMC credentials from secret store: %w", err)
|
return creds, fmt.Errorf("get default BMC credentials from secret store: %w", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -27,6 +30,9 @@ func GetBMCCredentialsDefault(store secrets.SecretStore) (BMCCredentials, error)
|
||||||
|
|
||||||
func GetBMCCredentials(store secrets.SecretStore, id string) (BMCCredentials, error) {
|
func GetBMCCredentials(store secrets.SecretStore, id string) (BMCCredentials, error) {
|
||||||
var creds BMCCredentials
|
var creds BMCCredentials
|
||||||
|
if store == nil {
|
||||||
|
return creds, fmt.Errorf("invalid secrets store")
|
||||||
|
}
|
||||||
if strCreds, err := store.GetSecretByID(id); err != nil {
|
if strCreds, err := store.GetSecretByID(id); err != nil {
|
||||||
return creds, fmt.Errorf("get BMC credentials from secret store: %w", err)
|
return creds, fmt.Errorf("get BMC credentials from secret store: %w", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -375,7 +375,7 @@ func loadBMCCreds(config CrawlerConfig) (bmc.BMCCredentials, error) {
|
||||||
return bmc.BMCCredentials{}, fmt.Errorf("credential store is invalid")
|
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 == (bmc.BMCCredentials{}) {
|
||||||
return creds, fmt.Errorf("%s: credentials blank for BNC", config.URI)
|
return creds, fmt.Errorf("%s: credentials blank for BMC", config.URI)
|
||||||
} else {
|
} else {
|
||||||
return creds, nil
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
urlx "github.com/davidallendj/magellan/internal/url"
|
urlx "github.com/davidallendj/magellan/internal/urlx"
|
||||||
"github.com/davidallendj/magellan/pkg/client"
|
"github.com/davidallendj/magellan/pkg/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue