diff --git a/nucleus/admin/config-api/src/main/java/com/sun/enterprise/config/serverbeans/Node.java b/nucleus/admin/config-api/src/main/java/com/sun/enterprise/config/serverbeans/Node.java index c995282184b..87d9a829c26 100644 --- a/nucleus/admin/config-api/src/main/java/com/sun/enterprise/config/serverbeans/Node.java +++ b/nucleus/admin/config-api/src/main/java/com/sun/enterprise/config/serverbeans/Node.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] Payara Foundation and/or affiiates +// Portions Copyright [2018-2021] Payara Foundation and/or affiiates package com.sun.enterprise.config.serverbeans; @@ -333,7 +333,9 @@ public static boolean isLocal(Node node) { return false; } // Although the Docker container may be local to this machine, it's not truly "local" - if (node.getType().equals("DOCKER")) { + // TEMP is a docker container as well. + if (node.getType().equals("DOCKER") + || node.getType().equals("TEMP")) { return false; } return NetUtils.isThisHostLocal(nodeHost); 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 a280c84a036..fcab8b32773 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 @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. * - * Portions Copyright [2017-2018] Payara Foundation and/or affiliates + * Portions Copyright [2017-2021] Payara Foundation and/or affiliates */ package com.sun.enterprise.server.logging.logviewer.backend; @@ -53,11 +53,17 @@ import com.trilead.ssh2.SFTPv3DirectoryEntry; import com.trilead.ssh2.SFTPv3FileAttributes; +import fish.payara.enterprise.server.logging.TrivialTarInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; @@ -178,14 +184,60 @@ public File downloadGivenInstanceLogFile(ServiceLocator habitat, Server targetSe wrf.copyTo(instanceLogFile); } catch (WindowsException ex) { - throw new IOException("Unable to download instance log file from DCOM Instance Node"); + throw new IOException("Unable to download instance log file from DCOM Instance Node", ex); } + } else if (node.getType().equals("DOCKER") || node.getType().equals("TEMP")) { + String dockerContainerId = targetServer.getDockerContainerId(); + String nodeHost = node.getNodeHost(); + int nodeDockerPort = Integer.valueOf(node.getDockerPort()); + try { + if (dockerContainerId == null && node.getType().equals("TEMP")) { + // FIXME: it would be easies, if the TEMP server had docker container id set! + // temporary docker node, we need to access the original node, cut the added generated name + String originalInstanceName = instanceName.substring(0, instanceName.lastIndexOf('-')); + Server originalInstance = domain.getServerNamed(originalInstanceName); + dockerContainerId = originalInstance.getDockerContainerId(); + String originalNodeName = originalInstance.getNodeRef(); + Node originalNode = nodes.getNode(originalNodeName); + nodeHost = originalNode.getNodeHost(); + nodeDockerPort = Integer.valueOf(originalNode.getDockerPort()); + logFileName = "server.log"; + } + File logFileDirectoryOnServer = makingDirectory(domainRoot + File.separator + "logs" + + File.separator + instanceName); + + String loggingDir = getLoggingDirectoryForNode(instanceLogFileName, node, sNode, instanceName); + + if (logFileName == null || logFileName.equals("")) { + logFileName = "server.log"; + } + //"/opt/payara/appserver/glassfish/nodes/Hilarious-Angelfish/docker-instance-LovelyChar/logs/server.log" + String remotePath = loggingDir + "/" + logFileName; + + String prefix = "http" + (Boolean.valueOf(node.getUseTls()) ? "s" : ""); + + // store the log file to the given path + URL logUrl = new URL(prefix, nodeHost, nodeDockerPort, "/containers/" + + dockerContainerId + + "/archive?path=" + + remotePath); + BufferedInputStream downloadFile = new BufferedInputStream(logUrl.openStream()); +// ArchiveInputStream tarStream = new ArchiveStreamFactory().createArchiveInputStream(downloadFile); + TrivialTarInputStream tarStream = new TrivialTarInputStream(downloadFile); + Path instanceLogPath = Paths.get(logFileDirectoryOnServer.getAbsolutePath(), logFileName); + //Path instanceLogPathTar = Paths.get(logFileDirectoryOnServer.getAbsolutePath() + ".tar", logFileName); + Files.copy(tarStream, instanceLogPath, StandardCopyOption.REPLACE_EXISTING); +// Files.copy(downloadFile, instanceLogPath, StandardCopyOption.REPLACE_EXISTING); + instanceLogFile = instanceLogPath.toFile(); + } catch (IOException ex) { +// } catch (IOException | ArchiveException ex) { + throw new IOException("Unable to download file from docker node at " + nodeHost + ":" + nodeDockerPort + ", instance " + instanceName + ", container " + dockerContainerId, ex); + } } return instanceLogFile; - } public void downloadAllInstanceLogFiles(ServiceLocator habitat, Server targetServer, Domain domain, Logger logger, @@ -402,7 +454,7 @@ private File makingDirectory(String path) { } } - created = targetDir.mkdir(); + created = targetDir.mkdirs(); if (!created) { return null; } else { diff --git a/nucleus/core/logging/src/main/java/fish/payara/enterprise/server/logging/TrivialTarInputStream.java b/nucleus/core/logging/src/main/java/fish/payara/enterprise/server/logging/TrivialTarInputStream.java new file mode 100644 index 00000000000..f289f23ac4f --- /dev/null +++ b/nucleus/core/logging/src/main/java/fish/payara/enterprise/server/logging/TrivialTarInputStream.java @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2021] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package fish.payara.enterprise.server.logging; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Trivial implementation for TAR file downloaded from Docker, expecting regular file, ignoring filename. + * + * @author Petr Aubrecht + */ +public class TrivialTarInputStream extends InputStream { + + private final InputStream sourceStream; + private byte[] header = null; + private long size; + private long readSoFar = 0; + + public TrivialTarInputStream(InputStream sourceStream) { + this.sourceStream = sourceStream; + } + + @Override + public int read() throws IOException { + if (header == null) { + header = new byte[512]; + sourceStream.read(header); + byte fileLinkType = header[156]; + if (fileLinkType != 0 && fileLinkType != 48 /*'0'*/) { + throw new IOException("Tar file is not a normal file, type is " + fileLinkType); + } + String sizeStr = new String(header, 124, 11, "ASCII"); + size = Integer.valueOf(sizeStr, 8); + } + if (readSoFar >= size) { + // we are at the end of file + return -1; + } + readSoFar++; + return sourceStream.read(); + } + +}