initial upload
This commit is contained in:
parent
a0aa9cc28e
commit
f857f43df4
553 changed files with 46169 additions and 13 deletions
14
src/Server/Insight.Server/Constants/Appsettings.cs
Normal file
14
src/Server/Insight.Server/Constants/Appsettings.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace Insight.Server
|
||||
{
|
||||
internal static class Appsettings
|
||||
{
|
||||
internal const string AgentServerPort = "agent.server.port";
|
||||
internal const string AgentServerCertificate = "agent.server.certificate";
|
||||
internal const string AgentServerCertificatePassword = "agent.server.certificate.password";
|
||||
internal const string DispatchWebmatic = "dispatch.webmatic";
|
||||
|
||||
internal const string WebServerPort = "web.server.port";
|
||||
internal const string WebServerCertificate = "web.server.certificate";
|
||||
internal const string WebServerCertificatePassword = "web.server.certificate.password";
|
||||
}
|
||||
}
|
||||
53
src/Server/Insight.Server/Extensions/Async.cs
Normal file
53
src/Server/Insight.Server/Extensions/Async.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System.Threading.Tasks.Dataflow;
|
||||
|
||||
namespace Insight.Server.Extensions
|
||||
{
|
||||
public static class Async
|
||||
{
|
||||
public static async Task ParallelForEach<T>(
|
||||
this IAsyncEnumerable<T> source,
|
||||
Func<T, Task> body,
|
||||
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
|
||||
TaskScheduler scheduler = null)
|
||||
{
|
||||
var options = new ExecutionDataflowBlockOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = maxDegreeOfParallelism
|
||||
};
|
||||
|
||||
if (scheduler != null)
|
||||
options.TaskScheduler = scheduler;
|
||||
|
||||
var block = new ActionBlock<T>(body, options);
|
||||
|
||||
await foreach (var item in source)
|
||||
block.Post(item);
|
||||
|
||||
block.Complete();
|
||||
await block.Completion;
|
||||
}
|
||||
|
||||
public static async Task ParallelForEach<T>(
|
||||
this IEnumerable<T> source,
|
||||
Func<T, Task> body,
|
||||
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
|
||||
TaskScheduler scheduler = null)
|
||||
{
|
||||
var options = new ExecutionDataflowBlockOptions
|
||||
{
|
||||
MaxDegreeOfParallelism = maxDegreeOfParallelism
|
||||
};
|
||||
|
||||
if (scheduler != null)
|
||||
options.TaskScheduler = scheduler;
|
||||
|
||||
var block = new ActionBlock<T>(body, options);
|
||||
|
||||
foreach (var item in source)
|
||||
block.Post(item);
|
||||
|
||||
block.Complete();
|
||||
await block.Completion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Insight.Server.Extensions
|
||||
{
|
||||
public static class ConfigurationExtensions
|
||||
{
|
||||
public static IConfigurationBuilder Defaults(this IConfigurationBuilder configuration)
|
||||
{
|
||||
configuration.Sources.Clear();
|
||||
configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
|
||||
return configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/Server/Insight.Server/Insight.Server.csproj
Normal file
71
src/Server/Insight.Server/Insight.Server.csproj
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Product>Insight</Product>
|
||||
<AssemblyName>server</AssemblyName>
|
||||
<AssemblyVersion>2023.9.14.0</AssemblyVersion>
|
||||
<RootNamespace>Insight.Server</RootNamespace>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.Development.json" />
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.Development.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
|
||||
<!--Unix Serilog stuff-->
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
|
||||
<PackageReference Include="Vaitr.Bus" Version="0.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Agent\Insight.Agent.Assets\Insight.Agent.Assets.csproj" />
|
||||
<ProjectReference Include="..\..\Core\Insight.Infrastructure\Insight.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Web\Insight.Web.Assets\Insight.Web.Assets.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="localhost.pfx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Properties\launchSettings.json">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
27
src/Server/Insight.Server/Models/MonitorMessage.cs
Normal file
27
src/Server/Insight.Server/Models/MonitorMessage.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Insight.Agent.Enums;
|
||||
|
||||
namespace Insight.Server.Models
|
||||
{
|
||||
internal class MonitorMessage
|
||||
{
|
||||
public DateTime? Timestamp { get; set; }
|
||||
public string? Community { get; set; }
|
||||
public ApplicationEnum? Application { get; set; }
|
||||
public CategoryEnum? Category { get; set; }
|
||||
public StatusEnum? Status { get; set; }
|
||||
public string? Endpoint { get; set; }
|
||||
public string? Hostname { get; set; }
|
||||
public string? Subject { get; set; }
|
||||
public string? Message { get; set; }
|
||||
|
||||
public enum ApplicationEnum
|
||||
{
|
||||
Unknown = 0,
|
||||
Insight = 1,
|
||||
Acronis = 2,
|
||||
Veeam = 3,
|
||||
QNAP = 4,
|
||||
FreeNas = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/Server/Insight.Server/Network/AgentSession.cs
Normal file
89
src/Server/Insight.Server/Network/AgentSession.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Server.Network.Handlers.Agent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Vaitr.Network;
|
||||
|
||||
namespace Insight.Server.Network
|
||||
{
|
||||
public class AgentSession : TcpSession<IAgentMessage>
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
private readonly AgentHandler _agentHandler;
|
||||
private readonly IEnumerable<IAgentMessageHandler<AgentSession>> _handlers;
|
||||
|
||||
public AgentSession(AgentHandler agentHandler, IEnumerable<IAgentMessageHandler<AgentSession>> handlers, ISerializer<IAgentMessage> serializer, ILogger<AgentSession> logger) : base(serializer, logger)
|
||||
{
|
||||
_agentHandler = agentHandler;
|
||||
_handlers = handlers;
|
||||
}
|
||||
|
||||
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Agent ({ep?}) connected", RemoteEndPoint);
|
||||
|
||||
var request = new AuthenticationRequest();
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
await handler.HandleAsync(this, request, cancellationToken);
|
||||
}
|
||||
|
||||
await _agentHandler.ConnectedAsync(this, default);
|
||||
await _agentHandler.StatisticUpdateAsync(this, default);
|
||||
|
||||
_logger.LogInformation("Agent ({ep?}) ID: {id}", RemoteEndPoint, Id);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Agent ({ep?}) disconnected", RemoteEndPoint);
|
||||
|
||||
await _agentHandler.StatisticUpdateAsync(this, default);
|
||||
await _agentHandler.DisconnectedAsync(this, default);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnSentAsync(IPacketContext<IAgentMessage> context, CancellationToken cancellationToken)
|
||||
{
|
||||
await base.OnSentAsync(context, cancellationToken);
|
||||
|
||||
await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnReceivedAsync(IPacketContext<IAgentMessage> context, CancellationToken cancellationToken)
|
||||
{
|
||||
await base.OnReceivedAsync(context, cancellationToken);
|
||||
|
||||
if (Id is null && context.Packet is not Authentication) return;
|
||||
|
||||
await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
await handler.HandleAsync(this, context.Packet, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Agent ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
|
||||
|
||||
//await _mediator.Send(new AgentLog(new AgentLogEntity
|
||||
//{
|
||||
// Category = CategoryEnum.Network.ToString(),
|
||||
// Status = StatusEnum.Error.ToString(),
|
||||
// Message = e.StackTrace
|
||||
//}, this), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Agent ({ep?}) Heartbeat", RemoteEndPoint);
|
||||
|
||||
await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
162
src/Server/Insight.Server/Network/Handlers/Agent/AgentHandler.cs
Normal file
162
src/Server/Insight.Server/Network/Handlers/Agent/AgentHandler.cs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
using Insight.Agent.Enums;
|
||||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class AgentHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly ILogger<AgentHandler> _logger;
|
||||
|
||||
public AgentHandler(IMongoDatabase database, ILogger<AgentHandler> logger)
|
||||
{
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is AuthenticationRequest authenticationRequest)
|
||||
{
|
||||
await AuthenticationRequestAsync(sender, authenticationRequest, cancellationToken);
|
||||
}
|
||||
|
||||
if (message is Authentication authentication)
|
||||
{
|
||||
await AuthenticationAsync(sender, authentication, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask AuthenticationRequestAsync(AgentSession session, AuthenticationRequest message, CancellationToken cancellationToken)
|
||||
{
|
||||
await session.SendAsync(message, cancellationToken);
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
if (session.Id is not null)
|
||||
{
|
||||
_logger.LogInformation("Agent ({ep?}) authenticated", session.RemoteEndPoint);
|
||||
return;
|
||||
}
|
||||
|
||||
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_logger.LogError("Authentication Timeout ({ep?})", session.RemoteEndPoint);
|
||||
session.Disconnect();
|
||||
}
|
||||
|
||||
private async ValueTask AuthenticationAsync(AgentSession session, Authentication authentication, CancellationToken cancellationToken)
|
||||
{
|
||||
if (authentication is null)
|
||||
{
|
||||
throw new NullReferenceException($"authentication failed (empty response)");
|
||||
}
|
||||
|
||||
if (authentication.Serial == default)
|
||||
{
|
||||
throw new InvalidDataException($"authentication failed ({nameof(authentication.Serial)})");
|
||||
}
|
||||
|
||||
//if (authentication.Version == default || authentication.Version < Domain.Constants.Configuration.Version)
|
||||
//{
|
||||
// throw new InvalidDataException($"authentication failed ({nameof(authentication.Version)})");
|
||||
//}
|
||||
|
||||
// upsert agent
|
||||
await _database.Agent().UpdateOneAsync(Builders<AgentEntity>
|
||||
.Filter
|
||||
.Eq(p => p.Serial, authentication.Serial.ToString()), Builders<AgentEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, DateTime.Now)
|
||||
.SetOnInsert(p => p.Serial, authentication.Serial.ToString())
|
||||
.Set(p => p.Update, DateTime.Now)
|
||||
.Set(p => p.Connected, DateTime.Now)
|
||||
.Set(p => p.Version, authentication.Version)
|
||||
.Set(p => p.Endpoint, session.RemoteEndPoint?.ToString())
|
||||
.Set(p => p.Hostname, authentication.Hostname), new UpdateOptions
|
||||
{
|
||||
IsUpsert = true
|
||||
}, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// get agent
|
||||
var agentEntity = await _database.Agent()
|
||||
.Find(Builders<AgentEntity>
|
||||
.Filter
|
||||
.Eq(p => p.Serial, authentication.Serial.ToString()))
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// set session id
|
||||
session.Id = agentEntity.Id;
|
||||
}
|
||||
|
||||
public async ValueTask ConnectedAsync(AgentSession session, CancellationToken cancellationToken)
|
||||
{
|
||||
if (session.Id is null) return;
|
||||
|
||||
// insert connect log
|
||||
await _database.AgentLog()
|
||||
.InsertOneAsync(new AgentLogEntity
|
||||
{
|
||||
Insert = DateTime.Now,
|
||||
Agent = session.Id,
|
||||
Category = CategoryEnum.Network.ToString(),
|
||||
Status = StatusEnum.Information.ToString(),
|
||||
Message = $"Connected ({session.RemoteEndPoint})",
|
||||
Timestamp = DateTime.Now
|
||||
}, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask DisconnectedAsync(AgentSession session, CancellationToken cancellationToken)
|
||||
{
|
||||
if (session.Id is null) return;
|
||||
|
||||
// insert disconnect log
|
||||
await _database.AgentLog()
|
||||
.InsertOneAsync(new AgentLogEntity
|
||||
{
|
||||
Insert = DateTime.Now,
|
||||
Agent = session.Id,
|
||||
Category = CategoryEnum.Network.ToString(),
|
||||
Status = StatusEnum.Information.ToString(),
|
||||
Message = $"Disconnected ({session.RemoteEndPoint})",
|
||||
Timestamp = DateTime.Now
|
||||
}, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask StatisticUpdateAsync(AgentSession session, CancellationToken cancellationToken)
|
||||
{
|
||||
if (session.Id is null) return;
|
||||
|
||||
// update agents stats
|
||||
await _database.Agent().UpdateOneAsync(Builders<AgentEntity>
|
||||
.Filter
|
||||
.Eq(p => p.Id, session.Id), Builders<AgentEntity>
|
||||
.Update
|
||||
.Set(p => p.Update, DateTime.Now)
|
||||
.Set(p => p.Activity, session.Activity)
|
||||
.Set(p => p.SentBytes, session.SentBytes)
|
||||
.Set(p => p.ReceivedBytes, session.ReceivedBytes)
|
||||
.Set(p => p.SentPackets, session.SentPackets)
|
||||
.Set(p => p.ReceivedPackets, session.ReceivedPackets), null, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask LogAsync(AgentSession session, AgentLogEntity log, CancellationToken cancellationToken)
|
||||
{
|
||||
if (session.Id is null) return;
|
||||
|
||||
await _database.AgentLog()
|
||||
.InsertOneAsync(log, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Web.Messages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using Vaitr.Network;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class ConsoleHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly ISessionPool<WebSession, IWebMessage> _webPool;
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly ILogger<ConsoleHandler> _logger;
|
||||
|
||||
public ConsoleHandler(
|
||||
ISessionPool<WebSession, IWebMessage> webPool,
|
||||
IMongoDatabase database,
|
||||
ILogger<ConsoleHandler> logger)
|
||||
{
|
||||
_webPool = webPool;
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is ConsoleQuery consoleQuery)
|
||||
{
|
||||
await OnConsoleQueryAsync(sender, consoleQuery, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnConsoleQueryAsync(AgentSession session, ConsoleQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
// check if web online
|
||||
if (_webPool.FirstOrDefault().Value is not WebSession web) return;
|
||||
|
||||
await web.SendAsync(new ConsoleQueryProxy
|
||||
{
|
||||
Id = query.Id,
|
||||
HostId = query.HostId,
|
||||
Query = query.Query,
|
||||
Data = query.Data,
|
||||
Errors = query.Errors,
|
||||
HadErrors = query.HadErrors
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
145
src/Server/Insight.Server/Network/Handlers/Agent/DriveHandler.cs
Normal file
145
src/Server/Insight.Server/Network/Handlers/Agent/DriveHandler.cs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class DriveHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public DriveHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is DriveList drives)
|
||||
{
|
||||
await OnDrivesAsync(sender, drives, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnDrivesAsync(AgentSession session, List<Drive> drives, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var driveBulk = new List<WriteModel<HostDriveEntity>>();
|
||||
|
||||
if (drives is not null && drives.Any())
|
||||
{
|
||||
foreach (var drive in drives)
|
||||
{
|
||||
var driveFilter = Builders<HostDriveEntity>.Filter.And(new List<FilterDefinition<HostDriveEntity>>
|
||||
{
|
||||
Builders<HostDriveEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostDriveEntity>.Filter.Eq(x => x.Index, drive.Index)
|
||||
});
|
||||
|
||||
var driveUpdate = Builders<HostDriveEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Index, drive.Index)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Company, drive.Manufacturer)
|
||||
.Set(p => p.Name, drive.Name)
|
||||
.Set(p => p.Size, drive.Size)
|
||||
.Set(p => p.Type, drive.InterfaceType)
|
||||
.Set(p => p.Serial, drive.SerialNumber)
|
||||
.Set(p => p.Firmware, drive.FirmwareRevision)
|
||||
.Set(p => p.Status, drive.Status)
|
||||
.Set(p => p.Pnp, drive.PNPDeviceID);
|
||||
|
||||
driveBulk.Add(new UpdateOneModel<HostDriveEntity>(driveFilter, driveUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
driveBulk.Add(new DeleteManyModel<HostDriveEntity>(Builders<HostDriveEntity>.Filter.And(new List<FilterDefinition<HostDriveEntity>>
|
||||
{
|
||||
Builders<HostDriveEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostDriveEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var driveResult = await _database.HostDrive().BulkWriteAsync(driveBulk, cancellationToken: cancellationToken);
|
||||
|
||||
// volumes
|
||||
|
||||
var volumeBulk = new List<WriteModel<HostVolumeEntity>>();
|
||||
|
||||
if (drives is not null && drives.Any())
|
||||
{
|
||||
foreach (var drive in drives)
|
||||
{
|
||||
var driveId = await _database.HostDrive()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Index == drive.Index)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (drive.Volumes is not null && drive.Volumes.Any())
|
||||
{
|
||||
foreach (var volume in drive.Volumes)
|
||||
{
|
||||
var volumeFilter = Builders<HostVolumeEntity>.Filter.And(new List<FilterDefinition<HostVolumeEntity>>
|
||||
{
|
||||
Builders<HostVolumeEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostVolumeEntity>.Filter.Eq(x => x.Drive, driveId),
|
||||
Builders<HostVolumeEntity>.Filter.Eq(x => x.Index, volume.Index)
|
||||
});
|
||||
|
||||
var volumeUpdate = Builders<HostVolumeEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Drive, driveId)
|
||||
.SetOnInsert(p => p.Index, volume.Index)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Name, volume.Name)
|
||||
.Set(p => p.Label, volume.Id)
|
||||
.Set(p => p.Serial, volume.SerialNumber)
|
||||
.Set(p => p.Size, volume.Size)
|
||||
.Set(p => p.FreeSpace, volume.FreeSpace)
|
||||
.Set(p => p.Type, volume.Type)
|
||||
.Set(p => p.FileSystem, volume.FileSystem)
|
||||
.Set(p => p.Compressed, volume.Compressed)
|
||||
.Set(p => p.Bootable, volume.Bootable)
|
||||
.Set(p => p.Primary, volume.PrimaryPartition)
|
||||
.Set(p => p.Boot, volume.Bootable)
|
||||
.Set(p => p.BlockSize, volume.BlockSize)
|
||||
.Set(p => p.Blocks, volume.NumberOfBlocks)
|
||||
.Set(p => p.StartingOffset, volume.StartingOffset)
|
||||
.Set(p => p.Provider, volume.ProviderName);
|
||||
|
||||
volumeBulk.Add(new UpdateOneModel<HostVolumeEntity>(volumeFilter, volumeUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volumeBulk.Add(new DeleteManyModel<HostVolumeEntity>(Builders<HostVolumeEntity>.Filter.And(new List<FilterDefinition<HostVolumeEntity>>
|
||||
{
|
||||
Builders<HostVolumeEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostVolumeEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var volumeResult = await _database.HostVolume().BulkWriteAsync(volumeBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
266
src/Server/Insight.Server/Network/Handlers/Agent/EventHandler.cs
Normal file
266
src/Server/Insight.Server/Network/Handlers/Agent/EventHandler.cs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
using Insight.Agent.Enums;
|
||||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using static Insight.Agent.Messages.Event;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class EventHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly ILogger<EventHandler> _logger;
|
||||
|
||||
public EventHandler(IMongoDatabase database, ILogger<EventHandler> logger)
|
||||
{
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is Event @event)
|
||||
{
|
||||
await OnEventAsync(sender, @event, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnEventAsync(AgentSession session, Event @event, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
if (FilterEventId(@event)) return;
|
||||
|
||||
var hostLog = await InsertHostLogAsync(hostEntity, @event, cancellationToken);
|
||||
|
||||
if (hostLog is null || FilterMonitoringHostLog(hostLog)) return;
|
||||
|
||||
await _database.HostLogMonitoring()
|
||||
.InsertOneAsync(new HostLogMonitoringEntity
|
||||
{
|
||||
Host = hostEntity.Id,
|
||||
Insert = hostLog.Insert,
|
||||
Timestamp = hostLog.Timestamp,
|
||||
Category = hostLog.Category,
|
||||
Status = hostLog.Status,
|
||||
Message = hostLog.Message,
|
||||
Dispatch = DispatchEnum.Pending.ToString()
|
||||
}, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
private async ValueTask<AgentLogEntity?> InsertAgentLogAsync(AgentSession session, Event @event, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent()
|
||||
.Aggregate()
|
||||
.Match(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id))
|
||||
.Lookup<AgentEntity, HostEntity, AgentEntity>(_database.Host(), p => p.Serial, p => p.Agent, p => p.Hosts)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (agentEntity is null) return null;
|
||||
|
||||
StatusEnum? status = @event.Status switch
|
||||
{
|
||||
StatusType.Information => StatusEnum.Information,
|
||||
StatusType.Warning => StatusEnum.Warning,
|
||||
StatusType.Error => StatusEnum.Error,
|
||||
_ => null
|
||||
};
|
||||
|
||||
CategoryEnum? category = @event.Category.ToLower() switch
|
||||
{
|
||||
"network" => CategoryEnum.Network,
|
||||
"application" => CategoryEnum.Application,
|
||||
"security" => CategoryEnum.Security,
|
||||
"system" => CategoryEnum.System,
|
||||
_ => null
|
||||
};
|
||||
|
||||
var date = DateTime.Now;
|
||||
|
||||
var log = new AgentLogEntity
|
||||
{
|
||||
Insert = date,
|
||||
Agent = agentEntity.Id,
|
||||
Timestamp = @event.Timestamp,
|
||||
EventId = @event.EventId.ToString(),
|
||||
Source = @event.Source,
|
||||
Status = status.ToString(),
|
||||
Category = category.ToString(),
|
||||
Message = @event.Message
|
||||
};
|
||||
|
||||
await _database.AgentLog().InsertOneAsync(log, cancellationToken: cancellationToken);
|
||||
return log;
|
||||
}
|
||||
|
||||
private async ValueTask<HostLogEntity?> InsertHostLogAsync(HostEntity hostEntity, Event @event, CancellationToken cancellationToken)
|
||||
{
|
||||
StatusEnum? status = @event.Status switch
|
||||
{
|
||||
StatusType.Information => StatusEnum.Information,
|
||||
StatusType.Warning => StatusEnum.Warning,
|
||||
StatusType.Error => StatusEnum.Error,
|
||||
StatusType.Critical => StatusEnum.Error,
|
||||
StatusType.Unknown => null,
|
||||
_ => null
|
||||
};
|
||||
|
||||
CategoryEnum? category = null;
|
||||
switch (@event.Category)
|
||||
{
|
||||
case var _ when @event.Category.Contains("network", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Network;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("application", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Application;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("security", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Security;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("system", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.System;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("printservice", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Printer;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("taskscheduler", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Task;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("terminalservices", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.RDP;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("smbclient", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Network;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("smbserver", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.Network;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("storagespaces", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.System;
|
||||
break;
|
||||
|
||||
case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase):
|
||||
category = CategoryEnum.System;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var date = DateTime.Now;
|
||||
|
||||
var log = new HostLogEntity
|
||||
{
|
||||
Insert = date,
|
||||
Host = hostEntity.Id,
|
||||
Timestamp = @event.Timestamp,
|
||||
EventId = @event.EventId.ToString(),
|
||||
Status = status.ToString(),
|
||||
Source = @event.Source,
|
||||
Category = category?.ToString(),
|
||||
Message = @event.Message
|
||||
};
|
||||
|
||||
await _database.HostLog().InsertOneAsync(log, cancellationToken: cancellationToken);
|
||||
return log;
|
||||
}
|
||||
|
||||
private bool FilterEventId(Event @event)
|
||||
{
|
||||
var filter = new List<int>
|
||||
{
|
||||
0,
|
||||
3,
|
||||
4,
|
||||
16,
|
||||
37,
|
||||
900,
|
||||
902,
|
||||
903,
|
||||
1001,
|
||||
1003,
|
||||
1008,
|
||||
1023,
|
||||
1066,
|
||||
4624,
|
||||
4625,
|
||||
4634,
|
||||
4648,
|
||||
4672,
|
||||
4776,
|
||||
4798,
|
||||
4799,
|
||||
5058,
|
||||
5059,
|
||||
5061,
|
||||
5379,
|
||||
5612,
|
||||
5781,
|
||||
//7036,
|
||||
8014,
|
||||
8016,
|
||||
8019,
|
||||
8194,
|
||||
8224,
|
||||
9009,
|
||||
9027,
|
||||
10001,
|
||||
10016,
|
||||
16384,
|
||||
16394,
|
||||
36874,
|
||||
36888,
|
||||
};
|
||||
|
||||
if (filter.Any(p => p == @event.EventId)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool FilterMonitoringHostLog(HostLogEntity hostLog)
|
||||
{
|
||||
//_logger.LogDebug($"try filter event: {hostLog.Category}.{hostLog.Source}.{hostLog.Status}");
|
||||
|
||||
if (Enum.TryParse(hostLog.Status, out StatusType status) is false) return true;
|
||||
|
||||
if (hostLog.Category == CategoryEnum.System.ToString())
|
||||
{
|
||||
if (hostLog.Source == "Service Control Manager" && status < StatusType.Warning) return true;
|
||||
}
|
||||
|
||||
if (hostLog.Category == CategoryEnum.Task.ToString())
|
||||
{
|
||||
if (status < StatusType.Error) return true;
|
||||
}
|
||||
|
||||
// skip rdp infos
|
||||
if (hostLog.Category == CategoryEnum.RDP.ToString())
|
||||
{
|
||||
if (hostLog.EventId == "261") return true;
|
||||
}
|
||||
|
||||
// skip smbclient (veeam errors)
|
||||
if (hostLog.Category == CategoryEnum.Security.ToString())
|
||||
{
|
||||
if (hostLog.Source == "Microsoft-Windows-SMBClient") return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class InterfaceHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public InterfaceHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is InterfaceList interfaces)
|
||||
{
|
||||
await OnInterfacesAsync(sender, interfaces, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnInterfacesAsync(AgentSession session, List<Interface> interfaces, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
// interfaces
|
||||
|
||||
if (interfaces is not null && interfaces.Any())
|
||||
{
|
||||
var interfaceBulk = new List<WriteModel<HostInterfaceEntity>>();
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var interfaceFilter = Builders<HostInterfaceEntity>.Filter.And(new List<FilterDefinition<HostInterfaceEntity>>
|
||||
{
|
||||
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Index, @interface.Index)
|
||||
});
|
||||
|
||||
var interfaceUpdate = Builders<HostInterfaceEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Index, @interface.Index)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Mac, @interface?.Mac)
|
||||
.Set(p => p.Name, @interface?.Name)
|
||||
.Set(p => p.Description, @interface?.Description)
|
||||
.Set(p => p.Physical, @interface?.Physical)
|
||||
.Set(p => p.Status, @interface?.Status?.ToString())
|
||||
.Set(p => p.Suffix, @interface?.Suffix)
|
||||
.Set(p => p.Speed, @interface?.Speed)
|
||||
.Set(p => p.Ipv4Mtu, @interface?.Ipv4Mtu)
|
||||
.Set(p => p.Ipv4Dhcp, @interface?.Ipv4Dhcp)
|
||||
|
||||
.Set(p => p.Ipv4Forwarding, @interface?.Ipv4Forwarding)
|
||||
.Set(p => p.Ipv6Mtu, @interface?.Ipv6Mtu)
|
||||
.Set(p => p.Sent, @interface?.Sent)
|
||||
.Set(p => p.Received, @interface?.Received)
|
||||
.Set(p => p.IncomingPacketsDiscarded, @interface?.IncomingPacketsDiscarded)
|
||||
.Set(p => p.IncomingPacketsWithErrors, @interface?.IncomingPacketsWithErrors)
|
||||
.Set(p => p.IncomingUnknownProtocolPackets, @interface?.IncomingUnknownProtocolPackets)
|
||||
.Set(p => p.OutgoingPacketsDiscarded, @interface?.OutgoingPacketsDiscarded)
|
||||
.Set(p => p.OutgoingPacketsWithErrors, @interface?.OutgoingPacketsWithErrors);
|
||||
|
||||
interfaceBulk.Add(new UpdateOneModel<HostInterfaceEntity>(interfaceFilter, interfaceUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
interfaceBulk.Add(new DeleteManyModel<HostInterfaceEntity>(Builders<HostInterfaceEntity>.Filter.And(new List<FilterDefinition<HostInterfaceEntity>>
|
||||
{
|
||||
Builders<HostInterfaceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var interfaceResult = await _database.HostInterface().BulkWriteAsync(interfaceBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// addresses
|
||||
|
||||
if (interfaces is not null && interfaces.Any())
|
||||
{
|
||||
var addressBulk = new List<WriteModel<HostInterfaceAddressEntity>>();
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var interfaceId = await _database.HostInterface()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (@interface.Addresses is not null && @interface.Addresses.Any())
|
||||
{
|
||||
foreach (var address in @interface.Addresses)
|
||||
{
|
||||
var addressFilter = Builders<HostInterfaceAddressEntity>.Filter.And(new List<FilterDefinition<HostInterfaceAddressEntity>>
|
||||
{
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Interface, interfaceId),
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Address, address?.IpAddress?.Address),
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Mask, address?.Ipv4Mask?.Address)
|
||||
});
|
||||
|
||||
var addressUpdate = Builders<HostInterfaceAddressEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Interface, interfaceId)
|
||||
.SetOnInsert(p => p.Address, address?.IpAddress?.Address)
|
||||
.SetOnInsert(p => p.Mask, address?.Ipv4Mask?.Address)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch);
|
||||
|
||||
addressBulk.Add(new UpdateOneModel<HostInterfaceAddressEntity>(addressFilter, addressUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addressBulk.Add(new DeleteManyModel<HostInterfaceAddressEntity>(Builders<HostInterfaceAddressEntity>.Filter.And(new List<FilterDefinition<HostInterfaceAddressEntity>>
|
||||
{
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceAddressEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var addressResult = await _database.HostInterfaceAddress().BulkWriteAsync(addressBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// gateways
|
||||
|
||||
if (interfaces is not null && interfaces.Any())
|
||||
{
|
||||
var gatewayBulk = new List<WriteModel<HostInterfaceGatewayEntity>>();
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var interfaceId = await _database.HostInterface()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (@interface.Gateways is not null && @interface.Gateways.Any())
|
||||
{
|
||||
foreach (var gateway in @interface.Gateways)
|
||||
{
|
||||
var gatewayFilter = Builders<HostInterfaceGatewayEntity>.Filter.And(new List<FilterDefinition<HostInterfaceGatewayEntity>>
|
||||
{
|
||||
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Interface, interfaceId),
|
||||
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Address, gateway?.Address)
|
||||
});
|
||||
|
||||
var gatewayUpdate = Builders<HostInterfaceGatewayEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Interface, interfaceId)
|
||||
.SetOnInsert(p => p.Address, gateway?.Address)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch);
|
||||
|
||||
gatewayBulk.Add(new UpdateOneModel<HostInterfaceGatewayEntity>(gatewayFilter, gatewayUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gatewayBulk.Add(new DeleteManyModel<HostInterfaceGatewayEntity>(Builders<HostInterfaceGatewayEntity>.Filter.And(new List<FilterDefinition<HostInterfaceGatewayEntity>>
|
||||
{
|
||||
Builders<HostInterfaceGatewayEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceGatewayEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var gatewayResult = await _database.HostInterfaceGateway().BulkWriteAsync(gatewayBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// nameservers
|
||||
|
||||
if (interfaces is not null && interfaces.Any())
|
||||
{
|
||||
var nameserverBulk = new List<WriteModel<HostInterfaceNameserverEntity>>();
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var interfaceId = await _database.HostInterface()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (@interface.Dns is not null && @interface.Dns.Any())
|
||||
{
|
||||
foreach (var nameserver in @interface.Dns)
|
||||
{
|
||||
var nameserverFilter = Builders<HostInterfaceNameserverEntity>.Filter.And(new List<FilterDefinition<HostInterfaceNameserverEntity>>
|
||||
{
|
||||
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Interface, interfaceId),
|
||||
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Address, nameserver?.Address)
|
||||
});
|
||||
|
||||
var nameserverUpdate = Builders<HostInterfaceNameserverEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Interface, interfaceId)
|
||||
.SetOnInsert(p => p.Address, nameserver?.Address)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch);
|
||||
|
||||
nameserverBulk.Add(new UpdateOneModel<HostInterfaceNameserverEntity>(nameserverFilter, nameserverUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nameserverBulk.Add(new DeleteManyModel<HostInterfaceNameserverEntity>(Builders<HostInterfaceNameserverEntity>.Filter.And(new List<FilterDefinition<HostInterfaceNameserverEntity>>
|
||||
{
|
||||
Builders<HostInterfaceNameserverEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceNameserverEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var nameserverResult = await _database.HostInterfaceNameserver().BulkWriteAsync(nameserverBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// routes
|
||||
|
||||
if (interfaces is not null && interfaces.Any())
|
||||
{
|
||||
var routeBulk = new List<WriteModel<HostInterfaceRouteEntity>>();
|
||||
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
var interfaceId = await _database.HostInterface()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (@interface.Routes is not null && @interface.Routes.Any())
|
||||
{
|
||||
foreach (var route in @interface.Routes)
|
||||
{
|
||||
var routeFilter = Builders<HostInterfaceRouteEntity>.Filter.And(new List<FilterDefinition<HostInterfaceRouteEntity>>
|
||||
{
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Interface, interfaceId),
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Destination, route?.Destination?.Address),
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Gateway, route?.Gateway?.Address),
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Mask, route?.Mask),
|
||||
});
|
||||
|
||||
var routeUpdate = Builders<HostInterfaceRouteEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Interface, interfaceId)
|
||||
.SetOnInsert(p => p.Destination, route?.Destination?.Address)
|
||||
.SetOnInsert(p => p.Gateway, route?.Gateway?.Address)
|
||||
.SetOnInsert(p => p.Mask, route?.Mask)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Metric, route?.Metric);
|
||||
|
||||
routeBulk.Add(new UpdateOneModel<HostInterfaceRouteEntity>(routeFilter, routeUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routeBulk.Add(new DeleteManyModel<HostInterfaceRouteEntity>(Builders<HostInterfaceRouteEntity>.Filter.And(new List<FilterDefinition<HostInterfaceRouteEntity>>
|
||||
{
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostInterfaceRouteEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var routeResult = await _database.HostInterfaceRoute().BulkWriteAsync(routeBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class MainboardHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public MainboardHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is Mainboard mainboard)
|
||||
{
|
||||
await OnMainboardAsync(sender, mainboard, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnMainboardAsync(AgentSession session, Mainboard mainboard, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var date = DateTime.Now;
|
||||
|
||||
await _database.HostMainboard().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostMainboardEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Name, mainboard?.Manufacturer)
|
||||
.Set(p => p.Name, mainboard?.Model)
|
||||
.Set(p => p.Serial, mainboard?.Serial)
|
||||
.Set(p => p.Bios, mainboard?.BiosManufacturer)
|
||||
.Set(p => p.Version, mainboard?.BiosVersion)
|
||||
.Set(p => p.Date, mainboard?.BiosDate), new UpdateOptions
|
||||
{
|
||||
IsUpsert = true
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class MemoryHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public MemoryHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is MemoryList memory)
|
||||
{
|
||||
await OnMemoryAsync(sender, memory, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnMemoryAsync(AgentSession session, List<Memory> memory, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostMemoryEntity>>();
|
||||
|
||||
if (memory is not null && memory.Any())
|
||||
{
|
||||
foreach (var mem in memory)
|
||||
{
|
||||
var filterDefinition = Builders<HostMemoryEntity>.Filter.And(new List<FilterDefinition<HostMemoryEntity>>
|
||||
{
|
||||
Builders<HostMemoryEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostMemoryEntity>.Filter.Eq(x => x.Index, mem.Index)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostMemoryEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Index, mem.Index)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Company, mem.Manufacturer)
|
||||
.Set(p => p.Name, mem.Model)
|
||||
.Set(p => p.Tag, mem.Tag)
|
||||
.Set(p => p.Location, mem.Location)
|
||||
.Set(p => p.Serial, mem.Serial)
|
||||
.Set(p => p.Capacity, mem.Capacity)
|
||||
.Set(p => p.Clock, mem.Speed)
|
||||
.Set(p => p.CurrentClock, mem.ConfiguredSpeed)
|
||||
.Set(p => p.Voltage, mem.Voltage)
|
||||
.Set(p => p.CurrentVoltage, mem.ConfiguredVoltage);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostMemoryEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostMemoryEntity>(Builders<HostMemoryEntity>.Filter.And(new List<FilterDefinition<HostMemoryEntity>>
|
||||
{
|
||||
Builders<HostMemoryEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostMemoryEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostMemory().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class OperationSystemHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public OperationSystemHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is OperationSystem os)
|
||||
{
|
||||
await OnOperationSystemAsync(sender, os, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnOperationSystemAsync(AgentSession session, OperationSystem operatingSystem, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var date = DateTime.Now;
|
||||
|
||||
await _database.HostOs().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostOsEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Name, operatingSystem.Name)
|
||||
.Set(p => p.Version, operatingSystem.Version)
|
||||
.Set(p => p.Architecture, operatingSystem.Architecture.ToString())
|
||||
.Set(p => p.SerialNumber, operatingSystem.SerialNumber)
|
||||
.Set(p => p.Virtual, operatingSystem.Virtual)
|
||||
.Set(p => p.Installed, operatingSystem.InstallDate), new UpdateOptions
|
||||
{
|
||||
IsUpsert = true
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class PrinterHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public PrinterHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is PrinterList printers)
|
||||
{
|
||||
await OnPrintersAsync(sender, printers, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnPrintersAsync(AgentSession session, List<Printer> printers, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostPrinterEntity>>();
|
||||
|
||||
if (printers is not null && printers.Any())
|
||||
{
|
||||
foreach (var printer in printers)
|
||||
{
|
||||
var filterDefinition = Builders<HostPrinterEntity>.Filter.And(new List<FilterDefinition<HostPrinterEntity>>
|
||||
{
|
||||
Builders<HostPrinterEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostPrinterEntity>.Filter.Eq(x => x.Name, printer.Name)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostPrinterEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Name, printer.Name)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Port, printer.Port)
|
||||
.Set(p => p.Location, printer.Location)
|
||||
.Set(p => p.Comment, printer.Comment);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostPrinterEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostPrinterEntity>(Builders<HostPrinterEntity>.Filter.And(new List<FilterDefinition<HostPrinterEntity>>
|
||||
{
|
||||
Builders<HostPrinterEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostPrinterEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostPrinter().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class ProcessorHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public ProcessorHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is ProcessorList processors)
|
||||
{
|
||||
await OnProcessorsAsync(sender, processors, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnProcessorsAsync(AgentSession session, List<Processor> processors, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostProcessorEntity>>();
|
||||
|
||||
if (processors is not null && processors.Any())
|
||||
{
|
||||
foreach (var processor in processors)
|
||||
{
|
||||
var filterDefinition = Builders<HostProcessorEntity>.Filter.And(new List<FilterDefinition<HostProcessorEntity>>
|
||||
{
|
||||
Builders<HostProcessorEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostProcessorEntity>.Filter.Eq(x => x.Index, processor.Index)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostProcessorEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Index, processor.Index)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Company, processor.Manufacturer)
|
||||
.Set(p => p.Name, processor.Name)
|
||||
.Set(p => p.Socket, processor.Socket)
|
||||
.Set(p => p.Serial, processor.SerialNumber)
|
||||
.Set(p => p.Version, processor.Version)
|
||||
.Set(p => p.Cores, processor.Cores)
|
||||
.Set(p => p.LogicalCores, processor.LogicalCores)
|
||||
.Set(p => p.Clock, processor.MaxSpeed)
|
||||
.Set(p => p.CurrentClock, processor.CurrentSpeed)
|
||||
.Set(p => p.L1Size, processor.L1Size)
|
||||
.Set(p => p.L2Size, processor.L2Size)
|
||||
.Set(p => p.L3Size, processor.L3Size)
|
||||
.Set(p => p.Virtualization, processor.Virtualization)
|
||||
.Set(p => p.PNP, processor.DeviceId);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostProcessorEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostProcessorEntity>(Builders<HostProcessorEntity>.Filter.And(new List<FilterDefinition<HostProcessorEntity>>
|
||||
{
|
||||
Builders<HostProcessorEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostProcessorEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostProcessor().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class ServiceHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public ServiceHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is ServiceList services)
|
||||
{
|
||||
await OnServicesAsync(sender, services, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnServicesAsync(AgentSession session, List<Service> services, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostServiceEntity>>();
|
||||
|
||||
if (services is not null && services.Any())
|
||||
{
|
||||
foreach (var service in services)
|
||||
{
|
||||
var filterDefinition = Builders<HostServiceEntity>.Filter.And(new List<FilterDefinition<HostServiceEntity>>
|
||||
{
|
||||
Builders<HostServiceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostServiceEntity>.Filter.Eq(x => x.Name, service.Name)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostServiceEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Name, service.Name)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.DisplayName, service.Display)
|
||||
.Set(p => p.Description, service.Description)
|
||||
.Set(p => p.StartMode, service.StartMode.ToString())
|
||||
.Set(p => p.State, service.Status.ToString())
|
||||
.Set(p => p.ProcessId, service.ProcessId)
|
||||
.Set(p => p.Delay, service.Delay)
|
||||
.Set(p => p.Path, service.PathName)
|
||||
.Set(p => p.Account, service.Account);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostServiceEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostServiceEntity>(Builders<HostServiceEntity>.Filter.And(new List<FilterDefinition<HostServiceEntity>>
|
||||
{
|
||||
Builders<HostServiceEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostServiceEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostService().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class SessionHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public SessionHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is SessionList sessions)
|
||||
{
|
||||
await OnSessionsAsync(sender, sessions, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnSessionsAsync(AgentSession session, List<Session> sessions, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostSessionEntity>>();
|
||||
|
||||
if (sessions is not null && sessions.Any())
|
||||
{
|
||||
foreach (var sess in sessions)
|
||||
{
|
||||
var filterDefinition = Builders<HostSessionEntity>.Filter.And(new List<FilterDefinition<HostSessionEntity>>
|
||||
{
|
||||
Builders<HostSessionEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostSessionEntity>.Filter.Eq(x => x.Sid, sess.Sid)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostSessionEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Sid, sess.Sid)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.User, sess.User)
|
||||
.Set(p => p.Remote, sess.Remote)
|
||||
.Set(p => p.Type, sess.Type)
|
||||
.Set(p => p.State, sess.Status);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostSessionEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostSessionEntity>(Builders<HostSessionEntity>.Filter.And(new List<FilterDefinition<HostSessionEntity>>
|
||||
{
|
||||
Builders<HostSessionEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostSessionEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostSession().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class SoftwareHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public SoftwareHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is ApplicationList applications)
|
||||
{
|
||||
await OnApplicationsAsync(sender, applications, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnApplicationsAsync(AgentSession session, List<Application> applications, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostApplicationEntity>>();
|
||||
|
||||
if (applications is not null && applications.Any())
|
||||
{
|
||||
foreach (var app in applications)
|
||||
{
|
||||
var filterDefinition = Builders<HostApplicationEntity>.Filter.And(new List<FilterDefinition<HostApplicationEntity>>
|
||||
{
|
||||
Builders<HostApplicationEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostApplicationEntity>.Filter.Eq(x => x.Name, app.Name),
|
||||
Builders<HostApplicationEntity>.Filter.Eq(x => x.Architecture, app.Architecture?.ToString())
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostApplicationEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Name, app.Name)
|
||||
.SetOnInsert(p => p.Architecture, app.Architecture?.ToString())
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Company, app.Publisher)
|
||||
.Set(p => p.Version, app.Version)
|
||||
.Set(p => p.InstallDate, app.InstallDate);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostApplicationEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostApplicationEntity>(Builders<HostApplicationEntity>.Filter.And(new List<FilterDefinition<HostApplicationEntity>>
|
||||
{
|
||||
Builders<HostApplicationEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostApplicationEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostApplication().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class StoragePoolHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public StoragePoolHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is StoragePoolList storagePools)
|
||||
{
|
||||
await OnStoragePoolsAsync(sender, storagePools, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnStoragePoolsAsync(AgentSession session, List<StoragePool>? storagePools, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
// storagepools
|
||||
|
||||
if (storagePools is not null && storagePools.Any())
|
||||
{
|
||||
var storagepoolBulk = new List<WriteModel<HostStoragePoolEntity>>();
|
||||
|
||||
foreach (var storagePool in storagePools)
|
||||
{
|
||||
var storagePoolFilter = Builders<HostStoragePoolEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.UniqueId, storagePool.UniqueId)
|
||||
});
|
||||
|
||||
List<string>? states = null;
|
||||
|
||||
if (storagePool.States is not null)
|
||||
{
|
||||
states = new List<string>();
|
||||
|
||||
foreach (var state in storagePool.States)
|
||||
{
|
||||
states.Add(state.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var storagePoolUpdate = Builders<HostStoragePoolEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.UniqueId, storagePool.UniqueId)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Name, storagePool.FriendlyName)
|
||||
.Set(p => p.Health, storagePool.Health?.ToString())
|
||||
.Set(p => p.Resiliency, storagePool.Resiliency)
|
||||
.Set(p => p.Primordial, storagePool.IsPrimordial)
|
||||
.Set(p => p.ReadOnly, storagePool.IsReadOnly)
|
||||
.Set(p => p.Clustered, storagePool.IsClustered)
|
||||
.Set(p => p.Size, storagePool.Size)
|
||||
.Set(p => p.AllocatedSize, storagePool.AllocatedSize)
|
||||
.Set(p => p.SectorSize, storagePool.SectorSize)
|
||||
.Set(p => p.States, states);
|
||||
|
||||
storagepoolBulk.Add(new UpdateOneModel<HostStoragePoolEntity>(storagePoolFilter, storagePoolUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
storagepoolBulk.Add(new DeleteManyModel<HostStoragePoolEntity>(Builders<HostStoragePoolEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var storagePoolResult = await _database.HostStoragePool().BulkWriteAsync(storagepoolBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// physicaldisks
|
||||
|
||||
if (storagePools is not null && storagePools.Any())
|
||||
{
|
||||
var physicalDiskBulk = new List<WriteModel<HostStoragePoolPhysicalDiskEntity>>();
|
||||
|
||||
foreach (var storagePool in storagePools)
|
||||
{
|
||||
var storagePoolId = await _database.HostStoragePool()
|
||||
.Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Any())
|
||||
{
|
||||
foreach (var physicalDisk in storagePool.PhysicalDisks)
|
||||
{
|
||||
var physicalDiskFilter = Builders<HostStoragePoolPhysicalDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolPhysicalDiskEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.StoragePool, storagePoolId),
|
||||
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.UniqueId, physicalDisk.UniqueId)
|
||||
});
|
||||
|
||||
List<string>? states = null;
|
||||
|
||||
if (physicalDisk.States is not null)
|
||||
{
|
||||
states = new List<string>();
|
||||
|
||||
foreach (var state in physicalDisk.States)
|
||||
{
|
||||
states.Add(state.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var physicalDiskUpdate = Builders<HostStoragePoolPhysicalDiskEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.StoragePool, storagePoolId)
|
||||
.SetOnInsert(p => p.UniqueId, physicalDisk.UniqueId)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.DeviceId, physicalDisk.DeviceId)
|
||||
.Set(p => p.Name, physicalDisk.FriendlyName)
|
||||
.Set(p => p.Manufacturer, physicalDisk.Manufacturer)
|
||||
.Set(p => p.Model, physicalDisk.Model)
|
||||
.Set(p => p.Media, physicalDisk.MediaType.ToString())
|
||||
.Set(p => p.Bus, physicalDisk.BusType.ToString())
|
||||
.Set(p => p.Health, physicalDisk.Health.ToString())
|
||||
.Set(p => p.Usage, physicalDisk.Usage)
|
||||
.Set(p => p.Location, physicalDisk.PhysicalLocation)
|
||||
.Set(p => p.Serial, physicalDisk.SerialNumber)
|
||||
.Set(p => p.Firmware, physicalDisk.FirmwareVersion)
|
||||
.Set(p => p.Size, physicalDisk.Size)
|
||||
.Set(p => p.AllocatedSize, physicalDisk.AllocatedSize)
|
||||
.Set(p => p.Footprint, physicalDisk.VirtualDiskFootprint)
|
||||
.Set(p => p.LogicalSectorSize, physicalDisk.LogicalSectorSize)
|
||||
.Set(p => p.PhysicalSectorSize, physicalDisk.PhysicalSectorSize)
|
||||
.Set(p => p.States, states);
|
||||
|
||||
physicalDiskBulk.Add(new UpdateOneModel<HostStoragePoolPhysicalDiskEntity>(physicalDiskFilter, physicalDiskUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
physicalDiskBulk.Add(new DeleteManyModel<HostStoragePoolPhysicalDiskEntity>(Builders<HostStoragePoolPhysicalDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolPhysicalDiskEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolPhysicalDiskEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var physicalDiskResult = await _database.HostStoragePoolPhysicalDisk().BulkWriteAsync(physicalDiskBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// virtual disks
|
||||
|
||||
if (storagePools is not null && storagePools.Any())
|
||||
{
|
||||
var virtualDiskBulk = new List<WriteModel<HostStoragePoolVirtualDiskEntity>>();
|
||||
|
||||
foreach (var storagePool in storagePools)
|
||||
{
|
||||
if (storagePool.VirtualDisks is not null && storagePool.VirtualDisks.Any())
|
||||
{
|
||||
foreach (var virtualDisk in storagePool.VirtualDisks)
|
||||
{
|
||||
var storagePoolId = await _database.HostStoragePool()
|
||||
.Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var virtualDiskFilter = Builders<HostStoragePoolVirtualDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolVirtualDiskEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.StoragePool, storagePoolId),
|
||||
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.UniqueId, virtualDisk.UniqueId)
|
||||
});
|
||||
|
||||
List<string>? states = null;
|
||||
|
||||
if (virtualDisk.States is not null)
|
||||
{
|
||||
states = new List<string>();
|
||||
|
||||
foreach (var state in virtualDisk.States)
|
||||
{
|
||||
states.Add(state.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var virtualDiskUpdate = Builders<HostStoragePoolVirtualDiskEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.StoragePool, storagePoolId)
|
||||
.SetOnInsert(p => p.UniqueId, virtualDisk.UniqueId)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Name, virtualDisk.FriendlyName)
|
||||
.Set(p => p.Health, virtualDisk.Health.ToString())
|
||||
.Set(p => p.Access, virtualDisk.AccessType.ToString())
|
||||
.Set(p => p.Provisioning, virtualDisk.ProvisioningType.ToString())
|
||||
.Set(p => p.PhysicalRedundancy, virtualDisk.PhysicalDiskRedundancy)
|
||||
.Set(p => p.Resiliency, virtualDisk.ResiliencySettingName)
|
||||
.Set(p => p.Deduplication, virtualDisk.Deduplication)
|
||||
.Set(p => p.Snapshot, virtualDisk.IsSnapshot)
|
||||
.Set(p => p.Size, virtualDisk.Size)
|
||||
.Set(p => p.AllocatedSize, virtualDisk.AllocatedSize)
|
||||
.Set(p => p.Footprint, virtualDisk.FootprintOnPool)
|
||||
.Set(p => p.ReadCacheSize, virtualDisk.ReadCacheSize)
|
||||
.Set(p => p.WriteCacheSize, virtualDisk.WriteCacheSize)
|
||||
.Set(p => p.States, states);
|
||||
|
||||
virtualDiskBulk.Add(new UpdateOneModel<HostStoragePoolVirtualDiskEntity>(virtualDiskFilter, virtualDiskUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtualDiskBulk.Add(new DeleteManyModel<HostStoragePoolVirtualDiskEntity>(Builders<HostStoragePoolVirtualDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolVirtualDiskEntity>>
|
||||
{
|
||||
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostStoragePoolVirtualDiskEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var virtualDiskResult = await _database.HostStoragePoolVirtualDisk().BulkWriteAsync(virtualDiskBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class SystemInfoHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public SystemInfoHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is SystemInfo systemInfo)
|
||||
{
|
||||
await OnSystemInfoAsync(sender, systemInfo, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnSystemInfoAsync(AgentSession session, SystemInfo? system, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var date = DateTime.Now;
|
||||
|
||||
await _database.HostSystem().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders<HostSystemEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.BootUpTime, system.LastBootUpTime)
|
||||
.Set(p => p.LocalTime, system.LocalDateTime)
|
||||
.Set(p => p.Processes, system.Processes)
|
||||
.Set(p => p.License, system.License), new UpdateOptions
|
||||
{
|
||||
IsUpsert = true
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
289
src/Server/Insight.Server/Network/Handlers/Agent/TrapHandler.cs
Normal file
289
src/Server/Insight.Server/Network/Handlers/Agent/TrapHandler.cs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
using Insight.Agent.Enums;
|
||||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Insight.Server.Models;
|
||||
using MongoDB.Driver;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using static Insight.Server.Models.MonitorMessage;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class TrapHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public TrapHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is Trap trap)
|
||||
{
|
||||
await OnTrapAsync(sender, trap, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnTrapAsync(AgentSession session, Trap? trap, CancellationToken cancellationToken)
|
||||
{
|
||||
if (trap is null) return;
|
||||
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
if (TryParse(trap, out var monitoring) is false)
|
||||
{
|
||||
//_logger.LogWarning($"Failed to parse");
|
||||
}
|
||||
|
||||
// insert monitoring log
|
||||
var monitoringLog = new HostLogMonitoringEntity
|
||||
{
|
||||
Host = hostEntity.Id,
|
||||
Insert = DateTime.Now,
|
||||
Timestamp = monitoring?.Timestamp,
|
||||
Category = monitoring?.Category?.ToString(),
|
||||
Status = monitoring?.Status?.ToString(),
|
||||
Hostname = monitoring?.Hostname,
|
||||
Task = monitoring?.Subject,
|
||||
Message = monitoring?.Message,
|
||||
Dispatch = DispatchEnum.Pending.ToString()
|
||||
};
|
||||
|
||||
await _database.HostLogMonitoring()
|
||||
.InsertOneAsync(monitoringLog, cancellationToken: cancellationToken);
|
||||
|
||||
// insert host log
|
||||
var log = new HostLogEntity
|
||||
{
|
||||
Insert = monitoringLog.Insert,
|
||||
Host = monitoringLog.Host,
|
||||
Category = monitoringLog.Category,
|
||||
Status = monitoringLog.Status,
|
||||
Source = "Trap",
|
||||
Message = monitoringLog?.Task,
|
||||
Timestamp = monitoringLog?.Insert
|
||||
};
|
||||
|
||||
if (monitoringLog?.Message is not null) log.Message += $"\n{monitoringLog.Message}";
|
||||
|
||||
await _database.HostLog()
|
||||
.InsertOneAsync(log, cancellationToken: cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static bool TryParse(Trap packet, out MonitorMessage? monitoring)
|
||||
{
|
||||
monitoring = null;
|
||||
|
||||
if (packet is null || packet.Data is null || packet.Data.Any() is false) return false;
|
||||
|
||||
monitoring = new MonitorMessage
|
||||
{
|
||||
Community = packet.Community,
|
||||
Category = CategoryEnum.Monitoring,
|
||||
Endpoint = packet.Endpoint,
|
||||
Timestamp = packet.Timestamp
|
||||
};
|
||||
|
||||
if (Enum.TryParse<ApplicationEnum>(packet.Community, true, out var application))
|
||||
{
|
||||
monitoring.Application = application;
|
||||
}
|
||||
|
||||
StatusEnum? status;
|
||||
string? task;
|
||||
string? message;
|
||||
|
||||
switch (application)
|
||||
{
|
||||
case ApplicationEnum.Acronis:
|
||||
monitoring.Application = ApplicationEnum.Acronis;
|
||||
if (ParseAcronis(packet.Data, out status, out task, out message) is false) return false;
|
||||
break;
|
||||
case ApplicationEnum.Veeam:
|
||||
monitoring.Application = ApplicationEnum.Veeam;
|
||||
if (ParseVeeam(packet.Data, out status, out task, out message) is false) return false;
|
||||
break;
|
||||
case ApplicationEnum.QNAP:
|
||||
monitoring.Application = ApplicationEnum.QNAP;
|
||||
monitoring.Category = CategoryEnum.System;
|
||||
monitoring.Hostname = packet.Hostname;
|
||||
if (ParseQnap(packet.Data, out status, out task, out message) is false) return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
monitoring.Status = status;
|
||||
monitoring.Subject = task;
|
||||
monitoring.Message = message;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool ParseAcronis(List<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
|
||||
{
|
||||
status = data[0].Value.ToLower() switch
|
||||
{
|
||||
"erfolgreich" => StatusEnum.Information,
|
||||
"success" => StatusEnum.Information,
|
||||
"information" => StatusEnum.Information,
|
||||
"warnung" => StatusEnum.Warning,
|
||||
"warning" => StatusEnum.Warning,
|
||||
"fehler" => StatusEnum.Error,
|
||||
"failed" => StatusEnum.Error,
|
||||
"error" => StatusEnum.Error,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
task = null;
|
||||
message = null;
|
||||
|
||||
var parsed = false;
|
||||
|
||||
try
|
||||
{
|
||||
var trim = data[1].Value.Split(new string[] { ":" }, StringSplitOptions.None);
|
||||
task = trim[1].Split(new string[] { "'" }, StringSplitOptions.None)[1].Split("'")[0].Trim();
|
||||
message = trim[1].Split(new string[] { "' " }, StringSplitOptions.None)[1].Trim();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// skipped for base64 parse
|
||||
}
|
||||
|
||||
if (parsed) return true;
|
||||
|
||||
try
|
||||
{
|
||||
var content = Regex.Replace(data[1].Value, @"\s+", "");
|
||||
var bytes = Enumerable.Range(0, content.Length)
|
||||
.Where(x => x % 2 == 0)
|
||||
.Select(x => Convert.ToByte(content.Substring(x, 2), 16))
|
||||
.ToArray();
|
||||
|
||||
content = Encoding.UTF8.GetString(bytes);
|
||||
|
||||
var trim = content.Split(new string[] { ":" }, StringSplitOptions.None);
|
||||
task = trim[1].Split(new string[] { "'" }, StringSplitOptions.None)[1].Split("'")[0].Trim();
|
||||
message = trim[1].Split(new string[] { "' " }, StringSplitOptions.None)[1].Trim();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//_logger.LogError("{ex}", ex);
|
||||
}
|
||||
|
||||
if (parsed) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ParseVeeam(List<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
|
||||
{
|
||||
status = null;
|
||||
task = null;
|
||||
message = null;
|
||||
|
||||
var parsed = false;
|
||||
|
||||
try
|
||||
{
|
||||
var summary = false;
|
||||
|
||||
if (Guid.TryParse(data[0].Value, out _))
|
||||
summary = true;
|
||||
|
||||
if (data[1].Value.ToLower() == "backup configuration job")
|
||||
return false;
|
||||
|
||||
status = (summary ? data[2].Value.ToLower() : data[3].Value.ToLower()) switch
|
||||
{
|
||||
"success" => StatusEnum.Information,
|
||||
"warning" => StatusEnum.Warning,
|
||||
"failed" => StatusEnum.Error,
|
||||
"error" => StatusEnum.Error,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
task = data[1].Value;
|
||||
parsed = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (parsed) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ParseQnap(List<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
|
||||
{
|
||||
status = StatusEnum.Information;
|
||||
task = null;
|
||||
message = string.Empty;
|
||||
|
||||
var parsed = false;
|
||||
|
||||
try
|
||||
{
|
||||
var keywords = new Dictionary<string, StatusEnum>
|
||||
{
|
||||
{ "power", StatusEnum.Information },
|
||||
{ "rights", StatusEnum.Information },
|
||||
{ "added", StatusEnum.Information },
|
||||
{ "changed", StatusEnum.Information },
|
||||
{ "password", StatusEnum.Information },
|
||||
{ "firmware", StatusEnum.Information },
|
||||
{ "restarting", StatusEnum.Information },
|
||||
{ "detected", StatusEnum.Warning },
|
||||
{ "external", StatusEnum.Warning },
|
||||
{ "threshold", StatusEnum.Warning },
|
||||
{ "file system", StatusEnum.Warning },
|
||||
{ "raid", StatusEnum.Warning },
|
||||
{ "full", StatusEnum.Error },
|
||||
{ "failure", StatusEnum.Error },
|
||||
{ "failed", StatusEnum.Error },
|
||||
{ "resyncing", StatusEnum.Error },
|
||||
{ "degraded", StatusEnum.Error },
|
||||
{ "error", StatusEnum.Error },
|
||||
{ "without error", StatusEnum.Information },
|
||||
{ "ncsi", StatusEnum.Information }
|
||||
};
|
||||
|
||||
foreach (var key in keywords)
|
||||
{
|
||||
if (Regex.IsMatch(string.Concat(data).ToLowerInvariant(), $@"\b{key.Key}\b"))
|
||||
{
|
||||
status = key.Value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in data)
|
||||
{
|
||||
message += kv.Value;
|
||||
}
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//_logger.LogError("{ex}", ex);
|
||||
}
|
||||
|
||||
if (parsed) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class UpdateHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public UpdateHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is UpdateList updates)
|
||||
{
|
||||
await OnUpdatesAsync(sender, updates, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnUpdatesAsync(AgentSession session, UpdateList updates, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostUpdateEntity>>();
|
||||
|
||||
if (updates is not null)
|
||||
{
|
||||
if (updates.Installed is not null && updates.Installed.Any())
|
||||
{
|
||||
foreach (var update in updates.Installed)
|
||||
{
|
||||
var filterDefinition = Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
|
||||
{
|
||||
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUpdateEntity>.Filter.Eq(x => x.Serial, update.Id)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostUpdateEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Serial, update.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Pending, false)
|
||||
.Set(p => p.Name, update.Name)
|
||||
.Set(p => p.Description, update.Description)
|
||||
.Set(p => p.SupportUrl, update.SupportUrl)
|
||||
.Set(p => p.Result, update.Result.ToString())
|
||||
.Set(p => p.Date, update.Date);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostUpdateEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (updates.Pending is not null && updates.Pending.Any())
|
||||
{
|
||||
foreach (var update in updates.Pending)
|
||||
{
|
||||
var filterDefinition = Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
|
||||
{
|
||||
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUpdateEntity>.Filter.Eq(x => x.Serial, update.Id)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostUpdateEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Serial, update.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Pending, true)
|
||||
.Set(p => p.Name, update.Name)
|
||||
.Set(p => p.Description, update.Description)
|
||||
.Set(p => p.SupportUrl, update.SupportUrl)
|
||||
.Set(p => p.Result, update.Result?.ToString())
|
||||
|
||||
.Set(p => p.Type, update.Type.ToString())
|
||||
.Set(p => p.Size, update.Size)
|
||||
.Set(p => p.IsDownloaded, update.IsDownloaded)
|
||||
.Set(p => p.CanRequestUserInput, update.CanRequestUserInput)
|
||||
.Set(p => p.RebootBehavior, update.RebootBehavior?.ToString())
|
||||
|
||||
.Set(p => p.Date, update.Date);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostUpdateEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostUpdateEntity>(Builders<HostUpdateEntity>.Filter.And(new List<FilterDefinition<HostUpdateEntity>>
|
||||
{
|
||||
Builders<HostUpdateEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUpdateEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostUpdate().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
188
src/Server/Insight.Server/Network/Handlers/Agent/UserHandler.cs
Normal file
188
src/Server/Insight.Server/Network/Handlers/Agent/UserHandler.cs
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class UserHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public UserHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is UserList users)
|
||||
{
|
||||
await OnUsersAsync(sender, users, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnUsersAsync(AgentSession session, List<User>? users, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
// users
|
||||
|
||||
if (users is not null && users.Any())
|
||||
{
|
||||
var userBulk = new List<WriteModel<HostUserEntity>>();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
var userFilter = Builders<HostUserEntity>.Filter.And(new List<FilterDefinition<HostUserEntity>>
|
||||
{
|
||||
Builders<HostUserEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUserEntity>.Filter.Eq(x => x.Domain, user?.Domain),
|
||||
Builders<HostUserEntity>.Filter.Eq(x => x.Name, user?.Name)
|
||||
});
|
||||
|
||||
var userUpdate = Builders<HostUserEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Domain, user?.Domain)
|
||||
.SetOnInsert(p => p.Name, user?.Name)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Sid, user?.Sid)
|
||||
.Set(p => p.FullName, user?.FullName)
|
||||
.Set(p => p.Description, user?.Description)
|
||||
.Set(p => p.Status, user?.Status)
|
||||
.Set(p => p.LocalAccount, user?.LocalAccount)
|
||||
.Set(p => p.Disabled, user?.Disabled)
|
||||
.Set(p => p.Lockout, user?.Lockout)
|
||||
.Set(p => p.PasswordChangeable, user?.PasswordChangeable)
|
||||
.Set(p => p.PasswordExpires, user?.PasswordExpires)
|
||||
.Set(p => p.PasswordRequired, user?.PasswordRequired);
|
||||
|
||||
userBulk.Add(new UpdateOneModel<HostUserEntity>(userFilter, userUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
userBulk.Add(new DeleteManyModel<HostUserEntity>(Builders<HostUserEntity>.Filter.And(new List<FilterDefinition<HostUserEntity>>
|
||||
{
|
||||
Builders<HostUserEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUserEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var userResult = await _database.HostSystemUser().BulkWriteAsync(userBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// groups
|
||||
|
||||
if (users is not null && users.Any())
|
||||
{
|
||||
var groupBulk = new List<WriteModel<HostGroupEntity>>();
|
||||
|
||||
var distinctGroups = users.SelectMany(p => p.Groups)
|
||||
.GroupBy(p => new { p?.Domain, p?.Name })
|
||||
.Select(p => p.First());
|
||||
|
||||
foreach (var group in distinctGroups)
|
||||
{
|
||||
var groupFilter = Builders<HostGroupEntity>.Filter.And(new List<FilterDefinition<HostGroupEntity>>
|
||||
{
|
||||
Builders<HostGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostGroupEntity>.Filter.Eq(x => x.Domain, group?.Domain),
|
||||
Builders<HostGroupEntity>.Filter.Eq(x => x.Name, group?.Name)
|
||||
});
|
||||
|
||||
var groupUpdate = Builders<HostGroupEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Domain, group?.Domain)
|
||||
.SetOnInsert(p => p.Name, group?.Name)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Sid, group?.Sid)
|
||||
.Set(p => p.Description, group?.Description)
|
||||
.Set(p => p.LocalAccount, group?.LocalAccount);
|
||||
|
||||
groupBulk.Add(new UpdateOneModel<HostGroupEntity>(groupFilter, groupUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
groupBulk.Add(new DeleteManyModel<HostGroupEntity>(Builders<HostGroupEntity>.Filter.And(new List<FilterDefinition<HostGroupEntity>>
|
||||
{
|
||||
Builders<HostGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostGroupEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var groupResult = await _database.HostSystemGroup().BulkWriteAsync(groupBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// relations
|
||||
|
||||
if (users is not null && users.Any())
|
||||
{
|
||||
var relationBulk = new List<WriteModel<HostUserGroupEntity>>();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
var userId = await _database.HostSystemUser()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Domain == user.Domain && p.Name == user.Name)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (user.Groups is not null && user.Groups.Any())
|
||||
{
|
||||
foreach (var group in user.Groups)
|
||||
{
|
||||
var groupId = await _database.HostSystemGroup()
|
||||
.Find(p => p.Host == hostEntity.Id && p.Domain == group.Domain && p.Name == group.Name)
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var relationFilter = Builders<HostUserGroupEntity>.Filter.And(new List<FilterDefinition<HostUserGroupEntity>>
|
||||
{
|
||||
Builders<HostUserGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUserGroupEntity>.Filter.Eq(x => x.User, userId),
|
||||
Builders<HostUserGroupEntity>.Filter.Eq(x => x.Group, groupId)
|
||||
});
|
||||
|
||||
var relationUpdate = Builders<HostUserGroupEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.User, userId)
|
||||
.SetOnInsert(p => p.Group, groupId)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch);
|
||||
|
||||
relationBulk.Add(new UpdateOneModel<HostUserGroupEntity>(relationFilter, relationUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relationBulk.Add(new DeleteManyModel<HostUserGroupEntity>(Builders<HostUserGroupEntity>.Filter.And(new List<FilterDefinition<HostUserGroupEntity>>
|
||||
{
|
||||
Builders<HostUserGroupEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostUserGroupEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var relationResult = await _database.HostSystemUserSystemGroup().BulkWriteAsync(relationBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class VideocardHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public VideocardHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is VideocardList videocards)
|
||||
{
|
||||
await OnVideocardsAsync(sender, videocards, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnVideocardsAsync(AgentSession session, List<Videocard>? videocards, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
var bulk = new List<WriteModel<HostVideocardEntity>>();
|
||||
|
||||
if (videocards is not null && videocards.Any())
|
||||
{
|
||||
foreach (var videocard in videocards)
|
||||
{
|
||||
var filterDefinition = Builders<HostVideocardEntity>.Filter.And(new List<FilterDefinition<HostVideocardEntity>>
|
||||
{
|
||||
Builders<HostVideocardEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostVideocardEntity>.Filter.Eq(x => x.Name, videocard.Model)
|
||||
});
|
||||
|
||||
var updateDefinition = Builders<HostVideocardEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.Name, videocard.Model)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
.Set(p => p.Company, null)
|
||||
.Set(p => p.Memory, videocard.Memory)
|
||||
.Set(p => p.Driver, videocard.DriverVersion)
|
||||
.Set(p => p.Date, videocard.DriverDate);
|
||||
|
||||
bulk.Add(new UpdateOneModel<HostVideocardEntity>(filterDefinition, updateDefinition)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
bulk.Add(new DeleteManyModel<HostVideocardEntity>(Builders<HostVideocardEntity>.Filter.And(new List<FilterDefinition<HostVideocardEntity>>
|
||||
{
|
||||
Builders<HostVideocardEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostVideocardEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var result = await _database.HostVideocard().BulkWriteAsync(bulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Agent
|
||||
{
|
||||
public class VirtualMaschineHandler : IAgentMessageHandler<AgentSession>
|
||||
{
|
||||
private readonly IMongoDatabase _database;
|
||||
|
||||
public VirtualMaschineHandler(IMongoDatabase database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage
|
||||
{
|
||||
if (message is VirtualMaschineList virtualMaschines)
|
||||
{
|
||||
await OnVirtualMaschinesAsync(sender, virtualMaschines, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnVirtualMaschinesAsync(AgentSession session, List<VirtualMaschine>? virtualMaschines, CancellationToken cancellationToken)
|
||||
{
|
||||
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (agentEntity is null) return;
|
||||
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return;
|
||||
|
||||
var batch = ObjectId.GenerateNewId().ToString();
|
||||
var date = DateTime.Now;
|
||||
|
||||
// virtual maschines
|
||||
if (virtualMaschines is not null && virtualMaschines.Any())
|
||||
{
|
||||
var virtualMaschineBulk = new List<WriteModel<HostHypervisorVirtualMaschineEntity>>();
|
||||
|
||||
foreach (var virtualMaschine in virtualMaschines)
|
||||
{
|
||||
var virtualMaschineFilter = Builders<HostHypervisorVirtualMaschineEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineEntity>>
|
||||
{
|
||||
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.UniqueId, virtualMaschine.Id.ToString())
|
||||
});
|
||||
|
||||
var virtualMaschineUpdate = Builders<HostHypervisorVirtualMaschineEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.UniqueId, virtualMaschine.Id.ToString())
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.Name, virtualMaschine?.Name)
|
||||
.Set(p => p.Notes, virtualMaschine?.Notes)
|
||||
.Set(p => p.Enabled, virtualMaschine?.Enabled?.ToString())
|
||||
.Set(p => p.EnabledDefault, virtualMaschine?.EnabledDefault?.ToString())
|
||||
.Set(p => p.Health, virtualMaschine?.HealthState?.ToString())
|
||||
.Set(p => p.Status, virtualMaschine?.Status)
|
||||
.Set(p => p.OnTime, virtualMaschine?.OnTime)
|
||||
.Set(p => p.ReplicationState, virtualMaschine?.ReplicationState?.ToString())
|
||||
.Set(p => p.ReplicationHealth, virtualMaschine?.ReplicationHealth?.ToString())
|
||||
.Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion)
|
||||
.Set(p => p.IntegrationServicesVersionState, virtualMaschine?.IntegrationServicesVersionState?.ToString())
|
||||
.Set(p => p.ProcessId, virtualMaschine?.ProcessId)
|
||||
.Set(p => p.NumberOfProcessors, virtualMaschine?.NumberOfProcessors)
|
||||
.Set(p => p.ProcessorLoad, virtualMaschine?.ProcessorLoad)
|
||||
.Set(p => p.MemoryAvailable, virtualMaschine?.MemoryAvailable)
|
||||
.Set(p => p.MemoryUsage, virtualMaschine?.MemoryUsage)
|
||||
.Set(p => p.InstallDate, virtualMaschine?.InstallDate)
|
||||
.Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion)
|
||||
.Set(p => p.TimeOfLastStateChange, virtualMaschine?.TimeOfLastStateChange)
|
||||
.Set(p => p.LastReplicationTime, virtualMaschine?.LastReplicationTime)
|
||||
.Set(p => p.Os, virtualMaschine?.GuestOperatingSystem);
|
||||
|
||||
virtualMaschineBulk.Add(new UpdateOneModel<HostHypervisorVirtualMaschineEntity>(virtualMaschineFilter, virtualMaschineUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
|
||||
virtualMaschineBulk.Add(new DeleteManyModel<HostHypervisorVirtualMaschineEntity>(Builders<HostHypervisorVirtualMaschineEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineEntity>>
|
||||
{
|
||||
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostHypervisorVirtualMaschineEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var virtualMaschineResult = await _database.HostHypervisorVirtualMaschine().BulkWriteAsync(virtualMaschineBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
// virtual maschine configurations
|
||||
|
||||
if (virtualMaschines is not null && virtualMaschines.Any())
|
||||
{
|
||||
var configurationBulk = new List<WriteModel<HostHypervisorVirtualMaschineConfigEntity>>();
|
||||
|
||||
foreach (var virtualmaschine in virtualMaschines)
|
||||
{
|
||||
var virtualMaschineId = await _database.HostHypervisorVirtualMaschine()
|
||||
.Find(p => p.Host == hostEntity.Id && p.UniqueId == virtualmaschine.Id.ToString())
|
||||
.Project(p => p.Id)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (virtualmaschine.Configurations is not null && virtualmaschine.Configurations.Any())
|
||||
{
|
||||
foreach (var config in virtualmaschine.Configurations)
|
||||
{
|
||||
var configFilter = Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineConfigEntity>>
|
||||
{
|
||||
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.VirtualMaschine, virtualMaschineId),
|
||||
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.UniqueId, config.Id)
|
||||
});
|
||||
|
||||
// custom "notes" concat
|
||||
string notes = string.Empty;
|
||||
if (config?.Notes is not null) foreach (var n in config.Notes) notes += n;
|
||||
|
||||
var configUpdate = Builders<HostHypervisorVirtualMaschineConfigEntity>.Update
|
||||
.SetOnInsert(p => p.Insert, date)
|
||||
.SetOnInsert(p => p.Host, hostEntity.Id)
|
||||
.SetOnInsert(p => p.VirtualMaschine, virtualMaschineId)
|
||||
.SetOnInsert(p => p.UniqueId, config.Id)
|
||||
.Set(p => p.Update, date)
|
||||
.Set(p => p.Batch, batch)
|
||||
|
||||
.Set(p => p.ParentId, config.ParentId)
|
||||
.Set(p => p.Type, config.Type)
|
||||
.Set(p => p.Name, config.Name)
|
||||
.Set(p => p.Notes, notes)
|
||||
.Set(p => p.CreationTime, config.CreationTime)
|
||||
.Set(p => p.Generation, config.Generation)
|
||||
.Set(p => p.Architecture, config.Architecture)
|
||||
.Set(p => p.SecureBootEnabled, config.SecureBootEnabled)
|
||||
.Set(p => p.IsAutomaticSnapshot, config.IsAutomaticSnapshot)
|
||||
.Set(p => p.AutomaticStartupAction, config.AutomaticStartupAction?.ToString())
|
||||
.Set(p => p.AutomaticShutdownAction, config.AutomaticShutdownAction?.ToString())
|
||||
.Set(p => p.AutomaticRecoveryAction, config.AutomaticRecoveryAction?.ToString())
|
||||
.Set(p => p.AutomaticSnapshotsEnabled, config.AutomaticSnapshotsEnabled)
|
||||
.Set(p => p.BaseBoardSerialNumber, config.BaseBoardSerialNumber)
|
||||
.Set(p => p.BIOSSerialNumber, config.BIOSSerialNumber)
|
||||
.Set(p => p.BIOSGUID, config.BIOSGUID)
|
||||
.Set(p => p.ConfigurationDataRoot, config.ConfigurationDataRoot)
|
||||
.Set(p => p.ConfigurationFile, config.ConfigurationFile)
|
||||
.Set(p => p.GuestStateDataRoot, config.GuestStateDataRoot)
|
||||
.Set(p => p.GuestStateFile, config.GuestStateFile)
|
||||
.Set(p => p.SnapshotDataRoot, config.SnapshotDataRoot)
|
||||
.Set(p => p.SuspendDataRoot, config.SuspendDataRoot)
|
||||
.Set(p => p.SwapFileDataRoot, config.SwapFileDataRoot);
|
||||
|
||||
configurationBulk.Add(new UpdateOneModel<HostHypervisorVirtualMaschineConfigEntity>(configFilter, configUpdate)
|
||||
{
|
||||
IsUpsert = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurationBulk.Add(new DeleteManyModel<HostHypervisorVirtualMaschineConfigEntity>(Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.And(new List<FilterDefinition<HostHypervisorVirtualMaschineConfigEntity>>
|
||||
{
|
||||
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Eq(x => x.Host, hostEntity.Id),
|
||||
Builders<HostHypervisorVirtualMaschineConfigEntity>.Filter.Ne(x => x.Batch, batch)
|
||||
})));
|
||||
|
||||
var configurationResult = await _database.HostVirtualMaschineConfig().BulkWriteAsync(configurationBulk, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Insight.Web.Interfaces;
|
||||
using Insight.Web.Messages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using Vaitr.Bus;
|
||||
using Vaitr.Network;
|
||||
|
||||
namespace Insight.Server.Network.Handlers.Web
|
||||
{
|
||||
public class ConsoleProxyHandler : IWebMessageHandler<WebSession>
|
||||
{
|
||||
private readonly List<IDisposable> _subscriptions = new();
|
||||
|
||||
private readonly ISessionPool<AgentSession, IAgentMessage> _agentPool;
|
||||
private readonly ISessionPool<WebSession, IWebMessage> _webPool;
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly Bus _bus;
|
||||
private readonly ILogger<ConsoleProxyHandler> _logger;
|
||||
|
||||
public ConsoleProxyHandler(
|
||||
ISessionPool<AgentSession, IAgentMessage> agentPool,
|
||||
ISessionPool<WebSession, IWebMessage> webPool,
|
||||
IMongoDatabase database,
|
||||
Bus bus,
|
||||
ILogger<ConsoleProxyHandler> logger)
|
||||
{
|
||||
_agentPool = agentPool;
|
||||
_webPool = webPool;
|
||||
_database = database;
|
||||
_bus = bus;
|
||||
_logger = logger;
|
||||
|
||||
_subscriptions.Add(_bus.SubscribeAsync<ConsoleQuery>(OnConsoleQueryAsync, null));
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync<TMessage>(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IWebMessage
|
||||
{
|
||||
if (message is ConsoleQueryProxyRequest consoleRequest)
|
||||
{
|
||||
await OnConsoleQueryRequestAsync(sender, consoleRequest, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask OnConsoleQueryRequestAsync(WebSession session, ConsoleQueryProxyRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
// get host
|
||||
var hostEntity = await _database.Host()
|
||||
.Find(Builders<HostEntity>
|
||||
.Filter
|
||||
.Eq(p => p.Id, request.HostId))
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (hostEntity is null)
|
||||
{
|
||||
_logger.LogWarning("hostEntity is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// get agent
|
||||
var agentEntity = await _database.Agent()
|
||||
.Find(Builders<AgentEntity>
|
||||
.Filter
|
||||
.Eq(p => p.Id, hostEntity.Agent))
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (agentEntity is null)
|
||||
{
|
||||
_logger.LogWarning("agentEntity is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// check if agent online
|
||||
if (_agentPool.FirstOrDefault(p => p.Value.Id == agentEntity.Id).Value is not AgentSession agent) return;
|
||||
|
||||
// send "real" packet to agent
|
||||
await agent.SendAsync(new ConsoleQueryRequest
|
||||
{
|
||||
Id = request.Id,
|
||||
HostId = request.HostId,
|
||||
Query = request.Query
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private async ValueTask OnConsoleQueryAsync(ConsoleQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
// check if web online
|
||||
if (_webPool.FirstOrDefault().Value is not WebSession web) return;
|
||||
|
||||
await web.SendAsync(new ConsoleQueryProxy
|
||||
{
|
||||
Id = query.Id,
|
||||
HostId = query.HostId,
|
||||
Query = query.Query,
|
||||
Data = query.Data,
|
||||
Errors = query.Errors,
|
||||
HadErrors = query.HadErrors
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/Server/Insight.Server/Network/WebSession.cs
Normal file
55
src/Server/Insight.Server/Network/WebSession.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using Insight.Web.Interfaces;
|
||||
using Insight.Web.Messages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Vaitr.Network;
|
||||
|
||||
namespace Insight.Server.Network;
|
||||
|
||||
public class WebSession : TcpSession<IWebMessage>
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
private readonly IEnumerable<IWebMessageHandler<WebSession>> _handlers;
|
||||
|
||||
public WebSession(IEnumerable<IWebMessageHandler<WebSession>> handlers, ISerializer<IWebMessage> serializer, ILogger<WebSession> logger) : base(serializer, logger)
|
||||
{
|
||||
_handlers = handlers;
|
||||
}
|
||||
|
||||
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Web ({ep?}) connected", RemoteEndPoint);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Web ({ep?}) disconnected", RemoteEndPoint);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnSentAsync(IPacketContext<IWebMessage> context, CancellationToken cancellationToken)
|
||||
{
|
||||
await base.OnSentAsync(context, cancellationToken);
|
||||
}
|
||||
|
||||
protected override async ValueTask OnReceivedAsync(IPacketContext<IWebMessage> context, CancellationToken cancellationToken)
|
||||
{
|
||||
await base.OnReceivedAsync(context, cancellationToken);
|
||||
|
||||
foreach (var handler in _handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
await handler.HandleAsync(this, context.Packet, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Web ({ep?}) Heartbeat", RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
135
src/Server/Insight.Server/Program.cs
Normal file
135
src/Server/Insight.Server/Program.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using Insight.Agent.Interfaces;
|
||||
using Insight.Agent.Messages;
|
||||
using Insight.Domain.Constants;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Server.Extensions;
|
||||
using Insight.Server.Network;
|
||||
using Insight.Server.Network.Handlers.Agent;
|
||||
using Insight.Server.Network.Handlers.Web;
|
||||
using Insight.Server.Services;
|
||||
using Insight.Web.Interfaces;
|
||||
using Insight.Web.Messages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net;
|
||||
using Vaitr.Bus;
|
||||
using Vaitr.Network;
|
||||
using Vaitr.Network.Hosting;
|
||||
|
||||
namespace Insight.Server
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var builder = Host.CreateDefaultBuilder(args);
|
||||
builder.UseWindowsService();
|
||||
builder.UseSystemd();
|
||||
|
||||
builder.ConfigureAppConfiguration(options =>
|
||||
{
|
||||
options.Defaults();
|
||||
});
|
||||
|
||||
builder.ConfigureLogging(options =>
|
||||
{
|
||||
options.ClearProviders();
|
||||
options.SetMinimumLevel(LogLevel.Trace);
|
||||
|
||||
options.AddSimpleConsole(options =>
|
||||
{
|
||||
options.IncludeScopes = true;
|
||||
options.SingleLine = true;
|
||||
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff ";
|
||||
});
|
||||
|
||||
options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/server_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}");
|
||||
});
|
||||
|
||||
builder.ConfigureServices((host, services) =>
|
||||
{
|
||||
//var databaseLoggerFactory = LoggerFactory.Create(b =>
|
||||
//{
|
||||
// b.AddSimpleConsole();
|
||||
// b.SetMinimumLevel(LogLevel.Debug);
|
||||
//});
|
||||
|
||||
// INFRASTRUCTURE
|
||||
services.AddDatabase(host.Configuration);
|
||||
|
||||
// AGENT SERVER
|
||||
services.UseHostedServer<AgentSession, IAgentMessage>(options =>
|
||||
{
|
||||
options.Address = IPAddress.Any;
|
||||
options.Port = host.Configuration.GetValue<int?>(Appsettings.AgentServerPort) ?? throw new Exception($"{Appsettings.AgentServerPort} value not set (appsettings)");
|
||||
options.Keepalive = 10000;
|
||||
options.Timeout = 30000;
|
||||
options.Backlog = 128;
|
||||
|
||||
options.Encryption = Encryption.Tls12;
|
||||
options.Certificate = host.Configuration.GetValue<string?>(Appsettings.AgentServerCertificate) ?? throw new Exception($"{Appsettings.AgentServerCertificate} value not set (appsettings)");
|
||||
options.CertificatePassword = host.Configuration.GetValue<string?>(Appsettings.AgentServerCertificatePassword) ?? throw new Exception($"{Appsettings.AgentServerCertificatePassword} value not set (appsettings)");
|
||||
|
||||
options.UseSerializer<MemPackSerializer<IAgentMessage>, IAgentMessage>();
|
||||
});
|
||||
|
||||
services.AddSingleton<AgentHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, AgentHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, DriveHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, Network.Handlers.Agent.EventHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, InterfaceHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, MainboardHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, MemoryHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, OperationSystemHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, PrinterHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, ProcessorHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, ServiceHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, SessionHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, SoftwareHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, StoragePoolHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, SystemInfoHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, TrapHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, UpdateHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, UserHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, VideocardHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, VirtualMaschineHandler>();
|
||||
services.AddSingleton<IAgentMessageHandler<AgentSession>, ConsoleHandler>();
|
||||
|
||||
// WEB (FRONTEND-PROXY) SERVER
|
||||
services.UseHostedServer<WebSession, IWebMessage>(options =>
|
||||
{
|
||||
options.Address = IPAddress.Any;
|
||||
options.Port = host.Configuration.GetValue<int?>(Appsettings.WebServerPort) ?? throw new Exception($"{Appsettings.WebServerPort} value not set (appsettings)");
|
||||
options.Keepalive = 10000;
|
||||
options.Timeout = 30000;
|
||||
options.Backlog = 128;
|
||||
|
||||
options.Encryption = Encryption.Tls12;
|
||||
options.Certificate = host.Configuration.GetValue<string?>(Appsettings.WebServerCertificate) ?? throw new Exception($"{Appsettings.WebServerCertificate} value not set (appsettings)");
|
||||
options.CertificatePassword = host.Configuration.GetValue<string?>(Appsettings.WebServerCertificatePassword) ?? throw new Exception($"{Appsettings.WebServerCertificatePassword} value not set (appsettings)");
|
||||
|
||||
options.UseSerializer<MemPackSerializer<IWebMessage>, IWebMessage>();
|
||||
});
|
||||
|
||||
services.AddSingleton<IWebMessageHandler<WebSession>, ConsoleProxyHandler>();
|
||||
|
||||
// DISPATCH
|
||||
services.AddHostedService<JobService>();
|
||||
services.AddHostedService<DispatchService>();
|
||||
|
||||
// GLOBAL DEPENDENCIES
|
||||
services.AddSingleton<Bus>();
|
||||
services.AddTransient(provider => new HttpClient(new HttpClientHandler
|
||||
{
|
||||
ClientCertificateOptions = ClientCertificateOption.Manual,
|
||||
ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
|
||||
}));
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
await host.RunAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Server/Insight.Server/Properties/launchSettings.json
Normal file
14
src/Server/Insight.Server/Properties/launchSettings.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"Development": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Production": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
158
src/Server/Insight.Server/Services/DispatchService.cs
Normal file
158
src/Server/Insight.Server/Services/DispatchService.cs
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
using Insight.Agent.Enums;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace Insight.Server.Services
|
||||
{
|
||||
internal class DispatchService : BackgroundService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<DispatchService> _logger;
|
||||
|
||||
public DispatchService(HttpClient httpClient, IMongoDatabase database, IConfiguration configuration, ILogger<DispatchService> logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_database = database;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogTrace("ExecuteAsync");
|
||||
|
||||
var enabled = _configuration.GetValue<bool?>(Appsettings.DispatchWebmatic) ?? throw new Exception($"{Appsettings.DispatchWebmatic} value not set (appsettings)");
|
||||
if (enabled is false) return;
|
||||
|
||||
try
|
||||
{
|
||||
while (cancellationToken.IsCancellationRequested is false)
|
||||
{
|
||||
await DispatchAsync(cancellationToken);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
private async ValueTask DispatchAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogTrace($"DispatchAsync");
|
||||
|
||||
var pendings = await _database.HostLogMonitoring()
|
||||
.Find(Builders<HostLogMonitoringEntity>
|
||||
.Filter.Eq(p => p.Dispatch, DispatchEnum.Pending.ToString()))
|
||||
.Limit(10)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (pendings is null || pendings.Any() is false) return;
|
||||
|
||||
foreach (var entity in pendings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await SendAsync(entity, default);
|
||||
|
||||
await _database.HostLogMonitoring()
|
||||
.UpdateOneAsync(Builders<HostLogMonitoringEntity>.Filter
|
||||
.Eq(p => p.Id, entity.Id), Builders<HostLogMonitoringEntity>
|
||||
.Update
|
||||
.Set(p => p.Dispatch, result.ToString()), cancellationToken: default);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
_logger.LogTrace(ex.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// webmatic safety offset
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<DispatchEnum> SendAsync(HostLogMonitoringEntity monitoring, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogTrace($"SendAsync ({monitoring})");
|
||||
|
||||
var monitoringApi = Monitoring.LogUri;
|
||||
var monitoringContent = new List<KeyValuePair<string, string>>();
|
||||
var monitoringResult = new List<KeyValuePair<string, string>>();
|
||||
|
||||
// adjust by category
|
||||
if (Enum.TryParse<CategoryEnum>(monitoring.Category, true, out var monitoringCategory) is false) return DispatchEnum.Failure;
|
||||
|
||||
if (monitoringCategory == CategoryEnum.Monitoring) monitoringApi = Monitoring.StatusUri;
|
||||
|
||||
// set category (if log)
|
||||
if (monitoringApi == Monitoring.LogUri) monitoringContent.Add(new KeyValuePair<string, string>("category", monitoringCategory.ToString()));
|
||||
|
||||
// host resolve
|
||||
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Id, monitoring.Host?.ToString())).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return DispatchEnum.Failure;
|
||||
|
||||
// customer resolve
|
||||
var customerEntity = await _database.Customer().Find(Builders<CustomerEntity>.Filter.Eq(p => p.Id, hostEntity.Customer)).FirstOrDefaultAsync(cancellationToken);
|
||||
if (hostEntity is null) return DispatchEnum.Failure;
|
||||
|
||||
// set host name if no remote host set
|
||||
if (string.IsNullOrEmpty(monitoring.Hostname)) monitoring.Hostname = hostEntity.Name;
|
||||
|
||||
// remove any domain from hostname
|
||||
if (monitoring.Hostname is not null && monitoring.Hostname.Contains('.')) monitoring.Hostname = monitoring.Hostname.Split(".")[0];
|
||||
|
||||
// add customer tag to hostname
|
||||
monitoring.Hostname += $".{customerEntity.Tag}";
|
||||
|
||||
// if task null, set hostname
|
||||
if (string.IsNullOrEmpty(monitoring.Task)) monitoring.Task = monitoring.Hostname;
|
||||
|
||||
// insert hostname as computer-name (lowercase)
|
||||
monitoringContent.Add(new KeyValuePair<string, string>("computer_name", monitoring.Hostname.ToLower()));
|
||||
|
||||
// insert converted status (api styled)
|
||||
if (Enum.TryParse<StatusEnum>(monitoring.Status, true, out var monitoringStatus) is false) return DispatchEnum.Failure;
|
||||
|
||||
monitoringContent.Add(monitoringStatus switch
|
||||
{
|
||||
StatusEnum.Information => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "erfolgreich" : "info"),
|
||||
StatusEnum.Warning => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "Interaktion" : "warning"),
|
||||
StatusEnum.Error => new KeyValuePair<string, string>("status", monitoringApi == Monitoring.StatusUri ? "fehlgeschlagen" : "error"),
|
||||
_ => throw new NotImplementedException(nameof(monitoringStatus))
|
||||
});
|
||||
|
||||
// insert task, timestamp, message,
|
||||
monitoringContent.Add(new KeyValuePair<string, string>("task", monitoring.Task));
|
||||
|
||||
if (monitoring.Timestamp is not null)
|
||||
{
|
||||
monitoringContent.Add(new KeyValuePair<string, string>("timestamp", monitoring.Timestamp.Value.ToLocalTime().ToString()));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(monitoring.Message) is false)
|
||||
{
|
||||
monitoringContent.Add(new KeyValuePair<string, string>("message", monitoring.Message));
|
||||
}
|
||||
|
||||
// send message
|
||||
var result = await _httpClient.PostAsync(monitoringApi, new FormUrlEncodedContent(monitoringContent), default);
|
||||
|
||||
monitoringResult.Add(new KeyValuePair<string, string>("HttpStatusCode", result.StatusCode.ToString()));
|
||||
monitoringResult.Add(new KeyValuePair<string, string>("HttpResponseMessage", await result.Content.ReadAsStringAsync(default)));
|
||||
|
||||
// if content != "OK"
|
||||
if (result is null || result.IsSuccessStatusCode == false) return DispatchEnum.Failure;
|
||||
|
||||
// success
|
||||
return DispatchEnum.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/Server/Insight.Server/Services/JobService.cs
Normal file
79
src/Server/Insight.Server/Services/JobService.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using Insight.Agent.Messages;
|
||||
using Insight.Infrastructure;
|
||||
using Insight.Infrastructure.Entities;
|
||||
using Insight.Server.Extensions;
|
||||
using Insight.Server.Network;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MongoDB.Driver;
|
||||
using Vaitr.Network;
|
||||
|
||||
namespace Insight.Server.Services
|
||||
{
|
||||
internal class JobService : BackgroundService
|
||||
{
|
||||
private readonly ISessionPool<AgentSession, IAgentMessage> _agentPool;
|
||||
private readonly IMongoDatabase _database;
|
||||
private readonly ILogger<JobService> _logger;
|
||||
|
||||
public JobService(ISessionPool<AgentSession, IAgentMessage> agentPool, IMongoDatabase database, ILogger<JobService> logger)
|
||||
{
|
||||
_agentPool = agentPool;
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogTrace("ExecuteAsync");
|
||||
|
||||
var jobs = new List<Task>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (cancellationToken.IsCancellationRequested is false)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var agent in await GetAssignedAgentsAsync(cancellationToken))
|
||||
{
|
||||
await agent.SendAsync(new GetInventory(), cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception) { }
|
||||
finally
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
|
||||
}
|
||||
}
|
||||
}, default)
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(jobs).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
private async ValueTask<IEnumerable<AgentSession>> GetAssignedAgentsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var valid = new List<AgentSession>();
|
||||
|
||||
await Async.ParallelForEach(_agentPool.Where(p => p.Value.Id is not null), async x =>
|
||||
{
|
||||
var host = await _database.Host()
|
||||
.Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, x.Value.Id))
|
||||
.FirstOrDefaultAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (host is null) return;
|
||||
valid.Add(x.Value);
|
||||
});
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/Server/Insight.Server/appsettings.Development.json
Normal file
12
src/Server/Insight.Server/appsettings.Development.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"database": "mongodb://db.insight.local:27017",
|
||||
"agent.server.port": 3002,
|
||||
"agent.server.certificate": "localhost.pfx",
|
||||
"agent.server.certificate.password": "Webmatic12",
|
||||
|
||||
"web.server.port": 3001,
|
||||
"web.server.certificate": "localhost.pfx",
|
||||
"web.server.certificate.password": "Webmatic12",
|
||||
|
||||
"dispatch.webmatic": false
|
||||
}
|
||||
12
src/Server/Insight.Server/appsettings.json
Normal file
12
src/Server/Insight.Server/appsettings.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"database": "mongodb://127.0.0.1:27017",
|
||||
"agent.server.port": 3002,
|
||||
"agent.server.certificate": "localhost.pfx",
|
||||
"agent.server.certificate.password": "Webmatic12",
|
||||
|
||||
"web.server.port": 3001,
|
||||
"web.server.certificate": "localhost.pfx",
|
||||
"web.server.certificate.password": "Webmatic12",
|
||||
|
||||
"dispatch.webmatic": false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue