// Copyright 2017 The Nomulus Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package google.registry.config; import static com.google.common.base.Ascii.toLowerCase; import static google.registry.util.ResourceUtils.readResourceUtf8; import com.google.common.flogger.FluentLogger; import java.util.Map; import java.util.Optional; import org.yaml.snakeyaml.Yaml; /** * Utility methods for dealing with YAML. * *
There are always two YAML configuration files that are used: the {@code default-config.yaml}
* file, which contains default configuration for all environments, and the environment-specific
* {@code nomulus-config-ENVIRONMENT.yaml} file, which contains overrides for the default values for
* environment-specific settings such as the App Engine project ID. The environment-specific
* configuration can be blank, but it must exist.
*/
public final class YamlUtils {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final String ENVIRONMENT_CONFIG_FORMAT = "files/nomulus-config-%s.yaml";
private static final String YAML_CONFIG_PROD =
readResourceUtf8(RegistryConfig.class, "files/default-config.yaml");
/**
* Loads the POJO of type {@code T} from merged YAML configuration files.
*
* @param defaultYaml content of the default YAML file.
* @param customYaml content of the custom YAML file, to override default values.
* @param clazz type of the POJO loaded from the merged YAML files.
* @throws IllegalStateException if the configuration files don't exist or are invalid
*/
public static The {@code default-config.yaml} file in this directory is loaded first, and a fatal error is
* thrown if it cannot be found or if there is an error parsing it. Separately, the
* environment-specific config file named {@code nomulus-config-ENVIRONMENT.yaml} is also loaded
* and those values merged into the POJO.
*/
static RegistryConfigSettings getConfigSettings() {
String configFilePath =
String.format(ENVIRONMENT_CONFIG_FORMAT, toLowerCase(RegistryEnvironment.get().name()));
String customYaml = readResourceUtf8(RegistryConfig.class, configFilePath);
return getConfigSettings(YAML_CONFIG_PROD, customYaml, RegistryConfigSettings.class);
}
/**
* Recursively merges two YAML documents together.
*
* Any fields that are specified in customYaml will override fields of the same path in
* defaultYaml. Additional fields in customYaml that aren't specified in defaultYaml will be
* ignored. The schemas of all fields that are present must be identical, e.g. it is an error to
* override a field that has a Map value in the default YAML with a field of any other type in the
* custom YAML.
*
* Only maps are handled recursively; lists are simply overridden in place as-is, as are maps
* whose name is suffixed with "Map" -- this allows entire maps to be overridden, rather than
* merged.
*/
static String mergeYaml(String defaultYaml, String customYaml) {
Yaml yaml = new Yaml();
Map