fix: Enrollment-Duplikate, IPv6-Adresse, Agent-Status
- Backend: Enroll-Upsert via MAC-Adresse (kein Duplikat bei Neustart) HeartbeatInterval auf 30s reduziert - Go collector: IPv4 bevorzugen, Loopback/Teredo/ISATAP überspringen, Link-Local IPv6 ignorieren - Go main.go: Enrollment nimmt beste IPv4-Schnittstelle statt Networks[0]
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -40,10 +41,20 @@ func main() {
|
|||||||
if cfg.AgentID == "" {
|
if cfg.AgentID == "" {
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
metrics, _ := collector.Collect()
|
metrics, _ := collector.Collect()
|
||||||
|
// Beste Netzwerkschnittstelle für Enrollment wählen (bevorzuge IPv4)
|
||||||
mac, ip := "", ""
|
mac, ip := "", ""
|
||||||
if len(metrics.Networks) > 0 {
|
for _, n := range metrics.Networks {
|
||||||
mac = metrics.Networks[0].MAC
|
if n.MAC == "" || n.IPAddress == "" {
|
||||||
ip = metrics.Networks[0].IPAddress
|
continue
|
||||||
|
}
|
||||||
|
if mac == "" {
|
||||||
|
mac, ip = n.MAC, n.IPAddress
|
||||||
|
}
|
||||||
|
// Sobald IPv4 gefunden: nehmen und fertig
|
||||||
|
if !strings.Contains(n.IPAddress, ":") {
|
||||||
|
mac, ip = n.MAC, n.IPAddress
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Client.Enroll(context.Background(), &pb.EnrollRequest{
|
resp, err := client.Client.Enroll(context.Background(), &pb.EnrollRequest{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
@@ -79,15 +81,41 @@ func Collect() (*Metrics, error) {
|
|||||||
counterMap[c.Name] = c
|
counterMap[c.Name] = c
|
||||||
}
|
}
|
||||||
for _, iface := range interfaces {
|
for _, iface := range interfaces {
|
||||||
if len(iface.Addrs) == 0 {
|
if len(iface.Addrs) == 0 || iface.HardwareAddr == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Loopback und virtuelle Adapter überspringen
|
||||||
|
nameLower := strings.ToLower(iface.Name)
|
||||||
|
if strings.Contains(nameLower, "loopback") || strings.Contains(nameLower, "teredo") ||
|
||||||
|
strings.Contains(nameLower, "isatap") || strings.Contains(nameLower, "6to4") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ni := NetInfo{
|
ni := NetInfo{
|
||||||
Name: iface.Name,
|
Name: iface.Name,
|
||||||
MAC: iface.HardwareAddr,
|
MAC: iface.HardwareAddr,
|
||||||
}
|
}
|
||||||
if len(iface.Addrs) > 0 {
|
// IPv4 bevorzugen, IPv6 als Fallback
|
||||||
ni.IPAddress = iface.Addrs[0].Addr
|
for _, addr := range iface.Addrs {
|
||||||
|
ip, _, err := net.ParseCIDR(addr.Addr)
|
||||||
|
if err != nil {
|
||||||
|
// Versuche direkte IP-Adresse (ohne CIDR)
|
||||||
|
ip = net.ParseIP(addr.Addr)
|
||||||
|
}
|
||||||
|
if ip == nil || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ip.To4() != nil {
|
||||||
|
// IPv4 gefunden — nehmen und abbrechen
|
||||||
|
ni.IPAddress = addr.Addr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ni.IPAddress == "" {
|
||||||
|
// IPv6 als vorläufiger Fallback
|
||||||
|
ni.IPAddress = addr.Addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ni.IPAddress == "" {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if c, ok := counterMap[iface.Name]; ok {
|
if c, ok := counterMap[iface.Name]; ok {
|
||||||
ni.BytesSent = c.BytesSent
|
ni.BytesSent = c.BytesSent
|
||||||
|
|||||||
@@ -29,6 +29,24 @@ public class AgentGrpcService : AgentService.AgentServiceBase
|
|||||||
|
|
||||||
public override async Task<EnrollResponse> Enroll(EnrollRequest request, ServerCallContext context)
|
public override async Task<EnrollResponse> Enroll(EnrollRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
// Upsert via MAC-Adresse — verhindert Duplikate bei Agent-Neustart
|
||||||
|
var existing = !string.IsNullOrEmpty(request.MacAddress)
|
||||||
|
? await _db.Agents.FirstOrDefaultAsync(a => a.MacAddress == request.MacAddress)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (existing is not null)
|
||||||
|
{
|
||||||
|
existing.Hostname = request.Hostname;
|
||||||
|
existing.OsVersion = request.OsVersion;
|
||||||
|
existing.IpAddress = request.IpAddress;
|
||||||
|
existing.AgentVersion = request.AgentVersion;
|
||||||
|
existing.Status = AgentStatus.Online;
|
||||||
|
existing.LastSeen = DateTime.UtcNow;
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
_logger.LogInformation("Agent re-enrolled: {AgentId} ({Hostname})", existing.Id, existing.Hostname);
|
||||||
|
return new EnrollResponse { AgentId = existing.Id.ToString(), HeartbeatInterval = 30 };
|
||||||
|
}
|
||||||
|
|
||||||
var agent = new AgentModel
|
var agent = new AgentModel
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@@ -47,11 +65,7 @@ public class AgentGrpcService : AgentService.AgentServiceBase
|
|||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
_logger.LogInformation("Agent enrolled: {AgentId} ({Hostname})", agent.Id, agent.Hostname);
|
_logger.LogInformation("Agent enrolled: {AgentId} ({Hostname})", agent.Id, agent.Hostname);
|
||||||
|
|
||||||
return new EnrollResponse
|
return new EnrollResponse { AgentId = agent.Id.ToString(), HeartbeatInterval = 30 };
|
||||||
{
|
|
||||||
AgentId = agent.Id.ToString(),
|
|
||||||
HeartbeatInterval = 60
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<HeartbeatResponse> Heartbeat(HeartbeatRequest request, ServerCallContext context)
|
public override async Task<HeartbeatResponse> Heartbeat(HeartbeatRequest request, ServerCallContext context)
|
||||||
|
|||||||
Reference in New Issue
Block a user