public void Constructor_BindsConfigurationCorrectly() { var appsettings = new Dictionary <string, string>() { ["management:endpoints:enabled"] = "false", ["management:endpoints:path"] = "/cloudfoundryapplication", ["management:endpoints:health:enabled"] = "true", ["management:endpoints:health:requiredPermissions"] = "NONE", ["management:endpoints:cloudfoundry:validatecertificates"] = "true", ["management:endpoints:cloudfoundry:enabled"] = "true" }; ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(appsettings); var config = configurationBuilder.Build(); var opts = new HealthEndpointOptions(config); var cloudOpts = new CloudFoundryEndpointOptions(config); Assert.True(cloudOpts.Enabled); Assert.Equal(string.Empty, cloudOpts.Id); Assert.Equal(string.Empty, cloudOpts.Path); Assert.True(cloudOpts.ValidateCertificates); Assert.True(opts.Enabled); Assert.Equal("health", opts.Id); Assert.Equal("health", opts.Path); Assert.Equal(Permissions.NONE, opts.RequiredPermissions); }
public void Invoke_HandlesExceptions_ReturnsExpectedHealth() { var opts = new HealthEndpointOptions(); var contributors = new List <IHealthContributor>() { new TestContrib("h1"), new TestContrib("h2", true), new TestContrib("h3") }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contributors); var info = ep.Invoke(null); foreach (var contrib in contributors) { TestContrib tc = (TestContrib)contrib; if (tc.Throws) { Assert.False(tc.Called); } else { Assert.True(tc.Called); } } Assert.Equal(HealthStatus.UP, info.Status); }
public async Task SpringBootAdminClient_RegistersAndDeletes() { var appsettings = new Dictionary <string, string>() { ["management:endpoints:path"] = "/management", ["management:endpoints:health:path"] = "myhealth", ["URLS"] = "http://localhost:8080;https://localhost:8082", ["spring:boot:admin:client:url"] = "http://springbootadmin:9090", ["spring:application:name"] = "MySteeltoeApplication", }; var config = new ConfigurationBuilder().AddInMemoryCollection(appsettings).Build(); var appInfo = new ApplicationInstanceInfo(config); var sbaOptions = new SpringBootAdminClientOptions(config, appInfo); var mgmtOptions = new ManagementEndpointOptions(config); var healthOptions = new HealthEndpointOptions(config); var httpMessageHandler = new MockHttpMessageHandler(); httpMessageHandler .Expect(HttpMethod.Post, "http://springbootadmin:9090/instances") .Respond("application/json", "{\"Id\":\"1234567\"}"); httpMessageHandler .Expect(HttpMethod.Delete, "http://springbootadmin:9090/instances/1234567") .Respond(req => new HttpResponseMessage(HttpStatusCode.NoContent)); Assert.Null(SpringBootAdminClientHostedService.RegistrationResult); var service = new SpringBootAdminClientHostedService(sbaOptions, mgmtOptions, healthOptions, httpMessageHandler.ToHttpClient()); await service.StartAsync(default);
#pragma warning disable S107 // Methods should not have too many parameters public static void UseCloudFoundryActuators(this IAppBuilder app, IConfiguration configuration, IEnumerable <IHealthContributor> healthContributors, IApiExplorer apiExplorer, ILoggerProvider loggerProvider, ILoggerFactory loggerFactory, MediaTypeVersion version, ActuatorContext context) #pragma warning restore S107 // Methods should not have too many parameters { app.UseDiagnosticSourceMiddleware(loggerFactory); if (context != ActuatorContext.Actuator) { app.UseCloudFoundrySecurityMiddleware(configuration, loggerFactory); app.UseCloudFoundryActuator(configuration, loggerFactory); } if (context != ActuatorContext.CloudFoundry) { app.UseHypermediaActuator(configuration, loggerFactory); } if (Environment.OSVersion.Platform == PlatformID.Win32NT) { app.UseThreadDumpActuator(configuration, loggerFactory, version); app.UseHeapDumpActuator(configuration, null, loggerFactory); } app.UseInfoActuator(configuration, loggerFactory); app.UseEnvActuator(configuration, loggerFactory); var healthOptions = new HealthEndpointOptions(configuration); app.UseHealthActuator(healthOptions, new DefaultHealthAggregator(), healthContributors, loggerFactory); app.UseLoggersActuator(configuration, loggerProvider, loggerFactory); app.UseTraceActuator(configuration, null, loggerFactory, version); app.UseMappingActuator(configuration, apiExplorer, loggerFactory); }
public async void HandleHealthRequestAsync_ReturnsExpected() { var opts = new HealthEndpointOptions(); var mgmtOptions = new CloudFoundryManagementOptions(); mgmtOptions.EndpointOptions.Add(opts); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor() }; var ep = new TestHealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var middle = new HealthEndpointMiddleware(null, new List <IManagementOptions> { mgmtOptions }); middle.Endpoint = ep; var context = CreateRequest("GET", "/health"); await middle.HandleHealthRequestAsync(context); context.Response.Body.Seek(0, SeekOrigin.Begin); StreamReader rdr = new StreamReader(context.Response.Body); string json = await rdr.ReadToEndAsync(); Assert.Equal("{\"status\":\"UNKNOWN\"}", json); }
public SpringBootAdminClientHostedService(SpringBootAdminClientOptions options, ManagementEndpointOptions mgmtOptions, HealthEndpointOptions healthOptions, HttpClient httpClient = null, ILogger logger = null) { _options = options; _mgmtOptions = mgmtOptions; _healthOptions = healthOptions; _httpClient = httpClient ?? HttpClientHelper.GetHttpClient(_options.ValidateCertificates, _options.ConnectionTimeoutMS); _logger = logger ?? NullLogger.Instance; }
public void UseHealthActuator_ThrowsIfContributorsNull() { var builder = new AppBuilder(); var config = new ConfigurationBuilder().Build(); var options = new HealthEndpointOptions(config); var exception = Assert.Throws <ArgumentNullException>(() => builder.UseHealthActuator(options, new DefaultHealthAggregator(), contributors: null)); Assert.Equal("contributors", exception.ParamName); }
public void Constructor_InitializesWithDefaults() { var opts = new HealthEndpointOptions(); Assert.Null(opts.Enabled); Assert.Equal("health", opts.Id); Assert.Equal(ShowDetails.Always, opts.ShowDetails); Assert.Equal(Permissions.RESTRICTED, opts.RequiredPermissions); }
public void RoutesByPathAndVerb() { var options = new HealthEndpointOptions(); Assert.False(options.ExactMatch); Assert.Equal("/actuator/health/{**_}", options.GetContextPath(new ActuatorManagementOptions())); Assert.Equal("/cloudfoundryapplication/health/{**_}", options.GetContextPath(new CloudFoundryManagementOptions())); Assert.Null(options.AllowedVerbs); }
public void Configuration(IAppBuilder app) { var healthEndpointOptions = new HealthEndpointOptions(); healthEndpointOptions .AddCpuUsageIndicator() .AddDiskSpaceUsageIndicator() .AddMemoryUsageIndicator(); app.UseHealthEndpoint(healthEndpointOptions); }
public void Invoke_NoContributors_ReturnsExpectedHealth() { var opts = new HealthEndpointOptions(); var contributors = new List <IHealthContributor>(); var agg = new DefaultHealthAggregator(); var ep = new HealthEndpoint(opts, agg, contributors, GetLogger <HealthEndpoint>()); var health = ep.Invoke(null); Assert.NotNull(health); Assert.Equal(HealthStatus.UNKNOWN, health.Status); }
public void HealthEndpointMiddleware_PathAndVerbMatching_ReturnsExpected() { var opts = new HealthEndpointOptions(); var contribs = new List<IHealthContributor>() { new DiskSpaceContributor() }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var actMOptions = new ActuatorManagementOptions(); actMOptions.EndpointOptions.Add(opts); var middle = new HealthEndpointMiddleware(null, ep, new List<IManagementOptions> { actMOptions }); Assert.True(middle.RequestVerbAndPathMatch("GET", "/actuator/health")); Assert.False(middle.RequestVerbAndPathMatch("PUT", "/actuator/health")); Assert.False(middle.RequestVerbAndPathMatch("GET", "/actuator/badpath")); }
public void HealthEndpointMiddleware_PathAndVerbMatching_ReturnsExpected() { var opts = new HealthEndpointOptions(); var mopts = TestHelpers.GetManagementOptions(opts); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor() }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var middle = new HealthEndpointOwinMiddleware(null, ep, mopts); Assert.True(middle.RequestVerbAndPathMatch("GET", "/cloudfoundryapplication/health")); Assert.False(middle.RequestVerbAndPathMatch("PUT", "/cloudfoundryapplication/health")); Assert.False(middle.RequestVerbAndPathMatch("GET", "/cloudfoundryapplication/badpath")); }
public void Invoke_CallsAllContributors() { var opts = new HealthEndpointOptions(); var contributors = new List <IHealthContributor>() { new TestContrib("h1"), new TestContrib("h2"), new TestContrib("h3") }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contributors); var info = ep.Invoke(null); foreach (var contrib in contributors) { TestContrib tc = (TestContrib)contrib; Assert.True(tc.Called); } }
public void Constructor_BindsRoleCorrectly() { var appsettings = new Dictionary <string, string>() { ["management:endpoints:health:role"] = "roleclaimvalue" }; ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(appsettings); var config = configurationBuilder.Build(); var opts = new HealthEndpointOptions(config); Assert.NotNull(opts.Claim); Assert.Equal(ClaimTypes.Role, opts.Claim.Type); Assert.Equal("roleclaimvalue", opts.Claim.Value); }
public async void HealthInvoke_ReturnsExpected() { // arrange var opts = new HealthEndpointOptions(); var mopts = TestHelpers.GetManagementOptions(opts); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor() }; var ep = new TestHealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var middle = new HealthEndpointOwinMiddleware(null, ep, mopts); var context = OwinTestHelpers.CreateRequest("GET", "/cloudfoundryapplication/health"); // act var json = await middle.InvokeAndReadResponse(context); // assert Assert.Equal("{\"status\":\"UNKNOWN\"}", json); }
/// <summary> /// Adds the services used by the Health actuator /// </summary> /// <param name="services">Reference to the service collection</param> /// <param name="configuration">Reference to the configuration system</param> /// <returns>A reference to the service collection</returns> public static IServiceCollection AddHealthActuatorServices(this IServiceCollection services, IConfiguration configuration) { if (services == null) { throw new ArgumentNullException(nameof(services)); } if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } var options = new HealthEndpointOptions(configuration); services.TryAddSingleton <IHealthOptions>(options); services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IEndpointOptions), options)); services.TryAddScoped <HealthEndpoint>(); return(services); }
public static void UseHealthActuator(IConfiguration configuration, IHealthAggregator healthAggregator = null, IEnumerable <IHealthContributor> contributors = null, ILoggerFactory loggerFactory = null) { var options = new HealthEndpointOptions(configuration); _mgmtOptions.RegisterEndpointOptions(configuration, options); if (ConfiguredHandlers.OfType <HealthHandler>().Any()) { return; } healthAggregator = healthAggregator ?? new DefaultHealthAggregator(); contributors = contributors ?? new List <IHealthContributor>() { new DiskSpaceContributor(new DiskSpaceContributorOptions(configuration)) }; var ep = new HealthEndpoint(options, healthAggregator, contributors, CreateLogger <HealthEndpoint>(loggerFactory)); var handler = new HealthHandler(ep, SecurityServices, _mgmtOptions, CreateLogger <HealthHandler>(loggerFactory)); ConfiguredHandlers.Add(handler); }
public void InvokeWithInvalidGroupReturnsAllContributors() { // arrange var opts = new HealthEndpointOptions(); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor(), new OutOfSserviceContributor(), new UnknownContributor(), new UpContributor() }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var context = Substitute.For <ISecurityContext>(); context.GetRequestComponents().Returns(new string[] { "health", "iNvAlId" }); // act var result = ep.Invoke(context); // assert Assert.Equal(HealthStatus.OUT_OF_SERVICE, result.Status); Assert.True(result.Details.Keys.Count == 4); Assert.True(result.Groups.Count() == 2); }
/// <summary> /// Add HealthCheck actuator endpoint to OWIN Pipeline /// </summary> /// <param name="builder">OWIN <see cref="IAppBuilder" /></param> /// <param name="config"><see cref="IConfiguration"/> of application for configuring health endpoint</param> /// <param name="loggerFactory">For logging within the middleware</param> /// <returns>OWIN <see cref="IAppBuilder" /> with Health Endpoint added</returns> public static IAppBuilder UseHealthActuator(this IAppBuilder builder, IConfiguration config, ILoggerFactory loggerFactory = null) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } var mgmtOptions = ManagementOptions.Get(config); var options = new HealthEndpointOptions(config); foreach (var mgmt in mgmtOptions) { mgmt.EndpointOptions.Add(options); } return(builder.UseHealthActuator(options, new DefaultHealthAggregator(), loggerFactory)); }
public void GetStatusCode_ReturnsExpected() { var opts = new HealthEndpointOptions(); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor() }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); Assert.Equal(503, ep.GetStatusCode(new HealthCheckResult { Status = HealthStatus.DOWN })); Assert.Equal(503, ep.GetStatusCode(new HealthCheckResult { Status = HealthStatus.OUT_OF_SERVICE })); Assert.Equal(200, ep.GetStatusCode(new HealthCheckResult { Status = HealthStatus.UP })); Assert.Equal(200, ep.GetStatusCode(new HealthCheckResult { Status = HealthStatus.UNKNOWN })); }
/// <summary> /// Register the Health endpoint, OWIN middleware and options /// </summary> /// <param name="container">Autofac DI <see cref="ContainerBuilder"/></param> /// <param name="config">Your application's <see cref="IConfiguration"/></param> /// <param name="aggregator">Your <see cref="IHealthAggregator"/></param> /// <param name="contributors">Types that implement <see cref="IHealthContributor"/></param> public static void RegisterHealthActuator(this ContainerBuilder container, IConfiguration config, IHealthAggregator aggregator, params Type[] contributors) { if (container == null) { throw new ArgumentNullException(nameof(container)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } if (aggregator == null) { aggregator = new DefaultHealthAggregator(); } container.Register(c => { var options = new HealthEndpointOptions(config); var mgmtOptions = c.Resolve <IEnumerable <IManagementOptions> >(); foreach (var mgmt in mgmtOptions) { mgmt.EndpointOptions.Add(options); } return(options); }).As <IHealthOptions>().IfNotRegistered(typeof(IHealthOptions)).SingleInstance(); container.RegisterInstance(aggregator).As <IHealthAggregator>().SingleInstance(); foreach (var c in contributors) { container.RegisterType(c).As <IHealthContributor>(); } container.RegisterType <HealthEndpoint>(); container.RegisterType <HealthEndpointOwinMiddleware>(); }
public void InvokeWithLivenessGroupReturnsGroupResults() { // arrange var opts = new HealthEndpointOptions(); var appAvailability = new ApplicationAvailability(); var contribs = new List <IHealthContributor>() { new DiskSpaceContributor(), new LivenessHealthContributor(appAvailability) }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var context = Substitute.For <ISecurityContext>(); context.GetRequestComponents().Returns(new string[] { "cloudfoundryapplication", "health", "liVeness" }); appAvailability.SetAvailabilityState(appAvailability.LivenessKey, LivenessState.Correct, null); // act var result = ep.Invoke(context); // assert Assert.Equal(HealthStatus.UP, result.Status); Assert.True(result.Details.Keys.Count == 1); Assert.True(result.Groups.Count() == 2); }
public void InvokeWithReadinessGroupReturnsGroupResults() { // arrange var opts = new HealthEndpointOptions(); var appAvailability = new ApplicationAvailability(); var contribs = new List <IHealthContributor>() { new UnknownContributor(), new UpContributor(), new ReadinessHealthContributor(appAvailability) }; var ep = new HealthEndpoint(opts, new DefaultHealthAggregator(), contribs); var context = Substitute.For <ISecurityContext>(); context.GetRequestComponents().Returns(new string[] { "actuator", "health", "readiness" }); appAvailability.SetAvailabilityState(appAvailability.ReadinessKey, ReadinessState.AcceptingTraffic, null); // act var result = ep.Invoke(context); // assert Assert.Equal(HealthStatus.UP, result.Status); Assert.True(result.Details.Keys.Count == 1); Assert.True(result.Groups.Count() == 2); }
public void Constructor_BindsConfigurationCorrectly() { var appsettings = new Dictionary <string, string>() { ["management:endpoints:enabled"] = "false", ["management:endpoints:path"] = "/cloudfoundryapplication", ["management:endpoints:health:enabled"] = "true", ["management:endpoints:health:requiredPermissions"] = "NONE", ["management:endpoints:cloudfoundry:validatecertificates"] = "true", ["management:endpoints:cloudfoundry:enabled"] = "true", ["management:endpoints:health:groups:custom:include"] = "diskSpace", ["management:endpoints:health:groups:lIveness:include"] = "diskSpace", ["management:endpoints:health:groups:rEadinEss:include"] = "diskSpace" }; ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.AddInMemoryCollection(appsettings); var config = configurationBuilder.Build(); var opts = new HealthEndpointOptions(config); var cloudOpts = new CloudFoundryEndpointOptions(config); Assert.True(cloudOpts.Enabled); Assert.Equal(string.Empty, cloudOpts.Id); Assert.Equal(string.Empty, cloudOpts.Path); Assert.True(cloudOpts.ValidateCertificates); Assert.True(opts.Enabled); Assert.Equal("health", opts.Id); Assert.Equal("health", opts.Path); Assert.Equal(Permissions.NONE, opts.RequiredPermissions); Assert.Equal(3, opts.Groups.Count); Assert.True(opts.Groups.ContainsKey("custom")); Assert.True(opts.Groups.ContainsKey("liveness")); Assert.True(opts.Groups.ContainsKey("READINESS")); }
public static HealthEndpointOptions AddCpuUsageIndicator(this HealthEndpointOptions options) { Ensure.NotNull(options, nameof(options)); options.AddIndicator(new CpuUsageIndicator()); return(options); }
public HealthEndpointController(HealthEndpointOptions options) { Ensure.NotNull(options, nameof(options)); _options = options; }
/// <summary> /// Register the application with a Spring-Boot-Admin server /// </summary> /// <param name="builder"><see cref="IApplicationBuilder"/></param> /// <param name="configuration">App configuration. Will be retrieved from builder.ApplicationServices if not provided</param> /// <param name="httpClient">A customized HttpClient. [Bring your own auth]</param> public static void RegisterWithSpringBootAdmin(this IApplicationBuilder builder, IConfiguration configuration = null, HttpClient httpClient = null) { if (builder is null) { throw new ArgumentNullException(nameof(builder)); } if (configuration is null) { configuration = builder.ApplicationServices.GetRequiredService <IConfiguration>(); } var logger = builder.ApplicationServices.GetService <ILogger <SpringBootAdminClientOptions> >(); var appInfo = builder.ApplicationServices.GetApplicationInstanceInfo(); var options = new SpringBootAdminClientOptions(configuration, appInfo); var mgmtOptions = new ManagementEndpointOptions(configuration); var healthOptions = new HealthEndpointOptions(configuration); var basePath = options.BasePath.TrimEnd('/'); httpClient ??= HttpClientHelper.GetHttpClient(options.ValidateCertificates, ConnectionTimeoutMs); var app = new Application() { Name = options.ApplicationName ?? "Steeltoe", HealthUrl = new Uri($"{basePath}{mgmtOptions.Path}/{healthOptions.Path}"), ManagementUrl = new Uri($"{basePath}{mgmtOptions.Path}"), ServiceUrl = new Uri($"{basePath}/"), Metadata = new Dictionary <string, object> { { "startup", DateTime.Now } }, }; app.Metadata.Merge(options.Metadata); var lifetime = builder.ApplicationServices.GetService <IHostApplicationLifetime>(); lifetime.ApplicationStarted.Register(() => { logger?.LogInformation("Registering with Spring Boot Admin Server at {0}", options.Url); var result = httpClient.PostAsJsonAsync($"{options.Url}/instances", app).GetAwaiter().GetResult(); if (result.IsSuccessStatusCode) { RegistrationResult = result.Content.ReadFromJsonAsync <RegistrationResult>().GetAwaiter().GetResult(); } else { logger.LogError($"Error registering with SpringBootAdmin {result}"); } }); lifetime.ApplicationStopped.Register(() => { if (RegistrationResult == null || string.IsNullOrEmpty(RegistrationResult.Id)) { return; } _ = httpClient.DeleteAsync($"{options.Url}/instances/{RegistrationResult.Id}").GetAwaiter().GetResult(); }); }