Child pages
  • Auto-discovering Jenkins on the network
Skip to end of metadata
Go to start of metadata

If you are developing client applications or server applications that interact with Jenkins, you can benefit from auto-discovering Jenkins in the network. Jenkins supports several modes of programmable auto-discovery.

UDP multicast/broadcast

Jenkins listens on UDP port 33848. You can either send an UDP broadcast packet (targeted to 255.255.255.255) to this port, or you can send an UDP multicast packet (targeted to 239.77.124.213) to this port. When a packet is received (the payload doesn't matter), Jenkins will send an XML response to the sending UDP port as a datagram. By sending a packet and listening for incoming ones, you can have an UDP client to discover nearby Jenkins instances. UDP multicast works with version 1.335 and later, UDP broadcast works with version 1.282 and later.

The structure of the XML is as follows:

<hudson>
  <version>1.354</version><!-- version of the Jenkins -->
  <url>http://server/hudson/</url><!-- the top page of the Jenkins -->
  <slave-port>12345</slave-port><!-- TCP port number for slaves and CLIs to connect to -->
  ... more elements may appear here ...
</hudson>

Plugins can extend what to include in this XML fragment by contributing to the UDPBroadcastFragment extension point.

This feature can be disabled via the hudson.udp system property.

From Java

See the sample code written in Java that does auto-discovery via UDP broadcast.

DNS multicast

Jenkins advertises itself at "_jenkins._tcp.local" with DNS multicast. This is another way to discover Jenkins instances on the same subnet (or by extending the "_jenkins._tcp" convention, you can discover Jenkins for arbitrary domain names, such as "_jenkins._tcp.example.com", as a convention.) This works with version 1.359 and later.

The same version, url, and slave-port are available as the key/value pairs associated with the DNS record.

This feature can be disabled via the hudson.DNSMultiCast.disabled system property.

From Java

You can use jmDNS if you want to perform DNS multi-cast service discovery from Java. The sample code is below:

import javax.jmdns.*;

static class SampleListener implements ServiceListener {
    public void addService(JmDNS jmdns, String type, String name) {
        System.out.println("ADD: " + jmdns.getServiceInfo(type, name));
    }
    public void removeService(JmDNS jmdns, String type, String name) {
        System.out.println("REMOVE: " + name);
    }
    public void resolveService(JmDNS jmdns, String type, String name, ServiceInfo info) {
        System.out.println("RESOLVED: " + info);
    }
}

JmDNS jmdns = new JmDNS();
jmdns.addServiceListener("jenkins._tcp.local.", new SampleListener());
  • No labels

3 Comments

  1. Groovy code for DNS multi-cast looks like this:

    import javax.jmdns.*;
    import groovy.transform.Canonical
    import groovy.util.logging.Log4j2
    
    @Canonical
    @Log4j2
    class JenkinsServersFinder implements ServiceListener  {
    
    	static final String bonjourServiceType = "_hudson._tcp.local."
    	static final JmDNS jmdns = JmDNS.create()
    	
    	public void serviceAdded(ServiceEvent event) {
    		log.debug "serviceAdded: ${event.getName()}"
    	}
    	
    	public void serviceRemoved(ServiceEvent event) {
    		log.debug "serviceRemoved: ${event.getName()}"
    	}
    	
    	public void serviceResolved(ServiceEvent event) {
    		log.debug "serviceResolved: ${event.getName()}"
    	}
    	
    	static main(args) {
    		jmdns.addServiceListener(bonjourServiceType, new JenkinsServersFinder())
    		ServiceInfo[] serviceInfos = jmdns.list(bonjourServiceType)
    		for (ServiceInfo info : serviceInfos) {
    		  log.info "Found Jenkins service: ${info.getName()} : ${info.getURL()}"
    		}
    		jmdns.close()
    	}
    }
    

    For me the application displays only Jenkins instances found in my subnetwork, not the entire LAN.
    I'd like to know if it is possible to implement such functionality...

    1. Thanks! I could not find the @Grab for the Log4j2 so I used this:

      @Grab(group='javax.jmdns', module='jmdns', version='3.4.1')
      import javax.jmdns.*;
      @Grab(group='org.slf4j', module='slf4j-simple', version='1.6.1')
      import groovy.util.logging.Slf4j
       
      @Slf4j
  2. Additionally Python script sending UDP broadcast packet.
    The same problem here: it reports Jenkins instances from local subnetwork only.

    import socket
    
    IP_ADDR = '255.255.255.255'
    PORT_NO = 33848
    
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(30)
    
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.sendto(b'test', (IP_ADDR, PORT_NO))
    
    try:
        while True:
            data = s.recv(4096)
            if not data:
                break
            print("Message:", data.decode())
    except socket.timeout:
        print("Timeout!")
    finally:
        s.close()