lcmc.ArgumentParser.java Source code

Java tutorial

Introduction

Here is the source code for lcmc.ArgumentParser.java

Source

/*
 * This file is part of LCMC written by Rasto Levrinc.
 *
 * Copyright (C) 2014, Rastislav Levrinc.
 *
 * The LCMC is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * The LCMC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LCMC; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package lcmc;

import lcmc.common.domain.AccessMode;
import lcmc.common.domain.Application;
import lcmc.cluster.domain.Cluster;
import lcmc.common.ui.Access;
import lcmc.common.ui.main.MainData;
import lcmc.common.ui.utils.SwingUtils;
import lcmc.host.domain.Host;
import lcmc.host.domain.HostOptions;
import lcmc.common.domain.UserConfig;
import lcmc.robotest.RoboTest;
import lcmc.robotest.StartTests;
import lcmc.robotest.Test;
import lcmc.logger.Logger;
import lcmc.logger.LoggerFactory;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Named
@Singleton
public class ArgumentParser {
    private static final Logger LOG = LoggerFactory.getLogger(ArgumentParser.class);

    private static final String HELP_OP = "help";
    private static final String VERSION_OP = "version";
    private static final String NOLRM_OP = "nolrm";
    private static final String AUTO_OP = "auto";
    private static final String PCMKTEST_OP = "pcmktest";
    private static final String DRBDTEST_OP = "drbdtest";
    private static final String VMTEST_OP = "vmtest";
    private static final String GUITEST_OP = "guitest";
    private static final String RO_OP = "ro";
    private static final String OP_OP = "op";
    private static final String ADMIN_OP = "admin";
    private static final String OP_MODE_OP = "op-mode";
    private static final String NO_UPGRADE_CHECK_OP = "no-upgrade-check";
    /** The --no-plugin-check option. DEPRECATED, doesn't do anything */
    private static final String NO_PLUGIN_CHECK_OP = "no-plugin-check";
    private static final String TIGHTVNC_OP = "tightvnc";
    private static final String ULTRAVNC_OP = "ultravnc";
    private static final String REALVNC_OP = "realvnc";
    private static final String BIGDRBDCONF_OP = "big-drbd-conf";
    private static final String STAGING_DRBD_OP = "staging-drbd";
    private static final String STAGING_PACEMAKER_OP = "staging-pacemaker";
    private static final String VNC_PORT_OFFSET_OP = "vnc-port-offset";
    private static final String SLOW_OP = "slow";
    private static final String RESTORE_MOUSE_OP = "restore-mouse";
    private static final String KEEP_HELPER_OP = "keep-helper";
    private static final String SCALE_OP = "scale";
    private static final String ID_DSA_OP = "id-dsa";
    private static final String ID_RSA_OP = "id-rsa";
    private static final String KNOWN_HOSTS_OP = "known-hosts";
    private static final String OUT_OP = "out";
    private static final String DEBUG_OP = "debug";
    private static final String CLUSTER_OP = "cluster";
    private static final String HOST_OP = "host";
    private static final String USER_OP = "user";
    private static final String SUDO_OP = "sudo";
    private static final String PORT_OP = "port";
    private static final String ADVANCED_OP = "advanced";
    private static final String ONE_HOST_CLUSTER_OP = "one-host-cluster";
    private static final String NO_PASSPHRASE_OP = "no-passphrase";
    /** The --embed. Embed in the browser option. */
    private static final String EMBED_OP = "embed";

    /** The --no-embed. Don't embed in the browser option. */
    private static final String NO_EMBED_OP = "no-embed";
    /** The --cmd-log. /var/log/lcmc.log on the servers. */
    private static final String CMD_LOG_OP = "cmd-log";
    private static final String CHECK_SWING_OP = "check-swing";
    @Inject
    private UserConfig userConfig;
    @Inject
    private RoboTest roboTest;
    @Inject
    private Provider<Cluster> clusterProvider;
    @Inject
    private Application application;
    @Inject
    private SwingUtils swingUtils;
    @Inject
    private Access access;
    @Inject
    private MainData mainData;

    public void parseOptionsAndReturnAutoArguments(String[] args) {
        final Options options = new Options();

        options.addOption("h", HELP_OP, false, "print this help");
        options.addOption(null, KEEP_HELPER_OP, false, "do not overwrite the lcmc-gui-helper program");
        options.addOption(null, RO_OP, false, "read only mode");
        options.addOption(null, OP_OP, false, "operator mode");
        options.addOption(null, ADMIN_OP, false, "administrator mode");
        options.addOption(null, OP_MODE_OP, true, "operating mode. <arg> can be:\n" + "ro - read only\n"
                + "op - operator\n" + "admin - administrator");
        options.addOption(null, NOLRM_OP, false, "do not show removed resources from LRM.");
        options.addOption("v", VERSION_OP, false, "print version");
        options.addOption(null, AUTO_OP, true, "ADVANCED USE: for testing");
        options.addOption(null, PCMKTEST_OP, true, "ADVANCED USE: for testing");
        options.addOption(null, DRBDTEST_OP, true, "ADVANCED USE: for testing");
        options.addOption(null, VMTEST_OP, true, "ADVANCED USE: for testing");
        options.addOption(null, GUITEST_OP, true, "ADVANCED USE: for testing");
        options.addOption(null, NO_UPGRADE_CHECK_OP, false, "disable upgrade check");
        options.addOption(null, NO_PLUGIN_CHECK_OP, false,
                "disable plugin check, DEPRECATED: there are no plugins");
        options.addOption(null, TIGHTVNC_OP, false, "enable tight vnc viewer");
        options.addOption(null, ULTRAVNC_OP, false, "enable ultra vnc viewer");
        options.addOption(null, REALVNC_OP, false, "enable real vnc viewer");
        options.addOption(null, BIGDRBDCONF_OP, false,
                "create one big drbd.conf, instead of many" + " files in drbd.d/ directory");
        options.addOption(null, STAGING_DRBD_OP, false, "enable more DRBD installation options");
        options.addOption(null, STAGING_PACEMAKER_OP, false, "enable more Pacemaker installation options");
        options.addOption(null, VNC_PORT_OFFSET_OP, true, "offset for port forwarding");
        options.addOption(null, SLOW_OP, false, "specify this if you have slow computer");
        options.addOption(null, RESTORE_MOUSE_OP, false, "ADVANCED USE: for testing");
        options.addOption(null, SCALE_OP, true, "scale fonts and sizes of elements in percent (100)");
        options.addOption(null, ID_DSA_OP, true, "location of id_dsa file ($HOME/.ssh/id_dsa)");
        options.addOption(null, ID_RSA_OP, true, "location of id_rsa file ($HOME/.ssh/id_rsa)");
        options.addOption(null, KNOWN_HOSTS_OP, true, "location of known_hosts file ($HOME/.ssh/known_hosts)");
        options.addOption(null, OUT_OP, true, "where to redirect the standard out");
        options.addOption(null, DEBUG_OP, true, "debug level, 0 - none, 3 - all");
        options.addOption("c", CLUSTER_OP, true, "define a cluster");
        final Option hostOp = new Option("h", HOST_OP, true, "define a cluster, used with --cluster option");
        hostOp.setArgs(10000);
        options.addOption(hostOp);
        options.addOption(null, SUDO_OP, false, "whether to use sudo, used with --cluster option");
        options.addOption(null, USER_OP, true, "user to use with sudo, used with --cluster option");
        options.addOption(null, PORT_OP, true, "ssh port, used with --cluster option");
        options.addOption(null, ADVANCED_OP, false, "start in an advanced mode");
        options.addOption(null, ONE_HOST_CLUSTER_OP, false, "allow one host cluster");
        options.addOption(null, NO_PASSPHRASE_OP, false, "try no passphrase first");
        options.addOption(null, EMBED_OP, false, "embed applet in the browser");
        options.addOption(null, NO_EMBED_OP, false, "don't embed applet in the browser");
        options.addOption(null, CMD_LOG_OP, false, "Log executed commands to the lcmc.log on the servers");
        options.addOption(null, CHECK_SWING_OP, false, "ADVANCED USE: for testing");
        final CommandLineParser parser = new PosixParser();
        String autoArgs = null;
        try {
            final CommandLine cmd = parser.parse(options, args);
            if (cmd.hasOption(OUT_OP)) {
                final String out = cmd.getOptionValue(OUT_OP);
                if (out != null) {
                    try {
                        System.setOut(new PrintStream(new FileOutputStream(out)));
                    } catch (final FileNotFoundException e) {
                        System.exit(2);
                    }
                }
            }
            if (cmd.hasOption(DEBUG_OP)) {
                final String level = cmd.getOptionValue(DEBUG_OP);
                if (level != null && lcmc.common.domain.util.Tools.isNumber(level)) {
                    LoggerFactory.setDebugLevel(Integer.parseInt(level));
                } else {
                    throw new ParseException("cannot parse debug level: " + level);
                }
            }
            boolean tightvnc = cmd.hasOption(TIGHTVNC_OP);
            boolean ultravnc = cmd.hasOption(ULTRAVNC_OP);
            final boolean realvnc = cmd.hasOption(REALVNC_OP);
            if (!tightvnc && !ultravnc && !realvnc) {
                if (lcmc.common.domain.util.Tools.isLinux()) {
                    tightvnc = true;
                } else {
                    tightvnc = true;
                    ultravnc = true;
                }
            }
            final boolean advanced = cmd.hasOption(ADVANCED_OP);
            access.setAdvancedMode(advanced);
            application.setUseTightvnc(tightvnc);
            application.setUseUltravnc(ultravnc);
            application.setUseRealvnc(realvnc);

            application.setUpgradeCheckEnabled(!cmd.hasOption(NO_UPGRADE_CHECK_OP));
            application.setBigDRBDConf(cmd.hasOption(BIGDRBDCONF_OP));
            application.setStagingDrbd(cmd.hasOption(STAGING_DRBD_OP));
            application.setStagingPacemaker(cmd.hasOption(STAGING_PACEMAKER_OP));
            application.setHideLRM(cmd.hasOption(NOLRM_OP));
            application.setKeepHelper(cmd.hasOption(KEEP_HELPER_OP));
            application.setOneHostCluster(cmd.hasOption(ONE_HOST_CLUSTER_OP));
            application.setNoPassphrase(cmd.hasOption(NO_PASSPHRASE_OP));
            if (cmd.hasOption(EMBED_OP)) {
                application.setEmbedApplet(true);
            }
            if (cmd.hasOption(NO_EMBED_OP)) {
                application.setEmbedApplet(false);
            }
            if (cmd.hasOption(CMD_LOG_OP)) {
                application.setCmdLog(true);
            }
            if (cmd.hasOption(CHECK_SWING_OP)) {
                swingUtils.setCheckSwing(true);
            }
            final String pwd = System.getProperty("user.home");
            final String scaleOp = cmd.getOptionValue(SCALE_OP, "100");
            try {
                final int scale = Integer.parseInt(scaleOp);
                application.setScale(scale);
                application.resizeFonts(scale);
            } catch (final NumberFormatException e) {
                LOG.appWarning("initApp: cannot parse scale: " + scaleOp);
            }

            final String idDsaPath = cmd.getOptionValue(ID_DSA_OP, pwd + "/.ssh/id_dsa");
            final String idRsaPath = cmd.getOptionValue(ID_RSA_OP, pwd + "/.ssh/id_rsa");
            final String knownHostsPath = cmd.getOptionValue(KNOWN_HOSTS_OP, pwd + "/.ssh/known_hosts");
            application.setIdDSAPath(idDsaPath);
            application.setIdRSAPath(idRsaPath);
            application.setKnownHostPath(knownHostsPath);

            final String opMode = cmd.getOptionValue(OP_MODE_OP);
            autoArgs = cmd.getOptionValue(AUTO_OP);
            if (cmd.hasOption(HELP_OP)) {
                final HelpFormatter formatter = new HelpFormatter();
                formatter.printHelp("java -jar LCMC.jar [OPTIONS]", options);
                System.exit(0);
            }
            if (cmd.hasOption(VERSION_OP)) {
                System.out.println("LINUX CLUSTER MANAGEMENT CONSOLE " + lcmc.common.domain.util.Tools.getRelease()
                        + " by Rasto Levrinc");
                System.exit(0);
            }
            if (cmd.hasOption("ro") || "ro".equals(opMode)) {
                access.setAccessType(AccessMode.RO);
                access.setMaxAccessType(AccessMode.RO);
            } else if (cmd.hasOption("op") || "op".equals(opMode)) {
                access.setAccessType(AccessMode.OP);
                access.setMaxAccessType(AccessMode.OP);
            } else if (cmd.hasOption("admin") || "admin".equals(opMode)) {
                access.setAccessType(AccessMode.ADMIN);
                access.setMaxAccessType(AccessMode.ADMIN);
            } else if (opMode != null) {
                LOG.appWarning("initApp: unknown operating mode: " + opMode);
            }
            float fps = MainData.DEFAULT_ANIM_FPS;
            if (cmd.hasOption(SLOW_OP)) {
                fps /= 2;
            }
            if (cmd.hasOption(RESTORE_MOUSE_OP)) {
                /* restore mouse if it is stuck in pressed state, during
                * robot tests. */
                roboTest.restoreMouse();
            }
            final String vncPortOffsetString = cmd.getOptionValue(VNC_PORT_OFFSET_OP);
            if (vncPortOffsetString != null && lcmc.common.domain.util.Tools.isNumber(vncPortOffsetString)) {
                application.setVncPortOffset(Integer.parseInt(vncPortOffsetString));
            }
            mainData.setAnimFPS(fps);
            if (cmd.hasOption(CLUSTER_OP) || cmd.hasOption(HOST_OP)) {
                parseClusterOptionsAndCreateClusterButton(cmd);
            }
        } catch (final ParseException exp) {
            System.out.println("ERROR: " + exp.getMessage());
            System.exit(1);
        }
        LOG.debug1("initApp: max mem: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + 'm');
        if (autoArgs != null) {
            parseAutoArgs(autoArgs);
        }
    }

    public void parseClusterOptionsAndCreateClusterButton(final CommandLine cmd) throws ParseException {
        String clusterName = null;
        List<HostOptions> hostsOptions = null;
        final Map<String, List<HostOptions>> clusters = new LinkedHashMap<String, List<HostOptions>>();
        for (final Option option : cmd.getOptions()) {
            final String op = option.getLongOpt();
            if (CLUSTER_OP.equals(op)) {
                clusterName = option.getValue();
                if (clusterName == null) {
                    throw new ParseException("could not parse " + CLUSTER_OP + " option");

                }
                clusters.put(clusterName, new ArrayList<HostOptions>());
            } else if (HOST_OP.equals(op)) {
                final String[] hostNames = option.getValues();
                if (clusterName == null) {
                    clusterName = "default";
                    clusters.put(clusterName, new ArrayList<HostOptions>());
                }
                if (hostNames == null) {
                    throw new ParseException("could not parse " + HOST_OP + " option");
                }
                hostsOptions = new ArrayList<HostOptions>();
                for (final String hostNameEntered : hostNames) {
                    final String hostName;
                    String port = null;
                    if (hostNameEntered.indexOf(':') > 0) {
                        final String[] he = hostNameEntered.split(":");
                        hostName = he[0];
                        port = he[1];
                        if (port != null && port.isEmpty() || !lcmc.common.domain.util.Tools.isNumber(port)) {
                            throw new ParseException("could not parse " + HOST_OP + " option");
                        }
                    } else {
                        hostName = hostNameEntered;
                    }
                    final HostOptions ho = new HostOptions(hostName);
                    if (port != null) {
                        ho.setPort(port);
                    }
                    hostsOptions.add(ho);
                    clusters.get(clusterName).add(ho);
                }
            } else if (SUDO_OP.equals(op)) {
                if (hostsOptions == null) {
                    throw new ParseException(SUDO_OP + " must be defined after " + HOST_OP);
                }
                for (final HostOptions ho : hostsOptions) {
                    ho.setUseSudo(true);
                }
            } else if (USER_OP.equals(op)) {
                if (hostsOptions == null) {
                    throw new ParseException(USER_OP + " must be defined after " + HOST_OP);
                }
                final String userName = option.getValue();
                if (userName == null) {
                    throw new ParseException("could not parse " + USER_OP + " option");
                }
                for (final HostOptions ho : hostsOptions) {
                    ho.setLoginUser(userName);
                }
            } else if (PORT_OP.equals(op)) {
                if (hostsOptions == null) {
                    throw new ParseException(PORT_OP + " must be defined after " + HOST_OP);
                }
                final String port = option.getValue();
                if (port == null) {
                    throw new ParseException("could not parse " + PORT_OP + " option");
                }
                for (final HostOptions ho : hostsOptions) {
                    ho.setPort(port);
                }
            } else if (PCMKTEST_OP.equals(op)) {
                final String index = option.getValue();
                if (index != null && !index.isEmpty()) {
                    application.setAutoTest(new Test(StartTests.Type.PCMK, index.charAt(0)));
                }
            } else if (DRBDTEST_OP.equals(op)) {
                final String index = option.getValue();
                if (index != null && !index.isEmpty()) {
                    application.setAutoTest(new Test(StartTests.Type.DRBD, index.charAt(0)));
                }
            } else if (VMTEST_OP.equals(op)) {
                final String index = option.getValue();
                if (index != null && !index.isEmpty()) {
                    application.setAutoTest(new Test(StartTests.Type.VM, index.charAt(0)));
                }
            } else if (GUITEST_OP.equals(op)) {
                final String index = option.getValue();
                if (index != null && !index.isEmpty()) {
                    application.setAutoTest(new Test(StartTests.Type.GUI, index.charAt(0)));
                }
            }
        }
        for (final Map.Entry<String, List<HostOptions>> clusterEntry : clusters.entrySet()) {
            final List<HostOptions> hostOptions = clusterEntry.getValue();
            if (hostOptions.size() < 1 || (hostOptions.size() == 1 && !application.isOneHostCluster())) {
                throw new ParseException("not enough hosts for cluster: " + clusterEntry.getKey());
            }
        }
        final String failedHost = setUserConfigFromOptions(clusters);
        if (failedHost != null) {
            LOG.appWarning("parseClusterOptions: could not resolve host \"" + failedHost + "\" skipping");
        }
    }

    /**
     * Parses arguments from --auto command line option, it makes some
     * automatical gui actions, that help to test the gui and can find some
     * other uses later.
     * To find out which options are available, you'd have to grep for
     * getAutoOptionHost and getAutoOptionCluster
     */
    void parseAutoArgs(final String line) {
        if (line == null) {
            return;
        }
        final String[] args = line.split(",");
        String host = null;
        String cluster = null;
        boolean global = false;
        for (final String arg : args) {
            final String[] pair = arg.split(":");
            if (pair.length != 2) {
                LOG.appWarning("parseAutoArgs: cannot parse: " + line);
                return;
            }
            final String option = pair[0];
            final String value = pair[1];
            if ("host".equals(option)) {
                cluster = null;
                host = value;
                application.addAutoHost(host);
                continue;
            } else if ("cluster".equals(option)) {
                host = null;
                cluster = value;
                application.addAutoCluster(cluster);
                continue;
            } else if ("global".equals(option)) {
                host = null;
                cluster = null;
                global = true;
                continue;
            }
            if (host != null) {
                application.addAutoOption(host, option, value);
            } else if (cluster != null) {
                application.addAutoOption(cluster, option, value);
            } else if (global) {
                application.addAutoOption("global", option, value);
            } else {
                LOG.appWarning("parseAutoArgs: cannot parse: " + line);
                return;
            }
        }
    }

    /** Sets user config from command line options returns host, for which dns lookup failed. */
    private String setUserConfigFromOptions(final Map<String, List<HostOptions>> clusters) {
        final Map<String, List<Host>> hostMap = new LinkedHashMap<String, List<Host>>();
        for (final String clusterName : clusters.keySet()) {
            for (final HostOptions hostOptions : clusters.get(clusterName)) {
                final String hostnameEntered = hostOptions.getHost();
                InetAddress[] addresses = null;
                try {
                    addresses = InetAddress.getAllByName(hostnameEntered);
                } catch (final UnknownHostException e) {
                }
                String ip = null;
                if (addresses != null) {
                    if (addresses.length == 0) {
                        LOG.debug("setUserConfigFromOptions: lookup failed");
                        /* lookup failed */
                    } else {
                        ip = addresses[0].getHostAddress();
                    }
                }
                if (ip == null) {
                    return hostnameEntered;
                }
                userConfig.setHost(hostMap, hostOptions.getLoginUser(), hostnameEntered, ip, hostOptions.getPort(),
                        null, hostOptions.getUseSudo(), false);
            }
        }
        for (final String clusterName : clusters.keySet()) {
            final Cluster cluster = clusterProvider.get();
            cluster.setName(clusterName);
            cluster.setSavable(false);
            application.addClusterToClusters(cluster);
            for (final HostOptions ho : clusters.get(clusterName)) {
                userConfig.setHostCluster(hostMap, cluster, ho.getHost(), !UserConfig.PROXY_HOST);
            }
        }
        return null;
    }

}