initial upload

This commit is contained in:
kkb 2023-09-21 18:58:32 +02:00
parent a0aa9cc28e
commit f857f43df4
553 changed files with 46169 additions and 13 deletions

View 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";
}
}

View 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;
}
}
}

View file

@ -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);
}
}
}

View 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>

View 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
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View file

@ -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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}

View 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;
}
}
}

View file

@ -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);
}
}
}

View 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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}

View 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);
}
}

View 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);
}
}
}

View file

@ -0,0 +1,14 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"Development": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Production": {
"commandName": "Project"
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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
}

View 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
}