/* * 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.bootstrap; import joptsimple.OptionSet; import joptsimple.OptionSpec; import joptsimple.OptionSpecBuilder; import joptsimple.util.PathConverter; import org.opensearch.Build; import org.opensearch.cli.EnvironmentAwareCommand; import org.opensearch.cli.ExitCodes; import org.opensearch.cli.Terminal; import org.opensearch.cli.UserException; import org.opensearch.common.logging.LogConfigurator; import org.opensearch.env.Environment; import org.opensearch.monitor.jvm.JvmInfo; import org.opensearch.node.NodeValidationException; import java.io.IOException; import java.nio.file.Path; import java.security.Permission; import java.security.Security; import java.util.Arrays; import java.util.Locale; /** * This class starts opensearch. * * @opensearch.internal */ class OpenSearch extends EnvironmentAwareCommand { private final OptionSpecBuilder versionOption; private final OptionSpecBuilder daemonizeOption; private final OptionSpec pidfileOption; private final OptionSpecBuilder quietOption; // visible for testing OpenSearch() { super("Starts OpenSearch", () -> {}); // we configure logging later so we override the base class from configuring logging versionOption = parser.acceptsAll(Arrays.asList("V", "version"), "Prints OpenSearch version information and exits"); daemonizeOption = parser.acceptsAll(Arrays.asList("d", "daemonize"), "Starts OpenSearch in the background") .availableUnless(versionOption); pidfileOption = parser.acceptsAll(Arrays.asList("p", "pidfile"), "Creates a pid file in the specified path on start") .availableUnless(versionOption) .withRequiredArg() .withValuesConvertedBy(new PathConverter()); quietOption = parser.acceptsAll(Arrays.asList("q", "quiet"), "Turns off standard output/error streams logging in console") .availableUnless(versionOption) .availableUnless(daemonizeOption); } /** * Main entry point for starting opensearch */ public static void main(final String[] args) throws Exception { overrideDnsCachePolicyProperties(); /* * We want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the * presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy). This * forces such policies to take effect immediately. */ System.setSecurityManager(new SecurityManager() { @Override public void checkPermission(Permission perm) { // grant all permissions so that we can later set the security manager to the one that we want } }); LogConfigurator.registerErrorListener(); final OpenSearch opensearch = new OpenSearch(); int status = main(args, opensearch, Terminal.DEFAULT); if (status != ExitCodes.OK) { final String basePath = System.getProperty("opensearch.logs.base_path"); // It's possible to fail before logging has been configured, in which case there's no point // suggesting that the user look in the log file. if (basePath != null) { Terminal.DEFAULT.errorPrintln( "ERROR: OpenSearch did not exit normally - check the logs at " + basePath + System.getProperty("file.separator") + System.getProperty("opensearch.logs.cluster_name") + ".log" ); } exit(status); } } private static void overrideDnsCachePolicyProperties() { for (final String property : new String[] { "networkaddress.cache.ttl", "networkaddress.cache.negative.ttl" }) { final String overrideProperty = "opensearch." + property; final String overrideValue = System.getProperty(overrideProperty); if (overrideValue != null) { try { // round-trip the property to an integer and back to a string to ensure that it parses properly Security.setProperty(property, Integer.toString(Integer.valueOf(overrideValue))); } catch (final NumberFormatException e) { throw new IllegalArgumentException("failed to parse [" + overrideProperty + "] with value [" + overrideValue + "]", e); } } } } static int main(final String[] args, final OpenSearch opensearch, final Terminal terminal) throws Exception { return opensearch.main(args, terminal); } @Override protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException { if (options.nonOptionArguments().isEmpty() == false) { throw new UserException(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments()); } if (options.has(versionOption)) { final String versionOutput = String.format( Locale.ROOT, "Version: %s, Build: %s/%s/%s, JVM: %s", Build.CURRENT.getQualifiedVersion(), Build.CURRENT.type().displayName(), Build.CURRENT.hash(), Build.CURRENT.date(), JvmInfo.jvmInfo().version() ); terminal.println(versionOutput); return; } final boolean daemonize = options.has(daemonizeOption); final Path pidFile = pidfileOption.value(options); final boolean quiet = options.has(quietOption); // a misconfigured java.io.tmpdir can cause hard-to-diagnose problems later, so reject it immediately try { env.validateTmpDir(); } catch (IOException e) { throw new UserException(ExitCodes.CONFIG, e.getMessage()); } try { init(daemonize, pidFile, quiet, env); } catch (NodeValidationException e) { throw new UserException(ExitCodes.CONFIG, e.getMessage()); } } void init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv) throws NodeValidationException, UserException { try { Bootstrap.init(!daemonize, pidFile, quiet, initialEnv); } catch (BootstrapException | RuntimeException e) { // format exceptions to the console in a special way // to avoid 2MB stacktraces from guice, etc. throw new StartupException(e); } } /** * Required method that's called by Apache Commons procrun when * running as a service on Windows, when the service is stopped. * * http://commons.apache.org/proper/commons-daemon/procrun.html * * NOTE: If this method is renamed and/or moved, make sure to * update opensearch-service.bat! */ static void close(String[] args) throws IOException { Bootstrap.stop(); } }