com.oneops.boo.BooCli.java Source code

Java tutorial

Introduction

Here is the source code for com.oneops.boo.BooCli.java

Source

/*
 * Copyright 2017 Walmart, 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.oneops.boo;

import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.UUID;

import com.oneops.api.resource.model.Deployment;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.jayway.restassured.RestAssured;
import com.oneops.api.OOInstance;
import com.oneops.api.exception.OneOpsClientAPIException;
import com.oneops.boo.exception.BooException;
import com.oneops.boo.utils.BooUtils;
import com.oneops.boo.workflow.BuildAllPlatforms;
import com.oneops.boo.yaml.Constants;

/**
 * The Class BooCli.
 */
public class BooCli {

    /** The Constant LOG. */
    private static final Logger LOG = LoggerFactory.getLogger(BooCli.class);

    /** The is quiet. */
    private static boolean isQuiet = false;

    /** The is forced. */
    private static boolean isForced = false;

    /** The is no deploy. */
    private static boolean isNoDeploy = false;

    /** The Constant YES_NO. */
    private static final String YES_NO = "WARNING! There are %s instances using the %s configuration. Do you want to destroy all of them? (y/n)";

    private static int DEPLOYMENT_TIMEOUT_SECONDS = 90 * 60; //90 minutes

    /** The config file. */
    private File configFile;

    /** The flow. */
    private BuildAllPlatforms flow;

    /** The options. */
    private Options options = new Options();

    /** The config. */
    private ClientConfig config;

    /** The injector. */
    private Injector injector;

    /** The boo utils. */
    private BooUtils booUtils = new BooUtils();

    private String comment = null;

    private String profile = ClientConfig.ONEOPS_DEFAULT_PROFILE;

    /**
     * Instantiates a new boo cli.
     */
    public BooCli() {
        Option help = new Option("h", "help", false, "show help.");
        Option create = Option.builder("c").longOpt("create").desc(
                "Create a new Assembly specified by -f. If Assembly automatic naming is enabled, each invocation will create a new Assembly.")
                .build();
        Option update = Option.builder("u").longOpt("update").desc("Update configurations specified by -f.")
                .build();
        Option status = Option.builder("s").longOpt("status").desc("Get status of deployments specified by -f")
                .build();

        Option config = Option.builder("f").longOpt("config-file").argName("FILE").hasArg()
                .desc("Use specified Boo YAML file").build();

        Option cleanup = Option.builder("r").longOpt("remove")
                .desc("Remove all deployed configurations specified by -f").build();
        Option list = Option.builder("l").longOpt("list").numberOfArgs(1).optionalArg(Boolean.TRUE)
                .desc("Return a list of instances applicable to the identifier provided..").build();

        Option force = Option.builder().longOpt("force").desc("Do not prompt for --remove").build();

        Option nodeploy = Option.builder().longOpt("no-deploy").desc("Create assembly without deployments").build();

        Option getIps = Option.builder().longOpt("get-ips").argName("environment> <compute-class")
                .desc("Get IPs of deployed nodes specified by -f; Args are optional.").build();
        getIps.setOptionalArg(true);
        getIps.setArgs(Option.UNLIMITED_VALUES);

        Option retry = Option.builder().longOpt("retry").desc("Retry deployments of configurations specified by -f")
                .build();
        Option quiet = Option.builder().longOpt("quiet").desc("Silence the textual output.").build();
        Option assembly = Option.builder("a").longOpt("assembly").hasArg().desc("Override the assembly name.")
                .build();
        Option action = Option.builder().longOpt("procedure").numberOfArgs(3).optionalArg(Boolean.TRUE)
                .argName("platform> <component> <action")
                .desc("Execute actions. Use 'list' as an action to show available actions.").build();
        Option procedureArguments = Option.builder().longOpt("procedure-arguments").argName("arglist").hasArg()
                .desc("Arguments to pass to the procedure call. Example: '{\"backup_type\":\"incremental\"}'")
                .build();
        Option instanceList = Option.builder().longOpt("procedure-instances").argName("instanceList").hasArg().desc(
                "Comma-separated list of component instance names. 'list' to show all available component instances.")
                .build();

        Option stepSize = Option.builder().longOpt("procedure-step-size").argName("size").hasArg()
                .desc("Percent of nodes to perform procedure on, default is 100.").build();
        Option comment = Option.builder("m").longOpt("message").argName("description").hasArg()
                .desc("Customize the comment for deployments").build();
        Option view = Option.builder("v").longOpt("view").desc("View interpolated Boo YAML template").build();
        Option profile = Option.builder("p").longOpt("profile").argName("PROFILE").hasArg()
                .desc("Choose specific profile from ~/.boo/config").build();

        options.addOption(help);
        options.addOption(config);
        options.addOption(create);
        options.addOption(update);
        options.addOption(status);
        options.addOption(list);
        options.addOption(cleanup);
        options.addOption(getIps);
        options.addOption(retry);
        options.addOption(quiet);
        options.addOption(force);
        options.addOption(nodeploy);
        options.addOption(assembly);
        options.addOption(action);
        options.addOption(procedureArguments);
        options.addOption(instanceList);
        options.addOption(stepSize);
        options.addOption(comment);
        options.addOption(view);
        options.addOption(profile);
    }

    static {
        RestAssured.useRelaxedHTTPSValidation();
    }

    /**
     * Inits the YAML template.
     *
     * @param template the template
     * @param assembly the assembly
     * @throws BooException the Boo exception
     */
    public void init(File template, String assembly, Map<String, String> variables, String comment)
            throws BooException {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Loading {}", template);
        }
        LOG.info("Boo variables : " + variables);
        this.configFile = template;
        if (variables != null) {
            injector = Guice.createInjector(new JaywayHttpModule(this.configFile, variables));
        } else {
            injector = Guice.createInjector(new JaywayHttpModule(this.configFile, this.profile));
        }
        config = injector.getInstance(ClientConfig.class);
        booUtils.verifyTemplate(config);
        if (assembly != null) {
            config.getYaml().getAssembly().setName(assembly);
        }
        this.initOo(config, null, comment);
    }

    /**
     * Inits the OO.
     *
     * @param config the config
     * @param assembly the assembly
     */
    public void initOo(ClientConfig config, String assembly, String comment) {
        OOInstance oo = injector.getInstance(OOInstance.class);
        oo.setGzipEnabled(config.getYaml().getBoo().isGzipEnabled());
        try {
            if (assembly != null) {
                config.getYaml().getAssembly().setName(assembly);
            }
            flow = new BuildAllPlatforms(oo, config, comment);
        } catch (OneOpsClientAPIException e) {
            System.err.println("Init failed with " + e.getMessage());
        }
    }

    /**
     * Parse user's input.
     *
     * @param arg the arg
     * @throws ParseException the parse exception
     * @throws BooException the Boo exception
     * @throws OneOpsClientAPIException the one ops client API exception
     */
    public int parse(String[] arg) throws ParseException, BooException, OneOpsClientAPIException {
        CommandLineParser parser = new DefaultParser();
        int exit = 0;
        // CommandLineParser parser = new GnuParser();
        try {

            String assembly = null;
            CommandLine cmd = parser.parse(options, arg);
            /**
             * Handle command without configuration file dependency first.
             */
            if (cmd.hasOption("h")) {
                this.help(null, "");
                return exit;
            }

            if (cmd.hasOption("quiet")) {
                BooCli.setQuiet(Boolean.TRUE);
            }

            if (cmd.hasOption("force")) {
                BooCli.setForced(Boolean.TRUE);
            }
            if (cmd.hasOption("no-deploy")) {
                BooCli.setNoDeploy(Boolean.TRUE);
            }

            if (cmd.hasOption("a")) {
                assembly = cmd.getOptionValue("a");
            }
            /**
             * Get configuration dir or file.
             */
            if (cmd.hasOption("f")) {
                this.configFile = new File(booUtils.getAbsolutePath(cmd.getOptionValue("f")));
                System.out.printf(Constants.CONFIG_FILE, this.configFile);
                System.out.println();
            }

            if (this.configFile == null || !this.configFile.exists()) {
                this.help(null, "No YAML file found.");
                return Constants.EXIT_YAML_NOT_FOUND;
            }

            String yaml = "";

            if (ClientConfig.ONEOPS_CONFIG.exists()) {
                if (cmd.hasOption("profile")) {
                    this.profile = cmd.getOptionValue("profile");
                }
                ClientConfigIniReader iniReader = new ClientConfigIniReader();
                if (iniReader.read(ClientConfig.ONEOPS_CONFIG, profile) == null) {
                    System.out.format("%n%s is not a valid profile in %s.%n%n", profile,
                            ClientConfig.ONEOPS_CONFIG);
                    return Constants.EXIT_INVALID_PROFILE;
                }

                ClientConfigInterpolator interpolator = new ClientConfigInterpolator();
                yaml = interpolator.interpolate(this.configFile, ClientConfig.ONEOPS_CONFIG, this.profile);
            }

            if (cmd.hasOption('v')) {
                System.out.println(yaml);
                if (!ClientConfig.ONEOPS_CONFIG.exists()) {
                    System.out.format("%nYou do not have a %s file. No interpolation can be performed.%n%n",
                            ClientConfig.ONEOPS_CONFIG);
                }
                return exit;
            }

            if (cmd.hasOption("m")) {
                this.comment = cmd.getOptionValue("m");
            }

            this.init(this.configFile, assembly, null, comment);
            if (cmd.hasOption("l")) {
                String prefix = cmd.getOptionValue("l");
                if (prefix == null) {
                    this.listFiles(config.getYaml().getAssembly().getName());
                } else {
                    this.listFiles(prefix.trim());
                }
                return Constants.EXIT_NORMAL;
            }
            /**
             * Handle other commands.
             */
            if (cmd.hasOption("s")) {
                if (!flow.isAssemblyExist()) {
                    System.err.printf(Constants.NOTFOUND_ERROR, config.getYaml().getAssembly().getName());
                    return Constants.EXIT_ASSEMBLY_NOT_FOUND;
                } else {
                    System.out.println(this.getStatus());
                }
            } else if (cmd.hasOption("c")) {
                if (config.getYaml().getAssembly().getAutoGen()) {
                    this.initOo(this.config, this.autoGenAssemblyName(config.getYaml().getAssembly().getAutoGen(),
                            config.getYaml().getAssembly().getName()), comment);
                    LogUtils.info(Constants.CREATING_ASSEMBLY, config.getYaml().getAssembly().getName());
                }
                this.createPacks(Boolean.FALSE, isNoDeploy);
            } else if (cmd.hasOption("u")) {
                if (!config.getYaml().getAssembly().getAutoGen()) {
                    if (flow.isAssemblyExist()) {
                        this.createPacks(Boolean.TRUE, isNoDeploy);
                    } else {
                        System.err.printf(Constants.NOTFOUND_ERROR, config.getYaml().getAssembly().getName());
                    }
                } else {
                    List<String> assemblies = this.listFiles(this.config.getYaml().getAssembly().getName());
                    for (String asm : assemblies) {
                        this.initOo(config, asm, comment);
                        this.createPacks(Boolean.TRUE, isNoDeploy);
                    }
                }
            } else if (cmd.hasOption("r")) {
                List<String> assemblies;
                if (config.getYaml().getAssembly().getAutoGen()) {
                    assemblies = this.listFiles(this.config.getYaml().getAssembly().getName());
                } else {
                    assemblies = new ArrayList<String>();
                    String asb = this.config.getYaml().getAssembly().getName();
                    if (this.flow.isAssemblyExist(asb)) {
                        assemblies.add(asb);
                    }
                }
                this.cleanup(assemblies);
            } else if (cmd.hasOption("get-ips")) {
                if (!flow.isAssemblyExist()) {
                    System.err.printf(Constants.NOTFOUND_ERROR, config.getYaml().getAssembly().getName());
                } else if (cmd.getOptionValues("get-ips") == null) {
                    // if there is no args for get-ips
                    getIps0();
                } else if (cmd.getOptionValues("get-ips").length == 1) {
                    // if there is one arg for get-ips
                    getIps1(cmd.getOptionValues("get-ips")[0]);
                } else if (cmd.getOptionValues("get-ips").length == 2) {
                    // if there are two args for get-ips
                    getIps2(cmd.getOptionValues("get-ips")[0], cmd.getOptionValues("get-ips")[1]);
                }
            } else if (cmd.hasOption("retry")) {
                this.retryDeployment();
            } else if (cmd.hasOption("procedure")) {
                if (cmd.getOptionValues("procedure").length != 3) {
                    System.err.println("Wrong parameters! --prodedure <platformName> <componentName> <actionName>");
                    return Constants.EXIT_WRONG_PRAMETER;
                } else {
                    String[] args = cmd.getOptionValues("procedure");
                    String arglist = "";
                    int rollAt = 100;
                    if (cmd.hasOption("procedure-arguments")) {
                        arglist = cmd.getOptionValue("procedure-arguments");
                    }
                    if (cmd.hasOption("procedure-step-size")) {
                        rollAt = Integer.parseInt(cmd.getOptionValue("procedure-step-size"));
                    }
                    List<String> instances = null;
                    if (cmd.hasOption("procedure-instances")) {
                        String ins = cmd.getOptionValue("procedure-instances");
                        if (ins != null && ins.trim().length() > 0) {
                            if (ins.equalsIgnoreCase("list")) {
                                List<String> list = flow.listInstances(args[0], args[1]);
                                if (list != null) {
                                    for (String instance : list) {
                                        System.out.println(instance);
                                    }
                                }
                                return Constants.EXIT_NORMAL;
                            }
                            instances = Arrays.asList(ins.split(","));
                        }
                    }
                    if ("list".equalsIgnoreCase(args[2])) {
                        List<String> list = flow.listActions(args[0], args[1]);
                        if (list != null) {
                            for (String instance : list) {
                                System.out.println(instance);
                            }
                        }
                    } else {
                        exit = this.executeAction(args[0], args[1], args[2], arglist, instances, rollAt);
                    }

                }
            } else {
                System.err.println("Wrong parameters!");
                return Constants.EXIT_WRONG_PRAMETER;
            }
        } catch (ParseException e) {
            exit = Constants.EXIT_PARSE_ERROR;
        } catch (Exception e) {
            exit = Constants.EXIT_UNKOWN;
            e.printStackTrace(new PrintStream(System.err));
        }
        return exit;
    }

    /**
     * Execute action.
     *
     * @param platformName the platform name
     * @param componentName the component name
     * @param actionName the action name
     * @param arglist the arglist
     * @param instanceList the instance list
     * @param rollAt the roll at
     */
    private int executeAction(String platformName, String componentName, String actionName, String arglist,
            List<String> instanceList, int rollAt) {
        int returnCode = 0;
        Long procedureId = null;
        try {
            System.out.println(Constants.PROCEDURE_RUNNING);
            procedureId = flow.executeAction(platformName, componentName, actionName, arglist, instanceList,
                    rollAt);

        } catch (OneOpsClientAPIException e) {
            System.err.println(e.getMessage());
            returnCode = Constants.EXIT_CLIENT;
        }
        if (procedureId != null) {
            String procStatus = "active";
            try {
                while (procStatus != null
                        && (procStatus.equalsIgnoreCase("active") || procStatus.equalsIgnoreCase("pending"))) {
                    procStatus = flow.getProcedureStatus(procedureId);
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
            } catch (OneOpsClientAPIException e) {
                // Ignore
            }
            if (procStatus.equalsIgnoreCase("complete")) {
                System.out.println(Constants.SUCCEED);
            } else {
                System.err.println(Constants.PROCEDURE_NOT_COMPLETE);
                returnCode = Constants.EXIT_NOT_COMPLETE;
            }
        }
        return returnCode;
    }

    /**
     * User input.
     *
     * @param msg the msg
     * @return the string
     */
    @SuppressWarnings("resource")
    private String userInput(String msg) {
        System.out.println(msg);
        Scanner inputReader = new Scanner(System.in);
        String input = inputReader.nextLine();
        return input;
    }

    /**
     * Gets the ips 0.
     *
     * @return the ips 0
     */
    private void getIps0() {
        Map<String, Object> platforms = flow.getConfig().getYaml().getPlatforms();
        List<String> computes = booUtils.getComponentOfCompute(this.flow);
        System.out.println("Environment name: " + flow.getConfig().getYaml().getBoo().getEnvName());
        for (String pname : platforms.keySet()) {
            System.out.println("Platform name: " + pname);
            for (String cname : computes) {
                System.out.println("Compute name: " + cname);
                System.out.printf(getIps(pname, cname));
            }
        }
    }

    /**
     * Gets the ips 1.
     *
     * @param inputEnv the input env
     * @return the ips 1
     */
    private void getIps1(String inputEnv) {
        String yamlEnv = flow.getConfig().getYaml().getBoo().getEnvName();
        if (yamlEnv.equals(inputEnv)) {
            getIps0();
        } else {
            System.out.println(Constants.NO_ENVIRONMENT);
        }
    }

    /**
     * Gets the ips 2.
     *
     * @param inputEnv the input env
     * @param componentName the component name
     * @return the ips 2
     */
    private void getIps2(String inputEnv, String componentName) {
        String yamlEnv = flow.getConfig().getYaml().getBoo().getEnvName();
        if (inputEnv.equals("*") || yamlEnv.equals(inputEnv)) {
            Map<String, Object> platforms = flow.getConfig().getYaml().getPlatforms();
            List<String> computes = booUtils.getComponentOfCompute(this.flow);
            for (String s : computes) {
                if (s.equals(componentName)) {
                    System.out.println("Environment name: " + flow.getConfig().getYaml().getBoo().getEnvName());
                    for (String pname : platforms.keySet()) {
                        System.out.println("Platform name: " + pname);
                        System.out.println("Compute name: " + componentName);
                        System.out.printf(getIps(pname, componentName));
                    }
                    return;
                }
            }
            System.out.println("No such component: " + componentName);
        } else {
            System.out.println("No such environment: " + inputEnv);
        }
    }

    /**
     * Gets the ips.
     *
     * @param platformName the platform name
     * @param componentName the component name
     * @return the ips
     */
    private String getIps(String platformName, String componentName) {
        try {
            return flow.printIps(platformName, componentName);
        } catch (OneOpsClientAPIException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Retry deployment.
     *
     * @return true, if successful
     */
    private boolean retryDeployment() {
        return flow.retryDeployment();
    }

    /**
     * Help.
     *
     * @param header the header
     * @param footer the footer
     */
    private void help(String header, String footer) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(120, "boo", header, options, footer, true);
    }

    /**
     * List files.
     *
     * @param prefix the prefix
     * @return the list
     */
    private List<String> listFiles(String prefix) {
        if (prefix == null || prefix.trim().length() == 0) {
            System.err.println(Constants.ASSEMBLY_PREFIX_ERROR);
            System.exit(1);
        }
        List<String> assemblies = flow.getAllAutoGenAssemblies(prefix);
        for (String assembly : assemblies) {
            if (assembly != null) {
                System.out.println(assembly);
            }

        }
        return assemblies;
    }

    /**
     * Creates the packs.
     *
     * @param isUpdate the is update
     * @param isAssemblyOnly the is assembly only
     * @throws BooException the Boo exception
     * @throws OneOpsClientAPIException the one ops client API exception
     */
    public void createPacks(boolean isUpdate, boolean isAssemblyOnly)
            throws BooException, OneOpsClientAPIException {
        flow.process(isUpdate, isAssemblyOnly);
    }

    /**
     *  Creates platforms if the assembly does not exist. Updates the platform/components if assembly already exists
     * @throws BooException
     * @throws OneOpsClientAPIException
     */
    public Deployment createOrUpdatePlatforms()
            throws BooException, OneOpsClientAPIException, InterruptedException {
        Deployment deployment = null;
        if (flow.isAssemblyExist()) {
            deployment = flow.process(Boolean.TRUE, Boolean.FALSE);
        } else {
            deployment = flow.process(Boolean.FALSE, Boolean.FALSE);
        }

        if (deployment != null) {
            int sleepDurationSeconds = 5;
            int maxChecks = DEPLOYMENT_TIMEOUT_SECONDS / sleepDurationSeconds;

            for (int i = 0; i < maxChecks; i++) {
                deployment = flow.getDeployment(deployment.getDeploymentId());
                if (deployment.getDeploymentState().equals("active")) {
                    LogUtils.info(" .");
                    Thread.sleep(sleepDurationSeconds * 1000L);
                    continue;
                } else {
                    LogUtils.info("Deployment State is: " + deployment.getDeploymentState());
                    return deployment;
                }
            }
            LogUtils.info("Deployment running too long, Please check in OneOps");
        }
        return deployment;
    }

    /**
     * Limit to 32 characters long.
     *
     * @param isAutoGen the is auto gen
     * @param assemblyName the assembly name
     * @return the string
     */
    private String autoGenAssemblyName(boolean isAutoGen, String assemblyName) {
        if (isAutoGen) {
            assemblyName = (assemblyName == null ? this.randomString("")
                    : (assemblyName + Constants.DASH + this.randomString(assemblyName)));
        }
        return assemblyName;
    }

    /**
     * Random string.
     *
     * @param assemblyName the assembly name
     * @return the string
     */
    private String randomString(String assemblyName) {
        StringBuilder name = new StringBuilder();
        int rand = 32 - assemblyName.length() - 1;
        rand = rand > 8 ? 8 : rand;
        name.append(UUID.randomUUID().toString().substring(0, rand));
        return name.toString();
    }

    /**
     * Cleanup.
     *
     * @param assemblies the assemblies
     */
    public void cleanup(List<String> assemblies) {
        if (assemblies.size() == 0) {
            System.out.println("There is no instance to remove");
            return;
        }
        if (isForced == false) {
            String str = String.format(YES_NO, assemblies.size(), this.config.getYaml().getAssembly().getName());
            str = this.userInput(str);
            if (!"y".equalsIgnoreCase(str.trim())) {
                return;
            }

        }
        boolean isSuc = true;
        for (String assembly : assemblies) {
            LogUtils.info("Destroying OneOps assembly %s \n", assembly);
            this.initOo(config, assembly, comment);
            if (flow.isAssemblyExist(assembly)) {
                boolean isDone;
                try {
                    isDone = flow.removeAllEnvs();
                    isDone = flow.removeAllPlatforms();
                    if (!isDone && isSuc) {
                        isSuc = false;
                    }
                } catch (OneOpsClientAPIException e) {
                    isSuc = false;
                }
            }
        }
        if (!isSuc) {
            LogUtils.error(Constants.NEED_ANOTHER_CLEANUP);
        }
    }

    /**
     * Gets the status.
     *
     * @return the status
     * @throws BooException the Boo exception
     */
    public String getStatus() throws BooException {
        return flow.getStatus();
    }

    /**
     * Checks if is quiet.
     *
     * @return true, if is quiet
     */
    public static boolean isQuiet() {
        return isQuiet;
    }

    /**
     * Sets the quiet.
     *
     * @param isQuiet the new quiet
     */
    public static void setQuiet(boolean isQuiet) {
        BooCli.isQuiet = isQuiet;
    }

    /**
     * Sets the forced.
     *
     * @param isForced the new forced
     */
    public static void setForced(boolean isForced) {
        BooCli.isForced = isForced;
    }

    /**
     * Sets the no deploy.
     *
     * @param isNoDeploy the new no deploy
     */
    public static void setNoDeploy(boolean isNoDeploy) {
        BooCli.isNoDeploy = isNoDeploy;
    }

    /**
     * Checks if is no deploy.
     *
     * @return true, if is no deploy
     */
    public static boolean isNoDeploy() {
        return isNoDeploy;
    }
}