@mytechtoday/augment-extensions 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/augment-extensions/coding-standards/c/CHANGELOG.md +55 -0
- package/augment-extensions/coding-standards/c/LICENSE +22 -0
- package/augment-extensions/coding-standards/c/README.md +167 -0
- package/augment-extensions/coding-standards/c/config/defaults.json +26 -0
- package/augment-extensions/coding-standards/c/config/examples/embedded.yaml +25 -0
- package/augment-extensions/coding-standards/c/config/examples/systems.json +31 -0
- package/augment-extensions/coding-standards/c/config/schema.json +244 -0
- package/augment-extensions/coding-standards/c/docs/API.md +613 -0
- package/augment-extensions/coding-standards/c/docs/CONFIGURATION.md +259 -0
- package/augment-extensions/coding-standards/c/docs/USER_GUIDE.md +567 -0
- package/augment-extensions/coding-standards/c/examples/drivers/Makefile +33 -0
- package/augment-extensions/coding-standards/c/examples/drivers/README.md +192 -0
- package/augment-extensions/coding-standards/c/examples/drivers/dma-example.c +224 -0
- package/augment-extensions/coding-standards/c/examples/drivers/example.dts +64 -0
- package/augment-extensions/coding-standards/c/examples/drivers/platform-driver.c +174 -0
- package/augment-extensions/coding-standards/c/examples/embedded/README.md +167 -0
- package/augment-extensions/coding-standards/c/examples/embedded/gpio-control.c +172 -0
- package/augment-extensions/coding-standards/c/examples/embedded/timer-isr.c +198 -0
- package/augment-extensions/coding-standards/c/examples/embedded/uart-communication.c +212 -0
- package/augment-extensions/coding-standards/c/examples/kernel/Makefile +82 -0
- package/augment-extensions/coding-standards/c/examples/kernel/README.md +168 -0
- package/augment-extensions/coding-standards/c/examples/kernel/char-device.c +198 -0
- package/augment-extensions/coding-standards/c/examples/kernel/proc-file.c +131 -0
- package/augment-extensions/coding-standards/c/examples/kernel/simple-module.c +111 -0
- package/augment-extensions/coding-standards/c/examples/legacy/Makefile +62 -0
- package/augment-extensions/coding-standards/c/examples/legacy/README.md +255 -0
- package/augment-extensions/coding-standards/c/examples/legacy/c89-to-c11-migration.c +268 -0
- package/augment-extensions/coding-standards/c/examples/legacy/compatibility-layer.c +239 -0
- package/augment-extensions/coding-standards/c/examples/networking/Makefile +35 -0
- package/augment-extensions/coding-standards/c/examples/networking/README.md +207 -0
- package/augment-extensions/coding-standards/c/examples/networking/protocol-parser.c +270 -0
- package/augment-extensions/coding-standards/c/examples/networking/tcp-server.c +197 -0
- package/augment-extensions/coding-standards/c/examples/networking/udp-multicast.c +220 -0
- package/augment-extensions/coding-standards/c/examples/realtime/Makefile +53 -0
- package/augment-extensions/coding-standards/c/examples/realtime/README.md +199 -0
- package/augment-extensions/coding-standards/c/examples/realtime/deadline-monitoring.c +260 -0
- package/augment-extensions/coding-standards/c/examples/realtime/priority-scheduling.c +258 -0
- package/augment-extensions/coding-standards/c/examples/systems/Makefile +34 -0
- package/augment-extensions/coding-standards/c/examples/systems/README.md +123 -0
- package/augment-extensions/coding-standards/c/examples/systems/ipc-pipes.c +181 -0
- package/augment-extensions/coding-standards/c/examples/systems/process-management.c +153 -0
- package/augment-extensions/coding-standards/c/examples/systems/signal-handling.c +162 -0
- package/augment-extensions/coding-standards/c/module.json +149 -0
- package/augment-extensions/coding-standards/c/rules/categories/drivers.md +635 -0
- package/augment-extensions/coding-standards/c/rules/categories/embedded.md +510 -0
- package/augment-extensions/coding-standards/c/rules/categories/kernel.md +653 -0
- package/augment-extensions/coding-standards/c/rules/categories/legacy.md +526 -0
- package/augment-extensions/coding-standards/c/rules/categories/networking.md +735 -0
- package/augment-extensions/coding-standards/c/rules/categories/realtime.md +631 -0
- package/augment-extensions/coding-standards/c/rules/categories/systems.md +586 -0
- package/augment-extensions/coding-standards/c/rules/universal/const-correctness.md +275 -0
- package/augment-extensions/coding-standards/c/rules/universal/documentation.md +251 -0
- package/augment-extensions/coding-standards/c/rules/universal/error-handling.md +250 -0
- package/augment-extensions/coding-standards/c/rules/universal/header-guards.md +254 -0
- package/augment-extensions/coding-standards/c/rules/universal/memory-safety.md +233 -0
- package/augment-extensions/coding-standards/c/rules/universal/naming.md +146 -0
- package/augment-extensions/coding-standards/c/src/conflict-detector.ts +461 -0
- package/augment-extensions/coding-standards/c/src/prompt-generator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-evaluator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-override.ts +427 -0
- package/augment-extensions/coding-standards/c/src/template-engine.ts +217 -0
- package/augment-extensions/coding-standards/c/templates/prompts/drivers.txt +191 -0
- package/augment-extensions/coding-standards/c/templates/prompts/embedded.txt +164 -0
- package/augment-extensions/coding-standards/c/templates/prompts/kernel.txt +175 -0
- package/augment-extensions/coding-standards/c/templates/prompts/legacy.txt +280 -0
- package/augment-extensions/coding-standards/c/templates/prompts/networking.txt +259 -0
- package/augment-extensions/coding-standards/c/templates/prompts/realtime.txt +219 -0
- package/augment-extensions/coding-standards/c/templates/prompts/systems.txt +147 -0
- package/augment-extensions/coding-standards/c/tests/integration/category-specific.test.ts +356 -0
- package/augment-extensions/coding-standards/c/tests/integration/end-to-end-workflow.test.ts +377 -0
- package/augment-extensions/coding-standards/c/tests/performance/benchmarks.test.ts +407 -0
- package/augment-extensions/coding-standards/c/tests/unit/config-manager.test.ts +345 -0
- package/augment-extensions/coding-standards/c/tests/unit/conflict-detector.test.ts +294 -0
- package/augment-extensions/coding-standards/c/tests/unit/prompt-generator.test.ts +174 -0
- package/augment-extensions/coding-standards/c/tests/unit/registry.test.ts +313 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-evaluator.test.ts +318 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-override.test.ts +326 -0
- package/augment-extensions/coding-standards/c/tests/unit/template-engine.test.ts +314 -0
- package/augment-extensions/coding-standards/go/CHARACTER-COUNT-REPORT.md +135 -0
- package/augment-extensions/coding-standards/go/PHASE1-COMPLETION.md +146 -0
- package/augment-extensions/coding-standards/go/PHASE4-COMPLETION.md +184 -0
- package/augment-extensions/coding-standards/go/README.md +200 -0
- package/augment-extensions/coding-standards/go/VALIDATION-CHECKLIST.md +154 -0
- package/augment-extensions/coding-standards/go/config/examples/example-cli.json +15 -0
- package/augment-extensions/coding-standards/go/config/examples/example-microservices.json +21 -0
- package/augment-extensions/coding-standards/go/config/examples/example-multi-category.yaml +24 -0
- package/augment-extensions/coding-standards/go/config/examples/example-web.json +15 -0
- package/augment-extensions/coding-standards/go/config/schema.json +110 -0
- package/augment-extensions/coding-standards/go/docs/CATEGORIES.md +221 -0
- package/augment-extensions/coding-standards/go/docs/CONFIGURATION.md +198 -0
- package/augment-extensions/coding-standards/go/docs/TROUBLESHOOTING.md +285 -0
- package/augment-extensions/coding-standards/go/examples/cli/cobra-app.go +287 -0
- package/augment-extensions/coding-standards/go/examples/cloud-native-app.go +217 -0
- package/augment-extensions/coding-standards/go/examples/devops-tool.go +250 -0
- package/augment-extensions/coding-standards/go/examples/distributed-system.go +247 -0
- package/augment-extensions/coding-standards/go/examples/microservices/grpc-service.go +253 -0
- package/augment-extensions/coding-standards/go/examples/rest-api.go +270 -0
- package/augment-extensions/coding-standards/go/examples/web/http-server.go +224 -0
- package/augment-extensions/coding-standards/go/module.json +139 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/api-versioning.md +149 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rate-limiting.md +209 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rest-api-design.md +183 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/cloud-config.md +193 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/health-checks.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/kubernetes.md +180 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/automation.md +179 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/ci-cd-integration.md +147 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/infrastructure-as-code.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/caching.md +150 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/consensus.md +187 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/event-sourcing.md +246 -0
- package/augment-extensions/coding-standards/go/rules/cli/command-parsing.md +264 -0
- package/augment-extensions/coding-standards/go/rules/cli/configuration.md +268 -0
- package/augment-extensions/coding-standards/go/rules/cli/cross-platform.md +324 -0
- package/augment-extensions/coding-standards/go/rules/microservices/distributed-tracing.md +253 -0
- package/augment-extensions/coding-standards/go/rules/microservices/grpc.md +257 -0
- package/augment-extensions/coding-standards/go/rules/microservices/metrics.md +278 -0
- package/augment-extensions/coding-standards/go/rules/microservices/service-discovery.md +249 -0
- package/augment-extensions/coding-standards/go/rules/universal/code-organization.md +221 -0
- package/augment-extensions/coding-standards/go/rules/universal/documentation.md +269 -0
- package/augment-extensions/coding-standards/go/rules/universal/performance.md +323 -0
- package/augment-extensions/coding-standards/go/rules/universal/testing.md +162 -0
- package/augment-extensions/coding-standards/go/rules/web/graceful-shutdown.md +249 -0
- package/augment-extensions/coding-standards/go/rules/web/http-handlers.md +164 -0
- package/augment-extensions/coding-standards/go/rules/web/middleware.md +234 -0
- package/augment-extensions/coding-standards/go/rules/web/routing.md +251 -0
- package/augment-extensions/coding-standards/go/templates/prompts/api.md +160 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cli.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cloud-native.md +121 -0
- package/augment-extensions/coding-standards/go/templates/prompts/devops.md +146 -0
- package/augment-extensions/coding-standards/go/templates/prompts/distributed.md +133 -0
- package/augment-extensions/coding-standards/go/templates/prompts/microservices.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/web.md +181 -0
- package/augment-extensions/coding-standards/go/tests/integration/module-integration.test.ts +164 -0
- package/augment-extensions/coding-standards/go/tests/unit/category-selection.test.ts +147 -0
- package/augment-extensions/coding-standards/go/tests/unit/module-structure.test.ts +154 -0
- package/augment-extensions/coding-standards/go/tests/validate-character-count.ps1 +13 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.ps1 +148 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.sh +135 -0
- package/cli/dist/analysis/ast-parser.d.ts +47 -0
- package/cli/dist/analysis/ast-parser.d.ts.map +1 -0
- package/cli/dist/analysis/ast-parser.js +161 -0
- package/cli/dist/analysis/ast-parser.js.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts +27 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.js +189 -0
- package/cli/dist/analysis/complexity-analyzer.js.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts +23 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.js +237 -0
- package/cli/dist/analysis/dependency-analyzer.js.map +1 -0
- package/cli/dist/analysis/index.d.ts +9 -0
- package/cli/dist/analysis/index.d.ts.map +1 -0
- package/cli/dist/analysis/index.js +25 -0
- package/cli/dist/analysis/index.js.map +1 -0
- package/cli/dist/analysis/security-scanner.d.ts +11 -0
- package/cli/dist/analysis/security-scanner.d.ts.map +1 -0
- package/cli/dist/analysis/security-scanner.js +294 -0
- package/cli/dist/analysis/security-scanner.js.map +1 -0
- package/cli/dist/analysis/types.d.ts +151 -0
- package/cli/dist/analysis/types.d.ts.map +1 -0
- package/cli/dist/analysis/types.js +6 -0
- package/cli/dist/analysis/types.js.map +1 -0
- package/cli/dist/cli.js +24 -0
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/code-analysis.d.ts +11 -0
- package/cli/dist/commands/code-analysis.d.ts.map +1 -0
- package/cli/dist/commands/code-analysis.js +412 -0
- package/cli/dist/commands/code-analysis.js.map +1 -0
- package/modules.md +99 -3
- package/package.json +14 -2
- package/cli/dist/commands/agent.d.ts +0 -37
- package/cli/dist/commands/agent.d.ts.map +0 -1
- package/cli/dist/commands/agent.js +0 -222
- package/cli/dist/commands/agent.js.map +0 -1
- package/cli/dist/commands/beads.d.ts +0 -64
- package/cli/dist/commands/beads.d.ts.map +0 -1
- package/cli/dist/commands/beads.js +0 -377
- package/cli/dist/commands/beads.js.map +0 -1
- package/cli/dist/commands/change.d.ts +0 -54
- package/cli/dist/commands/change.d.ts.map +0 -1
- package/cli/dist/commands/change.js +0 -243
- package/cli/dist/commands/change.js.map +0 -1
- package/cli/dist/commands/clean.d.ts +0 -15
- package/cli/dist/commands/clean.d.ts.map +0 -1
- package/cli/dist/commands/clean.js +0 -63
- package/cli/dist/commands/clean.js.map +0 -1
- package/cli/dist/commands/clone.d.ts +0 -15
- package/cli/dist/commands/clone.d.ts.map +0 -1
- package/cli/dist/commands/clone.js +0 -49
- package/cli/dist/commands/clone.js.map +0 -1
- package/cli/dist/commands/config.d.ts +0 -33
- package/cli/dist/commands/config.d.ts.map +0 -1
- package/cli/dist/commands/config.js +0 -166
- package/cli/dist/commands/config.js.map +0 -1
- package/cli/dist/commands/context.d.ts +0 -38
- package/cli/dist/commands/context.d.ts.map +0 -1
- package/cli/dist/commands/context.js +0 -205
- package/cli/dist/commands/context.js.map +0 -1
- package/cli/dist/commands/create.d.ts +0 -18
- package/cli/dist/commands/create.d.ts.map +0 -1
- package/cli/dist/commands/create.js +0 -178
- package/cli/dist/commands/create.js.map +0 -1
- package/cli/dist/commands/diff.d.ts +0 -19
- package/cli/dist/commands/diff.d.ts.map +0 -1
- package/cli/dist/commands/diff.js +0 -104
- package/cli/dist/commands/diff.js.map +0 -1
- package/cli/dist/commands/doctor.d.ts +0 -14
- package/cli/dist/commands/doctor.d.ts.map +0 -1
- package/cli/dist/commands/doctor.js +0 -62
- package/cli/dist/commands/doctor.js.map +0 -1
- package/cli/dist/commands/export.d.ts +0 -28
- package/cli/dist/commands/export.d.ts.map +0 -1
- package/cli/dist/commands/export.js +0 -135
- package/cli/dist/commands/export.js.map +0 -1
- package/cli/dist/commands/import.d.ts +0 -23
- package/cli/dist/commands/import.d.ts.map +0 -1
- package/cli/dist/commands/import.js +0 -118
- package/cli/dist/commands/import.js.map +0 -1
- package/cli/dist/commands/prompt.d.ts +0 -45
- package/cli/dist/commands/prompt.d.ts.map +0 -1
- package/cli/dist/commands/prompt.js +0 -223
- package/cli/dist/commands/prompt.js.map +0 -1
- package/cli/dist/commands/spec.d.ts +0 -57
- package/cli/dist/commands/spec.d.ts.map +0 -1
- package/cli/dist/commands/spec.js +0 -279
- package/cli/dist/commands/spec.js.map +0 -1
- package/cli/dist/commands/stats.d.ts +0 -18
- package/cli/dist/commands/stats.d.ts.map +0 -1
- package/cli/dist/commands/stats.js +0 -85
- package/cli/dist/commands/stats.js.map +0 -1
- package/cli/dist/commands/task.d.ts +0 -65
- package/cli/dist/commands/task.d.ts.map +0 -1
- package/cli/dist/commands/task.js +0 -282
- package/cli/dist/commands/task.js.map +0 -1
- package/cli/dist/commands/template.d.ts +0 -17
- package/cli/dist/commands/template.d.ts.map +0 -1
- package/cli/dist/commands/template.js +0 -55
- package/cli/dist/commands/template.js.map +0 -1
- package/cli/dist/utils/agent-config.d.ts +0 -129
- package/cli/dist/utils/agent-config.d.ts.map +0 -1
- package/cli/dist/utils/agent-config.js +0 -297
- package/cli/dist/utils/agent-config.js.map +0 -1
- package/cli/dist/utils/beads-graph.d.ts +0 -17
- package/cli/dist/utils/beads-graph.d.ts.map +0 -1
- package/cli/dist/utils/beads-graph.js +0 -150
- package/cli/dist/utils/beads-graph.js.map +0 -1
- package/cli/dist/utils/beads-integration.d.ts +0 -112
- package/cli/dist/utils/beads-integration.d.ts.map +0 -1
- package/cli/dist/utils/beads-integration.js +0 -312
- package/cli/dist/utils/beads-integration.js.map +0 -1
- package/cli/dist/utils/beads-reporter.d.ts +0 -17
- package/cli/dist/utils/beads-reporter.d.ts.map +0 -1
- package/cli/dist/utils/beads-reporter.js +0 -160
- package/cli/dist/utils/beads-reporter.js.map +0 -1
- package/cli/dist/utils/cache-manager.d.ts +0 -55
- package/cli/dist/utils/cache-manager.d.ts.map +0 -1
- package/cli/dist/utils/cache-manager.js +0 -150
- package/cli/dist/utils/cache-manager.js.map +0 -1
- package/cli/dist/utils/change-manager.d.ts +0 -70
- package/cli/dist/utils/change-manager.d.ts.map +0 -1
- package/cli/dist/utils/change-manager.js +0 -412
- package/cli/dist/utils/change-manager.js.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.d.ts +0 -66
- package/cli/dist/utils/config-manager-enhanced.d.ts.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.js +0 -77
- package/cli/dist/utils/config-manager-enhanced.js.map +0 -1
- package/cli/dist/utils/context-manager.d.ts +0 -96
- package/cli/dist/utils/context-manager.d.ts.map +0 -1
- package/cli/dist/utils/context-manager.js +0 -258
- package/cli/dist/utils/context-manager.js.map +0 -1
- package/cli/dist/utils/diff-engine.d.ts +0 -78
- package/cli/dist/utils/diff-engine.d.ts.map +0 -1
- package/cli/dist/utils/diff-engine.js +0 -233
- package/cli/dist/utils/diff-engine.js.map +0 -1
- package/cli/dist/utils/export-system.d.ts +0 -101
- package/cli/dist/utils/export-system.d.ts.map +0 -1
- package/cli/dist/utils/export-system.js +0 -289
- package/cli/dist/utils/export-system.js.map +0 -1
- package/cli/dist/utils/health-checker.d.ts +0 -66
- package/cli/dist/utils/health-checker.d.ts.map +0 -1
- package/cli/dist/utils/health-checker.js +0 -285
- package/cli/dist/utils/health-checker.js.map +0 -1
- package/cli/dist/utils/import-system.d.ts +0 -74
- package/cli/dist/utils/import-system.d.ts.map +0 -1
- package/cli/dist/utils/import-system.js +0 -317
- package/cli/dist/utils/import-system.js.map +0 -1
- package/cli/dist/utils/module-cloner.d.ts +0 -40
- package/cli/dist/utils/module-cloner.d.ts.map +0 -1
- package/cli/dist/utils/module-cloner.js +0 -136
- package/cli/dist/utils/module-cloner.js.map +0 -1
- package/cli/dist/utils/prompt-manager.d.ts +0 -90
- package/cli/dist/utils/prompt-manager.d.ts.map +0 -1
- package/cli/dist/utils/prompt-manager.js +0 -302
- package/cli/dist/utils/prompt-manager.js.map +0 -1
- package/cli/dist/utils/spec-manager.d.ts +0 -65
- package/cli/dist/utils/spec-manager.d.ts.map +0 -1
- package/cli/dist/utils/spec-manager.js +0 -329
- package/cli/dist/utils/spec-manager.js.map +0 -1
- package/cli/dist/utils/stats-collector.d.ts +0 -74
- package/cli/dist/utils/stats-collector.d.ts.map +0 -1
- package/cli/dist/utils/stats-collector.js +0 -164
- package/cli/dist/utils/stats-collector.js.map +0 -1
- package/cli/dist/utils/template-engine.d.ts +0 -47
- package/cli/dist/utils/template-engine.d.ts.map +0 -1
- package/cli/dist/utils/template-engine.js +0 -204
- package/cli/dist/utils/template-engine.js.map +0 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Health Check and Readiness Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for implementing health checks, readiness probes, and liveness probes in cloud-native Go applications.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Implement Separate Health and Readiness Endpoints
|
|
10
|
+
|
|
11
|
+
**Rule**: Provide separate `/health` (liveness) and `/ready` (readiness) endpoints.
|
|
12
|
+
|
|
13
|
+
**Rationale**: Liveness checks determine if the app should be restarted; readiness checks determine if it can receive traffic.
|
|
14
|
+
|
|
15
|
+
**Good Example**:
|
|
16
|
+
```go
|
|
17
|
+
func healthHandler(w http.ResponseWriter, r *http.Request) {
|
|
18
|
+
w.WriteHeader(http.StatusOK)
|
|
19
|
+
w.Write([]byte("OK"))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func readinessHandler(db *sql.DB) http.HandlerFunc {
|
|
23
|
+
return func(w http.ResponseWriter, r *http.Request) {
|
|
24
|
+
// Check database connection
|
|
25
|
+
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
|
|
26
|
+
defer cancel()
|
|
27
|
+
|
|
28
|
+
if err := db.PingContext(ctx); err != nil {
|
|
29
|
+
w.WriteHeader(http.StatusServiceUnavailable)
|
|
30
|
+
w.Write([]byte("Database unavailable"))
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
w.WriteHeader(http.StatusOK)
|
|
35
|
+
w.Write([]byte("Ready"))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func main() {
|
|
40
|
+
db, _ := sql.Open("postgres", dsn)
|
|
41
|
+
|
|
42
|
+
http.HandleFunc("/health", healthHandler)
|
|
43
|
+
http.HandleFunc("/ready", readinessHandler(db))
|
|
44
|
+
|
|
45
|
+
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Keep Health Checks Lightweight
|
|
50
|
+
|
|
51
|
+
**Rule**: Health checks should be fast (<1s) and not perform expensive operations.
|
|
52
|
+
|
|
53
|
+
**Good Example**:
|
|
54
|
+
```go
|
|
55
|
+
type HealthChecker struct {
|
|
56
|
+
checks map[string]HealthCheck
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type HealthCheck func(context.Context) error
|
|
60
|
+
|
|
61
|
+
func (hc *HealthChecker) AddCheck(name string, check HealthCheck) {
|
|
62
|
+
hc.checks[name] = check
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func (hc *HealthChecker) Check(ctx context.Context) (map[string]string, error) {
|
|
66
|
+
results := make(map[string]string)
|
|
67
|
+
var hasError bool
|
|
68
|
+
|
|
69
|
+
for name, check := range hc.checks {
|
|
70
|
+
checkCtx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
|
71
|
+
defer cancel()
|
|
72
|
+
|
|
73
|
+
if err := check(checkCtx); err != nil {
|
|
74
|
+
results[name] = fmt.Sprintf("FAIL: %v", err)
|
|
75
|
+
hasError = true
|
|
76
|
+
} else {
|
|
77
|
+
results[name] = "OK"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if hasError {
|
|
82
|
+
return results, fmt.Errorf("health check failed")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return results, nil
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3. Include Dependency Checks in Readiness
|
|
90
|
+
|
|
91
|
+
**Rule**: Readiness probes should verify all critical dependencies are available.
|
|
92
|
+
|
|
93
|
+
**Good Example**:
|
|
94
|
+
```go
|
|
95
|
+
func NewReadinessChecker(db *sql.DB, cache *redis.Client) *HealthChecker {
|
|
96
|
+
hc := &HealthChecker{checks: make(map[string]HealthCheck)}
|
|
97
|
+
|
|
98
|
+
// Database check
|
|
99
|
+
hc.AddCheck("database", func(ctx context.Context) error {
|
|
100
|
+
return db.PingContext(ctx)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
// Cache check
|
|
104
|
+
hc.AddCheck("cache", func(ctx context.Context) error {
|
|
105
|
+
return cache.Ping(ctx).Err()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// External API check (optional)
|
|
109
|
+
hc.AddCheck("external_api", func(ctx context.Context) error {
|
|
110
|
+
req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com/health", nil)
|
|
111
|
+
resp, err := http.DefaultClient.Do(req)
|
|
112
|
+
if err != nil {
|
|
113
|
+
return err
|
|
114
|
+
}
|
|
115
|
+
defer resp.Body.Close()
|
|
116
|
+
|
|
117
|
+
if resp.StatusCode != http.StatusOK {
|
|
118
|
+
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
|
|
119
|
+
}
|
|
120
|
+
return nil
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
return hc
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4. Return Detailed Status Information
|
|
128
|
+
|
|
129
|
+
**Rule**: Return structured health check responses with component-level details.
|
|
130
|
+
|
|
131
|
+
**Good Example**:
|
|
132
|
+
```go
|
|
133
|
+
type HealthResponse struct {
|
|
134
|
+
Status string `json:"status"`
|
|
135
|
+
Timestamp time.Time `json:"timestamp"`
|
|
136
|
+
Components map[string]string `json:"components"`
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func healthCheckHandler(checker *HealthChecker) http.HandlerFunc {
|
|
140
|
+
return func(w http.ResponseWriter, r *http.Request) {
|
|
141
|
+
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
|
142
|
+
defer cancel()
|
|
143
|
+
|
|
144
|
+
components, err := checker.Check(ctx)
|
|
145
|
+
|
|
146
|
+
response := HealthResponse{
|
|
147
|
+
Timestamp: time.Now(),
|
|
148
|
+
Components: components,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if err != nil {
|
|
152
|
+
response.Status = "unhealthy"
|
|
153
|
+
w.WriteHeader(http.StatusServiceUnavailable)
|
|
154
|
+
} else {
|
|
155
|
+
response.Status = "healthy"
|
|
156
|
+
w.WriteHeader(http.StatusOK)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
w.Header().Set("Content-Type", "application/json")
|
|
160
|
+
json.NewEncoder(w).Encode(response)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 5. Implement Graceful Degradation
|
|
166
|
+
|
|
167
|
+
**Rule**: Allow the application to continue running with degraded functionality when non-critical dependencies fail.
|
|
168
|
+
|
|
169
|
+
**Good Example**:
|
|
170
|
+
```go
|
|
171
|
+
type ServiceHealth struct {
|
|
172
|
+
mu sync.RWMutex
|
|
173
|
+
cacheAvailable bool
|
|
174
|
+
searchAvailable bool
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
func (sh *ServiceHealth) SetCacheAvailable(available bool) {
|
|
178
|
+
sh.mu.Lock()
|
|
179
|
+
defer sh.mu.Unlock()
|
|
180
|
+
sh.cacheAvailable = available
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
func (sh *ServiceHealth) IsCacheAvailable() bool {
|
|
184
|
+
sh.mu.RLock()
|
|
185
|
+
defer sh.mu.RUnlock()
|
|
186
|
+
return sh.cacheAvailable
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
func (sh *ServiceHealth) MonitorDependencies(ctx context.Context, cache *redis.Client) {
|
|
190
|
+
ticker := time.NewTicker(10 * time.Second)
|
|
191
|
+
defer ticker.Stop()
|
|
192
|
+
|
|
193
|
+
for {
|
|
194
|
+
select {
|
|
195
|
+
case <-ctx.Done():
|
|
196
|
+
return
|
|
197
|
+
case <-ticker.C:
|
|
198
|
+
checkCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
|
199
|
+
err := cache.Ping(checkCtx).Err()
|
|
200
|
+
cancel()
|
|
201
|
+
|
|
202
|
+
sh.SetCacheAvailable(err == nil)
|
|
203
|
+
|
|
204
|
+
if err != nil {
|
|
205
|
+
log.Printf("Cache unavailable: %v (degraded mode)", err)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
func getData(sh *ServiceHealth, cache *redis.Client, db *sql.DB, key string) (string, error) {
|
|
212
|
+
// Try cache first if available
|
|
213
|
+
if sh.IsCacheAvailable() {
|
|
214
|
+
val, err := cache.Get(context.Background(), key).Result()
|
|
215
|
+
if err == nil {
|
|
216
|
+
return val, nil
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Fallback to database
|
|
221
|
+
var value string
|
|
222
|
+
err := db.QueryRow("SELECT value FROM data WHERE key = $1", key).Scan(&value)
|
|
223
|
+
return value, err
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## References
|
|
228
|
+
|
|
229
|
+
- [Kubernetes Liveness and Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)
|
|
230
|
+
- [Health Check Response Format for HTTP APIs](https://tools.ietf.org/id/draft-inadarei-api-health-check-06.html)
|
|
231
|
+
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Kubernetes Integration Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for building Kubernetes-native Go applications including client-go usage, custom controllers, operators, and resource management.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Official Kubernetes Client Libraries
|
|
10
|
+
|
|
11
|
+
**Rule**: Always use `k8s.io/client-go` for Kubernetes API interactions.
|
|
12
|
+
|
|
13
|
+
**Rationale**: Official client libraries provide type-safe, versioned access to Kubernetes APIs with proper error handling and retry logic.
|
|
14
|
+
|
|
15
|
+
**Good Example**:
|
|
16
|
+
```go
|
|
17
|
+
import (
|
|
18
|
+
"k8s.io/client-go/kubernetes"
|
|
19
|
+
"k8s.io/client-go/rest"
|
|
20
|
+
"k8s.io/client-go/tools/clientcmd"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
func NewK8sClient() (*kubernetes.Clientset, error) {
|
|
24
|
+
config, err := rest.InClusterConfig()
|
|
25
|
+
if err != nil {
|
|
26
|
+
// Fallback to kubeconfig for local development
|
|
27
|
+
config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
|
|
28
|
+
if err != nil {
|
|
29
|
+
return nil, fmt.Errorf("failed to build config: %w", err)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
clientset, err := kubernetes.NewForConfig(config)
|
|
34
|
+
if err != nil {
|
|
35
|
+
return nil, fmt.Errorf("failed to create clientset: %w", err)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return clientset, nil
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Implement Proper Resource Watching
|
|
43
|
+
|
|
44
|
+
**Rule**: Use informers and listers for efficient resource watching instead of polling.
|
|
45
|
+
|
|
46
|
+
**Rationale**: Informers provide efficient, cached access to Kubernetes resources with automatic updates.
|
|
47
|
+
|
|
48
|
+
**Good Example**:
|
|
49
|
+
```go
|
|
50
|
+
import (
|
|
51
|
+
"k8s.io/client-go/informers"
|
|
52
|
+
"k8s.io/client-go/tools/cache"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
func WatchPods(clientset *kubernetes.Clientset) {
|
|
56
|
+
factory := informers.NewSharedInformerFactory(clientset, 30*time.Second)
|
|
57
|
+
podInformer := factory.Core().V1().Pods().Informer()
|
|
58
|
+
|
|
59
|
+
podInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
|
60
|
+
AddFunc: func(obj interface{}) {
|
|
61
|
+
pod := obj.(*corev1.Pod)
|
|
62
|
+
log.Printf("Pod added: %s/%s", pod.Namespace, pod.Name)
|
|
63
|
+
},
|
|
64
|
+
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
65
|
+
pod := newObj.(*corev1.Pod)
|
|
66
|
+
log.Printf("Pod updated: %s/%s", pod.Namespace, pod.Name)
|
|
67
|
+
},
|
|
68
|
+
DeleteFunc: func(obj interface{}) {
|
|
69
|
+
pod := obj.(*corev1.Pod)
|
|
70
|
+
log.Printf("Pod deleted: %s/%s", pod.Namespace, pod.Name)
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
stopCh := make(chan struct{})
|
|
75
|
+
defer close(stopCh)
|
|
76
|
+
|
|
77
|
+
factory.Start(stopCh)
|
|
78
|
+
factory.WaitForCacheSync(stopCh)
|
|
79
|
+
|
|
80
|
+
<-stopCh
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Handle API Errors Gracefully
|
|
85
|
+
|
|
86
|
+
**Rule**: Check for specific Kubernetes API errors using `apierrors` package.
|
|
87
|
+
|
|
88
|
+
**Good Example**:
|
|
89
|
+
```go
|
|
90
|
+
import "k8s.io/apimachinery/pkg/api/errors"
|
|
91
|
+
|
|
92
|
+
func GetPod(clientset *kubernetes.Clientset, namespace, name string) (*corev1.Pod, error) {
|
|
93
|
+
pod, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
|
94
|
+
if err != nil {
|
|
95
|
+
if errors.IsNotFound(err) {
|
|
96
|
+
return nil, fmt.Errorf("pod %s/%s not found", namespace, name)
|
|
97
|
+
}
|
|
98
|
+
if errors.IsUnauthorized(err) {
|
|
99
|
+
return nil, fmt.Errorf("unauthorized to access pod: %w", err)
|
|
100
|
+
}
|
|
101
|
+
return nil, fmt.Errorf("failed to get pod: %w", err)
|
|
102
|
+
}
|
|
103
|
+
return pod, nil
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 4. Use Controller Runtime for Custom Controllers
|
|
108
|
+
|
|
109
|
+
**Rule**: Use `sigs.k8s.io/controller-runtime` for building custom controllers and operators.
|
|
110
|
+
|
|
111
|
+
**Good Example**:
|
|
112
|
+
```go
|
|
113
|
+
import (
|
|
114
|
+
ctrl "sigs.k8s.io/controller-runtime"
|
|
115
|
+
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
type PodReconciler struct {
|
|
119
|
+
client.Client
|
|
120
|
+
Scheme *runtime.Scheme
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
124
|
+
var pod corev1.Pod
|
|
125
|
+
if err := r.Get(ctx, req.NamespacedName, &pod); err != nil {
|
|
126
|
+
if errors.IsNotFound(err) {
|
|
127
|
+
return ctrl.Result{}, nil
|
|
128
|
+
}
|
|
129
|
+
return ctrl.Result{}, err
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Reconciliation logic here
|
|
133
|
+
|
|
134
|
+
return ctrl.Result{}, nil
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 5. Implement Leader Election for High Availability
|
|
139
|
+
|
|
140
|
+
**Rule**: Use leader election for controllers running in multiple replicas.
|
|
141
|
+
|
|
142
|
+
**Good Example**:
|
|
143
|
+
```go
|
|
144
|
+
import "k8s.io/client-go/tools/leaderelection"
|
|
145
|
+
|
|
146
|
+
func RunWithLeaderElection(ctx context.Context, clientset *kubernetes.Clientset) {
|
|
147
|
+
lock := &resourcelock.LeaseLock{
|
|
148
|
+
LeaseMeta: metav1.ObjectMeta{
|
|
149
|
+
Name: "my-controller",
|
|
150
|
+
Namespace: "default",
|
|
151
|
+
},
|
|
152
|
+
Client: clientset.CoordinationV1(),
|
|
153
|
+
LockConfig: resourcelock.ResourceLockConfig{
|
|
154
|
+
Identity: os.Getenv("POD_NAME"),
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
|
|
159
|
+
Lock: lock,
|
|
160
|
+
LeaseDuration: 15 * time.Second,
|
|
161
|
+
RenewDeadline: 10 * time.Second,
|
|
162
|
+
RetryPeriod: 2 * time.Second,
|
|
163
|
+
Callbacks: leaderelection.LeaderCallbacks{
|
|
164
|
+
OnStartedLeading: func(ctx context.Context) {
|
|
165
|
+
// Start controller logic
|
|
166
|
+
},
|
|
167
|
+
OnStoppedLeading: func() {
|
|
168
|
+
log.Fatal("lost leadership")
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## References
|
|
176
|
+
|
|
177
|
+
- [Kubernetes Client-Go](https://github.com/kubernetes/client-go)
|
|
178
|
+
- [Controller Runtime](https://github.com/kubernetes-sigs/controller-runtime)
|
|
179
|
+
- [Kubebuilder Book](https://book.kubebuilder.io/)
|
|
180
|
+
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# DevOps Automation Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for building DevOps automation tools in Go including CLI tools, deployment automation, and infrastructure management.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Cobra for CLI Applications
|
|
10
|
+
|
|
11
|
+
**Rule**: Use Cobra framework for building command-line tools with subcommands.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
import "github.com/spf13/cobra"
|
|
16
|
+
|
|
17
|
+
var rootCmd = &cobra.Command{
|
|
18
|
+
Use: "devops-tool",
|
|
19
|
+
Short: "A DevOps automation tool",
|
|
20
|
+
Long: `A comprehensive DevOps automation tool for deployment and infrastructure management.`,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
var deployCmd = &cobra.Command{
|
|
24
|
+
Use: "deploy [environment]",
|
|
25
|
+
Short: "Deploy application to environment",
|
|
26
|
+
Args: cobra.ExactArgs(1),
|
|
27
|
+
RunE: func(cmd *cobra.Command, args []string) error {
|
|
28
|
+
environment := args[0]
|
|
29
|
+
return deployToEnvironment(environment)
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func init() {
|
|
34
|
+
deployCmd.Flags().StringP("version", "v", "latest", "Version to deploy")
|
|
35
|
+
deployCmd.Flags().BoolP("dry-run", "d", false, "Perform dry run")
|
|
36
|
+
rootCmd.AddCommand(deployCmd)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Implement Idempotent Operations
|
|
41
|
+
|
|
42
|
+
**Rule**: All automation operations should be idempotent and safe to retry.
|
|
43
|
+
|
|
44
|
+
**Good Example**:
|
|
45
|
+
```go
|
|
46
|
+
func EnsureDeployment(ctx context.Context, config *DeploymentConfig) error {
|
|
47
|
+
// Check if deployment already exists
|
|
48
|
+
existing, err := getDeployment(ctx, config.Name)
|
|
49
|
+
if err != nil && !isNotFoundError(err) {
|
|
50
|
+
return err
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if existing != nil {
|
|
54
|
+
// Update existing deployment
|
|
55
|
+
if deploymentMatches(existing, config) {
|
|
56
|
+
log.Printf("Deployment %s already up to date", config.Name)
|
|
57
|
+
return nil
|
|
58
|
+
}
|
|
59
|
+
return updateDeployment(ctx, config)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Create new deployment
|
|
63
|
+
return createDeployment(ctx, config)
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. Provide Detailed Progress Feedback
|
|
68
|
+
|
|
69
|
+
**Rule**: Show progress for long-running operations with clear status updates.
|
|
70
|
+
|
|
71
|
+
**Good Example**:
|
|
72
|
+
```go
|
|
73
|
+
import "github.com/schollz/progressbar/v3"
|
|
74
|
+
|
|
75
|
+
func DeployWithProgress(ctx context.Context, steps []DeploymentStep) error {
|
|
76
|
+
bar := progressbar.NewOptions(len(steps),
|
|
77
|
+
progressbar.OptionSetDescription("Deploying..."),
|
|
78
|
+
progressbar.OptionShowCount(),
|
|
79
|
+
progressbar.OptionSetWidth(40),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
for i, step := range steps {
|
|
83
|
+
bar.Describe(step.Description)
|
|
84
|
+
|
|
85
|
+
if err := step.Execute(ctx); err != nil {
|
|
86
|
+
return fmt.Errorf("step %d failed: %w", i+1, err)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
bar.Add(1)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return nil
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Support Dry-Run Mode
|
|
97
|
+
|
|
98
|
+
**Rule**: Implement dry-run mode for all destructive operations.
|
|
99
|
+
|
|
100
|
+
**Good Example**:
|
|
101
|
+
```go
|
|
102
|
+
type DeploymentOptions struct {
|
|
103
|
+
DryRun bool
|
|
104
|
+
Verbose bool
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
func Deploy(ctx context.Context, config *DeploymentConfig, opts *DeploymentOptions) error {
|
|
108
|
+
steps := []DeploymentStep{
|
|
109
|
+
{Name: "Validate config", Fn: validateConfig},
|
|
110
|
+
{Name: "Build image", Fn: buildImage},
|
|
111
|
+
{Name: "Push image", Fn: pushImage},
|
|
112
|
+
{Name: "Update deployment", Fn: updateDeployment},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
for _, step := range steps {
|
|
116
|
+
if opts.Verbose {
|
|
117
|
+
log.Printf("Executing: %s", step.Name)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if opts.DryRun {
|
|
121
|
+
log.Printf("[DRY RUN] Would execute: %s", step.Name)
|
|
122
|
+
continue
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if err := step.Fn(ctx, config); err != nil {
|
|
126
|
+
return fmt.Errorf("%s failed: %w", step.Name, err)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return nil
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 5. Implement Rollback Capability
|
|
135
|
+
|
|
136
|
+
**Rule**: Provide rollback functionality for failed deployments.
|
|
137
|
+
|
|
138
|
+
**Good Example**:
|
|
139
|
+
```go
|
|
140
|
+
type DeploymentHistory struct {
|
|
141
|
+
Deployments []DeploymentRecord
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
type DeploymentRecord struct {
|
|
145
|
+
Version string
|
|
146
|
+
Timestamp time.Time
|
|
147
|
+
Config *DeploymentConfig
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
func DeployWithRollback(ctx context.Context, config *DeploymentConfig) error {
|
|
151
|
+
// Save current state
|
|
152
|
+
currentState, err := captureCurrentState(ctx)
|
|
153
|
+
if err != nil {
|
|
154
|
+
return err
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Attempt deployment
|
|
158
|
+
if err := deploy(ctx, config); err != nil {
|
|
159
|
+
log.Printf("Deployment failed: %v, rolling back...", err)
|
|
160
|
+
|
|
161
|
+
if rollbackErr := rollback(ctx, currentState); rollbackErr != nil {
|
|
162
|
+
return fmt.Errorf("deployment failed and rollback failed: %v, %v", err, rollbackErr)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return fmt.Errorf("deployment failed (rolled back): %w", err)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Save successful deployment to history
|
|
169
|
+
saveDeploymentHistory(ctx, config)
|
|
170
|
+
|
|
171
|
+
return nil
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## References
|
|
176
|
+
|
|
177
|
+
- [Cobra CLI Framework](https://github.com/spf13/cobra)
|
|
178
|
+
- [The Twelve-Factor App](https://12factor.net/)
|
|
179
|
+
|