Files
ssh-netbox-wrapper/internal/notes/notes.go
2026-10-27 23:14:42 +01:00

93 lines
2.2 KiB
Go

// Package notes stores private server notes independently of the host cache.
package notes
import (
"context"
"crypto/sha256"
"fmt"
"os"
"path/filepath"
"strings"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/storage"
)
type Note struct {
Text, ETag string
Host netbox.HostEntry
}
type Service struct {
Dir, Namespace string
Client *netbox.Client
}
func New(namespace string, client *netbox.Client) *Service {
dir, err := os.UserConfigDir()
if err != nil {
dir = filepath.Join(os.Getenv("HOME"), ".config")
}
return &Service{Dir: filepath.Join(dir, "netssh", "notes"), Namespace: strings.TrimRight(namespace, "/"), Client: client}
}
func (s *Service) path(host netbox.HostEntry) string {
key := fmt.Sprintf("%s\x00%s\x00%s", s.Namespace, host.Kind, strings.ToLower(host.Name))
return filepath.Join(s.Dir, fmt.Sprintf("%x.txt", sha256.Sum256([]byte(key))))
}
func (s *Service) Read(ctx context.Context, host netbox.HostEntry, remote bool) (Note, error) {
note := Note{Host: host}
if remote {
if s.Client == nil {
return note, fmt.Errorf("NetBox is not configured")
}
if host.ID == 0 {
resolved, err := s.Client.FindHost(ctx, host.Name, host.Kind)
if err != nil {
return note, err
}
note.Host = resolved
}
var err error
note.Text, note.ETag, err = s.Client.GetComments(ctx, note.Host)
return note, err
}
path, err := s.localPath(host)
if err != nil {
return note, err
}
data, err := os.ReadFile(path)
if os.IsNotExist(err) {
return note, nil
}
note.Text = string(data)
return note, err
}
func (s *Service) Write(ctx context.Context, note Note, remote bool) error {
if remote {
if s.Client == nil {
return fmt.Errorf("NetBox is not configured")
}
return s.Client.SetComments(ctx, note.Host, note.Text, note.ETag)
}
path, err := s.localPath(note.Host)
if err != nil {
return err
}
return storage.WriteFile(path, []byte(note.Text), 0o600)
}
func (s *Service) localPath(host netbox.HostEntry) (string, error) {
if s.Client == nil {
return s.path(host), nil
}
host, namespace, err := s.Client.HostScope(host)
if err != nil {
return "", err
}
scoped := *s
scoped.Namespace = namespace
return scoped.path(host), nil
}