提交 e321cbb4 编写于 作者: J Jesse Glick

Merge branch 'master' into BuildTrigger-auth-JENKINS-16956

......@@ -55,7 +55,14 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=bug>
Fixed NPE from view new job name autocompletion since 1.553.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-22142">issue 22142</a>)
<li class='major bug'>
Deadlocks in concurrent builds under some conditions since 1.556.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-22560">issue 22560</a>)
<li class=rfe>
JNLP slaves are now handled through NIO-based remoting channels for better scalability.
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -29,7 +29,7 @@ import hudson.remoting.PingThread;
import hudson.remoting.Pipe;
import hudson.remoting.RemoteInputStream;
import hudson.remoting.RemoteOutputStream;
import hudson.remoting.SocketInputStream;
import hudson.remoting.SocketChannelStream;
import hudson.remoting.SocketOutputStream;
import javax.crypto.SecretKey;
......@@ -201,7 +201,7 @@ public class CLI {
} else {
s = new Socket();
s.connect(clip.endpoint,3000);
out = new SocketOutputStream(s);
out = SocketChannelStream.out(s);
}
closables.add(new Closeable() {
......@@ -210,7 +210,7 @@ public class CLI {
}
});
Connection c = new Connection(new SocketInputStream(s),out);
Connection c = new Connection(SocketChannelStream.in(s),out);
switch (clip.version) {
case 1:
......
......@@ -23,8 +23,7 @@
*/
package hudson.cli;
import hudson.remoting.SocketInputStream;
import hudson.remoting.SocketOutputStream;
import hudson.remoting.SocketChannelStream;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
......@@ -63,7 +62,7 @@ public class Connection {
public final DataOutputStream dout;
public Connection(Socket socket) throws IOException {
this(new SocketInputStream(socket),new SocketOutputStream(socket));
this(SocketChannelStream.in(socket),SocketChannelStream.out(socket));
}
public Connection(InputStream in, OutputStream out) {
......
......@@ -818,7 +818,7 @@ public abstract class Launcher {
* Kill the process when the channel is severed.
*/
@Override
protected synchronized void terminate(IOException e) {
public synchronized void terminate(IOException e) {
super.terminate(e);
ProcessTree pt = ProcessTree.get();
try {
......
......@@ -32,8 +32,10 @@ import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -55,7 +57,7 @@ import java.util.logging.Logger;
*/
public final class TcpSlaveAgentListener extends Thread {
private final ServerSocket serverSocket;
private final ServerSocketChannel serverSocket;
private volatile boolean shuttingDown;
public final int configuredPort;
......@@ -67,7 +69,8 @@ public final class TcpSlaveAgentListener extends Thread {
public TcpSlaveAgentListener(int port) throws IOException {
super("TCP slave agent listener port="+port);
try {
serverSocket = new ServerSocket(port);
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
} catch (BindException e) {
throw (BindException)new BindException("Failed to listen on port "+port+" because it's already in use.").initCause(e);
}
......@@ -82,7 +85,7 @@ public final class TcpSlaveAgentListener extends Thread {
* Gets the TCP port number in which we are listening.
*/
public int getPort() {
return serverSocket.getLocalPort();
return serverSocket.socket().getLocalPort();
}
@Override
......@@ -90,7 +93,7 @@ public final class TcpSlaveAgentListener extends Thread {
try {
// the loop eventually terminates when the socket is closed.
while (true) {
Socket s = serverSocket.accept();
Socket s = serverSocket.accept().socket();
// this prevents a connection from silently terminated by the router in between or the other peer
// and that goes without unnoticed. However, the time out is often very long (for example 2 hours
......
......@@ -4,9 +4,13 @@ import hudson.Extension;
import hudson.model.Computer;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Mode;
import hudson.remoting.ChannelBuilder;
import jenkins.AgentProtocol;
import jenkins.model.Jenkins;
import jenkins.slaves.NioChannelSelector;
import org.jenkinsci.remoting.nio.NioChannelHub;
import javax.inject.Inject;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
......@@ -23,6 +27,9 @@ import java.net.Socket;
*/
@Extension
public class CliProtocol extends AgentProtocol {
@Inject
NioChannelSelector nio;
@Override
public String getName() {
return "CLI-connect";
......@@ -30,13 +37,23 @@ public class CliProtocol extends AgentProtocol {
@Override
public void handle(Socket socket) throws IOException, InterruptedException {
new Handler(socket).run();
new Handler(nio.getHub(),socket).run();
}
protected static class Handler {
protected final NioChannelHub hub;
protected final Socket socket;
/**
* @deprecated as of 1.559
* Use {@link #Handler(NioChannelHub, Socket)}
*/
public Handler(Socket socket) {
this(null,socket);
}
public Handler(NioChannelHub hub, Socket socket) {
this.hub = hub;
this.socket = socket;
}
......@@ -47,9 +64,21 @@ public class CliProtocol extends AgentProtocol {
}
protected void runCli(Connection c) throws IOException, InterruptedException {
Channel channel = new Channel("CLI channel from " + socket.getInetAddress(),
Computer.threadPoolForRemoting, Mode.BINARY,
new BufferedInputStream(c.in), new BufferedOutputStream(c.out), null, true, Jenkins.getInstance().pluginManager.uberClassLoader);
ChannelBuilder cb;
String name = "CLI channel from " + socket.getInetAddress();
// Connection can contain cipher wrapper, which can't be NIO-ed.
// if (hub!=null)
// cb = hub.newChannelBuilder(name, Computer.threadPoolForRemoting);
// else
cb = new ChannelBuilder(name, Computer.threadPoolForRemoting);
Channel channel = cb
.withMode(Mode.BINARY)
.withRestricted(true)
.withBaseLoader(Jenkins.getInstance().pluginManager.uberClassLoader)
.build(new BufferedInputStream(c.in), new BufferedOutputStream(c.out));
channel.setProperty(CliEntryPoint.class.getName(),new CliManagerImpl(channel));
channel.join();
}
......
......@@ -2,6 +2,7 @@ package hudson.cli;
import hudson.Extension;
import jenkins.model.Jenkins;
import org.jenkinsci.remoting.nio.NioChannelHub;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
......@@ -28,14 +29,22 @@ public class CliProtocol2 extends CliProtocol {
@Override
public void handle(Socket socket) throws IOException, InterruptedException {
new Handler2(socket).run();
new Handler2(nio.getHub(), socket).run();
}
protected static class Handler2 extends Handler {
/**
* @deprecated as of 1.559
* Use {@link #Handler2(NioChannelHub, Socket)}
*/
public Handler2(Socket socket) {
super(socket);
}
public Handler2(NioChannelHub hub, Socket socket) {
super(hub, socket);
}
@Override
public void run() throws IOException, InterruptedException {
try {
......
......@@ -71,7 +71,6 @@ import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -156,7 +155,11 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
*/
protected transient List<Environment> buildEnvironments;
private transient LazyBuildMixIn.RunMixIn<P,R> runMixIn;
private transient final LazyBuildMixIn.RunMixIn<P,R> runMixIn = new LazyBuildMixIn.RunMixIn<P,R>() {
@Override protected R asRun() {
return _this();
}
};
protected AbstractBuild(P job) throws IOException {
super(job);
......@@ -174,14 +177,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
return getParent();
}
@Override public final synchronized LazyBuildMixIn.RunMixIn<P,R> getRunMixIn() {
if (runMixIn == null) {
runMixIn = new LazyBuildMixIn.RunMixIn<P,R>() {
@Override protected R asRun() {
return _this();
}
};
}
@Override public final LazyBuildMixIn.RunMixIn<P,R> getRunMixIn() {
return runMixIn;
}
......
......@@ -108,6 +108,7 @@ public abstract class ItemGroupMixIn {
item = (V) Items.load( parent, subdir );
}else{
Logger.getLogger( ItemGroupMixIn.class.getName() ).log( Level.WARNING, "could not find file " + xmlFile.getFile());
continue;
}
} else {
item.onLoad(parent, subdir.getName());
......
......@@ -25,6 +25,8 @@ package hudson.model;
import hudson.model.Descriptor.FormException;
import hudson.slaves.NodeProperty;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
......@@ -77,5 +79,5 @@ public interface ReconfigurableDescribable<T extends ReconfigurableDescribable<T
* @return
* The new instance. To not to create an instance of a describable, return null.
*/
T reconfigure(StaplerRequest req, JSONObject form) throws FormException;
@CheckForNull T reconfigure(@Nonnull StaplerRequest req, @CheckForNull JSONObject form) throws FormException;
}
......@@ -1445,17 +1445,19 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* @throws IOException
* if we fail to delete.
*/
public synchronized void delete() throws IOException {
public void delete() throws IOException {
File rootDir = getRootDir();
if (!rootDir.isDirectory()) {
throw new IOException(this + ": " + rootDir + " looks to have already been deleted");
}
RunListener.fireDeleted(this);
synchronized (this) { // avoid holding a lock while calling plugin impls of onDeleted
// if we have a symlink, delete it, too
File link = new File(project.getBuildDir(), String.valueOf(getNumber()));
link.delete();
File rootDir = getRootDir();
if (!rootDir.isDirectory()) {
throw new IOException(this + ": " + rootDir + " looks to have already been deleted");
}
File tmp = new File(rootDir.getParentFile(),'.'+rootDir.getName());
if (tmp.exists()) {
......@@ -1474,6 +1476,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
LOGGER.log(FINE, "{0}: {1} successfully deleted", new Object[] {this, rootDir});
removeRunFromParent();
}
}
@SuppressWarnings("unchecked") // seems this is too clever for Java's type system?
......
......@@ -26,7 +26,8 @@ package hudson.model;
import hudson.views.ListViewColumn;
import hudson.views.ListViewColumnDescriptor;
import hudson.views.ViewJobFilter;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.AncestorInPath;
......@@ -68,35 +69,10 @@ public abstract class ViewDescriptor extends Descriptor<View> {
protected ViewDescriptor() {
}
@Deprecated
public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(final String prefix) {
final AutoCompletionCandidates r = new AutoCompletionCandidates();
new ItemVisitor() {
@Override
public void onItemGroup(ItemGroup<?> group) {
// only dig deep when the path matches what's typed.
// for example, if 'foo/bar' is typed, we want to show 'foo/barcode'
if (prefix.startsWith(group.getFullName()))
super.onItemGroup(group);
}
@Override
public void onItem(Item i) {
if (i.getFullName().startsWith(prefix)) {
r.add((i.getFullName()));
super.onItem(i);
}
}
}.onItemGroup(Jenkins.getInstance());
return r;
}
/**
* Auto-completion for the "copy from" field in the new job page.
* @since 1.553
*/
@Restricted(DoNotUse.class)
public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value, @AncestorInPath ItemGroup container) {
return AutoCompletionCandidates.ofJobNames(TopLevelItem.class, value, container);
}
......
......@@ -235,7 +235,7 @@ public abstract class RunListener<R extends Run> implements ExtensionPoint {
}
/**
* Fires the {@link #onFinalized(Run)} event.
* Fires the {@link #onDeleted} event.
*/
public static void fireDeleted(Run r) {
for (RunListener l : all()) {
......
......@@ -30,8 +30,7 @@ import hudson.model.Computer;
import hudson.model.TaskListener;
import hudson.remoting.Channel;
import hudson.remoting.Launcher;
import hudson.remoting.SocketInputStream;
import hudson.remoting.SocketOutputStream;
import hudson.remoting.SocketChannelStream;
import hudson.util.ClasspathBuilder;
import hudson.util.JVMBuilder;
import hudson.util.StreamCopyThread;
......@@ -73,7 +72,7 @@ public class Channels {
* Kill the process when the channel is severed.
*/
@Override
protected synchronized void terminate(IOException e) {
public synchronized void terminate(IOException e) {
super.terminate(e);
try {
proc.kill();
......@@ -109,7 +108,7 @@ public class Channels {
* Kill the process when the channel is severed.
*/
@Override
protected synchronized void terminate(IOException e) {
public synchronized void terminate(IOException e) {
super.terminate(e);
proc.destroy();
// the stderr copier should exit by itself
......@@ -205,8 +204,8 @@ public class Channels {
serverSocket.close();
return forProcess("Channel to "+displayName, Computer.threadPoolForRemoting,
new BufferedInputStream(new SocketInputStream(s)),
new BufferedOutputStream(new SocketOutputStream(s)),null,p);
new BufferedInputStream(SocketChannelStream.in(s)),
new BufferedOutputStream(SocketChannelStream.out(s)),null,p);
}
......
......@@ -75,12 +75,12 @@ public abstract class ParameterizedJobMixIn<JobT extends Job<JobT, RunT> & Param
/** @see BuildableItem#scheduleBuild() */
@SuppressWarnings("deprecation")
public final boolean scheduleBuild() {
return scheduleBuild(Jenkins.getInstance().getQuietPeriod(), new Cause.LegacyCodeCause());
return scheduleBuild(asJob().getQuietPeriod(), new Cause.LegacyCodeCause());
}
/** @see BuildableItem#scheduleBuild(Cause) */
public final boolean scheduleBuild(Cause c) {
return scheduleBuild(Jenkins.getInstance().getQuietPeriod(), c);
return scheduleBuild(asJob().getQuietPeriod(), c);
}
/** @see BuildableItem#scheduleBuild(int) */
......
......@@ -280,7 +280,7 @@ public abstract class LazyBuildMixIn<JobT extends Job<JobT,RunT> & Queue.Task &
/**
* Accompanying helper for the run type.
* Stateful but should be held in a {@code transient} field.
* Stateful but should be held in a {@code transient final} field.
*/
public static abstract class RunMixIn<JobT extends Job<JobT,RunT> & Queue.Task & LazyBuildMixIn.LazyLoadingJob<JobT,RunT>, RunT extends Run<JobT,RunT> & LazyLoadingRun<JobT,RunT>> {
......
......@@ -2,18 +2,18 @@ package jenkins.slaves;
import hudson.AbortException;
import hudson.Extension;
import hudson.model.Computer;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Listener;
import hudson.remoting.ChannelBuilder;
import hudson.remoting.Engine;
import hudson.remoting.SocketInputStream;
import hudson.remoting.SocketOutputStream;
import hudson.slaves.SlaveComputer;
import jenkins.AgentProtocol;
import jenkins.model.Jenkins;
import jenkins.security.HMACConfidentialKey;
import org.jenkinsci.remoting.nio.NioChannelHub;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import javax.inject.Inject;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
......@@ -55,6 +55,9 @@ import java.util.logging.Logger;
*/
@Extension
public class JnlpSlaveAgentProtocol extends AgentProtocol {
@Inject
NioChannelSelector hub;
@Override
public String getName() {
return "JNLP-connect";
......@@ -62,10 +65,11 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol {
@Override
public void handle(Socket socket) throws IOException, InterruptedException {
new Handler(socket).run();
new Handler(hub.getHub(),socket).run();
}
protected static class Handler {
protected final NioChannelHub hub;
protected final Socket socket;
/**
......@@ -82,7 +86,16 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol {
*/
protected final PrintWriter out;
/**
* @deprecated as of 1.559
* Use {@link #Handler(NioChannelHub, Socket)}
*/
public Handler(Socket socket) throws IOException {
this(null,socket);
}
public Handler(NioChannelHub hub, Socket socket) throws IOException {
this.hub = hub;
this.socket = socket;
in = new DataInputStream(socket.getInputStream());
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8")),true);
......@@ -121,7 +134,14 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol {
logw.println("JNLP agent connected from "+ socket.getInetAddress());
try {
computer.setChannel(new BufferedInputStream(new SocketInputStream(socket)), new BufferedOutputStream(new SocketOutputStream(socket)), log,
ChannelBuilder cb;
if (hub==null)
cb = new ChannelBuilder(nodeName, Computer.threadPoolForRemoting);
else
cb = hub.newChannelBuilder(nodeName, Computer.threadPoolForRemoting);
computer.setChannel(cb.withHeaderStream(log).build(socket), log,
new Listener() {
@Override
public void onClosed(Channel channel, IOException cause) {
......
......@@ -7,6 +7,7 @@ import hudson.remoting.Channel;
import hudson.remoting.Engine;
import hudson.slaves.SlaveComputer;
import jenkins.model.Jenkins;
import org.jenkinsci.remoting.nio.NioChannelHub;
import java.io.ByteArrayInputStream;
import java.io.IOException;
......@@ -40,14 +41,22 @@ public class JnlpSlaveAgentProtocol2 extends JnlpSlaveAgentProtocol {
@Override
public void handle(Socket socket) throws IOException, InterruptedException {
new Handler2(socket).run();
new Handler2(hub.getHub(),socket).run();
}
protected static class Handler2 extends Handler {
/**
* @deprecated as of 1.559
* Use {@link #Handler2(NioChannelHub, Socket)}
*/
public Handler2(Socket socket) throws IOException {
super(socket);
}
public Handler2(NioChannelHub hub, Socket socket) throws IOException {
super(hub, socket);
}
/**
* Handles JNLP slave agent connection request (v2 protocol)
*/
......
package jenkins.slaves;
import hudson.Extension;
import hudson.model.Computer;
import org.jenkinsci.remoting.nio.NioChannelHub;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Singleton holder of {@link NioChannelHub}
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class NioChannelSelector {
private NioChannelHub hub;
public NioChannelSelector() {
try {
if (!DISABLED) {
this.hub = new NioChannelHub(Computer.threadPoolForRemoting);
Computer.threadPoolForRemoting.submit(hub);
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Failed to launch NIO hub",e);
this.hub = null;
DISABLED = true;
}
}
public NioChannelHub getHub() {
return hub;
}
/**
* Escape hatch to disable use of NIO.
*/
public static boolean DISABLED = Boolean.getBoolean(NioChannelSelector.class.getName()+".disabled");
private static final Logger LOGGER = Logger.getLogger(NioChannelSelector.class.getName());
}
......@@ -172,7 +172,7 @@ THE SOFTWARE.
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>remoting</artifactId>
<version>2.37</version>
<version>2.39</version>
</dependency>
<dependency>
......
......@@ -160,6 +160,14 @@ THE SOFTWARE.
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>other</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<!-- no security constraint -->
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
......
......@@ -1814,6 +1814,7 @@ function buildFormTree(form) {
}
var p;
var r;
var type = e.getAttribute("type");
if(type==null) type="";
switch(type.toLowerCase()) {
......@@ -1861,15 +1862,17 @@ function buildFormTree(form) {
break;
case "radio":
if(!e.checked) break;
while (e.name.substring(0,8)=='removeme')
e.name = e.name.substring(e.name.indexOf('_',8)+1);
r=0;
while (e.name.substring(r,r+8)=='removeme')
r = e.name.indexOf('_',r+8)+1;
p = findParent(e);
if(e.groupingNode) {
p = findParent(e);
addProperty(p, e.name, e.formDom = { value: e.value });
break;
addProperty(p, e.name.substring(r), e.formDom = { value: e.value });
} else {
addProperty(p, e.name.substring(r), e.value);
}
break;
// otherwise fall through
default:
p = findParent(e);
addProperty(p, e.name, e.value);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册