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

Add customized admin endpoints #618

Merged
merged 6 commits into from
Aug 11, 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
55 changes: 44 additions & 11 deletions docs/config-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ Removes and downloads file again if depending service cant process probably corr
- `<SERVICE>.remote-file-syncer.http-client.connect-timeout-ms` - set the connect timeout.
- `<SERVICE>.remote-file-syncer.http-client.max-redirects` - set the maximum amount of HTTP redirections to follow. A value of 0 (the default) prevents redirections from being followed.

## General settings
- `host-id` - the ID of node where prebid server deployed.
- `external-url` - the setting stands for external URL prebid server is reachable by, for example address of the load-balancer e.g. http://prebid.host.com.
- `admin.port` - the port to listen on administration requests.

## Auction (Legacy)
- `default-timeout-ms` - this setting controls default timeout for /auction endpoint.
- `max-timeout-ms` - this setting controls maximum timeout for /auction endpoint.
- `timeout-adjustment-ms` - reduces timeout value passed in legacy Auction request so that Prebid Server can handle timeouts from adapters and respond to the request before it times out.

## Auction (OpenRTB)
- `auction.blacklisted-accounts` - comma separated list of blacklisted account IDs.
- `auction.blacklisted-apps` - comma separated list of blacklisted applications IDs, requests from which should not be processed.
Expand Down Expand Up @@ -104,7 +114,7 @@ There are several typical keys:

But feel free to add additional bidder's specific options.

## Admin
## Logger Level Modifier
- `logger-level-modifier.enabled` - enable the `/admin` endpoint.

## Currency Converter
Expand All @@ -113,6 +123,39 @@ But feel free to add additional bidder's specific options.
- `currency-converter.external-rates.default-timeout-ms` - default operation timeout for fetching currency rates.
- `currency-converter.external-rates.refresh-period-ms` - default refresh period for currency rates updates.

## Admin Endpoints
- `admin-endpoints.version.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.version.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.version.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.version.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.currency-rates.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.currency-rates.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.currency-rates.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.currency-rates.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.storedrequest.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.storedrequest.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.storedrequest.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.storedrequest.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.storedrequest-amp.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.storedrequest-amp.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.storedrequest-amp.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.storedrequest-amp.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.cache-invalidation.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.cache-invalidation.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.cache-invalidation.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.cache-invalidation.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.logger-level-modifier.enabled` - if equals to `true` the endpoint will be available.
- `admin-endpoints.logger-level-modifier.path` - the server context path where the endpoint will be accessible.
- `admin-endpoints.logger-level-modifier.on-application-port` - when equals to `false` endpoint will be bound to `admin.port`.
- `admin-endpoints.logger-level-modifier.protected` - when equals to `true` endpoint will be protected by basic authentication configured in `admin-endpoints.credentials`

- `admin-endpoints.credentials` - user and password for access to admin endpoints if `admin-endpoints.[NAME].protected` is true`.

## Metrics
- `metrics.metricType` - set the type of metric counter for [Dropwizard Metrics](http://metrics.dropwizard.io). Can be `flushingCounter` (default), `counter` or `meter`.

Expand Down Expand Up @@ -273,13 +316,3 @@ If not defined in config all other Health Checkers would be disabled and endpoin
- `geolocation.type` - set the geo location service provider, can be `maxmind` or custom provided by hosting company.
- `geolocation.maxmind` - section for [MaxMind](https://www.maxmind.com) configuration as geo location service provider.
- `geolocation.maxmind.remote-file-syncer` - use RemoteFileSyncer component for downloading/updating MaxMind database file. See [RemoteFileSyncer](#remote-file-syncer) section for its configuration.

## Auction (Legacy)
- `default-timeout-ms` - this setting controls default timeout for /auction endpoint.
- `max-timeout-ms` - this setting controls maximum timeout for /auction endpoint.
- `timeout-adjustment-ms` - reduces timeout value passed in legacy Auction request so that Prebid Server can handle timeouts from adapters and respond to the request before it times out.

## General settings
- `host-id` - the ID of node where prebid server deployed.
- `external-url` - the setting stands for external URL prebid server is reachable by, for example address of the load-balancer e.g. http://prebid.host.com.
- `admin.port` - the port to listen on administration requests.
8 changes: 3 additions & 5 deletions docs/endpoints/admin.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Admin Endpoint

This `/admin` endpoint is bound to `admin.port`.

Unavailable if `logger level modifier` is disabled (`logger-level-modifier.enabled` config property)
Unavailable if `logger level modifier` is disabled (`logger-level-modifier.enabled` config property).

This endpoint will set the desirable logging level and number of logs for `400` responses.

### Query Params

- `logging`: Desirable logging level: `info`, `warn`, `trace`, `error`, `fatal`, `debug`.
- `records`: numbers of logs with changed logging level. (0 < n < 100_000)
- `logging` - Desirable logging level: `info`, `warn`, `trace`, `error`, `fatal`, `debug`.
- `records` - numbers of logs with changed logging level. (0 < n < 100_000).
9 changes: 9 additions & 0 deletions docs/endpoints/cache-invalidation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Cache Invalidation

Unavailable if in-memory cache invalidation is disabled (`settings.in-memory-cache.notification-endpoints-enabled` config property).

This endpoint can be used for invalidating of account settings cache. Responds with empty body.

### Query Params

- `account` - account ID to clear the cache.
4 changes: 1 addition & 3 deletions docs/endpoints/currency-rates.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Currency Rates

This /currency-rates endpoint is bound to `admin.port`.

Unavailable if currency conversion is disabled (`currency-converter.external-rates.enabled` config property)
Unavailable if currency conversion is disabled (`currency-converter.external-rates.enabled` config property).

This endpoint will return a json with the latest update timestamp.

Expand Down
4 changes: 2 additions & 2 deletions docs/endpoints/storedrequests/amp.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Amp

This `/storedrequests/amp` endpoint is bound to `admin.port`.
Unavailable if notification is disabled (`settings.in-memory-cache.notification-endpoints-enabled` config property).

The goal is to update/invalidate AMP stored request/impression in-memory caches.

The request/response is equivalent to [openrtb2](../openrtb2.md)
The request/response is equivalent to [openrtb2](../openrtb2.md).
2 changes: 1 addition & 1 deletion docs/endpoints/storedrequests/openrtb2.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Openrtb2

This `/storedrequests/openrtb2` endpoint is bound to `admin.port`.
Unavailable if notification is disabled (`settings.in-memory-cache.notification-endpoints-enabled` config property).

The goal is to update/invalidate stored request/impression in-memory caches.

Expand Down
5 changes: 5 additions & 0 deletions docs/endpoints/version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Version

Unavailable if `admin-endpoints.version.enabled` config property is not set.

This endpoint can be used for verifying running Prebid Server git revision.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@
<artifactId>vertx-dropwizard-metrics</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-common</artifactId>
<version>${vertx.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.prebid.server.handler;

import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.ext.auth.AuthProvider;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BasicAuthHandler;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.Objects;

public class CustomizedAdminEndpoint {

private final String path;
private final Handler<RoutingContext> handler;
private final boolean isOnApplicationPort;
private final boolean isProtected;
private Map<String, String> credentials;

public CustomizedAdminEndpoint(String path, Handler<RoutingContext> handler, boolean isOnApplicationPort,
boolean isProtected) {
this.path = Objects.requireNonNull(path);
this.handler = Objects.requireNonNull(handler);
this.isOnApplicationPort = isOnApplicationPort;
this.isProtected = isProtected;
}

public CustomizedAdminEndpoint withCredentials(Map<String, String> credentials) {
this.credentials = credentials;
return this;
}

public boolean isOnApplicationPort() {
return isOnApplicationPort;
}

public void router(Router router) {
if (isProtected) {
routeToHandlerWithCredentials(router);
} else {
routeToHandler(router);
}
}

private void routeToHandlerWithCredentials(Router router) {
if (credentials == null) {
throw new IllegalArgumentException("Credentials for admin endpoint is empty.");
}

final AuthProvider authProvider = createAuthProvider(credentials);
router.route(path).handler(BasicAuthHandler.create(authProvider)).handler(handler);
}

private void routeToHandler(Router router) {
router.route(path).handler(handler);
}

private AuthProvider createAuthProvider(Map<String, String> credentials) {
return (authInfo, resultHandler) -> {
if (MapUtils.isEmpty(credentials)) {
resultHandler.handle(Future.failedFuture("Credentials not set in configuration."));
return;
}

final String requestUsername = authInfo.getString("username");
final String requestPassword = StringUtils.chomp(authInfo.getString("password"));

final String storedPassword = credentials.get(requestUsername);
if (StringUtils.isNotBlank(requestPassword) && Objects.equals(storedPassword, requestPassword)) {
resultHandler.handle(Future.succeededFuture());
} else {
resultHandler.handle(Future.failedFuture("No such user, or password incorrect."));
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package org.prebid.server.spring.config;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.prebid.server.currency.CurrencyConversionService;
import org.prebid.server.handler.AccountCacheInvalidationHandler;
import org.prebid.server.handler.AdminHandler;
import org.prebid.server.handler.CurrencyRatesHandler;
import org.prebid.server.handler.CustomizedAdminEndpoint;
import org.prebid.server.handler.SettingsCacheNotificationHandler;
import org.prebid.server.handler.VersionHandler;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.manager.AdminManager;
import org.prebid.server.settings.CachingApplicationSettings;
import org.prebid.server.settings.SettingsCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.Map;

@Configuration
public class AdminEndpointsConfiguration {

@Bean
@ConditionalOnExpression("${admin-endpoints.version.enabled} == true")
CustomizedAdminEndpoint versionEndpoint(
JacksonMapper mapper,
@Value("${admin-endpoints.version.path}") String path,
@Value("${admin-endpoints.version.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.version.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
VersionHandler.create("git-revision.json", mapper),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
@ConditionalOnExpression("${currency-converter.external-rates.enabled} == true"
+ " and ${admin-endpoints.currency-rates.enabled} == true")
CustomizedAdminEndpoint currencyConversionRatesEndpoint(
CurrencyConversionService currencyConversionRates,
JacksonMapper mapper,
@Value("${admin-endpoints.currency-rates.path}") String path,
@Value("${admin-endpoints.currency-rates.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.currency-rates.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
new CurrencyRatesHandler(currencyConversionRates, mapper),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
@ConditionalOnExpression("${settings.in-memory-cache.notification-endpoints-enabled} == true"
+ " and ${admin-endpoints.storedrequest.enabled} == true")
CustomizedAdminEndpoint cacheNotificationEndpoint(
SettingsCache settingsCache,
JacksonMapper mapper,
@Value("${admin-endpoints.storedrequest.path}") String path,
@Value("${admin-endpoints.storedrequest.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.storedrequest.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
new SettingsCacheNotificationHandler(settingsCache, mapper),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
@ConditionalOnExpression("${settings.in-memory-cache.notification-endpoints-enabled} == true"
+ " and ${admin-endpoints.storedrequest-amp.enabled} == true")
CustomizedAdminEndpoint ampCacheNotificationEndpoint(
SettingsCache ampSettingsCache,
JacksonMapper mapper,
@Value("${admin-endpoints.storedrequest-amp.path}") String path,
@Value("${admin-endpoints.storedrequest-amp.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.storedrequest-amp.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
new SettingsCacheNotificationHandler(ampSettingsCache, mapper),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
@ConditionalOnExpression("${settings.in-memory-cache.notification-endpoints-enabled} == true"
+ " and ${admin-endpoints.cache-invalidation.enabled} == true")
CustomizedAdminEndpoint cacheInvalidateNotificationEndpoint(
CachingApplicationSettings cachingApplicationSettings,
@Value("${admin-endpoints.cache-invalidation.path}") String path,
@Value("${admin-endpoints.cache-invalidation.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.cache-invalidation.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
new AccountCacheInvalidationHandler(cachingApplicationSettings),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
@ConditionalOnExpression("${logger-level-modifier.enabled} == true"
+ " and ${admin-endpoints.logger-level-modifier.enabled} == true")
CustomizedAdminEndpoint loggerLevelModifierEndpoint(
AdminManager adminManager,
@Value("${admin-endpoints.logger-level-modifier.path}") String path,
@Value("${admin-endpoints.logger-level-modifier.on-application-port}") boolean isOnApplicationPort,
@Value("${admin-endpoints.logger-level-modifier.protected}") boolean isProtected,
@Autowired(required = false) Map<String, String> adminEndpointCredentials) {

return new CustomizedAdminEndpoint(
path,
new AdminHandler(adminManager),
isOnApplicationPort,
isProtected)
.withCredentials(adminEndpointCredentials);
}

@Bean
Map<String, String> adminEndpointCredentials(
DGarbar marked this conversation as resolved.
Show resolved Hide resolved
@Autowired(required = false) AdminEndpointCredentials adminEndpointCredentials) {

return ObjectUtils.defaultIfNull(adminEndpointCredentials.getCredentials(), Collections.emptyMap());
}

@Component
@ConfigurationProperties(prefix = "admin-endpoints")
@Data
@NoArgsConstructor
public static class AdminEndpointCredentials {

private Map<String, String> credentials;
}
}
Loading