mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 20:53:06 +00:00
removed simulator and introduction of logreplayservice
This commit is contained in:
@@ -65,16 +65,6 @@ namespace AutopilotMonitor.Agent.Core.Configuration
|
||||
/// </summary>
|
||||
public int MaxRetryAttempts { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Enable Autopilot simulator for testing/demo (generates fake events)
|
||||
/// </summary>
|
||||
public bool EnableSimulator { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Simulate enrollment failure (only used if EnableSimulator is true)
|
||||
/// </summary>
|
||||
public bool SimulateFailure { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to cleanup files on exit (delete C:\ProgramData\AutopilotMonitor)
|
||||
/// </summary>
|
||||
@@ -119,18 +109,16 @@ namespace AutopilotMonitor.Agent.Core.Configuration
|
||||
public string ImeMatchLogPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path to directory with real IME log files for simulation replay.
|
||||
/// When set (with EnableSimulator), the simulator replays these logs with time compression
|
||||
/// instead of generating artificial events.
|
||||
/// Path to directory with real IME log files for log replay.
|
||||
/// When set, the agent replays these logs with time compression instead of reading live logs.
|
||||
/// </summary>
|
||||
public string SimulationLogDirectory { get; set; }
|
||||
public string ReplayLogDir { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time compression factor for simulation mode.
|
||||
/// Time compression factor for log replay.
|
||||
/// Higher values = faster replay. Default: 50 (e.g., 50 minutes of real logs = 1 minute of replay).
|
||||
/// Targeting 3-5 minute total enrollment replay.
|
||||
/// </summary>
|
||||
public double SimulationSpeedFactor { get; set; } = 50;
|
||||
public double ReplaySpeedFactor { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Wait time in seconds after ESP exit before marking Hello as skipped.
|
||||
|
||||
@@ -8,7 +8,7 @@ using AutopilotMonitor.Agent.Core.Configuration;
|
||||
using AutopilotMonitor.Agent.Core.Logging;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Collectors;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Network;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Simulation;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Replay;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Tracking;
|
||||
using AutopilotMonitor.Shared.Models;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
|
||||
// Core event collectors (always on)
|
||||
private HelloDetector _helloDetector;
|
||||
private AutopilotSimulator _simulator;
|
||||
private LogReplayService _logReplay;
|
||||
|
||||
// Optional collectors (toggled via remote config)
|
||||
private PerformanceCollector _performanceCollector;
|
||||
@@ -187,23 +187,22 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
);
|
||||
_helloDetector.Start();
|
||||
|
||||
// Start Autopilot Simulator if enabled
|
||||
if (_configuration.EnableSimulator)
|
||||
// Start log replay if a replay directory is configured
|
||||
if (!string.IsNullOrEmpty(_configuration.ReplayLogDir))
|
||||
{
|
||||
_logger.Info("Simulator mode enabled - starting Autopilot simulator");
|
||||
_logger.Info($"Log replay mode enabled - starting log replay from: {_configuration.ReplayLogDir}");
|
||||
var imeLogPatterns = _remoteConfigService?.CurrentConfig?.ImeLogPatterns;
|
||||
_simulator = new AutopilotSimulator(
|
||||
_logReplay = new LogReplayService(
|
||||
_configuration.SessionId,
|
||||
_configuration.TenantId,
|
||||
EmitEvent,
|
||||
_logger,
|
||||
_configuration.SimulateFailure,
|
||||
_configuration.SimulationLogDirectory,
|
||||
_configuration.SimulationSpeedFactor,
|
||||
_configuration.ReplayLogDir,
|
||||
_configuration.ReplaySpeedFactor,
|
||||
imeLogPatterns
|
||||
);
|
||||
_simulator.Start();
|
||||
_logger.Info("Autopilot simulator started");
|
||||
_logReplay.Start();
|
||||
_logger.Info("Log replay started");
|
||||
}
|
||||
|
||||
_logger.Info("Core event collectors started successfully");
|
||||
@@ -290,7 +289,8 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
|
||||
// EnrollmentTracker: smart enrollment tracking with IME log parsing
|
||||
// (replaces DownloadProgressCollector + EspUiStateCollector)
|
||||
if (!_configuration.EnableSimulator)
|
||||
// Skip when log replay is active - LogReplayService starts its own EnrollmentTracker
|
||||
if (string.IsNullOrEmpty(_configuration.ReplayLogDir))
|
||||
{
|
||||
var imeLogPatterns = config?.ImeLogPatterns;
|
||||
var imeMatchLogPath = string.IsNullOrEmpty(_configuration.ImeMatchLogPath)
|
||||
@@ -483,8 +483,8 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
_helloDetector?.Stop();
|
||||
_helloDetector?.Dispose();
|
||||
|
||||
_simulator?.Stop();
|
||||
_simulator?.Dispose();
|
||||
_logReplay?.Stop();
|
||||
_logReplay?.Dispose();
|
||||
|
||||
// Stop optional collectors
|
||||
StopOptionalCollectors();
|
||||
@@ -788,7 +788,7 @@ namespace AutopilotMonitor.Agent.Core.Monitoring.Core
|
||||
_apiClient?.Dispose();
|
||||
_spool?.Dispose();
|
||||
_helloDetector?.Dispose();
|
||||
_simulator?.Dispose();
|
||||
_logReplay?.Dispose();
|
||||
_performanceCollector?.Dispose();
|
||||
_enrollmentTracker?.Dispose();
|
||||
_gatherRuleExecutor?.Dispose();
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutopilotMonitor.Agent.Core.Logging;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Tracking;
|
||||
using AutopilotMonitor.Shared.Models;
|
||||
|
||||
namespace AutopilotMonitor.Agent.Core.Monitoring.Replay
|
||||
{
|
||||
/// <summary>
|
||||
/// Replays a real Autopilot enrollment using IME log files with time compression.
|
||||
///
|
||||
/// Key principle: Real data, no mocks.
|
||||
/// - Device info: collected from actual WMI/Registry on the machine running the replay
|
||||
/// - App tracking: replayed from real IME log files with configurable speed factor
|
||||
/// - Performance data: handled by PerformanceCollector (always on, real machine data)
|
||||
/// </summary>
|
||||
public class LogReplayService : IDisposable
|
||||
{
|
||||
private readonly AgentLogger _logger;
|
||||
private readonly string _sessionId;
|
||||
private readonly string _tenantId;
|
||||
private readonly Action<EnrollmentEvent> _onEventCollected;
|
||||
private readonly string _replayLogDir;
|
||||
private readonly double _speedFactor;
|
||||
private readonly List<ImeLogPattern> _imeLogPatterns;
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task _replayTask;
|
||||
private EnrollmentTracker _enrollmentTracker;
|
||||
private bool _disposed = false;
|
||||
|
||||
public LogReplayService(
|
||||
string sessionId,
|
||||
string tenantId,
|
||||
Action<EnrollmentEvent> onEventCollected,
|
||||
AgentLogger logger,
|
||||
string replayLogDir = null,
|
||||
double speedFactor = 50,
|
||||
List<ImeLogPattern> imeLogPatterns = null)
|
||||
{
|
||||
_sessionId = sessionId ?? throw new ArgumentNullException(nameof(sessionId));
|
||||
_tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
|
||||
_onEventCollected = onEventCollected ?? throw new ArgumentNullException(nameof(onEventCollected));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_replayLogDir = replayLogDir;
|
||||
_speedFactor = speedFactor;
|
||||
_imeLogPatterns = imeLogPatterns ?? new List<ImeLogPattern>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts log replay
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
_logger.Info("Starting log replay service");
|
||||
|
||||
if (string.IsNullOrEmpty(_replayLogDir) || !Directory.Exists(_replayLogDir))
|
||||
{
|
||||
_logger.Warning($"Replay log directory not found or not specified: {_replayLogDir}");
|
||||
_logger.Info("Log replay will only emit device info events (no log replay)");
|
||||
}
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_replayTask = Task.Run(() => RunReplay(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the log replay
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_logger.Info("Stopping log replay service");
|
||||
|
||||
try
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_replayTask?.Wait(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (AggregateException) { }
|
||||
}
|
||||
|
||||
private async Task RunReplay(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info($"Starting log replay (real device data + IME log replay, speed factor: {_speedFactor}x)");
|
||||
|
||||
_enrollmentTracker = new EnrollmentTracker(
|
||||
_sessionId,
|
||||
_tenantId,
|
||||
_onEventCollected,
|
||||
_logger,
|
||||
_imeLogPatterns,
|
||||
_replayLogDir,
|
||||
simulationMode: true,
|
||||
speedFactor: _speedFactor
|
||||
);
|
||||
|
||||
_enrollmentTracker.Start();
|
||||
_logger.Info($"EnrollmentTracker started in replay mode (speed factor: {_speedFactor}x)");
|
||||
|
||||
// Wait for log replay to complete or be cancelled
|
||||
var checkInterval = TimeSpan.FromSeconds(5);
|
||||
var maxWaitTime = TimeSpan.FromMinutes(10); // Safety timeout
|
||||
var elapsed = TimeSpan.Zero;
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested && elapsed < maxWaitTime)
|
||||
{
|
||||
await Task.Delay(checkInterval, cancellationToken);
|
||||
elapsed += checkInterval;
|
||||
|
||||
var packageStates = _enrollmentTracker.ImeTracker?.PackageStates;
|
||||
if (packageStates != null && packageStates.CountAll > 0 && packageStates.IsAllCompleted())
|
||||
{
|
||||
_logger.Info($"Log replay: all {packageStates.CountAll} apps completed after {elapsed.TotalSeconds:F0}s");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Info("Log replay completed (enrollment_complete will be emitted when IME log shows user session completion)");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Info("Log replay cancelled");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("Error in log replay", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
_enrollmentTracker?.Dispose();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutopilotMonitor.Agent.Core.Logging;
|
||||
using AutopilotMonitor.Agent.Core.Monitoring.Tracking;
|
||||
using AutopilotMonitor.Shared.Models;
|
||||
|
||||
namespace AutopilotMonitor.Agent.Core.Monitoring.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// Simulates Autopilot enrollment using real IME log replay and real device data.
|
||||
///
|
||||
/// Key principle: Real data, no mocks.
|
||||
/// - Device info: collected from actual WMI/Registry on the machine running the simulator
|
||||
/// - App tracking: replayed from real IME log files with time-compressed delays
|
||||
/// - Performance data: handled by PerformanceCollector (always on, real machine data)
|
||||
/// </summary>
|
||||
public class AutopilotSimulator : IDisposable
|
||||
{
|
||||
private readonly AgentLogger _logger;
|
||||
private readonly string _sessionId;
|
||||
private readonly string _tenantId;
|
||||
private readonly Action<EnrollmentEvent> _onEventCollected;
|
||||
private readonly bool _simulateFailure;
|
||||
private readonly string _simulationLogDirectory;
|
||||
private readonly double _speedFactor;
|
||||
private readonly List<ImeLogPattern> _imeLogPatterns;
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Task _simulationTask;
|
||||
private EnrollmentTracker _enrollmentTracker;
|
||||
private bool _disposed = false;
|
||||
|
||||
public AutopilotSimulator(
|
||||
string sessionId,
|
||||
string tenantId,
|
||||
Action<EnrollmentEvent> onEventCollected,
|
||||
AgentLogger logger,
|
||||
bool simulateFailure = false,
|
||||
string simulationLogDirectory = null,
|
||||
double speedFactor = 50,
|
||||
List<ImeLogPattern> imeLogPatterns = null)
|
||||
{
|
||||
_sessionId = sessionId ?? throw new ArgumentNullException(nameof(sessionId));
|
||||
_tenantId = tenantId ?? throw new ArgumentNullException(nameof(tenantId));
|
||||
_onEventCollected = onEventCollected ?? throw new ArgumentNullException(nameof(onEventCollected));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_simulateFailure = simulateFailure;
|
||||
_simulationLogDirectory = simulationLogDirectory;
|
||||
_speedFactor = speedFactor;
|
||||
_imeLogPatterns = imeLogPatterns ?? new List<ImeLogPattern>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the Autopilot simulation
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
_logger.Info("Starting Autopilot Simulator (log replay mode)");
|
||||
|
||||
if (string.IsNullOrEmpty(_simulationLogDirectory) || !Directory.Exists(_simulationLogDirectory))
|
||||
{
|
||||
_logger.Warning($"Simulation log directory not found or not specified: {_simulationLogDirectory}");
|
||||
_logger.Info("Simulator will only emit device info events (no log replay)");
|
||||
}
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_simulationTask = Task.Run(() => RunSimulation(_cancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the simulation
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
_logger.Info("Stopping Autopilot Simulator");
|
||||
|
||||
try
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_simulationTask?.Wait(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (AggregateException) { }
|
||||
}
|
||||
|
||||
private async Task RunSimulation(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Starting simulated Autopilot enrollment (real device data + log replay)");
|
||||
|
||||
// Create EnrollmentTracker in simulation mode
|
||||
// This collects REAL device info from this machine and replays IME logs
|
||||
// The EnrollmentTracker will emit all real events from log replay
|
||||
_enrollmentTracker = new EnrollmentTracker(
|
||||
_sessionId,
|
||||
_tenantId,
|
||||
_onEventCollected,
|
||||
_logger,
|
||||
_imeLogPatterns,
|
||||
_simulationLogDirectory,
|
||||
simulationMode: true,
|
||||
speedFactor: _speedFactor
|
||||
);
|
||||
|
||||
_enrollmentTracker.Start();
|
||||
_logger.Info($"EnrollmentTracker started in simulation mode (speed factor: {_speedFactor}x)");
|
||||
|
||||
// Wait for log replay to complete or be cancelled
|
||||
// The ImeLogTracker will parse all log files and then the polling loop will idle
|
||||
// We monitor the app tracking state to know when to complete
|
||||
var checkInterval = TimeSpan.FromSeconds(5);
|
||||
var maxWaitTime = TimeSpan.FromMinutes(10); // Safety timeout
|
||||
var elapsed = TimeSpan.Zero;
|
||||
var allAppsCompleted = false;
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested && elapsed < maxWaitTime)
|
||||
{
|
||||
await Task.Delay(checkInterval, cancellationToken);
|
||||
elapsed += checkInterval;
|
||||
|
||||
// Check if all apps have been tracked and completed
|
||||
var packageStates = _enrollmentTracker.ImeTracker?.PackageStates;
|
||||
if (packageStates != null && packageStates.CountAll > 0 && packageStates.IsAllCompleted())
|
||||
{
|
||||
allAppsCompleted = true;
|
||||
_logger.Info($"Simulator: all {packageStates.CountAll} apps completed after {elapsed.TotalSeconds:F0}s");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested) return;
|
||||
|
||||
// Note: enrollment_complete event is now emitted by EnrollmentTracker
|
||||
// when it detects "Completed user session" in the IME log.
|
||||
// We only emit failure events here if simulation fails.
|
||||
if (_simulateFailure && !allAppsCompleted)
|
||||
{
|
||||
EmitEvent("enrollment_failed", "Enrollment failed: app installation timeout",
|
||||
EventSeverity.Critical, EnrollmentPhase.Failed,
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "failedPhase", "AppInstallation" },
|
||||
{ "reason", "App installation did not complete within timeout" }
|
||||
});
|
||||
}
|
||||
|
||||
_logger.Info("Simulated Autopilot enrollment replay completed (enrollment_complete will be emitted when IME log shows user session completion)");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Info("Autopilot simulation cancelled");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("Error in Autopilot simulation", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitEvent(string eventType, string message, EventSeverity severity,
|
||||
EnrollmentPhase phase, Dictionary<string, object> data = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_onEventCollected(new EnrollmentEvent
|
||||
{
|
||||
SessionId = _sessionId,
|
||||
TenantId = _tenantId,
|
||||
Timestamp = DateTime.UtcNow,
|
||||
EventType = eventType,
|
||||
Severity = severity,
|
||||
Source = "Simulator",
|
||||
Phase = phase,
|
||||
Message = message,
|
||||
Data = data ?? new Dictionary<string, object>()
|
||||
});
|
||||
_logger.Debug($"Simulator event: {eventType} - {message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"Error emitting simulator event: {eventType}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
_enrollmentTracker?.Dispose();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -23,13 +22,6 @@ namespace AutopilotMonitor.Agent
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for mass rollout simulator mode
|
||||
if (args.Contains("--simulator-mass-rollout"))
|
||||
{
|
||||
RunMassRolloutSimulator(args);
|
||||
return;
|
||||
}
|
||||
|
||||
// Always run directly - no ServiceBase.Run.
|
||||
// The agent is started by the Scheduled Task (SYSTEM) or manually with --console.
|
||||
// Both paths land here and run identically; --console just enables console output.
|
||||
@@ -172,12 +164,8 @@ namespace AutopilotMonitor.Agent
|
||||
Console.WriteLine($"API URL: {config.ApiBaseUrl}");
|
||||
Console.WriteLine($"Log Dir: {logDir}");
|
||||
Console.WriteLine($"Keep Logs: {config.KeepLogFile}");
|
||||
if (config.EnableSimulator)
|
||||
{
|
||||
Console.WriteLine($"Simulator: ENABLED (Failure={config.SimulateFailure})");
|
||||
if (!string.IsNullOrEmpty(config.SimulationLogDirectory))
|
||||
Console.WriteLine($"Sim Log Dir: {config.SimulationLogDirectory} ({config.SimulationSpeedFactor}x)");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(config.ReplayLogDir))
|
||||
Console.WriteLine($"Replay Dir: {config.ReplayLogDir} ({config.ReplaySpeedFactor}x)");
|
||||
if (config.RebootOnComplete) Console.WriteLine("Reboot: ON COMPLETE");
|
||||
if (config.UseClientCertAuth)
|
||||
{
|
||||
@@ -231,105 +219,6 @@ namespace AutopilotMonitor.Agent
|
||||
}
|
||||
}
|
||||
|
||||
static void RunMassRolloutSimulator(string[] args)
|
||||
{
|
||||
Console.WriteLine("Autopilot Monitor Agent - MASS ROLLOUT SIMULATOR MODE");
|
||||
Console.WriteLine("======================================================");
|
||||
Console.WriteLine("Simulating 5 parallel device enrollments across 3 tenants:");
|
||||
Console.WriteLine(" - 3x Tenant: b54dc1af-5320-4f60-b5d4-821e0cf2a359 (1 will fail)");
|
||||
Console.WriteLine(" - 1x Tenant: a53834b7-42bc-46a3-b004-369735c3acf9");
|
||||
Console.WriteLine(" - 1x Tenant: deadbeef-dead-beef-dead-beefdeadbeef");
|
||||
Console.WriteLine();
|
||||
|
||||
// Parse base configuration from args (API URL, etc.)
|
||||
var baseConfig = LoadConfiguration(args);
|
||||
|
||||
// Define the 5 device configurations
|
||||
var deviceConfigs = new[]
|
||||
{
|
||||
new { TenantId = "b54dc1af-5320-4f60-b5d4-821e0cf2a359", SimulateFailure = false, DeviceName = "Device-1" },
|
||||
new { TenantId = "b54dc1af-5320-4f60-b5d4-821e0cf2a359", SimulateFailure = true, DeviceName = "Device-2" },
|
||||
new { TenantId = "b54dc1af-5320-4f60-b5d4-821e0cf2a359", SimulateFailure = false, DeviceName = "Device-3" },
|
||||
new { TenantId = "a53834b7-42bc-46a3-b004-369735c3acf9", SimulateFailure = false, DeviceName = "Device-4" },
|
||||
new { TenantId = "deadbeef-dead-beef-dead-beefdeadbeef", SimulateFailure = false, DeviceName = "Device-5" }
|
||||
};
|
||||
|
||||
var tasks = new List<System.Threading.Tasks.Task>();
|
||||
var services = new List<MonitoringService>();
|
||||
|
||||
for (int i = 0; i < deviceConfigs.Length; i++)
|
||||
{
|
||||
var deviceConfig = deviceConfigs[i];
|
||||
var instanceNumber = i + 1;
|
||||
|
||||
var config = new AgentConfiguration
|
||||
{
|
||||
ApiBaseUrl = baseConfig.ApiBaseUrl,
|
||||
SessionId = Guid.NewGuid().ToString(),
|
||||
TenantId = deviceConfig.TenantId,
|
||||
SpoolDirectory = Environment.ExpandEnvironmentVariables($@"%ProgramData%\AutopilotMonitor\MassRollout\{deviceConfig.DeviceName}\Spool"),
|
||||
LogDirectory = Environment.ExpandEnvironmentVariables($@"%ProgramData%\AutopilotMonitor\MassRollout\{deviceConfig.DeviceName}\Logs"),
|
||||
UploadIntervalSeconds = Constants.DefaultUploadIntervalSeconds,
|
||||
MaxBatchSize = Constants.MaxBatchSize,
|
||||
LogLevel = AgentLogLevel.Debug,
|
||||
EnableSimulator = true,
|
||||
SimulateFailure = deviceConfig.SimulateFailure,
|
||||
UseClientCertAuth = baseConfig.UseClientCertAuth,
|
||||
ClientCertThumbprint = baseConfig.ClientCertThumbprint,
|
||||
CleanupOnExit = false,
|
||||
SelfDestructOnComplete = false,
|
||||
RebootOnComplete = false,
|
||||
EnableGeoLocation = false
|
||||
};
|
||||
|
||||
var logDir = Environment.ExpandEnvironmentVariables(config.LogDirectory);
|
||||
Directory.CreateDirectory(config.SpoolDirectory);
|
||||
Directory.CreateDirectory(config.LogDirectory);
|
||||
|
||||
var logger = new AgentLogger(logDir, AgentLogLevel.Debug);
|
||||
|
||||
Console.WriteLine($"[{deviceConfig.DeviceName}] Starting instance {instanceNumber}/5");
|
||||
Console.WriteLine($" Tenant ID: {deviceConfig.TenantId}");
|
||||
Console.WriteLine($" Session ID: {config.SessionId}");
|
||||
Console.WriteLine($" Simulate Failure: {(deviceConfig.SimulateFailure ? "YES" : "NO")}");
|
||||
Console.WriteLine();
|
||||
|
||||
var service = new MonitoringService(config, logger, GetAgentVersion());
|
||||
services.Add(service);
|
||||
|
||||
var task = System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
service.Start();
|
||||
while (true)
|
||||
System.Threading.Thread.Sleep(1000);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"[{deviceConfig.DeviceName}] Error in monitoring service", ex);
|
||||
Console.WriteLine($"[{deviceConfig.DeviceName}] ERROR: {ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
tasks.Add(task);
|
||||
}
|
||||
|
||||
Console.WriteLine("All 5 instances started in parallel.");
|
||||
Console.WriteLine("Press Enter to stop all instances...");
|
||||
Console.ReadLine();
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Stopping all instances...");
|
||||
foreach (var service in services)
|
||||
{
|
||||
try { service.Stop(); service.Dispose(); }
|
||||
catch (Exception ex) { Console.WriteLine($"Error stopping service: {ex.Message}"); }
|
||||
}
|
||||
|
||||
Console.WriteLine("All instances stopped.");
|
||||
}
|
||||
|
||||
static string GetTenantIdFromRegistry()
|
||||
{
|
||||
try
|
||||
@@ -365,8 +254,6 @@ namespace AutopilotMonitor.Agent
|
||||
|
||||
static AgentConfiguration LoadConfiguration(string[] args = null)
|
||||
{
|
||||
var enableSimulator = args?.Contains("--simulator") ?? false;
|
||||
var simulateFailure = args?.Contains("--simulate-failure") ?? false;
|
||||
var noAuth = args?.Contains("--no-auth") ?? false;
|
||||
var noCleanup = args?.Contains("--no-cleanup") ?? false;
|
||||
var rebootOnComplete = args?.Contains("--reboot-on-complete") ?? false;
|
||||
@@ -379,8 +266,8 @@ namespace AutopilotMonitor.Agent
|
||||
string apiBaseUrlOverride = null;
|
||||
string imeLogPathOverride = null;
|
||||
string imeMatchLogPath = null;
|
||||
string simulationLogDir = null;
|
||||
double simulationSpeedFactor = 50;
|
||||
string replayLogDir = null;
|
||||
double replaySpeedFactor = 50;
|
||||
|
||||
if (args != null)
|
||||
{
|
||||
@@ -394,10 +281,9 @@ namespace AutopilotMonitor.Agent
|
||||
|
||||
// Local backend URL override for debugging/testing.
|
||||
// Supported aliases:
|
||||
// --ApiUrl https://...
|
||||
// --api-url https://...
|
||||
// --backend-api https://...
|
||||
apiBaseUrlOverride = GetArgValue(args, "--ApiUrl", "--api-url", "--backend-api");
|
||||
apiBaseUrlOverride = GetArgValue(args, "--api-url", "--backend-api");
|
||||
|
||||
var imeLogPathIndex = Array.IndexOf(args, "--ime-log-path");
|
||||
if (imeLogPathIndex >= 0 && imeLogPathIndex + 1 < args.Length)
|
||||
@@ -407,14 +293,14 @@ namespace AutopilotMonitor.Agent
|
||||
if (imeMatchLogIndex >= 0 && imeMatchLogIndex + 1 < args.Length)
|
||||
imeMatchLogPath = args[imeMatchLogIndex + 1];
|
||||
|
||||
var simLogDirIndex = Array.IndexOf(args, "--simulation-log-dir");
|
||||
if (simLogDirIndex >= 0 && simLogDirIndex + 1 < args.Length)
|
||||
simulationLogDir = args[simLogDirIndex + 1];
|
||||
var replayLogDirIndex = Array.IndexOf(args, "--replay-log-dir");
|
||||
if (replayLogDirIndex >= 0 && replayLogDirIndex + 1 < args.Length)
|
||||
replayLogDir = args[replayLogDirIndex + 1];
|
||||
|
||||
var simSpeedIndex = Array.IndexOf(args, "--simulation-speed-factor");
|
||||
if (simSpeedIndex >= 0 && simSpeedIndex + 1 < args.Length)
|
||||
if (double.TryParse(args[simSpeedIndex + 1], out var speed))
|
||||
simulationSpeedFactor = speed;
|
||||
var replaySpeedIndex = Array.IndexOf(args, "--replay-speed-factor");
|
||||
if (replaySpeedIndex >= 0 && replaySpeedIndex + 1 < args.Length)
|
||||
if (double.TryParse(args[replaySpeedIndex + 1], out var speed))
|
||||
replaySpeedFactor = speed;
|
||||
}
|
||||
|
||||
// Defaults
|
||||
@@ -447,8 +333,6 @@ namespace AutopilotMonitor.Agent
|
||||
else
|
||||
{
|
||||
tenantId = GetTenantIdFromRegistry();
|
||||
if (string.IsNullOrEmpty(tenantId))
|
||||
tenantId = "b54dc1af-5320-4f60-b5d4-821e0cf2a359"; // fallback for dev/testing
|
||||
}
|
||||
|
||||
var dataDirectory = Environment.ExpandEnvironmentVariables(Constants.AgentDataDirectory);
|
||||
@@ -469,8 +353,6 @@ namespace AutopilotMonitor.Agent
|
||||
UploadIntervalSeconds = uploadIntervalSeconds,
|
||||
MaxBatchSize = Constants.MaxBatchSize,
|
||||
LogLevel = AgentLogLevel.Info,
|
||||
EnableSimulator = enableSimulator,
|
||||
SimulateFailure = simulateFailure,
|
||||
UseClientCertAuth = !noAuth && useClientCertAuthConfig,
|
||||
ClientCertThumbprint = certThumbprint,
|
||||
CleanupOnExit = cleanupOnExit,
|
||||
@@ -479,8 +361,8 @@ namespace AutopilotMonitor.Agent
|
||||
EnableGeoLocation = !disableGeoLoc && enableGeoLocationConfig,
|
||||
ImeLogPathOverride = imeLogPathOverride,
|
||||
ImeMatchLogPath = imeMatchLogPath,
|
||||
SimulationLogDirectory = simulationLogDir,
|
||||
SimulationSpeedFactor = simulationSpeedFactor,
|
||||
ReplayLogDir = replayLogDir,
|
||||
ReplaySpeedFactor = replaySpeedFactor,
|
||||
KeepLogFile = keepLogFile
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
31
|
||||
32
|
||||
|
||||
Reference in New Issue
Block a user