/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.node; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Supplier; import java.util.function.Function; import org.opensearch.Version; import org.opensearch.cluster.ClusterName; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsException; import org.opensearch.env.Environment; /** * Prepares internal settings * * @opensearch.internal */ public class InternalSettingsPreparer { private static final String SECRET_PROMPT_VALUE = "${prompt.secret}"; private static final String TEXT_PROMPT_VALUE = "${prompt.text}"; /** * TODO: Refactor this as transport client is removed and this used to prepare settings for the transport client by * gathering all opensearch system properties and setting defaults. */ public static Settings prepareSettings(Settings input) { Settings.Builder output = Settings.builder(); initializeSettings(output, input, Collections.emptyMap()); finalizeSettings(output, () -> null); return output.build(); } /** * Prepares the settings by gathering all opensearch system properties, optionally loading the configuration settings. * * @param input the custom settings to use; these are not overwritten by settings in the configuration file * @param properties map of properties key/value pairs (usually from the command-line) * @param configPath path to config directory; (use null to indicate the default) * @param defaultNodeName supplier for the default node.name if the setting isn't defined * @return the {@link Environment} */ public static Environment prepareEnvironment( Settings input, Map properties, Path configPath, Supplier defaultNodeName ) { // just create enough settings to build the environment, to get the config dir Settings.Builder output = Settings.builder(); initializeSettings(output, input, properties); Environment environment = new Environment(output.build(), configPath); output = Settings.builder(); // start with a fresh output Path path = environment.configDir().resolve("opensearch.yml"); if (Files.exists(path)) { try { output.loadFromPath(path); } catch (IOException e) { throw new SettingsException("Failed to load settings from " + path.toString(), e); } } // re-initialize settings now that the config file has been loaded initializeSettings(output, input, properties); checkSettingsForTerminalDeprecation(output); finalizeSettings(output, defaultNodeName); return new Environment(output.build(), configPath); } /** * Initializes the builder with the given input settings, and applies settings from the specified map (these settings typically come * from the command line). * * @param output the settings builder to apply the input and default settings to * @param input the input settings * @param esSettings a map from which to apply settings */ static void initializeSettings(final Settings.Builder output, final Settings input, final Map esSettings) { output.put(input); output.putProperties(esSettings, Function.identity()); output.replacePropertyPlaceholders(); } /** * Checks all settings values to make sure they do not have the old prompt settings. These were deprecated in 6.0.0. * This check should be removed in 8.0.0. */ private static void checkSettingsForTerminalDeprecation(final Settings.Builder output) throws SettingsException { // This method to be removed in 8.0.0, as it was deprecated in 6.0 and removed in 7.0 assert Version.CURRENT.major != 8 : "Logic pertaining to config driven prompting should be removed"; for (String setting : output.keys()) { final String value = output.get(setting); if (value != null) { switch (value) { case SECRET_PROMPT_VALUE: throw new SettingsException( "Config driven secret prompting was deprecated in 6.0.0. Use the keystore" + " for secure settings." ); case TEXT_PROMPT_VALUE: throw new SettingsException( "Config driven text prompting was deprecated in 6.0.0. Use the keystore" + " for secure settings." ); } } } } /** * Finish preparing settings by replacing forced settings and any defaults that need to be added. */ private static void finalizeSettings(Settings.Builder output, Supplier defaultNodeName) { // allow to force set properties based on configuration of the settings provided List forcedSettings = new ArrayList<>(); for (String setting : output.keys()) { if (setting.startsWith("force.")) { forcedSettings.add(setting); } } for (String forcedSetting : forcedSettings) { String value = output.remove(forcedSetting); output.put(forcedSetting.substring("force.".length()), value); } output.replacePropertyPlaceholders(); // put the cluster and node name if they aren't set if (output.get(ClusterName.CLUSTER_NAME_SETTING.getKey()) == null) { output.put(ClusterName.CLUSTER_NAME_SETTING.getKey(), ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY).value()); } if (output.get(Node.NODE_NAME_SETTING.getKey()) == null) { output.put(Node.NODE_NAME_SETTING.getKey(), defaultNodeName.get()); } } }