Files
ssh-netbox-wrapper/cmd/netssh/notes.go
T
2026-10-27 17:51:59 +01:00

94 lines
2.7 KiB
Go

package main
import (
"context"
"fmt"
"io"
"strings"
"time"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/cache"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/config"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/notes"
"github.com/spf13/cobra"
)
func notesCmd() *cobra.Command {
var remote bool
var kind string
cmd := &cobra.Command{Use: "notes", Short: "Read and write server notes (local by default)"}
cmd.PersistentFlags().BoolVar(&remote, "netbox", false, "Use the NetBox comments field instead of local notes")
cmd.PersistentFlags().StringVar(&kind, "kind", "", "Host kind: device or vm (required for uncached local hosts)")
for _, action := range []string{"show", "set", "append"} {
sub := &cobra.Command{Use: action + " <host> [text]", Short: action + " a server note", Args: cobra.RangeArgs(1, 2)}
if action == "show" {
sub.Args = cobra.ExactArgs(1)
}
sub.RunE = func(cmd *cobra.Command, args []string) error {
if kind != "" && kind != "vm" && kind != "device" {
return fmt.Errorf("invalid kind %q", kind)
}
cfg, err := config.Load()
if err != nil {
return err
}
var client *netbox.Client
if cfg.NetBox.URL != "" {
client = netbox.NewClient(cfg.NetBox.URL, cfg.NetBox.Token, cfg.NetBox.TokenVersion)
}
host := netbox.HostEntry{Name: args[0], Kind: kind}
c := cache.New(cfg.Cache.Path, cfg.Cache.TTL)
if err := c.Load(); err != nil {
return err
}
var cached []cache.Entry
if !remote {
cached = c.All()
}
for _, entry := range cached {
if strings.EqualFold(entry.Name, host.Name) && (kind == "" || kind == entry.Kind) {
host.Name = entry.Name
host.Kind = entry.Kind
break
}
}
if !remote && host.Kind == "" {
return fmt.Errorf("host is not cached; specify --kind device or --kind vm")
}
ctx, cancel := context.WithTimeout(cmd.Context(), 20*time.Second)
defer cancel()
service := notes.New(cfg.NetBox.URL, client)
note, err := service.Read(ctx, host, remote)
if err != nil {
return err
}
if action == "show" {
_, err := fmt.Fprint(cmd.OutOrStdout(), note.Text)
return err
}
var text string
if len(args) == 2 {
text = args[1]
} else {
data, err := io.ReadAll(io.LimitReader(cmd.InOrStdin(), 1024*1024+1))
if err != nil {
return err
}
if len(data) > 1024*1024 {
return fmt.Errorf("note exceeds 1 MiB")
}
text = string(data)
}
if action == "append" && note.Text != "" {
note.Text = strings.TrimRight(note.Text, "\n") + "\n" + text
} else {
note.Text = text
}
return service.Write(ctx, note, remote)
}
cmd.AddCommand(sub)
}
return cmd
}