v0.22.0: First-run setup wizard, local infra backup, hub verification
New controller features:
- Web-based setup wizard replaces docker-setup.sh interactive config
- Dual listener: :8080 (Traefik) + :8081 (direct HTTP for LAN)
- Drive scanner finds .felhom-infra-backup/ on all block devices
- Hub recovery pull (GET /api/v1/recovery/{id}) with retrieval password
- Fresh install: Hub config download or manual wizard
- CSRF protection, state persistence, Hungarian UI
- Local infra backup written to all connected drives after each backup cycle
- .felhom-infra-backup/backup.json + metadata.json with SHA256 checksum
- Hub verification: parse customer_blocked from report push response
- Limited mode after 7 days without verification
- Recovery info page on Settings + recovery-info.txt file generation
- Pending events queue: DR events sent to Hub on next report push
- docker-setup.sh v6.0.0: removed interactive wizard, minimal controller.yaml only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,7 @@ type PathsConfig struct {
|
||||
|
||||
type WebConfig struct {
|
||||
Listen string `yaml:"listen"`
|
||||
SetupListen string `yaml:"setup_listen"` // Plain HTTP listener for setup wizard (only active during setup mode)
|
||||
PasswordHash string `yaml:"password_hash"`
|
||||
SessionSecret string `yaml:"session_secret"`
|
||||
}
|
||||
@@ -149,6 +150,31 @@ type HubConfig struct {
|
||||
|
||||
// Load reads and parses the config file, applies defaults, and validates.
|
||||
func Load(path string) (*Config, error) {
|
||||
cfg, err := loadAndParse(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validate(cfg); err != nil {
|
||||
return nil, fmt.Errorf("config validation: %w", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// LoadPermissive reads and parses the config file, applies defaults, but skips validation.
|
||||
// Used during setup mode where customer.id and domain may not be set yet.
|
||||
func LoadPermissive(path string) (*Config, error) {
|
||||
return loadAndParse(path)
|
||||
}
|
||||
|
||||
// Default returns a Config with all defaults applied. Used when the config file
|
||||
// is missing or unreadable and the controller needs to enter setup mode.
|
||||
func Default() *Config {
|
||||
cfg := &Config{}
|
||||
applyDefaults(cfg)
|
||||
return cfg
|
||||
}
|
||||
|
||||
func loadAndParse(path string) (*Config, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading config file: %w", err)
|
||||
@@ -165,10 +191,6 @@ func Load(path string) (*Config, error) {
|
||||
applyDefaults(cfg)
|
||||
applyEnvOverrides(cfg)
|
||||
|
||||
if err := validate(cfg); err != nil {
|
||||
return nil, fmt.Errorf("config validation: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@@ -212,6 +234,7 @@ func applyDefaults(cfg *Config) {
|
||||
d(&cfg.Paths.DataDir, "/opt/docker/felhom-controller/data")
|
||||
d(&cfg.Paths.SystemDataPath, "/mnt/sys_drive")
|
||||
d(&cfg.Web.Listen, ":8080")
|
||||
d(&cfg.Web.SetupListen, ":8081")
|
||||
d(&cfg.Git.Branch, "main")
|
||||
d(&cfg.Git.SyncInterval, "15m")
|
||||
d(&cfg.Stacks.UpdateWindow, "03:00-05:00")
|
||||
|
||||
Reference in New Issue
Block a user