feat: cloud-init supports all documented KubeSolo CLI flags
Some checks failed
CI / Go Tests (push) Has been cancelled
CI / Build Go Binaries (amd64, linux, linux-amd64) (push) Has been cancelled
CI / Build Go Binaries (arm64, linux, linux-arm64) (push) Has been cancelled
CI / Shellcheck (push) Has been cancelled

Add missing flags (--local-storage-shared-path, --debug, --pprof-server,
--portainer-edge-id, --portainer-edge-key, --portainer-edge-async) so all
10 documented KubeSolo parameters can be configured via cloud-init YAML.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 15:49:31 -06:00
parent 4fc078f7a3
commit 61bd28c692
8 changed files with 189 additions and 12 deletions

View File

@@ -31,9 +31,15 @@ type NetworkConfig struct {
// KubeSoloConfig defines KubeSolo-specific settings.
type KubeSoloConfig struct {
ExtraFlags string `yaml:"extra-flags"`
LocalStorage *bool `yaml:"local-storage"`
ExtraSANs []string `yaml:"apiserver-extra-sans"`
ExtraFlags string `yaml:"extra-flags"`
LocalStorage *bool `yaml:"local-storage"`
LocalStorageSharedPath string `yaml:"local-storage-shared-path"`
ExtraSANs []string `yaml:"apiserver-extra-sans"`
Debug bool `yaml:"debug"`
PprofServer bool `yaml:"pprof-server"`
PortainerEdgeID string `yaml:"portainer-edge-id"`
PortainerEdgeKey string `yaml:"portainer-edge-key"`
PortainerEdgeAsync bool `yaml:"portainer-edge-async"`
}
// NTPConfig defines NTP settings.

View File

@@ -0,0 +1,40 @@
# KubeSolo OS Cloud-Init — Full Configuration Reference
# Shows ALL supported KubeSolo parameters.
# Place at: /mnt/data/etc-kubesolo/cloud-init.yaml (on data partition)
# Or pass via boot param: kubesolo.cloudinit=/path/to/this.yaml
hostname: kubesolo-edge-01
network:
mode: dhcp
# interface: eth0 # Optional: specify interface (auto-detected if omitted)
# dns: # Optional: override DHCP-provided DNS
# - 8.8.8.8
kubesolo:
# Enable local-path-provisioner for persistent volumes (default: true)
local-storage: true
# Shared path for local-path-provisioner storage
local-storage-shared-path: "/mnt/shared"
# Extra SANs for API server TLS certificate
apiserver-extra-sans:
- kubesolo-edge-01.local
- 192.168.1.100
# Enable verbose debug logging
debug: false
# Enable Go pprof profiling server
pprof-server: false
# Portainer Edge Agent connection (alternative to portainer.edge-agent section)
# These generate --portainer-edge-id, --portainer-edge-key, --portainer-edge-async
# CLI flags for KubeSolo's built-in Edge Agent support.
portainer-edge-id: "your-edge-id"
portainer-edge-key: "your-edge-key"
portainer-edge-async: true
# Arbitrary extra flags passed directly to the KubeSolo binary
# extra-flags: "--disable traefik --disable servicelb"

View File

@@ -46,6 +46,30 @@ func buildExtraFlags(cfg *Config) string {
parts = append(parts, "--apiserver-extra-sans", san)
}
if cfg.KubeSolo.LocalStorageSharedPath != "" {
parts = append(parts, "--local-storage-shared-path", cfg.KubeSolo.LocalStorageSharedPath)
}
if cfg.KubeSolo.Debug {
parts = append(parts, "--debug")
}
if cfg.KubeSolo.PprofServer {
parts = append(parts, "--pprof-server")
}
if cfg.KubeSolo.PortainerEdgeID != "" {
parts = append(parts, "--portainer-edge-id", cfg.KubeSolo.PortainerEdgeID)
}
if cfg.KubeSolo.PortainerEdgeKey != "" {
parts = append(parts, "--portainer-edge-key", cfg.KubeSolo.PortainerEdgeKey)
}
if cfg.KubeSolo.PortainerEdgeAsync {
parts = append(parts, "--portainer-edge-async")
}
return strings.Join(parts, " ")
}

View File

@@ -44,6 +44,54 @@ func TestBuildExtraFlags(t *testing.T) {
},
want: "--disable servicelb --apiserver-extra-sans edge.local",
},
{
name: "debug flag",
cfg: Config{
KubeSolo: KubeSoloConfig{Debug: true},
},
want: "--debug",
},
{
name: "pprof-server flag",
cfg: Config{
KubeSolo: KubeSoloConfig{PprofServer: true},
},
want: "--pprof-server",
},
{
name: "local-storage-shared-path",
cfg: Config{
KubeSolo: KubeSoloConfig{LocalStorageSharedPath: "/mnt/shared"},
},
want: "--local-storage-shared-path /mnt/shared",
},
{
name: "portainer edge flags",
cfg: Config{
KubeSolo: KubeSoloConfig{
PortainerEdgeID: "test-id-123",
PortainerEdgeKey: "test-key-456",
PortainerEdgeAsync: true,
},
},
want: "--portainer-edge-id test-id-123 --portainer-edge-key test-key-456 --portainer-edge-async",
},
{
name: "all new flags",
cfg: Config{
KubeSolo: KubeSoloConfig{
ExtraFlags: "--disable traefik",
ExtraSANs: []string{"node.local"},
LocalStorageSharedPath: "/mnt/data/shared",
Debug: true,
PprofServer: true,
PortainerEdgeID: "eid",
PortainerEdgeKey: "ekey",
PortainerEdgeAsync: true,
},
},
want: "--disable traefik --apiserver-extra-sans node.local --local-storage-shared-path /mnt/data/shared --debug --pprof-server --portainer-edge-id eid --portainer-edge-key ekey --portainer-edge-async",
},
}
for _, tt := range tests {
@@ -61,9 +109,14 @@ func TestApplyKubeSolo(t *testing.T) {
tr := true
cfg := &Config{
KubeSolo: KubeSoloConfig{
ExtraFlags: "--disable traefik",
LocalStorage: &tr,
ExtraSANs: []string{"test.local"},
ExtraFlags: "--disable traefik",
LocalStorage: &tr,
ExtraSANs: []string{"test.local"},
LocalStorageSharedPath: "/mnt/shared",
Debug: true,
PortainerEdgeID: "eid",
PortainerEdgeKey: "ekey",
PortainerEdgeAsync: true,
},
}
@@ -83,6 +136,21 @@ func TestApplyKubeSolo(t *testing.T) {
if !strings.Contains(flags, "--apiserver-extra-sans test.local") {
t.Errorf("extra-flags missing SANs: %q", flags)
}
if !strings.Contains(flags, "--local-storage-shared-path /mnt/shared") {
t.Errorf("extra-flags missing local-storage-shared-path: %q", flags)
}
if !strings.Contains(flags, "--debug") {
t.Errorf("extra-flags missing --debug: %q", flags)
}
if !strings.Contains(flags, "--portainer-edge-id eid") {
t.Errorf("extra-flags missing --portainer-edge-id: %q", flags)
}
if !strings.Contains(flags, "--portainer-edge-key ekey") {
t.Errorf("extra-flags missing --portainer-edge-key: %q", flags)
}
if !strings.Contains(flags, "--portainer-edge-async") {
t.Errorf("extra-flags missing --portainer-edge-async: %q", flags)
}
// Check config.yaml
configData, err := os.ReadFile(filepath.Join(dir, "config.yaml"))

View File

@@ -225,6 +225,7 @@ func TestParseExampleFiles(t *testing.T) {
"examples/static-ip.yaml",
"examples/portainer-edge.yaml",
"examples/airgapped.yaml",
"examples/full-config.yaml",
}
for _, path := range examples {