Skip to content

Commit

Permalink
Merge pull request #5676 from ibi-group/config-check
Browse files Browse the repository at this point in the history
Optionally abort startup when unknown configuration parameters were detected
  • Loading branch information
leonardehrenfried authored Apr 18, 2024
2 parents d0788f2 + 68f667e commit 085f049
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 49 deletions.
37 changes: 37 additions & 0 deletions docs/Migrating-Configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
While OTP's GraphQL APIs are very, very stable even across versions, the JSON configuration schema
is not. Changes to it are relatively frequent and you can see all PRs that change it with
the [Github tag 'config change'](https://github.com/opentripplanner/OpenTripPlanner/pulls?q=label%3A%22config+change%22).

### Migrating the JSON configuration

OTP validates the configuration and prints warnings during startup. This means that when you
migrate to a newer version, you should carefully inspect the logs. If you see messages like

```
(NodeAdapter.java:170) Unexpected config parameter: 'routingDefaults.stairsReluctance:1.65' in 'router-config.json'
```

this means there are properties in your configuration that are unknown to OTP and therefore likely
to be a configuration error, perhaps because the schema was changed. In such a case you should
consult the [feature](Configuration.md#otp-features), [router](RouterConfiguration.md) or
[build configuration documentation](BuildConfiguration.md) to find out what the new schema looks like.

By default, OTP starts up even if unknown configuration parameters exist. This supports forward and backwards
migration of config parameters independent if the OTP version. This allows the configuration to follow
the lifecycle of the environment and still be able to roll back OTP.
Combined with the config parameter substitution it also allows using the same configuration in
different environments. Tip! Rolling out the configuration before rolling out a new
version of OTP, ensure you that you are safe and can roll back later.

An example: you change the location of the graphs, a critical error occurs afterwards and you need to
roll back. Any member of the dev-ops team should then be confident that they can roll back without
risk - even if the environment changed since the last OTP version was rolled out.

### Aborting on invalid configuration

If you want OTP to abort the startup when encountering unknown configuration parameters, you can add
the flag `--abortOnUnknownConfig` to your regular OTP CLI commands.

This should of course be used wisely as it can also accidentally make your production instances refuse to start up.
For some deployments this is a good solution - especially if the config substitution feature is used to inject
environment specific information. Using this feature in the graph-build phase is less risky, than in the OTP serve phase.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ nav:
- Router: 'RouterConfiguration.md'
- "Route Request": 'RouteRequest.md'
- "Realtime Updaters": 'UpdaterConfig.md'
- "Migrating between versions/builds": 'Migrating-Configuration.md'
- Features explained:
- "Routing modes": 'RoutingModes.md'
- "In-station navigation": 'In-Station-Navigation.md'
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/opentripplanner/standalone/OTPMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.opentripplanner.raptor.configure.RaptorConfig;
import org.opentripplanner.routing.graph.SerializedGraphObject;
import org.opentripplanner.standalone.config.CommandLineParameters;
import org.opentripplanner.standalone.config.ConfigModel;
import org.opentripplanner.standalone.configure.ConstructApplication;
import org.opentripplanner.standalone.configure.LoadApplication;
import org.opentripplanner.standalone.server.GrizzlyServer;
Expand Down Expand Up @@ -113,6 +114,8 @@ private static void startOTPServer(CommandLineParameters cli) {
var loadApp = new LoadApplication(cli);
var config = loadApp.config();

detectUnusedConfigParams(cli, config);

// Validate data sources, command line arguments and config before loading and
// processing input data to fail early
loadApp.validateConfigAndDataSources();
Expand Down Expand Up @@ -173,6 +176,15 @@ private static void startOTPServer(CommandLineParameters cli) {
}
}

/**
* Optionally, check if the config is valid and if not abort the startup process.
*/
private static void detectUnusedConfigParams(CommandLineParameters cli, ConfigModel config) {
if (cli.abortOnUnknownConfig) {
config.abortOnUnknownParameters();
}
}

private static void startOtpWebServer(CommandLineParameters params, ConstructApplication app) {
// Index graph for travel search
app.transitModel().index();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -726,4 +726,11 @@ public int getSubwayAccessTimeSeconds() {
public NodeAdapter asNodeAdapter() {
return root;
}

/**
* Checks if any unknown or invalid parameters were encountered while loading the configuration.
*/
public boolean hasUnknownParameters() {
return root.hasUnknownParameters();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ public class CommandLineParameters {
)
public boolean visualize;

@Parameter(
names = { "--abortOnUnknownConfig" },
description = "Abort the startup if configuration files are found to contain unknown parameters."
)
public boolean abortOnUnknownConfig = false;

/**
* The remaining single parameter after the switches is the directory with the configuration
* files. This directory may contain other files like the graph, input data and report files.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.node.MissingNode;
import org.opentripplanner.framework.application.OTPFeature;
import org.opentripplanner.framework.application.OtpAppException;
import org.opentripplanner.framework.application.OtpFileNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -105,4 +106,24 @@ public static void initializeOtpFeatures(OtpConfig otpConfig) {
OTPFeature.enableFeatures(otpConfig.otpFeatures);
OTPFeature.logFeatureSetup();
}

/**
* Checks if any unknown or invalid parameters were encountered while loading the configuration.
* <p>
* If so it throws an exception.
*/
public void abortOnUnknownParameters() {
if (
(
otpConfig.hasUnknownParameters() ||
buildConfig.hasUnknownParameters() ||
routerConfig.hasUnknownParameters()
)
) {
throw new OtpAppException(
"Configuration contains unknown parameters (see above for details). " +
"Please fix your configuration or remove --abortOnUnknownConfig from your OTP CLI parameters."
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,11 @@ public OtpConfig(NodeAdapter nodeAdapter, boolean logUnusedParams) {
root.logAllWarnings(LOG::warn);
}
}

/**
* Checks if any unknown or invalid parameters were encountered while loading the configuration.
*/
public boolean hasUnknownParameters() {
return root.hasUnknownParameters();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,11 @@ public String toString() {
// Print ONLY the values set, not default values
return root.toPrettyString();
}

/**
* Checks if any unknown or invalid parameters were encountered while loading the configuration.
*/
public boolean hasUnknownParameters() {
return root.hasUnknownParameters();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ public void logAllWarnings(Consumer<String> logger) {
allWarnings().forEach(logger);
}

/**
* Checks if any unknown or invalid properties were encountered while loading the configuration.
*/
public boolean hasUnknownParameters() {
return !unusedParams().isEmpty();
}

/**
* Be careful when using this method - this bypasses the NodeAdaptor, and we loose
* track of unused parameters and cannot generate documentation for the children.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,6 @@ public Boolean asBoolean(boolean defaultValue) {
return ofOptional(BOOLEAN, defaultValue, JsonNode::asBoolean);
}

public Map<String, Boolean> asBooleanMap() {
return ofOptionalMap(BOOLEAN, JsonNode::asBoolean);
}

/** @throws OtpAppException if parameter is missing. */
public double asDouble() {
return ofRequired(DOUBLE).asDouble();
Expand Down
Loading

0 comments on commit 085f049

Please sign in to comment.