Ravindra BagaleCourses & study guides मराठी

Chapter 31: Backup, Configuration as Code and Jenkins Operations

31.8 Script Console

Why: the problem

Suppose we are admins at Infosys and 300 jobs still use an old Git URL. Changing them by hand would take days. Jenkins has a Script Console that runs Groovy code inside the controller. It is very powerful: it can read every credential and change anything. So only a few admins may use it, every script is reviewed, and we test on a copy first.

What we will build

You will run read-only Groovy scripts first, then one reviewed change on a restored copy, and do the same job safely from the CLI and from a REST call.

What: every term in plain English

  • Script Console — A page at /script that runs Groovy inside Jenkins.
  • Groovy — The scripting language Jenkins is written for. Like Java, shorter.
  • Jenkins.instance — The main Jenkins object in Groovy.
  • Read-only script — A script that only prints, never changes.
  • Dry run — Print what would change, change nothing.
  • Overall/Administer — The permission needed for the Script Console.
Open on the test copy only Count jobs (read-only) List offline agents (read-only) Dry run the URL change Run for real on the copy Check a changed job Run reviewed script on production via REST
Script Console: read-only, dry run, copy, review, then production

How: step by step

  1. Open on the test copy only

    http://localhost:8081/script
    

    What it does: Practise on the restored copy from 31.2.

    Output

    (Script Console page)
    
  2. Count jobs (read-only)

    println Jenkins.instance.getAllItems(hudson.model.Job).size()
    

    What it does: Safe warm-up.

    Output

    214
    
  3. List offline agents (read-only)

    Jenkins.instance.computers.findAll{ it.offline }.each{ println it.name }
    

    What it does: Useful in incidents.

    Output

    agent2
    
  4. Dry run the URL change

    see Example 1 with DRY_RUN = true
    

    What it does: Shows which jobs would change.

    Output

    would change: badge-api
    would change: orders-api
    2 jobs
    
  5. Run for real on the copy

    set DRY_RUN = false and run again
    

    What it does: Changes only the copy.

    Output

    changed: badge-api
    changed: orders-api
    2 jobs
    
  6. Check a changed job

    curl -s -u ravi:$JENKINS_TOKEN localhost:8081/job/orders-api/config.xml | grep -o "https://git.shipit.internal/[a-z-]*.git"
    

    What it does: Proves the new URL.

    Output

    https://git.shipit.internal/orders-api.git
    
  7. Run reviewed script on production via REST

    curl -s -u ravi:$JENKINS_TOKEN --data-urlencode "script@migrate-git-url.groovy" localhost:8080/scriptText
    

    What it does: Same reviewed file, logged in the change ticket.

    Output

    changed: badge-api
    changed: orders-api
    2 jobs
    

Example 1: Groovy: change an old Git URL in all freestyle jobs, with a dry-run switch

Stack. Jenkins Script Console, Groovy, Git plugin

Goal. Groovy: change an old Git URL in all freestyle jobs, with a dry-run switch.

migrate-git-url.groovy

// migrate-git-url.groovy - reviewed in change ticket CHG-1042
import hudson.plugins.git.*
def OLD = "git.oldhost.internal"; def NEW = "git.shipit.internal"
def DRY_RUN = true
int n = 0
Jenkins.instance.getAllItems(hudson.model.FreeStyleProject).each { job ->
  def scm = job.scm
  if (scm instanceof GitSCM && scm.userRemoteConfigs.any { it.url.contains(OLD) }) {
    n++
    if (DRY_RUN) { println "would change: ${job.fullName}"; return }
    def remotes = scm.userRemoteConfigs.collect {
      new UserRemoteConfig(it.url.replace(OLD, NEW), it.name, it.refspec, it.credentialsId) }
    job.scm = new GitSCM(remotes, scm.branches, scm.browser, scm.gitTool, scm.extensions)
    job.save()
    println "changed: ${job.fullName}"
  }
}
println "${n} jobs"

What each line does

  • DRY_RUN = true — First run only prints.
  • getAllItems(FreeStyleProject) — Every freestyle job, in folders too.
  • it.url.contains(OLD) — Only jobs that use the old host.
  • job.save() — Writes config.xml. Only when DRY_RUN is false.

Green output

would change: badge-api
would change: orders-api
2 jobs

Expected result. A safe, reviewed bulk change with a preview.

Example 2: Read-only health script: disk, queue and offline agents in one print

Stack. Groovy

Goal. Read-only health script: disk, queue and offline agents in one print.

health.groovy

// health.groovy - read only, safe to run in an incident
def j = Jenkins.instance
println "queue: ${j.queue.items.size()}"
println "offline: ${j.computers.findAll{ it.offline }*.name}"
def root = j.rootDir
println "free disk GB: ${(root.usableSpace / 1e9).round(1)}"
println "builds running: ${j.computers.sum{ it.countBusy() }}"

What each line does

  • queue.items.size() — How many builds wait.
  • computers.findAll offline — Which agents are down.
  • rootDir.usableSpace — Free space on JENKINS_HOME.

Green output

queue: 3
offline: [agent2]
free disk GB: 41.7
builds running: 5

Expected result. A quick incident snapshot without changing anything.

Example 3: CLI groovy: run the reviewed file from a terminal so it is saved in shell logs and the ticket

Stack. Java 17, jenkins-cli.jar

Goal. CLI groovy: run the reviewed file from a terminal so it is saved in shell logs and the ticket.

commands

cat health.groovy | java -jar jenkins-cli.jar -s http://localhost:8081/ -auth ravi:$JENKINS_TOKEN groovy =
cat migrate-git-url.groovy | java -jar jenkins-cli.jar -s http://localhost:8081/ -auth ravi:$JENKINS_TOKEN groovy =

What each line does

  • groovy = — Read the script from standard input.
  • -s http://localhost:8081/ — The test copy first.

Green output

queue: 0
offline: []
free disk GB: 18.2
builds running: 0
would change: badge-api
would change: orders-api
2 jobs

Expected result. Same scripts, from a terminal, on the copy first.

Example 4: Python: run a reviewed read-only script through /scriptText from a release tool, and save the output for the ticket

Stack. Python 3.12, requests

Goal. Python: run a reviewed read-only script through /scriptText from a release tool, and save the output for the ticket.

run_groovy.py

# run_groovy.py SCRIPT.groovy [URL] - send a reviewed Groovy file to /scriptText
import os, sys, datetime, requests
script = open(sys.argv[1]).read()
url = sys.argv[2] if len(sys.argv) > 2 else "http://localhost:8081"   # copy by default
auth = ("ravi", os.environ["JENKINS_TOKEN"])
if "DRY_RUN = false" in script and "8081" not in url:
    sys.exit("refusing: live change on production needs the change ticket approval flag")
r = requests.post(f"{url}/scriptText", data={"script": script}, auth=auth, timeout=60)
r.raise_for_status()
stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M")
out = f"script-run-{stamp}.txt"
open(out, "w").write(r.text)
print(r.text.strip()); print("saved", out)

What each line does

  • url default 8081 — The test copy is the default target.
  • refusing: live change — A guard: a real change on production is blocked by the script.
  • requests.post(.../scriptText) — Runs the Groovy and returns what it printed.
  • script-run-STAMP.txt — Output saved to attach to the change ticket.

Green output

$ python3 run_groovy.py health.groovy
queue: 0
offline: []
free disk GB: 18.2
builds running: 0
saved script-run-20261025-0245.txt

Expected result. The output is saved as proof, and live changes need an explicit approval step.

Verify: did it work?

  1. Check who can use the console

    curl -s -u ravi:$JENKINS_TOKEN localhost:8080/manage/configureSecurity/ -o /dev/null -w "%{http_code}\n"
    

    What it does: Only admins get 200 here.

    Output

    200
    
  2. Check audit

    grep -i "script" /var/lib/jenkins/logs/audit.log | tail -1
    

    What it does: With the Audit Trail plugin, console runs are logged.

    Output

    2026-10-25 02:40 ravi /scriptText
    
  3. Check jobs still build

    curl -s -X POST -u ravi:$JENKINS_TOKEN localhost:8080/job/orders-api/build -w "%{http_code}\n"
    

    What it does: A real build after the change.

    Output

    201
    

When it is red 1

groovy.lang.MissingPropertyException: No such property: GitSCM for class: Script1

Cause. The import is missing.

Fix, step by step

  1. Add import hudson.plugins.git.*.
  2. Run the dry run again.

When it is red 2

java.lang.NullPointerException: Cannot invoke method contains() on null object

Cause. A job has no URL set.

Fix, step by step

  1. Add a null check: it.url?.contains(OLD).
  2. Run the dry run again.

When it is red 3

java.lang.InterruptedException (script ran for 10 minutes and the page timed out)

Cause. A heavy loop over thousands of builds blocks the controller.

Fix, step by step

  1. Stop the request.
  2. Limit the loop to job configs, not build history.
  3. Run big scripts in a quiet window on the copy first.

When it is red 4

HTTP ERROR 403 Access Denied: ravi is missing the Overall/Administer permission

Cause. Only admins can run scripts. That is correct.

Fix, step by step

  1. Ask an admin to run the reviewed script.
  2. Do not give admin rights just for this.

Cleanup

  1. Remove the test controller

    docker rm -f jenkins-restore-test
    

    What it does: Lab only.

    Output

    jenkins-restore-test
    

Practice tasks

Easy Count jobs

Why: Safe warm-up.

What to do: Run the count script.

How:
  1. Open /script on the copy.

Check: You see a number.

Medium Write a dry run

Why: Habit of preview.

What to do: Add DRY_RUN to any change script.

How:
  1. if (DRY_RUN) println ...

Check: First run changes nothing.

Hard Add audit

Why: Know who ran what.

What to do: Install Audit Trail and check the log.

How:
  1. Add the plugin.
  2. Run a script.

Check: Log line appears.

Easy Say the Script Console in two lines

Why: If you can say it simply, you understand it.

What to do: Write two short lines about the Script Console for a fresher.

How:
  1. Write the problem.
  2. Write the command or file you use.

Check: A fresher understands it.

Easy Start a fresh lab Jenkins

Why: Practice needs a throwaway Jenkins.

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 logs jenkins | grep -A2 "initialAdminPassword"

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

Medium Do it on the second setup

Why: The idea must work on VM, Docker and Kubernetes.

What to do: Repeat this lesson on a different setup than the one you used.

How:
  1. Pick Docker if you used a VM, or kind if you used Docker.
  2. Run the same steps.

Check: Same result on the second setup.

Medium Break it on purpose

Why: You must know the red output by face.

What to do: Cause one error from "When it is red" and fix it.

How:
  1. Follow the error section.
  2. Write down the exact message.

Check: You fixed it using the steps.

Medium Write a runbook page

Why: At 2 a.m. nobody remembers.

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

How:
  1. Title, when to use, steps, how to check.

Check: A teammate can follow it alone.

Hard Explain it like an interview

Why: Interviewers want real stories.

What to do: Record a 60 second answer.

How:
  1. Problem, command, one error you hit.

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

Hard Draw the flow top to bottom

Why: A drawing shows the order.

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

How:
  1. Start at the trigger, end at the check.

Check: Each box matches a real step you ran.

Homework: try at home

Try at home

At home, write a read-only Groovy script that prints every job that has no build discarder, and run it on your lab copy.

Recap

  • The Script Console runs Groovy with full power.
  • Only admins, only reviewed scripts.
  • Read-only first, then dry run, then copy, then production.
  • Prefer CasC and Job DSL for lasting changes.
  • Log every run in a change ticket.

FAQ

Is the Script Console dangerous?

Yes. It can read all secrets and delete anything.

Should developers have access?

No.

Can I undo a script?

Only from backup. That is why you test on a copy.

Is a pipeline script the same?

No. Pipelines run in a sandbox with fewer rights.

When is it the right tool?

One-off admin tasks, incidents, bulk fixes.

Interview questions

  1. What is the Jenkins Script Console?

    An admin page that runs Groovy inside the controller with full access.

  2. How do you use it safely?

    Admin-only, reviewed scripts, dry run, test on a copy, audit.

  3. Script Console vs pipeline Groovy?

    Console is unsandboxed; pipeline Groovy runs in a sandbox.

  4. How to run a script remotely?

    POST to /scriptText or jenkins-cli groovy.

  5. Name a read-only use.

    Listing offline agents during an incident.

Quick quiz

Q1. Who may use the Script Console?

Only admins with Overall/Administer.

Q2. Why dry run first?

To see what would change.

Q3. Where do you test?

On a restored copy.

Q4. Can scripts read credentials?

Yes, which is why access is limited.

Q5. Which REST path runs a script?

/scriptText.

Lab

  1. Take a backup tarball.
  2. On a disposable lab, restore and open badge-node-pipeline.
  3. Trigger one build via CLI with auth file outside Git.

Practice task

Write the stop→tar→start backup commands and the restore chown line from memory.

Ravindra Bagale's Tip

Backup vina upgrade nako. Don controllers ek LB — HA nahi. Script Console student tool nahi. Dhyan rakho!

Thodkyaat sangaycha tar

  • Backup/restore JENKINS_HOME with a real restore test.
  • HA is not two writers behind one LB.
  • CasC keeps config in Git.
  • Upgrade test first. Monitor disk and journal.
  • CLI/REST to start jobs; Script Console admin-only.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards