// Package bootstate parses kernel cmdline parameters that the // orchestrator baked into the iPXE script. The agent consumes these // on startup to learn which run it belongs to and how to reach back. package bootstate import ( "errors" "fmt" "os" "strconv" "strings" ) type Params struct { OrchestratorURL string RunID int64 MAC string Token string TLSCertFPR string // optional } // ParseCmdline reads /proc/cmdline (or a user-supplied path for tests) // and pulls out the vetting.* parameters. func ParseCmdline(path string) (*Params, error) { if path == "" { path = "/proc/cmdline" } b, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read %s: %w", path, err) } return ParseCmdlineString(string(b)) } func ParseCmdlineString(s string) (*Params, error) { fields := strings.Fields(strings.TrimSpace(s)) var p Params for _, f := range fields { k, v, ok := strings.Cut(f, "=") if !ok { continue } switch k { case "vetting.orchestrator": p.OrchestratorURL = v case "vetting.run_id": id, err := strconv.ParseInt(v, 10, 64) if err != nil { return nil, fmt.Errorf("vetting.run_id=%q: %w", v, err) } p.RunID = id case "vetting.mac": p.MAC = strings.ToLower(v) case "vetting.token": p.Token = v case "vetting.cert_fpr": p.TLSCertFPR = v } } if p.OrchestratorURL == "" || p.RunID == 0 || p.MAC == "" || p.Token == "" { return nil, errors.New("cmdline missing one of vetting.orchestrator, vetting.run_id, vetting.mac, vetting.token") } return &p, nil }