Job DSL, Seed Jobs, Folder Hierarchies, Programmatic Job Creation, and Jenkins API Automation: Concepts, Architecture, and Mental Model
Job DSL turns a reviewed desired-state description into Jenkins items, but the generator itself is privileged automation. Learn to separate the versioned DSL source, seed-job identity, sandbox/approval state, generated-item ownership, folder boundaries and removal policy before allowing a seed build to mutate controller item configuration.
Learning objectives
- Explain Job DSL, seed jobs and generated-item ownership without confusing them with Pipeline DSL.
- Trace versioned DSL source through a seed build into persisted folders/jobs.
- Separate seed identity, Script Security, folder permissions and generated-item lifecycle.
- Inspect current state before allowing generator mutations.
- Define auditable idempotency and recovery evidence for generated jobs.
1. The practical problem: hundreds of UI-created jobs do not scale
Creating one Jenkins job in the UI is easy. Creating the same class of job for dozens of services, keeping every option consistent, proving who changed it and rolling back a bad bulk edit is not. Job DSL solves this by treating item definitions as reviewed Groovy-based desired-state code.
The dangerous part is equally important: Job DSL is not a harmless template engine. A seed job can create, update, disable or delete persisted Jenkins items. The generator therefore belongs in the controller trust model alongside JCasC, plugins and trusted Shared Libraries.
2. Mental model: source → seed → generated state
Read this flow from left to right. The Git commit is the desired-state input. The seed job supplies execution identity, workspace and build audit. Job DSL interprets the files under sandbox/approval rules. Jenkins then persists item configuration. Later builds of generated jobs are separate runs with their own source, queue, agent and artifacts.
flowchart TD A[Versioned Job DSL source\ncommit + files] --> B[Seed job\nfull name + build + identity] B --> C[Job DSL execution\nsandbox or approved script] C --> D[Desired folders and jobs\nfull names + ownership] D --> E[Created / updated / disabled / deleted items] E --> F[Generated-job builds\nqueue + agent + workspace] F --> G[Reports / artifacts / statuses] B --> H[Seed audit evidence\nconsole + generated objects + API] E --> H
The arrows matter. A green generated application build does not prove the seed source was safe. A green seed build does not prove every generated job later runs correctly. Persisted item configuration and build runtime are different states.
3. Terminology before commands
| Term | Meaning | State to record |
|---|---|---|
| Job DSL | Groovy-based domain-specific language that creates/updates Jenkins items. | plugin version, DSL files, source commit |
| Seed job | A Jenkins job/Pipeline that executes the Job DSL step. | full name, build number/URL, cause, run identity |
| Generated item | Folder/job/view/config produced and tracked by the Job DSL run. | full name, config digest, lifecycle action |
| Sandbox | Script Security mode that restricts Groovy operations to approved signatures. | sandbox flag, rejected/approved signatures |
| Lookup strategy | How relative item names are resolved: Jenkins root or seed-job folder. | JENKINS_ROOT or SEED_JOB |
| Removed-item action | Policy for items previously generated but no longer described. | IGNORE / DISABLE / DELETE |
| Ownership marker | Human-readable metadata such as a description/tag plus plugin-generated tracking. | seed name, team, source path; not an ACL |
4. State boundaries you must keep separate
Job DSL, Folders, Script Security, authorization plugins,
JENKINS_HOME and persisted config.xml files.
Seed configuration, build number, exact SCM commit, workspace and console/generated-object action.
Folders/jobs/views, full names, descriptions, disabled state and ownership.
Queue, executor, agent, workspace, Pipeline CPS and artifacts of generated jobs.
Seed run-as identity, folder ACL, sandbox/approval and source-review boundary.
Git revert, controller snapshot/backup and retained job histories before destructive lifecycle actions.
5. Read-only inspection before mutation
On the disposable controller, inspect rather than configure first. Record the values in a small evidence file:
# Controller/runtime evidence
curl -fsSI "$JENKINS_URL/login" | grep -i '^X-Jenkins:' || true
java -version
# Plugin versions through the authenticated API (token stored outside shell history)
curl -fsS --user "$JENKINS_USER:$JENKINS_API_TOKEN" \
"$JENKINS_URL/pluginManager/api/json?depth=1" > evidence/plugins.json
# Existing items only; no POST and no mutation
curl -fsS --user "$JENKINS_USER:$JENKINS_API_TOKEN" \
"$JENKINS_URL/api/json?tree=jobs[fullName,_class,color]" > evidence/items-before.json
Use an API token through a protected environment/file binding; never put a real token in lesson files or command history. API-token-authenticated POSTs are exempt from crumb requirements, while username/password scripted clients generally need the crumb/session flow.
6. Seed identity is part of the desired-state contract
A seed should not run with more authority than needed. In a strong design, the seed’s build identity can configure/create items in its platform/team folder and cannot administer the controller or mutate unrelated folders. When sandboxed Job DSL performs Jenkins access checks, a deliberate build identity is especially important; Authorize Project is one current mechanism for that.
Folder-relative generation helps but does not replace authorization.
lookupStrategy: 'SEED_JOB' makes relative names resolve
beneath the seed’s folder. Pair that with folder permissions and a
test that an out-of-scope write is denied.
7. Job DSL is not Pipeline DSL
// Job DSL: creates a Pipeline job
pipelineJob('apps/api-ci') {
description('[managed-by=job-dsl][owner=platform-lab]')
definition {
cpsScm {
scm {
git { remote { url('file:///workspace/app-repo.git') } }
}
scriptPath('Jenkinsfile')
}
}
}
// Pipeline DSL: executed later *by* the generated job
pipeline {
agent { label 'linux-ci' }
stages {
stage('Test') { steps { sh './test.sh' } }
}
}
The first script mutates Jenkins item configuration. The second governs one build’s runtime. Mixing them produces confusing syntax and trust failures.
8. Removed items: lifecycle, not garbage collection
| Action | Effect | Use |
|---|---|---|
IGNORE |
Previously generated item remains unchanged. | Safest while ownership is uncertain. |
DISABLE |
Job stays with history/config but cannot run normally. | Recommended intermediate state for controlled retirement. |
DELETE |
Generated item is removed. | Only after explicit ownership, retention and recovery checks. |
When multiple Job DSL steps run in one seed build, apply DISABLE/DELETE removed-item actions only on the last relevant Job DSL step; otherwise an item can be disabled/deleted before a later step recreates it.
9. DevOps connection: generator evidence makes automation reproducible
A useful generated job has a chain you can reconstruct: DSL repository commit → seed full name/build/cause → sandbox/identity → generated item full name/config → later build source/queue/agent → reports/artifacts. If any link is implicit, debugging and governance become guesswork.
10. Common wrong approaches
- Give every developer permission to edit an admin-equivalent seed.
- Run arbitrary unsandboxed Groovy because “the source is in Git.”
- Use names with timestamps/random suffixes and call repeated generation idempotent.
- Delete jobs that merely happen to share a naming prefix.
- Use Job DSL to replace JCasC global configuration or Pipeline runtime logic.
- Treat a 200 API response as proof a queued/generated job completed successfully.
Knowledge check
Answer before revealing the explanation.
1. What problem does Job DSL solve that a Jenkinsfile does not?
A Jenkinsfile describes the execution of one Pipeline build. Job DSL programmatically creates or updates Jenkins items such as folders, freestyle jobs, Pipeline jobs and multibranch jobs. It is configuration-generation code, not the runtime Pipeline definition itself.
2. Why is a seed job a security boundary?
The seed can create or reconfigure persisted Jenkins items. Its build identity, script trust mode and permissions therefore determine what the generator can change. Treat it like platform administration automation, not an ordinary application build.
3. What does lookupStrategy SEED_JOB change?
Relative item names are resolved beneath the folder containing the seed job instead of from Jenkins root. That supports folder-scoped generation and reduces accidental cross-team writes, but authorization still needs to enforce the boundary.
4. Why is removedJobAction not just cleanup convenience?
IGNORE, DISABLE and DELETE have different retention and recovery consequences. DELETE can remove history and configuration, so it should only be used when ownership is proven, evidence is retained and rollback is defined.
5. What is the difference between a generated-item marker and an authorization control?
A description tag such as managed-by=job-dsl helps humans and audits identify ownership, but it does not prevent mutation. Actual authorization comes from Jenkins permissions, folder inheritance, seed identity and Script Security.
Official references and version notes
- Job DSL plugin — current release, minimum core requirement, maintenance/security status and links to the API Viewer.
-
Jenkins Pipeline Steps — Job DSL
— current
jobDslparameters including sandbox, lookup strategy and removed-item actions. - Job DSL upstream repository — getting started, Job DSL versus Pipeline DSL, and API Viewer guidance.
- Job DSL — Script Security — sandbox/approval behavior and build-identity implications.
- Script Security plugin — Groovy sandbox and signature-approval boundary.
- Folders plugin — folder hierarchy baseline used by the examples.
- Matrix Authorization Strategy — optional fine-grained folder/item permission model for the lab.
- Authorize Project plugin — optional explicit build identity used when exercising sandboxed Job DSL with access-control checks.
- Jenkins Remote Access API and CSRF protection — current API authentication/POST semantics.
- Jenkins LTS changelog and Java support policy.
2.568.3 LTS with Java 21 (Jenkins
2.568.3 is tested with Java 21 and 25). Job DSL is
3732.v9a_c49a_61a_313, requires Jenkins 2.479.3 and is
currently marked “up for adoption” on the plugin site. Script
Security is 1422.v06869826dd9b_; Folders is
6.1106.v3a_d9a_6d2465e; Matrix Authorization Strategy
is 3.3; Authorize Project is
534.v2f208c45e11c. Re-check current plugin/API
documentation and security advisories before reusing the lab. The
mandatory path uses only a disposable local controller, synthetic
Git repository and fake identities.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.