Found by the new Docker test environment against a real NetBox 4.7: - The interface_name strategy filtered IP addresses with interface_name and vminterface_name, which NetBox ignores, so it returned the first address of the host instead of the named interface's. Use the real filters interface and vminterface; a missing interface (HTTP 400) falls through to the next strategy. - sftp and scp took instance-qualified hosts (prod/web01:/path) for local paths, because a "/" comes before the ":". Such arguments are remote when the prefix is a configured NetBox instance. - Shell aliases of instance-qualified hosts ran the shortcut rules on "instance/host", so anchored rewrite rules never matched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
42 lines
1.3 KiB
Go
42 lines
1.3 KiB
Go
package resolver
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"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)
|
|
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
|
|
}
|