399 lines
12 KiB
Markdown
399 lines
12 KiB
Markdown
# P4-004: Directory Path Standardization
|
|
|
|
**Priority:** P4 (Technical Debt)
|
|
**Source Reference:** From analysis of needsfixingbeforepush.md lines 1584-1609 and DEVELOPMENT_TODOS.md lines 580-607
|
|
**Date Identified:** 2025-11-12
|
|
|
|
## Problem Description
|
|
|
|
Mixed directory naming creates confusion and maintenance issues throughout the codebase. Both `/var/lib/aggregator` and `/var/lib/redflag` paths are used inconsistently across agent and server code, leading to operational complexity, backup/restore challenges, and potential path conflicts.
|
|
|
|
## Impact
|
|
|
|
- **User Confusion:** Inconsistent file locations make system administration difficult
|
|
- **Maintenance Overhead:** Multiple path patterns increase development complexity
|
|
- **Backup Complexity:** Mixed paths complicate backup and restore procedures
|
|
- **Documentation Conflicts:** Documentation shows different paths than actual usage
|
|
- **Migration Issues:** Path inconsistencies break upgrade processes
|
|
|
|
## Current Path Inconsistencies
|
|
|
|
### Agent Code
|
|
- **Config:** `/etc/aggregator/config.json` (old) vs `/etc/redflag/config.json` (new)
|
|
- **State:** `/var/lib/aggregator/` (old) vs `/var/lib/redflag/` (new)
|
|
- **Logs:** Mixed usage in different files
|
|
|
|
### Server Code
|
|
- **Install Scripts:** References to both old and new paths
|
|
- **Documentation:** Inconsistent path examples
|
|
- **Templates:** Mixed path usage in install script templates
|
|
|
|
### File References
|
|
```go
|
|
// Found in codebase:
|
|
STATE_DIR = "/var/lib/aggregator" // aggregator-agent/cmd/agent/main.go:47
|
|
CONFIG_PATH = "/etc/redflag/config.json" // Some newer files
|
|
STATE_DIR = "/var/lib/redflag" // Other files
|
|
```
|
|
|
|
## Proposed Solution
|
|
|
|
Standardize on `/var/lib/redflag` and `/etc/redflag` throughout the entire codebase:
|
|
|
|
### 1. Centralized Path Constants
|
|
```go
|
|
// aggregator/internal/paths/paths.go
|
|
package paths
|
|
|
|
const (
|
|
// Standard paths for RedFlag
|
|
ConfigDir = "/etc/redflag"
|
|
StateDir = "/var/lib/redflag"
|
|
LogDir = "/var/log/redflag"
|
|
BackupDir = "/var/lib/redflag/backups"
|
|
CacheDir = "/var/lib/redflag/cache"
|
|
|
|
// Specific files
|
|
ConfigFile = ConfigDir + "/config.json"
|
|
StateFile = StateDir + "/last_scan.json"
|
|
AckFile = StateDir + "/pending_acks.json"
|
|
HistoryFile = StateDir + "/command_history.json"
|
|
|
|
// Legacy paths (for migration)
|
|
LegacyConfigDir = "/etc/aggregator"
|
|
LegacyStateDir = "/var/lib/aggregator"
|
|
LegacyLogDir = "/var/log/aggregator"
|
|
)
|
|
|
|
type PathConfig struct {
|
|
Config string
|
|
State string
|
|
Log string
|
|
Backup string
|
|
Cache string
|
|
}
|
|
|
|
func GetStandardPaths() PathConfig {
|
|
return PathConfig{
|
|
Config: ConfigDir,
|
|
State: StateDir,
|
|
Log: LogDir,
|
|
Backup: BackupDir,
|
|
Cache: CacheDir,
|
|
}
|
|
}
|
|
|
|
func GetStandardFiles() map[string]string {
|
|
return map[string]string{
|
|
"config": ConfigFile,
|
|
"state": StateFile,
|
|
"acknowledgments": AckFile,
|
|
"history": HistoryFile,
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Path Migration System
|
|
```go
|
|
// aggregator/internal/paths/migration.go
|
|
package paths
|
|
|
|
type PathMigrator struct {
|
|
Standard PathConfig
|
|
Legacy PathConfig
|
|
DryRun bool
|
|
Backup bool
|
|
}
|
|
|
|
func NewPathMigrator(backup bool) *PathMigrator {
|
|
return &PathMigrator{
|
|
Standard: GetStandardPaths(),
|
|
Legacy: PathConfig{
|
|
Config: LegacyConfigDir,
|
|
State: LegacyStateDir,
|
|
Log: LegacyLogDir,
|
|
},
|
|
Backup: backup,
|
|
}
|
|
}
|
|
|
|
func (pm *PathMigrator) MigrateAll() error {
|
|
// Migrate configuration directory
|
|
if err := pm.migrateDirectory(pm.Legacy.Config, pm.Standard.Config); err != nil {
|
|
return fmt.Errorf("config migration failed: %w", err)
|
|
}
|
|
|
|
// Migrate state directory
|
|
if err := pm.migrateDirectory(pm.Legacy.State, pm.Standard.State); err != nil {
|
|
return fmt.Errorf("state migration failed: %w", err)
|
|
}
|
|
|
|
// Migrate log directory
|
|
if err := pm.migrateDirectory(pm.Legacy.Log, pm.Standard.Log); err != nil {
|
|
return fmt.Errorf("log migration failed: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (pm *PathMigrator) migrateDirectory(legacyPath, standardPath string) error {
|
|
// Check if legacy path exists
|
|
if _, err := os.Stat(legacyPath); os.IsNotExist(err) {
|
|
return nil // No migration needed
|
|
}
|
|
|
|
// Check if standard path already exists
|
|
if _, err := os.Stat(standardPath); err == nil {
|
|
return fmt.Errorf("standard path already exists: %s", standardPath)
|
|
}
|
|
|
|
if pm.DryRun {
|
|
log.Printf("[DRY RUN] Would migrate %s -> %s", legacyPath, standardPath)
|
|
return nil
|
|
}
|
|
|
|
// Create backup if requested
|
|
if pm.Backup {
|
|
backupPath := standardPath + ".backup." + time.Now().Format("20060102-150405")
|
|
if err := copyDirectory(legacyPath, backupPath); err != nil {
|
|
return fmt.Errorf("backup creation failed: %w", err)
|
|
}
|
|
}
|
|
|
|
// Perform migration
|
|
if err := os.Rename(legacyPath, standardPath); err != nil {
|
|
return fmt.Errorf("directory rename failed: %w", err)
|
|
}
|
|
|
|
log.Printf("Migrated directory: %s -> %s", legacyPath, standardPath)
|
|
return nil
|
|
}
|
|
```
|
|
|
|
### 3. Install Script Template Updates
|
|
```go
|
|
// Update linux.sh.tmpl to use standard paths
|
|
const LinuxInstallTemplate = `
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# Standard RedFlag paths
|
|
CONFIG_DIR="{{ .ConfigDir }}"
|
|
STATE_DIR="{{ .StateDir }}"
|
|
LOG_DIR="{{ .LogDir }}"
|
|
AGENT_USER="redflag-agent"
|
|
|
|
# Create directories with proper permissions
|
|
for dir in "$CONFIG_DIR" "$STATE_DIR" "$LOG_DIR"; do
|
|
if [ ! -d "$dir" ]; then
|
|
mkdir -p "$dir"
|
|
chown "$AGENT_USER:$AGENT_USER" "$dir"
|
|
chmod 755 "$dir"
|
|
fi
|
|
done
|
|
|
|
# Check for legacy paths and migrate
|
|
LEGACY_CONFIG_DIR="/etc/aggregator"
|
|
LEGACY_STATE_DIR="/var/lib/aggregator"
|
|
|
|
if [ -d "$LEGACY_CONFIG_DIR" ] && [ ! -d "$CONFIG_DIR" ]; then
|
|
echo "Migrating configuration from legacy path..."
|
|
mv "$LEGACY_CONFIG_DIR" "$CONFIG_DIR"
|
|
fi
|
|
|
|
if [ -d "$LEGACY_STATE_DIR" ] && [ ! -d "$STATE_DIR" ]; then
|
|
echo "Migrating state from legacy path..."
|
|
mv "$LEGACY_STATE_DIR" "$STATE_DIR"
|
|
fi
|
|
`
|
|
```
|
|
|
|
### 4. Agent Configuration Integration
|
|
```go
|
|
// Update agent config to use path constants
|
|
type AgentConfig struct {
|
|
Server string `json:"server_url"`
|
|
AgentID string `json:"agent_id"`
|
|
Token string `json:"registration_token,omitempty"`
|
|
Paths PathConfig `json:"paths,omitempty"`
|
|
}
|
|
|
|
func DefaultAgentConfig() AgentConfig {
|
|
return AgentConfig{
|
|
Paths: paths.GetStandardPaths(),
|
|
}
|
|
}
|
|
|
|
// Usage in agent code
|
|
func (a *Agent) getStateFilePath() string {
|
|
if a.config.Paths.State != "" {
|
|
return filepath.Join(a.config.Paths.State, "last_scan.json")
|
|
}
|
|
return paths.StateFile
|
|
}
|
|
```
|
|
|
|
### 5. Code Updates Strategy
|
|
|
|
#### Phase 1: Introduce Path Constants
|
|
```bash
|
|
# Find all hardcoded paths
|
|
grep -r "/var/lib/aggregator" aggregator-agent/
|
|
grep -r "/etc/aggregator" aggregator-agent/
|
|
grep -r "/var/lib/redflag" aggregator-agent/
|
|
grep -r "/etc/redflag" aggregator-agent/
|
|
|
|
# Replace with path constants
|
|
find . -name "*.go" -exec sed -i 's|"/var/lib/aggregator"|paths.StateDir|g' {} \;
|
|
```
|
|
|
|
#### Phase 2: Update Import Statements
|
|
```go
|
|
// Add to files using paths
|
|
import (
|
|
"github.com/redflag/redflag/internal/paths"
|
|
)
|
|
```
|
|
|
|
#### Phase 3: Update Documentation
|
|
```markdown
|
|
## Installation Paths
|
|
|
|
RedFlag uses standardized paths for all installations:
|
|
|
|
- **Configuration:** `/etc/redflag/config.json`
|
|
- **State Data:** `/var/lib/redflag/`
|
|
- **Log Files:** `/var/log/redflag/`
|
|
- **Backups:** `/var/lib/redflag/backups/`
|
|
|
|
### File Structure
|
|
```
|
|
/etc/redflag/
|
|
└── config.json # Agent configuration
|
|
|
|
/var/lib/redflag/
|
|
├── last_scan.json # Last scan results
|
|
├── pending_acks.json # Pending acknowledgments
|
|
├── command_history.json # Command history
|
|
└── backups/ # Backup directory
|
|
|
|
/var/log/redflag/
|
|
└── agent.log # Agent log files
|
|
```
|
|
```
|
|
|
|
## Definition of Done
|
|
|
|
- [ ] All hardcoded paths replaced with centralized constants
|
|
- [ ] Path migration system handles legacy installations
|
|
- [ ] Install script templates use standard paths
|
|
- [ ] Documentation updated with correct paths
|
|
- [ ] Server code updated for consistency
|
|
- [ ] Agent code uses path constants throughout
|
|
- [ ] SystemD service files updated with correct paths
|
|
- [ ] Migration process tested on existing installations
|
|
|
|
## Implementation Details
|
|
|
|
### Files Requiring Updates
|
|
|
|
#### Agent Code
|
|
- `aggregator-agent/cmd/agent/main.go` - STATE_DIR and CONFIG_PATH constants
|
|
- `aggregator-agent/internal/config/config.go` - Default paths
|
|
- `aggregator-agent/internal/orchestrator/*.go` - File path references
|
|
- `aggregator-agent/internal/installer/*.go` - Installation paths
|
|
|
|
#### Server Code
|
|
- `aggregator-server/internal/api/handlers/downloads.go` - Install script templates
|
|
- `aggregator-server/internal/services/templates/install/scripts/linux.sh.tmpl`
|
|
- `aggregator-server/internal/services/templates/install/scripts/windows.ps1.tmpl`
|
|
|
|
#### Configuration Files
|
|
- Dockerfiles and docker-compose.yml
|
|
- SystemD unit files
|
|
- Documentation files
|
|
|
|
### Migration Process
|
|
1. **Backup:** Create backup of existing installations
|
|
2. **Path Detection:** Detect which paths are currently in use
|
|
3. **Migration:** Move files to standard locations
|
|
4. **Permission Updates:** Ensure correct ownership and permissions
|
|
5. **Validation:** Verify all files are accessible after migration
|
|
|
|
### Testing Strategy
|
|
- Test migration from legacy paths to standard paths
|
|
- Verify fresh installations use standard paths
|
|
- Test that existing installations continue to work
|
|
- Validate SystemD service files work with new paths
|
|
|
|
## Testing Scenarios
|
|
|
|
### 1. Fresh Installation Test
|
|
```bash
|
|
# Fresh install should create standard paths
|
|
curl -sSL http://localhost:8080/api/v1/install/linux | sudo bash
|
|
|
|
# Verify standard paths exist
|
|
ls -la /etc/redflag/
|
|
ls -la /var/lib/redflag/
|
|
```
|
|
|
|
### 2. Migration Test
|
|
```bash
|
|
# Simulate legacy installation
|
|
sudo mkdir -p /etc/aggregator /var/lib/aggregator
|
|
echo "legacy config" | sudo tee /etc/aggregator/config.json
|
|
echo "legacy state" | sudo tee /var/lib/aggregator/last_scan.json
|
|
|
|
# Run migration
|
|
sudo /usr/local/bin/redflag-agent --migrate-paths
|
|
|
|
# Verify files moved to standard paths
|
|
ls -la /etc/redflag/config.json
|
|
ls -la /var/lib/redflag/last_scan.json
|
|
|
|
# Verify legacy paths removed
|
|
! test -d /etc/aggregator
|
|
! test -d /var/lib/aggregator
|
|
```
|
|
|
|
### 3. Service Integration Test
|
|
```bash
|
|
# Ensure SystemD service works with new paths
|
|
sudo systemctl restart redflag-agent
|
|
sudo systemctl status redflag-agent
|
|
sudo journalctl -u redflag-agent -n 20
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
- Path detection and migration system implemented
|
|
- Backup system for safe migrations
|
|
- Install script template system available
|
|
- Configuration system supports path overrides
|
|
|
|
## Effort Estimate
|
|
|
|
**Complexity:** Medium
|
|
**Effort:** 2-3 days
|
|
- Day 1: Create path constants and migration system
|
|
- Day 2: Update agent code and test migration
|
|
- Day 3: Update server code, templates, and documentation
|
|
|
|
## Success Metrics
|
|
|
|
- Zero hardcoded paths remaining in codebase
|
|
- All installations use consistent paths
|
|
- Migration成功率 for existing installations >95%
|
|
- No data loss during migration process
|
|
- Documentation matches actual implementation
|
|
- SystemD service integration works seamlessly
|
|
|
|
## Rollback Plan
|
|
|
|
If issues arise during migration:
|
|
1. Stop all RedFlag services
|
|
2. Restore from backups created during migration
|
|
3. Update configuration to point to legacy paths
|
|
4. Restart services
|
|
5. Document issues for future improvement |