113 lines
3.8 KiB
Go
113 lines
3.8 KiB
Go
package setup
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"charm.land/huh/v2"
|
|
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/config"
|
|
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
|
|
)
|
|
|
|
// configureInstances edits a copy; nothing is written until the whole wizard succeeds.
|
|
func configureInstances(cfg *config.Config) ([]config.NetBoxConfig, error) {
|
|
sources := append([]config.NetBoxConfig(nil), cfg.NetBoxes...)
|
|
if len(sources) == 0 && cfg.NetBox.URL != "" {
|
|
source := cfg.NetBox
|
|
source.Name = "default"
|
|
sources = append(sources, source)
|
|
}
|
|
for {
|
|
if len(sources) == 0 {
|
|
source, err := editInstance(config.NetBoxConfig{Name: "default"}, sources, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sources = append(sources, source)
|
|
}
|
|
action := "done"
|
|
var options []huh.Option[string]
|
|
for _, source := range sources {
|
|
options = append(options, huh.NewOption("Edit "+source.Name+" ("+source.URL+")", "edit:"+source.Name))
|
|
options = append(options, huh.NewOption("Remove "+source.Name, "remove:"+source.Name))
|
|
}
|
|
options = append(options, huh.NewOption("Add another NetBox", "add"), huh.NewOption("Continue with these instances", "done"))
|
|
err := huh.NewForm(huh.NewGroup(huh.NewSelect[string]().Title("NetBox instances").Description("All configured instances are searched together.").Options(options...).Value(&action))).Run()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if action == "done" {
|
|
return sources, nil
|
|
}
|
|
if action == "add" {
|
|
source, err := editInstance(config.NetBoxConfig{}, sources, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sources = append(sources, source)
|
|
continue
|
|
}
|
|
verb, name, _ := strings.Cut(action, ":")
|
|
for i, source := range sources {
|
|
if source.Name != name {
|
|
continue
|
|
}
|
|
if verb == "edit" {
|
|
edited, err := editInstance(source, sources, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sources[i] = edited
|
|
} else {
|
|
remove := false
|
|
if err := huh.NewConfirm().Title("Remove " + name + "?").Value(&remove).Run(); err != nil {
|
|
return nil, err
|
|
}
|
|
if remove {
|
|
sources = append(sources[:i], sources[i+1:]...)
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func editInstance(source config.NetBoxConfig, sources []config.NetBoxConfig, original string) (config.NetBoxConfig, error) {
|
|
err := huh.NewForm(huh.NewGroup(
|
|
huh.NewInput().Title("Instance name").Description("Used in selectors such as office/web01.").Value(&source.Name).Validate(func(name string) error {
|
|
name = strings.ToLower(strings.TrimSpace(name))
|
|
candidate := config.Config{NetBoxes: []config.NetBoxConfig{{Name: name, URL: "https://example.invalid"}}}
|
|
if err := candidate.ValidateNetBoxes(); err != nil {
|
|
return err
|
|
}
|
|
for _, existing := range sources {
|
|
if strings.EqualFold(existing.Name, name) && !strings.EqualFold(existing.Name, original) {
|
|
return fmt.Errorf("instance name %q is already used", name)
|
|
}
|
|
}
|
|
return nil
|
|
}),
|
|
huh.NewInput().Title("NetBox URL").Placeholder("https://netbox.example.com").Value(&source.URL).Validate(func(value string) error {
|
|
return (&config.Config{NetBoxes: []config.NetBoxConfig{{Name: "instance", URL: strings.TrimSpace(value)}}}).ValidateNetBoxes()
|
|
}),
|
|
huh.NewInput().Title("NetBox API token").EchoMode(huh.EchoModePassword).Value(&source.Token).Validate(func(value string) error {
|
|
if strings.TrimSpace(value) == "" {
|
|
return fmt.Errorf("required")
|
|
}
|
|
return nil
|
|
}),
|
|
).Title("NetBox connection")).Run()
|
|
if err != nil {
|
|
return source, err
|
|
}
|
|
source.Name = strings.ToLower(strings.TrimSpace(source.Name))
|
|
source.URL = strings.TrimRight(strings.TrimSpace(source.URL), "/")
|
|
source.Token = strings.TrimSpace(source.Token)
|
|
source.TokenVersion = netbox.TokenVersion(source.Token)
|
|
if source.TokenVersion == 1 {
|
|
fmt.Fprintf(os.Stderr, "Note: NetBox %s uses a legacy v1 token. A v2 token starts with nbt_.\n", source.Name)
|
|
}
|
|
return source, nil
|
|
}
|