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>
70 lines
2.0 KiB
Go
70 lines
2.0 KiB
Go
package shortcuts
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
|
|
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/config"
|
|
)
|
|
|
|
// compiled caches rewrite patterns: Normalize runs for every cache entry on each lookup.
|
|
var compiled sync.Map // pattern → *regexp.Regexp
|
|
|
|
func rewritePattern(pattern string) *regexp.Regexp {
|
|
if re, ok := compiled.Load(pattern); ok {
|
|
return re.(*regexp.Regexp)
|
|
}
|
|
re, err := regexp.Compile(pattern)
|
|
if err != nil {
|
|
return nil // rejected by config.Load already
|
|
}
|
|
compiled.Store(pattern, re)
|
|
return re
|
|
}
|
|
|
|
// Normalize strips configured domain suffixes, applies rewrite rules in order, and
|
|
// optionally strips hyphens. The result is lowercased for case-insensitive comparison.
|
|
func Normalize(name string, cfg config.ShortcutsConfig) string {
|
|
s := strings.ToLower(name)
|
|
for _, domain := range cfg.Domains {
|
|
suffix := strings.ToLower(domain)
|
|
if !strings.HasPrefix(suffix, ".") {
|
|
suffix = "." + suffix
|
|
}
|
|
if strings.HasSuffix(s, suffix) {
|
|
s = s[:len(s)-len(suffix)]
|
|
break
|
|
}
|
|
}
|
|
for _, rewrite := range cfg.Rewrites {
|
|
if re := rewritePattern(rewrite.Pattern); re != nil {
|
|
s = re.ReplaceAllString(s, rewrite.Replace)
|
|
}
|
|
}
|
|
if cfg.StripHyphens {
|
|
s = strings.ReplaceAll(s, "-", "")
|
|
}
|
|
return s
|
|
}
|
|
|
|
// MakeNormalizer returns a closure bound to cfg, suitable for Cache.GetByShortcut.
|
|
func MakeNormalizer(cfg config.ShortcutsConfig) func(string) string {
|
|
return func(name string) string {
|
|
return Normalize(name, cfg)
|
|
}
|
|
}
|
|
|
|
// AliasName returns a shell-safe alias name for the given host.
|
|
// It normalizes the name (strips configured domains, applies rewrites, optionally strips hyphens) then
|
|
// replaces any remaining dots with underscores so the result is a valid identifier.
|
|
func AliasName(name string, cfg config.ShortcutsConfig) string {
|
|
// Shorten only the hostname: anchored rewrite rules must not see "instance/".
|
|
prefix := ""
|
|
if source, host, ok := strings.Cut(name, "/"); ok {
|
|
prefix, name = strings.ToLower(source)+"_", host
|
|
}
|
|
s := prefix + Normalize(name, cfg)
|
|
return strings.NewReplacer(".", "_", "/", "_").Replace(s)
|
|
}
|