Ravindra BagaleCourses & study guides मराठी

Chapter 23: Jenkins Fundamentals, Install and Architecture

23.8 CLI, from your own controller

Why: the problem

Think of Infosys running 300 Jenkins jobs. A release manager needs to start 20 builds in a row every Friday night, check which ones failed, and disable old jobs. Clicking 20 times in a browser is slow and error-prone. Scripts are better. Jenkins has two ways to be controlled from the terminal. The Jenkins CLI is a small Java program, jenkins-cli.jar, that you download from your own Jenkins. The REST API is plain HTTP: you call URLs with curl and get JSON back. Both need a login, and the safe login is an API token kept in a file outside Git, never your password. In this lesson you will use both to build jobs, pass parameters, follow logs, copy jobs, install plugins and check status.

What we will build

You will create an API token for a bot user. You will save it in a file only you can read. You will download jenkins-cli.jar from your controller and run common commands: who-am-i, list-jobs, build with parameters and console following, get-job and create-job to copy a job, and install-plugin. Then you will do the same work with curl and the REST API, and write a small release script that builds several jobs and prints a result table.

What: every term in plain English

  • Jenkins CLI — A command line tool, jenkins-cli.jar, that talks to your Jenkins.
  • REST API — URLs that return JSON or XML. Add /api/json to almost any Jenkins page.
  • API token — A long random key made per user. Use it instead of a password for scripts. You can revoke it any time.
  • -auth @file — CLI option that reads user:token from a file, so it is not typed on the command line.
  • Crumb — A CSRF protection value. Not needed when you use an API token.
  • tree= — A URL filter that returns only the fields you ask for. Makes API calls small and fast.
  • config.xml — The job definition. get-job prints it, create-job reads it.
  • Bot user — A Jenkins user for scripts, like ci-bot, with only the rights it needs.
Make a token Save it in a private file Download the CLI Make a short alias Check who you are List jobs Build and follow
CLI and REST API with a token file, top to bottom

How: step by step

  1. Make a token

    Click your name > Security > API Token > Add new Token > name: cli-laptop > Generate
    

    What it does: Copy it once; Jenkins does not show it again.

    Output

    Token created: 11a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7
    
  2. Save it in a private file

    umask 077 && printf "ravi:%s" "PASTE_TOKEN" > ~/.jenkins-auth && ls -l ~/.jenkins-auth
    

    What it does: umask 077 makes the file readable only by you.

    Output

    -rw------- 1 ravi ravi 40 Oct 25 12:01 /home/ravi/.jenkins-auth
    
  3. Download the CLI

    curl -fsSLO http://localhost:8080/jnlpJars/jenkins-cli.jar
    

    What it does: The CLI version always matches your Jenkins.

    Output

    (jenkins-cli.jar saved)
    
  4. Make a short alias

    alias jcli="java -jar ~/jenkins-cli.jar -s http://localhost:8080/ -auth @$HOME/.jenkins-auth"
    

    What it does: So you type jcli instead of the long line.

    Output

    (no output)
    
  5. Check who you are

    jcli who-am-i
    

    What it does: Proves the token works.

    Output

    Authenticated as: ravi
    Authorities:
      authenticated
    
  6. List jobs

    jcli list-jobs
    

    What it does: Prints every job name.

    Output

    env-demo
    flask-ci
    hello-pipeline
    
  7. Build and follow

    jcli build hello-pipeline -s -v
    

    What it does: Starts a build, waits, and prints the console.

    Output

    Started hello-pipeline #9
    ...
    Completed hello-pipeline #9 : SUCCESS
    

Example 1: Everyday CLI commands for a release manager

Stack. jenkins-cli.jar, Java 17

Goal. Everyday CLI commands for a release manager.

cli-demo.sh

#!/usr/bin/env bash
set -euo pipefail
J="java -jar $HOME/jenkins-cli.jar -s http://localhost:8080/ -auth @$HOME/.jenkins-auth"
$J version
$J list-jobs
$J build env-demo -p TARGET=qa -p APP_VERSION=2.4.0 -s -v | tail -5
$J console env-demo | tail -3
$J get-job hello-pipeline > hello-pipeline.xml
cat hello-pipeline.xml | $J create-job hello-pipeline-copy
$J disable-job hello-pipeline-copy
$J list-plugins | grep -E "^(git|workflow-aggregator) "

What each line does

  • version — Prints the Jenkins version.
  • build env-demo -p NAME=value — Starts a parameterized build.
  • -s -v — -s waits for the build to finish; -v prints the console output.
  • console env-demo — Prints the console of the last build.
  • get-job ... > file — Saves the job config.xml to a file.
  • cat file | create-job name — Creates a new job from that XML. This is how you copy jobs between servers.
  • disable-job — Stops a job from running without deleting it.
  • list-plugins — Lists installed plugins and versions.

Green output

2.479.1
env-demo
flask-ci
hello-pipeline
App shop-api tag 2.4.0-7 to qa
Finished: SUCCESS
Completed env-demo #7 : SUCCESS
git 5.5.2
workflow-aggregator 600.vb_57cdd26fdd7

Expected result. A copy job exists and is disabled. The parameterized build used your values. All without opening the browser.

Example 2: The same work with curl and the REST API

Stack. curl, jq, Jenkins REST API

Goal. The same work with curl and the REST API.

api-demo.sh

#!/usr/bin/env bash
set -euo pipefail
J="http://localhost:8080"
AUTH="$(cat "$HOME/.jenkins-auth")"
api() { curl -fsS -u "$AUTH" "$@"; }
api "$J/api/json?tree=jobs[name,color]" | jq -r '.jobs[] | "\(.name)\t\(.color)"'
api -X POST "$J/job/env-demo/buildWithParameters?TARGET=dev&APP_VERSION=2.5.0" -o /dev/null -w "queued %{http_code}\n"
sleep 20
api "$J/job/env-demo/lastBuild/api/json?tree=number,result,duration" | jq .
api "$J/job/env-demo/lastBuild/consoleText" | tail -3
api "$J/job/hello-pipeline/config.xml" -o hello-pipeline.xml
api -X POST "$J/createItem?name=hello-api-copy" -H "Content-Type: application/xml" --data-binary @hello-pipeline.xml -o /dev/null -w "created %{http_code}\n"

What each line does

  • AUTH="$(cat ...)" — Reads user:token from the private file.
  • ?tree=jobs[name,color] — Ask for only names and colours. Faster than the full JSON.
  • jq -r — Turns JSON into clean text lines.
  • buildWithParameters?... — Starts a build with parameters through HTTP. 201 means queued.
  • /consoleText — The plain text log of a build.
  • /createItem?name=... — Creates a job from config.xml sent in the body.

Green output

env-demo    blue
flask-ci    blue
hello-pipeline  blue
queued 201
{
  "duration": 4120,
  "number": 8,
  "result": "SUCCESS"
}
App shop-api tag 2.5.0-8 to dev
Finished: SUCCESS
created 200

Expected result. Everything the CLI did, plain curl can do. Tools like Ansible, Python scripts and chat bots use this API.

Example 3: A Friday release script that builds several jobs and prints a table

Stack. bash, jenkins-cli.jar

Goal. A Friday release script that builds several jobs and prints a table.

release-friday.sh

#!/usr/bin/env bash
# Usage: bash release-friday.sh orders-api payments-api web-ui
set -uo pipefail
J="java -jar $HOME/jenkins-cli.jar -s https://jenkins.shop-lab.in/ -auth @$HOME/.jenkins-auth"
printf "%-16s %-8s\n" JOB RESULT
fail=0
for job in "$@"; do
  if $J build "$job" -s > "/tmp/$job.log" 2>&1; then r=SUCCESS; else r=FAILED; fail=1; fi
  printf "%-16s %-8s\n" "$job" "$r"
done
[ "$fail" -eq 0 ] && echo "All green. Ready to release." || echo "Some jobs failed. See /tmp/JOB.log"
exit $fail

What each line does

  • set -uo pipefail — No -e here, so one failed job does not stop the loop.
  • for job in "$@" — Loops over all job names given to the script.
  • build "$job" -s — Waits for each build. The CLI exit code is non-zero when the build fails.
  • > /tmp/$job.log 2>&1 — Keeps each output in its own file for later reading.
  • printf "%-16s %-8s" — Prints a neat table with fixed column widths.
  • exit $fail — The script itself fails if any job failed, so another tool can react.

Green output

$ bash release-friday.sh orders-api payments-api web-ui
JOB              RESULT
orders-api       SUCCESS
payments-api     FAILED
web-ui           SUCCESS
Some jobs failed. See /tmp/JOB.log

Expected result. One command checks the whole release. Open /tmp/payments-api.log to see why it failed.

Verify: did it work?

  1. Token works by API

    curl -s -u "$(cat ~/.jenkins-auth)" http://localhost:8080/whoAmI/api/json | jq -r .name
    

    What it does: Prints your user name.

    Output

    ravi
    
  2. CLI help

    jcli help | head -5
    

    What it does: Lists all CLI commands your Jenkins supports.

    Output

    add-job-to-view
    build
    cancel-quiet-down
    clear-queue
    connect-node
    

When it is red 1

ERROR: You must authenticate to access this Jenkins.

Cause. No -auth, or the auth file is empty or wrong.

Fix, step by step

  1. cat ~/.jenkins-auth and check it is user:token.
  2. Make a new token if it was revoked.
  3. Use -auth @$HOME/.jenkins-auth.

When it is red 2

HTTP ERROR 403 No valid crumb was included in the request

Cause. You sent a POST with a password and no crumb.

Fix, step by step

  1. Use an API token instead of a password.
  2. Tokens skip the crumb check.

When it is red 3

io.jenkins.cli.shaded.jakarta.websocket.DeploymentException: Handshake error.

Cause. The reverse proxy does not pass WebSocket headers, which the CLI uses by default.

Fix, step by step

  1. Add Upgrade and Connection headers in nginx.
  2. Or run the CLI with -http instead of the default WebSocket mode.

Cleanup

  1. Delete copy jobs

    jcli delete-job hello-pipeline-copy && jcli delete-job hello-api-copy
    

    What it does: Removes the test copies.

    Output

    (no output)
    
  2. Revoke the token when done

    Your name > Security > API Token > Revoke
    

    What it does: Old tokens should not live forever.

    Output

    Token revoked
    

Ravindra Bagale's Tip

Token file madhe theva, command madhe nako. Bot user la kami adhikar dya. Lakshat theva!

Practice tasks

Easy Run five CLI commands

Why: Muscle memory helps in outages.

What to do: Run who-am-i, version, list-jobs, build, console.

How:
  1. Use the jcli alias.

Check: Five outputs saved.

Medium Copy a job to a second Jenkins

Why: Migrations use this.

What to do: get-job from one Jenkins, create-job on another.

How:
  1. Use two -s URLs.

Check: The job appears on the second Jenkins.

Hard Python API client

Why: Many tools are written in Python.

What to do: Use the python-jenkins library to list jobs and start a build.

How:
  1. pip install python-jenkins.
  2. Read the token from the file.

Check: The script prints job names and a build number.

Easy Say Jenkins CLI and API in two lines

Why: If you can say it simply, you understand it. Juniors and interviewers want the short version first.

What to do: Write two short lines about Jenkins CLI and API for a fresher who knows only Linux basics.

How:
  1. Write what problem it solves.
  2. Write the one command or menu you use for it.
  3. Read it aloud to a friend.

Check: A fresher understands it without asking a question.

Easy Start a fresh lab Jenkins

Why: Practice needs a throwaway Jenkins. If you break it, you delete it and start again.

What to do: Run Jenkins LTS in Docker with a named volume.

How:
  1. docker volume create jenkins_home
  2. docker run -d --name jenkins -p 8080:8080 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk17
  3. docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Check: The Jenkins unlock page opens on localhost:8080.

Medium Break it on purpose

Why: You must know the red message by face. During an outage there is no time to read slowly.

What to do: Cause one error from the "When it is red" part of this lesson and fix it.

How:
  1. Follow the error section.
  2. Copy the exact message into your notes.
  3. Write the fix in one line.

Check: You fixed it using only the steps, without searching the web.

Medium Write a one-page runbook

Why: At 2 a.m. nobody remembers where a file lives. A short page saves the on-call person.

What to do: Write a runbook page for this lesson.

How:
  1. Title, when to use, exact command, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Repeat it on a cloud VM

Why: A laptop is not a server. Real Jenkins runs on EC2 or a company VM.

What to do: Do the main steps of this lesson again on a small Ubuntu 22.04 EC2 instance.

How:
  1. Launch t3.small with 20 GB disk.
  2. Open port 22 only to your IP.
  3. Repeat the steps and compare the output.

Check: Same green output on the VM as on your laptop.

Hard Explain it like an interview

Why: Interviewers want real stories, not definitions.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command you ran, and one error you hit.

Check: Your answer has a real command and a real error message.

Hard Draw the flow top to bottom

Why: A drawing shows who talks to whom and in what order.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at the developer push, go through the controller and agent, end at the result.

Check: Each box matches a real thing you saw on screen.

Homework: try at home

Try at home

At home, create a bot user ci-bot with only Read and Build rights. Make a token for it, save it in ~/.jenkins-bot-auth, and run release-friday.sh with that file. Check that ci-bot cannot delete a job.

Recap

  • Use jenkins-cli.jar from your own controller, or curl with the REST API.
  • Log in with an API token kept in a private file, never a password on the command line.
  • build -s -v waits and shows the log; buildWithParameters does it over HTTP.
  • get-job and create-job copy jobs.
  • Use a bot user with least rights for scripts.

FAQ

CLI or REST API?

Both are fine. CLI is short for humans; REST is easy from any language.

Can I script Jenkins with Python?

Yes, with requests or the python-jenkins library.

Is the old remoting CLI mode safe?

No. It was removed. Modern CLI uses WebSocket or HTTP.

Where do I find all API URLs?

Click the REST API link at the bottom of any Jenkins page.

Does the token expire?

Not by default. Revoke unused tokens, and use one token per tool.

Interview questions

  1. How do you trigger Jenkins jobs remotely?

    With the REST API (POST to /job/NAME/build or buildWithParameters) using a user API token, or with jenkins-cli.jar build.

  2. How do you copy a job between Jenkins servers?

    jenkins-cli get-job to save config.xml, then create-job on the other server. Better: keep jobs as Jenkinsfiles or Job DSL in Git.

  3. Why do you get a 403 crumb error?

    CSRF protection blocks POSTs with password auth and no crumb. Use an API token.

  4. How do you read a build result from a script?

    GET /job/NAME/lastBuild/api/json?tree=result,number.

  5. How do you keep CLI credentials safe?

    Store user:token in a file readable only by you and use -auth @file. Never paste tokens in commands or Git.

Quick quiz

Q1. Where do you download jenkins-cli.jar?

From your own Jenkins at /jnlpJars/jenkins-cli.jar.

Q2. Why use an API token instead of a password?

It can be revoked alone, is per tool, and needs no crumb.

Q3. How do you get JSON for a page?

Add /api/json to the URL.

Q4. Which CLI flags wait and show the log?

-s and -v.

Q5. How do you copy a job?

get-job to XML, then create-job from that XML.

Lab

  1. Find JENKINS_HOME on your install and list jobs/ without opening secrets/.
  2. Confirm controller vs agent: who runs npm?
  3. Start one badge build from the UI, then once from CLI with a token file outside Git.

Practice task

Name six words: controller, agent, executor, job, build, artifact — one sentence each with a badge example.

Ravindra Bagale's Tip

Controller UI thevto; agent kam karto. secrets/ Git madhe nako. Dhyan rakho!

In short

  • Jenkins schedules CI for the badge; Git stays the source.
  • Controller vs agent vs executor.
  • JENKINS_HOME holds state; secrets stay out of Git.
  • One install path; Nginx + firewall for HTTPS labs.
  • CLI builds with auth file, not pasted tokens.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards