Files
kubesolo-os/cloud-init/parser.go
Adolfo Delorenzo d900fa920e feat: add cloud-init Go parser (Phase 2)
Implement a lightweight cloud-init system for first-boot configuration:
- Go parser for YAML config (hostname, network, KubeSolo settings)
- Static/DHCP network modes with DNS override
- KubeSolo extra flags and API server SAN configuration
- Portainer Edge Agent and air-gapped deployment support
- New init stage 45-cloud-init.sh runs before network/hostname stages
- Stages 50/60 skip gracefully when cloud-init has already applied
- Build script compiles static Linux/amd64 binary (~2.7 MB)
- 17 unit tests covering parsing, validation, and example files
- Full documentation at docs/cloud-init.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:39:05 -06:00

55 lines
1.2 KiB
Go

package cloudinit
import (
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// Parse reads a cloud-init YAML file and returns the parsed config.
func Parse(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading cloud-init file %s: %w", path, err)
}
return ParseBytes(data)
}
// ParseBytes parses cloud-init YAML from a byte slice.
func ParseBytes(data []byte) (*Config, error) {
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing cloud-init YAML: %w", err)
}
if err := validate(&cfg); err != nil {
return nil, fmt.Errorf("validating cloud-init config: %w", err)
}
// Apply defaults
if cfg.Network.Mode == "" {
cfg.Network.Mode = "dhcp"
}
return &cfg, nil
}
func validate(cfg *Config) error {
switch cfg.Network.Mode {
case "", "dhcp":
// valid
case "static":
if cfg.Network.Address == "" {
return fmt.Errorf("static network mode requires 'address' field")
}
if cfg.Network.Gateway == "" {
return fmt.Errorf("static network mode requires 'gateway' field")
}
default:
return fmt.Errorf("unknown network mode: %q (expected 'dhcp' or 'static')", cfg.Network.Mode)
}
return nil
}