jenkinsci / jenkinsci/google-compute-engine-plugin
markExhausted throws IllegalArgumentException for template-based instance configurations, breaking zone fallback
- Dominant language
- Java
- Stars
- 58
- Forks
- 97
- PR merge metrics
- No merged PRs in 30d
Description
### Jenkins and plugins versions report
- Jenkins: 2.520+ (observed on current LTS line)
- google-compute-engine: 4.815.v9a_de97053e3a_ (bug introduced with the zone-fallback feature, #555)
### What Operating System are you using (both controller, and any agents involved in the problem)?
Controller: Linux (k8s). Agents: GCE VMs, Debian 13.
### Reproduction steps
1. Configure a GCE cloud with an **instance-template-based** instance configuration (template set, machine type field left empty — the normal state for template-based configs, since `machineType` is only used when no template is set).
2. Have GCE return a capacity error on instance insert (`ZONE_RESOURCE_POOL_EXHAUSTED`, reason `stockout`).
3. The launcher detects the capacity error and calls `config.markExhausted(zone)`.
### Expected Results
The zone is marked exhausted and the next provisioning cycle uses a fallback zone (the new #555 behavior).
### Actual Results
`markExhausted` throws a bare `IllegalArgumentException` from `ClientUtil.nameFromSelfLink("")` while formatting its **log message**, because template-based configurations have an empty `machineType`:
```
java.lang.IllegalArgumentException
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:127)
at com.google.cloud.graphite.platforms.plugin.client.util.ClientUtil.nameFromSelfLink(ClientUtil.java:84)
at com.google.jenkins.plugins.computeengine.InstanceConfiguration.markExhausted(InstanceConfiguration.java:501)
at com.google.jenkins.plugins.computeengine.ComputeEngineComputerLauncher.launch(ComputeEngineComputerLauncher.java:209)
at hudson.slaves.SlaveComputer.lambda$_connect$0(SlaveComputer.java:298)
```
Jenkins surfaces it as "ERROR: Unexpected error in launching an agent. This is probably a bug in Jenkins" on the node's launch log, repeatedly (the retention strategy retries `connect()` forever).
Consequences:
- the exception propagates out of `launch()` **before** `terminateNode()` runs, so the dead node object is never cleaned up and the retention strategy relaunches it in a loop;
- the zone is never marked exhausted, so the fallback-zone feature never engages and the provisioner keeps hammering the stocked-out zone.
We hit this in production during a real c3d/c4d stockout in us-central1-a; every template-based config crashed the same way.
### Anything else?
Workaround we used: populate the (otherwise unused) machine type field on template-based configurations — `instance()` only reads `machineType` in the no-template branch, so this is safe and stops the crash. After that, the #555 fallback logic worked exactly as designed under a subsequent real stockout.
### Are you interested in contributing a fix?
Yes — PR incoming (guard the log message for empty `machineType`, fall back to the template name, plus a regression test).
Contributor guide
Research direction
Start in InstanceConfiguration.markExhausted and trace the call from ComputeEngineComputerLauncher.launch, focusing on the ClientUtil.nameFromSelfLink usage shown in the stack trace. Add or run the regression test for an instance-template configuration with an empty machine type and verify that exhaustion marking, fallback-zone provisioning, and node cleanup proceed without the exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- google-cloud, java
- Domain
- cloud
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100