feat(go): advance validation sidecar toward production
This commit is contained in:
parent
6a06eba255
commit
f85c2e831a
92 changed files with 8881 additions and 91 deletions
49
go-agent/internal/sdnotify/notify.go
Normal file
49
go-agent/internal/sdnotify/notify.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Package sdnotify implements the small systemd notification subset needed by
|
||||
// the service binary without adding a runtime dependency.
|
||||
package sdnotify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Notifier sends state records to the socket inherited from systemd. An empty
|
||||
// socket makes Notify a no-op so the agent behaves identically outside a unit.
|
||||
type Notifier struct {
|
||||
socket string
|
||||
}
|
||||
|
||||
// FromEnvironment returns a notifier for systemd's NOTIFY_SOCKET contract.
|
||||
func FromEnvironment() Notifier {
|
||||
return New(os.Getenv("NOTIFY_SOCKET"))
|
||||
}
|
||||
|
||||
// New constructs a notifier for an explicit socket, primarily for tests.
|
||||
func New(socket string) Notifier {
|
||||
return Notifier{socket: socket}
|
||||
}
|
||||
|
||||
// Notify sends one newline-delimited systemd state record.
|
||||
func (n Notifier) Notify(state string) error {
|
||||
if n.socket == "" {
|
||||
return nil
|
||||
}
|
||||
if state == "" || strings.ContainsRune(state, '\x00') {
|
||||
return fmt.Errorf("invalid empty or NUL-containing notification")
|
||||
}
|
||||
connection, err := net.DialUnix(
|
||||
"unixgram", nil, &net.UnixAddr{Name: n.socket, Net: "unixgram"},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect notify socket: %w", err)
|
||||
}
|
||||
defer connection.Close()
|
||||
if _, err := connection.Write([]byte(state)); err != nil {
|
||||
return fmt.Errorf("write notify socket: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
48
go-agent/internal/sdnotify/notify_test.go
Normal file
48
go-agent/internal/sdnotify/notify_test.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package sdnotify
|
||||
|
||||
import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDisabledNotifierIsNoOp(t *testing.T) {
|
||||
if err := New("").Notify("READY=1"); err != nil {
|
||||
t.Fatalf("disabled notifier: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifierSendsDatagram(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "notify.sock")
|
||||
listener, err := net.ListenUnixgram("unixgram", &net.UnixAddr{Name: path, Net: "unixgram"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
if err := New(path).Notify("READY=1\nSTATUS=initialized"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := listener.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buffer := make([]byte, 128)
|
||||
read, _, err := listener.ReadFromUnix(buffer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := string(buffer[:read]); got != "READY=1\nSTATUS=initialized" {
|
||||
t.Fatalf("notification=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifierRejectsInvalidState(t *testing.T) {
|
||||
if err := New("unused").Notify(""); err == nil {
|
||||
t.Fatal("empty state accepted")
|
||||
}
|
||||
if err := New("unused").Notify("READY=1\x00STATUS=bad"); err == nil {
|
||||
t.Fatal("NUL state accepted")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue