diff --git a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java index d41f6129df1..be7c1ce7576 100644 --- a/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java +++ b/nucleus/admin/cli/src/main/java/com/sun/enterprise/admin/cli/remote/RemoteCLICommand.java @@ -70,6 +70,8 @@ import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.BuilderHelper; +import org.jline.reader.EndOfFileException; +import org.jline.reader.UserInterruptException; import org.jvnet.hk2.component.MultiMap; import java.io.*; @@ -79,8 +81,6 @@ import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; -import org.jline.reader.EndOfFileException; -import org.jline.reader.UserInterruptException; /** * A remote command handled by the asadmin CLI. @@ -105,6 +105,7 @@ public class RemoteCLICommand extends CLICommand { private RemoteCLICommand.CLIRemoteAdminCommand rac; private final MultiMap> listeners = new MultiMap>(); + private int readTimeout; /** * A special RemoteAdminCommand that overrides methods so that we can handle @@ -156,6 +157,15 @@ public CLIRemoteAdminCommand(String name, String host, int port, boolean secure, super.setReadTimeout(Integer.parseInt(stimeout)); } } + + /** + * Set the RemoteRestCommand read timeout + * @param readTimeout timeout in milliseconds + */ + @Override + public void setReadTimeout(int readTimeout){ + super.setReadTimeout(readTimeout); + } @Override public void fetchCommandModel() throws CommandException { @@ -924,6 +934,9 @@ private void initializeRemoteAdminCommand() throws CommandException { programOpts.getPassword(), logger, programOpts.getAuthToken(),programOpts.isNotifyCommand()); rac.setFileOutputDirectory(outputDir); rac.setInteractive(programOpts.isInteractive()); + if (readTimeout > 0) { + rac.setReadTimeout(readTimeout); + } for (String key : listeners.keySet()) { for (AdminCommandListener listener : listeners.get(key)) { rac.registerListener(key, listener); @@ -1026,4 +1039,12 @@ private static synchronized ClassLoader getModuleClassLoader() { moduleClassLoader = new DirectoryClassLoader(modulesDir, CLICommand.class.getClassLoader()); return moduleClassLoader; } + + /** + * Set read timeout for RemoteRestCommand + * @param readTimeout + */ + public void setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + } } diff --git a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/LocalServerCommand.java b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/LocalServerCommand.java index 72d6da9f7c6..fb790a37508 100644 --- a/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/LocalServerCommand.java +++ b/nucleus/admin/server-mgmt/src/main/java/com/sun/enterprise/admin/servermgmt/cli/LocalServerCommand.java @@ -38,23 +38,10 @@ * holder. */ -// Portions Copyright [2016-2021] [Payara Foundation and/or affiliates] +// Portions Copyright [2016-2022] [Payara Foundation and/or affiliates] package com.sun.enterprise.admin.servermgmt.cli; -import static com.sun.enterprise.admin.servermgmt.domain.DomainConstants.MASTERPASSWORD_FILE; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.Socket; -import java.security.KeyStore; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.Arrays; - import com.sun.enterprise.admin.cli.CLICommand; import com.sun.enterprise.admin.cli.CLIConstants; import com.sun.enterprise.admin.cli.ProgramOptions; @@ -71,15 +58,9 @@ import com.sun.enterprise.util.SystemPropertyConstants; import com.sun.enterprise.util.io.FileUtils; import com.sun.enterprise.util.io.ServerDirs; - -import java.net.InetAddress; -import java.net.InetSocketAddress; - import org.glassfish.api.ActionReport; import org.glassfish.api.admin.CommandException; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; @@ -92,6 +73,19 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.XMLEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.security.KeyStore; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; + +import static com.sun.enterprise.admin.servermgmt.domain.DomainConstants.MASTERPASSWORD_FILE; /** * A class that's supposed to capture all the behavior common to operation on a @@ -409,23 +403,27 @@ protected boolean isRunning() { } } - /** - * Byron Nevins Says: We have quite a historical assortment of ways to determine - * if a server has restarted. There are little teeny timing issues with all of - * them. I'm confident that this new technique will clear them all up. Here we - * are just monitoring the PID of the new server and comparing it to the pid of - * the old server. The oldServerPid is guaranteed to be either the PID of the - * "old" server or -1 if we couldn't get it -- or it isn't running. If it is -1 - * then we make the assumption that once we DO get a valid pid that the server - * has started. If the old pid is valid we simply poll until we get a different - * pid. Notice that we will never get a valid pid back unless the server is - * officially up and running and "STARTED" Created April 2013 - * - * @param oldServerPid The pid of the server which is being restarted. - * @throws CommandException if we time out. - */ protected final void waitForRestart(final int oldServerPid) throws CommandException { - long end = getEndTime(); + waitForRestart(oldServerPid, CLIConstants.WAIT_FOR_DAS_TIME_MS); + } + + /** + * Byron Nevins Says: We have quite a historical assortment of ways to determine + * if a server has restarted. There are little teeny timing issues with all of + * them. I'm confident that this new technique will clear them all up. Here we + * are just monitoring the PID of the new server and comparing it to the pid of + * the old server. The oldServerPid is guaranteed to be either the PID of the + * "old" server or -1 if we couldn't get it -- or it isn't running. If it is -1 + * then we make the assumption that once we DO get a valid pid that the server + * has started. If the old pid is valid we simply poll until we get a different + * pid. Notice that we will never get a valid pid back unless the server is + * officially up and running and "STARTED" Created April 2013 + * + * @param oldServerPid The pid of the server which is being restarted. + * @throws CommandException if we time out. + */ + protected final void waitForRestart(final int oldServerPid, long timeout) throws CommandException { + long end = getEndTime(timeout); while (now() < end) { try { @@ -608,10 +606,8 @@ private long now() { return System.currentTimeMillis(); } - private long getEndTime() { - // it's a method in case we someday allow configuring this VERY long - // timeout at runtime. - return CLIConstants.WAIT_FOR_DAS_TIME_MS + now(); + private long getEndTime(long timeout) { + return timeout + now(); } protected boolean dataGridEncryptionEnabled() throws IOException, XMLStreamException { diff --git a/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/TimeoutParamDefaultCalculator.java b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/TimeoutParamDefaultCalculator.java new file mode 100644 index 00000000000..56a1f9dd355 --- /dev/null +++ b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/TimeoutParamDefaultCalculator.java @@ -0,0 +1,62 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2022 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.enterprise.admin.util; + +import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; +import org.glassfish.api.ExecutionContext; +import org.glassfish.api.ParamDefaultCalculator; + +/** + * Class to use within the @Param annotation for a calculator to get the timeout + * from either a System Property, Environment Property or a constant value + * + * @author Kalin Chan + */ +public class TimeoutParamDefaultCalculator extends ParamDefaultCalculator { + + public TimeoutParamDefaultCalculator() { + } + + @Override + public String defaultValue(ExecutionContext context) { + return String.valueOf(RemoteRestAdminCommand.getReadTimeout() / 1000) ; + } +} diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/ClusterCommandHelper.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/ClusterCommandHelper.java index 1e533e8ac89..b492181f6b9 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/ClusterCommandHelper.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/ClusterCommandHelper.java @@ -38,16 +38,19 @@ * holder. */ -// Portions Copyright [2018-2019] [Payara Foundation and/or its affiliates] +// Portions Copyright [2018-2022] [Payara Foundation and/or its affiliates] package com.sun.enterprise.v3.admin.cluster; -import static java.lang.Math.min; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.logging.Level.FINE; -import static org.glassfish.api.ActionReport.ExitCode.FAILURE; -import static org.glassfish.api.ActionReport.ExitCode.SUCCESS; -import static org.glassfish.api.ActionReport.ExitCode.WARNING; +import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; +import com.sun.enterprise.config.serverbeans.Cluster; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.Server; +import com.sun.enterprise.v3.admin.adapter.AdminEndpointDecider; +import org.glassfish.api.ActionReport; +import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandRunner.CommandInvocation; import java.util.ArrayList; import java.util.HashMap; @@ -58,20 +61,10 @@ import java.util.concurrent.Executors; import java.util.logging.Logger; -import org.glassfish.api.ActionReport; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandRunner; -import org.glassfish.api.admin.CommandRunner.CommandInvocation; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.ProgressStatus; - -import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; -import com.sun.enterprise.config.serverbeans.Cluster; -import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.Domain; -import com.sun.enterprise.config.serverbeans.Server; -import com.sun.enterprise.v3.admin.adapter.AdminEndpointDecider; +import static java.lang.Math.min; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.logging.Level.FINE; +import static org.glassfish.api.ActionReport.ExitCode.*; /* * ClusterCommandHelper is a helper class that knows how to execute an @@ -92,6 +85,7 @@ public class ClusterCommandHelper { private final CommandRunner runner; private ProgressStatus progress; + private long adminTimeout; /** * Construct a ClusterCommandHelper @@ -102,6 +96,7 @@ public class ClusterCommandHelper { public ClusterCommandHelper(Domain domain, CommandRunner runner) { this.domain = domain; this.runner = runner; + this.adminTimeout = RemoteRestAdminCommand.getReadTimeout(); } /** @@ -241,7 +236,7 @@ public ActionReport runCommand(String command, ParameterMap map, String targetNa // Make sure we don't wait longer than the admin read timeout. Set // our limit to be 3 seconds less. - long adminTimeout = RemoteRestAdminCommand.getReadTimeout() - 3000; + adminTimeout = adminTimeout - 3000; if (adminTimeout <= 0) { // This should never be the case adminTimeout = 57 * 1000; @@ -436,4 +431,12 @@ public static class ReportResult { public final List succeededServerNames = new ArrayList<>(); public final List failedServerNames = new ArrayList<>(); } + + /** + * Set the timeout for ClusterCommandHelper + * @param adminTimeout in milliseconds + */ + public void setAdminTimeout(long adminTimeout) { + this.adminTimeout = adminTimeout; + } } diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/LocalStrings.properties b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/LocalStrings.properties index 5ebe9e50eee..4f03a4947db 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/LocalStrings.properties +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/LocalStrings.properties @@ -37,7 +37,7 @@ # only if the new code is made subject to such option by the copyright # holder. # -## Portions Copyright [2018-2019] [Payara Foundation and/or its affiliates] +## Portions Copyright [2018-2022] [Payara Foundation and/or its affiliates] #####restart-instance restart.instance.notInstance=-_restart-instance only works on instances. This is a {0} @@ -152,6 +152,7 @@ start.dg.command=Start a deployment group start.dg=Starting deployment group {0} stop.dg=Stopping deployment group {0} restart.dg=Restarting deployment group {0} +restart.dg.timeout=Timed out while waiting for deployment group {0} to restart ## StartClusterCommand start.cluster.command=Start a cluster start.cluster=Starting cluster {0} diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartClusterCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartClusterCommand.java index 7427fff8bcf..bab602213b1 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartClusterCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartClusterCommand.java @@ -37,26 +37,24 @@ * only if the new code is made subject to such option by the copyright * holder. * - * Portions Copyright [2016-2018] [Payara Foundation and/or its affiliates] + * Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates] * */ package com.sun.enterprise.v3.admin.cluster; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Cluster; -import java.util.logging.Logger; - -import org.glassfish.api.admin.*; -import javax.inject.Inject; - - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.Param; +import com.sun.enterprise.config.serverbeans.Domain; import org.glassfish.api.ActionReport; import org.glassfish.api.ActionReport.ExitCode; +import org.glassfish.api.Param; +import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; +import org.jvnet.hk2.annotations.Service; -import com.sun.enterprise.config.serverbeans.Domain; +import javax.inject.Inject; +import java.util.logging.Logger; @Service(name = "restart-cluster") @ExecuteOn(value={RuntimeType.DAS}) @@ -88,19 +86,41 @@ public class RestartClusterCommand implements AdminCommand { @Param(optional = true, defaultValue = "false") private boolean verbose; - + @Param(optional = true, defaultValue = "true") private boolean rolling; - + @Param(optional = true, defaultValue = "0") private String delay; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int instanceTimeout; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override public void execute(AdminCommandContext context) { ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("restart.cluster", clusterName)); // Require that we be a DAS @@ -120,6 +140,8 @@ public void execute(AdminCommandContext context) { String commandName = "restart-instance"; ParameterMap pm = new ParameterMap(); pm.add("delay", delay); + pm.add("timeout", String.valueOf(instanceTimeout)); + clusterHelper.setAdminTimeout(timeout * 1000); clusterHelper.runCommand(commandName, pm, clusterName, context, verbose, rolling); } diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartInstanceCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartInstanceCommand.java index eed2ae29b36..df6e41d552b 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartInstanceCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/RestartInstanceCommand.java @@ -37,34 +37,33 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] [Payara Foundation and/or its affiliates] +// Portions Copyright [2018-2022] [Payara Foundation and/or its affiliates] package com.sun.enterprise.v3.admin.cluster; import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; import com.sun.enterprise.admin.remote.ServerRemoteRestAdminCommand; -import com.sun.enterprise.admin.util.*; -import com.sun.enterprise.config.serverbeans.Config; -import com.sun.enterprise.config.serverbeans.Domain; -import com.sun.enterprise.config.serverbeans.Node; -import com.sun.enterprise.config.serverbeans.Nodes; -import com.sun.enterprise.config.serverbeans.Server; +import com.sun.enterprise.admin.util.InstanceStateService; +import com.sun.enterprise.admin.util.RemoteInstanceCommandHelper; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; +import com.sun.enterprise.config.serverbeans.*; import com.sun.enterprise.util.OS; import com.sun.enterprise.util.ObjectAnalyzer; import com.sun.enterprise.util.StringUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; -import java.util.logging.Level; -import org.glassfish.api.*; +import org.glassfish.api.ActionReport; +import org.glassfish.api.I18n; +import org.glassfish.api.Param; import org.glassfish.api.admin.*; - -import org.jvnet.hk2.annotations.Service; import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.api.ServiceLocator; +import org.jvnet.hk2.annotations.Service; import javax.inject.Inject; import javax.inject.Named; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @@ -115,10 +114,13 @@ public class RestartInstanceCommand implements AdminCommand { @Param(name = "sync", optional = true, defaultValue = "normal", acceptableValues = "none, normal, full") private String sync; - - @Param(name="delay", optional = true, defaultValue = "0") + + @Param(name = "delay", optional = true, defaultValue = "0") private int delay; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + private Logger logger; private RemoteInstanceCommandHelper helper; @@ -134,9 +136,7 @@ public class RestartInstanceCommand implements AdminCommand { private String oldPid; private AdminCommandContext context; - - private static final long WAIT_TIME_MS = 600000; // 10 minutes - + @Override public void execute(AdminCommandContext ctx) { try { @@ -144,6 +144,15 @@ public void execute(AdminCommandContext ctx) { helper = new RemoteInstanceCommandHelper(habitat); report = context.getActionReport(); logger = context.getLogger(); + + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + report.setActionExitCode(ActionReport.ExitCode.SUCCESS); // Each of the methods below immediately returns if there has been an error @@ -158,7 +167,7 @@ public void execute(AdminCommandContext ctx) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, "Restart-instance old-pid = {0}", oldPid); callInstance(); - waitForRestart(); + checkForRestart(); if (!isError()) { String msg = Strings.get("restart.instance.success", instanceName); @@ -189,6 +198,7 @@ private void synchronizeInstance() { command.add(instanceName); } + // Convert the command into a string representing the command a human should run. // Convert the command into a string representing the command a human should run. humanCommand = makeCommandHuman(command); @@ -289,9 +299,10 @@ private void callInstance() throws CommandException { // notice how we do NOT send in the instance's name as an operand!! ParameterMap map = new ParameterMap(); - if (debug != null) + if (debug != null) { map.add("debug", debug); - + } + rac.setReadTimeout(timeout * 1000); rac.executeCommand(map); } @@ -315,35 +326,31 @@ private boolean isInstanceRestartable() throws InstanceNotRunningException { String val = rac.findPropertyInReport("restartable"); if (val != null && val.equals("false")) { return false; - } + } return true; } - private void waitForRestart() { - if (isError()) + private void checkForRestart() { + if (isError()) { return; - - long deadline = System.currentTimeMillis() + WAIT_TIME_MS; - - while (System.currentTimeMillis() < deadline) { - try { - String newpid = getPid(); - // when the next statement is true -- the server has restarted. - if (StringUtils.ok(newpid) && !newpid.equals(oldPid)) { - if (logger.isLoggable(Level.FINE)) - logger.fine("Restarted instance pid = " + newpid); - try { - Thread.sleep(delay); - } catch(InterruptedException ie) {} - return; + } + try { + String newpid = getPid(); + // when the next statement is true -- the server has restarted. + if (StringUtils.ok(newpid) && !newpid.equals(oldPid)) { + if (logger.isLoggable(Level.FINE)) { + logger.fine("Restarted instance pid = " + newpid); } - Thread.sleep(100);// don't busy wait - } - catch (Exception e) { - // ignore. This is normal! + try { + Thread.sleep(delay); + } catch (InterruptedException ie) { + } + return; } + } catch (Exception e) { + // ignore. This is normal! } - setError(Strings.get("restart.instance.timeout", instanceName)); + setError(Strings.get("restart.instance.racError", instanceName, "instance pid is the same")); } private RemoteRestAdminCommand createRac(String cmdName) throws CommandException { diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StartClusterCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StartClusterCommand.java index 1b399fdb3ca..ef303e4d135 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StartClusterCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StartClusterCommand.java @@ -37,24 +37,22 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] [Payara Foundation and/or its affiliates] +// Portions Copyright [2018-2022] [Payara Foundation and/or its affiliates] package com.sun.enterprise.v3.admin.cluster; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Cluster; -import java.util.logging.Logger; - -import org.glassfish.api.admin.*; -import javax.inject.Inject; - - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.I18n; -import org.glassfish.api.Param; +import com.sun.enterprise.config.serverbeans.Domain; import org.glassfish.api.ActionReport; import org.glassfish.api.ActionReport.ExitCode; +import org.glassfish.api.I18n; +import org.glassfish.api.Param; +import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; +import org.jvnet.hk2.annotations.Service; -import com.sun.enterprise.config.serverbeans.Domain; +import javax.inject.Inject; +import java.util.logging.Logger; @I18n("start.cluster.command") @Service(name = "start-cluster") @@ -87,13 +85,35 @@ public class StartClusterCommand implements AdminCommand { @Param(optional = true, defaultValue = "false") private boolean verbose; - + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int instanceTimeout; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override public void execute(AdminCommandContext context) { - + ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("start.cluster", clusterName)); // Require that we be a DAS @@ -107,12 +127,16 @@ public void execute(AdminCommandContext context) { ClusterCommandHelper clusterHelper = new ClusterCommandHelper(domain, runner); - + try { // Run start-instance against each instance in the cluster - String commandName = "start-instance"; - clusterHelper.runCommand(commandName, null, clusterName, context, - verbose); + String commandName = "start-instance"; + ParameterMap map = new ParameterMap(); + map.add("timeout", String.valueOf(instanceTimeout)); + clusterHelper.setAdminTimeout(timeout * 1000); + + clusterHelper.runCommand(commandName, map, clusterName, context, + verbose); } catch (CommandException e) { String msg = e.getLocalizedMessage(); diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopClusterCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopClusterCommand.java index 075e441dd98..5c0ddd5ff65 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopClusterCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopClusterCommand.java @@ -38,23 +38,23 @@ * holder. */ -// Portions Copyright [2018] [Payara Foundation and/or its affiliates] +// Portions Copyright [2018-2022] [Payara Foundation and/or its affiliates] package com.sun.enterprise.v3.admin.cluster; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Cluster; -import java.util.logging.Logger; -import javax.inject.Inject; - - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.I18n; -import org.glassfish.api.Param; +import com.sun.enterprise.config.serverbeans.Domain; import org.glassfish.api.ActionReport; import org.glassfish.api.ActionReport.ExitCode; -import com.sun.enterprise.config.serverbeans.Domain; +import org.glassfish.api.I18n; +import org.glassfish.api.Param; import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; +import org.jvnet.hk2.annotations.Service; + +import javax.inject.Inject; +import java.util.logging.Logger; @I18n("stop.cluster.command") @Service(name="stop-cluster") @@ -89,16 +89,38 @@ public class StopClusterCommand implements AdminCommand { @Param(optional = true, defaultValue = "false") private boolean verbose; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int instanceTimeout; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override public void execute(AdminCommandContext context) { ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("stop.cluster", clusterName)); // Require that we be a DAS - if(!env.isDas()) { + if (!env.isDas()) { String msg = Strings.get("cluster.command.notDas"); logger.warning(msg); report.setActionExitCode(ExitCode.FAILURE); @@ -109,14 +131,17 @@ public void execute(AdminCommandContext context) { ClusterCommandHelper clusterHelper = new ClusterCommandHelper(domain, runner); - ParameterMap map = null; + ParameterMap map = new ParameterMap(); if (kill) { - map = new ParameterMap(); map.add("kill", "true"); } + map.add("timeout", String.valueOf(instanceTimeout)); try { // Run start-instance against each instance in the cluster String commandName = "stop-instance"; + + clusterHelper.setAdminTimeout(timeout * 1000); + clusterHelper.runCommand(commandName, map, clusterName, context, verbose); } catch (CommandException e) { diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopInstanceCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopInstanceCommand.java index 09efcb38478..55aad61f9dc 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopInstanceCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/StopInstanceCommand.java @@ -42,44 +42,38 @@ package com.sun.enterprise.v3.admin.cluster; import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; -import com.sun.enterprise.util.cluster.windows.process.WindowsException; -import java.util.logging.Logger; -import java.util.logging.Level; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - import com.sun.enterprise.admin.remote.ServerRemoteRestAdminCommand; import com.sun.enterprise.admin.util.RemoteInstanceCommandHelper; -import com.sun.enterprise.config.serverbeans.*; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; +import com.sun.enterprise.config.serverbeans.Node; +import com.sun.enterprise.config.serverbeans.Nodes; +import com.sun.enterprise.config.serverbeans.Server; import com.sun.enterprise.module.ModulesRegistry; import com.sun.enterprise.util.StringUtils; +import com.sun.enterprise.util.cluster.windows.io.WindowsRemoteFile; +import com.sun.enterprise.util.cluster.windows.process.WindowsException; import com.sun.enterprise.v3.admin.StopServer; import org.glassfish.api.ActionReport; import org.glassfish.api.I18n; import org.glassfish.api.Param; -import org.glassfish.api.admin.AdminCommand; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.ExecuteOn; -import org.glassfish.api.admin.CommandLock; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.RuntimeType; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.hk2.api.IterableProvider; -import org.glassfish.internal.api.ServerContext; - -import com.sun.enterprise.util.cluster.windows.io.WindowsRemoteFile; import org.glassfish.api.admin.*; -import javax.inject.Inject; - -import org.jvnet.hk2.annotations.Service; -import org.glassfish.hk2.api.PostConstruct; -import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.sftp.SFTPClient; import org.glassfish.cluster.ssh.util.DcomInfo; +import org.glassfish.hk2.api.IterableProvider; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.hk2.api.PostConstruct; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.api.ServerContext; +import org.jvnet.hk2.annotations.Service; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; /** * AdminCommand to stop the instance @@ -108,22 +102,34 @@ public class StopInstanceCommand extends StopServer implements AdminCommand, Pos @Inject private ServiceLocator habitat; + @Inject private ServerContext serverContext; + @Inject private Nodes nodes; + @Inject private ServerEnvironment env; + @Inject IterableProvider nodeList; + @Inject private ModulesRegistry registry; + @Param(optional = true, defaultValue = "true") private Boolean force = true; + @Param(optional = true, defaultValue = "false") private Boolean kill = false; + @Param(optional = false, primary = true) private String instanceName; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + private Logger logger; private RemoteInstanceCommandHelper helper; private ActionReport report; @@ -131,13 +137,21 @@ public class StopInstanceCommand extends StopServer implements AdminCommand, Pos private String cmdName = "stop-instance"; private Server instance; File pidFile = null; - SFTPClient ftpClient=null; + SFTPClient ftpClient = null; private WindowsRemoteFile wrf; @Override public void execute(AdminCommandContext context) { report = context.getActionReport(); logger = context.getLogger(); + + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } SSHLauncher launcher; if (env.isDas()) { @@ -146,7 +160,7 @@ public void execute(AdminCommandContext context) { } else { errorMessage = callInstance(); } - } else { + } else { errorMessage = Strings.get("stop.instance.notDas", env.getRuntimeType().toString()); } @@ -349,50 +363,45 @@ private String killInstance(AdminCommandContext context) { // return null means A-OK private String pollForDeath() { - int counter = 0; // 120 seconds + long deadline = System.currentTimeMillis() + (timeout * 1000); - while (++counter < 240) { + while (System.currentTimeMillis() < deadline) { if (!instance.isRunning()) return null; try { Thread.sleep(500); - } - catch (Exception e) { + } catch (Exception e) { // ignore } } return Strings.get("stop.instance.timeout", instanceName); } - private String pollForRealDeath(String mode){ - int counter = 0; // 30 seconds + private String pollForRealDeath(String mode) { + long deadline = System.currentTimeMillis() + (timeout * 1000); - // 24 * 5 = 120 seconds - while (++counter < 24) { + while (System.currentTimeMillis() < deadline) { try { - if (mode.equals("local")){ - if(!pidFile.exists()){ + if (mode.equals("local")) { + if (!pidFile.exists()) { return null; } - }else if (mode.equals("SSH")){ + } else if (mode.equals("SSH")) { if (!ftpClient.exists(pidFile.toString())) return null; - }else if (mode.equals("DCOM")){ + } else if (mode.equals("DCOM")) { if (wrf == null || !wrf.exists()) return null; } - // Fairly long interval between tries because checking over // SSH is expensive. Thread.sleep(5000); } catch (Exception e) { // ignore } - } return Strings.get("stop.instance.timeout.completely", instanceName); - } private String makeCommandHuman(List command) { diff --git a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/RestartDeploymentGroupCommand.java b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/RestartDeploymentGroupCommand.java index 9f3beb013b9..452299746d5 100644 --- a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/RestartDeploymentGroupCommand.java +++ b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/RestartDeploymentGroupCommand.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2017-2019 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017-2022 Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -39,39 +39,35 @@ */ package fish.payara.admin.cluster; +import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Domain; import com.sun.enterprise.config.serverbeans.Server; import com.sun.enterprise.v3.admin.cluster.ClusterCommandHelper; import com.sun.enterprise.v3.admin.cluster.Strings; import fish.payara.enterprise.config.serverbeans.DeploymentGroup; -import java.util.List; -import java.util.logging.Logger; -import javax.inject.Inject; +import fish.payara.nucleus.executorservice.PayaraExecutorService; import org.glassfish.api.ActionReport; import org.glassfish.api.Param; -import org.glassfish.api.admin.AdminCommand; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandLock; -import org.glassfish.api.admin.CommandRunner; -import org.glassfish.api.admin.ExecuteOn; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.RestEndpoint; -import org.glassfish.api.admin.RestEndpoints; -import org.glassfish.api.admin.RestParam; -import org.glassfish.api.admin.RuntimeType; -import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; +import javax.inject.Inject; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + /** * Restarts all instances in a deployment group - * - * @since 5.0 + * * @author Steve Millidge (Payara Services Limited) + * @since 5.0 */ @Service(name = "restart-deployment-group") -@ExecuteOn(value={RuntimeType.DAS}) +@ExecuteOn(value = {RuntimeType.DAS}) @CommandLock(CommandLock.LockType.NONE) // don't prevent _synchronize-files @PerLookup @RestEndpoints({ @@ -86,7 +82,7 @@ public class RestartDeploymentGroupCommand implements AdminCommand { private static final String NL = System.lineSeparator(); - + @Inject private ServerEnvironment env; @@ -96,6 +92,9 @@ public class RestartDeploymentGroupCommand implements AdminCommand { @Inject private CommandRunner runner; + @Inject + private PayaraExecutorService executor; + @Param(optional = false, primary = true) private String deploymentGroup; @@ -104,15 +103,39 @@ public class RestartDeploymentGroupCommand implements AdminCommand { @Param(optional = true, defaultValue = "true") private boolean rolling; - + @Param(optional = true, defaultValue = "5000") private String delay; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int instanceTimeout; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + + private ActionReport report; + @Override public void execute(AdminCommandContext context) { ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("restart.dg", deploymentGroup)); // Require that we be a DAS @@ -123,9 +146,26 @@ public void execute(AdminCommandContext context) { report.setMessage(msg); return; } - + if (rolling) { - doRolling(context); + CountDownLatch commandTimeout = new CountDownLatch(1); + ScheduledFuture commandFuture = executor.schedule(() -> { + doRolling(context); + commandTimeout.countDown(); + }, 500, TimeUnit.MILLISECONDS); + try { + if (!commandTimeout.await(timeout <= 0 ? RemoteRestAdminCommand.getReadTimeout() : timeout, TimeUnit.SECONDS)) { + String msg = Strings.get("restart.dg.timeout", deploymentGroup); + + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + } catch (InterruptedException e) { + return; + } finally { + commandFuture.cancel(true); + } } else { ClusterCommandHelper clusterHelper = new ClusterCommandHelper(domain, @@ -133,36 +173,40 @@ public void execute(AdminCommandContext context) { ParameterMap pm = new ParameterMap(); pm.add("delay", delay); + + pm.add("timeout", String.valueOf(instanceTimeout)); + try { // Run restart-instance against each instance in the Deployment Group String commandName = "restart-instance"; + clusterHelper.setAdminTimeout(timeout * 1000); clusterHelper.runCommand(commandName, pm, deploymentGroup, context, verbose, rolling); - } - catch (CommandException e) { + } catch (CommandException e) { String msg = e.getLocalizedMessage(); logger.warning(msg); report.setActionExitCode(ActionReport.ExitCode.FAILURE); - report.setMessage(msg); + report.setMessage(msg); } } } private void doRolling(AdminCommandContext context) { List servers = domain.getServersInTarget(deploymentGroup); - StringBuilder output = new StringBuilder(); + StringBuilder output = new StringBuilder(); Logger logger = context.getLogger(); - + for (Server server : servers) { ParameterMap instanceParameterMap = new ParameterMap(); // Set the instance name as the operand for the commnd instanceParameterMap.set("DEFAULT", server.getName()); + instanceParameterMap.add("timeout", String.valueOf(instanceTimeout)); ActionReport instanceReport = runner.getActionReport("plain"); instanceReport.setActionExitCode(ActionReport.ExitCode.SUCCESS); CommandRunner.CommandInvocation invocation = runner.getCommandInvocation( - "stop-instance", instanceReport, context.getSubject()); - invocation.parameters(instanceParameterMap); + "stop-instance", instanceReport, context.getSubject()); + invocation.parameters(instanceParameterMap); String msg = "stop-instance" + " " + server.getName(); logger.info(msg); @@ -177,10 +221,11 @@ private void doRolling(AdminCommandContext context) { instanceParameterMap = new ParameterMap(); // Set the instance name as the operand for the commnd instanceParameterMap.set("DEFAULT", server.getName()); + instanceParameterMap.add("timeout", String.valueOf(instanceTimeout)); instanceReport.setActionExitCode(ActionReport.ExitCode.SUCCESS); invocation = runner.getCommandInvocation( - "start-instance", instanceReport, context.getSubject()); - invocation.parameters(instanceParameterMap); + "start-instance", instanceReport, context.getSubject()); + invocation.parameters(instanceParameterMap); msg = "start-instance" + " " + server.getName(); logger.info(msg); if (verbose) { diff --git a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StartDeploymentGroupCommand.java b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StartDeploymentGroupCommand.java index 1fb614e4f83..98a57a23cc1 100644 --- a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StartDeploymentGroupCommand.java +++ b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StartDeploymentGroupCommand.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2017-2019 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017-2022 Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -39,37 +39,26 @@ */ package fish.payara.admin.cluster; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Domain; import com.sun.enterprise.v3.admin.cluster.ClusterCommandHelper; import com.sun.enterprise.v3.admin.cluster.Strings; import fish.payara.enterprise.config.serverbeans.DeploymentGroup; -import java.util.logging.Logger; -import javax.inject.Inject; -import javax.validation.constraints.Min; import org.glassfish.api.ActionReport; import org.glassfish.api.I18n; import org.glassfish.api.Param; -import org.glassfish.api.admin.AdminCommand; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandLock; -import org.glassfish.api.admin.CommandRunner; -import org.glassfish.api.admin.ExecuteOn; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.Progress; -import org.glassfish.api.admin.RestEndpoint; -import org.glassfish.api.admin.RestEndpoints; -import org.glassfish.api.admin.RestParam; -import org.glassfish.api.admin.RuntimeType; -import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; +import javax.inject.Inject; +import java.util.logging.Logger; + /** * Starts all instances in a deployment group - * - * @since 5.0 + * * @author Steve Millidge (Payara Services Limited) + * @since 5.0 */ @I18n("start.dg.command") @@ -88,7 +77,7 @@ }) @Progress public class StartDeploymentGroupCommand implements AdminCommand { - + @Inject private ServerEnvironment env; @@ -103,16 +92,34 @@ public class StartDeploymentGroupCommand implements AdminCommand { @Param(optional = true, shortName = "v", defaultValue = "false") private boolean verbose; - - @Min(message = "Timeout must be at least 1 second long.", value = 1) - @Param(optional = true, shortName = "t", defaultValue = "120") + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) private int instanceTimeout; - + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override public void execute(AdminCommandContext context) { ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("start.dg", deploymentGroup)); // Require that we be a DAS @@ -129,10 +136,10 @@ public void execute(AdminCommandContext context) { try { // Run start-instance with timeout parameter against each instance in the Deployment Group String commandName = "start-instance"; - + ParameterMap parameterMap = new ParameterMap(); parameterMap.add("timeout", String.valueOf(instanceTimeout)); - + clusterHelper.setAdminTimeout(timeout * 1000); clusterHelper.runCommand(commandName, parameterMap, deploymentGroup, context, verbose); } catch (CommandException e) { String msg = e.getLocalizedMessage(); diff --git a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StopDeploymentGroupCommand.java b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StopDeploymentGroupCommand.java index 4b26124d875..1cce6255bbf 100644 --- a/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StopDeploymentGroupCommand.java +++ b/nucleus/cluster/admin/src/main/java/fish/payara/admin/cluster/StopDeploymentGroupCommand.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2017 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017-2022 Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -39,36 +39,29 @@ */ package fish.payara.admin.cluster; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.config.serverbeans.Domain; import com.sun.enterprise.v3.admin.cluster.ClusterCommandHelper; import com.sun.enterprise.v3.admin.cluster.Strings; import fish.payara.enterprise.config.serverbeans.DeploymentGroup; -import java.util.logging.Logger; -import javax.inject.Inject; import org.glassfish.api.ActionReport; import org.glassfish.api.I18n; import org.glassfish.api.Param; -import org.glassfish.api.admin.AdminCommand; -import org.glassfish.api.admin.AdminCommandContext; -import org.glassfish.api.admin.CommandException; -import org.glassfish.api.admin.CommandRunner; -import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.Progress; -import org.glassfish.api.admin.RestEndpoint; -import org.glassfish.api.admin.RestEndpoints; -import org.glassfish.api.admin.RestParam; -import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.admin.*; import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; +import javax.inject.Inject; +import java.util.logging.Logger; + /** * Stops all instances in a deployment group - * - * @since 5.0 + * * @author Steve Millidge (Payara Services Limited) + * @since 5.0 */ @I18n("stop.dg.command") -@Service(name="stop-deployment-group") +@Service(name = "stop-deployment-group") @PerLookup @RestEndpoints({ @RestEndpoint(configBean=DeploymentGroup.class, @@ -99,17 +92,38 @@ public class StopDeploymentGroupCommand implements AdminCommand{ @Param(optional = true, defaultValue = "false") private boolean verbose; - + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int instanceTimeout; + + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override public void execute(AdminCommandContext context) { - ActionReport report = context.getActionReport(); Logger logger = context.getLogger(); + if (timeout <= 0) { + String msg = "Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + + if (instanceTimeout <= 0) { + String msg = "Instance Timeout must be at least 1 second long."; + logger.warning(msg); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + report.setMessage(msg); + return; + } + logger.info(Strings.get("stop.dg", deploymentGroup)); // Require that we be a DAS - if(!env.isDas()) { + if (!env.isDas()) { String msg = Strings.get("cluster.command.notDas"); logger.warning(msg); report.setActionExitCode(ActionReport.ExitCode.FAILURE); @@ -120,14 +134,16 @@ public void execute(AdminCommandContext context) { ClusterCommandHelper clusterHelper = new ClusterCommandHelper(domain, runner); - ParameterMap map = null; + ParameterMap map = new ParameterMap(); if (kill) { - map = new ParameterMap(); map.add("kill", "true"); } + map.add("timeout", String.valueOf(instanceTimeout)); + try { // Run start-instance against each instance in the cluster String commandName = "stop-instance"; + clusterHelper.setAdminTimeout(Integer.valueOf(timeout) * 1000); clusterHelper.runCommand(commandName, map, deploymentGroup, context, verbose); } catch (CommandException e) { @@ -136,5 +152,5 @@ public void execute(AdminCommandContext context) { report.setActionExitCode(ActionReport.ExitCode.FAILURE); report.setMessage(msg); } - } + } } diff --git a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/restart-instance.1 b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/restart-instance.1 index 9dfc2961a79..fef8c4f57a8 100644 --- a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/restart-instance.1 +++ b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/restart-instance.1 @@ -5,7 +5,8 @@ NAME SYNOPSIS restart-instance [--help] - [--debug={false|true}] instance-name + [--debug={false|true}] + [--timeout timeout] instance-name DESCRIPTION The restart-instance subcommand restarts a running GlassFish Server @@ -81,6 +82,10 @@ OPTIONS The default is the current setting of this option for the instance that is being restarted. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name The name of the GlassFish Server instance to restart. If the diff --git a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-cluster.1 b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-cluster.1 index 068f3c168f8..e8d85ed7a87 100644 --- a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-cluster.1 +++ b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-cluster.1 @@ -5,7 +5,8 @@ NAME SYNOPSIS start-cluster [--help] [--autohadboverride={true|false}] - [--verbose={false|true}] cluster-name + [--verbose={false|true}] [--timeout timeout] + [--instancetimeout timeout] cluster-name DESCRIPTION The start-cluster subcommand starts a cluster by starting all GlassFish @@ -59,6 +60,14 @@ OPTIONS false Displays no additional status information (default). + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + + --instancetimeout + Specifies the amount of time in seconds each instance will attempt to start + before timing out. + OPERANDS cluster-name The name of the cluster to start. diff --git a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-instance.1 b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-instance.1 index c7c029111cc..dce755ac0c9 100644 --- a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-instance.1 +++ b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/start-instance.1 @@ -6,7 +6,7 @@ NAME SYNOPSIS start-instance [--help] [--debug={false|true}] [--sync={normal|full|none}] - instance-name + [--timeout timeout] instance-name DESCRIPTION The start-instance subcommand starts a GlassFish Server instance. This @@ -94,6 +94,10 @@ OPTIONS the startup of the instance while the DAS updates all files in the instance's directories. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name The name of the GlassFish Server instance to start. diff --git a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-cluster.1 b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-cluster.1 index 0deea2b50fe..f67da43b186 100644 --- a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-cluster.1 +++ b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-cluster.1 @@ -8,7 +8,8 @@ SYNOPSIS [--verbose={false|true}] [--kill={false|true}] [--autohadboverride={true|false}] - cluster-name + [--timeout timeout] + [--instancetimeout timeout] cluster-name DESCRIPTION The stop-cluster subcommand stops a GlassFish Server cluster by @@ -57,6 +58,14 @@ OPTIONS successfully and displays a warning message that the option is ignored. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + + --instancetimeout + Specifies the amount of time in seconds each instance will attempt to shutdown + before timing out. + OPERANDS cluster-name The name of the cluster to stop. diff --git a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-instance.1 b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-instance.1 index 6b44bfd1b74..578cffb825f 100644 --- a/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-instance.1 +++ b/nucleus/cluster/admin/src/main/manpages/com/sun/enterprise/v3/admin/cluster/stop-instance.1 @@ -6,7 +6,7 @@ NAME SYNOPSIS stop-instance [--help] [--force={false|true}] [--kill={false|true}] - instance-name + [--timeout timeout] instance-name DESCRIPTION The stop-instance subcommand stops a running GlassFish Server instance. @@ -49,6 +49,10 @@ OPTIONS The instance is killed. The subcommand uses functionality of the operating system to terminate the instance process. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name This is the name of the GlassFish Server instance to stop. diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/RestartLocalInstanceCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/RestartLocalInstanceCommand.java index e99401b36e6..f3cd2a26809 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/RestartLocalInstanceCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/RestartLocalInstanceCommand.java @@ -37,23 +37,28 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018-2019] Payara Foundation and/or affiliates +// Portions Copyright [2018-2022] Payara Foundation and/or affiliates package com.sun.enterprise.admin.cli.cluster; -import java.io.*; -import java.util.*; -import java.util.logging.*; -import org.jvnet.hk2.annotations.Service; -import org.glassfish.api.Param; -import org.glassfish.api.admin.*; -import org.glassfish.hk2.api.PerLookup; -import com.sun.enterprise.admin.cli.*; -import com.sun.enterprise.util.ObjectAnalyzer; +import com.sun.enterprise.admin.cli.CLICommand; import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.util.HostAndPort; -import javax.inject.Inject; +import com.sun.enterprise.util.ObjectAnalyzer; +import org.glassfish.api.Param; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.api.ServiceLocator; +import org.jvnet.hk2.annotations.Service; + +import javax.inject.Inject; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; /** * Restart a local server instance. @@ -66,6 +71,9 @@ public class RestartLocalInstanceCommand extends SynchronizeInstanceCommand { @Param(optional = true, shortName = "d", defaultValue = "false") private Boolean debug; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Inject private ServiceLocator habitat; @@ -131,7 +139,8 @@ protected final int doRemoteCommand() throws CommandException { cmd.executeAndReturnOutput("_restart-instance"); } - waitForRestart(oldServerPid); + waitForRestart(oldServerPid, (timeout * 1000)); + return 0; } @@ -187,12 +196,15 @@ protected boolean mkdirs(File f) { protected void validate() throws CommandException { super.validate(); + if (timeout <= 0) { + throw new CommandException("Timeout must be at least 1 second long."); + } + File dir = getServerDirs().getServerDir(); if (!dir.isDirectory()) { throw new CommandException(Strings.get("Instance.noSuchInstance")); } - } /** diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StartLocalInstanceCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StartLocalInstanceCommand.java index 904841c8e7c..31ee834d326 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StartLocalInstanceCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StartLocalInstanceCommand.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2017-2020] Payara Foundation and/or affiliates +// Portions Copyright [2017-2022] Payara Foundation and/or affiliates package com.sun.enterprise.admin.cli.cluster; import com.sun.enterprise.admin.launcher.GFLauncher; @@ -46,15 +46,9 @@ import com.sun.enterprise.admin.launcher.GFLauncherInfo; import com.sun.enterprise.admin.servermgmt.cli.StartServerCommand; import com.sun.enterprise.admin.servermgmt.cli.StartServerHelper; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.universal.xml.MiniXmlParserException; import com.sun.enterprise.util.ObjectAnalyzer; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import javax.validation.constraints.Min; - import org.glassfish.api.Param; import org.glassfish.api.admin.CommandException; import org.glassfish.api.admin.ExecuteOn; @@ -62,10 +56,11 @@ import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; -import static com.sun.enterprise.admin.cli.CLIConstants.RESTART_DEBUG_OFF; -import static com.sun.enterprise.admin.cli.CLIConstants.RESTART_DEBUG_ON; -import static com.sun.enterprise.admin.cli.CLIConstants.RESTART_NORMAL; -import static com.sun.enterprise.admin.cli.CLIConstants.WALL_CLOCK_START_PROP; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static com.sun.enterprise.admin.cli.CLIConstants.*; import static java.util.Arrays.asList; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Level.FINE; @@ -91,8 +86,7 @@ public class StartLocalInstanceCommand extends SynchronizeInstanceCommand implem @Param(name = "dry-run", shortName = "n", optional = true, defaultValue = "false") private boolean dryRun; - @Min(message = "Timeout must be at least 1 second long.", value = 1) - @Param(optional = true, defaultValue = "600") + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) private int timeout; // In Seconds, by default 10 minutes for historical reasons private StartServerHelper startServerHelper; @@ -142,10 +136,9 @@ protected void validate() throws CommandException { throw new CommandException(Strings.get("Instance.noSuchInstance")); } - if (timeout < 1) { + if (timeout <= 0) { throw new CommandException("Timeout must be at least 1 second long."); } - } @Override diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StopLocalInstanceCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StopLocalInstanceCommand.java index 0d216b8f9b9..adc2103196c 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StopLocalInstanceCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/StopLocalInstanceCommand.java @@ -37,27 +37,29 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2019] Payara Foundation and/or affiliates +// Portions Copyright [2019-2022] Payara Foundation and/or affiliates package com.sun.enterprise.admin.cli.cluster; -import java.util.logging.Level; -import com.sun.enterprise.admin.cli.*; import com.sun.enterprise.admin.cli.remote.RemoteCLICommand; +import com.sun.enterprise.admin.util.TimeoutParamDefaultCalculator; import com.sun.enterprise.universal.process.ProcessUtils; import com.sun.enterprise.util.HostAndPort; import com.sun.enterprise.util.io.FileUtils; -import java.io.*; import org.glassfish.api.Param; -import org.glassfish.api.admin.*; +import org.glassfish.api.admin.CommandException; +import org.glassfish.api.admin.CommandValidationException; import org.glassfish.hk2.api.PerLookup; import org.jvnet.hk2.annotations.Service; +import java.io.File; +import java.util.logging.Level; + /** * Stop a local server instance. + * * @author Bill Shannon * @author Byron Nevins - * */ @Service(name = "stop-local-instance") @PerLookup @@ -65,13 +67,21 @@ public class StopLocalInstanceCommand extends LocalInstanceCommand { @Param(optional = true, defaultValue = "true") private Boolean force; + @Param(name = "instance_name", primary = true, optional = true) private String userArgInstanceName; + @Param(optional = true, defaultValue = "false") Boolean kill; + @Param(optional = true, defaultCalculator = TimeoutParamDefaultCalculator.class) + private int timeout; + @Override protected void validate() throws CommandException, CommandValidationException { + if (timeout <= 0) { + throw new CommandException("Timeout must be at least 1 second long."); + } instanceName = userArgInstanceName; super.validate(); } @@ -213,6 +223,7 @@ private Exception runRemoteStop() { // 2 catch blocks just to make things crystal clear. try { RemoteCLICommand cmd = new RemoteCLICommand("_stop-instance", programOpts, env); + cmd.setReadTimeout(timeout * 1000); cmd.executeAndReturnOutput("_stop-instance", "--force", force.toString()); return null; } catch (CommandException e) { @@ -260,12 +271,12 @@ private void waitForDeath() throws CommandException { } if (alive) { - throw new CommandException(Strings.get("StopInstance.instanceNotDead", (CLIConstants.DEATH_TIMEOUT_MS / 1000))); + throw new CommandException(Strings.get("StopInstance.instanceNotDead", timeout)); } } private boolean timedOut(long startTime) { - return (System.currentTimeMillis() - startTime) > CLIConstants.DEATH_TIMEOUT_MS; + return (System.currentTimeMillis() - startTime) > (timeout * 1000); } private int kill() throws CommandException { diff --git a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/restart-local-instance.1 b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/restart-local-instance.1 index 4a4871c66bc..3e22a7cae2c 100644 --- a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/restart-local-instance.1 +++ b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/restart-local-instance.1 @@ -9,7 +9,7 @@ SYNOPSIS [--nodedir nodedir] [--node node] [--debug={false|true}] [--force={true|false}] [--kill={false|true}] - [instance-name] + [--timeout timeout] [instance-name] DESCRIPTION The restart-local-instance subcommand restarts a GlassFish Server @@ -121,6 +121,10 @@ OPTIONS The instance is killed. The subcommand uses functionality of the operating system to terminate the instance process. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name The name of the GlassFish Server instance to restart. If the diff --git a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/start-local-instance.1 b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/start-local-instance.1 index 8c82367869a..929c396a5ac 100644 --- a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/start-local-instance.1 +++ b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/start-local-instance.1 @@ -10,7 +10,7 @@ SYNOPSIS [--debug={false|true}] [--dry-run={true|false}] [--sync={normal|full|none}] [--verbose={false|true}] [--watchdog={true|false}] - [instance-name] + [--timeout timeout] [instance-name] DESCRIPTION The start-local-instance subcommand starts a GlassFish Server instance @@ -170,6 +170,10 @@ OPTIONS Limited information is not displayed in the console window (default). + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name The name of the instance to start. diff --git a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/stop-local-instance.1 b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/stop-local-instance.1 index a7830a4b7b6..fa5f19e0b3e 100644 --- a/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/stop-local-instance.1 +++ b/nucleus/cluster/cli/src/main/manpages/com/sun/enterprise/admin/cli/cluster/stop-local-instance.1 @@ -8,7 +8,7 @@ SYNOPSIS stop-local-instance [--help] [--nodedir node-dir] [--node node] [--force={true|false}] [--kill={false|true}] - [instance-name] + [--timeout timeout] [instance-name] DESCRIPTION The stop-local-instance subcommand stops a GlassFish Server instance on @@ -70,6 +70,10 @@ OPTIONS The instance is killed. The subcommand uses functionality of the operating system to terminate the instance process. + --timeout + Specifies the amount of time in seconds the command will run for before timing + out. + OPERANDS instance-name The name of the instance to stop.