Files
monok8s/clitools/pkg/node/uboot/env_writer.go
2026-04-04 22:47:51 +08:00

144 lines
3.4 KiB
Go

package uboot
import (
"context"
"fmt"
"strings"
"time"
"k8s.io/klog/v2"
"example.com/monok8s/pkg/system"
)
func NewFWEnvWriter(configPath string, ctlPath string) *FWEnvWriter {
return &FWEnvWriter{
Runner: system.NewRunner(system.RunnerConfig{
DefaultTimeout: 15 * time.Second,
StreamOutput: false,
Logger: &system.StdLogger{},
}),
ConfigPath: configPath,
CtlPath: ctlPath,
}
}
func (w *FWEnvWriter) GetEnv(ctx context.Context, key string) (string, error) {
key = strings.TrimSpace(key)
if key == "" {
return "", fmt.Errorf("key is required")
}
args := []string{
"internal", "fw-printenv",
"--key", key,
"--config", w.ConfigPath,
}
res, err := w.Runner.RunWithOptions(ctx, w.CtlPath, args, system.RunOptions{Quiet: true})
if err != nil {
if res != nil {
return "", fmt.Errorf("fw-printenv %q: %w (stdout=%q stderr=%q)",
key, err, strings.TrimSpace(res.Stdout), strings.TrimSpace(res.Stderr))
}
return "", fmt.Errorf("fw-printenv %q: %w", key, err)
}
out := strings.TrimSpace(res.Stdout)
if out == "" {
return "", fmt.Errorf("empty output for key %q", key)
}
parts := strings.SplitN(out, "=", 2)
if len(parts) != 2 {
return "", fmt.Errorf("unexpected fw_printenv output for %q: %q", key, out)
}
if parts[0] != key {
return "", fmt.Errorf("unexpected fw_printenv key: got %q want %q", parts[0], key)
}
return parts[1], nil
}
func (w *FWEnvWriter) SetEnv(ctx context.Context, key, value string) error {
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
if key == "" {
return fmt.Errorf("key is required")
}
if value == "" {
return fmt.Errorf("value is required")
}
args := []string{
"internal", "fw-setenv",
"--key", key,
"--value", value,
"--config", w.ConfigPath,
}
res, err := w.Runner.RunWithOptions(ctx, w.CtlPath, args, system.RunOptions{Quiet: true})
if err != nil {
if res != nil {
return fmt.Errorf("fw-setenv %q: %w (stdout=%q stderr=%q)",
key, err, strings.TrimSpace(res.Stdout), strings.TrimSpace(res.Stderr))
}
return fmt.Errorf("fw-setenv %q: %w", key, err)
}
return nil
}
func (w *FWEnvWriter) SetEnvIfDifferent(ctx context.Context, key, desired string) error {
current, err := w.GetEnv(ctx, key)
if err == nil && current == desired {
klog.V(1).InfoS("fw env already matches", "key", key, "value", desired)
return nil
}
if err != nil {
klog.InfoS("fw env key missing or unreadable, will set",
"key", key,
"desired", desired,
"error", err,
)
} else {
klog.InfoS("fw env drift detected, updating",
"key", key,
"current", current,
"desired", desired,
)
}
return w.SetEnv(ctx, key, desired)
}
func (w *FWEnvWriter) EnsureBootEnv(ctx context.Context, cfg BootEnvConfig) error {
if err := cfg.Validate(); err != nil {
return err
}
envs := []struct {
Key string
Value string
}{
{"bootcmd", cfg.bootCmdOrDefault()},
{"boot_source", string(cfg.BootSource)},
{"boot_part", string(cfg.BootPart)},
{"boot_disk", fmt.Sprintf("%d", cfg.BootDisk)},
{"rootfs_a_partnum", fmt.Sprintf("%d", cfg.RootfsAPartNum)},
{"rootfs_b_partnum", fmt.Sprintf("%d", cfg.RootfsBPartNum)},
{"data_partnum", fmt.Sprintf("%d", cfg.DataPartNum)},
{"linux_root_prefix", cfg.LinuxRootPrefix},
}
for _, kv := range envs {
if err := w.SetEnvIfDifferent(ctx, kv.Key, kv.Value); err != nil {
return fmt.Errorf("ensure %s: %w", kv.Key, err)
}
}
return nil
}