feat: enhance host resolution, filtering, and cache management
Release / release (push) Successful in 49s
Release / release (push) Successful in 49s
- **Strategies**: Add resolver strategy input validation and parsing in setup wizard. Support comma-separated input with known strategy mapping. - **Client**: Extend Search and SearchAll to include kind and tag filters. Add pagination for full cache refresh handling large datasets. - **Cache**: Introduce `RecentlyUsed` and `MarkUsed`. Persist `LastUsed` timestamps for entries. - **TUI**: Add recent hosts view, tag/kind filters, and inline editor for user/port override. - **Tests**: Comprehensive unit tests for new features, including strategy validation, cache behavior, and client filtering. - **Docs**: Update README with new TUI features and cache subcommands.
This commit is contained in:
+37
-11
@@ -20,13 +20,13 @@ func RunWizard(cfg *config.Config) error {
|
||||
url := cfg.NetBox.URL
|
||||
token := cfg.NetBox.Token
|
||||
defaultUser := cfg.SSH.DefaultUser
|
||||
strategies := cfg.Resolver.Strategies
|
||||
strategiesRaw := strings.Join(cfg.Resolver.Strategies, ", ")
|
||||
subnets := strings.Join(cfg.Resolver.ManagementSubnets, ", ")
|
||||
interfaceName := cfg.Resolver.InterfaceName
|
||||
cacheTTL := strconv.Itoa(cfg.Cache.TTL)
|
||||
|
||||
if len(strategies) == 0 {
|
||||
strategies = []string{"primary_ip"}
|
||||
if strategiesRaw == "" {
|
||||
strategiesRaw = "primary_ip"
|
||||
}
|
||||
if cacheTTL == "0" {
|
||||
cacheTTL = "3600"
|
||||
@@ -65,15 +65,12 @@ func RunWizard(cfg *config.Config) error {
|
||||
).Title("SSH defaults"),
|
||||
|
||||
huh.NewGroup(
|
||||
huh.NewMultiSelect[string]().
|
||||
huh.NewInput().
|
||||
Title("Resolver strategies").
|
||||
Description("Order matters: first match wins.").
|
||||
Options(
|
||||
huh.NewOption("primary_ip — NetBox primary IPv4/IPv6", "primary_ip"),
|
||||
huh.NewOption("management_subnet — first IP inside a subnet", "management_subnet"),
|
||||
huh.NewOption("interface_name — IP on a named interface", "interface_name"),
|
||||
).
|
||||
Value(&strategies),
|
||||
Description("Comma-separated, in priority order. First match wins.\nAvailable: primary_ip, management_subnet, interface_name").
|
||||
Placeholder("primary_ip, management_subnet").
|
||||
Value(&strategiesRaw).
|
||||
Validate(validateStrategies),
|
||||
huh.NewInput().
|
||||
Title("Management subnets").
|
||||
Description("Comma-separated CIDRs, e.g. 10.0.0.0/8, 192.168.0.0/16\nOnly used when management_subnet strategy is active.").
|
||||
@@ -103,6 +100,7 @@ func RunWizard(cfg *config.Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
strategies := parseStrategies(strategiesRaw)
|
||||
tokenVersion := netbox.TokenVersion(token)
|
||||
if tokenVersion == 1 {
|
||||
fmt.Fprintln(os.Stderr, "\nHinweis: Du verwendest einen Legacy-Token (v1). Erstelle in NetBox einen v2-Token (beginnt mit nbt_) für bessere Kompatibilität.")
|
||||
@@ -140,6 +138,34 @@ func RunWizard(cfg *config.Config) error {
|
||||
return save(out)
|
||||
}
|
||||
|
||||
var knownStrategies = map[string]bool{
|
||||
"primary_ip": true,
|
||||
"management_subnet": true,
|
||||
"interface_name": true,
|
||||
}
|
||||
|
||||
func validateStrategies(s string) error {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return errors.New("at least one strategy is required")
|
||||
}
|
||||
for _, name := range parseStrategies(s) {
|
||||
if !knownStrategies[name] {
|
||||
return fmt.Errorf("unknown strategy %q — available: primary_ip, management_subnet, interface_name", name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseStrategies(s string) []string {
|
||||
var out []string
|
||||
for _, part := range strings.Split(s, ",") {
|
||||
if name := strings.TrimSpace(part); name != "" {
|
||||
out = append(out, name)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func save(cfg config.Config) error {
|
||||
path := config.Path()
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user