- Updated file permissions in certificate_service_test.go and log_service_test.go to use octal notation. - Added a new doc.go file to document the services package. - Enhanced error handling in docker_service.go, log_service.go, notification_service.go, proxyhost_service.go, remoteserver_service.go, update_service.go, and uptime_service.go by logging errors when closing resources. - Improved log_service.go to simplify log file processing and deduplication. - Introduced CRUD tests for notification templates in notification_service_template_test.go. - Removed the obsolete python_compile_check.sh script. - Updated notification_service.go to improve template management functions. - Added tests for uptime service notifications in uptime_service_notification_test.go.
95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"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) (running bool, pid int, err error) {
|
|
b, err := os.ReadFile(e.pidFile(configDir))
|
|
if err != nil {
|
|
// Missing pid file is treated as not running
|
|
return false, 0, nil
|
|
}
|
|
|
|
pid, err = strconv.Atoi(string(b))
|
|
if err != nil {
|
|
// Malformed pid file is treated as not running
|
|
return false, 0, nil
|
|
}
|
|
|
|
proc, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
// Process lookup failures are treated as not running
|
|
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 {
|
|
if errors.Is(err, os.ErrProcessDone) {
|
|
return false, pid, nil
|
|
}
|
|
// ESRCH or other errors mean process isn't running
|
|
return false, pid, nil
|
|
}
|
|
|
|
return true, pid, nil
|
|
}
|