Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/doc/examples/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ If you have a question, please open a [GitHub issue](https://github.com/jenkinsc
- [Lock specific stages](lock-specific-stages.md)
- [Locking multiple stages in declarative pipeline](locking-multiple-stages-in-declarative-pipeline.md)
- [Locking a random free resource](locking-random-free-resource.md)
- [Resource properties](resource-properties.md)
- [Scripted vs declarative pipeline](scripted-vs-declarative-pipeline.md)
- [Timeout inside lock](timeout-inside-lock.md)
- [Dynamic resource pool expansion](dynamic-resource-pool-expansion.md)
110 changes: 110 additions & 0 deletions src/doc/examples/resource-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Resource Properties

Resources can have custom **properties** (name:value pairs) that are exposed
as environment variables when the resource is locked.

## Defining properties

Properties can be added to a resource via:

- **Web UI** — Manage Jenkins → Lockable Resources → edit a resource → add properties
- **JCasC** (Jenkins Configuration as Code):

```yaml
unclassified:
lockableResourcesManager:
resources:
- name: "staging-server"
properties:
- name: "HOST"
value: "192.168.1.10"
- name: "PORT"
value: "8080"
```

## Accessing properties in a pipeline

Properties are exposed as environment variables **only when the `variable`
parameter is specified** in the `lock()` step.

### Naming pattern

| Variable | Value |
|----------|-------|
| `{variable}` | Comma-separated list of all locked resource names |
| `{variable}0` | Name of the first locked resource |
| `{variable}0_{PROPERTY_NAME}` | Value of that resource's property |
| `{variable}1` | Name of the second locked resource (if any) |
| `{variable}1_{PROPERTY_NAME}` | Value of the second resource's property |

### Example: Read properties after locking by name

```groovy
pipeline {
agent any
stages {
stage('Deploy') {
options {
lock(resource: 'staging-server', variable: 'LOCKED')
}
steps {
echo "Resource: ${env.LOCKED0}" // staging-server
echo "Host: ${env.LOCKED0_HOST}" // 192.168.1.10
echo "Port: ${env.LOCKED0_PORT}" // 8080
}
}
}
}
```

### Example: Lock by label and read properties

```groovy
pipeline {
agent any
stages {
stage('Test') {
options {
lock(label: 'gpu', quantity: 1, variable: 'GPU')
}
steps {
echo "Got: ${env.GPU0}"
echo "GPU model: ${env.GPU0_MODEL}"
}
}
}
}
```

## Filtering resources by properties

Use a `resourceMatchScript` to lock only resources whose properties match
specific criteria:

```groovy
lock(extra: [
[$class: 'LockableResourcesStruct',
resourceMatchScript: [
$class: 'SecureGroovyScript',
script: '''
resourceInstance.properties.any {
it.name == "ENV" && it.value == "staging"
}
''',
sandbox: true
],
resourceNumber: '1'
]
]) {
echo "Got a staging resource: ${env.LOCKED_RESOURCE0}"
}
```

## Common pitfalls

1. **Missing `variable` parameter** — without it, no environment variables are
created. This is the most common reason properties appear to be `null`.
2. **Property name is case-sensitive** — if the property is named `host`, the
env var is `LOCKED0_host`, not `LOCKED0_HOST`.
3. **Properties are only available inside the lock block** — they cannot be
accessed after the lock is released.
76 changes: 76 additions & 0 deletions src/doc/examples/timeout-inside-lock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Timeout Inside Lock

When a pipeline uses both `timeout` and `lock`, the placement of `timeout`
determines whether queue wait time counts against the deadline.

## Problem

If `timeout` wraps the entire pipeline or stage, the clock starts before the
lock is acquired. A job that waits a long time in the queue may time out
before it gets a chance to run:

```groovy
pipeline {
agent any
options {
// Clock starts immediately — includes queue wait time!
timeout(time: 5, unit: 'HOURS')
}
stages {
stage('Deploy') {
steps {
lock('my-resource') {
echo 'Deploying...'
}
}
}
}
}
```

## Solution

Place `timeout` **inside** `lock` so the countdown begins only after the
resource has been acquired:

```groovy
pipeline {
agent any
stages {
stage('Deploy') {
steps {
lock('my-resource') {
timeout(time: 5, unit: 'HOURS') {
echo 'Deploying...'
}
}
}
}
}
}
```

This way a job can wait in the queue as long as necessary without the
timeout expiring prematurely.

## Stage-level variant

The same pattern works with `options` at the stage level:

```groovy
pipeline {
agent any
stages {
stage('Deploy') {
options {
lock('my-resource')
}
steps {
timeout(time: 5, unit: 'HOURS') {
echo 'Deploying...'
}
}
}
}
}
```
Loading