Files
kubesolo-os/cloud-init/kubesolo.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

80 lines
2.1 KiB
Go

package cloudinit
import (
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
)
// ApplyKubeSolo writes KubeSolo configuration files based on cloud-init config.
// These files are read by init stage 90-kubesolo.sh when building the
// KubeSolo command line.
func ApplyKubeSolo(cfg *Config, configDir string) error {
if err := os.MkdirAll(configDir, 0o755); err != nil {
return fmt.Errorf("creating config dir %s: %w", configDir, err)
}
// Write extra flags file (consumed by 90-kubesolo.sh)
flags := buildExtraFlags(cfg)
if flags != "" {
flagsPath := filepath.Join(configDir, "extra-flags")
if err := os.WriteFile(flagsPath, []byte(flags+"\n"), 0o644); err != nil {
return fmt.Errorf("writing extra-flags: %w", err)
}
slog.Info("wrote KubeSolo extra flags", "path", flagsPath, "flags", flags)
}
// Write config.yaml for KubeSolo if we have settings beyond defaults
if err := writeKubeSoloConfig(cfg, configDir); err != nil {
return err
}
return nil
}
func buildExtraFlags(cfg *Config) string {
var parts []string
if cfg.KubeSolo.ExtraFlags != "" {
parts = append(parts, cfg.KubeSolo.ExtraFlags)
}
// Add extra SANs from cloud-init
for _, san := range cfg.KubeSolo.ExtraSANs {
parts = append(parts, "--apiserver-extra-sans", san)
}
return strings.Join(parts, " ")
}
func writeKubeSoloConfig(cfg *Config, configDir string) error {
var lines []string
lines = append(lines, "# Generated by KubeSolo OS cloud-init")
lines = append(lines, "data-dir: /var/lib/kubesolo")
if cfg.KubeSolo.LocalStorage != nil {
if *cfg.KubeSolo.LocalStorage {
lines = append(lines, "local-storage: true")
} else {
lines = append(lines, "local-storage: false")
}
} else {
lines = append(lines, "local-storage: true")
}
lines = append(lines, "bind-address: 0.0.0.0")
lines = append(lines, "cluster-cidr: 10.42.0.0/16")
lines = append(lines, "service-cidr: 10.43.0.0/16")
dest := filepath.Join(configDir, "config.yaml")
content := strings.Join(lines, "\n") + "\n"
if err := os.WriteFile(dest, []byte(content), 0o644); err != nil {
return fmt.Errorf("writing config.yaml: %w", err)
}
slog.Info("wrote KubeSolo config", "path", dest)
return nil
}