Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide X-Version response header for API endpoints #1355

Merged
merged 5 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/content/experimental/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ version:
- {{% tag added %}} New validation rule to ensure declarative or dynamic discovery for metrics to scrape are configured
- {{% tag added %}} New System API endpoint giving runtime information ([docs](https://promitor.io/operations/#system)
| [#1208](https://github.com/tomkerkhove/promitor/issues/1208))
- {{% tag added %}} Provide `X-Version` response header for API endpoints ([#1209](https://github.com/tomkerkhove/promitor/issues/1209))
- {{% tag added %}} Provide capability to tweak liveness/readines probes in Helm charts ([#1350](https://github.com/tomkerkhove/promitor/issues/1350))
- {{% tag changed %}} Show Promitor version during startup
- {{% tag changed %}} Provide capability to scrape all queues in Azure Service Bus, instead of having to declare the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Promitor.Agents.Core.Middleware;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerUI;

Expand All @@ -8,6 +9,16 @@ namespace Microsoft.AspNetCore.Builder
// ReSharper disable once InconsistentNaming
public static class IApplicationBuilderExtensions
{
/// <summary>
/// Adds middleware to automatically add the version in our responses
/// </summary>
public static IApplicationBuilder UseVersionMiddleware(this IApplicationBuilder app)
{
app.UseMiddleware<AgentVersionMiddleware>();

return app;
}

/// <summary>
/// Add support for Open API with API explorer
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions src/Promitor.Agents.Core/HttpHeaders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Promitor.Agents.Core
{
public class HttpHeaders
{
public const string AgentVersion = "X-Version";
}
}
41 changes: 41 additions & 0 deletions src/Promitor.Agents.Core/Middleware/AgentVersionMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Promitor.Core;

namespace Promitor.Agents.Core.Middleware
{
public class AgentVersionMiddleware
{
private readonly RequestDelegate _next;

/// <summary>
/// Initializes a new instance of the <see cref="AgentVersionMiddleware" /> class which automatically adds the version of the agent to all HTTP responses
/// </summary>
/// <param name="next">The next <see cref="RequestDelegate" /> in the ASP.NET Core request pipeline.</param>
/// <exception cref="System.ArgumentNullException">When the <paramref name="next" /> is <c>null</c>.</exception>
public AgentVersionMiddleware(RequestDelegate next)
{
_next = next;
}

/// <summary>
/// Invoke the middleware to automatically add version to HTTP responses.
/// </summary>
/// <param name="httpContext">The context for the current HTTP request.</param>
public async Task Invoke(HttpContext httpContext)
{
var version = Version.Get();

httpContext.Response.OnStarting(state =>
{
var context = (HttpContext)state;
context.Response.Headers.TryAdd(HttpHeaders.AgentVersion, version);

return Task.CompletedTask;
}, httpContext);

await _next(httpContext);
}
}
}
1 change: 1 addition & 0 deletions src/Promitor.Agents.ResourceDiscovery/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseExceptionHandling();
app.UseRequestTracking();
app.UseHttpCorrelation();
app.UseVersionMiddleware();
app.UseRouting();

app.ExposeOpenApiUi(ApiName);
Expand Down
2 changes: 2 additions & 0 deletions src/Promitor.Agents.Scraper/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseExceptionHandling()
.UseRequestTracking()
.UseHttpCorrelation()
.UseVersionMiddleware()
.UseRouting()
.UseMetricSinks(Configuration)
.ExposeOpenApiUi()
.UseEndpoints(endpoints => endpoints.MapControllers());

UseSerilog(ComponentName, app.ApplicationServices);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Net;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Promitor.Agents.Core;
using Promitor.Tests.Integration.Clients;
using Xunit;
using Xunit.Abstractions;
Expand All @@ -24,6 +26,8 @@ public async Task Health_Get_ReturnsOk()

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Promitor.Agents.Core;
using Promitor.Agents.ResourceDiscovery.Configuration;
using Promitor.Tests.Integration.Clients;
using Xunit;
Expand Down Expand Up @@ -33,5 +35,20 @@ public async Task ResourceDiscoveryGroup_GetAll_ReturnsValidList()
Assert.NotNull(resourceDiscoveryGroups);
Assert.NotEmpty(resourceDiscoveryGroups);
}

[Fact]
public async Task ResourceDiscoveryGroup_SuccessfulCall_ReturnsVersionHeader()
{
// Arrange
var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger);

// Act
var response = await resourceDiscoveryClient.GetResourceDiscoveryGroupsAsync();

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class ResourceDiscoveryIntegrationTest: IntegrationTest
public ResourceDiscoveryIntegrationTest(ITestOutputHelper testOutput) : base(testOutput)
{
}

public string ExpectedVersion => Configuration["Agents:ResourceDiscovery:Expectations:Version"];
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Bogus;
using Newtonsoft.Json;
using Promitor.Agents.Core;
using Promitor.Agents.ResourceDiscovery.Graph.Model;
using Promitor.Tests.Integration.Clients;
using Xunit;
Expand Down Expand Up @@ -31,6 +33,24 @@ public async Task ResourceDiscovery_GetForUnexistingResourceDiscoveryGroup_Retur

// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}

[Fact]
public async Task ResourceDiscovery_SuccessfulCall_ReturnsVersionHeader()
{
// Arrange
const string resourceDiscoveryGroupName = "logic-apps-unfiltered";
var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger);

// Act
var response = await resourceDiscoveryClient.GetDiscoveredResourcesAsync(resourceDiscoveryGroupName);

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Net;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Promitor.Agents.Core;
using Promitor.Agents.Core.Contracts;
using Promitor.Tests.Integration.Clients;
using Xunit;
Expand All @@ -19,7 +21,6 @@ public SystemTests(ITestOutputHelper testOutput)
public async Task System_GetInfo_ReturnsOk()
{
// Arrange
var expectedVersion = Configuration["Agents:ResourceDiscovery:Expectations:Version"];
var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger);

// Act
Expand All @@ -31,7 +32,9 @@ public async Task System_GetInfo_ReturnsOk()
Assert.NotEmpty(rawPayload);
var systemInfo = JsonConvert.DeserializeObject<SystemInfo>(rawPayload);
Assert.NotNull(systemInfo);
Assert.Equal(expectedVersion, systemInfo.Version);
Assert.Equal(ExpectedVersion, systemInfo.Version);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Net;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Promitor.Agents.Core;
using Promitor.Tests.Integration.Clients;
using Xunit;
using Xunit.Abstractions;
Expand All @@ -24,6 +26,8 @@ public async Task Health_Get_ReturnsOk()

// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class ScraperIntegrationTest: IntegrationTest
public ScraperIntegrationTest(ITestOutputHelper testOutput) : base(testOutput)
{
}

public string ExpectedVersion => Configuration["Agents:Scraper:Expectations:Version"];
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Net;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Promitor.Agents.Core;
using Promitor.Agents.Core.Contracts;
using Promitor.Tests.Integration.Clients;
using Xunit;
Expand All @@ -19,7 +21,6 @@ public SystemTests(ITestOutputHelper testOutput)
public async Task System_GetInfo_ReturnsOk()
{
// Arrange
var expectedVersion = Configuration["Agents:Scraper:Expectations:Version"];
var resourceDiscoveryClient = new ScraperClient(Configuration, Logger);

// Act
Expand All @@ -31,7 +32,9 @@ public async Task System_GetInfo_ReturnsOk()
Assert.NotEmpty(rawPayload);
var systemInfo = JsonConvert.DeserializeObject<SystemInfo>(rawPayload);
Assert.NotNull(systemInfo);
Assert.Equal(expectedVersion, systemInfo.Version);
Assert.Equal(ExpectedVersion, systemInfo.Version);
Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion));
Assert.Equal(ExpectedVersion, response.Headers.GetValues(HttpHeaders.AgentVersion).First());
}
}
}