- Implemented CrowdSec configuration page with import/export capabilities. - Added API endpoints for exporting, importing, listing, reading, and writing CrowdSec configuration files. - Enhanced security handler to support runtime overrides for CrowdSec mode and API URL. - Updated frontend components to include CrowdSec settings in the UI. - Added tests for CrowdSec configuration management and security handler behavior. - Improved user experience with toast notifications for successful operations and error handling.
84 lines
2.1 KiB
Go
84 lines
2.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"syscall"
|
|
)
|
|
|
|
// DefaultCrowdsecExecutor implements CrowdsecExecutor using OS processes.
|
|
type DefaultCrowdsecExecutor struct {
|
|
}
|
|
|
|
func NewDefaultCrowdsecExecutor() *DefaultCrowdsecExecutor { return &DefaultCrowdsecExecutor{} }
|
|
|
|
func (e *DefaultCrowdsecExecutor) pidFile(configDir string) string {
|
|
return filepath.Join(configDir, "crowdsec.pid")
|
|
}
|
|
|
|
func (e *DefaultCrowdsecExecutor) Start(ctx context.Context, binPath, configDir string) (int, error) {
|
|
cmd := exec.CommandContext(ctx, binPath, "--config-dir", configDir)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
return 0, err
|
|
}
|
|
pid := cmd.Process.Pid
|
|
// write pid file
|
|
if err := os.WriteFile(e.pidFile(configDir), []byte(strconv.Itoa(pid)), 0o644); err != nil {
|
|
return pid, fmt.Errorf("failed to write pid file: %w", err)
|
|
}
|
|
// wait in background
|
|
go func() {
|
|
_ = cmd.Wait()
|
|
_ = os.Remove(e.pidFile(configDir))
|
|
}()
|
|
return pid, nil
|
|
}
|
|
|
|
func (e *DefaultCrowdsecExecutor) Stop(ctx context.Context, configDir string) error {
|
|
b, err := os.ReadFile(e.pidFile(configDir))
|
|
if err != nil {
|
|
return fmt.Errorf("pid file read: %w", err)
|
|
}
|
|
pid, err := strconv.Atoi(string(b))
|
|
if err != nil {
|
|
return fmt.Errorf("invalid pid: %w", err)
|
|
}
|
|
proc, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := proc.Signal(syscall.SIGTERM); err != nil {
|
|
return err
|
|
}
|
|
// best-effort remove pid file
|
|
_ = os.Remove(e.pidFile(configDir))
|
|
return nil
|
|
}
|
|
|
|
func (e *DefaultCrowdsecExecutor) Status(ctx context.Context, configDir string) (bool, int, error) {
|
|
b, err := os.ReadFile(e.pidFile(configDir))
|
|
if err != nil {
|
|
return false, 0, nil
|
|
}
|
|
pid, err := strconv.Atoi(string(b))
|
|
if err != nil {
|
|
return false, 0, nil
|
|
}
|
|
// Check process exists
|
|
proc, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
return false, pid, nil
|
|
}
|
|
// Sending signal 0 is not portable on Windows, but OK for Linux containers
|
|
if err := proc.Signal(syscall.Signal(0)); err != nil {
|
|
return false, pid, nil
|
|
}
|
|
return true, pid, nil
|
|
}
|