agent session id persistence

This commit is contained in:
Oliver Kieselbach
2026-02-05 23:31:02 +01:00
parent c2a7c28eec
commit d7fdef39d6
4 changed files with 152 additions and 9 deletions
@@ -403,12 +403,20 @@ namespace AutopilotMonitor.Agent.Core.Monitoring
}
// Check for enrollment completion events
if (_configuration.SelfDestructOnComplete &&
(evt.EventType == "enrollment_complete" || evt.EventType == "enrollment_failed"))
if (evt.EventType == "enrollment_complete" || evt.EventType == "enrollment_failed")
{
_logger.Info($"Enrollment completion detected: {evt.EventType}");
Task.Run(() => HandleEnrollmentComplete());
return; // Don't continue with normal event processing
// ALWAYS delete session ID when enrollment is complete/failed
// This ensures a new session will be created on next enrollment
DeleteSessionId();
// Only trigger self-destruct if configured
if (_configuration.SelfDestructOnComplete)
{
Task.Run(() => HandleEnrollmentComplete());
return; // Don't continue with normal event processing
}
}
// Immediate upload for:
@@ -499,6 +507,26 @@ namespace AutopilotMonitor.Agent.Core.Monitoring
}
}
/// <summary>
/// Deletes the persisted session ID file
/// Should be called when enrollment is complete/failed
/// </summary>
private void DeleteSessionId()
{
_logger.Info("Deleting persisted session ID...");
try
{
var dataDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor");
var sessionPersistence = new SessionPersistence(dataDirectory);
sessionPersistence.DeleteSession();
_logger.Info("Session ID deleted successfully");
}
catch (Exception ex)
{
_logger.Warning($"Failed to delete session ID: {ex.Message}");
}
}
/// <summary>
/// Handles enrollment completion and triggers self-destruct sequence
/// </summary>
@@ -520,7 +548,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring
// Give a moment for final upload to complete
await Task.Delay(2000);
// Step 3: Execute self-destruct
// Step 3: Execute self-destruct or cleanup
if (_configuration.SelfDestructOnComplete)
{
ExecuteSelfDestruct();
@@ -0,0 +1,100 @@
using System;
using System.IO;
namespace AutopilotMonitor.Agent.Core.Storage
{
/// <summary>
/// Manages persistent session ID storage to maintain tracking across agent restarts
/// </summary>
public class SessionPersistence
{
private readonly string _sessionFilePath;
private readonly object _lockObject = new object();
public SessionPersistence(string dataDirectory)
{
if (string.IsNullOrWhiteSpace(dataDirectory))
{
throw new ArgumentNullException(nameof(dataDirectory));
}
if (!Directory.Exists(dataDirectory))
{
Directory.CreateDirectory(dataDirectory);
}
_sessionFilePath = Path.Combine(dataDirectory, "session.id");
}
/// <summary>
/// Loads existing session ID from disk or creates a new one if none exists
/// </summary>
/// <returns>Session ID (GUID string)</returns>
public string LoadOrCreateSessionId()
{
lock (_lockObject)
{
try
{
// Check if session file exists and is valid
if (File.Exists(_sessionFilePath))
{
var sessionId = File.ReadAllText(_sessionFilePath).Trim();
// Validate it's a valid GUID format
if (Guid.TryParse(sessionId, out _))
{
return sessionId;
}
}
// Create new session ID if file doesn't exist or is invalid
var newSessionId = Guid.NewGuid().ToString();
File.WriteAllText(_sessionFilePath, newSessionId);
return newSessionId;
}
catch (Exception ex)
{
// If we can't read/write the session file, generate a new ID in memory
// Log this error if logger is available
throw new InvalidOperationException($"Failed to load or create session ID at {_sessionFilePath}", ex);
}
}
}
/// <summary>
/// Deletes the persisted session ID file
/// This should be called when enrollment is complete
/// </summary>
public void DeleteSession()
{
lock (_lockObject)
{
try
{
if (File.Exists(_sessionFilePath))
{
File.Delete(_sessionFilePath);
}
}
catch (Exception)
{
// Suppress deletion errors - not critical if cleanup fails
// The file will be overwritten on next start anyway
}
}
}
/// <summary>
/// Checks if a persisted session ID exists
/// </summary>
/// <returns>True if session file exists</returns>
public bool SessionExists()
{
lock (_lockObject)
{
return File.Exists(_sessionFilePath);
}
}
}
}
@@ -3,6 +3,7 @@ using System.ServiceProcess;
using AutopilotMonitor.Agent.Core.Configuration;
using AutopilotMonitor.Agent.Core.Logging;
using AutopilotMonitor.Agent.Core.Monitoring;
using AutopilotMonitor.Agent.Core.Storage;
namespace AutopilotMonitor.Agent
{
@@ -61,12 +62,15 @@ namespace AutopilotMonitor.Agent
private AgentConfiguration LoadConfiguration()
{
// TODO: Load from registry or config file
// For now, return a default configuration
// Load or create persisted session ID
var dataDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor");
var sessionPersistence = new SessionPersistence(dataDirectory);
var sessionId = sessionPersistence.LoadOrCreateSessionId();
return new AgentConfiguration
{
ApiBaseUrl = Environment.GetEnvironmentVariable("AUTOPILOT_MONITOR_API") ?? "http://localhost:7071",
SessionId = Guid.NewGuid().ToString(),
SessionId = sessionId,
TenantId = "default-tenant",
SpoolDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Spool"),
LogDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Logs"),
+12 -1
View File
@@ -6,6 +6,7 @@ using System.ServiceProcess;
using AutopilotMonitor.Agent.Core.Configuration;
using AutopilotMonitor.Agent.Core.Logging;
using AutopilotMonitor.Agent.Core.Monitoring;
using AutopilotMonitor.Agent.Core.Storage;
using Microsoft.Win32;
using Newtonsoft.Json;
@@ -264,10 +265,20 @@ namespace AutopilotMonitor.Agent
}
}
// Load or create persisted session ID
var dataDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor");
var sessionPersistence = new SessionPersistence(dataDirectory);
var sessionId = sessionPersistence.LoadOrCreateSessionId();
var sessionStatus = sessionPersistence.SessionExists() && File.GetCreationTime(Path.Combine(dataDirectory, "session.id")) < DateTime.Now.AddMinutes(-1)
? "Restored from previous session"
: "New session created";
Console.WriteLine($"Session ID: {sessionId} ({sessionStatus})");
return new AgentConfiguration
{
ApiBaseUrl = apiBaseUrl,
SessionId = Guid.NewGuid().ToString(),
SessionId = sessionId,
TenantId = tenantId,
SpoolDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Spool"),
LogDirectory = Environment.ExpandEnvironmentVariables(@"%ProgramData%\AutopilotMonitor\Logs"),