Files
ssh-netbox-wrapper/internal/resolver/interface_name.go
T
Sebastian UnterschützandClaude Fable 5.2 4287b7b650 fix: harden config loading and ssh addresses, stop resolver on API errors
- read netssh.yaml from the user config directory only, not from the
  working directory
- refuse addresses from NetBox or the cache that are neither an IP
  address nor a hostname (ssh read "-oProxyCommand=…" as an option)
- resolver chain stops at an API failure; only "no address" falls
  through to the next strategy
- netssh --help and -h show netssh's help
- start at most one background cache refresh per 5 minutes
- validate the legacy netbox.url
- page through all IP addresses of a host
- CI: run format check, vet, and tests on pull requests and main
- changelog for v0.0.25

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-15 23:25:28 +01:00

48 lines
1.5 KiB
Go

package resolver
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
)
// InterfaceNameStrategy finds the first IP assigned to a named interface (e.g. "mgmt0", "eth0").
type InterfaceNameStrategy struct {
name string
}
func (s *InterfaceNameStrategy) Name() string { return "interface_name" }
func (s *InterfaceNameStrategy) Resolve(ctx context.Context, entry *netbox.HostEntry, client *netbox.Client) (string, error) {
// NetBox filters IP addresses by interface name with interface= (devices)
// and vminterface= (VMs); unknown parameters would be ignored silently and
// return every address of the host. A missing interface is an HTTP 400,
// which lets the chain try the next strategy.
var filterParam string
switch entry.Kind {
case "device":
filterParam = fmt.Sprintf("device_id=%d&interface=%s", entry.ID, url.QueryEscape(s.name))
case "vm":
filterParam = fmt.Sprintf("virtual_machine_id=%d&vminterface=%s", entry.ID, url.QueryEscape(s.name))
default:
return "", fmt.Errorf("unknown kind %q", entry.Kind)
}
ips, err := client.GetIPsWithFilterForHost(ctx, *entry, filterParam)
var status *netbox.StatusError
if errors.As(err, &status) && status.Code == http.StatusBadRequest {
return "", ErrNoIP // the host has no interface of this name
}
if err != nil {
return "", fmt.Errorf("fetching IPs for interface %q: %w", s.name, err)
}
if len(ips) == 0 {
return "", ErrNoIP
}
return ips[0], nil
}