somewhat working ebpf bpftrace
This commit is contained in:
86
main.go
86
main.go
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"nannyagentv2/internal/auth"
|
||||
"nannyagentv2/internal/config"
|
||||
"nannyagentv2/internal/logging"
|
||||
"nannyagentv2/internal/metrics"
|
||||
"nannyagentv2/internal/types"
|
||||
)
|
||||
@@ -22,12 +23,9 @@ const Version = "v2.0.0"
|
||||
// checkRootPrivileges ensures the program is running as root
|
||||
func checkRootPrivileges() {
|
||||
if os.Geteuid() != 0 {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: This program must be run as root for eBPF functionality.\n")
|
||||
fmt.Fprintf(os.Stderr, "Please run with: sudo %s\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "Reason: eBPF programs require root privileges to:\n")
|
||||
fmt.Fprintf(os.Stderr, " - Load programs into the kernel\n")
|
||||
fmt.Fprintf(os.Stderr, " - Attach to kernel functions and tracepoints\n")
|
||||
fmt.Fprintf(os.Stderr, " - Access kernel memory maps\n")
|
||||
logging.Error("This program must be run as root for eBPF functionality")
|
||||
logging.Error("Please run with: sudo %s", os.Args[0])
|
||||
logging.Error("Reason: eBPF programs require root privileges to:\n - Load programs into the kernel\n - Attach to kernel functions and tracepoints\n - Access kernel memory maps")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +34,7 @@ func checkRootPrivileges() {
|
||||
func checkKernelVersionCompatibility() {
|
||||
output, err := exec.Command("uname", "-r").Output()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: Cannot determine kernel version: %v\n", err)
|
||||
logging.Error("Cannot determine kernel version: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -45,66 +43,57 @@ func checkKernelVersionCompatibility() {
|
||||
// Parse version (e.g., "5.15.0-56-generic" -> major=5, minor=15)
|
||||
parts := strings.Split(kernelVersion, ".")
|
||||
if len(parts) < 2 {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: Cannot parse kernel version: %s\n", kernelVersion)
|
||||
logging.Error("Cannot parse kernel version: %s", kernelVersion)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
major, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: Cannot parse major kernel version: %s\n", parts[0])
|
||||
logging.Error("Cannot parse major kernel version: %s", parts[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
minor, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: Cannot parse minor kernel version: %s\n", parts[1])
|
||||
logging.Error("Cannot parse minor kernel version: %s", parts[1])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Check if kernel is 4.4 or higher
|
||||
if major < 4 || (major == 4 && minor < 4) {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: Kernel version %s is too old for eBPF.\n", kernelVersion)
|
||||
fmt.Fprintf(os.Stderr, "Required: Linux kernel 4.4 or higher\n")
|
||||
fmt.Fprintf(os.Stderr, "Current: %s\n", kernelVersion)
|
||||
fmt.Fprintf(os.Stderr, "Reason: eBPF requires kernel features introduced in 4.4+:\n")
|
||||
fmt.Fprintf(os.Stderr, " - BPF system call support\n")
|
||||
fmt.Fprintf(os.Stderr, " - eBPF program types (kprobe, tracepoint)\n")
|
||||
fmt.Fprintf(os.Stderr, " - BPF maps and helper functions\n")
|
||||
logging.Error("Kernel version %s is too old for eBPF", kernelVersion)
|
||||
logging.Error("Required: Linux kernel 4.4 or higher")
|
||||
logging.Error("Current: %s", kernelVersion)
|
||||
logging.Error("Reason: eBPF requires kernel features introduced in 4.4+:\n - BPF system call support\n - eBPF program types (kprobe, tracepoint)\n - BPF maps and helper functions")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// checkEBPFSupport validates eBPF subsystem availability
|
||||
func checkEBPFSupport() {
|
||||
// Check if /sys/kernel/debug/tracing exists (debugfs mounted)
|
||||
if _, err := os.Stat("/sys/kernel/debug/tracing"); os.IsNotExist(err) {
|
||||
fmt.Fprintf(os.Stderr, "⚠️ WARNING: debugfs not mounted. Some eBPF features may not work.\n")
|
||||
fmt.Fprintf(os.Stderr, "To fix: sudo mount -t debugfs debugfs /sys/kernel/debug\n")
|
||||
logging.Warning("debugfs not mounted. Some eBPF features may not work")
|
||||
logging.Info("To fix: sudo mount -t debugfs debugfs /sys/kernel/debug")
|
||||
}
|
||||
|
||||
// Check if we can access BPF syscall
|
||||
fd, _, errno := syscall.Syscall(321, 0, 0, 0) // BPF syscall number on x86_64
|
||||
if errno != 0 && errno != syscall.EINVAL {
|
||||
fmt.Fprintf(os.Stderr, "❌ ERROR: BPF syscall not available (errno: %v)\n", errno)
|
||||
fmt.Fprintf(os.Stderr, "This may indicate:\n")
|
||||
fmt.Fprintf(os.Stderr, " - Kernel compiled without BPF support\n")
|
||||
fmt.Fprintf(os.Stderr, " - BPF syscall disabled in kernel config\n")
|
||||
logging.Error("BPF syscall not available (errno: %v)", errno)
|
||||
logging.Error("This may indicate:\n - Kernel compiled without BPF support\n - BPF syscall disabled in kernel config")
|
||||
os.Exit(1)
|
||||
}
|
||||
if fd > 0 {
|
||||
syscall.Close(int(fd))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// runInteractiveDiagnostics starts the interactive diagnostic session
|
||||
func runInteractiveDiagnostics(agent *LinuxDiagnosticAgent) {
|
||||
fmt.Println("")
|
||||
fmt.Println("🔍 Linux eBPF-Enhanced Diagnostic Agent")
|
||||
fmt.Println("=======================================")
|
||||
fmt.Println("Linux Diagnostic Agent Started")
|
||||
fmt.Println("Enter a system issue description (or 'quit' to exit):")
|
||||
logging.Info("=== Linux eBPF-Enhanced Diagnostic Agent ===")
|
||||
logging.Info("Linux Diagnostic Agent Started")
|
||||
logging.Info("Enter a system issue description (or 'quit' to exit):")
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for {
|
||||
@@ -124,7 +113,7 @@ func runInteractiveDiagnostics(agent *LinuxDiagnosticAgent) {
|
||||
|
||||
// Process the issue with AI capabilities via TensorZero
|
||||
if err := agent.DiagnoseIssue(input); err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
logging.Error("Diagnosis failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,19 +121,18 @@ func runInteractiveDiagnostics(agent *LinuxDiagnosticAgent) {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Goodbye!")
|
||||
logging.Info("Goodbye!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Printf("🚀 NannyAgent v%s starting...\n", Version)
|
||||
logging.Info("NannyAgent v%s starting...", Version)
|
||||
|
||||
// Perform system compatibility checks first
|
||||
fmt.Println("Performing system compatibility checks...")
|
||||
logging.Info("Performing system compatibility checks...")
|
||||
checkRootPrivileges()
|
||||
checkKernelVersionCompatibility()
|
||||
checkEBPFSupport()
|
||||
fmt.Println("✅ All system checks passed")
|
||||
fmt.Println("")
|
||||
logging.Info("All system checks passed")
|
||||
|
||||
// Load configuration
|
||||
cfg, err := config.LoadConfig()
|
||||
@@ -164,10 +152,10 @@ func main() {
|
||||
log.Fatalf("❌ Authentication failed: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("✅ Authentication successful!")
|
||||
logging.Info("Authentication successful!")
|
||||
|
||||
// Initialize the diagnostic agent for interactive CLI use
|
||||
agent := NewLinuxDiagnosticAgent()
|
||||
// Initialize the diagnostic agent for interactive CLI use with authentication
|
||||
agent := NewLinuxDiagnosticAgentWithAuth(authManager)
|
||||
|
||||
// Initialize a separate agent for WebSocket investigations using the application model
|
||||
applicationAgent := NewLinuxDiagnosticAgent()
|
||||
@@ -177,53 +165,53 @@ func main() {
|
||||
wsClient := NewWebSocketClient(applicationAgent, authManager)
|
||||
go func() {
|
||||
if err := wsClient.Start(); err != nil {
|
||||
log.Printf("❌ WebSocket client error: %v", err)
|
||||
logging.Error("WebSocket client error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start background metrics collection in a goroutine
|
||||
go func() {
|
||||
fmt.Println("❤️ Starting background metrics collection and heartbeat...")
|
||||
logging.Debug("Starting background metrics collection and heartbeat...")
|
||||
|
||||
ticker := time.NewTicker(time.Duration(cfg.MetricsInterval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
// Send initial heartbeat
|
||||
if err := sendHeartbeat(cfg, token, metricsCollector); err != nil {
|
||||
log.Printf("⚠️ Initial heartbeat failed: %v", err)
|
||||
logging.Warning("Initial heartbeat failed: %v", err)
|
||||
}
|
||||
|
||||
// Main heartbeat loop
|
||||
for range ticker.C {
|
||||
// Check if token needs refresh
|
||||
if authManager.IsTokenExpired(token) {
|
||||
fmt.Println("🔄 Token expiring soon, refreshing...")
|
||||
logging.Debug("Token expiring soon, refreshing...")
|
||||
newToken, refreshErr := authManager.EnsureAuthenticated()
|
||||
if refreshErr != nil {
|
||||
log.Printf("❌ Token refresh failed: %v", refreshErr)
|
||||
logging.Warning("Token refresh failed: %v", refreshErr)
|
||||
continue
|
||||
}
|
||||
token = newToken
|
||||
fmt.Println("✅ Token refreshed successfully")
|
||||
logging.Debug("Token refreshed successfully")
|
||||
}
|
||||
|
||||
// Send heartbeat
|
||||
if err := sendHeartbeat(cfg, token, metricsCollector); err != nil {
|
||||
log.Printf("⚠️ Heartbeat failed: %v", err)
|
||||
logging.Warning("Heartbeat failed: %v", err)
|
||||
|
||||
// If unauthorized, try to refresh token
|
||||
if err.Error() == "unauthorized" {
|
||||
fmt.Println("🔄 Unauthorized, attempting token refresh...")
|
||||
logging.Debug("Unauthorized, attempting token refresh...")
|
||||
newToken, refreshErr := authManager.EnsureAuthenticated()
|
||||
if refreshErr != nil {
|
||||
log.Printf("❌ Token refresh failed: %v", refreshErr)
|
||||
logging.Warning("Token refresh failed: %v", refreshErr)
|
||||
continue
|
||||
}
|
||||
token = newToken
|
||||
|
||||
// Retry heartbeat with new token (silently)
|
||||
if retryErr := sendHeartbeat(cfg, token, metricsCollector); retryErr != nil {
|
||||
log.Printf("⚠️ Retry heartbeat failed: %v", retryErr)
|
||||
logging.Warning("Retry heartbeat failed: %v", retryErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user