From 21a6a22a9e3d8f0731be468d3b6ac59c9536b9a0 Mon Sep 17 00:00:00 2001 From: dsokolovrudakov Date: Wed, 19 Feb 2025 23:02:15 +0200 Subject: [PATCH 1/2] Program.cs cleanup, HiveModel change, log level change Clean up HiveMind Minimal API setup - move configuration to extenstion methods, same for CommunicationControl, move RequestSchema for Hive to HiveModel, make ComControl use it, set minimum log level for files to Information --- .../Services/CommunicationControlService.cs | 4 +- .../DI/ApiVersioningConfiguration.cs | 29 +++++++++ .../DI/CorsConfiguration.cs | 21 +++++++ .../DI/HttpClientsConfiguration.cs | 21 +++++++ .../DI/OptionsConfiguration.cs | 14 +++++ .../DevOpsProject.HiveMind.API/Program.cs | 47 +++------------ .../appsettings.json | 2 +- .../Services/HiveMindService.cs | 4 +- .../ComControlCommunicationConfiguration.cs | 1 - .../Models/HiveConnectRequest.cs | 9 +-- .../DevOpsProject.Shared/Models/HiveModel.cs | 1 + .../Controllers/HiveController.cs | 1 + .../DI/ApiVersioningConfiguration.cs | 27 +++++++++ .../DevOpsProject/DI/CorsConfiguration.cs | 21 +++++++ .../DI/HttpClientsConfiguration.cs | 20 +++++++ .../DI/JsonControllerOptionsConfiguration.cs | 15 +++++ .../DevOpsProject/DI/OptionsConfiguration.cs | 16 +++++ .../DevOpsProject/Program.cs | 59 ++----------------- .../DevOpsProject/appsettings.json | 4 +- 19 files changed, 207 insertions(+), 109 deletions(-) create mode 100644 src/CommunicationControl/DevOpsProject.HiveMind.API/DI/ApiVersioningConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject.HiveMind.API/DI/CorsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject.HiveMind.API/DI/HttpClientsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject.HiveMind.API/DI/OptionsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject/DI/ApiVersioningConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject/DI/CorsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject/DI/HttpClientsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject/DI/JsonControllerOptionsConfiguration.cs create mode 100644 src/CommunicationControl/DevOpsProject/DI/OptionsConfiguration.cs diff --git a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs index 2e1a753..dea50b7 100644 --- a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs +++ b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs @@ -141,8 +141,8 @@ namespace DevOpsProject.CommunicationControl.Logic.Services Timestamp = DateTime.Now }; - var result = await _hiveHttpClient.SendHiveControlCommandAsync(_communicationControlConfiguration.CurrentValue.RequestScheme, - hive.HiveIP, hive.HivePort, _communicationControlConfiguration.CurrentValue.HiveMindPath, command); + var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort, + _communicationControlConfiguration.CurrentValue.HiveMindPath, command); isSuccessfullySent = true; return result; } diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/ApiVersioningConfiguration.cs b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/ApiVersioningConfiguration.cs new file mode 100644 index 0000000..8ad0c38 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/ApiVersioningConfiguration.cs @@ -0,0 +1,29 @@ +using DevOpsProject.HiveMind.Logic.Services.Interfaces; +using DevOpsProject.HiveMind.Logic.Services; +using Asp.Versioning; + +namespace DevOpsProject.HiveMind.API.DI +{ + public static class ApiVersioningConfiguration + { + public static IServiceCollection AddApiVersioningConfiguration(this IServiceCollection serviceCollection) + { + serviceCollection.AddApiVersioning(options => + { + options.DefaultApiVersion = new ApiVersion(1, 0); + options.AssumeDefaultVersionWhenUnspecified = true; + options.ReportApiVersions = true; + options.ApiVersionReader = ApiVersionReader.Combine( + new UrlSegmentApiVersionReader(), + new HeaderApiVersionReader("X-Api-Version") + ); + }).AddApiExplorer(options => + { + options.GroupNameFormat = "'v'VVV"; + options.SubstituteApiVersionInUrl = true; + }); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/CorsConfiguration.cs b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/CorsConfiguration.cs new file mode 100644 index 0000000..6544b85 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/CorsConfiguration.cs @@ -0,0 +1,21 @@ +namespace DevOpsProject.HiveMind.API.DI +{ + public static class CorsConfiguration + { + public static IServiceCollection AddCorsConfiguration(this IServiceCollection serviceCollection, string corsPolicyName) + { + serviceCollection.AddCors(options => + { + options.AddPolicy(name: corsPolicyName, + policy => + { + policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins + .AllowAnyMethod() + .AllowAnyHeader(); + }); + }); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/HttpClientsConfiguration.cs b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/HttpClientsConfiguration.cs new file mode 100644 index 0000000..c1ffa3e --- /dev/null +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/HttpClientsConfiguration.cs @@ -0,0 +1,21 @@ +using DevOpsProject.Shared.Clients; +using Polly.Extensions.Http; +using Polly; + +namespace DevOpsProject.HiveMind.API.DI +{ + public static class HttpClientsConfiguration + { + public static IServiceCollection AddHttpClientsConfiguration(this IServiceCollection serviceCollection) + { + var communicationControlTelemetryPolicy = HttpPolicyExtensions + .HandleTransientHttpError() + .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + serviceCollection.AddHttpClient() + .AddPolicyHandler(communicationControlTelemetryPolicy); + serviceCollection.AddHttpClient("HiveConnectClient"); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/OptionsConfiguration.cs b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/OptionsConfiguration.cs new file mode 100644 index 0000000..701b349 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/DI/OptionsConfiguration.cs @@ -0,0 +1,14 @@ +using DevOpsProject.Shared.Configuration; + +namespace DevOpsProject.HiveMind.API.DI +{ + public static class OptionsConfiguration + { + public static IServiceCollection AddOptionsConfiguration(this IServiceCollection serviceCollection, IConfiguration configuration) + { + serviceCollection.Configure(configuration.GetSection("CommunicationConfiguration")); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/Program.cs b/src/CommunicationControl/DevOpsProject.HiveMind.API/Program.cs index 65003c5..013786e 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.API/Program.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/Program.cs @@ -3,13 +3,10 @@ using Asp.Versioning.Builder; using DevOpsProject.HiveMind.API.DI; using DevOpsProject.HiveMind.API.Middleware; using DevOpsProject.HiveMind.Logic.Services.Interfaces; -using DevOpsProject.Shared.Clients; using DevOpsProject.Shared.Configuration; using DevOpsProject.Shared.Models; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; -using Polly; -using Polly.Extensions.Http; using Serilog; var builder = WebApplication.CreateBuilder(args); @@ -19,52 +16,23 @@ builder.Host.UseSerilog((context, services, loggerConfig) => .ReadFrom.Services(services) .Enrich.FromLogContext()); -builder.Services.AddApiVersioning(options => -{ - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = true; - options.ReportApiVersions = true; - options.ApiVersionReader = ApiVersionReader.Combine( - new UrlSegmentApiVersionReader(), - new HeaderApiVersionReader("X-Api-Version") - ); -}).AddApiExplorer(options => -{ - options.GroupNameFormat = "'v'VVV"; - options.SubstituteApiVersionInUrl = true; -}); +builder.Services.AddApiVersioningConfiguration(); -// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddAuthorization(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "HiveMind - V1", Version = "v1.0" }); }); + +builder.Services.AddOptionsConfiguration(builder.Configuration); + builder.Services.AddHiveMindLogic(); -builder.Services.Configure(builder.Configuration.GetSection("CommunicationConfiguration")); - -var communicationControlTelemetryPolicy = HttpPolicyExtensions - .HandleTransientHttpError() - .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); -builder.Services.AddHttpClient() - .AddPolicyHandler(communicationControlTelemetryPolicy); - -// register NAMED client for connect request -builder.Services.AddHttpClient("HiveConnectClient"); +builder.Services.AddHttpClientsConfiguration(); string corsPolicyName = "HiveMindCorsPolicy"; -builder.Services.AddCors(options => -{ - options.AddPolicy(name: corsPolicyName, - policy => - { - policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins - .AllowAnyMethod() - .AllowAnyHeader(); - }); -}); +builder.Services.AddCorsConfiguration(corsPolicyName); builder.Services.AddExceptionHandler(); builder.Services.AddProblemDetails(); @@ -82,7 +50,7 @@ using (var scope = app.Services.CreateScope()) catch (Exception ex) { logger.LogError($"Error occured while connecting Hive to Communication Control. \nException text: {ex.Message}"); - System.Diagnostics.Process.GetCurrentProcess().Kill(); + Environment.Exit(1); } } @@ -105,7 +73,6 @@ ApiVersionSet apiVersionSet = app.NewApiVersionSet() .HasApiVersion(new ApiVersion(1)) .ReportApiVersions() .Build(); - RouteGroupBuilder groupBuilder = app.MapGroup("api/v{apiVersion:apiVersion}").WithApiVersionSet(apiVersionSet); groupBuilder.MapGet("ping", (IOptionsSnapshot config) => diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.API/appsettings.json b/src/CommunicationControl/DevOpsProject.HiveMind.API/appsettings.json index f12b9a4..376b264 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.API/appsettings.json +++ b/src/CommunicationControl/DevOpsProject.HiveMind.API/appsettings.json @@ -38,7 +38,7 @@ "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact", - "restrictedToMinimumLevel": "Warning" + "restrictedToMinimumLevel": "Information" } } ], diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs index 4d3204f..6bf94d2 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs @@ -31,6 +31,7 @@ namespace DevOpsProject.HiveMind.Logic.Services { var request = new HiveConnectRequest { + HiveSchema = _communicationConfigurationOptions.RequestSchema, HiveIP = _communicationConfigurationOptions.HiveIP, HivePort = _communicationConfigurationOptions.HivePort, HiveID = _communicationConfigurationOptions.HiveID @@ -68,7 +69,6 @@ namespace DevOpsProject.HiveMind.Logic.Services HiveInMemoryState.OperationalArea = hiveConnectResponse.OperationalArea; HiveInMemoryState.CurrentLocation = _communicationConfigurationOptions.InitialLocation; - // HERE - we are starting to send telemetry StartTelemetry(); } else @@ -80,7 +80,7 @@ namespace DevOpsProject.HiveMind.Logic.Services else { _logger.LogError($"Failed to connect hive, terminating process"); - System.Diagnostics.Process.GetCurrentProcess().Kill(); + Environment.Exit(1); } } diff --git a/src/CommunicationControl/DevOpsProject.Shared/Configuration/ComControlCommunicationConfiguration.cs b/src/CommunicationControl/DevOpsProject.Shared/Configuration/ComControlCommunicationConfiguration.cs index 731d58d..e70b84b 100644 --- a/src/CommunicationControl/DevOpsProject.Shared/Configuration/ComControlCommunicationConfiguration.cs +++ b/src/CommunicationControl/DevOpsProject.Shared/Configuration/ComControlCommunicationConfiguration.cs @@ -2,7 +2,6 @@ { public class ComControlCommunicationConfiguration { - public string RequestScheme { get; set; } public string HiveMindPath { get; set; } } } diff --git a/src/CommunicationControl/DevOpsProject.Shared/Models/HiveConnectRequest.cs b/src/CommunicationControl/DevOpsProject.Shared/Models/HiveConnectRequest.cs index 86a2570..4776bc7 100644 --- a/src/CommunicationControl/DevOpsProject.Shared/Models/HiveConnectRequest.cs +++ b/src/CommunicationControl/DevOpsProject.Shared/Models/HiveConnectRequest.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DevOpsProject.Shared.Models +namespace DevOpsProject.Shared.Models { public class HiveConnectRequest { + public string HiveSchema { get; set; } public string HiveIP { get; set; } public int HivePort { get; set; } public string HiveID { get; set; } diff --git a/src/CommunicationControl/DevOpsProject.Shared/Models/HiveModel.cs b/src/CommunicationControl/DevOpsProject.Shared/Models/HiveModel.cs index 9a77869..174dca2 100644 --- a/src/CommunicationControl/DevOpsProject.Shared/Models/HiveModel.cs +++ b/src/CommunicationControl/DevOpsProject.Shared/Models/HiveModel.cs @@ -5,6 +5,7 @@ public string HiveID { get; set; } public string HiveIP { get; set; } public int HivePort { get; set; } + public string HiveSchema { get; set; } public HiveTelemetryModel Telemetry { get; set; } } } diff --git a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs index 4e4cd00..c346207 100644 --- a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs +++ b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs @@ -25,6 +25,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers HiveID = request.HiveID, HiveIP = request.HiveIP, HivePort = request.HivePort, + HiveSchema = request.HiveSchema }; var hiveOperationalArea = await _communicationControlService.ConnectHive(hiveModel); diff --git a/src/CommunicationControl/DevOpsProject/DI/ApiVersioningConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/ApiVersioningConfiguration.cs new file mode 100644 index 0000000..8886291 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject/DI/ApiVersioningConfiguration.cs @@ -0,0 +1,27 @@ +using Asp.Versioning; + +namespace DevOpsProject.CommunicationControl.API.DI +{ + public static class ApiVersioningConfiguration + { + public static IServiceCollection AddApiVersioningConfiguration(this IServiceCollection serviceCollection) + { + serviceCollection.AddApiVersioning(options => + { + options.DefaultApiVersion = new ApiVersion(1, 0); + options.AssumeDefaultVersionWhenUnspecified = true; + options.ReportApiVersions = true; + options.ApiVersionReader = ApiVersionReader.Combine( + new UrlSegmentApiVersionReader(), + new HeaderApiVersionReader("X-Api-Version") + ); + }).AddApiExplorer(options => + { + options.GroupNameFormat = "'v'VVV"; + options.SubstituteApiVersionInUrl = true; + }); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject/DI/CorsConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/CorsConfiguration.cs new file mode 100644 index 0000000..efb3832 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject/DI/CorsConfiguration.cs @@ -0,0 +1,21 @@ +namespace DevOpsProject.CommunicationControl.API.DI +{ + public static class CorsConfiguration + { + public static IServiceCollection AddCorsConfiguration(this IServiceCollection serviceCollection, string corsPolicyName) + { + serviceCollection.AddCors(options => + { + options.AddPolicy(name: corsPolicyName, + policy => + { + policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins + .AllowAnyMethod() + .AllowAnyHeader(); + }); + }); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject/DI/HttpClientsConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/HttpClientsConfiguration.cs new file mode 100644 index 0000000..ddced4d --- /dev/null +++ b/src/CommunicationControl/DevOpsProject/DI/HttpClientsConfiguration.cs @@ -0,0 +1,20 @@ +using DevOpsProject.Shared.Clients; +using Polly; +using Polly.Extensions.Http; + +namespace DevOpsProject.CommunicationControl.API.DI +{ + public static class HttpClientsConfiguration + { + public static IServiceCollection AddHttpClientsConfiguration(this IServiceCollection serviceCollection) + { + var hiveRetryPolicy = HttpPolicyExtensions + .HandleTransientHttpError() + .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); + serviceCollection.AddHttpClient() + .AddPolicyHandler(hiveRetryPolicy); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject/DI/JsonControllerOptionsConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/JsonControllerOptionsConfiguration.cs new file mode 100644 index 0000000..c797ad6 --- /dev/null +++ b/src/CommunicationControl/DevOpsProject/DI/JsonControllerOptionsConfiguration.cs @@ -0,0 +1,15 @@ +namespace DevOpsProject.CommunicationControl.API.DI +{ + public static class JsonControllerOptionsConfiguration + { + public static IServiceCollection AddJsonControllerOptionsConfiguration(this IServiceCollection serviceCollection) + { + serviceCollection.AddControllers().AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNamingPolicy = null; + }); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject/DI/OptionsConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/OptionsConfiguration.cs new file mode 100644 index 0000000..dcf856b --- /dev/null +++ b/src/CommunicationControl/DevOpsProject/DI/OptionsConfiguration.cs @@ -0,0 +1,16 @@ +using DevOpsProject.Shared.Configuration; +using DevOpsProject.Shared.Models; + +namespace DevOpsProject.CommunicationControl.API.DI +{ + public static class OptionsConfiguration + { + public static IServiceCollection AddOptionsConfiguration(this IServiceCollection serviceCollection, IConfiguration configuration) + { + serviceCollection.Configure(configuration.GetSection("OperationalArea")); + serviceCollection.Configure(configuration.GetSection("CommunicationConfiguration")); + + return serviceCollection; + } + } +} diff --git a/src/CommunicationControl/DevOpsProject/Program.cs b/src/CommunicationControl/DevOpsProject/Program.cs index 3b276c9..46db467 100644 --- a/src/CommunicationControl/DevOpsProject/Program.cs +++ b/src/CommunicationControl/DevOpsProject/Program.cs @@ -1,13 +1,6 @@ -using Asp.Versioning; using DevOpsProject.CommunicationControl.API.DI; using DevOpsProject.CommunicationControl.API.Middleware; -using DevOpsProject.Shared.Clients; -using DevOpsProject.Shared.Configuration; -using DevOpsProject.Shared.Models; -using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; -using Polly; -using Polly.Extensions.Http; using Serilog; internal class Program @@ -21,26 +14,11 @@ internal class Program .ReadFrom.Services(services) .Enrich.FromLogContext()); - builder.Services.AddApiVersioning(options => - { - options.DefaultApiVersion = new ApiVersion(1, 0); - options.AssumeDefaultVersionWhenUnspecified = true; - options.ReportApiVersions = true; - options.ApiVersionReader = ApiVersionReader.Combine( - new UrlSegmentApiVersionReader(), - new HeaderApiVersionReader("X-Api-Version") - ); - }).AddApiExplorer(options => - { - options.GroupNameFormat = "'v'VVV"; - options.SubstituteApiVersionInUrl = true; - }); + builder.Services.AddApiVersioningConfiguration(); // TODO: consider this approach - builder.Services.AddControllers().AddJsonOptions(options => - { - options.JsonSerializerOptions.PropertyNamingPolicy = null; - }); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddJsonControllerOptionsConfiguration(); + builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { @@ -52,36 +30,12 @@ internal class Program builder.Services.AddRedis(builder.Configuration); builder.Services.AddCommunicationControlLogic(); - builder.Services.Configure(builder.Configuration.GetSection("OperationalArea")); - builder.Services.Configure(builder.Configuration.GetSection("CommunicationConfiguration")); - - var hiveRetryPolicy = HttpPolicyExtensions - .HandleTransientHttpError() - .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); - builder.Services.AddHttpClient() - .AddPolicyHandler(hiveRetryPolicy); + builder.Services.AddOptionsConfiguration(builder.Configuration); + builder.Services.AddHttpClientsConfiguration(); var corsPolicyName = "AllowReactApp"; - var localCorsPolicyName = "AllowLocalHtml"; - builder.Services.AddCors(options => - { - options.AddPolicy(name: corsPolicyName, - policy => - { - policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins - .AllowAnyMethod() - .AllowAnyHeader(); - }); - - options.AddPolicy(name: localCorsPolicyName, - policy => - { - policy.AllowAnyOrigin() //SECURITY WARNING ! Never allow all origins - .AllowAnyMethod() - .AllowAnyHeader(); - }); - }); + builder.Services.AddCorsConfiguration(corsPolicyName); builder.Services.AddExceptionHandler(); builder.Services.AddProblemDetails(); @@ -97,7 +51,6 @@ internal class Program } app.UseCors(corsPolicyName); - //app.UseCors(localCorsPolicyName); app.UseAuthorization(); diff --git a/src/CommunicationControl/DevOpsProject/appsettings.json b/src/CommunicationControl/DevOpsProject/appsettings.json index 16d1344..882ad53 100644 --- a/src/CommunicationControl/DevOpsProject/appsettings.json +++ b/src/CommunicationControl/DevOpsProject/appsettings.json @@ -14,10 +14,8 @@ "InitialSpeed_KM": 5, "TelemetryInterval_MS": 30000, "PingInterval_MS": 15000 - }, "CommunicationConfiguration": { - "RequestScheme": "http", "HiveMindPath": "api/v1" }, "AllowedHosts": "*", @@ -45,7 +43,7 @@ "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact", - "restrictedToMinimumLevel": "Warning" + "restrictedToMinimumLevel": "Information" } } ], From 9329d76ab627b5c832d4c3bd96b02366d128a6ad Mon Sep 17 00:00:00 2001 From: dsokolovrudakov Date: Thu, 20 Feb 2025 00:05:33 +0200 Subject: [PATCH 2/2] Fix returned status codes depending on scenario, provide informative logs Extend logic of encpoints to provide more informative status codes on different scenarios (not found, bad request, etc). Update logging to write structured and informative logs --- .../Services/CommunicationControlService.cs | 90 ++++++++++--------- .../ICommunicationControlService.cs | 1 + .../Services/HiveMindMovingService.cs | 10 +-- .../Services/HiveMindService.cs | 2 + .../Exceptions/HiveNotFoundException.cs | 19 ---- .../Controllers/ClientController.cs | 13 ++- .../Controllers/HiveController.cs | 31 +++++-- .../DevOpsProject/DI/LogicConfiguration.cs | 2 - 8 files changed, 89 insertions(+), 79 deletions(-) delete mode 100644 src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs diff --git a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs index dea50b7..5e0b449 100644 --- a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs +++ b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/CommunicationControlService.cs @@ -37,7 +37,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services bool isSuccessfullyDisconnected = false; try { - var result = await _redisService.DeleteAsync(hiveId); + var result = await _redisService.DeleteAsync(GetHiveKey(hiveId)); isSuccessfullyDisconnected = result; return result; } @@ -65,9 +65,11 @@ namespace DevOpsProject.CommunicationControl.Logic.Services public async Task ConnectHive(HiveModel model) { + _logger.LogInformation("Trying to connect Hive: {@model}", model); bool result = await _redisService.SetAsync(GetHiveKey(model.HiveID), model); if (result) { + _logger.LogInformation("Successfully connected Hive: {@model}", model); var operationalArea = _spatialService.GetHiveOperationalArea(model); await _messageBus.Publish(new HiveConnectedMessage { @@ -80,46 +82,41 @@ namespace DevOpsProject.CommunicationControl.Logic.Services } else { - await _messageBus.Publish(new HiveConnectedMessage - { - HiveID = model.HiveID, - Hive = model, - IsSuccessfullyConnected = result - }); + _logger.LogError("Failed to connect Hive: {@model}", model); throw new HiveConnectionException($"Failed to connect hive for HiveId: {model.HiveID}"); } } + public async Task IsHiveConnected(string hiveId) + { + string hiveKey = GetHiveKey(hiveId); + return await _redisService.CheckIfKeyExists(hiveKey); + } + public async Task AddTelemetry(HiveTelemetryModel model) { string hiveKey = GetHiveKey(model.HiveID); - bool hiveExists = await _redisService.CheckIfKeyExists(hiveKey); - if (hiveExists) + bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) => { - bool result = await _redisService.UpdateAsync(hiveKey, (HiveModel hive) => - { - hive.Telemetry = model; - }); + hive.Telemetry = model; + }); - await _messageBus.Publish(new TelemetrySentMessage - { - HiveID = model.HiveID, - Telemetry = model, - IsSuccessfullySent = result - }); - return model.Timestamp; + if (result) + { + _logger.LogInformation("Telemetry updated for HiveID: {hiveId}. Updated telemetry timestamp: {timestamp}", model.HiveID, model.Timestamp); } else { - await _messageBus.Publish(new TelemetrySentMessage - { - HiveID = model.HiveID, - Telemetry = model, - IsSuccessfullySent = false - }); - throw new HiveNotFoundException($"Hive not found for id: {model.HiveID}"); + _logger.LogError("Failed to update Telemetry - Redis update issue. HiveID: {hiveId}, Telemetry model: {@telemetry}", model.HiveID, model); } + await _messageBus.Publish(new TelemetrySentMessage + { + HiveID = model.HiveID, + Telemetry = model, + IsSuccessfullySent = result + }); + return model.Timestamp; } public async Task SendHiveControlSignal(string hiveId, Location destination) @@ -127,33 +124,40 @@ namespace DevOpsProject.CommunicationControl.Logic.Services var hive = await GetHiveModel(hiveId); if (hive == null) { - throw new Exception($"Hive control signal error: cannot find hive with id: {hiveId}"); + _logger.LogError("Sending Hive Control signal: Hive not found for HiveID: {hiveId}", hiveId); + return null; } bool isSuccessfullySent = false; - + string hiveMindPath = _communicationControlConfiguration.CurrentValue.HiveMindPath; + var command = new MoveHiveMindCommand + { + CommandType = State.Move, + Location = destination, + Timestamp = DateTime.Now + }; try { - var command = new MoveHiveMindCommand - { - CommandType = State.Move, - Location = destination, - Timestamp = DateTime.Now - }; - - var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort, - _communicationControlConfiguration.CurrentValue.HiveMindPath, command); + var result = await _hiveHttpClient.SendHiveControlCommandAsync(hive.HiveSchema, hive.HiveIP, hive.HivePort, hiveMindPath, command); isSuccessfullySent = true; return result; } finally { - await _messageBus.Publish(new MoveHiveMessage + if (isSuccessfullySent) { - IsSuccessfullySent = isSuccessfullySent, - Destination = destination, - HiveID = hiveId - }); + await _messageBus.Publish(new MoveHiveMessage + { + IsSuccessfullySent = isSuccessfullySent, + Destination = destination, + HiveID = hiveId + }); + } + else + { + _logger.LogError("Failed to send control command for Hive: {@hive}, path: {path}, \n Command: {@command}", hive, hiveMindPath, command); + } + } } diff --git a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs index 86445cf..6569990 100644 --- a/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs +++ b/src/CommunicationControl/DevOpsProject.CommunicationControl.Logic/Services/Interfaces/ICommunicationControlService.cs @@ -8,6 +8,7 @@ namespace DevOpsProject.CommunicationControl.Logic.Services.Interfaces Task GetHiveModel(string hiveId); Task> GetAllHives(); Task ConnectHive(HiveModel model); + Task IsHiveConnected(string hiveId); Task AddTelemetry(HiveTelemetryModel model); Task SendHiveControlSignal(string hiveId, Location destination); } diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs index 5633e8a..553e89b 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindMovingService.cs @@ -27,6 +27,7 @@ namespace DevOpsProject.HiveMind.Logic.Services // If already moving - stop movement if (HiveInMemoryState.IsMoving) { + _logger.LogWarning("Previous movement command terminated. Previous destination: {@destination}, Current Location: {@current}, new destination: {@destination}", HiveInMemoryState.Destination, HiveInMemoryState.CurrentLocation, destination); StopMovement(); } @@ -39,8 +40,9 @@ namespace DevOpsProject.HiveMind.Logic.Services if (_movementTimer == null) { // TODO: Recalculating position each N seconds - _movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(3)); - _logger.LogInformation("Movement timer started."); + int intervalFromSeconds = 3; + _movementTimer = new Timer(UpdateMovement, null, TimeSpan.Zero, TimeSpan.FromSeconds(intervalFromSeconds)); + _logger.LogInformation("Movement timer started. Destination: {@destination}, recalculation interval: {interval}", destination, intervalFromSeconds); } } } @@ -60,14 +62,13 @@ namespace DevOpsProject.HiveMind.Logic.Services if (AreLocationsEqual(currentLocation.Value, destination.Value)) { + _logger.LogInformation("Reached destination. Current location: {@currentLocation}, Destination: {@destination}", currentLocation, destination); StopMovement(); return; } Location newLocation = CalculateNextPosition(currentLocation.Value, destination.Value, 0.1f); HiveInMemoryState.CurrentLocation = newLocation; - - _logger.LogInformation($"Moved closer: {newLocation}"); } } @@ -77,7 +78,6 @@ namespace DevOpsProject.HiveMind.Logic.Services _movementTimer = null; HiveInMemoryState.IsMoving = false; HiveInMemoryState.Destination = null; - _logger.LogInformation("Movement stopped: Reached destination."); } private static bool AreLocationsEqual(Location loc1, Location loc2) diff --git a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs index 6bf94d2..df1c01d 100644 --- a/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs +++ b/src/CommunicationControl/DevOpsProject.HiveMind.Logic/Services/HiveMindService.cs @@ -48,6 +48,8 @@ namespace DevOpsProject.HiveMind.Logic.Services }; var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); + _logger.LogInformation("Attempting to connect Hive. Request: {@request}, URI: {uri}", request, uriBuilder.Uri); + var retryPolicy = Policy.HandleResult(r => !r.IsSuccessStatusCode) .WaitAndRetryAsync( 10, diff --git a/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs b/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs deleted file mode 100644 index ada24fa..0000000 --- a/src/CommunicationControl/DevOpsProject.Shared/Exceptions/HiveNotFoundException.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace DevOpsProject.Shared.Exceptions -{ - public class HiveNotFoundException : Exception - { - public HiveNotFoundException() - { - } - - public HiveNotFoundException(string message) - : base(message) - { - } - - public HiveNotFoundException(string message, Exception inner) - : base(message, inner) - { - } - } -} diff --git a/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs b/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs index 0798b0d..1a4200f 100644 --- a/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs +++ b/src/CommunicationControl/DevOpsProject/Controllers/ClientController.cs @@ -32,17 +32,21 @@ namespace DevOpsProject.CommunicationControl.API.Controllers [HttpGet("hive/{hiveId}")] public async Task GetHive(string hiveId) { - var hiveModel = await _communicationControlService.GetHiveModel(hiveId); + var hiveExists = await _communicationControlService.IsHiveConnected(hiveId); + if (!hiveExists) + { + _logger.LogWarning("Failed to get Hive for HiveID: {hiveId}", hiveId); + return NotFound($"Hive with HiveID: {hiveId} is not found"); + } + var hiveModel = await _communicationControlService.GetHiveModel(hiveId); return Ok(hiveModel); } [HttpGet("hive")] public async Task GetHives() { - var hives = await _communicationControlService.GetAllHives(); - return Ok(hives); } @@ -59,6 +63,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers if (request?.Hives == null || !request.Hives.Any()) return BadRequest("No hive IDs provided."); + _logger.LogInformation("Hive moving request accepted by enpdoint. Request: {@request}", request); foreach (var id in request.Hives) { _ = Task.Run(async () => @@ -69,7 +74,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers } catch (Exception ex) { - _logger.LogError(ex, $"Failed to send control signal for HiveID: {id}"); + _logger.LogError(ex, "Failed to send control signal for HiveID: {id} \n Request: {@request}", id, request); } }); } diff --git a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs index c346207..8c3bf9c 100644 --- a/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs +++ b/src/CommunicationControl/DevOpsProject/Controllers/HiveController.cs @@ -11,10 +11,12 @@ namespace DevOpsProject.CommunicationControl.API.Controllers public class HiveController : Controller { private readonly ICommunicationControlService _communicationControlService; + private readonly ILogger _logger; - public HiveController(ICommunicationControlService communicationControlService) + public HiveController(ICommunicationControlService communicationControlService, ILogger logger) { _communicationControlService = communicationControlService; + _logger = logger; } [HttpPost("connect")] @@ -28,6 +30,13 @@ namespace DevOpsProject.CommunicationControl.API.Controllers HiveSchema = request.HiveSchema }; + bool isConnected = await _communicationControlService.IsHiveConnected(request.HiveID); + if (isConnected) + { + _logger.LogError("Hive with HiveID: {hiveId} already connected. Request: {@request}", request.HiveID, request); + return BadRequest($"Hive with HiveID: {request.HiveID} already connected"); + } + var hiveOperationalArea = await _communicationControlService.ConnectHive(hiveModel); var connectResponse = new HiveConnectResponse { @@ -36,6 +45,7 @@ namespace DevOpsProject.CommunicationControl.API.Controllers }; return Ok(connectResponse); + } [HttpPost("telemetry")] @@ -51,13 +61,22 @@ namespace DevOpsProject.CommunicationControl.API.Controllers Timestamp = DateTime.Now }; - var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel); - var telemetryResponse = new HiveTelemetryResponse + bool isHiveConnected = await _communicationControlService.IsHiveConnected(request.HiveID); + if (isHiveConnected) { - Timestamp = telemetryUpdateTimestamp - }; + var telemetryUpdateTimestamp = await _communicationControlService.AddTelemetry(hiveTelemetryModel); + var telemetryResponse = new HiveTelemetryResponse + { + Timestamp = telemetryUpdateTimestamp + }; - return Ok(telemetryResponse); + return Ok(telemetryResponse); + } + else + { + _logger.LogWarning("Failed to write telemetry. Hive with HiveID: {hiveId} is not connected. Request: {@request}", request.HiveID, request); + return NotFound($"Failed to write telemetry. Hive with HiveID: {request.HiveID} is not connected"); + } } } diff --git a/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs b/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs index e5bfa63..e55cf46 100644 --- a/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs +++ b/src/CommunicationControl/DevOpsProject/DI/LogicConfiguration.cs @@ -12,7 +12,5 @@ namespace DevOpsProject.CommunicationControl.API.DI return serviceCollection; } - - } }