package underlay import ( "context" "crypto/sha256" "fmt" "os/exec" "go.uber.org/zap" "github.com/guildhouse-co/kedge/internal/quartermaster" ) // Dispatcher triggers YANG compilation and coordinates SDK dispatch through Bascule. type Dispatcher struct { qm *quartermaster.Client log *zap.SugaredLogger // CompilerPath is the path to the YANG compiler script. CompilerPath string } // NewDispatcher creates a new underlay dispatch coordinator. func NewDispatcher(qm *quartermaster.Client, log *zap.SugaredLogger) *Dispatcher { return &Dispatcher{ qm: qm, log: log, CompilerPath: "/opt/kedge/yang/compiler/compile.py", } } // CompileAndDispatch runs the YANG compiler for the given site config and // dispatches the resulting vendor-specific payloads via Bascule SDK. func (d *Dispatcher) CompileAndDispatch(ctx context.Context, siteConfigPath string, sessionID string) error { // Hash the YANG source for the mutation artifact. yangHash, err := hashFile(siteConfigPath) if err != nil { return fmt.Errorf("failed to hash YANG source: %w", err) } // Run the YANG compiler as a subprocess. cmd := exec.CommandContext(ctx, "python3", d.CompilerPath, "--site-config", siteConfigPath, "--output-format", "json", ) output, err := cmd.Output() if err != nil { return fmt.Errorf("YANG compilation failed: %w", err) } d.log.Infow("YANG compilation complete", "site_config", siteConfigPath, "output_bytes", len(output)) // TODO: Parse compiler output into vendor-specific payloads. // TODO: For each device mutation, dispatch SDK call through Bascule, // capture before/after config hashes, and submit NetworkMutationArtifact. _ = yangHash _ = sessionID return nil } func hashFile(path string) ([]byte, error) { data, err := exec.Command("cat", path).Output() if err != nil { return nil, err } hash := sha256.Sum256(data) return hash[:], nil }