Skip to content

Commit

Permalink
[JENKINS-4758] Remove old JDK installer from the plugin (#89)
Browse files Browse the repository at this point in the history
* remove java installer
  • Loading branch information
kuisathaverat committed Jul 27, 2018
1 parent 04c816b commit 118423c
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 401 deletions.
118 changes: 118 additions & 0 deletions src/main/java/hudson/plugins/sshslaves/DefaultJavaProvider.java
@@ -0,0 +1,118 @@
/*
* The MIT License
*
* Copyright (c) 2004-, all the contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.sshslaves;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.trilead.ssh2.Connection;
import hudson.EnvVars;
import hudson.Extension;
import hudson.model.Descriptor;
import hudson.model.JDK;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.slaves.SlaveComputer;
import hudson.tools.ToolLocationNodeProperty;
import hudson.tools.ToolLocationNodeProperty.ToolLocation;
import jenkins.model.Jenkins;

/**
* Class to try to guess where is java.
* This is the list of places where it will try to find java:
* <p><ul>
* <li>Agent working directory - WORKING_DIRECTORY/jdk/bin/java
* <li>JAVA_HOME environment variable - JAVA_HOME/bin/java
* <li>JDK tools configured on Jenkins - JDK_TOOLS_LOCATIONS/bin/java
* <li>PATH
* <li>"/usr/bin/java"
* <li>"/usr/java/default/bin/java"
* <li>"/usr/java/latest/bin/java"
* <li>"/usr/local/bin/java"
* <li>"/usr/local/java/bin/java
* </ul><p>
*
*/
@Extension
public class DefaultJavaProvider extends JavaProvider {

public static final String JAVA_HOME = "JAVA_HOME";
public static final String BIN_JAVA = "/bin/java";

@Override
public List<String> getJavas(SlaveComputer computer, TaskListener listener, Connection connection) {
List<String> javas = new ArrayList<>();

String workingDirectory = SSHLauncher.getWorkingDirectory(computer);
if (workingDirectory != null) {
javas.add(workingDirectory + "/jdk/bin/java");
}

final Node node = computer.getNode();
javas.addAll(lookForJavaHome(node));
javas.addAll(lookForTools(node));
javas.addAll(Arrays.asList("java",
"/usr/bin/java",
"/usr/java/default/bin/java",
"/usr/java/latest/bin/java",
"/usr/local/bin/java",
"/usr/local/java/bin/java"));
return javas;
}

private List<String> lookForJavaHome(Node node) {
List<String> ret = Collections.emptyList();
if(node != null && node.getNodeProperties() != null){
for (NodeProperty property : node.getNodeProperties()){
if(property instanceof EnvironmentVariablesNodeProperty){
EnvVars env = ((EnvironmentVariablesNodeProperty) property).getEnvVars();
if (env != null && env.containsKey(JAVA_HOME)) {
ret.add(env.get(JAVA_HOME) + BIN_JAVA);
}
}
}
}
return ret;
}

private List<String> lookForTools(Node node) {
List<String> ret = Collections.emptyList();
Descriptor jdk = Jenkins.getActiveInstance().getDescriptorByType(JDK.DescriptorImpl.class);
if(node != null && node.getNodeProperties() != null){
for (NodeProperty property : node.getNodeProperties()){
if (property instanceof ToolLocationNodeProperty) {
for (ToolLocation tool : ((ToolLocationNodeProperty) property).getLocations()) {
if (tool.getType() == jdk) {
ret.add(tool.getHome() + BIN_JAVA);
}
}
}
}
}
return ret;
}
}
29 changes: 2 additions & 27 deletions src/main/java/hudson/plugins/sshslaves/JavaProvider.java
Expand Up @@ -29,23 +29,18 @@
import hudson.slaves.SlaveComputer;
import hudson.model.TaskListener;
import hudson.util.VersionNumber;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.List;
import java.util.Collections;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;

/**
* Guess where Java is.
*/
public abstract class JavaProvider implements ExtensionPoint {

private static final VersionNumber JAVA_LEVEL_7 = new VersionNumber("7");
private static final VersionNumber JAVA_LEVEL_8 = new VersionNumber("8");
private static final VersionNumber JAVA_8_MINIMAL_SINCE = new VersionNumber("2.54");


/**
* @deprecated
* Override {@link #getJavas(SlaveComputer, TaskListener, Connection)} instead.
Expand Down Expand Up @@ -75,31 +70,11 @@ public static ExtensionList<JavaProvider> all() {
* Gets minimal required Java version.
*
* @return Minimal Java version required on the master and agent side.
* It will be {@link #JAVA_LEVEL_7} if the core version cannot be determined due to whatever reason.
* @since TODO
*
*/
@Nonnull
public static VersionNumber getMinJavaLevel() {
// TODO: Use reflection to utilize new core API once JENKINS-43500 is integrated
// TODO: Get rid of it once Jenkins core requirement is bumped
/*try {
Method method = Jenkins.class.getMethod("getJavaMinLevel");
Object res = method.invoke(null);
if (res instanceof VersionNumber) {
return (VersionNumber) res;
}
} catch(SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
// Fallback to the default behavior, not supported yet
}*/

// Now use the known map of the previous updates
final VersionNumber version = Jenkins.getVersion();
if (version == null) {
// Version cannot be determined, assume it's an old one to retain compatibility.
return JAVA_LEVEL_7;
}

return version.isOlderThan(JAVA_8_MINIMAL_SINCE) ? JAVA_LEVEL_7 : JAVA_LEVEL_8;
return JAVA_LEVEL_8;
}
}
148 changes: 148 additions & 0 deletions src/main/java/hudson/plugins/sshslaves/JavaVersionChecker.java
@@ -0,0 +1,148 @@
/*
* The MIT License
*
* Copyright (c) 2004-, all the contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.sshslaves;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import java.util.logging.Logger;
import com.trilead.ssh2.Connection;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import hudson.model.TaskListener;
import hudson.slaves.SlaveComputer;
import hudson.util.VersionNumber;
import static java.util.logging.Level.FINE;

/**
* class to check if the version of java installed on the agent is a supported one.
*/
public class JavaVersionChecker {
private static final Logger LOGGER = Logger.getLogger(JavaVersionChecker.class.getName());

private final SlaveComputer computer;
private final TaskListener listener;
private final String jvmOptions;
private final Connection connection;

public JavaVersionChecker(SlaveComputer computer, TaskListener listener, String jvmOptions, Connection connection) {
this.computer = computer;
this.listener = listener;
this.jvmOptions = jvmOptions;
this.connection = connection;
}

/**
* return javaPath if specified in the configuration.
* Finds local Java.
*/
protected String resolveJava() throws InterruptedException, IOException {
for (JavaProvider provider : JavaProvider.all()) {
for (String javaCommand : provider.getJavas(computer, listener, connection)) {
LOGGER.fine("Trying Java at " + javaCommand);
try {
return checkJavaVersion(listener, javaCommand);
} catch (IOException e) {
LOGGER.log(FINE, "Failed to check the Java version",e);
// try the next one
}
}
}
throw new IOException("Java not found on " + computer + ". Install a Java 8 version on the Agent.");
}

@NonNull
private String checkJavaVersion(TaskListener listener, String javaCommand) throws IOException, InterruptedException {
listener.getLogger().println(Messages.SSHLauncher_CheckingDefaultJava(SSHLauncher.getTimestamp(),javaCommand));
StringWriter output = new StringWriter(); // record output from Java

ByteArrayOutputStream out = new ByteArrayOutputStream();
connection.exec(javaCommand + " "+ jvmOptions + " -version",out);
//TODO: Seems we need to retrieve the encoding from the connection destination
BufferedReader r = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(out.toByteArray()), Charset.defaultCharset()));
final String result = checkJavaVersion(listener.getLogger(), javaCommand, r, output);

if(null == result) {
listener.getLogger().println(Messages.SSHLauncher_UnknownJavaVersion(javaCommand));
listener.getLogger().println(output);
throw new IOException(Messages.SSHLauncher_UnknownJavaVersion(javaCommand));
} else {
return result;
}
}

/**
* Given the output of "java -version" in <code>r</code>, determine if this
* version of Java is supported.
*
* @param logger
* where to log the output
* @param javaCommand
* the command executed, used for logging
* @param r
* the output of "java -version"
* @param output
* copy the data from <code>r</code> into this output buffer
*/
@CheckForNull
@Restricted(NoExternalUse.class)
public String checkJavaVersion(final PrintStream logger, String javaCommand,
final BufferedReader r, final StringWriter output) throws IOException {
String line;
while (null != (line = r.readLine())) {
output.write(line);
output.write("\n");
line = line.toLowerCase(Locale.ENGLISH);
if (line.startsWith("java version \"") || line.startsWith("openjdk version \"")) {
final String versionStr = line.substring(line.indexOf('\"') + 1, line.lastIndexOf('\"'));
logger.println(Messages.SSHLauncher_JavaVersionResult(SSHLauncher.getTimestamp(), javaCommand, versionStr));

// parse as a number and we should be OK as all we care about is up through the first dot.
final VersionNumber minJavaLevel = JavaProvider.getMinJavaLevel();
try {
final Number version = NumberFormat.getNumberInstance(Locale.US).parse(versionStr);
//TODO: burn it with fire
if(version.doubleValue() < Double.parseDouble("1."+minJavaLevel)) {
throw new IOException(Messages.SSHLauncher_NoJavaFound2(line, minJavaLevel.toString()));
}
} catch(final ParseException e) {
throw new IOException(Messages.SSHLauncher_NoJavaFound2(line, minJavaLevel));
}
return javaCommand;
}
}
return null;
}
}

0 comments on commit 118423c

Please sign in to comment.