Skip to content

Commit 08fd655

Browse files
committed
STAC-23598: Restoring Stackgraph
1 parent 6123f01 commit 08fd655

57 files changed

Lines changed: 6133 additions & 228 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ARCHITECTURE.md

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# Repository Architecture
2+
3+
This document describes the overall architecture and package organization of the StackState Backup CLI.
4+
5+
## Design Philosophy
6+
7+
The codebase follows several key principles:
8+
9+
1. **Layered Architecture**: Dependencies flow from higher layers (commands) to lower layers (foundation utilities)
10+
2. **Self-Documenting Structure**: Directory hierarchy makes dependency rules and module purposes explicit
11+
3. **Clean Separation**: Domain logic, infrastructure, and presentation are clearly separated
12+
4. **Testability**: Lower layers can be tested independently without external dependencies
13+
5. **Reusability**: Shared functionality is extracted into appropriate packages
14+
15+
## Repository Structure
16+
17+
```
18+
stackstate-backup-cli/
19+
├── cmd/ # Command-line interface (Layer 3)
20+
│ ├── root.go # Root command and global flags
21+
│ ├── version/ # Version information command
22+
│ ├── elasticsearch/ # Elasticsearch backup/restore commands
23+
│ └── stackgraph/ # Stackgraph backup/restore commands
24+
25+
├── internal/ # Internal packages (Layers 0-2)
26+
│ ├── foundation/ # Layer 0: Core utilities
27+
│ │ ├── config/ # Configuration management
28+
│ │ ├── logger/ # Structured logging
29+
│ │ └── output/ # Output formatting
30+
│ │
31+
│ ├── clients/ # Layer 1: Service clients
32+
│ │ ├── k8s/ # Kubernetes client
33+
│ │ ├── elasticsearch/ # Elasticsearch client
34+
│ │ └── s3/ # S3/Minio client
35+
│ │
36+
│ ├── orchestration/ # Layer 2: Workflows
37+
│ │ ├── portforward/ # Port-forwarding orchestration
38+
│ │ └── scale/ # Deployment scaling workflows
39+
│ │
40+
│ └── scripts/ # Embedded bash scripts
41+
42+
├── main.go # Application entry point
43+
├── ARCHITECTURE.md # This file
44+
└── README.md # User documentation
45+
```
46+
47+
## Architectural Layers
48+
49+
### Layer 3: Commands (`cmd/`)
50+
51+
**Purpose**: User-facing CLI commands and application entry points
52+
53+
**Characteristics**:
54+
- Implements the Cobra command structure
55+
- Handles user input validation and flag parsing
56+
- Orchestrates calls to lower layers
57+
- Formats output for end users
58+
59+
**Key Packages**:
60+
- `cmd/elasticsearch/`: Elasticsearch snapshot/restore commands (configure, list-snapshots, list-indices, restore-snapshot)
61+
- `cmd/stackgraph/`: Stackgraph backup/restore commands (list, restore)
62+
- `cmd/version/`: Version information
63+
64+
**Dependency Rules**:
65+
- ✅ Can import: All `internal/` packages
66+
- ❌ Should not: Contain business logic or direct service calls
67+
68+
### Layer 2: Orchestration (`internal/orchestration/`)
69+
70+
**Purpose**: High-level workflows that coordinate multiple services
71+
72+
**Characteristics**:
73+
- Composes multiple clients to implement complex workflows
74+
- Handles sequencing and error recovery
75+
- Provides logging and user feedback
76+
- Stateless operations
77+
78+
**Key Packages**:
79+
- `portforward/`: Manages Kubernetes port-forwarding lifecycle
80+
- `scale/`: Deployment scaling workflows with detailed logging
81+
82+
**Dependency Rules**:
83+
- ✅ Can import: `internal/foundation/*`, `internal/clients/*`
84+
- ❌ Cannot import: Other `internal/orchestration/*` (to prevent circular dependencies)
85+
86+
### Layer 1: Clients (`internal/clients/`)
87+
88+
**Purpose**: Wrappers for external service APIs
89+
90+
**Characteristics**:
91+
- Thin abstraction over external APIs
92+
- Handles connection and authentication
93+
- Translates between external formats and internal types
94+
- No business logic or orchestration
95+
96+
**Key Packages**:
97+
- `k8s/`: Kubernetes API operations (Jobs, Pods, Deployments, ConfigMaps, Secrets, Logs)
98+
- `elasticsearch/`: Elasticsearch HTTP API (snapshots, indices, datastreams)
99+
- `s3/`: S3/Minio operations (client creation, object filtering)
100+
101+
**Dependency Rules**:
102+
- ✅ Can import: `internal/foundation/*`, standard library, external SDKs
103+
- ❌ Cannot import: `internal/orchestration/*`, other `internal/clients/*`
104+
105+
### Layer 0: Foundation (`internal/foundation/`)
106+
107+
**Purpose**: Core utilities with no internal dependencies
108+
109+
**Characteristics**:
110+
- Pure utility functions
111+
- No external service dependencies
112+
- Broadly reusable across the application
113+
- Well-tested and stable
114+
115+
**Key Packages**:
116+
- `config/`: Configuration loading from ConfigMaps, Secrets, environment, and flags
117+
- `logger/`: Structured logging with levels (Debug, Info, Warning, Error, Success)
118+
- `output/`: Output formatting (tables, JSON, YAML, messages)
119+
120+
**Dependency Rules**:
121+
- ✅ Can import: Standard library, external utility libraries
122+
- ❌ Cannot import: Any `internal/` packages
123+
124+
## Data Flow
125+
126+
### Typical Command Execution Flow
127+
128+
```
129+
1. User invokes CLI command
130+
└─> cmd/elasticsearch/restore-snapshot.go
131+
132+
2. Parse flags and validate input
133+
134+
3. Load configuration
135+
└─> internal/foundation/config/
136+
137+
4. Create clients
138+
└─> internal/clients/k8s/
139+
└─> internal/clients/elasticsearch/
140+
141+
5. Execute orchestration workflow
142+
└─> internal/orchestration/scale/
143+
└─> Scale down deployments
144+
└─> internal/orchestration/portforward/
145+
└─> Setup port-forward to Elasticsearch
146+
└─> internal/clients/elasticsearch/
147+
└─> Perform snapshot restore
148+
└─> internal/orchestration/scale/
149+
└─> Scale up deployments
150+
151+
6. Format and display results
152+
└─> internal/foundation/output/
153+
```
154+
155+
## Key Design Patterns
156+
157+
### 1. Configuration Precedence
158+
159+
Configuration is loaded with the following precedence (highest to lowest):
160+
161+
1. **CLI Flags**: Explicit user input
162+
2. **Environment Variables**: Runtime configuration
163+
3. **Kubernetes Secret**: Sensitive credentials (overrides ConfigMap)
164+
4. **Kubernetes ConfigMap**: Base configuration
165+
5. **Defaults**: Fallback values
166+
167+
Implementation: `internal/foundation/config/config.go`
168+
169+
### 2. Client Factory Pattern
170+
171+
Clients are created with a consistent factory pattern:
172+
173+
```go
174+
// Example from internal/clients/elasticsearch/client.go
175+
func NewClient(endpoint string) (*Client, error) {
176+
// Initialization logic
177+
return &Client{...}, nil
178+
}
179+
```
180+
181+
### 3. Port-Forward Lifecycle
182+
183+
Services running in Kubernetes are accessed via automatic port-forwarding:
184+
185+
```go
186+
// Example from internal/orchestration/portforward/portforward.go
187+
pf, err := SetupPortForward(k8sClient, namespace, service, localPort, remotePort, log)
188+
defer close(pf.StopChan) // Automatic cleanup
189+
```
190+
191+
### 4. Scale Down/Up Pattern
192+
193+
Deployments are scaled down before restore operations and scaled up afterward:
194+
195+
```go
196+
// Example usage
197+
scaledDeployments, _ := scale.ScaleDown(k8sClient, namespace, selector, log)
198+
defer scale.ScaleUp(k8sClient, namespace, scaledDeployments, log)
199+
```
200+
201+
### 5. Structured Logging
202+
203+
All operations use structured logging with consistent levels:
204+
205+
```go
206+
log.Infof("Starting operation...")
207+
log.Debugf("Detail: %v", detail)
208+
log.Warningf("Non-fatal issue: %v", warning)
209+
log.Errorf("Operation failed: %v", err)
210+
log.Successf("Operation completed successfully")
211+
```
212+
213+
## Testing Strategy
214+
215+
### Unit Tests
216+
- **Location**: Same directory as source (e.g., `config_test.go`)
217+
- **Focus**: Business logic, parsing, validation
218+
- **Mocking**: Use interfaces for external dependencies
219+
220+
### Integration Tests
221+
- **Location**: `cmd/*/` directories
222+
- **Focus**: Command execution with mocked Kubernetes
223+
- **Tools**: `fake.NewSimpleClientset()` from `k8s.io/client-go`
224+
225+
### End-to-End Tests
226+
- **Status**: Not yet implemented
227+
- **Future**: Use `kind` or `k3s` for local Kubernetes cluster testing
228+
229+
## Extending the Codebase
230+
231+
### Adding a New Command
232+
233+
1. Create command file in `cmd/<service>/`
234+
2. Implement Cobra command structure
235+
3. Use existing clients or create new ones in `internal/clients/`
236+
4. Implement workflow in `internal/orchestration/` if needed
237+
5. Add tests following existing patterns
238+
239+
### Adding a New Client
240+
241+
1. Create package in `internal/clients/<service>/`
242+
2. Implement client factory: `NewClient(...) (*Client, error)`
243+
3. Only import `internal/foundation/*` packages
244+
4. Add methods for each API operation
245+
5. Write unit tests with mocked HTTP/API calls
246+
247+
### Adding a New Orchestration Workflow
248+
249+
1. Create package in `internal/orchestration/<workflow>/`
250+
2. Import required clients from `internal/clients/*`
251+
3. Import utilities from `internal/foundation/*`
252+
4. Keep workflows stateless
253+
5. Add comprehensive logging
254+
255+
## Common Pitfalls to Avoid
256+
257+
### ❌ Don't: Import Clients from Other Clients
258+
259+
```go
260+
// BAD: internal/clients/elasticsearch/backup.go
261+
import "github.com/.../internal/clients/k8s" // Violates layer rules
262+
```
263+
264+
**Fix**: Move the orchestration logic to `internal/orchestration/`
265+
266+
### ❌ Don't: Put Business Logic in Commands
267+
268+
```go
269+
// BAD: cmd/elasticsearch/restore.go
270+
func runRestore() {
271+
// 200 lines of business logic here
272+
}
273+
```
274+
275+
**Fix**: Extract logic to orchestration or client packages
276+
277+
### ❌ Don't: Import Foundation Packages from Each Other
278+
279+
```go
280+
// BAD: internal/foundation/config/loader.go
281+
import "github.com/.../internal/foundation/output"
282+
```
283+
284+
**Fix**: Foundation packages should be independent
285+
286+
### ❌ Don't: Hard-code Configuration
287+
288+
```go
289+
// BAD
290+
endpoint := "http://localhost:9200"
291+
```
292+
293+
**Fix**: Use configuration management: `config.Elasticsearch.Service.Name`
294+
295+
## Automated Enforcement
296+
297+
Verify architectural rules with these commands:
298+
299+
```bash
300+
# Verify foundation/ has no internal/ imports
301+
go list -f '{{.ImportPath}}: {{join .Imports "\n"}}' ./internal/foundation/... | \
302+
grep 'stackvista.*internal'
303+
304+
# Verify clients/ only imports foundation/
305+
go list -f '{{.ImportPath}}: {{join .Imports "\n"}}' ./internal/clients/... | \
306+
grep 'stackvista.*internal' | grep -v foundation
307+
308+
# Verify orchestration/ doesn't import other orchestration/
309+
go list -f '{{.ImportPath}}: {{join .Imports "\n"}}' ./internal/orchestration/... | \
310+
grep 'stackvista.*orchestration'
311+
```

0 commit comments

Comments
 (0)