Add local and NetBox server notes and improve reliability
Release / release (push) Successful in 6m52s
Release / release (push) Successful in 6m52s
This commit is contained in:
1 parent
2852dff2c4
commit
12cc64fdd9
17 files changed
+848
-83
No files matched your search
@@ -0,0 +1,71 @@
|
||||
// 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
|
||||
}
|
||||
data, err := os.ReadFile(s.path(host))
|
||||
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)
|
||||
}
|
||||
return storage.WriteFile(s.path(note.Host), []byte(note.Text), 0o600)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package notes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.zb-server.de/Sebi/ssh-netbox-wrapper/internal/netbox"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalNotesPersistAndStayIsolated(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s := &Service{Dir: t.TempDir(), Namespace: "https://netbox.example"}
|
||||
host := netbox.HostEntry{Name: "web01", Kind: "device"}
|
||||
n := Note{Host: host, Text: "Wartung\nGrüße 🔧"}
|
||||
if err := s.Write(ctx, n, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reloaded := &Service{Dir: s.Dir, Namespace: s.Namespace}
|
||||
got, err := reloaded.Read(ctx, host, false)
|
||||
if err != nil || got.Text != n.Text {
|
||||
t.Fatalf("round trip: %+v, %v", got, err)
|
||||
}
|
||||
info, err := os.Stat(s.path(host))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if info.Mode().Perm() != 0o600 {
|
||||
t.Fatalf("permissions: %v", info.Mode())
|
||||
}
|
||||
host.Kind = "vm"
|
||||
got, err = s.Read(ctx, host, false)
|
||||
if err != nil || got.Text != "" {
|
||||
t.Fatalf("kind isolation: %+v, %v", got, err)
|
||||
}
|
||||
host.Kind = "device"
|
||||
reloaded.Namespace = "https://other.example"
|
||||
got, err = reloaded.Read(ctx, host, false)
|
||||
if err != nil || got.Text != "" {
|
||||
t.Fatalf("instance isolation: %+v, %v", got, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnreadableNoteIsNotTreatedAsEmpty(t *testing.T) {
|
||||
s := &Service{Dir: t.TempDir()}
|
||||
host := netbox.HostEntry{Name: "web01", Kind: "vm"}
|
||||
if err := os.Mkdir(s.path(host), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.Read(context.Background(), host, false); err == nil {
|
||||
t.Fatal("expected read error")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user