// Package config parses /etc/kubesolo/update.conf — the persistent // configuration for the update agent. Each line is "key = value"; blank // lines and "#"-prefixed comments are ignored. Unknown keys are tolerated // (forward compatibility). // // Example: // // # Where to look for updates // server = https://updates.kubesolo.example.com // channel = stable // // # Only apply between 03:00 and 05:00 local time // maintenance_window = 03:00-05:00 // // pubkey = /etc/kubesolo/update-pubkey.hex // // The file is populated on first boot by cloud-init (see the cloud-init // updates: block) and can be hand-edited afterwards. package config import ( "bufio" "fmt" "os" "strings" ) // DefaultPath is where update.conf lives on a live system. const DefaultPath = "/etc/kubesolo/update.conf" // Config holds the parsed update.conf values. Empty fields mean "not set" — // the caller's defaults apply. type Config struct { Server string Channel string MaintenanceWindow string PubKey string } // Load reads and parses update.conf. A missing file returns an empty Config // (not an error) — fresh systems before cloud-init has run. func Load(path string) (*Config, error) { f, err := os.Open(path) if err != nil { if os.IsNotExist(err) { return &Config{}, nil } return nil, fmt.Errorf("open %s: %w", path, err) } defer f.Close() c := &Config{} scanner := bufio.NewScanner(f) lineNo := 0 for scanner.Scan() { lineNo++ line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } eq := strings.IndexByte(line, '=') if eq < 0 { return nil, fmt.Errorf("%s:%d: missing '=' in line: %q", path, lineNo, line) } key := strings.TrimSpace(line[:eq]) value := strings.TrimSpace(line[eq+1:]) switch key { case "server": c.Server = value case "channel": c.Channel = value case "maintenance_window": c.MaintenanceWindow = value case "pubkey": c.PubKey = value } // Unknown keys are silently ignored for forward compatibility. } if err := scanner.Err(); err != nil { return nil, fmt.Errorf("read %s: %w", path, err) } return c, nil }