mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
Implements automated cleanup workflow when nodes are deleted from Pulse, removing all monitoring footprint from the host. Changes include a new RPC handler in the sensor proxy for cleanup requests, enhanced node deletion modal with detailed cleanup explanations, and improved SSH key management with proper tagging for atomic updates.
89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
const cleanupRequestFilename = "cleanup-request.json"
|
|
|
|
func (p *Proxy) cleanupRequestPath() (string, error) {
|
|
workDir := p.workDir
|
|
if workDir == "" {
|
|
workDir = defaultWorkDir()
|
|
}
|
|
|
|
if workDir == "" {
|
|
return "", errors.New("cleanup working directory not configured")
|
|
}
|
|
|
|
return filepath.Join(workDir, cleanupRequestFilename), nil
|
|
}
|
|
|
|
func (p *Proxy) handleRequestCleanup(ctx context.Context, req *RPCRequest, logger zerolog.Logger) (interface{}, error) {
|
|
cleanupPath, err := p.cleanupRequestPath()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dir := filepath.Dir(cleanupPath)
|
|
if err := os.MkdirAll(dir, 0o750); err != nil {
|
|
return nil, fmt.Errorf("ensure cleanup directory: %w", err)
|
|
}
|
|
|
|
payload := map[string]any{
|
|
"requestedAt": time.Now().UTC().Format(time.RFC3339),
|
|
}
|
|
if req != nil && req.Params != nil {
|
|
if host, ok := req.Params["host"].(string); ok && host != "" {
|
|
payload["host"] = host
|
|
}
|
|
if reason, ok := req.Params["reason"].(string); ok && reason != "" {
|
|
payload["reason"] = reason
|
|
}
|
|
}
|
|
|
|
data, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("encode cleanup payload: %w", err)
|
|
}
|
|
|
|
tmpFile, err := os.CreateTemp(dir, "cleanup-request-*.tmp")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("prepare cleanup signal: %w", err)
|
|
}
|
|
tmpName := tmpFile.Name()
|
|
if _, err := tmpFile.Write(append(data, '\n')); err != nil {
|
|
tmpFile.Close()
|
|
os.Remove(tmpName)
|
|
return nil, fmt.Errorf("write cleanup payload: %w", err)
|
|
}
|
|
if err := tmpFile.Chmod(0o600); err != nil {
|
|
logger.Warn().Err(err).Str("path", tmpName).Msg("Failed to set cleanup payload permissions")
|
|
}
|
|
if err := tmpFile.Close(); err != nil {
|
|
os.Remove(tmpName)
|
|
return nil, fmt.Errorf("close cleanup payload: %w", err)
|
|
}
|
|
|
|
// Replace any existing request atomically so systemd path units trigger on change.
|
|
if err := os.Rename(tmpName, cleanupPath); err != nil {
|
|
os.Remove(tmpName)
|
|
return nil, fmt.Errorf("activate cleanup payload: %w", err)
|
|
}
|
|
|
|
logger.Info().
|
|
Str("path", cleanupPath).
|
|
Interface("payload", payload).
|
|
Msg("Cleanup request signalled")
|
|
|
|
return map[string]any{"queued": true}, nil
|
|
}
|