Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create jenkins JLNP slave programmatically

Tags:

jenkins

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?

like image 512
Bobloblawlawblogs Avatar asked Mar 08 '17 22:03

Bobloblawlawblogs


People also ask

How do I set up a Windows slave agent via Jnlp if I have a Jenkins master configured on Linux?

To set-up the Windows-slave agent:Go to Manage Jenkins -> Manage Nodes ->click on New Node -> Enter the node name -> Select permanent agent. Enter a sample description and the no of executors (ie. no of jobs you want to run parallely on windows),here I have given 1 executor.


3 Answers

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.

like image 178
Christopher Orr Avatar answered Sep 20 '22 16:09

Christopher Orr


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\[email protected]',+'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"= '[email protected]';
                        "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"
like image 29
papanito Avatar answered Sep 22 '22 16:09

papanito


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.

like image 43
Nik Reiman Avatar answered Sep 22 '22 16:09

Nik Reiman