144 lines
3.4 KiB
Go
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
|
|
}
|