All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.plugins.PluginManagerCliParser Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * 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.
 */

package org.elasticsearch.plugins;

import org.apache.commons.cli.CommandLine;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.logging.log4j.LogConfigurator;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.env.Environment;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
import org.elasticsearch.plugins.PluginManager.OutputMode;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Locale;

import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
import static org.elasticsearch.common.cli.CliToolConfig.Builder.option;

public class PluginManagerCliParser extends CliTool {

    // By default timeout is 0 which means no timeout
    public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueMillis(0);

    private static final CliToolConfig CONFIG = CliToolConfig.config("plugin", PluginManagerCliParser.class)
            .cmds(ListPlugins.CMD, Install.CMD, Remove.CMD)
            .build();

    public static void main(String[] args) {
        // initialize default for es.logger.level because we will not read the logging.yml
        String loggerLevel = System.getProperty("es.logger.level", "INFO");
        // Set the appender for all potential log files to terminal so that other components that use the logger print out the
        // same terminal.
        // The reason for this is that the plugin cli cannot be configured with a file appender because when the plugin command is
        // executed there is no way of knowing where the logfiles should be placed. For example, if elasticsearch
        // is run as service then the logs should be at /var/log/elasticsearch but when started from the tar they should be at es.home/logs.
        // Therefore we print to Terminal.
        Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.builder()
                .put("appender.terminal.type", "terminal")
                .put("rootLogger", "${es.logger.level}, terminal")
                .put("es.logger.level", loggerLevel)
                .build(), Terminal.DEFAULT);
        // configure but do not read the logging conf file
        LogConfigurator.configure(env.settings(), false);
        int status = new PluginManagerCliParser().execute(args).status();
        exit(status);
    }

    @SuppressForbidden(reason = "Allowed to exit explicitly from #main()")
    private static void exit(int status) {
        System.exit(status);
    }

    public PluginManagerCliParser() {
        super(CONFIG);
    }

    public PluginManagerCliParser(Terminal terminal) {
        super(CONFIG, terminal);
    }

    @Override
    protected Command parse(String cmdName, CommandLine cli) throws Exception {
        switch (cmdName.toLowerCase(Locale.ROOT)) {
            case Install.NAME:
                return Install.parse(terminal, cli);
            case ListPlugins.NAME:
                return ListPlugins.parse(terminal, cli);
            case Remove.NAME:
                return Remove.parse(terminal, cli);
            default:
                assert false : "can't get here as cmd name is validated before this method is called";
                return exitCmd(ExitStatus.USAGE);
        }
    }

    /**
     * List all installed plugins
     */
    static class ListPlugins extends CliTool.Command {

        private static final String NAME = "list";

        private static final CliToolConfig.Cmd CMD = cmd(NAME, ListPlugins.class).build();
        private final OutputMode outputMode;

        public static Command parse(Terminal terminal, CommandLine cli) {
            OutputMode outputMode = OutputMode.DEFAULT;
            if (cli.hasOption("s")) {
                outputMode = OutputMode.SILENT;
            }
            if (cli.hasOption("v")) {
                outputMode = OutputMode.VERBOSE;
            }

            return new ListPlugins(terminal, outputMode);
        }

        ListPlugins(Terminal terminal, OutputMode outputMode) {
            super(terminal);
            this.outputMode = outputMode;
        }

        @Override
        public ExitStatus execute(Settings settings, Environment env) throws Exception {
            PluginManager pluginManager = new PluginManager(env, null, outputMode, DEFAULT_TIMEOUT);
            pluginManager.listInstalledPlugins(terminal);
            return ExitStatus.OK;
        }
    }

    /**
     * Remove a plugin
     */
    static class Remove extends CliTool.Command {

        private static final String NAME = "remove";

        private static final CliToolConfig.Cmd CMD = cmd(NAME, Remove.class).build();

        public static Command parse(Terminal terminal, CommandLine cli) {
            String[] args = cli.getArgs();
            if (args.length == 0) {
                return exitCmd(ExitStatus.USAGE, terminal, "plugin name is missing (type -h for help)");
            }

            OutputMode outputMode = OutputMode.DEFAULT;
            if (cli.hasOption("s")) {
                outputMode = OutputMode.SILENT;
            }
            if (cli.hasOption("v")) {
                outputMode = OutputMode.VERBOSE;
            }

            return new Remove(terminal, outputMode, args[0]);
        }

        private OutputMode outputMode;
        final String pluginName;

        Remove(Terminal terminal, OutputMode outputMode, String pluginToRemove) {
            super(terminal);
            this.outputMode = outputMode;
            this.pluginName = pluginToRemove;
        }

        @Override
        public ExitStatus execute(Settings settings, Environment env) throws Exception {

            PluginManager pluginManager = new PluginManager(env, null, outputMode, DEFAULT_TIMEOUT);
            terminal.println("-> Removing " + Strings.coalesceToEmpty(pluginName) + "...");
            pluginManager.removePlugin(pluginName, terminal);
            return ExitStatus.OK;
        }
    }

    /**
     * Installs a plugin
     */
    static class Install extends Command {

        private static final String NAME = "install";

        private static final CliToolConfig.Cmd CMD = cmd(NAME, Install.class)
                .options(option("t", "timeout").required(false).hasArg(false))
                .options(option("b", "batch").required(false))
                .build();

        static Command parse(Terminal terminal, CommandLine cli) {
            String[] args = cli.getArgs();

            // install [plugin-name/url]
            if ((args == null) || (args.length == 0)) {
                return exitCmd(ExitStatus.USAGE, terminal, "plugin name or url is missing (type -h for help)");
            }
            String name = args[0];

            URL optionalPluginUrl = null;
            // try parsing cli argument as URL
            try {
                optionalPluginUrl = new URL(name);
                name = null;
            } catch (MalformedURLException e) {
                // we tried to parse the cli argument as url and failed
                // continue treating it as a symbolic plugin name like `analysis-icu` etc.
            }

            TimeValue timeout = TimeValue.parseTimeValue(cli.getOptionValue("t"), DEFAULT_TIMEOUT, "cli");

            OutputMode outputMode = OutputMode.DEFAULT;
            if (cli.hasOption("s")) {
                outputMode = OutputMode.SILENT;
            }
            if (cli.hasOption("v")) {
                outputMode = OutputMode.VERBOSE;
            }
            
            boolean batch = System.console() == null;
            if (cli.hasOption("b")) {
                batch = true;
            }

            return new Install(terminal, name, outputMode, optionalPluginUrl, timeout, batch);
        }

        final String name;
        private OutputMode outputMode;
        final URL url;
        final TimeValue timeout;
        final boolean batch;

        Install(Terminal terminal, String name, OutputMode outputMode, URL url, TimeValue timeout, boolean batch) {
            super(terminal);
            this.name = name;
            this.outputMode = outputMode;
            this.url = url;
            this.timeout = timeout;
            this.batch = batch;
        }

        @Override
        public ExitStatus execute(Settings settings, Environment env) throws Exception {
            PluginManager pluginManager = new PluginManager(env, url, outputMode, timeout);
            if (name != null) {
                terminal.println("-> Installing " + Strings.coalesceToEmpty(name) + "...");
            } else {
                terminal.println("-> Installing from " + URLDecoder.decode(url.toString(), "UTF-8") + "...");
            }
            pluginManager.downloadAndExtract(name, terminal, batch);
            return ExitStatus.OK;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy