9

I am able to create a new node via the Jenkins web GUI and then have the node running in a container connect back to the Jenkins master via the name and -secret value

ex. docker run jenkinsci/jnlp-slave -url http://jenkins-server:port <secret> <slave name>

Is there a way to programmatically create a Jenkins node and get the secret and slave name so I don't have to do it via the GUI?

Bobloblawlawblogs
  • 293
  • 2
  • 5
  • 12

3 Answers3

13

Creating an agent programmatically

You can use the create-node CLI command to create new agents with a given configuration.

For example, given this minimal JNLP agent configuration in a file config.xml:

<slave>
  <remoteFS>/opt/jenkins</remoteFS>
  <numExecutors>2</numExecutors>
  <launcher class="hudson.slaves.JNLPLauncher" />
</slave>

you can run the create-node command via the CLI client, or the SSH interface:

cat config.xml | java -jar jenkins-cli.jar -s https://jenkins/ create-node my-agent

Viewing agent configuration

To see what the XML configuration looks like for an existing agent, you can append config.xml to an agent URL, e.g. https://jenkins/computer/some-agent-name/config.xml, or you can use the get-node CLI command.

Fetching the per-agent secret programmatically

To fetch the secret hex value without using the Jenkins web UI, you can run a script via the groovy CLI command:

echo 'println jenkins.model.Jenkins.instance.nodesObject.getNode("my-agent")?.computer?.jnlpMac' \
  | java -jar ~/Downloads/jenkins-cli.jar -s https://jenkins/ groovy =

This will return the secret value directly. Note that in order to use the groovy command via the SSH interface, you need Jenkins 2.46 or newer. In earlier versions, it only works via the CLI client.

Christopher Orr
  • 110,418
  • 27
  • 198
  • 193
  • shoud add "-remoting" before "groovy", and should checked "Enable CLI over Remoting" – qxo Sep 25 '17 at 07:03
6

You can also create an agent using the REST API. This is especially useful when having an apache proxy in front (see issue JENKINS47279) and no direct access to the jenkins otherwise (e.g. in a corporate network) where CLI will not work.

I recommend to create an API token for this purpose. Then you can do something like this

Linux (Bash)

export JENKINS_URL=https://jenkins.intra
export JENKINS_USER=papanito
export JENKINS_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
export NODE_NAME=testnode
export JSON_OBJECT="{ 'name':+'${NODE_NAME}',+'nodeDescription':+'Linux+slave',+'numExecutors':+'5',+'remoteFS':+'/home/jenkins/agent',+'labelString':+'SLAVE-DOCKER+linux',+'mode':+'EXCLUSIVE',+'':+['hudson.slaves.JNLPLauncher',+'hudson.slaves.RetentionStrategy\$Always'],+'launcher':+{'stapler-class':+'hudson.slaves.JNLPLauncher',+'\$class':+'hudson.slaves.JNLPLauncher',+'workDirSettings':+{'disabled':+true,+'workDirPath':+'',+'internalDir':+'remoting',+'failIfWorkDirIsMissing':+false},+'tunnel':+'',+'vmargs':+'-Xmx1024m'},+'retentionStrategy':+{'stapler-class':+'hudson.slaves.RetentionStrategy\$Always',+'\$class':+'hudson.slaves.RetentionStrategy\$Always'},+'nodeProperties':+{'stapler-class-bag':+'true',+'hudson-slaves-EnvironmentVariablesNodeProperty':+{'env':+[{'key':+'JAVA_HOME',+'value':+'/docker-java-home'},+{'key':+'JENKINS_HOME',+'value':+'/home/jenkins'}]},+'hudson-tools-ToolLocationNodeProperty':+{'locations':+[{'key':+'hudson.plugins.git.GitTool\$DescriptorImpl@Default',+'home':+'/usr/bin/git'},+{'key':+'hudson.model.JDK\$DescriptorImpl@JAVA-8',+'home':+'/usr/bin/java'},+{'key':+'hudson.tasks.Maven\$MavenInstallation\$DescriptorImpl@MAVEN-3.5.2',+'home':+'/usr/bin/mvn'}]}}}"

curl -L -s -o /dev/null -v -k -w "%{http_code}" -u "${JENKINS_USER}:${JENKINS_API_TOKEN}" -H "Content-Type:application/x-www-form-urlencoded" -X POST -d "json=${JSON_OBJECT}" "${JENKINS_URL}/computer/doCreateItem?name=${NODE_NAME}&type=hudson.slaves.DumbSlave"

In order to get the agent secret via REST API checkout this, which would look something like this:

curl -L -s -u ${JENKINS_USER}:${JENKINS_API_TOKEN} -X GET ${JENKINS_URL}/computer/${NODE_NAME}/slave-agent.jnlp | sed "s/.*<application-desc main-class=\"hudson.remoting.jnlp.Main\"><argument>\([a-z0-9]*\).*/\1/"

Windows (PS)

And here my solution for Windows using Powershell:

$JENKINS_URL="https://jenkins.intra"
$JENKINS_USER="papanito"
$JENKINS_API_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxx"
$NODE_NAME="testnode-ps"

# https://stackoverflow.com/questions/27951561/use-invoke-webrequest-with-a-username-and-password-for-basic-authentication-on-t
$bytes = [System.Text.Encoding]::ASCII.GetBytes("${JENKINS_USER}:${JENKINS_API_TOKEN}")
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{ Authorization = $basicAuthValue;  }

$hash=@{
    name="${NODE_NAME}";
    nodeDescription="Linux slave";
    numExecutors="5";
    remoteFS="/home/jenkins/agent";
    labelString="SLAVE-DOCKER linux";
    mode="EXCLUSIVE";
    ""=@(
            "hudson.slaves.JNLPLauncher";
            'hudson.slaves.RetentionStrategy$Always'
        );
    launcher=@{ 
        "stapler-class"="hudson.slaves.JNLPLauncher";
        "\$class"="hudson.slaves.JNLPLauncher";
        "workDirSettings"=@{
            "disabled"="true";
            "workDirPath"="";
            "internalDir"="remoting";
            "failIfWorkDirIsMissing"="false"
        };
        "tunnel"="";
        "vmargs"="-Xmx1024m"
        };
        "retentionStrategy"=@{
            "stapler-class"= 'hudson.slaves.RetentionStrategy$Always';
           '$class'= 'hudson.slaves.RetentionStrategy$Always'
        };
        "nodeProperties"=@{
            "stapler-class-bag"= "true";
            "hudson-slaves-EnvironmentVariablesNodeProperty"=@{
                "env"=@(
                    @{
                        "key"="JAVA_HOME";
                        "value"="/docker-java-home"
                    };
                    @{
                        "key"="JENKINS_HOME";
                        "value"="/home/jenkins"
                    }
                )
            };
            "hudson-tools-ToolLocationNodeProperty"=@{
                "locations"=@(
                    @{
                        "key"= 'hudson.plugins.git.GitTool$DescriptorImpl@Default';
                        "home"= "/usr/bin/git"
                    };
                    @{
                    "key"= 'hudson.model.JDK\$DescriptorImpl@JAVA-8';
                    "home"= "/usr/bin/java"
                    };
                    @{
                        "key"= 'hudson.tasks.Maven$MavenInstallation$DescriptorImpl@MAVEN-3.5.2';
                        "home"= "/usr/bin/mvn"
                    }
                )
            }
        }
    }

#https://stackoverflow.com/questions/17929494/powershell-convertto-json-with-embedded-hashtable
$JSON_OBJECT = $hash | convertto-json  -Depth 5
$JSON_OBJECT

Invoke-WebRequest -Headers $headers -ContentType "application/x-www-form-urlencoded" -Method POST -Body "json=${JSON_OBJECT}" -Uri "${JENKINS_URL}/computer/doCreateItem?name=${NODE_NAME}&type=hudson.slaves.DumbSlave"
papanito
  • 2,349
  • 2
  • 32
  • 60
1

Just chiming in a bit late to the party here, but I would highly recommend looking at the Jenkins Client plugin instead. Once the plugin is installed, you need only to start the client JAR from the build node and give it the IP address of the master.

As far as the master goes, you don't need to bother configuring anything. Nodes that register with the master are available automatically to start executing jobs. This is much easier than any of the slave.jar-based approaches.

Nik Reiman
  • 39,067
  • 29
  • 104
  • 160