refactor: consolidate config logic into ConfigService
Created centralized ConfigService for configuration management. Added deprecation comments to ConfigBuilder and AgentBuilder. Platform-specific defaults centralized in one place. Removed placeholder ConfigService from agent_lifecycle.go.
This commit is contained in:
@@ -91,6 +91,7 @@ func NewAgentBuild(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeAgentBuild handles agent upgrade requests
|
// UpgradeAgentBuild handles agent upgrade requests
|
||||||
|
// Deprecated: Use ConfigService for config building
|
||||||
func UpgradeAgentBuild(c *gin.Context) {
|
func UpgradeAgentBuild(c *gin.Context) {
|
||||||
agentID := c.Param("agentID")
|
agentID := c.Param("agentID")
|
||||||
if agentID == "" {
|
if agentID == "" {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AgentBuilder handles generating embedded agent configurations
|
// AgentBuilder handles generating embedded agent configurations
|
||||||
|
// Deprecated: Configuration logic should use services.ConfigService
|
||||||
type AgentBuilder struct {
|
type AgentBuilder struct {
|
||||||
buildContext string
|
buildContext string
|
||||||
}
|
}
|
||||||
@@ -21,6 +22,7 @@ func NewAgentBuilder() *AgentBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildAgentWithConfig generates agent configuration and prepares signed binary
|
// BuildAgentWithConfig generates agent configuration and prepares signed binary
|
||||||
|
// Deprecated: Delegate config generation to services.ConfigService
|
||||||
func (ab *AgentBuilder) BuildAgentWithConfig(config *AgentConfiguration) (*BuildResult, error) {
|
func (ab *AgentBuilder) BuildAgentWithConfig(config *AgentConfiguration) (*BuildResult, error) {
|
||||||
// Create temporary build directory
|
// Create temporary build directory
|
||||||
buildDir, err := os.MkdirTemp("", "agent-build-")
|
buildDir, err := os.MkdirTemp("", "agent-build-")
|
||||||
|
|||||||
@@ -269,27 +269,6 @@ func (s *BuildService) BuildArtifacts(ctx context.Context, cfg *AgentConfig) (*B
|
|||||||
return &BuildArtifacts{}, nil
|
return &BuildArtifacts{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigService placeholder (to be implemented)
|
|
||||||
type ConfigService struct {
|
|
||||||
db *sqlx.DB
|
|
||||||
config *config.Config
|
|
||||||
logger *log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConfigService(db *sqlx.DB, cfg *config.Config, logger *log.Logger) *ConfigService {
|
|
||||||
return &ConfigService{db: db, config: cfg, logger: logger}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConfigService) GenerateNewConfig(cfg *AgentConfig) ([]byte, error) {
|
|
||||||
// Placeholder: Return empty JSON
|
|
||||||
return []byte("{}"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConfigService) LoadExistingConfig(agentID string) ([]byte, error) {
|
|
||||||
// Placeholder: Return empty JSON
|
|
||||||
return []byte("{}"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArtifactService placeholder (to be implemented)
|
// ArtifactService placeholder (to be implemented)
|
||||||
type ArtifactService struct {
|
type ArtifactService struct {
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ type PublicKeyResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConfigBuilder handles dynamic agent configuration generation
|
// ConfigBuilder handles dynamic agent configuration generation
|
||||||
|
// ConfigBuilder builds agent configurations
|
||||||
|
// Deprecated: Use services.ConfigService instead
|
||||||
type ConfigBuilder struct {
|
type ConfigBuilder struct {
|
||||||
serverURL string
|
serverURL string
|
||||||
templates map[string]AgentTemplate
|
templates map[string]AgentTemplate
|
||||||
|
|||||||
177
aggregator-server/internal/services/config_service.go
Normal file
177
aggregator-server/internal/services/config_service.go
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
|
||||||
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConfigService manages agent configuration generation and validation
|
||||||
|
type ConfigService struct {
|
||||||
|
db *sqlx.DB
|
||||||
|
config *config.Config
|
||||||
|
logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfigService creates a new configuration service
|
||||||
|
func NewConfigService(db *sqlx.DB, cfg *config.Config, logger *log.Logger) *ConfigService {
|
||||||
|
return &ConfigService{
|
||||||
|
db: db,
|
||||||
|
config: cfg,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AgentConfigData represents agent configuration structure
|
||||||
|
type AgentConfigData struct {
|
||||||
|
AgentID string `json:"agent_id"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Platform string `json:"platform"`
|
||||||
|
ServerURL string `json:"server_url"`
|
||||||
|
LogLevel string `json:"log_level"`
|
||||||
|
Intervals map[string]int `json:"intervals"`
|
||||||
|
Subsystems map[string]interface{} `json:"subsystems"`
|
||||||
|
MaxRetries int `json:"max_retries"`
|
||||||
|
TimeoutSeconds int `json:"timeout_seconds"`
|
||||||
|
MachineID string `json:"machine_id"`
|
||||||
|
AgentType string `json:"agent_type"`
|
||||||
|
ConfigPath string `json:"config_path"`
|
||||||
|
StatePath string `json:"state_path"`
|
||||||
|
LogPath string `json:"log_path"`
|
||||||
|
ServiceName string `json:"service_name"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateNewConfig creates configuration for a new agent
|
||||||
|
func (s *ConfigService) GenerateNewConfig(agentCfg *AgentConfig) ([]byte, error) {
|
||||||
|
// Base configuration
|
||||||
|
serverURL := fmt.Sprintf("http://%s:%d", s.config.Server.Host, s.config.Server.Port)
|
||||||
|
if s.config.Server.PublicURL != "" {
|
||||||
|
serverURL = s.config.Server.PublicURL
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &AgentConfigData{
|
||||||
|
AgentID: agentCfg.AgentID,
|
||||||
|
Version: agentCfg.Version,
|
||||||
|
Platform: agentCfg.Platform,
|
||||||
|
ServerURL: serverURL,
|
||||||
|
LogLevel: "info",
|
||||||
|
Intervals: map[string]int{
|
||||||
|
"metrics": 300, // 5 minutes
|
||||||
|
"updates": 3600, // 1 hour
|
||||||
|
"commands": 30, // 30 seconds
|
||||||
|
},
|
||||||
|
Subsystems: map[string]interface{}{
|
||||||
|
"updates": map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 300},
|
||||||
|
"storage": map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 60},
|
||||||
|
"system": map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 60},
|
||||||
|
"docker": map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 120},
|
||||||
|
},
|
||||||
|
MaxRetries: 3,
|
||||||
|
TimeoutSeconds: 30,
|
||||||
|
MachineID: agentCfg.MachineID,
|
||||||
|
AgentType: agentCfg.AgentType,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
UpdatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform-specific customizations
|
||||||
|
s.applyPlatformDefaults(cfg)
|
||||||
|
|
||||||
|
// Validate configuration
|
||||||
|
if err := s.validateConfig(cfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("validation failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal to JSON
|
||||||
|
configJSON, err := json.MarshalIndent(cfg, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("marshal failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return configJSON, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadExistingConfig retrieves and updates existing agent configuration
|
||||||
|
func (s *ConfigService) LoadExistingConfig(agentID string) ([]byte, error) {
|
||||||
|
// Get existing agent from database
|
||||||
|
var agent models.Agent
|
||||||
|
query := `SELECT * FROM agents WHERE id = $1`
|
||||||
|
err := s.db.Get(&agent, query, agentID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("agent not found: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new config based on agent data
|
||||||
|
agentCfg := &AgentConfig{
|
||||||
|
AgentID: agentID,
|
||||||
|
Version: agent.CurrentVersion,
|
||||||
|
Platform: agent.OSType,
|
||||||
|
Architecture: agent.OSArchitecture,
|
||||||
|
MachineID: "",
|
||||||
|
AgentType: "", // Could be stored in Metadata
|
||||||
|
Hostname: agent.Hostname,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use GenerateNewConfig to create config
|
||||||
|
return s.GenerateNewConfig(agentCfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// applyPlatformDefaults applies platform-specific configuration
|
||||||
|
func (s *ConfigService) applyPlatformDefaults(cfg *AgentConfigData) {
|
||||||
|
switch cfg.Platform {
|
||||||
|
case "windows-amd64", "windows-arm64", "windows-386":
|
||||||
|
// Windows-specific paths
|
||||||
|
cfg.ConfigPath = "C:\\ProgramData\\RedFlag\\config.json"
|
||||||
|
cfg.StatePath = "C:\\ProgramData\\RedFlag\\state\\"
|
||||||
|
cfg.LogPath = "C:\\ProgramData\\RedFlag\\logs\\"
|
||||||
|
cfg.ServiceName = "RedFlagAgent"
|
||||||
|
|
||||||
|
// Windows-specific subsystems
|
||||||
|
cfg.Subsystems["windows"] = map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 300}
|
||||||
|
cfg.Subsystems["winget"] = map[string]interface{}{"enabled": true, "auto_run": true, "timeout": 180}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Linux defaults
|
||||||
|
cfg.ConfigPath = "/etc/redflag/config.json"
|
||||||
|
cfg.StatePath = "/var/lib/redflag/"
|
||||||
|
cfg.LogPath = "/var/log/redflag/"
|
||||||
|
cfg.ServiceName = "redflag-agent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateConfig validates configuration
|
||||||
|
func (s *ConfigService) validateConfig(cfg *AgentConfigData) error {
|
||||||
|
if cfg.AgentID == "" {
|
||||||
|
return fmt.Errorf("agent_id is required")
|
||||||
|
}
|
||||||
|
if cfg.Version == "" {
|
||||||
|
return fmt.Errorf("version is required")
|
||||||
|
}
|
||||||
|
if cfg.Platform == "" {
|
||||||
|
return fmt.Errorf("platform is required")
|
||||||
|
}
|
||||||
|
if cfg.ServerURL == "" {
|
||||||
|
return fmt.Errorf("server_url is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveConfig saves agent configuration to database
|
||||||
|
func (s *ConfigService) SaveConfig(ctx context.Context, agentID uuid.UUID, configJSON []byte) error {
|
||||||
|
query := `
|
||||||
|
UPDATE agents SET config = $1, updated_at = $2
|
||||||
|
WHERE id = $3
|
||||||
|
`
|
||||||
|
_, err := s.db.ExecContext(ctx, query, configJSON, time.Now(), agentID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user