Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2010 from jenkinsci/jnlp3
[FIXED JENKINS-26580][FIXED JENKINS-28289] Activate JNLP3 support (cherry picked from commit 6d3e054)
- Loading branch information
1 parent
5ca718a
commit af1a53d
Showing
7 changed files
with
173 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
137 changes: 137 additions & 0 deletions
137
core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package jenkins.slaves; | ||
|
||
import hudson.AbortException; | ||
import hudson.Extension; | ||
import hudson.Util; | ||
import hudson.model.Computer; | ||
import hudson.remoting.Channel; | ||
import hudson.remoting.ChannelBuilder; | ||
import hudson.slaves.SlaveComputer; | ||
import jenkins.AgentProtocol; | ||
import jenkins.model.Jenkins; | ||
import jenkins.security.ChannelConfigurator; | ||
import org.jenkinsci.remoting.engine.JnlpServer3Handshake; | ||
import org.jenkinsci.remoting.nio.NioChannelHub; | ||
import org.kohsuke.accmod.Restricted; | ||
import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
|
||
import javax.inject.Inject; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.io.PrintWriter; | ||
import java.net.Socket; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
/** | ||
* Master-side implementation for JNLP3-connect protocol. | ||
* | ||
* <p>@see {@link org.jenkinsci.remoting.engine.JnlpProtocol3} for more details. | ||
* | ||
* @author Akshay Dayal | ||
* @since 1.XXX | ||
*/ | ||
@Extension | ||
public class JnlpSlaveAgentProtocol3 extends AgentProtocol { | ||
@Inject | ||
NioChannelSelector hub; | ||
|
||
@Override | ||
public String getName() { | ||
if (ENABLED) return "JNLP3-connect"; | ||
else return "JNLP3-disabled"; | ||
} | ||
|
||
@Override | ||
public void handle(Socket socket) throws IOException, InterruptedException { | ||
new Handler(hub.getHub(), socket).run(); | ||
} | ||
|
||
static class Handler extends JnlpServer3Handshake { | ||
private SlaveComputer computer; | ||
private PrintWriter logw; | ||
private OutputStream log; | ||
|
||
public Handler(NioChannelHub hub, Socket socket) throws IOException { | ||
super(hub, Computer.threadPoolForRemoting, socket); | ||
} | ||
|
||
protected void run() throws IOException, InterruptedException { | ||
try { | ||
Channel channel = connect(); | ||
|
||
computer.setChannel(channel, log, | ||
new Channel.Listener() { | ||
@Override | ||
public void onClosed(Channel channel, IOException cause) { | ||
if (cause != null) | ||
LOGGER.log(Level.WARNING, | ||
Thread.currentThread().getName() + " for + " + | ||
getNodeName() + " terminated", cause); | ||
try { | ||
socket.close(); | ||
} catch (IOException e) { | ||
// Do nothing. | ||
} | ||
} | ||
}); | ||
} catch (AbortException e) { | ||
logw.println(e.getMessage()); | ||
logw.println("Failed to establish the connection with the agent"); | ||
throw e; | ||
} catch (IOException e) { | ||
logw.println("Failed to establish the connection with the agent " + getNodeName()); | ||
e.printStackTrace(logw); | ||
throw e; | ||
} | ||
} | ||
|
||
@Override | ||
public ChannelBuilder createChannelBuilder(String nodeName) { | ||
log = computer.openLogFile(); | ||
logw = new PrintWriter(log,true); | ||
logw.println("JNLP agent connected from " + socket.getInetAddress()); | ||
|
||
ChannelBuilder cb = super.createChannelBuilder(nodeName).withHeaderStream(log); | ||
|
||
for (ChannelConfigurator cc : ChannelConfigurator.all()) { | ||
cc.onChannelBuilding(cb, computer); | ||
} | ||
|
||
return cb; | ||
} | ||
|
||
@Override | ||
protected String getNodeSecret(String nodeName) throws Failure { | ||
computer = (SlaveComputer) Jenkins.getInstance().getComputer(nodeName); | ||
if (computer == null) { | ||
throw new Failure("Agent trying to register for invalid node: " + nodeName); | ||
} | ||
return computer.getJnlpMac(); | ||
} | ||
|
||
} | ||
|
||
private static final Logger LOGGER = Logger.getLogger(JnlpSlaveAgentProtocol3.class.getName()); | ||
|
||
/** | ||
* Flag to control the activation of JNLP3 protocol. | ||
* This feature is being A/B tested right now. | ||
* | ||
* <p> | ||
* Once this will be on by default, the flag and this field will disappear. The system property is | ||
* an escape hatch for those who hit any issues and those who are trying this out. | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public static boolean ENABLED; | ||
|
||
static { | ||
String propName = JnlpSlaveAgentProtocol3.class.getName() + ".enabled"; | ||
if (System.getProperties().containsKey(propName)) | ||
ENABLED = Boolean.getBoolean(propName); | ||
else { | ||
byte hash = Util.fromHexString(Jenkins.getActiveInstance().getLegacyInstanceId())[0]; | ||
ENABLED = (hash%10)==0; | ||
} | ||
} | ||
} |
110 changes: 7 additions & 103 deletions
110
core/src/main/java/jenkins/slaves/JnlpSlaveHandshake.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,22 @@ | ||
package jenkins.slaves; | ||
|
||
import hudson.model.Computer; | ||
import hudson.remoting.Channel; | ||
import hudson.remoting.ChannelBuilder; | ||
import hudson.remoting.Engine; | ||
import org.jenkinsci.remoting.engine.JnlpServerHandshake; | ||
import org.jenkinsci.remoting.nio.NioChannelHub; | ||
|
||
import java.io.DataInputStream; | ||
import java.io.DataOutputStream; | ||
import java.io.IOException; | ||
import java.io.PrintWriter; | ||
import java.net.Socket; | ||
import java.util.Map.Entry; | ||
import java.util.Properties; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import java.util.concurrent.ExecutorService; | ||
|
||
/** | ||
* Palette of objects to talk to the incoming JNLP slave connection. | ||
* | ||
* @author Kohsuke Kawaguchi | ||
* @since 1.561 | ||
* @deprecated as of 1.609 | ||
* Use {@link JnlpServerHandshake} | ||
*/ | ||
public class JnlpSlaveHandshake { | ||
/** | ||
* Useful for creating a {@link Channel} with NIO as the underlying transport. | ||
*/ | ||
/*package*/ final NioChannelHub hub; | ||
|
||
/** | ||
* Socket connection to the slave. | ||
*/ | ||
/*package*/ final Socket socket; | ||
|
||
/** | ||
* Wrapping Socket input stream. | ||
*/ | ||
/*package*/ final DataInputStream in; | ||
|
||
/** | ||
* For writing handshaking response. | ||
* | ||
* This is a poor design choice that we just carry forward for compatibility. | ||
* For better protocol design, {@link DataOutputStream} is preferred for newer | ||
* protocols. | ||
*/ | ||
/*package*/ final PrintWriter out; | ||
|
||
/** | ||
* Bag of properties the JNLP agent have sent us during the hand-shake. | ||
*/ | ||
/*package*/ final Properties request = new Properties(); | ||
|
||
|
||
/*package*/ JnlpSlaveHandshake(NioChannelHub hub, Socket socket, DataInputStream in, PrintWriter out) { | ||
this.hub = hub; | ||
this.socket = socket; | ||
this.in = in; | ||
this.out = out; | ||
} | ||
|
||
public NioChannelHub getHub() { | ||
return hub; | ||
} | ||
|
||
public Socket getSocket() { | ||
return socket; | ||
} | ||
|
||
public DataInputStream getIn() { | ||
return in; | ||
} | ||
|
||
public PrintWriter getOut() { | ||
return out; | ||
public class JnlpSlaveHandshake extends JnlpServerHandshake { | ||
/*package*/ JnlpSlaveHandshake(JnlpServerHandshake rhs) { | ||
super(rhs); | ||
} | ||
|
||
public Properties getRequestProperties() { | ||
return request; | ||
} | ||
|
||
public String getRequestProperty(String name) { | ||
return request.getProperty(name); | ||
} | ||
|
||
|
||
/** | ||
* Sends the error output and bail out. | ||
*/ | ||
public void error(String msg) throws IOException { | ||
out.println(msg); | ||
LOGGER.log(Level.WARNING,Thread.currentThread().getName()+" is aborted: "+msg); | ||
socket.close(); | ||
} | ||
|
||
/** | ||
* {@link JnlpAgentReceiver} calls this method to tell the client that the server | ||
* is happy with the handshaking and is ready to move on to build a channel. | ||
*/ | ||
public void success(Properties response) { | ||
out.println(Engine.GREETING_SUCCESS); | ||
for (Entry<Object, Object> e : response.entrySet()) { | ||
out.println(e.getKey()+": "+e.getValue()); | ||
} | ||
out.println(); // empty line to conclude the response header | ||
} | ||
|
||
public ChannelBuilder createChannelBuilder(String nodeName) { | ||
if (hub==null) | ||
return new ChannelBuilder(nodeName, Computer.threadPoolForRemoting); | ||
else | ||
return hub.newChannelBuilder(nodeName, Computer.threadPoolForRemoting); | ||
} | ||
|
||
|
||
private static final Logger LOGGER = Logger.getLogger(JnlpSlaveHandshake.class.getName()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters