2023-02-02 10:55:24 +01:00
|
|
|
package openwrt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
|
|
|
|
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
|
|
|
"forge.cadoles.com/Cadoles/emissary/internal/openwrt/uci"
|
2023-02-28 15:50:35 +01:00
|
|
|
ucispec "forge.cadoles.com/Cadoles/emissary/internal/spec/uci"
|
2023-10-13 12:30:52 +02:00
|
|
|
"github.com/getsentry/sentry-go"
|
2023-02-02 10:55:24 +01:00
|
|
|
"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 {
|
2023-02-28 15:50:35 +01:00
|
|
|
uciSpec := ucispec.NewSpec()
|
2023-02-02 10:55:24 +01:00
|
|
|
|
2023-02-28 15:50:35 +01:00
|
|
|
if err := state.GetSpec(ucispec.NameUCI, uciSpec); err != nil {
|
2023-02-02 10:55:24 +01:00
|
|
|
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 {
|
2023-10-13 12:30:52 +02:00
|
|
|
err = errors.WithStack(err)
|
|
|
|
logger.Error(ctx, "could not update configuration", logger.E(err))
|
|
|
|
sentry.CaptureException(err)
|
2023-02-02 10:55:24 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
c.currentSpecRevision = uciSpec.SpecRevision()
|
|
|
|
logger.Info(ctx, "updating current spec revision", logger.F("revision", c.currentSpecRevision))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-28 15:50:35 +01:00
|
|
|
func (c *UCIController) updateConfiguration(ctx context.Context, spec *ucispec.Spec) error {
|
2023-02-02 10:55:24 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-02-28 15:50:35 +01:00
|
|
|
func (c *UCIController) execPostImportCommands(ctx context.Context, commands []*ucispec.UCIPostImportCommand) error {
|
2023-02-02 10:55:24 +01:00
|
|
|
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{}
|