Go-based network automation with YANG models, gRPC, Ansible, Terraform, and Kubernetes integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
package topology
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
)
|
|
|
|
// Store provides thread-safe access to the mesh topology state.
|
|
// The DaemonSet writes topology updates, and the CNI plugin reads them.
|
|
// State is persisted to a JSON file on disk.
|
|
type Store struct {
|
|
mu sync.RWMutex
|
|
filePath string
|
|
topo *MeshTopology
|
|
}
|
|
|
|
// NewStore creates a topology store backed by the given file path.
|
|
func NewStore(filePath string) *Store {
|
|
return &Store{
|
|
filePath: filePath,
|
|
topo: &MeshTopology{},
|
|
}
|
|
}
|
|
|
|
// LoadFromFile reads a MeshTopology from a JSON file.
|
|
// Used by the CNI plugin to read the DaemonSet-written state.
|
|
func LoadFromFile(path string) (*MeshTopology, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read topology file %s: %w", path, err)
|
|
}
|
|
|
|
var topo MeshTopology
|
|
if err := json.Unmarshal(data, &topo); err != nil {
|
|
return nil, fmt.Errorf("failed to parse topology file: %w", err)
|
|
}
|
|
|
|
return &topo, nil
|
|
}
|
|
|
|
// Get returns a copy of the current topology.
|
|
func (s *Store) Get() MeshTopology {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return *s.topo
|
|
}
|
|
|
|
// Update atomically updates the topology and persists to disk.
|
|
func (s *Store) Update(fn func(*MeshTopology)) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
fn(s.topo)
|
|
|
|
return s.persist()
|
|
}
|
|
|
|
func (s *Store) persist() error {
|
|
data, err := json.MarshalIndent(s.topo, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal topology: %w", err)
|
|
}
|
|
|
|
// Atomic write: write to temp file, then rename.
|
|
tmpPath := s.filePath + ".tmp"
|
|
if err := os.WriteFile(tmpPath, data, 0644); err != nil {
|
|
return fmt.Errorf("failed to write topology file: %w", err)
|
|
}
|
|
if err := os.Rename(tmpPath, s.filePath); err != nil {
|
|
return fmt.Errorf("failed to rename topology file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|