/** * This method tries to compute the name of the host that's reachable by all the other nodes. * * <p>Since it's possible that the slave is not reachable from the master (it may be behind a * firewall, connecting to master via JNLP), this method may return null. * * <p>It's surprisingly tricky for a machine to know a name that other systems can get to, * especially between things like DNS search suffix, the hosts file, and YP. * * <p>So the technique here is to compute possible interfaces and names on the slave, then try to * ping them from the master, and pick the one that worked. * * <p>The computation may take some time, so it employs caching to make the successive lookups * faster. * * @since 1.300 * @return null if the host name cannot be computed (for example because this computer is offline, * because the slave is behind the firewall, etc.) */ public String getHostName() throws IOException, InterruptedException { if (hostNameCached) // in the worst case we end up having multiple threads computing the host name simultaneously, // but that's not harmful, just wasteful. return cachedHostName; VirtualChannel channel = getChannel(); if (channel == null) return null; // can't compute right now for (String address : channel.call(new ListPossibleNames())) { try { InetAddress ia = InetAddress.getByName(address); if (!(ia instanceof Inet4Address)) { LOGGER.fine(address + " is not an IPv4 address"); continue; } if (!ComputerPinger.checkIsReachable(ia, 3)) { LOGGER.fine(address + " didn't respond to ping"); continue; } cachedHostName = ia.getCanonicalHostName(); hostNameCached = true; return cachedHostName; } catch (IOException e) { // if a given name fails to parse on this host, we get this error LOGGER.log(Level.FINE, "Failed to parse " + address, e); } } // allow the administrator to manually specify the host name as a fallback. HUDSON-5373 cachedHostName = channel.call(new GetFallbackName()); hostNameCached = true; return cachedHostName; }
public static CommandOutputContent runOnNode(Node node, String name, String... command) { String content = "Exception occurred while retrieving command content"; VirtualChannel chan = node.getChannel(); if (chan == null) { content = "No connection to node"; } else { try { content = chan.call(new CommandLauncher(command)); } catch (IOException e) { final LogRecord lr = new LogRecord(Level.FINE, "Could not retrieve command content from {0}"); lr.setParameters(new Object[] {getNodeName(node)}); lr.setThrown(e); LOGGER.log(lr); } catch (InterruptedException e) { final LogRecord lr = new LogRecord(Level.FINE, "Could not retrieve command content from {0}"); lr.setParameters(new Object[] {getNodeName(node)}); lr.setThrown(e); LOGGER.log(lr); } } return new CommandOutputContent(name, content); }
@Override protected T monitor(Computer c) throws IOException, InterruptedException { VirtualChannel ch = c.getChannel(); if (ch != null) { Callable<T, IOException> cc = createCallable(c); if (cc != null) return ch.call(cc); } return null; }
/** Starts a new privilege-escalated environment, execute a closure, and shut it down. */ public static <V, T extends Throwable> V execute( TaskListener listener, String rootUsername, String rootPassword, final Callable<V, T> closure) throws T, IOException, InterruptedException { VirtualChannel ch = start(listener, rootUsername, rootPassword); try { return ch.call(closure); } finally { ch.close(); ch.join(3000); // give some time for orderly shutdown, but don't block forever. } }
private void install(Computer c, TaskListener listener) { try { final List<SlaveRestarter> restarters = new ArrayList<SlaveRestarter>(SlaveRestarter.all()); VirtualChannel ch = c.getChannel(); if (ch==null) return; // defensive check List<SlaveRestarter> effective = ch.call(new Callable<List<SlaveRestarter>, IOException>() { public List<SlaveRestarter> call() throws IOException { Engine e = Engine.current(); if (e == null) return null; // not running under Engine try { Engine.class.getMethod("addListener", EngineListener.class); } catch (NoSuchMethodException _) { return null; // running with older version of remoting that doesn't support adding listener } // filter out ones that doesn't apply for (Iterator<SlaveRestarter> itr = restarters.iterator(); itr.hasNext(); ) { SlaveRestarter r = itr.next(); if (!r.canWork()) itr.remove(); } e.addListener(new EngineListenerAdapter() { @Override public void onDisconnect() { try { for (SlaveRestarter r : restarters) { try { LOGGER.info("Restarting slave via "+r); r.restart(); } catch (Exception x) { LOGGER.log(SEVERE, "Failed to restart slave with "+r, x); } } } finally { // if we move on to the reconnection without restart, // don't let the current implementations kick in when the slave loses connection again restarters.clear(); } } }); return restarters; } }); listener.getLogger().println("Effective SlaveRestarter on " + c.getDisplayName() + ": " + effective); } catch (Throwable e) { e.printStackTrace(listener.error("Failed to install restarter")); } }
/** Performs all monitoring concurrently. */ @Override protected Map<Computer, T> monitor() throws InterruptedException { Map<Computer, Future<T>> futures = new HashMap<Computer, Future<T>>(); for (Computer c : Jenkins.getInstance().getComputers()) { try { VirtualChannel ch = c.getChannel(); futures.put(c, null); // sentinel value if (ch != null) { Callable<T, ?> cc = createCallable(c); if (cc != null) futures.put(c, ch.callAsync(cc)); } } catch (RuntimeException e) { LOGGER.log( WARNING, "Failed to monitor " + c.getDisplayName() + " for " + getDisplayName(), e); } catch (IOException e) { LOGGER.log( WARNING, "Failed to monitor " + c.getDisplayName() + " for " + getDisplayName(), e); } } final long now = System.currentTimeMillis(); final long end = now + getMonitoringTimeOut(); final Map<Computer, T> data = new HashMap<Computer, T>(); for (Entry<Computer, Future<T>> e : futures.entrySet()) { Computer c = e.getKey(); Future<T> f = futures.get(c); data.put(c, null); // sentinel value if (f != null) { try { data.put(c, f.get(Math.max(0, end - System.currentTimeMillis()), MILLISECONDS)); } catch (RuntimeException x) { LOGGER.log( WARNING, "Failed to monitor " + c.getDisplayName() + " for " + getDisplayName(), x); } catch (ExecutionException x) { LOGGER.log( WARNING, "Failed to monitor " + c.getDisplayName() + " for " + getDisplayName(), x); } catch (TimeoutException x) { LOGGER.log( WARNING, "Failed to monitor " + c.getDisplayName() + " for " + getDisplayName(), x); } } } return data; }
/** Dumps the contents of the export table. */ public void doDumpExportTable(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException { // this is a debug probe and may expose sensitive information checkPermission(Jenkins.ADMINISTER); rsp.setContentType("text/plain"); PrintWriter w = new PrintWriter(rsp.getCompressedWriter(req)); VirtualChannel vc = getChannel(); if (vc instanceof Channel) { w.println("Master to slave"); ((Channel) vc).dumpExportTable(w); w.flush(); // flush here once so that even if the dump from the slave fails, the client // gets some useful info w.println("\n\n\nSlave to master"); w.print(vc.call(new DumpExportTableTask())); } else { w.println(Messages.Computer_BadChannel()); } w.close(); }
public String getShellOrDefault(VirtualChannel channel) { if (shell != null) return shell; String interpreter = null; try { interpreter = channel.call(new Shellinterpreter()); } catch (IOException e) { LOGGER.warning(e.getMessage()); } catch (InterruptedException e) { LOGGER.warning(e.getMessage()); } if (interpreter == null) { interpreter = getShellOrDefault(); } return interpreter; }
/** Obtains the heap dump in an HPROF file. */ public static FilePath getHeapDump(VirtualChannel channel) throws IOException, InterruptedException { return channel.call( new MasterToSlaveCallable<FilePath, IOException>() { public FilePath call() throws IOException { final File hprof = File.createTempFile("hudson-heapdump", "hprof"); hprof.delete(); try { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.invoke( new ObjectName("com.sun.management:type=HotSpotDiagnostic"), "dumpHeap", new Object[] {hprof.getAbsolutePath(), true}, new String[] {String.class.getName(), boolean.class.getName()}); return new FilePath(hprof); } catch (JMException e) { throw new IOException(e); } } private static final long serialVersionUID = 1L; }); }
public static Future<Map<String, String>> getThreadDumpAsync(VirtualChannel channel) throws IOException, InterruptedException { if (channel == null) return new AsyncFutureImpl<Map<String, String>>(Collections.singletonMap("N/A", "offline")); return channel.callAsync(new GetThreadDump()); }
public static Map<String, String> getThreadDump(VirtualChannel channel) throws IOException, InterruptedException { if (channel == null) return Collections.singletonMap("N/A", "N/A"); return channel.call(new GetThreadDump()); }
public static Map<Object, Object> getSystemProperties(VirtualChannel channel) throws IOException, InterruptedException { if (channel == null) return Collections.<Object, Object>singletonMap("N/A", "N/A"); return channel.call(new GetSystemProperties()); }
/** Executes Groovy script remotely. */ public static String executeGroovy(String script, @Nonnull VirtualChannel channel) throws IOException, InterruptedException { return channel.call(new Script(script)); }