From 92032202f46767f367c000122171e9ceb163b6ac Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Sat, 11 Oct 2025 21:40:45 +0000 Subject: [PATCH] Dev env setup. --- .vscode/launch.json | 38 ++++++++++++++++ .vscode/settings.json | 23 ++++++++++ Makefile | 73 +++++++++++++++++++++++++++++++ internal/apps/apps.go | 2 +- internal/backup/backup.go | 8 ++-- internal/discovery/discovery.go | 24 +++++----- internal/instance/instance.go | 22 +++++----- internal/node/node.go | 10 ++--- internal/operations/operations.go | 2 +- internal/secrets/secrets.go | 5 +++ internal/services/manifest.go | 6 +-- internal/services/services.go | 14 +++--- internal/utilities/utilities.go | 6 +-- 13 files changed, 186 insertions(+), 47 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 Makefile diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e96edab --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Daemon (debug)", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}", + "console": "integratedTerminal", + "env": { + "GO_ENV": "development", + "WILD_CENTRAL_ENV": "development", + "DEBUG": "true" + }, + "args": [], + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "showLog": true, + "trace": "verbose" + }, + { + "name": "Daemon (no debug)", + "type": "go", + "request": "launch", + "program": "${workspaceFolder}", + "console": "integratedTerminal", + "env": { + "GO_ENV": "development", + "WILD_CENTRAL_ENV": "development" + }, + "args": [], + "cwd": "${workspaceFolder}", + "stopOnEntry": false, + "showLog": true + } + ], +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d6a6895 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "go.gopath": "", + "go.goroot": "", + "go.useLanguageServer": true, + + "gopls": { + "experimentalWorkspaceModule": true, + "build.experimentalWorkspaceModule": true + }, + + "go.lintTool": "golangci-lint", + "go.lintOnSave": "workspace", + "go.formatTool": "goimports", + "go.testOnSave": false, + + "[go]": { + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, + "editor.suggest.snippetsPreventQuickSuggestions": false + } +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7756101 --- /dev/null +++ b/Makefile @@ -0,0 +1,73 @@ +.PHONY: help build dev test clean install lint fmt vet + +# Binary name +BINARY_NAME=wildd +BUILD_DIR=build + +# Go parameters +GOCMD=go +GOBUILD=$(GOCMD) build +GOCLEAN=$(GOCMD) clean +GOTEST=$(GOCMD) test +GOGET=$(GOCMD) get +GOMOD=$(GOCMD) mod +GOFMT=$(GOCMD) fmt +GOVET=$(GOCMD) vet + +# Build flags +LDFLAGS=-ldflags "-s -w" + +help: ## Show this help message + @echo 'Usage: make [target]' + @echo '' + @echo 'Available targets:' + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +build: ## Build the daemon binary + @echo "Building $(BINARY_NAME)..." + @mkdir -p $(BUILD_DIR) + $(GOBUILD) $(LDFLAGS) -o $(BUILD_DIR)/$(BINARY_NAME) . + +dev: ## Run the daemon in development mode with live reloading + @echo "Starting $(BINARY_NAME) in development mode..." + $(GOCMD) run . + +test: ## Run tests + @echo "Running tests..." + $(GOTEST) -v ./... + +test-cover: ## Run tests with coverage + @echo "Running tests with coverage..." + $(GOTEST) -v -coverprofile=coverage.out ./... + $(GOCMD) tool cover -html=coverage.out -o coverage.html + @echo "Coverage report generated: coverage.html" + +clean: ## Clean build artifacts + @echo "Cleaning..." + $(GOCLEAN) + @rm -rf $(BUILD_DIR) + @rm -f coverage.out coverage.html + +install: build ## Install the binary to $(go env GOPATH)/bin + @echo "Installing $(BINARY_NAME)..." + @mkdir -p $$($(GOCMD) env GOPATH)/bin + @cp $(BUILD_DIR)/$(BINARY_NAME) $$($(GOCMD) env GOPATH)/bin/ + +deps: ## Download dependencies + @echo "Downloading dependencies..." + $(GOMOD) download + $(GOMOD) tidy + +fmt: ## Format Go code + @echo "Formatting code..." + $(GOFMT) ./... + +vet: ## Run go vet + @echo "Running go vet..." + $(GOVET) ./... + +lint: fmt vet ## Run formatters and linters + +check: lint test ## Run all checks (lint + test) + +all: clean lint test build ## Clean, lint, test, and build diff --git a/internal/apps/apps.go b/internal/apps/apps.go index 3b7a6af..4818f1a 100644 --- a/internal/apps/apps.go +++ b/internal/apps/apps.go @@ -485,7 +485,7 @@ func (m *Manager) GetStatus(instanceName, appName string) (*DeployedApp, error) var podList struct { Items []struct { Status struct { - Phase string `json:"phase"` + Phase string `json:"phase"` ContainerStatuses []struct { Ready bool `json:"ready"` } `json:"containerStatuses"` diff --git a/internal/backup/backup.go b/internal/backup/backup.go index d16769c..2fd150c 100644 --- a/internal/backup/backup.go +++ b/internal/backup/backup.go @@ -28,10 +28,10 @@ type BackupInfo struct { // RestoreOptions configures restore behavior type RestoreOptions struct { - DBOnly bool `json:"db_only"` - PVCOnly bool `json:"pvc_only"` - SkipGlobals bool `json:"skip_globals"` - SnapshotID string `json:"snapshot_id,omitempty"` + DBOnly bool `json:"db_only"` + PVCOnly bool `json:"pvc_only"` + SkipGlobals bool `json:"skip_globals"` + SnapshotID string `json:"snapshot_id,omitempty"` } // Manager handles backup and restore operations diff --git a/internal/discovery/discovery.go b/internal/discovery/discovery.go index e3bce54..988899c 100644 --- a/internal/discovery/discovery.go +++ b/internal/discovery/discovery.go @@ -15,9 +15,9 @@ import ( // Manager handles node discovery operations type Manager struct { - dataDir string - nodeMgr *node.Manager - talosctl *tools.Talosctl + dataDir string + nodeMgr *node.Manager + talosctl *tools.Talosctl discoveryMu sync.Mutex } @@ -35,20 +35,20 @@ func NewManager(dataDir string, instanceName string) *Manager { // DiscoveredNode represents a discovered node on the network type DiscoveredNode struct { - IP string `json:"ip"` - Hostname string `json:"hostname,omitempty"` - MaintenanceMode bool `json:"maintenance_mode"` - Version string `json:"version,omitempty"` - Interface string `json:"interface,omitempty"` + IP string `json:"ip"` + Hostname string `json:"hostname,omitempty"` + MaintenanceMode bool `json:"maintenance_mode"` + Version string `json:"version,omitempty"` + Interface string `json:"interface,omitempty"` Disks []string `json:"disks,omitempty"` } // DiscoveryStatus represents the current state of discovery type DiscoveryStatus struct { - Active bool `json:"active"` - StartedAt time.Time `json:"started_at,omitempty"` - NodesFound []DiscoveredNode `json:"nodes_found"` - Error string `json:"error,omitempty"` + Active bool `json:"active"` + StartedAt time.Time `json:"started_at,omitempty"` + NodesFound []DiscoveredNode `json:"nodes_found"` + Error string `json:"error,omitempty"` } // GetDiscoveryDir returns the discovery directory for an instance diff --git a/internal/instance/instance.go b/internal/instance/instance.go index b99b67c..6e55603 100644 --- a/internal/instance/instance.go +++ b/internal/instance/instance.go @@ -13,27 +13,27 @@ import ( // Manager handles instance lifecycle operations type Manager struct { - dataDir string - configMgr *config.Manager - secretsMgr *secrets.Manager - contextMgr *context.Manager + dataDir string + configMgr *config.Manager + secretsMgr *secrets.Manager + contextMgr *context.Manager } // NewManager creates a new instance manager func NewManager(dataDir string) *Manager { return &Manager{ - dataDir: dataDir, - configMgr: config.NewManager(), - secretsMgr: secrets.NewManager(), - contextMgr: context.NewManager(dataDir), + dataDir: dataDir, + configMgr: config.NewManager(), + secretsMgr: secrets.NewManager(), + contextMgr: context.NewManager(dataDir), } } // Instance represents a Wild Cloud instance type Instance struct { - Name string - Path string - ConfigPath string + Name string + Path string + ConfigPath string SecretsPath string } diff --git a/internal/node/node.go b/internal/node/node.go index 87e3408..cd21ad0 100644 --- a/internal/node/node.go +++ b/internal/node/node.go @@ -13,9 +13,9 @@ import ( // Manager handles node configuration and state management type Manager struct { - dataDir string - configMgr *config.Manager - talosctl *tools.Talosctl + dataDir string + configMgr *config.Manager + talosctl *tools.Talosctl } // NewManager creates a new node manager @@ -407,8 +407,8 @@ func (m *Manager) Apply(instanceName, nodeIdentifier string, opts ApplyOptions) // Post-application updates: move to production IP, exit maintenance mode node.Applied = true - node.CurrentIP = node.TargetIP // Node now on production IP - node.Maintenance = false // Exit maintenance mode + node.CurrentIP = node.TargetIP // Node now on production IP + node.Maintenance = false // Exit maintenance mode if err := m.updateNodeStatus(instanceName, node); err != nil { return fmt.Errorf("failed to update node status: %w", err) } diff --git a/internal/operations/operations.go b/internal/operations/operations.go index fc67bab..77d5df2 100644 --- a/internal/operations/operations.go +++ b/internal/operations/operations.go @@ -30,7 +30,7 @@ type Operation struct { Instance string `json:"instance"` Status string `json:"status"` // pending, running, completed, failed, cancelled Message string `json:"message,omitempty"` - Progress int `json:"progress"` // 0-100 + Progress int `json:"progress"` // 0-100 LogFile string `json:"logFile,omitempty"` // Path to output log file StartedAt time.Time `json:"started_at"` EndedAt time.Time `json:"ended_at,omitempty"` diff --git a/internal/secrets/secrets.go b/internal/secrets/secrets.go index 9737ecd..761e2c9 100644 --- a/internal/secrets/secrets.go +++ b/internal/secrets/secrets.go @@ -95,6 +95,11 @@ func (m *Manager) GetSecret(secretsPath, key string) (string, error) { return "", fmt.Errorf("getting secret %s: %w", key, err) } + // yq returns "null" for non-existent keys + if value == "" || value == "null" { + return "", fmt.Errorf("secret not found: %s", key) + } + return value, nil } diff --git a/internal/services/manifest.go b/internal/services/manifest.go index 88cb2ec..2cb0c04 100644 --- a/internal/services/manifest.go +++ b/internal/services/manifest.go @@ -24,9 +24,9 @@ type ServiceManifest struct { // ConfigDefinition defines config that should be prompted during service setup type ConfigDefinition struct { - Path string `yaml:"path" json:"path"` // Config path to set - Prompt string `yaml:"prompt" json:"prompt"` // User prompt text - Default string `yaml:"default" json:"default"` // Default value (supports templates) + Path string `yaml:"path" json:"path"` // Config path to set + Prompt string `yaml:"prompt" json:"prompt"` // User prompt text + Default string `yaml:"default" json:"default"` // Default value (supports templates) Type string `yaml:"type,omitempty" json:"type,omitempty"` // Value type: string|int|bool (default: string) } diff --git a/internal/services/services.go b/internal/services/services.go index 8a606b8..e5f7dc6 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -42,11 +42,11 @@ func NewManager(dataDir, servicesDir string) *Manager { // Service represents a base service type Service struct { - Name string `json:"name"` - Description string `json:"description"` - Status string `json:"status"` - Version string `json:"version"` - Namespace string `json:"namespace"` + Name string `json:"name"` + Description string `json:"description"` + Status string `json:"status"` + Version string `json:"version"` + Namespace string `json:"namespace"` Dependencies []string `json:"dependencies,omitempty"` } @@ -557,8 +557,8 @@ func (m *Manager) Deploy(instanceName, serviceName, opID string, broadcaster *op err := cmd.Run() fmt.Printf("[DEBUG] Command completed for opID=%s, err=%v\n", opID, err) if broadcaster != nil { - outputWriter.Flush() // Flush any remaining buffered data - broadcaster.Close(opID) // Close all SSE clients + outputWriter.Flush() // Flush any remaining buffered data + broadcaster.Close(opID) // Close all SSE clients } return err } else { diff --git a/internal/utilities/utilities.go b/internal/utilities/utilities.go index cf7d6c6..ec432a1 100644 --- a/internal/utilities/utilities.go +++ b/internal/utilities/utilities.go @@ -11,9 +11,9 @@ import ( // HealthStatus represents cluster health information type HealthStatus struct { - Overall string `json:"overall"` // healthy, degraded, unhealthy + Overall string `json:"overall"` // healthy, degraded, unhealthy Components map[string]string `json:"components"` // component -> status - Issues []string `json:"issues"` + Issues []string `json:"issues"` } // DashboardToken represents a Kubernetes dashboard token @@ -96,7 +96,7 @@ func checkComponent(kubeconfigPath, name, namespace, selector string) error { var result struct { Items []struct { Status struct { - Phase string `json:"phase"` + Phase string `json:"phase"` ContainerStatuses []struct { Ready bool `json:"ready"` } `json:"containerStatuses"`