Skip to content

Commit

Permalink
Merge commit '53b9bdff752b97bece30d450697852cbf8089c6d' of git://gith…
Browse files Browse the repository at this point in the history
…ub.com/jenkinsci/jenkins
  • Loading branch information
jglick committed Jan 30, 2018
2 parents 34191e7 + 53b9bdf commit 1977ca2
Show file tree
Hide file tree
Showing 197 changed files with 4,439 additions and 708 deletions.
2 changes: 1 addition & 1 deletion cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.100-SNAPSHOT</version>
<version>2.105-SNAPSHOT</version>
</parent>

<artifactId>cli</artifactId>
Expand Down
8 changes: 7 additions & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>2.100-SNAPSHOT</version>
<version>2.105-SNAPSHOT</version>
</parent>

<artifactId>jenkins-core</artifactId>
Expand Down Expand Up @@ -179,6 +179,12 @@ THE SOFTWARE.
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.infradna.tool</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Remoting version, which is embedded into the core
# This version MAY differ from what is really classloaded (see the "Pluggable Core Components", JENKINS-41196)
remoting.embedded.version=${remoting.version}

# Minimum Remoting version on external agents which is supported by the core
remoting.minimum.supported.version=${remoting.minimum.supported.version}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/ExtensionList.java
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ public static <T> ExtensionList<T> create(Jenkins jenkins, Class<T> type) {
* @return the singleton instance of the given type in its list.
* @throws IllegalStateException if there are no instances, or more than one
*
* @since TODO
* @since 2.87
*/
public static @Nonnull <U> U lookupSingleton(Class<U> type) {
ExtensionList<U> all = lookup(type);
Expand Down
7 changes: 5 additions & 2 deletions core/src/main/java/hudson/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.kohsuke.accmod.restrictions.NoExternalUse;

import javax.annotation.CheckForNull;
import javax.annotation.concurrent.GuardedBy;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -1308,7 +1307,11 @@ public int join() throws InterruptedException, IOException {
Channel taskChannel = null;
try {
// Sync IO will fail automatically if the channel is being closed, no need to use getOpenChannelOrFail()
taskChannel = Channel.currentOrFail();
// TODOL Replace by Channel#currentOrFail() when Remoting version allows
taskChannel = Channel.current();
if (taskChannel == null) {
throw new IOException("No Remoting channel associated with this thread");
}
taskChannel.syncIO();
} catch (Throwable t) {
// this includes a failure to sync, agent.jar too old, etc
Expand Down
15 changes: 10 additions & 5 deletions core/src/main/java/hudson/PluginManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import jenkins.security.CustomClassFilter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

Expand Down Expand Up @@ -705,13 +706,14 @@ public boolean accept(File dir, String name) {
// If this was a plugin that was detached some time in the past i.e. not just one of the
// plugins that was bundled "for fun".
if (ClassicPluginStrategy.isDetachedPlugin(name)) {
// If it's already installed and the installed version is older
// than the bundled version, then we upgrade. The bundled version is the min required version
// for "this" version of Jenkins, so we must upgrade.
VersionNumber installedVersion = getPluginVersion(rootDir, name);
VersionNumber bundledVersion = getPluginVersion(dir, name);
if (installedVersion != null && bundledVersion != null && installedVersion.isOlderThan(bundledVersion)) {
return true;
// If the plugin is already installed, we need to decide whether to replace it with the bundled version.
if (installedVersion != null && bundledVersion != null) {
// If the installed version is older than the bundled version, then it MUST be upgraded.
// If the installed version is newer than the bundled version, then it MUST NOT be upgraded.
// If the versions are equal we just keep the installed version.
return installedVersion.isOlderThan(bundledVersion);
}
}

Expand Down Expand Up @@ -867,6 +869,9 @@ public void dynamicLoad(File arc, boolean removeExisting) throws IOException, In
((UberClassLoader) uberClassLoader).loaded.clear();
}

// TODO antimodular; perhaps should have a PluginListener to complement ExtensionListListener?
CustomClassFilter.Contributed.load();

try {
p.resolvePluginDependencies();
strategy.load(p);
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/hudson/TcpSlaveAgentListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import hudson.model.AperiodicWork;
import jenkins.model.Jenkins;
import jenkins.model.identity.InstanceIdentityProvider;
import jenkins.slaves.RemotingVersionInfo;
import jenkins.util.SystemProperties;
import hudson.slaves.OfflineCause;
import java.io.DataOutputStream;
Expand Down Expand Up @@ -290,6 +291,7 @@ private void respondHello(String header, Socket s) throws IOException {
try {
Writer o = new OutputStreamWriter(s.getOutputStream(), "UTF-8");

//TODO: expose version about minimum supported Remoting version (JENKINS-48766)
if (header.startsWith("GET / ")) {
o.write("HTTP/1.0 200 OK\r\n");
o.write("Content-Type: text/plain;charset=UTF-8\r\n");
Expand All @@ -299,6 +301,7 @@ private void respondHello(String header, Socket s) throws IOException {
o.write("Jenkins-Session: " + Jenkins.SESSION_HASH + "\r\n");
o.write("Client: " + s.getInetAddress().getHostAddress() + "\r\n");
o.write("Server: " + s.getLocalAddress().getHostAddress() + "\r\n");
o.write("Remoting-Minimum-Version: " + RemotingVersionInfo.getMinimumSupportedVersion() + "\r\n");
o.flush();
s.shutdownOutput();
} else {
Expand Down
19 changes: 16 additions & 3 deletions core/src/main/java/hudson/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,26 @@ public static String loadFile(@Nonnull File logfile, @Nonnull Charset charset) t

StringBuilder str = new StringBuilder((int)logfile.length());

try (BufferedReader r = new BufferedReader(new InputStreamReader(Files.newInputStream(logfile.toPath()), charset))) {
// We're not using Files.newBufferedReader() here because there is a
// difference in how an InputStreamReader constructed from a Charset and
// the reader returned by Files.newBufferedReader() handle malformed and
// unmappable byte sequences for the specified encoding; the latter is
// more picky and will throw a CharacterCodingException. See:
// https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
//
// As reported at https://issues.jenkins-ci.org/browse/JENKINS-49112
// Run.getLog() calls loadFile() to fully read the generated log file.
// Until charset handling is resolved (e.g. by implementing
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), malformed
// bytes will need to be tolerated.
try (InputStream rawIn = Files.newInputStream(fileToPath(logfile));
Reader r = new BufferedReader(new InputStreamReader(rawIn, charset))) {
char[] buf = new char[1024];
int len;
while ((len = r.read(buf, 0, buf.length)) > 0)
str.append(buf, 0, len);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (Exception e) {
throw new IOException("Failed to fully read " + logfile + " using charset " + charset.name(), e);
}

return str.toString();
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/XmlFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public Object unmarshal( Object o ) throws IOException {

/**
* Variant of {@link #unmarshal(Object)} applying {@link XStream2#unmarshal(HierarchicalStreamReader, Object, DataHolder, boolean)}.
* @since FIXME
* @since 2.99
*/
public Object unmarshalNullingOut(Object o) throws IOException {
return unmarshal(o, true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hudson.init.impl;

import hudson.init.Initializer;
import java.io.EOFException;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.WebApp;
import org.kohsuke.stapler.compression.CompressionFilter;
Expand All @@ -17,31 +18,27 @@
import org.kohsuke.stapler.Stapler;

/**
* @author Kohsuke Kawaguchi
* Deals with exceptions that get thrown all the way up to the Stapler rendering layer.
*/
public class InstallUncaughtExceptionHandler {

private static final Logger LOGGER = Logger.getLogger(InstallUncaughtExceptionHandler.class.getName());

@Initializer
public static void init(final Jenkins j) throws IOException {
CompressionFilter.setUncaughtExceptionHandler(j.servletContext, new UncaughtExceptionHandler() {
@Override
public void reportException(Throwable e, ServletContext context, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
CompressionFilter.setUncaughtExceptionHandler(j.servletContext, (e, context, req, rsp) -> {
if (rsp.isCommitted()) {
LOGGER.log(Level.WARNING, null, e);
LOGGER.log(isEOFException(e) ? Level.FINE : Level.WARNING, null, e);
return;
}
req.setAttribute("javax.servlet.error.exception",e);
try {
WebApp.get(j.servletContext).getSomeStapler()
.invoke(req,rsp, Jenkins.getInstance(), "/oops");
WebApp.get(j.servletContext).getSomeStapler().invoke(req, rsp, Jenkins.get(), "/oops");
} catch (ServletException | IOException x) {
if (!Stapler.isSocketException(x)) {
throw x;
}
}
}
});
try {
Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
Expand All @@ -57,6 +54,16 @@ public void reportException(Throwable e, ServletContext context, HttpServletRequ
}
}

private static boolean isEOFException(Throwable e) {
if (e == null) {
return false;
} else if (e instanceof EOFException) {
return true;
} else {
return isEOFException(e.getCause());
}
}

/** An UncaughtExceptionHandler that just logs the exception */
private static class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

Expand Down
75 changes: 75 additions & 0 deletions core/src/main/java/hudson/lifecycle/ExitLifecycle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* The MIT License
*
* Copyright 2018 Alon Bar-Lev <alon.barlev@gmail.com>
*
* 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.lifecycle;

import hudson.Extension;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import java.util.logging.Level;
import java.util.logging.Logger;

import jenkins.model.Configuration;
import jenkins.model.Jenkins;

/**
* {@link Lifecycle} that delegates the responsibility to restart Jenkins to an external
* watchdog such as SystemD or OpenRC.
*
* <p>
* Restart by exit with specific code.
*
* @author Alon Bar-Lev
*/
@Restricted(NoExternalUse.class)
@Extension
public class ExitLifecycle extends Lifecycle {

private static final Logger LOGGER = Logger.getLogger(ExitLifecycle.class.getName());

private static final String EXIT_CODE_ON_RESTART = "exitCodeOnRestart";
private static final String DEFAULT_EXIT_CODE = "5";

private Integer exitOnRestart;

public ExitLifecycle() {
exitOnRestart = Integer.parseInt(Configuration.getStringConfigParameter(EXIT_CODE_ON_RESTART, DEFAULT_EXIT_CODE));
}

@Override
public void restart() {
Jenkins jenkins = Jenkins.getInstanceOrNull(); // guard against repeated concurrent calls to restart

try {
if (jenkins != null) {
jenkins.cleanUp();
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to clean up. Restart will continue.", e);
}

System.exit(exitOnRestart);
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/AbstractProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ public String getShortDescription() {
@Override
public CauseOfBlockage getCauseOfBlockage() {
// Block builds until they are done with post-production
if (isLogUpdated() && !isConcurrentBuild()) {
if (!isConcurrentBuild() && isLogUpdated()) {
final R lastBuild = getLastBuild();
if (lastBuild != null) {
return new BlockedBecauseOfBuildInProgress(lastBuild);
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/Cause.java
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public UserIdCause() {
/**
* Constructor.
* @param userId User ID. {@code null} if the user is unknown.
* @since TODO
* @since 2.96
*/
public UserIdCause(@CheckForNull String userId) {
this.userId = userId;
Expand Down
2 changes: 0 additions & 2 deletions core/src/main/java/hudson/model/Computer.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import hudson.slaves.Cloud;
import jenkins.util.SystemProperties;
import hudson.Util;
import hudson.cli.declarative.CLIMethod;
import hudson.cli.declarative.CLIResolver;
import hudson.console.AnnotatedLargeText;
import hudson.init.Initializer;
Expand Down Expand Up @@ -85,7 +84,6 @@
import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.args4j.Option;
import org.kohsuke.stapler.interceptor.RequirePOST;

import javax.annotation.OverridingMethodsMustInvokeSuper;
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/java/hudson/model/ItemGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ default void onRenamed(T item, String oldName, String newName) throws IOExceptio
/**
* Gets all the {@link Item}s recursively in the {@link ItemGroup} tree
* and filter them by the given type.
* @since FIXME
* @since 2.93
*/
default <T extends Item> List<T> getAllItems(Class<T> type) {
return Items.getAllItems(this, type);
Expand All @@ -102,23 +102,23 @@ default <T extends Item> List<T> getAllItems(Class<T> type) {
/**
* Gets all the {@link Item}s unordered, lazily and recursively in the {@link ItemGroup} tree
* and filter them by the given type.
* @since FIXME
* @since 2.93
*/
default <T extends Item> Iterable<T> allItems(Class<T> type) {
return Items.allItems(this, type);
}

/**
* Gets all the items recursively.
* @since FIXME
* @since 2.93
*/
default List<Item> getAllItems() {
return getAllItems(Item.class);
}

/**
* Gets all the items unordered, lazily and recursively.
* @since FIXME
* @since 2.93
*/
default Iterable<Item> allItems() {
return allItems(Item.class);
Expand Down
Loading

0 comments on commit 1977ca2

Please sign in to comment.