com.nike.cerberus.cli.CerberusRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.nike.cerberus.cli.CerberusRunner.java

Source

/*
 * Copyright (c) 2016 Nike, Inc.
 *
 * Licensed 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 com.nike.cerberus.cli;

import ch.qos.logback.classic.Level;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.MissingCommandException;
import com.beust.jcommander.ParameterDescription;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.WrappedParameter;
import com.beust.jcommander.internal.Lists;
import com.github.tomaslanger.chalk.Chalk;
import com.google.common.collect.Maps;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
import com.nike.cerberus.ConfigConstants;
import com.nike.cerberus.command.CerberusCommand;
import com.nike.cerberus.command.Command;
import com.nike.cerberus.command.cms.CreateCmsClusterCommand;
import com.nike.cerberus.command.cms.CreateCmsConfigCommand;
import com.nike.cerberus.command.consul.CreateConsulClusterCommand;
import com.nike.cerberus.command.consul.CreateConsulConfigCommand;
import com.nike.cerberus.command.consul.CreateVaultAclCommand;
import com.nike.cerberus.command.core.CreateBaseCommand;
import com.nike.cerberus.command.core.PrintStackInfoCommand;
import com.nike.cerberus.command.core.UpdateStackCommand;
import com.nike.cerberus.command.core.UploadCertFilesCommand;
import com.nike.cerberus.command.core.WhitelistCidrForVpcAccessCommand;
import com.nike.cerberus.command.dashboard.PublishDashboardCommand;
import com.nike.cerberus.command.gateway.CreateCloudFrontLogProcessingLambdaConfigCommand;
import com.nike.cerberus.command.gateway.CreateCloudFrontSecurityGroupUpdaterLambdaCommand;
import com.nike.cerberus.command.gateway.CreateGatewayClusterCommand;
import com.nike.cerberus.command.gateway.CreateGatewayConfigCommand;
import com.nike.cerberus.command.gateway.PublishLambdaCommand;
import com.nike.cerberus.command.vault.CreateCmsVaultTokenCommand;
import com.nike.cerberus.command.vault.CreateVaultClusterCommand;
import com.nike.cerberus.command.vault.CreateVaultConfigCommand;
import com.nike.cerberus.command.vault.DisableAuditBackendCommand;
import com.nike.cerberus.command.vault.EnableAuditBackendCommand;
import com.nike.cerberus.command.vault.InitVaultClusterCommand;
import com.nike.cerberus.command.vault.LoadDefaultVaultPoliciesCommand;
import com.nike.cerberus.command.vault.StoreOneLoginApiKeyCommand;
import com.nike.cerberus.command.vault.UnsealVaultClusterCommand;
import com.nike.cerberus.command.vault.VaultHealthCheckCommand;
import com.nike.cerberus.logging.LoggingConfigurer;
import com.nike.cerberus.module.CerberusModule;
import com.nike.cerberus.module.PropsModule;
import com.nike.cerberus.operation.Operation;
import com.nike.cerberus.util.LocalEnvironmentValidator;
import org.apache.commons.lang3.StringUtils;

import java.util.EnumSet;
import java.util.List;
import java.util.Map;

/**
 * CLI entry point.
 */
public class CerberusRunner {

    private final Map<String, Command> commandMap;
    private CerberusCommand cerberusCommand;
    private final JCommander commander;

    private CerberusRunner() {
        commandMap = Maps.newHashMap();
        cerberusCommand = new CerberusCommand();
        commander = new JCommander(cerberusCommand);
        commander.setProgramName("cerberus");
        commander.setAcceptUnknownOptions(true);
    }

    /**
     * Actual application runner.  Determines which command is specified and executes the associated operation.
     *
     * @param args Command line arguments
     */
    @SuppressWarnings("unchecked")
    public void run(String[] args) {
        registerAllCommands();

        try {
            commander.parse(args);
            configureLogging(cerberusCommand.isDebug());
            final String commandName = commander.getParsedCommand();
            Command command = commandMap.get(commandName);

            final Injector propsInjector = Guice.createInjector(new PropsModule());

            if (cerberusCommand.isVersion()) {
                String version = propsInjector
                        .getInstance(Key.get(String.class, Names.named(ConfigConstants.VERSION_PROPERTY)));
                String versionMessage = Chalk.on(String.format("Cerberus Lifecycle CLI version: %s", version))
                        .green().bold().toString();
                System.out.println(versionMessage);
            } else if (cerberusCommand.isHelp() || commandName == null) {
                if (StringUtils.isNotBlank(commandName)) {
                    commander.usage(commandName);
                } else {
                    printCustomUsage();
                }
            } else {
                final Injector injector = Guice
                        .createInjector(
                                new CerberusModule(cerberusCommand.getProxyDelegate(),
                                        cerberusCommand.getEnvironment(), cerberusCommand.getRegion()),
                                new PropsModule());

                // fail early if there is any problem in local environment
                LocalEnvironmentValidator validator = injector.getInstance(LocalEnvironmentValidator.class);
                validator.validate();

                final Operation operation = injector.getInstance(command.getOperationClass());

                if (operation.isRunnable(command)) {
                    operation.run(command);
                }
            }
        } catch (Throwable e) {
            if (!cerberusCommand.isHelp()) {
                System.err.println(Chalk.on("ERROR: " + e.getMessage()).red().bold().toString());
            }

            String commandName = commander.getParsedCommand();
            if (StringUtils.isNotBlank(commandName)) {
                commander.usage(commandName);
            } else {
                printCustomUsage();
            }
        }
    }

    private void printCommands() {
        System.out.println("Commands, use cerberus [-h, --help] [command name] for more info:");
        commander.getCommands().keySet().forEach(command -> {
            String msg = String.format("    %s, %s", Chalk.on(command).green().bold().toString(),
                    commander.getCommandDescription(command));
            System.out.println(msg);
        });
    }

    private void printCustomUsage() {
        StringBuilder sb = new StringBuilder("Usage: cerberus [options] [command] [command options]\n");

        String indent = "";
        //indenting
        int descriptionIndent = 6;
        int indentCount = indent.length() + descriptionIndent;

        int longestName = 0;
        List<ParameterDescription> sorted = Lists.newArrayList();
        for (ParameterDescription pd : commander.getParameters()) {
            if (!pd.getParameter().hidden()) {
                sorted.add(pd);
                // + to have an extra space between the name and the description
                int length = pd.getNames().length() + 2;
                if (length > longestName) {
                    longestName = length;
                }
            }
        }

        sb.append(indent).append("  Options:\n");

        sorted.stream().sorted((p0, p1) -> p0.getLongestName().compareTo(p1.getLongestName())).forEach(pd -> {
            WrappedParameter parameter = pd.getParameter();
            sb.append(indent).append("  " + (parameter.required() ? "* " : "  ")
                    + Chalk.on(pd.getNames()).green().bold().toString() + "\n");
            wrapDescription(sb, indentCount, s(indentCount) + pd.getDescription());
            Object def = pd.getDefault();
            if (def != null) {
                String displayedDef = StringUtils.isBlank(def.toString()) ? "<empty string>" : def.toString();
                sb.append("\n" + s(indentCount))
                        .append("Default: " + Chalk.on(displayedDef).yellow().bold().toString());
            }
            Class<?> type = pd.getParameterized().getType();
            if (type.isEnum()) {
                String values = EnumSet.allOf((Class<? extends Enum>) type).toString();
                sb.append("\n" + s(indentCount))
                        .append("Possible Values: " + Chalk.on(values).yellow().bold().toString());
            }
            sb.append("\n");
        });

        System.out.println(sb.toString());
        System.out.print("  ");
        printCommands();
    }

    private String s(int count) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < count; i++) {
            result.append(" ");
        }

        return result.toString();
    }

    private void wrapDescription(StringBuilder out, int indent, String description) {
        int max = 79;
        String[] words = description.split(" ");
        int current = 0;
        int i = 0;
        while (i < words.length) {
            String word = words[i];
            if (word.length() > max || current + 1 + word.length() <= max) {
                out.append(word).append(" ");
                current += word.length() + 1;
            } else {
                out.append("\n").append(s(indent)).append(word).append(" ");
                current = indent + 1 + word.length();
            }
            i++;
        }
    }

    /**
     * Convenience method for registering all top level commands.
     */
    private void registerAllCommands() {
        registerCommand(new CreateBaseCommand());
        registerCommand(new UploadCertFilesCommand());
        registerCommand(new CreateConsulConfigCommand());
        registerCommand(new CreateVaultAclCommand());
        registerCommand(new CreateConsulClusterCommand());
        registerCommand(new CreateVaultConfigCommand());
        registerCommand(new CreateVaultClusterCommand());
        registerCommand(new PublishDashboardCommand());
        registerCommand(new InitVaultClusterCommand());
        registerCommand(new UnsealVaultClusterCommand());
        registerCommand(new EnableAuditBackendCommand());
        registerCommand(new DisableAuditBackendCommand());
        registerCommand(new LoadDefaultVaultPoliciesCommand());
        registerCommand(new StoreOneLoginApiKeyCommand());
        registerCommand(new CreateCmsVaultTokenCommand());
        registerCommand(new CreateCmsConfigCommand());
        registerCommand(new CreateCmsClusterCommand());
        registerCommand(new CreateGatewayConfigCommand());
        registerCommand(new CreateGatewayClusterCommand());
        registerCommand(new UpdateStackCommand());
        registerCommand(new PrintStackInfoCommand());
        registerCommand(new VaultHealthCheckCommand());
        registerCommand(new PublishLambdaCommand());
        registerCommand(new CreateCloudFrontLogProcessingLambdaConfigCommand());
        registerCommand(new CreateCloudFrontSecurityGroupUpdaterLambdaCommand());
        registerCommand(new WhitelistCidrForVpcAccessCommand());
    }

    /**
     * Registers a command with the command map and commander.
     *
     * @param command Command to be registered
     */
    private void registerCommand(final Command command) {
        commandMap.put(command.getCommandName(), command);
        commander.addCommand(command.getCommandName(), command);
    }

    /**
     * Configures the logging backend.
     *
     * @param isDebug Whether debug logging is enabled
     */
    private void configureLogging(boolean isDebug) {
        Level logLevel = Level.INFO;
        if (isDebug) {
            logLevel = Level.DEBUG;
        }

        LoggingConfigurer.configure(logLevel);
    }

    /**
     * Program entry point.  Instantiates and calls run.
     * @param args Command line arguments
     */
    public static void main(String[] args) {
        CerberusRunner runner = new CerberusRunner();
        runner.run(args);
    }
}