117 lines
2.7 KiB
Go
117 lines
2.7 KiB
Go
|
package openwrt
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
|
||
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||
|
"forge.cadoles.com/Cadoles/emissary/internal/openwrt/uci"
|
||
|
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||
|
"github.com/pkg/errors"
|
||
|
"gitlab.com/wpetit/goweb/logger"
|
||
|
)
|
||
|
|
||
|
type UCIController struct {
|
||
|
binPath string
|
||
|
currentSpecRevision int
|
||
|
}
|
||
|
|
||
|
// Name implements node.Controller.
|
||
|
func (*UCIController) Name() string {
|
||
|
return "uci-controller"
|
||
|
}
|
||
|
|
||
|
// Reconcile implements node.Controller.
|
||
|
func (c *UCIController) Reconcile(ctx context.Context, state *agent.State) error {
|
||
|
uciSpec := spec.NewUCISpec()
|
||
|
|
||
|
if err := state.GetSpec(spec.NameUCI, uciSpec); err != nil {
|
||
|
if errors.Is(err, agent.ErrSpecNotFound) {
|
||
|
logger.Info(ctx, "could not find uci spec, doing nothing")
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
logger.Info(ctx, "retrieved spec", logger.F("spec", uciSpec.SpecName()), logger.F("revision", uciSpec.SpecRevision()))
|
||
|
|
||
|
if c.currentSpecRevision == uciSpec.SpecRevision() {
|
||
|
logger.Info(ctx, "spec revision did not change, doing nothing")
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if err := c.updateConfiguration(ctx, uciSpec); err != nil {
|
||
|
logger.Error(ctx, "could not update configuration", logger.E(errors.WithStack(err)))
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
c.currentSpecRevision = uciSpec.SpecRevision()
|
||
|
logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision))
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *UCIController) updateConfiguration(ctx context.Context, spec *spec.UCI) error {
|
||
|
logger.Info(ctx, "importing uci config")
|
||
|
|
||
|
if err := c.importConfig(ctx, spec.Config); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
if err := c.execPostImportCommands(ctx, spec.PostImportCommands); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *UCIController) importConfig(ctx context.Context, uci *uci.UCI) error {
|
||
|
cmd := exec.CommandContext(ctx, c.binPath, "import")
|
||
|
|
||
|
var buf bytes.Buffer
|
||
|
|
||
|
if _, err := buf.WriteString(uci.Export()); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
cmd.Stdin = &buf
|
||
|
cmd.Stderr = os.Stderr
|
||
|
cmd.Stdout = os.Stdout
|
||
|
|
||
|
if err := cmd.Run(); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (c *UCIController) execPostImportCommands(ctx context.Context, commands []*spec.UCIPostImportCommand) error {
|
||
|
for _, postImportCmd := range commands {
|
||
|
cmd := exec.CommandContext(ctx, postImportCmd.Command, postImportCmd.Args...)
|
||
|
|
||
|
cmd.Stderr = os.Stderr
|
||
|
cmd.Stdout = os.Stdout
|
||
|
|
||
|
if err := cmd.Run(); err != nil {
|
||
|
return errors.WithStack(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func NewUCIController(binPath string) *UCIController {
|
||
|
return &UCIController{
|
||
|
binPath: binPath,
|
||
|
currentSpecRevision: -1,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var _ agent.Controller = &UCIController{}
|