From 6fc795ac1fb0585952dd460ed827b3bdfebe07e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mat=C4=9Bj=C4=8Dek?= Date: Mon, 20 Jan 2025 21:41:44 +0100 Subject: [PATCH] Additional cleanups - formatting, syntax, logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: David Matějček --- .../admin/util/JvmOptionsHelper.java | 15 +- .../cluster/CreateNodeConfigCommand.java | 24 +- .../v3/admin/cluster/LocalStrings.properties | 2 +- .../v3/admin/cluster/NodeUtils.java | 40 +--- .../cluster/SecureAdminBootstrapHelper.java | 81 +++---- .../v3/admin/cluster/SetupSshCommand.java | 2 +- .../v3/admin/cluster/StopInstanceCommand.java | 12 +- .../v3/admin/cluster/UpdateNodeCommand.java | 70 +++--- .../CreateLocalInstanceFilesystemCommand.java | 17 +- .../cli/cluster/InstallNodeBaseCommand.java | 65 +++--- .../cli/cluster/InstallNodeSshCommand.java | 84 +++---- .../cli/cluster/LocalInstanceCommand.java | 56 +++-- .../admin/cli/cluster/LocalStrings.properties | 6 - .../cli/cluster/UninstallNodeSshCommand.java | 2 +- .../cluster/ssh/connect/NodeRunnerSsh.java | 15 +- .../launcher/RemoteSystemCapabilities.java | 16 +- .../cluster/ssh/launcher/SSHException.java | 10 +- .../cluster/ssh/launcher/SSHLauncher.java | 215 ++++++++++-------- .../cluster/ssh/launcher/SSHSession.java | 134 +++++------ .../cluster/ssh/sftp/SFTPClient.java | 128 +++++++---- .../util/logging/LoggingConfigImpl.java | 7 +- .../sun/enterprise/util/io/InstanceDirs.java | 42 +--- .../util/io/LocalStrings.properties | 2 +- .../internal/api/RelativePathResolver.java | 34 ++- .../logging/logviewer/backend/LogFilter.java | 23 +- .../backend/LogFilterForInstance.java | 34 ++- 26 files changed, 556 insertions(+), 580 deletions(-) diff --git a/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/JvmOptionsHelper.java b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/JvmOptionsHelper.java index 9e6ab27e66f..bf5bc28f557 100644 --- a/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/JvmOptionsHelper.java +++ b/nucleus/admin/util/src/main/java/com/sun/enterprise/admin/util/JvmOptionsHelper.java @@ -78,13 +78,13 @@ public String[] addJvmOptions(String[] options) throws InvalidJvmOptionException } final Set alreadyExist = new HashSet(); JvmOptionsElement last = last(); - for (int i = 0; i < options.length; i++) { - if (!head.hasOption(options[i])) { - JvmOptionsElement x = new JvmOptionsElement(options[i]); + for (String option : options) { + if (!head.hasOption(option)) { + JvmOptionsElement x = new JvmOptionsElement(option); last.setNext(x); last = x; } else { - alreadyExist.add(options[i]); + alreadyExist.add(option); } } return toStringArray(alreadyExist); @@ -115,9 +115,9 @@ public String[] deleteJvmOptions(String[] options) { } final Set donotExist = new HashSet(); - for (int i = 0; i < options.length; i++) { - if (!head.deleteJvmOption(options[i])) { - donotExist.add(options[i]); + for (String option : options) { + if (!head.deleteJvmOption(option)) { + donotExist.add(option); } } return toStringArray(donotExist); @@ -209,6 +209,7 @@ void setNext(JvmOptionsElement element) { throw new UnsupportedOperationException(); } }; + private final Set jvmOptions = new LinkedHashSet(); private JvmOptionsElement next; diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/CreateNodeConfigCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/CreateNodeConfigCommand.java index bceadb2c04e..e519d9df982 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/CreateNodeConfigCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/CreateNodeConfigCommand.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025 Contributors to the Eclipse Foundation * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -24,6 +25,7 @@ import jakarta.inject.Inject; import java.io.File; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -86,15 +88,12 @@ public void execute(AdminCommandContext context) { TokenResolver resolver = null; // Create a resolver that can replace system properties in strings - Map systemPropsMap = - new HashMap((Map)(System.getProperties())); + Map systemPropsMap = new HashMap((Map) (System.getProperties())); resolver = new TokenResolver(systemPropsMap); - String resolvedInstallDir = resolver.resolve(installdir); - File actualInstallDir = new File( resolvedInstallDir+"/" + NodeUtils.LANDMARK_FILE); - - - if (!actualInstallDir.exists()){ - report.setMessage(Strings.get("invalid.installdir",installdir)); + Path resolvedInstallDir = new File(resolver.resolve(installdir)).toPath(); + Path actualInstallDir = resolvedInstallDir.resolve(NodeUtils.LANDMARK_FILE); + if (!actualInstallDir.toFile().exists()) { + report.setMessage(Strings.get("invalid.installdir", installdir)); report.setActionExitCode(ActionReport.ExitCode.FAILURE); return; } @@ -103,12 +102,15 @@ public void execute(AdminCommandContext context) { CommandInvocation ci = cr.getCommandInvocation("_create-node", report, context.getSubject()); ParameterMap map = new ParameterMap(); map.add("DEFAULT", name); - if (StringUtils.ok(nodedir)) + if (StringUtils.ok(nodedir)) { map.add(NodeUtils.PARAM_NODEDIR, nodedir); - if (StringUtils.ok(installdir)) + } + if (StringUtils.ok(installdir)) { map.add(NodeUtils.PARAM_INSTALLDIR, installdir); - if (StringUtils.ok(nodehost)) + } + if (StringUtils.ok(nodehost)) { map.add(NodeUtils.PARAM_NODEHOST, nodehost); + } map.add(NodeUtils.PARAM_TYPE,"CONFIG"); ci.parameters(map); ci.execute(); 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 0a5b7028af9..cd771ade30a 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 @@ -205,7 +205,7 @@ update.node.ssh.not.updated=Node not updated. To force an update of the \ update.node.config.missing.attribute={1} attribute is required to update node {0}. update.node.config.defaultnode=Cannot update node {0}. It is the built-in localhost node. node.ssh.invalid.params=Warning: some parameters appear to be invalid. -ssh.bad.connect=Could not connect to host {0} using {1}. +ssh.bad.connect=Could not connect to host {0} using {1}. Cause: {2} ssh.invalid.port=Invalid port number {0}. key.path.not.absolute=Key file path {0} must be an absolute path. key.path.not.found=Key file {0} not found. The key file path must be reachable by the DAS. diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/NodeUtils.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/NodeUtils.java index 076ce54e726..d7d31a23e54 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/NodeUtils.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/NodeUtils.java @@ -28,8 +28,6 @@ import com.sun.enterprise.util.net.NetUtils; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.file.Path; @@ -45,6 +43,7 @@ import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.admin.SSHCommandExecutionException; import org.glassfish.cluster.ssh.connect.NodeRunner; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.internal.api.RelativePathResolver; @@ -284,16 +283,10 @@ private void pingSSHConnection(Node node) throws CommandValidationException { SSHLauncher sshL = new SSHLauncher(node); try { sshL.pingConnection(); - } catch (Exception e) { - String m1 = e.getMessage(); - String m2 = ""; - Throwable e2 = e.getCause(); - if (e2 != null) { - m2 = e2.getMessage(); - } - String msg = Strings.get("ssh.bad.connect", node.getNodeHost(), "SSH"); - logger.log(WARNING, StringUtils.cat(": ", msg, m1, m2), e); - throw new CommandValidationException(StringUtils.cat(NL, msg, m1, m2), e); + } catch (SSHException e) { + String msg = Strings.get("ssh.bad.connect", node.getNodeHost(), "SSH", e.getMessage()); + logger.log(WARNING, msg, e); + throw new CommandValidationException(msg, e); } } @@ -337,25 +330,14 @@ private void validateSSHConnection(ParameterMap map) throws sshpassword, keyFile == null ? null : new File(keyFile), sshkeypassphrase); try { Path pathToCheck = resolvedInstallDir.resolve(LANDMARK_FILE); - if (!sshLauncher.exists(pathToCheck)) { - throw new FileNotFoundException( + if (!installFlag && !sshLauncher.exists(pathToCheck)) { + throw new CommandValidationException( "Invalid install directory: could not find " + pathToCheck + " on " + host); } - } catch (IOException e) { - String m1 = e.getMessage(); - String m2 = ""; - Throwable e2 = e.getCause(); - if (e2 != null) { - m2 = e2.getMessage(); - } - if (e instanceof FileNotFoundException) { - if (!installFlag) { - throw new CommandValidationException(StringUtils.cat(NL, m1, m2), e); - } - } else { - String msg = Strings.get("ssh.bad.connect", nodehost, "SSH"); - throw new CommandValidationException(StringUtils.cat(NL, msg, m1, m2), e); - } + } catch (SSHException e) { + String msg = Strings.get("ssh.bad.connect", nodehost, "SSH", e.getMessage()); + logger.log(WARNING, msg, e); + throw new CommandValidationException(msg, e); } } diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SecureAdminBootstrapHelper.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SecureAdminBootstrapHelper.java index 59c6fc65fb1..baa49ae0a53 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SecureAdminBootstrapHelper.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SecureAdminBootstrapHelper.java @@ -17,9 +17,7 @@ package com.sun.enterprise.v3.admin.cluster; -import com.jcraft.jsch.JSchException; import com.jcraft.jsch.SftpATTRS; -import com.jcraft.jsch.SftpException; import com.sun.enterprise.config.serverbeans.Node; import com.sun.enterprise.util.cluster.RemoteType; import com.sun.enterprise.util.io.FileUtils; @@ -32,6 +30,7 @@ import java.net.URI; import java.nio.file.Path; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.launcher.SSHSession; import org.glassfish.cluster.ssh.sftp.SFTPClient; @@ -51,13 +50,12 @@ public abstract class SecureAdminBootstrapHelper implements AutoCloseable { Path.of("config", "keystore.jks"), Path.of("config", "cacerts.jks") }; - private static final String[] SECURE_ADMIN_FILE_DIRS_TO_CREATE = new String[] {"config"}; + private static final Path[] SECURE_ADMIN_FILE_DIRS_TO_CREATE = new Path[] {Path.of("config")}; /** * Creates a new helper for delivering files needed for secure admin to the remote instance. - * @param sshL * - * @param adminHost host or ip address of host which hosts DAS. + * @param sshL * @param dasInstanceDir directory of the local instance - source for the required files * @param remoteNodeDir directory of the remote node on the remote system * @param instance name of the instance on the remote node to bootstrap @@ -111,7 +109,7 @@ public static SecureAdminBootstrapHelper getLocalHelper(final File existingInsta /** * Cleans up any allocated resources. */ - protected abstract void mkdirs(String dirURI) throws IOException; + protected abstract void mkdirs(Path dir) throws IOException; @Override public void close() { @@ -164,7 +162,7 @@ public void bootstrapInstance() throws BootstrapException { } private void mkdirs() throws IOException { - for (String dirPath : SECURE_ADMIN_FILE_DIRS_TO_CREATE) { + for (Path dirPath : SECURE_ADMIN_FILE_DIRS_TO_CREATE) { mkdirs(dirPath); } } @@ -234,42 +232,33 @@ private SSHHelper( launcher = sshLauncher; try { session = launcher.openSession(); - } catch (JSchException e) { - throw new BootstrapException(launcher, e); + } catch (SSHException e) { + throw new BootstrapException(e); } try { ftpClient = session.createSFTPClient(); - } catch (JSchException e) { + } catch (SSHException e) { if (session != null) { session.close(); } - throw new BootstrapException(launcher, e); + throw new BootstrapException(e); } } @Override - protected void mkdirs(String dir) throws IOException { - Path remoteDir = remoteInstanceDir.resolve(Path.of(dir)); + protected void mkdirs(Path dir) throws IOException { + Path remoteDir = remoteInstanceDir.resolve(dir); LOG.log(Level.DEBUG, "Trying to create directories for remote path {0}", remoteDir); - int instanceDirPermissions; - try { - SftpATTRS attrs = ftpClient.lstat(remoteNodeDir); - if (attrs == null) { - throw new IOException("Remote path " + remoteNodeDir + " does not exist."); - } - instanceDirPermissions = attrs.getPermissions(); - } catch (SftpException ex) { - throw new IOException(remoteNodeDir.toString(), ex); + SftpATTRS attrs = ftpClient.lstat(remoteNodeDir); + if (attrs == null) { + throw new IOException("Remote path " + remoteNodeDir + " does not exist."); } + int instanceDirPermissions = attrs.getPermissions(); LOG.log(Level.DEBUG, "Creating remote bootstrap directory " + remoteDir + " with permissions " + Integer.toOctalString(instanceDirPermissions)); - try { - ftpClient.mkdirs(remoteDir); - if (launcher.getCapabilities().isChmodSupported()) { - ftpClient.chmod(remoteDir, instanceDirPermissions); - } - } catch (SftpException ex) { - throw new IOException(remoteDir.toString(), ex); + ftpClient.mkdirs(remoteDir); + if (launcher.getCapabilities().isChmodSupported()) { + ftpClient.chmod(remoteDir, instanceDirPermissions); } } @@ -285,11 +274,7 @@ public void close() { @Override void writeToFile(final Path remotePath, final File localFile) throws IOException { - try { - ftpClient.put(localFile, remotePath); - } catch (SftpException ex) { - throw new IOException(ex); - } + ftpClient.put(localFile, remotePath); } @Override @@ -298,21 +283,17 @@ protected void backdateInstanceDomainXML() throws BootstrapException { try { setLastModified(remoteDomainXML, 0); } catch (IOException ex) { - throw new BootstrapException(launcher, ex); + throw new BootstrapException(ex); } LOG.log(Level.DEBUG, "Backdated the instance's copy of domain.xml"); } + /** + * Times over ssh are expressed as seconds since 01 Jan 1970. + */ @Override void setLastModified(final Path path, final long when) throws IOException { - /* - * Times over ssh are expressed as seconds since 01 Jan 1970. - */ - try { - ftpClient.setTimeModified(path, when); - } catch (SftpException e) { - throw new IOException(e); - } + ftpClient.setTimeModified(path, when); } } @@ -329,8 +310,8 @@ private LocalHelper(final File existingInstanceDir, final File newInstanceDir) { } @Override - protected void mkdirs(String dir) { - final File newDir = new File(newInstanceDirURI.resolve(dir)); + protected void mkdirs(Path dir) { + final File newDir = Path.of(newInstanceDirURI).resolve(dir).toFile(); if (!newDir.exists() && !newDir.mkdirs()) { throw new RuntimeException(Strings.get("secure.admin.boot.errCreDir", newDir.getAbsolutePath())); } @@ -339,15 +320,15 @@ protected void mkdirs(String dir) { @Override public void copyBootstrapFiles() throws IOException { for (Path relativePathToFile : SECURE_ADMIN_FILE_REL_URIS_TO_COPY) { - final File origin = new File(existingInstanceDirURI.resolve(relativePathToFile.toString())); - final File dest = new File(newInstanceDirURI.resolve(relativePathToFile.toString())); + final File origin = Path.of(existingInstanceDirURI).resolve(relativePathToFile).toFile(); + final File dest = Path.of(newInstanceDirURI).resolve(relativePathToFile).toFile(); FileUtils.copy(origin, dest); } } @Override protected void backdateInstanceDomainXML() throws BootstrapException { - final File newDomainXMLFile = new File(newInstanceDirURI.resolve(DOMAIN_XML_PATH.toString())); + final File newDomainXMLFile = Path.of(newInstanceDirURI).resolve(DOMAIN_XML_PATH).toFile(); if (!newDomainXMLFile.setLastModified(0)) { throw new RuntimeException(Strings.get("secure.admin.boot.errSetLastMod", newDomainXMLFile.getAbsolutePath())); } @@ -357,10 +338,6 @@ protected void backdateInstanceDomainXML() throws BootstrapException { public static class BootstrapException extends Exception { private static final long serialVersionUID = -5488899043810477670L; - public BootstrapException(final SSHLauncher launcher, final Exception ex) { - super(ex.getMessage() + "; SSH settings: " + launcher, ex); - } - public BootstrapException(final String message, final Exception ex) { super(message + "; Cause: " + ex.getMessage(), ex); } diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SetupSshCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SetupSshCommand.java index 2e0e4c55ca6..3e7e21ec349 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SetupSshCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/SetupSshCommand.java @@ -148,7 +148,7 @@ public final void execute(AdminCommandContext context) { try { sshL.setupKey(node, sshpublickeyfile, generatekey, realPass); } catch (IOException ce) { - logger.log(Level.INFO, "SSH key setup failed: " + ce); + logger.log(Level.INFO, "SSH key setup failed.", ce); report.setMessage(Strings.get("setup.ssh.failed", ce.getMessage())); report.setActionExitCode(ActionReport.ExitCode.FAILURE); return; 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 783401692b9..55729759608 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 @@ -16,8 +16,6 @@ */ package com.sun.enterprise.v3.admin.cluster; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.SftpException; import com.sun.enterprise.admin.remote.RemoteRestAdminCommand; import com.sun.enterprise.admin.remote.ServerRemoteRestAdminCommand; import com.sun.enterprise.admin.util.RemoteInstanceCommandHelper; @@ -51,6 +49,7 @@ import org.glassfish.api.admin.RestParam; import org.glassfish.api.admin.RuntimeType; import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.launcher.SSHSession; import org.glassfish.cluster.ssh.sftp.SFTPClient; @@ -121,8 +120,7 @@ public void execute(AdminCommandContext context) { errorMessage = callInstance(); } } else { - errorMessage = Strings.get("stop.instance.notDas", - env.getRuntimeType().toString()); + errorMessage = Strings.get("stop.instance.notDas", env.getRuntimeType().toString()); } if(errorMessage == null && !kill) { @@ -174,15 +172,13 @@ public void execute(AdminCommandContext context) { Supplier check = () -> { try { return ftpClient.exists(pidFilePath); - } catch (SftpException e) { + } catch (SSHException e) { return false; } }; errorMessage = pollForRealDeath(check); } - } catch (JSchException ex) { - //could not get to other host - } catch (SftpException ex) { + } catch (SSHException ex) { //could not get to other host } } diff --git a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/UpdateNodeCommand.java b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/UpdateNodeCommand.java index 67a3b516cc4..1fab305f3ee 100644 --- a/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/UpdateNodeCommand.java +++ b/nucleus/cluster/admin/src/main/java/com/sun/enterprise/v3/admin/cluster/UpdateNodeCommand.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025 Contributors to the Eclipse Foundation * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -29,6 +30,7 @@ import java.beans.PropertyVetoException; import java.io.File; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; @@ -99,20 +101,20 @@ public class UpdateNodeCommand implements AdminCommand { @Param(name="sshnodehost", optional=true) String sshnodehost; - @Param(name="sshkeyfile", optional=true) + @Param(name = "sshkeyfile", optional = true) String sshkeyfile; - @Param(name = "sshpassword", optional = true, password=true) - String sshpassword; + @Param(name = "sshpassword", optional = true, password = true) + String sshpassword; - @Param(name = "sshkeypassphrase", optional = true, password=true) - String sshkeypassphrase; + @Param(name = "sshkeypassphrase", optional = true, password = true) + String sshkeypassphrase; @Param(name = "windowsdomain", optional = true) - String windowsdomain; + String windowsdomain; - @Param(name = "type", optional=true) - String type; + @Param(name = "type", optional = true) + String type; @Override public void execute(AdminCommandContext context) { @@ -134,15 +136,12 @@ public void execute(AdminCommandContext context) { TokenResolver resolver = null; // Create a resolver that can replace system properties in strings - Map systemPropsMap = - new HashMap((Map)(System.getProperties())); + Map systemPropsMap = new HashMap((Map) (System.getProperties())); resolver = new TokenResolver(systemPropsMap); - String resolvedInstallDir = resolver.resolve(installdir); - File actualInstallDir = new File( resolvedInstallDir+"/" + NodeUtils.LANDMARK_FILE); - - - if (!actualInstallDir.exists()){ - report.setMessage(Strings.get("invalid.installdir",installdir)); + Path resolvedInstallDir = new File(resolver.resolve(installdir)).toPath(); + Path actualInstallDir = resolvedInstallDir.resolve(NodeUtils.LANDMARK_FILE); + if (!actualInstallDir.toFile().exists()) { + report.setMessage(Strings.get("invalid.installdir", installdir)); report.setActionExitCode(ActionReport.ExitCode.FAILURE); return; } @@ -195,43 +194,56 @@ public Object run(ConfigBeanProxy param) throws PropertyVetoException, Transacti Nodes nodes = ((Domain)param).getNodes(); Node node = nodes.getNode(nodeName); Node writeableNode = t.enroll(node); - if (windowsdomain != null) + if (windowsdomain != null) { writeableNode.setWindowsDomain(windowsdomain); - if (nodedir != null) + } + if (nodedir != null) { writeableNode.setNodeDir(nodedir); - if (nodehost != null) + } + if (nodehost != null) { writeableNode.setNodeHost(nodehost); - if (installdir != null) + } + if (installdir != null) { writeableNode.setInstallDir(installdir); - if (type != null) + } + if (type != null) { writeableNode.setType(type); + } if (sshport != null || sshnodehost != null ||sshuser != null || sshkeyfile != null){ SshConnector sshC = writeableNode.getSshConnector(); if (sshC == null) { sshC =writeableNode.createChild(SshConnector.class); - }else + } else { sshC = t.enroll(sshC); + } - if (sshport != null) + if (sshport != null) { sshC.setSshPort(sshport); - if(sshnodehost != null) + } + if(sshnodehost != null) { sshC.setSshHost(sshnodehost); + } if (sshuser != null || sshkeyfile != null || sshpassword != null || sshkeypassphrase != null ) { SshAuth sshA = sshC.getSshAuth(); if (sshA == null) { sshA = sshC.createChild(SshAuth.class); - } else + } else { sshA = t.enroll(sshA); + } - if (sshuser != null) + if (sshuser != null) { sshA.setUserName(sshuser); - if (sshkeyfile != null) + } + if (sshkeyfile != null) { sshA.setKeyfile(sshkeyfile); - if(sshpassword != null) + } + if(sshpassword != null) { sshA.setPassword(sshpassword); - if(sshkeypassphrase != null) + } + if(sshkeypassphrase != null) { sshA.setKeyPassphrase(sshkeypassphrase); + } sshC.setSshAuth(sshA); } writeableNode.setSshConnector(sshC); diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/CreateLocalInstanceFilesystemCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/CreateLocalInstanceFilesystemCommand.java index 008f4396c23..a5916af4dc6 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/CreateLocalInstanceFilesystemCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/CreateLocalInstanceFilesystemCommand.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -13,7 +14,6 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 */ - package com.sun.enterprise.admin.cli.cluster; import com.sun.enterprise.util.net.NetUtils; @@ -70,10 +70,11 @@ public class CreateLocalInstanceFilesystemCommand extends LocalInstanceCommand { protected void validate() throws CommandException { - if(ok(instanceName0)) + if (ok(instanceName0)) { instanceName = instanceName0; - else + } else { throw new CommandException(Strings.get("Instance.badInstanceName")); + } isCreateInstanceFilesystem = true; @@ -108,8 +109,6 @@ protected void validate() } - /** - */ @Override protected int executeCommand() throws CommandException { @@ -188,17 +187,15 @@ private void checkDASCoordinates() throws CommandException { InetAddress.getByName(DASHost); } catch (UnknownHostException e) { String thisHost = NetUtils.getHostName(); - String msg = Strings.get("Instance.DasHostUnknown", - DASHost, thisHost); + String msg = Strings.get("Instance.DasHostUnknown", DASHost, thisHost); throw new CommandException(msg, e); } // See if DAS is reachable - if (! NetUtils.isRunning(DASHost, DASPort)) { + if (!NetUtils.isRunning(DASHost, DASPort)) { // DAS provided host and port String thisHost = NetUtils.getHostName(); - String msg = Strings.get("Instance.DasHostUnreachable", - DASHost, Integer.toString(DASPort), thisHost); + String msg = Strings.get("Instance.DasHostUnreachable", DASHost, Integer.toString(DASPort), thisHost); throw new CommandException(msg); } } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeBaseCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeBaseCommand.java index 9150e483198..14be18425b5 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeBaseCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeBaseCommand.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2025 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -34,7 +35,6 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; -import java.util.logging.Level; import org.glassfish.api.Param; import org.glassfish.api.admin.CommandException; @@ -43,6 +43,8 @@ import org.glassfish.internal.api.Globals; import org.jvnet.hk2.annotations.Service; +import static java.util.logging.Level.FINER; + /** * @author Rajiv Mordani * @author Byron Nevins @@ -83,24 +85,21 @@ protected void validate() throws CommandException { @Override protected int executeCommand() throws CommandException { File zipFile = null; - try { - ArrayList binDirFiles = new ArrayList(); + ArrayList binDirFiles = new ArrayList<>(); precopy(); zipFile = createZipFileIfNeeded(binDirFiles); copyToHosts(zipFile, binDirFiles); - } - catch (CommandException e) { + } catch (CommandException e) { throw e; - } - catch (Exception e) { + } catch (Exception e) { throw new CommandException(e); - } - finally { + } finally { if (!save && delete) { if (zipFile != null) { - if (!zipFile.delete()) + if (!zipFile.delete()) { zipFile.deleteOnExit(); + } } } } @@ -128,31 +127,28 @@ private File createZipFileIfNeeded(ArrayList binDirFiles) throws IOExcep File zipFileLocation = null; File glassFishZipFile = null; - if (archive != null) { + if (archive == null) { + zipFileLocation = new File("."); + if (!zipFileLocation.canWrite()) { + zipFileLocation = new File(System.getProperty("java.io.tmpdir")); + } + glassFishZipFile = File.createTempFile("glassfish", ".zip", zipFileLocation); + String filePath = glassFishZipFile.getCanonicalPath(); + filePath = filePath.replaceAll("\\\\", "/"); + archiveName = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.length()); + } else { archive = archive.replace('\\', '/'); archiveName = archive.substring(archive.lastIndexOf("/") + 1, archive.length()); zipFileLocation = new File(archive.substring(0, archive.lastIndexOf("/"))); glassFishZipFile = new File(archive); if (glassFishZipFile.exists() && !create) { - if (logger.isLoggable(Level.FINER)) - logger.finer("Found " + archive); + logger.log(FINER, "Found {0}", archive); delete = false; return glassFishZipFile; - } - else if (!zipFileLocation.canWrite()) { + } else if (!zipFileLocation.canWrite()) { throw new IOException("Cannot write to " + archive); } } - else { - zipFileLocation = new File("."); - if (!zipFileLocation.canWrite()) { - zipFileLocation = new File(System.getProperty("java.io.tmpdir")); - } - glassFishZipFile = File.createTempFile("glassfish", ".zip", zipFileLocation); - String filePath = glassFishZipFile.getCanonicalPath(); - filePath = filePath.replaceAll("\\\\", "/"); - archiveName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length()); - } FileListerRelative lister = new FileListerRelative(installRoot); lister.keepEmptyDirectories(); @@ -161,31 +157,25 @@ else if (!zipFileLocation.canWrite()) { List resultFiles1 = Arrays.asList(files); ArrayList resultFiles = new ArrayList(resultFiles1); - if (logger.isLoggable(Level.FINER)) - logger.finer("Number of files to be zipped = " + - resultFiles.size()); + logger.finer(() -> "Number of files to be zipped = " + resultFiles.size()); Iterator iter = resultFiles.iterator(); while (iter.hasNext()) { String fileName = iter.next(); - String fPath = fileName.substring(fileName.lastIndexOf("/") + 1); + String fPath = fileName.substring(fileName.lastIndexOf('/') + 1); if (fPath.equals(glassFishZipFile.getName())) { - if (logger.isLoggable(Level.FINER)) - logger.finer("Removing file = " + fileName); + logger.log(FINER, "Removing file = {0}", fileName); iter.remove(); continue; } if (fileName.contains("domains") || fileName.contains("nodes")) { iter.remove(); - } - else if (isFileWithinBinDirectory(fileName)) { + } else if (isFileWithinBinDirectory(fileName)) { binDirFiles.add(fileName); } } - if (logger.isLoggable(Level.FINER)) - logger.finer("Final number of files to be zipped = " + - resultFiles.size()); + logger.finer(() -> "Final number of files to be zipped = " + resultFiles.size()); String[] filesToZip = new String[resultFiles.size()]; filesToZip = resultFiles.toArray(filesToZip); @@ -218,8 +208,9 @@ public static String toString(InputStream ins) throws IOException { char[] buffer = new char[4096]; int n; - while ((n = reader.read(buffer)) >= 0) + while ((n = reader.read(buffer)) >= 0) { sw.write(buffer, 0, n); + } return sw.toString(); } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeSshCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeSshCommand.java index fc1cfd5bd09..2a71341e725 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeSshCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/InstallNodeSshCommand.java @@ -18,7 +18,6 @@ package com.sun.enterprise.admin.cli.cluster; import com.jcraft.jsch.ChannelSftp.LsEntry; -import com.jcraft.jsch.JSchException; import com.jcraft.jsch.SftpException; import com.sun.enterprise.util.SystemPropertyConstants; @@ -31,6 +30,7 @@ import org.glassfish.api.Param; import org.glassfish.api.admin.CommandException; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.launcher.SSHSession; import org.glassfish.cluster.ssh.sftp.SFTPClient; @@ -103,8 +103,6 @@ void copyToHosts(File zipFile, ArrayList binDirFiles) throws CommandExce copyToHostsInternal(zipFile, binDirFiles); } catch (CommandException ex) { throw ex; - } catch (JSchException ex) { - throw new CommandException(ex); } catch (IOException e) { // Note: CommandException is not printed to logs. logger.log(SEVERE, @@ -116,7 +114,7 @@ void copyToHosts(File zipFile, ArrayList binDirFiles) throws CommandExce private void copyToHostsInternal(File zipFile, ArrayList binDirFiles) - throws JSchException, IOException, CommandException { + throws IOException, CommandException { boolean prompt = promptPass; for (String host : hosts) { @@ -143,45 +141,27 @@ private void copyToHostsInternal(File zipFile, ArrayList binDirFiles) Path sshInstallDir = Path.of(getInstallDir()); try (SSHSession session = sshLauncher.openSession(); SFTPClient sftpClient = session.createSFTPClient()) { - try { - sftpClient.rmDir(sshInstallDir, true); - } catch (SftpException e) { - throw new IOException("Failed to remove content of " + sshInstallDir + ". Cause: " + e.getMessage(), - e); - } - - try { - if (!sftpClient.exists(sshInstallDir)) { - sftpClient.mkdirs(sshInstallDir); - if (sshLauncher.getCapabilities().isChmodSupported()) { - sftpClient.chmod(sshInstallDir, 0755); - } + sftpClient.rmDir(sshInstallDir, true); + if (!sftpClient.exists(sshInstallDir)) { + sftpClient.mkdirs(sshInstallDir); + if (sshLauncher.getCapabilities().isChmodSupported()) { + sftpClient.chmod(sshInstallDir, 0755); } - } catch (SftpException ioe) { - throw new IOException(Strings.get("mkdir.failed", sshInstallDir, host), ioe); } final Path remoteZipFile = sshInstallDir.resolve(zipFile.getName()); - try { - logger.info(() -> "Copying " + zipFile + " (" + zipFile.length() + " bytes)" + " to " + host + ":" - + sshInstallDir); - sftpClient.put(zipFile, remoteZipFile); - logger.finer(() -> "Copied " + zipFile + " to " + host + ":" + remoteZipFile); - } catch (SftpException ex) { - throw new IOException(Strings.get("cannot.copy.zip.file", zipFile, host), ex); - } + logger.info(() -> "Copying " + zipFile + " (" + zipFile.length() + " bytes)" + " to " + host + ":" + + sshInstallDir); + sftpClient.put(zipFile, remoteZipFile); + logger.finer(() -> "Copied " + zipFile + " to " + host + ":" + remoteZipFile); logger.info(() -> "Unpacking " + remoteZipFile + " on " + host + " to " + sshInstallDir); session.unzip(remoteZipFile, sshInstallDir); logger.finer(() -> "Unpacked " + getArchiveName() + " into " + host + ":" + sshInstallDir); - try { - logger.info(() -> "Removing " + host + ":" + remoteZipFile); - sftpClient.rm(remoteZipFile); - logger.finer(() -> "Removed " + host + ":" + remoteZipFile); - } catch (SftpException e) { - throw new IOException("Failed to remove file " + remoteZipFile + " from host " + host, e); - } + logger.info(() -> "Removing " + host + ":" + remoteZipFile); + sftpClient.rm(remoteZipFile); + logger.finer(() -> "Removed " + host + ":" + remoteZipFile); // zip doesn't retain file permissions, hence executables need // to be fixed with proper permissions @@ -198,8 +178,9 @@ private void copyToHostsInternal(File zipFile, ArrayList binDirFiles) } logger.finer( () -> "Fixed file permissions of all bin files under " + host + ":" + sshInstallDir); - } catch (SftpException ioe) { - throw new IOException(Strings.get("fix.permissions.failed", host, sshInstallDir), ioe); + } catch (SSHException e) { + throw new IOException("Could not set permissions on commands in bin directories under " + + sshInstallDir + " directory on host " + host + ". Cause: " + e, e); } } } @@ -213,7 +194,7 @@ private void copyToHostsInternal(File zipFile, ArrayList binDirFiles) * @param sftpClient ftp client handle * @throws SftpException */ - private void searchAndFixBinDirectoryFiles(Path installDir, SFTPClient sftpClient) throws SftpException { + private void searchAndFixBinDirectoryFiles(Path installDir, SFTPClient sftpClient) throws SSHException { for (LsEntry directoryEntry : sftpClient.lsDetails(installDir, e -> true)) { if (directoryEntry.getAttrs().isDir()) { Path subDir = installDir.resolve(directoryEntry.getFilename()); @@ -233,7 +214,7 @@ private void searchAndFixBinDirectoryFiles(Path installDir, SFTPClient sftpClien * @param sftpClient ftp client handle * @throws SftpException */ - private void fixFilePermissions(Path binDir, SFTPClient sftpClient) throws SftpException { + private void fixFilePermissions(Path binDir, SFTPClient sftpClient) throws SSHException { for (String directoryEntry : sftpClient.ls(binDir, entry -> !entry.getAttrs().isDir())) { sftpClient.chmod(binDir.resolve(directoryEntry), 0755); } @@ -268,14 +249,8 @@ final void precopy() throws CommandException { if (sftpClient.exists(sshInstallDir)) { checkIfAlreadyInstalled(session, host, sshInstallDir); } - } catch (SftpException ex) { - throw new CommandException(ex); } catch (IOException ex) { throw new CommandException(ex); - } catch (JSchException ex) { - throw new CommandException(ex); - } catch (InterruptedException ex) { - throw new CommandException(ex); } } } @@ -284,24 +259,17 @@ final void precopy() throws CommandException { /** * Determines if GlassFish is installed on remote host at specified location. * Uses SSH launcher to execute 'asadmin version' + * * @param host remote host - * @throws JSchException - * @throws CommandException - * @throws IOException - * @throws InterruptedException */ private void checkIfAlreadyInstalled(SSHSession session, String host, Path sshInstallDir) - throws JSchException, CommandException, IOException, InterruptedException { + throws CommandException, SSHException { //check if an installation already exists on remote host - try { - String asadmin = Constants.v4 ? "/lib/nadmin' version --local --terse" : "/bin/asadmin' version --local --terse"; - String cmd = "'" + sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + asadmin; - int status = session.exec(cmd); - if (status == 0) { - throw new CommandException(Strings.get("install.dir.exists", sshInstallDir)); - } - } catch (IOException ex) { - throw new IOException(Strings.get("glassfish.install.check.failed", host), ex); + String asadmin = Constants.v4 ? "/lib/nadmin' version --local --terse" : "/bin/asadmin' version --local --terse"; + String cmd = "'" + sshInstallDir + "/" + SystemPropertyConstants.getComponentName() + asadmin; + int status = session.exec(cmd); + if (status == 0) { + throw new CommandException(Strings.get("install.dir.exists", sshInstallDir)); } } } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java index 4926baddbd3..a42c679ad19 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalInstanceCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2024, 2025 Contributors to the Eclipse Foundation. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -131,10 +131,11 @@ protected boolean setServerDirs() { protected void initInstance() throws CommandException { /* node dir - parent directory of all node(s) */ String nodeDirRootPath = null; - if (ok(nodeDir)) + if (ok(nodeDir)) { nodeDirRootPath = nodeDir; - else // node dir = /nodes + } else { nodeDirRootPath = getNodeDirRootDefault(); + } nodeDirRoot = new File(nodeDirRootPath); mkdirs(nodeDirRoot); @@ -351,8 +352,9 @@ final protected void whackFilesystem() throws CommandException { if (files == null || files.length <= 0) { // empty dir - if (files != null) + if (files != null) { FileUtils.whack(whackee); + } throw new CommandException(Strings.get("DeleteInstance.noWhack", whackee)); @@ -368,22 +370,21 @@ final protected void whackFilesystem() throws CommandException { } FileUtils.renameFile(whackee, tmpwhackee); FileUtils.whack(tmpwhackee); - } - catch (IOException ioe) { - throw new CommandException(Strings.get("DeleteInstance.badWhackWithException", - whackee, ioe, StringUtils.getStackTrace(ioe))); + } catch (IOException ioe) { + throw new CommandException( + Strings.get("DeleteInstance.badWhackWithException", whackee, ioe, StringUtils.getStackTrace(ioe))); } if (whackee.isDirectory()) { StringBuilder sb = new StringBuilder(); sb.append("whackee=").append(whackee.toString()); sb.append(", files in parent:"); files = parent.listFiles(); - for (File f : files) + for (File f : files) { sb.append(f.toString()).append(", "); + } File f1 = new File(whackee.toString()); sb.append(", new wackee.exists=").append(f1.exists()); - throw new CommandException(Strings.get("DeleteInstance.badWhack", - whackee) + ", " + sb.toString()); + throw new CommandException(Strings.get("DeleteInstance.badWhack", whackee) + ", " + sb); } // now see if the parent dir is empty. If so wipe it out. @@ -406,13 +407,15 @@ final protected void whackFilesystem() throws CommandException { } private boolean noInstancesRemain(File[] files) { - if (files == null || files.length <= 0) + if (files == null || files.length <= 0) { return true; + } if (files.length == 1 && files[0].isDirectory() - && files[0].getName().equals("agent")) + && files[0].getName().equals("agent")) { return true; + } return false; } @@ -428,12 +431,14 @@ protected String getInstallRootPath() throws CommandException { String installRootPath = getSystemProperty( SystemPropertyConstants.INSTALL_ROOT_PROPERTY); - if (!StringUtils.ok(installRootPath)) + if (!StringUtils.ok(installRootPath)) { installRootPath = System.getProperty( SystemPropertyConstants.INSTALL_ROOT_PROPERTY); + } - if (!StringUtils.ok(installRootPath)) + if (!StringUtils.ok(installRootPath)) { throw new CommandException("noInstallDirPath"); + } return installRootPath; } @@ -451,9 +456,10 @@ protected String getProductRootPath() throws CommandException { String productRootPath = getSystemProperty( SystemPropertyConstants.PRODUCT_ROOT_PROPERTY); - if (!StringUtils.ok(productRootPath)) + if (!StringUtils.ok(productRootPath)) { productRootPath = System.getProperty( SystemPropertyConstants.PRODUCT_ROOT_PROPERTY); + } if (!StringUtils.ok(productRootPath)) { // Product install root is parent of glassfish install root @@ -504,8 +510,9 @@ else if ((cons = System.console()) != null) { while (line != null && line.length() > 0) { try { port = Integer.parseInt(line); - if (port > 0 && port <= 65535) + if (port > 0 && port <= 65535) { break; + } } catch (NumberFormatException nfex) { } @@ -567,8 +574,9 @@ public boolean accept(File f) { } // the usual case -- one node dir child - if (files != null && files.length == 1) + if (files != null && files.length == 1) { return files[0]; + } /* * If there is no existing node dir child -- create one! @@ -623,8 +631,9 @@ public boolean accept(File f) { } for (File f : files) { - if (!f.getName().equals("agent")) + if (!f.getName().equals("agent")) { return f; + } } throw new CommandException( Strings.get("Instance.noInstanceDirs", parent)); @@ -643,8 +652,9 @@ private String getNodeDirRootDefault() throws CommandException { String nodeDirDefault = getSystemProperty( SystemPropertyConstants.AGENT_ROOT_PROPERTY); - if (StringUtils.ok(nodeDirDefault)) + if (StringUtils.ok(nodeDirDefault)) { return nodeDirDefault; + } String installRootPath = getInstallRootPath(); return installRootPath + "/" + "nodes"; @@ -653,12 +663,14 @@ private String getNodeDirRootDefault() throws CommandException { @Override protected File getMasterPasswordFile() { - if (nodeDirChild == null) + if (nodeDirChild == null) { return null; + } File mp = new File(new File(nodeDirChild,"agent"), "master-password"); - if (!mp.canRead()) + if (!mp.canRead()) { return null; + } return mp; } diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalStrings.properties b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalStrings.properties index bbce819afa3..d10ff74c5e7 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalStrings.properties +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/LocalStrings.properties @@ -150,12 +150,6 @@ DomainMasterPasswordPrompt=Password is aliased. To obtain the real password, ent GetPasswordFailure=Failed to get the password from {0}''s keystore. PasswordAuthFailure=Failed to authenticate using the aliased password stored in {0}''s keystore. -#installNode -mkdir.failed=Could not create the directory {0} on host {1} -cannot.copy.zip.file=Could not copy zip file {0} to host {1} -fix.permissions.failed=Could not set permissions on commands in bin directory on host {0} for glassfish installation {1} -glassfish.install.check.failed=Problem encountered while checking if installation already exists on remote host. - StopInstance.nopidprev=Can not find the process ID of the server. It is supposed to be here: {0}. Unable to kill the process. StopInstance.pidprevreaderror=Error trying to read the Process ID from {0}: {1} CreateLocalInstance.errSetLastMod=Attempt to set lastModified date for {0} failed; no further information is available diff --git a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/UninstallNodeSshCommand.java b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/UninstallNodeSshCommand.java index 0d12cca1e4c..25d06dead7d 100644 --- a/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/UninstallNodeSshCommand.java +++ b/nucleus/cluster/cli/src/main/java/com/sun/enterprise/admin/cli/cluster/UninstallNodeSshCommand.java @@ -101,7 +101,7 @@ void deleteFromHosts() throws CommandException { try (SSHSession session = sshLauncher.openSession(); SFTPClient sftpClient = session.createSFTPClient()) { if (!sftpClient.exists(installDir)) { - throw new IOException(getInstallDir() + " Directory does not exist"); + throw new IOException("Directory does not exist: " + getInstallDir()); } sftpClient.rmDir(installDir, false); } diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/connect/NodeRunnerSsh.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/connect/NodeRunnerSsh.java index d8c4e277a73..834d6422671 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/connect/NodeRunnerSsh.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/connect/NodeRunnerSsh.java @@ -17,18 +17,17 @@ package org.glassfish.cluster.ssh.connect; -import com.jcraft.jsch.JSchException; import com.sun.enterprise.config.serverbeans.Node; import com.sun.enterprise.util.StringUtils; import com.sun.enterprise.util.SystemPropertyConstants; -import java.io.IOException; import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.ArrayList; import java.util.List; import org.glassfish.api.admin.SSHCommandExecutionException; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.launcher.SSHSession; import org.glassfish.common.util.admin.AsadminInput; @@ -89,15 +88,9 @@ public int runAdminCommandOnRemoteNode(Node node, StringBuilder output, } output.append(commandOutput); return commandStatus; - } catch (JSchException | IOException ex) { - String m1 = " Command execution failed. " + ex.getMessage(); - String m2 = ""; - Throwable e2 = ex.getCause(); - if (e2 != null) { - m2 = e2.getMessage(); - } - LOG.log(Level.ERROR, "Command execution failed for " + lastCommandRun); - SSHCommandExecutionException cee = new SSHCommandExecutionException(StringUtils.cat(":", m1, m2)); + } catch (SSHException e) { + LOG.log(Level.ERROR, "Command execution failed for " + lastCommandRun, e); + SSHCommandExecutionException cee = new SSHCommandExecutionException(e.getMessage(), e); cee.setSSHSettings(sshL.toString()); cee.setCommandRun(lastCommandRun); throw cee; diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/RemoteSystemCapabilities.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/RemoteSystemCapabilities.java index 35845ad440a..687243e9cd2 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/RemoteSystemCapabilities.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/RemoteSystemCapabilities.java @@ -17,6 +17,7 @@ package org.glassfish.cluster.ssh.launcher; import java.lang.Runtime.Version; +import java.nio.charset.Charset; /** * Detected capabilities of the remote operating system. @@ -26,16 +27,19 @@ public class RemoteSystemCapabilities { private final String javaHome; private final Version javaVersion; private final OperatingSystem operatingSystem; + private final Charset charset; /** * @param javaHome - it is a string, because we want to use it as it is reported from the operating system. * @param javaVersion * @param operatingSystem + * @param charset */ - RemoteSystemCapabilities(String javaHome, Version javaVersion, OperatingSystem operatingSystem) { + RemoteSystemCapabilities(String javaHome, Version javaVersion, OperatingSystem operatingSystem, Charset charset) { this.javaHome = javaHome; this.javaVersion = javaVersion; this.operatingSystem = operatingSystem; + this.charset = charset; } @@ -64,10 +68,18 @@ public OperatingSystem getOperatingSystem() { } + /** + * @return detected charset used by the remote system. + */ + public Charset getCharset() { + return charset; + } + + @Override public String toString() { - return getClass().getSimpleName() + "[os=" + operatingSystem + ", javaHome=" + javaHome + return getClass().getSimpleName() + "[os=" + operatingSystem + ", charset=" + charset + ", javaHome=" + javaHome + ", javaVersion=" + javaVersion + "]"; } } diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHException.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHException.java index 42fccf10fc4..85e7f0c7a7f 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHException.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHException.java @@ -25,10 +25,18 @@ public class SSHException extends IOException { private static final long serialVersionUID = 1L; public SSHException(String message, Exception cause) { - super(message, cause); + super(message + ' ' + toCauseMessage(cause), cause); } public SSHException(String message) { super(message); } + + + private static String toCauseMessage(Exception e) { + if (e instanceof SSHException) { + return e.getMessage(); + } + return e.toString(); + } } diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHLauncher.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHLauncher.java index 5e515fc2ab9..56125ee6275 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHLauncher.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHLauncher.java @@ -20,7 +20,6 @@ import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; -import com.jcraft.jsch.SftpException; import com.sun.enterprise.config.serverbeans.Node; import com.sun.enterprise.config.serverbeans.SshAuth; import com.sun.enterprise.config.serverbeans.SshConnector; @@ -34,6 +33,8 @@ import java.io.IOException; import java.lang.Runtime.Version; import java.lang.System.Logger; +import java.nio.charset.Charset; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -49,6 +50,8 @@ import static java.lang.System.Logger.Level.ERROR; import static java.lang.System.Logger.Level.INFO; import static java.lang.System.Logger.Level.WARNING; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.glassfish.cluster.ssh.launcher.OperatingSystem.GENERIC; /** * @author Rajiv Mordani, Krishna Deepak @@ -112,7 +115,8 @@ public SSHLauncher(Node node) { this.keyPassPhrase = keyPassPhraseParameter == null || keyPassPhraseParameter.isEmpty() ? null : expandPasswordAlias(keyPassPhraseParameter); - this.capabilities = analyzeRemote(); + this.capabilities = analyzeRemote(this.host, this.port, this.userName, this.password, this.keyFile, + this.keyPassPhrase); LOG.log(DEBUG, "SSH client configuration: {0}", this); } @@ -138,7 +142,8 @@ public SSHLauncher(String userName, String host, int port, String password, File this.keyPassPhrase = keyPassPhrase == null || keyPassPhrase.isEmpty() ? null : expandPasswordAlias(keyPassPhrase); - this.capabilities = analyzeRemote(); + this.capabilities = analyzeRemote(this.host, this.port, this.userName, this.password, this.keyFile, + this.keyPassPhrase); LOG.log(DEBUG, "SSH client configuration: {0}", this); } @@ -171,12 +176,28 @@ public RemoteSystemCapabilities getCapabilities() { * Open the {@link SSHSession}. * * @return open {@link SSHSession} - * @throws JSchException + * @throws SSHException */ - public SSHSession openSession() throws JSchException { - JSch jsch = new JSch(); + public SSHSession openSession() throws SSHException { + return openSession(getCapabilities(), host, port, userName, password, keyFile, keyPassPhrase); + } + - // Client Auth + /** + * Open the {@link SSHSession}. + * + * @return open {@link SSHSession} + * @throws SSHException + */ + private static SSHSession openSession( + RemoteSystemCapabilities capabilities, + String host, + int port, + String userName, + String password, + File keyFile, + String keyPassPhrase) throws SSHException { + JSch jsch = new JSch(); String message = ""; boolean triedAuthentication = false; // Private key file is provided - Public Key Authentication @@ -185,7 +206,7 @@ public SSHSession openSession() throws JSchException { if (keyFile.exists()) { triedAuthentication = true; LOG.log(DEBUG, () -> "Adding identity for private key at " + keyFile); - jsch.addIdentity(keyFile.getAbsolutePath(), keyPassPhrase); + addIdentity(jsch, keyFile, keyPassPhrase); } else { message = "Specified key file does not exist \n"; } @@ -200,30 +221,32 @@ public SSHSession openSession() throws JSchException { File key = home.resolve(Path.of(SSH_DIR_NAME, keyName)).toFile(); if (key.exists()) { triedAuthentication = true; - jsch.addIdentity(key.getAbsolutePath(), keyPassPhrase); + addIdentity(jsch, key, keyPassPhrase); } } } - final Session session = jsch.getSession(userName, host, port); + final Session session = openSession(jsch, host, port, userName); try { // TODO: Insecure, maybe we could create an input field and allow user to check the host key? session.setConfig("StrictHostKeyChecking", "accept-new"); session.setUserInfo(new GlassFishSshUserInfo()); - // Password Auth if (password != null && !password.isEmpty()) { LOG.log(DEBUG, () -> "Authenticating with password " + getPrintablePassword(password)); triedAuthentication = true; session.setPassword(password); } if (!triedAuthentication) { - throw new JSchException("Could not authenticate. " + message); + throw new SSHException("Could not authenticate: " + message + '.'); } session.connect(); - return new SSHSession(session, getCapabilities()); - } catch (Exception e) { + return new SSHSession(session, capabilities); + } catch (SSHException e) { session.disconnect(); throw e; + } catch (JSchException e) { + session.disconnect(); + throw new SSHException("Could not authenticate: " + message + '.', e); } } @@ -231,9 +254,9 @@ public SSHSession openSession() throws JSchException { /** * Open and close the session. * - * @throws JSchException + * @throws SSHException */ - public void pingConnection() throws JSchException { + public void pingConnection() throws SSHException { LOG.log(DEBUG, () -> "Trying to establish connection to host: " + this.host); try (SSHSession session = openSession()) { LOG.log(INFO, () -> "Establishing SSH connection to host " + this.host + " succeeded!"); @@ -253,10 +276,6 @@ public void pingConnection() throws JSchException { public boolean exists(Path path) throws SSHException { try (SSHSession session = openSession(); SFTPClient sftpClient = session.createSFTPClient()) { return sftpClient.exists(path); - } catch (JSchException | SftpException e) { - String msg = "Failed to check if the file exists: " + path + " on host " + host; - LOG.log(WARNING, msg, e); - throw new SSHException(msg, e); } } @@ -266,37 +285,48 @@ public boolean exists(Path path) throws SSHException { * with Linux or Windows based operating systems. * * @return {@link RemoteSystemCapabilities} + * @throws SSHException */ - private RemoteSystemCapabilities analyzeRemote() { - try (SSHSession session = openSession(); SFTPClient sftpClient = session.createSFTPClient()) { - Map env = session.detectShellEnv(); - LOG.log(DEBUG, "Environment of the operating system obtained for the SSH client: {0}", env); - - StringBuilder outputBuilder = new StringBuilder(); - // java must be available in the environment. - // If you use docker java images, check UsePam=yes and /etc/environment - // By default images configure ENV properties just for the container app, not for ssh clients. - final int code = session.exec(Arrays.asList("java", "-XshowSettings:properties", "-version"), null, - outputBuilder); - if (code != 0) { - throw new IllegalStateException( - "Could not execute the java command on the host " + host + ". Output: " + outputBuilder); + private static RemoteSystemCapabilities analyzeRemote(String host, int port, String userName, String password, + File keyFile, String keyPassPhrase) { + final String[] sysPropOutputLines; + final RemoteSystemCapabilities capabilities = new RemoteSystemCapabilities(null, null, GENERIC, UTF_8); + try (SSHSession session = openSession(capabilities, host, port, userName, password, keyFile, keyPassPhrase)) { + if (LOG.isLoggable(DEBUG)) { + Map env = session.detectShellEnv(); + LOG.log(DEBUG, "Environment of the operating system obtained for the SSH client: {0}", env); } - - String[] output = outputBuilder.toString().split("\\R"); - String javaHome = getValue("java.home", output); - Version javaVersion = getProperty("java.version", output, Version::parse); - OperatingSystem os = getProperty("os.name", output, OperatingSystem::parse); - return new RemoteSystemCapabilities(javaHome, javaVersion, os); - } catch (JSchException | SSHException e) { - String msg = "Failed to analyze the remote system."; + sysPropOutputLines = loadRemoteJavaSystemProperties(session); + } catch (SSHException e) { + String msg = "Failed to analyze the remote system. Some commands probably are not supported."; LOG.log(WARNING, msg, e); - throw new IllegalStateException(msg, e); + return new RemoteSystemCapabilities(null, null, GENERIC, UTF_8); + } + + String javaHome = getValue("java.home", sysPropOutputLines); + Version javaVersion = getProperty("java.version", sysPropOutputLines, Version::parse); + OperatingSystem os = getProperty("os.name", sysPropOutputLines, OperatingSystem::parse); + Charset charset = getProperty("file.encoding", sysPropOutputLines, Charset::forName); + return new RemoteSystemCapabilities(javaHome, javaVersion, os, charset); + } + + + private static String[] loadRemoteJavaSystemProperties(SSHSession session) throws SSHException { + StringBuilder outputBuilder = new StringBuilder(); + // java must be available in the environment. + // If you use docker java images, check UsePam=yes and /etc/environment + // By default images configure ENV properties just for the container app, not for ssh clients. + final int code = session.exec(Arrays.asList("java", "-XshowSettings:properties", "-version"), null, + outputBuilder); + if (code != 0) { + throw new SSHException("Java command on the remote host failed. Output: " + outputBuilder + '.'); } + + return outputBuilder.toString().split("\\R"); } - private boolean isPasswordAlias(String alias) { + private static boolean isPasswordAlias(String alias) { // Check if the passed string is specified using the alias syntax String aliasName = RelativePathResolver.getAlias(alias); return aliasName != null; @@ -307,7 +337,7 @@ private boolean isPasswordAlias(String alias) { * @param p password string * @return printable version of password */ - private String getPrintablePassword(String p) { + private static String getPrintablePassword(String p) { // We only display the password if it is an alias, else // we display "". String printable = "null"; @@ -336,11 +366,8 @@ private String getPrintablePassword(String p) { * @param generateKey - flag to indicate if key needs to be generated or not * @param passwd - ssh user password * @throws IOException - * @throws InterruptedException */ - public void setupKey(String node, String pubKeyFile, boolean generateKey, String passwd) - throws IOException, InterruptedException { - + public void setupKey(String node, String pubKeyFile, boolean generateKey, String passwd) throws IOException { File key = keyFile; LOG.log(DEBUG, () -> "Key = " + keyFile); if (key.exists()) { @@ -349,7 +376,7 @@ public void setupKey(String node, String pubKeyFile, boolean generateKey, String } } else { if (generateKey) { - if(!generateKeyPair()) { + if (!generateKeyPair()) { throw new IOException("SSH key pair generation failed. Please generate key manually."); } } else { @@ -362,9 +389,6 @@ public void setupKey(String node, String pubKeyFile, boolean generateKey, String throw new IOException("SSH password is required for distributing the public key. You can specify the SSH password in a password file and pass it through --passwordfile option."); } try (SSHSession session = openSession(passwd)) { - if (!session.isOpen()) { - throw new IOException("SSH password authentication failed for user " + userName + " on host " + node); - } try (SFTPClient sftp = session.createSFTPClient()) { if (key.exists()) { @@ -383,31 +407,22 @@ public void setupKey(String node, String pubKeyFile, boolean generateKey, String final Path remoteSshDir; try { remoteSshDir = sftp.getHome().resolve(SSH_DIR_NAME); - } catch (SftpException e) { - throw new IOException("Could not resolve home directory of the remote user: " + e.getMessage(), - e); + } catch (InvalidPathException e) { + throw new SSHException("Could not resolve ssh home directory of the remote user.", e); } - try { - if (!sftp.exists(remoteSshDir)) { - LOG.log(DEBUG, () -> SSH_DIR_NAME + " does not exist"); - sftp.mkdirs(remoteSshDir); - if (getCapabilities().isChmodSupported()) { - sftp.chmod(remoteSshDir, 0700); - } + if (!sftp.exists(remoteSshDir)) { + LOG.log(DEBUG, () -> SSH_DIR_NAME + " does not exist"); + sftp.mkdirs(remoteSshDir); + if (getCapabilities().isChmodSupported()) { + sftp.chmod(remoteSshDir, 0700); } - } catch (SftpException e) { - throw new IOException("Error while creating .ssh directory on remote host: " + e.getMessage(), e); } // copy over the public key to remote host final Path remoteKeyTmp = remoteSshDir.resolve("key.tmp"); - try { - sftp.put(pubKey, remoteKeyTmp); - if (getCapabilities().isChmodSupported()) { - sftp.chmod(remoteKeyTmp, 0600); - } - } catch (SftpException ex) { - throw new IOException("Unable to copy the public key", ex); + sftp.put(pubKey, remoteKeyTmp); + if (getCapabilities().isChmodSupported()) { + sftp.chmod(remoteKeyTmp, 0600); } // append the public key file contents to authorized_keys file on remote host @@ -422,25 +437,19 @@ public void setupKey(String node, String pubKeyFile, boolean generateKey, String try { sftp.rm(remoteKeyTmp); LOG.log(DEBUG, "Removed the temporary key file on remote host"); - } catch (SftpException e) { - LOG.log(WARNING, "WARNING: Failed to remove the public key file key.tmp on remote host " + host); + } catch (SSHException e) { + LOG.log(WARNING, "Failed to remove the public key file key.tmp on remote host " + host); } if (capabilities.isChmodSupported()) { LOG.log(INFO, "Fixing file permissions for home(755), .ssh(700) and authorized_keys file(600)"); - try { - sftp.cd(sftp.getHome()); - sftp.chmod(remoteSshDir.getParent(), 0755); - sftp.chmod(remoteSshDir, 0700); - sftp.chmod(authKeyFile, 0600); - } catch (SftpException ex) { - throw new IOException("Unable to fix file permissions", ex); - } + sftp.cd(sftp.getHome()); + sftp.chmod(remoteSshDir.getParent(), 0755); + sftp.chmod(remoteSshDir, 0700); + sftp.chmod(authKeyFile, 0600); } } } - } catch (JSchException ex) { - throw new IOException(ex); } } @@ -455,7 +464,7 @@ public boolean checkConnection() { try { jsch.addIdentity(keyFile.getAbsolutePath(), keyPassPhrase); sess = jsch.getSession(userName, host, port); - sess.setConfig("StrictHostKeyChecking", "no"); + sess.setConfig("StrictHostKeyChecking", "accept-new"); sess.connect(); if (sess.isConnected()) { LOG.log(INFO, () -> "Successfully connected to " + userName + "@" + host + " using keyfile " + keyFile); @@ -487,7 +496,7 @@ public boolean checkPasswordAuth() { Session sess = null; try { sess = jsch.getSession(userName, host, port); - sess.setConfig("StrictHostKeyChecking", "no"); + sess.setConfig("StrictHostKeyChecking", "accept-new"); sess.setPassword(password); sess.connect(); if (sess.isConnected()) { @@ -646,13 +655,35 @@ private boolean setupSSHDir() throws IOException { } - private SSHSession openSession(String passwordParam) throws JSchException { + private static void addIdentity(JSch jsch, File identityFile, String keyPassPhrase) throws SSHException { + try { + jsch.addIdentity(identityFile.getAbsolutePath(), keyPassPhrase); + } catch (JSchException e) { + throw new SSHException("Invalid key passphrase for key: " + identityFile.getAbsolutePath() + ".", e); + } + } + + + private SSHSession openSession(String passwordParam) throws SSHException { JSch jsch = new JSch(); - Session session = jsch.getSession(userName, host, port); - session.setConfig("StrictHostKeyChecking", "no"); - session.setPassword(passwordParam); - session.connect(); - return new SSHSession(session); + Session session = openSession(jsch, host, port, userName); + try { + session.setConfig("StrictHostKeyChecking", "accept-new"); + session.setPassword(passwordParam); + session.connect(); + return new SSHSession(session); + } catch (JSchException e) { + throw new SSHException("Failed to connect.", e); + } + } + + + private static Session openSession(JSch jsch, String host, int port, String userName) throws SSHException { + try { + return jsch.getSession(userName, host, port); + } catch (JSchException e) { + throw new SSHException("Could not authenticate user " + userName + " to " + host + ':' + port + '.', e); + } } diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHSession.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHSession.java index c3d8e04a6a1..e4986ebe778 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHSession.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/launcher/SSHSession.java @@ -16,6 +16,7 @@ package org.glassfish.cluster.ssh.launcher; +import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelShell; @@ -29,6 +30,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.System.Logger; +import java.nio.charset.Charset; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -53,13 +55,14 @@ public class SSHSession implements AutoCloseable { /** * This constructor uses GENERIC operating system. Suitable just for operations where - * you don't care about commands available on the operating system. + * you don't care about commands available on the operating system and you are happy + * with the default UTF-8 charset in outputs (might be corrupted).. * * @param session */ SSHSession(Session session) { this.session = session; - this.capabilities = new RemoteSystemCapabilities(null, null, OperatingSystem.GENERIC); + this.capabilities = new RemoteSystemCapabilities(null, null, OperatingSystem.GENERIC, UTF_8); } @@ -91,52 +94,11 @@ public boolean isOpen() { * @throws SSHException */ public Map detectShellEnv() throws SSHException { - ChannelShell shell; - try { - shell = (ChannelShell) session.openChannel("shell"); - } catch (JSchException e) { - throw new SSHException("Could not open the shell session.", e); - } - final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8192); - try { - // Command is executable both in Linux and Windows os - shell.setInputStream(listInputStream(List.of("env || set"))); - shell.setPty(false); - InputStream in = shell.getInputStream(); - PumpThread t1 = new PumpThread(in, outputStream); - t1.start(); - shell.connect(); - t1.join(); - // Don't check the exit code, returns -1 on windows. - String output = outputStream.toString(UTF_8); - LOG.log(DEBUG, () -> "Environment options - command output: \n" + output); - return parseProperties(output); - } catch (Exception e) { - throw new SSHException( - "Could not detect shell environment options. Output: " + outputStream.toString(UTF_8), e); - } finally { - shell.disconnect(); - } - } - - - /** - * Detects default system properties of the remote java command. - * - * @return map of system properties - * @throws SSHException - */ - public Map detectJavaSystemProperties() throws SSHException { - ChannelShell shell; - try { - shell = (ChannelShell) session.openChannel("shell"); - } catch (JSchException e) { - throw new SSHException("Could not open the shell session.", e); - } final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8192); + final ChannelShell shell = openChannel(session, "shell"); try { // Command is executable both in Linux and Windows os - shell.setInputStream(listInputStream(List.of("env || set"))); + shell.setInputStream(listInputStream(List.of("env || set"), UTF_8)); shell.setPty(false); InputStream in = shell.getInputStream(); PumpThread t1 = new PumpThread(in, outputStream); @@ -144,12 +106,14 @@ public Map detectJavaSystemProperties() throws SSHException { shell.connect(); t1.join(); // Don't check the exit code, returns -1 on windows. + // Expect UTF-8 for now. It will be probably different on Windows, + // but we will parse it from the output. String output = outputStream.toString(UTF_8); LOG.log(DEBUG, () -> "Environment options - command output: \n" + output); return parseProperties(output); } catch (Exception e) { - throw new SSHException( - "Could not detect shell environment options. Output: " + outputStream.toString(UTF_8), e); + throw new SSHException("Could not detect shell environment options. Output: " + + outputStream.toString(UTF_8), e); } finally { shell.disconnect(); } @@ -176,15 +140,11 @@ public void unzip(Path remoteZipFile, Path remoteDir) throws SSHException { } final StringBuilder output = new StringBuilder(); - try { - int status = exec(unzipCommand, null, output); - if (status != 0) { - throw new SSHException("Failed unpacking glassfish zip file. Output: " + output + "."); - } - LOG.log(DEBUG, () -> "Unpacked " + remoteZipFile + " to directory " + remoteDir); - } catch (JSchException e) { - throw new SSHException("Failed unpacking glassfish zip file. Output: " + output + ".", e); + final int status = exec(unzipCommand, null, output); + if (status != 0) { + throw new SSHException("Failed unpacking glassfish zip file. Output: " + output + "."); } + LOG.log(DEBUG, () -> "Unpacked " + remoteZipFile + " to directory " + remoteDir); } @@ -198,11 +158,9 @@ public void unzip(Path remoteZipFile, Path remoteDir) throws SSHException { * @param output - empty collector of the output. Can be null. * @return exit code * @throws SSHException - * @throws JSchException */ - public int exec(List command, List stdinLines, StringBuilder output) - throws SSHException, JSchException { - return exec(commandListToQuotedString(command), listInputStream(stdinLines), output); + public int exec(List command, List stdinLines, StringBuilder output) throws SSHException { + return exec(commandListToQuotedString(command), listInputStream(stdinLines, capabilities.getCharset()), output); } @@ -216,7 +174,7 @@ public int exec(List command, List stdinLines, StringBuilder out * @return exit code * @throws SSHException */ - public int exec(List command, List stdinLines) throws JSchException, SSHException { + public int exec(List command, List stdinLines) throws SSHException { return exec(commandListToQuotedString(command), stdinLines); } @@ -231,8 +189,8 @@ public int exec(List command, List stdinLines) throws JSchExcept * @return exit code * @throws SSHException */ - public int exec(String command, List stdinLines) throws JSchException, SSHException { - return exec(command, listInputStream(stdinLines)); + public int exec(String command, List stdinLines) throws SSHException { + return exec(command, listInputStream(stdinLines, capabilities.getCharset())); } @@ -244,8 +202,7 @@ public int exec(String command, List stdinLines) throws JSchException, S * @return exit code * @throws SSHException */ - public int exec(final String command) - throws JSchException, SSHException { + public int exec(final String command) throws SSHException { return exec(command, (InputStream) null); } @@ -260,7 +217,7 @@ public int exec(final String command) * @return exit code * @throws SSHException */ - public int exec(final String command, final InputStream stdin) throws JSchException, SSHException { + public int exec(final String command, final InputStream stdin) throws SSHException { return exec(command, stdin, null); } @@ -272,14 +229,31 @@ public int exec(final String command, final InputStream stdin) throws JSchExcept * * @param command - command to execute. If it has arguments, better use {@link #exec(List, List, StringBuilder)}. * @param stdin - stream used to fake standard input in STDIN stream. Can be null. + * @param output + * @return exit code + * @throws SSHException + */ + public int exec(final String command, final InputStream stdin, final StringBuilder output) throws SSHException { + return exec(command, stdin, output, capabilities.getCharset()); + } + + + /** + * SFTP exec command. + * Executes a command on the remote system via ssh, optionally sending + * lines of data to the remote process's System.in. + * + * @param command - command to execute. If it has arguments, better use {@link #exec(List, List, StringBuilder)}. + * @param stdin - stream used to fake standard input in STDIN stream. Can be null. + * @param output * @return exit code * @throws SSHException */ - public int exec(final String command, final InputStream stdin, final StringBuilder output) - throws JSchException, SSHException { + int exec(final String command, final InputStream stdin, final StringBuilder output, final Charset charset) + throws SSHException { LOG.log(INFO, () -> "Executing command " + command + " on host: " + session.getHost()); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8192); - final ChannelExec execChannel = (ChannelExec) session.openChannel("exec"); + final ChannelExec execChannel = openChannel(session, "exec"); try { execChannel.setInputStream(stdin); execChannel.setCommand(command); @@ -293,7 +267,7 @@ public int exec(final String command, final InputStream stdin, final StringBuild t1.join(); t2.join(); if (output != null || LOG.isLoggable(DEBUG)) { - String commandOutput = outputStream.toString(UTF_8); + String commandOutput = outputStream.toString(charset); LOG.log(DEBUG, () -> "Command output: \n" + commandOutput); if (output != null) { output.append(commandOutput); @@ -304,7 +278,7 @@ public int exec(final String command, final InputStream stdin, final StringBuild } return -1; } catch (Exception e) { - throw new SSHException("Command " + command + " failed. Output: " + outputStream.toString(UTF_8), e); + throw new SSHException("Command " + command + " failed. Output: " + outputStream.toString(charset), e); } finally { execChannel.disconnect(); } @@ -313,10 +287,10 @@ public int exec(final String command, final InputStream stdin, final StringBuild /** * @return new {@link SFTPClient} - * @throws JSchException + * @throws SSHException if the connection failed, ie because the server does not support SFTP. */ - public SFTPClient createSFTPClient() throws JSchException { - return new SFTPClient((ChannelSftp) session.openChannel("sftp")); + public SFTPClient createSFTPClient() throws SSHException { + return new SFTPClient((ChannelSftp) openChannel(session, "sftp")); } @@ -360,14 +334,14 @@ private static String commandListToQuotedString(List command) { } - private static InputStream listInputStream(final List stdinLines) { + private static InputStream listInputStream(final List stdinLines, Charset charset) { if (stdinLines == null) { return null; } try { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); for (String line : stdinLines) { - baos.write(line.getBytes(UTF_8)); + baos.write(line.getBytes(charset)); baos.write('\n'); } return new ByteArrayInputStream(baos.toByteArray()); @@ -377,6 +351,16 @@ private static InputStream listInputStream(final List stdinLines) { } + @SuppressWarnings("unchecked") + private static T openChannel(Session session, String type) throws SSHException { + try { + return (T) session.openChannel(type); + } catch (JSchException e) { + throw new SSHException("Could not open the session of type=" + type, e); + } + } + + private static Map parseProperties(String output) { String[] lines = output.split("\\R"); Map properties = new TreeMap<>(); diff --git a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/sftp/SFTPClient.java b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/sftp/SFTPClient.java index 80d92cfc392..ab856da4138 100644 --- a/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/sftp/SFTPClient.java +++ b/nucleus/cluster/ssh/src/main/java/org/glassfish/cluster/ssh/sftp/SFTPClient.java @@ -34,6 +34,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHSession; import static java.lang.System.Logger.Level.TRACE; @@ -53,9 +54,13 @@ public class SFTPClient implements AutoCloseable { private final ChannelSftp sftpChannel; - public SFTPClient(ChannelSftp channel) throws JSchException { + public SFTPClient(ChannelSftp channel) throws SSHException { this.sftpChannel = channel; - this.sftpChannel.connect(); + try { + this.sftpChannel.connect(); + } catch (JSchException e) { + throw new SSHException("Failed to connect to the SFTP server. Is it correctly configured on the server?", e); + } } /** @@ -74,15 +79,23 @@ public ChannelSftp getSftpChannel() { } - public Path getHome() throws SftpException { - return Path.of(sftpChannel.getHome()); + /** + * @return Configured SSH server home directory. Usually user's home directory. + * @throws SSHException + */ + public Path getHome() throws SSHException { + try { + return Path.of(sftpChannel.getHome()); + } catch (SftpException e) { + throw new SSHException("Could not resolve SFTP Home path.", e); + } } /** * Makes sure that the directory exists, by creating it if necessary. */ - public void mkdirs(Path path) throws SftpException { + public void mkdirs(Path path) throws SSHException { if (existsDirectory(path)) { return; } @@ -92,17 +105,21 @@ public void mkdirs(Path path) throws SftpException { if (existsDirectory(current)) { continue; } - sftpChannel.mkdir(current.toString()); + try { + sftpChannel.mkdir(current.toString()); + } catch (SftpException e) { + throw new SSHException("Failed to create the directory " + path + '.', e); + } } } - public boolean existsDirectory(Path path) throws SftpException { + public boolean existsDirectory(Path path) throws SSHException { SftpATTRS attrs = stat(path); return attrs != null && attrs.isDir(); } - public boolean isEmptyDirectory(Path path) throws SftpException { + public boolean isEmptyDirectory(Path path) throws SSHException { SftpATTRS attrs = stat(path); return attrs != null && attrs.isDir() && ls(path, e -> true).isEmpty(); } @@ -114,14 +131,14 @@ public boolean isEmptyDirectory(Path path) throws SftpException { * @param path * @param onlyContent * @param exclude - * @throws SftpException + * @throws SSHException */ - public void rmDir(Path path, boolean onlyContent, Path... exclude) throws SftpException { + public void rmDir(Path path, boolean onlyContent, Path... exclude) throws SSHException { if (!exists(path)) { return; } // We use recursion while the channel is stateful - sftpChannel.cd(path.getParent().toString()); + cd(path.getParent()); List content = lsDetails(path, p -> true); for (LsEntry entry : content) { final String filename = entry.getFilename(); @@ -134,13 +151,12 @@ public void rmDir(Path path, boolean onlyContent, Path... exclude) throws SftpEx rmDir(entryPath, false, getSubFilter(filename, exclude)); } else { LOG.log(TRACE, "Deleting file {0}", entryPath); - sftpChannel.rm(entryPath.toString()); + rm(entryPath); } } if (!onlyContent) { - sftpChannel.cd(path.getParent().toString()); LOG.log(TRACE, "Deleting directory {0}", path); - sftpChannel.rmdir(path.toString()); + rm(path.getParent()); } } @@ -163,27 +179,36 @@ private static Path[] getSubFilter(String firstName, Path... exclusions) { } - public void put(File localFile, Path remoteFile) throws SftpException { - sftpChannel.cd(remoteFile.getParent().toString()); - sftpChannel.put(localFile.getAbsolutePath(), remoteFile.toString()); + public void put(File localFile, Path remoteFile) throws SSHException { + try { + sftpChannel.cd(remoteFile.getParent().toString()); + sftpChannel.put(localFile.getAbsolutePath(), remoteFile.toString()); + } catch (SftpException e) { + throw new SSHException( + "Failed to upload the local file " + localFile + " to remote file " + remoteFile + '.', e); + } } /** * Deletes the specified remote file. * * @param path - * @throws SftpException + * @throws SSHException */ - public void rm(Path path) throws SftpException { - sftpChannel.cd(path.getParent().toString()); - sftpChannel.rm(path.toString()); + public void rm(Path path) throws SSHException { + try { + sftpChannel.cd(path.getParent().toString()); + sftpChannel.rm(path.toString()); + } catch (SftpException e) { + throw new SSHException("Failed to remove path " + path + '.', e); + } } /** * @return true if the given path exists. */ - public boolean exists(Path path) throws SftpException { + public boolean exists(Path path) throws SSHException { return stat(path) != null; } @@ -192,14 +217,14 @@ public boolean exists(Path path) throws SftpException { * Graceful stat that returns null if the path doesn't exist. * This method follows symlinks. */ - public SftpATTRS stat(Path path) throws SftpException { + public SftpATTRS stat(Path path) throws SSHException { try { return sftpChannel.stat(path.toString()); } catch (SftpException e) { if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { return null; } - throw e; + throw new SSHException("Failed to call SFTP stat for " + path + '.', e); } } @@ -207,44 +232,69 @@ public SftpATTRS stat(Path path) throws SftpException { * Graceful lstat that returns null if the path doesn't exist. * This method does not follow symlinks. */ - public SftpATTRS lstat(Path path) throws SftpException { + public SftpATTRS lstat(Path path) throws SSHException { try { return sftpChannel.lstat(path.toString()); } catch (SftpException e) { if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { return null; } - throw e; + throw new SSHException("Failed to call SFTP lstat for " + path + '.', e); } } - public void setTimeModified(Path path, long millisSinceUnixEpoch) throws SftpException { - sftpChannel.setMtime(path.toString(), (int) (millisSinceUnixEpoch / 1000)); + public void setTimeModified(Path path, long millisSinceUnixEpoch) throws SSHException { + try { + sftpChannel.setMtime(path.toString(), (int) (millisSinceUnixEpoch / 1000)); + } catch (SftpException e) { + throw new SSHException("Failed to set time modification for path " + path + '.', e); + } } - public void chmod(Path path, int permissions) throws SftpException { - sftpChannel.chmod(permissions, path.toString()); + public void chmod(Path path, int permissions) throws SSHException { + try { + sftpChannel.chmod(permissions, path.toString()); + } catch (SftpException e) { + throw new SSHException( + "Failed to call chmod for remote path " + path + " and permissions " + permissions + ".", e); + } } - public void cd(Path path) throws SftpException { - sftpChannel.cd(path.toString()); + + public void cd(Path path) throws SSHException { + try { + sftpChannel.cd(path.toString()); + } catch (SftpException e) { + throw new SSHException("Failed to change the remote directory to " + path + '.', e); + } } - public void download(Path remoteFile, Path localFile) throws IOException, SftpException { + public void download(Path remoteFile, Path localFile) throws SSHException { try (InputStream inputStream = sftpChannel.get(remoteFile.toString())) { Files.copy(inputStream, localFile); + } catch (SftpException | IOException e) { + throw new SSHException( + "Failed to download the remote file " + remoteFile + " to local file " + localFile + '.', e); } } - public List ls(Path path, Predicate filter) throws SftpException { - return sftpChannel.ls(path.toString()).stream().filter(filter.and(PREDICATE_NO_DOTS)).map(LsEntry::getFilename) - .collect(Collectors.toList()); + public List ls(Path path, Predicate filter) throws SSHException { + try { + return sftpChannel.ls(path.toString()).stream().filter(filter.and(PREDICATE_NO_DOTS)).map(LsEntry::getFilename) + .collect(Collectors.toList()); + } catch (SftpException e) { + throw new SSHException("Failed to list remote directory " + path + '.', e); + } } - public List lsDetails(Path path, Predicate filter) throws SftpException { - return sftpChannel.ls(path.toString()).stream().filter(filter.and(PREDICATE_NO_DOTS)) - .collect(Collectors.toList()); + public List lsDetails(Path path, Predicate filter) throws SSHException { + try { + return sftpChannel.ls(path.toString()).stream().filter(filter.and(PREDICATE_NO_DOTS)) + .collect(Collectors.toList()); + } catch (SftpException e) { + throw new SSHException("Failed to list remote directory " + path + '.', e); + } } } diff --git a/nucleus/common/common-util/src/main/java/com/sun/common/util/logging/LoggingConfigImpl.java b/nucleus/common/common-util/src/main/java/com/sun/common/util/logging/LoggingConfigImpl.java index e95e918aa29..c89bb782bb7 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/common/util/logging/LoggingConfigImpl.java +++ b/nucleus/common/common-util/src/main/java/com/sun/common/util/logging/LoggingConfigImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024 Contributors to the Eclipse Foundation + * Copyright (c) 2022, 2025 Contributors to the Eclipse Foundation * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -606,8 +606,7 @@ private void addDirectory(ZipOutputStream zout, File fileSource, int ignoreLengt } /** - * Return a logging file details in the logging.properties file. - * + * @return a logging file path from the logging.properties file. * @throws IOException If an I/O error occurs */ public synchronized String getLoggingFileDetails() throws IOException { @@ -631,7 +630,7 @@ public synchronized String getLoggingFileDetails() throws IOException { /** - * @return a logging file details in the logging.properties file for given target. + * @return a logging file path in the logging.properties file for given target. * @throws IOException If an I/O error occurs */ public synchronized String getLoggingFileDetails(String targetConfigName) throws IOException { diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/InstanceDirs.java b/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/InstanceDirs.java index 5dfa7aa6452..97373a306fd 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/InstanceDirs.java +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/InstanceDirs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Contributors to the Eclipse Foundation. + * Copyright (c) 2024, 2025 Contributors to the Eclipse Foundation. * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -65,6 +65,7 @@ public InstanceDirs(File instanceDir) throws IOException { /** * This constructor handles 0, 1, 2 or 3 null args. * It is smart enough to figure out many defaults. + * * @param nodeDirParentPath E.g. install-dir/nodes * @param nodeDirName E.g. install-dir/nodes/localhost * @param instanceName E.g. i1 @@ -74,67 +75,46 @@ public InstanceDirs(String nodeDirParentPath, String nodeDirName, String instanc nodeDirParentPath = getNodeDirRootDefault(); } - File nodeDirParent = new File(nodeDirParentPath); - + final File nodeDirParent = new File(nodeDirParentPath); if (!nodeDirParent.isDirectory()) { dirs = null; - throw new IOException(Strings.get("InstanceDirs.noNodeParent")); + throw new IOException(Strings.get("InstanceDirs.noNodeParent", nodeDirParent)); } - File nodeDir; - + final File nodeDir; if (StringUtils.ok(nodeDirName)) { nodeDir = new File(nodeDirParent, nodeDirName); } else { nodeDir = getTheOneAndOnlyNode(nodeDirParent); } - if (!nodeDir.isDirectory()) { dirs = null; throw new IOException(Strings.get("InstanceDirs.badNodeDir", nodeDir)); } - File instanceDir; - + final File instanceDir; if (StringUtils.ok(instanceName)) { instanceDir = new File(nodeDir, instanceName); } else { instanceDir = getTheOneAndOnlyInstance(nodeDir); } - if (!instanceDir.isDirectory()) { dirs = null; throw new IOException(Strings.get("InstanceDirs.badInstanceDir", instanceDir)); } - - // whew!!! - dirs = new ServerDirs(instanceDir); } - private File getTheOneAndOnlyNode(File parent) throws IOException { - // look for subdirs in the parent dir -- there must be one and only one - - File[] files = parent.listFiles(new FileFilter() { - - @Override - public boolean accept(File f) { - return f != null && f.isDirectory(); - } - }); - // ERROR: No node dirs + /** Look for subdirs in the parent dir -- there must be one and only one */ + private File getTheOneAndOnlyNode(File parent) throws IOException { + File[] files = parent.listFiles(f -> f != null && f.isDirectory()); if (files == null || files.length < 1) { - throw new IOException( - Strings.get("InstanceDirs.noNodes", parent)); + throw new IOException(Strings.get("InstanceDirs.noNodes", parent)); } - // ERROR: more than one node dir child if (files.length > 1) { - throw new IOException( - Strings.get("InstanceDirs.tooManyNodes", parent, files.length)); + throw new IOException(Strings.get("InstanceDirs.tooManyNodes", parent, files.length)); } - - // the usual case -- one node dir child return files[0]; } diff --git a/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/LocalStrings.properties b/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/LocalStrings.properties index 47de09275a6..e08e7dd54d2 100644 --- a/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/LocalStrings.properties +++ b/nucleus/common/common-util/src/main/java/com/sun/enterprise/util/io/LocalStrings.properties @@ -22,7 +22,7 @@ ServerDirs.invalidState=This method call is illegal because the object is in an ServerDirs.nullArg=Null arguments are not allowed in {0} InstanceDirs.noGrandParent=Server instances are required to have a grandparent \ directory for backward compatability. Here is the instance's directory: {0} -InstanceDirs.noNodeParent=No node parent directory found. +InstanceDirs.noNodeParent=No node parent directory found: {0} InstanceDirs.tooManyNodes=There is more than one directory ({1}) in the node parent directory ({0}). Cannot choose a default node. InstanceDirs.noNodes=There are no nodes in {0}. InstanceDirs.badNodeDir=The specified node directory doesn''t exist: {0} diff --git a/nucleus/common/internal-api/src/main/java/org/glassfish/internal/api/RelativePathResolver.java b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/api/RelativePathResolver.java index 5da7e56a354..19a4da8d7b4 100644 --- a/nucleus/common/internal-api/src/main/java/org/glassfish/internal/api/RelativePathResolver.java +++ b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/api/RelativePathResolver.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, 2025 Contributors to the Eclipse Foundation * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -21,13 +22,8 @@ import com.sun.enterprise.util.i18n.StringManagerBase; import java.io.File; -import java.io.IOException; import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; import java.util.logging.Level; -import java.util.logging.Logger; import org.glassfish.api.admin.PasswordAliasStore; @@ -48,8 +44,6 @@ */ public class RelativePathResolver { - private static Logger _logger = null; - private static RelativePathResolver _instance = null; private static final String ALIAS_TOKEN = "ALIAS"; @@ -99,8 +93,8 @@ public String unresolve(String path, String[] propNames) { //assumption is that the File class can convert this to an OS //dependent path separator (e.g. \\ on windows). path = path.replace(File.separatorChar, '/'); - for (int i = 0; i < propNames.length; i++) { - propVal = getPropertyValue(propNames[i], true); + for (String propName : propNames) { + propVal = getPropertyValue(propName, true); if (propVal != null) { //All paths returned will contain / as the separator. This will allow //all comparison to be done using / as the separator @@ -108,13 +102,13 @@ public String unresolve(String path, String[] propNames) { startIdx = path.indexOf(propVal); if (startIdx >= 0) { path = path.substring(0, startIdx) + - "${" + propNames[i] + "}" + + "${" + propName + "}" + path.substring(startIdx + propVal.length()); } } else { InternalLoggerInfo.getLogger().log(Level.SEVERE, InternalLoggerInfo.unknownProperty, - new Object[] {propNames[i], path}); + new Object[] {propName, path}); } } } @@ -162,8 +156,9 @@ static public String getAlias(String propName) int lastIdx = propName.length() - 1; if (lastIdx > 1) { propName = propName.substring(0,lastIdx); - if (propName!=null) - aliasName = propName.trim(); + if (propName!=null) { + aliasName = propName.trim(); + } } } return aliasName; @@ -180,8 +175,9 @@ static public String getAlias(String propName) */ protected String getPropertyValue(String propName, boolean bIncludingEnvironmentVariables) { - if(!bIncludingEnvironmentVariables) - return null; + if(!bIncludingEnvironmentVariables) { + return null; + } // Try finding the property as a system property String result = System.getProperty(propName); @@ -308,8 +304,8 @@ public static void main(String[] args) { System.out.println(args[i] + " " + result + " " + resolvePath(result)); } } else { - for (int i = 0; i < args.length; i++) { - System.out.println(args[i] + " " + resolvePath(args[i])); + for (String arg : args) { + System.out.println(arg + " " + resolvePath(arg)); } } } @@ -333,9 +329,7 @@ public static void main(String[] args) { * UnrecoverableKeyException if there is an error is opening or * processing the password store */ - public static String getRealPasswordFromAlias(final String at) throws - KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, - UnrecoverableKeyException { + public static String getRealPasswordFromAlias(final String at) throws KeyStoreException { try { if (at == null || RelativePathResolver.getAlias(at) == null) { return ( at ); diff --git a/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilter.java b/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilter.java index c8116ca2d47..86ae70e04b9 100644 --- a/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilter.java +++ b/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilter.java @@ -293,15 +293,14 @@ public String getLogFileForGivenTarget(String targetServerName) throws IOExcepti if (node.isLocal()) { // if local just returning log file to view return loggingFile; - } else { - // if remote then need to download log file on DAS and returning that log file for view - String logFileName = logFileDetailsForInstance.substring(logFileDetailsForInstance.lastIndexOf(File.separator) + 1, logFileDetailsForInstance.length()); - File instanceFile = null; - instanceFile = new LogFilterForInstance().downloadGivenInstanceLogFile(habitat, targetServer, domain, LOGGER, - targetServerName, env.getInstanceRoot().getAbsolutePath(), logFileName, logFileDetailsForInstance); - - return instanceFile.getAbsolutePath(); } + // if remote then need to download log file on DAS and returning that log file for view + String logFileName = logFileDetailsForInstance.substring(logFileDetailsForInstance.lastIndexOf(File.separator) + 1, logFileDetailsForInstance.length()); + File instanceFile = null; + instanceFile = new LogFilterForInstance().downloadGivenInstanceLogFile(habitat, targetServer, domain, + targetServerName, env.getInstanceRoot().getAbsolutePath(), logFileName, logFileDetailsForInstance); + + return instanceFile.getAbsolutePath(); } @@ -383,7 +382,7 @@ public AttributeList getLogRecordsUsingQuery( try { // this code is used when the node is not local. instanceLogFile = new LogFilterForInstance().downloadGivenInstanceLogFile(habitat, targetServer, - domain, LOGGER, instanceName, env.getInstanceRoot().getAbsolutePath(), logFileName, instanceLogFileName); + domain, instanceName, env.getInstanceRoot().getAbsolutePath(), logFileName, instanceLogFileName); } catch (Exception e) { LOGGER.log(Level.SEVERE, LogFacade.ERROR_EXECUTING_LOG_QUERY, e); return new AttributeList(); @@ -391,17 +390,15 @@ public AttributeList getLogRecordsUsingQuery( } - LogFile logFile = null; File loggingFileExists = new File(instanceLogFile.getAbsolutePath()); if (!loggingFileExists.exists()) { LOGGER.log(Level.WARNING, LogFacade.INSTANCE_LOG_FILE_NOT_FOUND, instanceLogFile.getAbsolutePath()); return new AttributeList(); } - logFile = getLogFile(instanceLogFile.getAbsolutePath()); + final LogFile logFile = getLogFile(instanceLogFile.getAbsolutePath()); boolean forwd = (forward == null) ? true : forward.booleanValue(); boolean nxt = (next == null) ? true : next.booleanValue(); - long reqCount = (requestedCount == null) ? - logFile.getIndexSize() : requestedCount.intValue(); + long reqCount = (requestedCount == null) ? logFile.getIndexSize() : requestedCount.intValue(); long startingRecord; if (fromRecord == -1) { // In this case next/previous (before/after) don't mean much since diff --git a/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilterForInstance.java b/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilterForInstance.java index 1d240af5a4c..95f91b87657 100644 --- a/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilterForInstance.java +++ b/nucleus/core/logging/src/main/java/com/sun/enterprise/server/logging/logviewer/backend/LogFilterForInstance.java @@ -18,9 +18,7 @@ package com.sun.enterprise.server.logging.logviewer.backend; import com.jcraft.jsch.ChannelSftp.LsEntry; -import com.jcraft.jsch.JSchException; import com.jcraft.jsch.SftpATTRS; -import com.jcraft.jsch.SftpException; import com.sun.enterprise.config.serverbeans.Domain; import com.sun.enterprise.config.serverbeans.Node; import com.sun.enterprise.config.serverbeans.Nodes; @@ -33,6 +31,7 @@ import java.util.List; import java.util.logging.Logger; +import org.glassfish.cluster.ssh.launcher.SSHException; import org.glassfish.cluster.ssh.launcher.SSHLauncher; import org.glassfish.cluster.ssh.launcher.SSHSession; import org.glassfish.cluster.ssh.sftp.SFTPClient; @@ -45,7 +44,7 @@ */ public class LogFilterForInstance { - public File downloadGivenInstanceLogFile(ServiceLocator habitat, Server targetServer, Domain domain, Logger logger, + public File downloadGivenInstanceLogFile(ServiceLocator habitat, Server targetServer, Domain domain, String instanceName, String domainRoot, String logFileName, String instanceLogFileName) throws IOException { // method is used from logviewer back end code logfilter. @@ -107,22 +106,21 @@ public File downloadGivenInstanceLogFile(ServiceLocator habitat, Server targetSe sftpClient.download(loggingFile, instanceLogFile.toPath()); } return instanceLogFile; - } catch (JSchException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); - } catch (SftpException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); + } catch (SSHException ex) { + throw new SSHException( + "Unable to download log file of instance " + instanceName + " from SSH Node " + node.getName() + '.', + ex); } } + /** + * Download log files of all instances of the node. + */ public void downloadAllInstanceLogFiles(ServiceLocator habitat, Server targetServer, Domain domain, Logger logger, String instanceName, Path tempDirectoryOnServer, String instanceLogFileDirectory) throws IOException { - // method is used from collect-log-files command - // for Instance it's going through this loop. This will use ssh utility to get file from instance machine(remote machine) and - // store in tempDirectoryOnServer which is used to create zip file. - // Right now user needs to go through this URL to setup and configure ssh http://wikis.sun.com/display/GlassFish/3.1SSHSetup String sNode = targetServer.getNodeRef(); Nodes nodes = domain.getNodes(); Node node = nodes.getNode(sNode); @@ -159,10 +157,9 @@ public void downloadAllInstanceLogFiles(ServiceLocator habitat, Server targetSer sftpClient.download(sourceDir.resolve(fileName), tempDirectoryOnServer.resolve(fileName)); } } - } catch (JSchException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); - } catch (SftpException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); + } catch (Exception e) { + throw new SSHException("Unable to download log file of instance " + instanceName + " from SSH Node " + + node.getName() + '.', e); } } } @@ -237,10 +234,9 @@ public List getInstanceLogFileNames(ServiceLocator habitat, Server targe List instanceLogFileNames = sftpClient.ls(loggingDir, this::isAcceptable); instanceLogFileNamesAsString.addAll(instanceLogFileNames); } - } catch (JSchException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); - } catch (SftpException ex) { - throw new IOException("Unable to download instance log file from SSH Node", ex); + } catch (SSHException e) { + throw new SSHException("Unable to download log file of instance " + instanceName + " from SSH Node " + + node.getName() + '.', e); } } return instanceLogFileNamesAsString;