/* * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial agreement. */ package org.elasticsearch.node.internal; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import io.crate.Constants; import io.crate.metadata.settings.CrateSettings; import io.crate.settings.CrateSetting; import org.elasticsearch.cli.Terminal; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.env.Environment; import org.elasticsearch.node.Node; import org.elasticsearch.transport.Netty3Plugin; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; import static org.elasticsearch.common.Strings.cleanPath; import static org.elasticsearch.common.network.NetworkModule.TRANSPORT_TYPE_DEFAULT_KEY; import static org.elasticsearch.common.network.NetworkService.DEFAULT_NETWORK_HOST; import static org.elasticsearch.common.network.NetworkService.GLOBAL_NETWORK_HOST_SETTING; import static org.elasticsearch.http.HttpTransportSettings.SETTING_HTTP_PORT; import static org.elasticsearch.transport.TransportSettings.PORT; public class CrateSettingsPreparer { /** * ES_COPY_OF: core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java * This is a copy of {@link InternalSettingsPreparer#prepareEnvironment(Settings, Terminal, Map)} * <p> * with the addition of the "applyCrateDefaults" call and resolving `crate.yml` instead of `elasticsearch.yml`. */ public static Environment prepareEnvironment(Settings input, Terminal terminal, Map<String, String> properties) { // just create enough settings to build the environment, to get the config dir Settings.Builder output = Settings.builder(); InternalSettingsPreparer.initializeSettings(output, input, true, properties); Environment environment = new Environment(output.build()); Path path = environment.configFile().resolve("crate.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 // TODO: only re-initialize if a config file was actually loaded InternalSettingsPreparer.initializeSettings(output, input, false, properties); InternalSettingsPreparer.finalizeSettings(output, terminal); validateKnownSettings(output); applyCrateDefaults(output); environment = new Environment(output.build()); // we put back the path.logs so we can use it in the logging configuration file output.put(Environment.PATH_LOGS_SETTING.getKey(), cleanPath(environment.logsFile().toAbsolutePath().toString())); return new Environment(output.build()); } static void validateKnownSettings(Settings.Builder builder) { Settings settings = builder.build(); for (CrateSetting<?> crateSetting : CrateSettings.BUILT_IN_SETTINGS) { try { crateSetting.setting().get(settings); } catch (IllegalArgumentException e) { throw new RuntimeException(String.format(Locale.ENGLISH, "Invalid value [%s] for the [%s] setting.", crateSetting.setting().getRaw(settings), crateSetting.getKey()), e); } } } @VisibleForTesting static void applyCrateDefaults(Settings.Builder settingsBuilder) { // read also from crate.yml by default if no other config path has been set // if there is also a elasticsearch.yml file this file will be read first and the settings in crate.yml // will overwrite them. putIfAbsent(settingsBuilder, TRANSPORT_TYPE_DEFAULT_KEY, Netty3Plugin.NETTY_TRANSPORT_NAME); putIfAbsent(settingsBuilder, SETTING_HTTP_PORT.getKey(), Constants.HTTP_PORT_RANGE); putIfAbsent(settingsBuilder, PORT.getKey(), Constants.TRANSPORT_PORT_RANGE); putIfAbsent(settingsBuilder, GLOBAL_NETWORK_HOST_SETTING.getKey(), DEFAULT_NETWORK_HOST); // Set the default cluster name if not explicitly defined if (settingsBuilder.get(ClusterName.CLUSTER_NAME_SETTING.getKey()).equals(ClusterName.DEFAULT.value())) { settingsBuilder.put(ClusterName.CLUSTER_NAME_SETTING.getKey(), "crate"); } // Set a random node name if none is explicitly defined if (settingsBuilder.get(Node.NODE_NAME_SETTING.getKey()) == null) { settingsBuilder.put(Node.NODE_NAME_SETTING.getKey(), randomNodeName()); } } private static <T> void putIfAbsent(Settings.Builder settingsBuilder, String setting, T value) { if (settingsBuilder.get(setting) == null) { settingsBuilder.put(setting, value); } } private static String randomNodeName() { List<String> names = nodeNames(); int index = ThreadLocalRandom.current().nextInt(names.size()); return names.get(index); } @VisibleForTesting static List<String> nodeNames() { InputStream input = InternalSettingsPreparer.class.getResourceAsStream("/config/names.txt"); try { List<String> names = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, Charsets.UTF_8))) { String line = reader.readLine(); while (line != null) { String[] fields = line.split("\t"); if (fields.length == 0) { throw new RuntimeException("Failed to parse the names.txt. Malformed record: " + line); } names.add(fields[0]); line = reader.readLine(); } } return names; } catch (IOException e) { throw new RuntimeException("Could not read node names list", e); } } }