control agent can now uboot commands

This commit is contained in:
2026-04-04 20:19:25 +08:00
parent 4f490ab37e
commit 517cc2e01d
19 changed files with 579 additions and 69 deletions

View File

@@ -4,10 +4,10 @@ import (
"context"
"fmt"
"k8s.io/klog/v2"
monov1alpha1 "example.com/monok8s/pkg/apis/monok8s/v1alpha1"
"example.com/monok8s/pkg/node"
"example.com/monok8s/pkg/system"
"k8s.io/klog/v2"
)
type Runner struct {
@@ -132,6 +132,11 @@ func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
Name: "Apply node metadata",
Desc: "Apply labels/annotations to the local node if API server is reachable",
},
{
RegKey: "ConfigureUBootCommands",
Name: "Ensure fw_env config and u-boot-tools availablilty",
Desc: "Install or generate /etc/fw_env.config for U-Boot environment access",
},
{
RegKey: "ApplyControlAgentDaemonSetResources",
Name: "Apply daemonset for control agent",

View File

@@ -0,0 +1,89 @@
package internal
import (
"fmt"
"os"
"strings"
"time"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"example.com/monok8s/pkg/system"
)
func newInternalFWPrintEnvCmd() *cobra.Command {
var key string
var configPath string
cmd := &cobra.Command{
Use: "fw-printenv",
Short: "Run fw_printenv",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
key = strings.TrimSpace(key)
configPath = strings.TrimSpace(configPath)
if configPath == "" {
configPath = defaultFWEnvConfigPath
}
if _, err := os.Stat(configPath); err != nil {
return fmt.Errorf("stat fw env config %q: %w", configPath, err)
}
runner := system.NewRunner(system.RunnerConfig{
DefaultTimeout: 15 * time.Second,
StreamOutput: false,
Logger: &system.StdLogger{},
})
runArgs := []string{"-c", configPath}
if key != "" {
runArgs = append(runArgs, key)
}
res, err := runner.RunWithOptions(
ctx,
"/fw_printenv",
runArgs,
system.RunOptions{
Quiet: true,
},
)
if err != nil {
if res != nil {
klog.ErrorS(err, "fw_printenv failed",
"key", key,
"stdout", strings.TrimSpace(res.Stdout),
"stderr", strings.TrimSpace(res.Stderr),
)
}
return err
}
stdout := strings.TrimSpace(res.Stdout)
stderr := strings.TrimSpace(res.Stderr)
if stdout != "" {
fmt.Println(stdout)
}
if stderr != "" {
klog.InfoS("fw_printenv stderr", "output", stderr)
}
klog.InfoS("fw_printenv succeeded",
"key", key,
"configPath", configPath,
)
return nil
},
}
cmd.Flags().StringVar(&key, "key", "", "U-Boot environment variable name to print")
cmd.Flags().StringVar(&configPath, "config", defaultFWEnvConfigPath, "Path to fw_env.config")
return cmd
}

View File

@@ -0,0 +1,115 @@
package internal
import (
"fmt"
"os"
"strings"
"time"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"example.com/monok8s/pkg/system"
)
const defaultFWEnvConfigPath = "/host/etc/fw_env.config"
func newInternalFWSetEnvCmd() *cobra.Command {
var key string
var value string
var configPath string
cmd := &cobra.Command{
Use: "fw-setenv",
Short: "Run fw_setenv",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
configPath = strings.TrimSpace(configPath)
if key == "" {
return fmt.Errorf("--key is required")
}
if value == "" {
return fmt.Errorf("--value is required")
}
if configPath == "" {
configPath = defaultFWEnvConfigPath
}
if _, err := os.Stat(configPath); err != nil {
return fmt.Errorf("stat fw env config %q: %w", configPath, err)
}
runner := system.NewRunner(system.RunnerConfig{
DefaultTimeout: 15 * time.Second,
StreamOutput: false,
Logger: &system.StdLogger{},
})
// Preflight first so failure is clearer than blindly writing.
preflightRes, err := runner.RunWithOptions(
ctx,
"/fw_printenv",
[]string{"-c", configPath},
system.RunOptions{
Quiet: true,
},
)
if err != nil {
if preflightRes != nil {
klog.ErrorS(err, "fw_printenv preflight failed",
"stdout", strings.TrimSpace(preflightRes.Stdout),
"stderr", strings.TrimSpace(preflightRes.Stderr),
)
}
return fmt.Errorf("fw_printenv preflight: %w", err)
}
res, err := runner.RunWithOptions(
ctx,
"/fw_setenv",
[]string{
"-c", configPath,
key, value,
},
system.RunOptions{
Quiet: true,
},
)
if err != nil {
if res != nil {
klog.ErrorS(err, "fw_setenv failed",
"key", key,
"value", value,
"stdout", strings.TrimSpace(res.Stdout),
"stderr", strings.TrimSpace(res.Stderr),
)
}
return err
}
if strings.TrimSpace(res.Stdout) != "" {
klog.InfoS("fw_setenv stdout", "output", strings.TrimSpace(res.Stdout))
}
if strings.TrimSpace(res.Stderr) != "" {
klog.InfoS("fw_setenv stderr", "output", strings.TrimSpace(res.Stderr))
}
klog.InfoS("fw_setenv succeeded",
"key", key,
"value", value,
"configPath", configPath,
)
return nil
},
}
cmd.Flags().StringVar(&key, "key", "", "U-Boot environment variable name")
cmd.Flags().StringVar(&value, "value", "", "U-Boot environment variable value")
cmd.Flags().StringVar(&configPath, "config", defaultFWEnvConfigPath, "Path to fw_env.config")
return cmd
}

View File

@@ -1,9 +1,9 @@
package internal
import (
"github.com/spf13/cobra"
"example.com/monok8s/pkg/bootstrap"
"example.com/monok8s/pkg/config"
"github.com/spf13/cobra"
)
func NewCmdInternal() *cobra.Command {
@@ -33,6 +33,9 @@ func NewCmdInternal() *cobra.Command {
return nil
},
})
cmd.AddCommand(newInternalFWSetEnvCmd())
cmd.AddCommand(newInternalFWPrintEnvCmd())
cmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to MonoKSConfig yaml")
return cmd
}

View File

@@ -0,0 +1,37 @@
package osupgrade
import (
"context"
"fmt"
"os/exec"
)
type NextBootConfig struct {
Key string
Value string
}
func SetNextBootEnv(ctx context.Context, cfg NextBootConfig) error {
if cfg.Key == "" {
return fmt.Errorf("boot env key is empty")
}
if cfg.Value == "" {
return fmt.Errorf("boot env value is empty")
}
cmd := exec.CommandContext(
ctx,
"/proc/self/exe",
"internal",
"fw-setenv",
"--key", cfg.Key,
"--value", cfg.Value,
)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("invoke internal fw-setenv: %w: %s", err, string(out))
}
return nil
}

View File

@@ -128,7 +128,22 @@ func HandleOSUpgrade(ctx context.Context, clients *kube.Clients,
}
klog.Info(result)
// TODO: fw_setenv
if err := SetNextBootEnv(ctx, NextBootConfig{
Key: "boot_part",
Value: "B",
}); err != nil {
return failProgress(ctx, clients, osup, "set boot env", err)
}
now = metav1.Now()
osup.Status.LastUpdatedAt = &now
osup.Status.Message = "image applied, verified, and next boot environment updated"
osup.Status.Phase = monov1alpha1.OSUpgradeProgressPhaseRebooting
osup, err = updateProgressStatus(ctx, clients, osup_gvr, osup)
if err != nil {
return fmt.Errorf("update progress status: %w", err)
}
return nil
}

View File

@@ -273,20 +273,8 @@ func applyControlAgentDaemonSet(ctx context.Context, kubeClient kubernetes.Inter
Value: "/host/opt/monok8s/config/cluster.env",
},
{
Name: "HOST_MOUNT_ROOT",
Value: "/host/mnt/control-agent",
},
{
Name: "HOST_DEV_DIR",
Value: "/host/dev",
},
{
Name: "HOST_PROC_DIR",
Value: "/host/proc",
},
{
Name: "HOST_RUN_DIR",
Value: "/host/run",
Name: "FW_ENV_CONFIG_FILE",
Value: "/host/etc/fw_env.config",
},
},
SecurityContext: &corev1.SecurityContext{
@@ -295,22 +283,18 @@ func applyControlAgentDaemonSet(ctx context.Context, kubeClient kubernetes.Inter
VolumeMounts: []corev1.VolumeMount{
{
Name: "host-dev",
MountPath: "/host/dev",
MountPath: "/dev",
},
{
Name: "host-etc",
MountPath: "/host/etc",
ReadOnly: true,
},
{
Name: "host-config",
MountPath: "/host/opt/monok8s/config",
ReadOnly: true,
},
{
Name: "host-run",
MountPath: "/host/run",
},
{
Name: "host-proc",
MountPath: "/host/proc",
ReadOnly: true,
},
},
},
},
@@ -324,6 +308,15 @@ func applyControlAgentDaemonSet(ctx context.Context, kubeClient kubernetes.Inter
},
},
},
{
Name: "host-etc",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/etc",
Type: hostPathType(corev1.HostPathDirectory),
},
},
},
{
Name: "host-config",
VolumeSource: corev1.VolumeSource{
@@ -333,24 +326,6 @@ func applyControlAgentDaemonSet(ctx context.Context, kubeClient kubernetes.Inter
},
},
},
{
Name: "host-run",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/run",
Type: hostPathType(corev1.HostPathDirectory),
},
},
},
{
Name: "host-proc",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/proc",
Type: hostPathType(corev1.HostPathDirectory),
},
},
},
},
},
},

View File

@@ -7,8 +7,8 @@ import (
"os"
"strings"
"k8s.io/klog/v2"
system "example.com/monok8s/pkg/system"
"k8s.io/klog/v2"
)
type NetworkConfig struct {