From c6f31bfb56b866f05c7def172af96753136a35cf Mon Sep 17 00:00:00 2001 From: res0nance Date: Sat, 2 Sep 2023 22:15:38 +0800 Subject: [PATCH] JENKINS-71554: Reconnect on "RequestExpired" exception --- .../java/hudson/plugins/ec2/EC2Cloud.java | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index f20644f0e..95a04b4a6 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -19,6 +19,7 @@ package hudson.plugins.ec2; import com.amazonaws.AmazonClientException; +import com.amazonaws.AmazonServiceException; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; @@ -694,7 +695,7 @@ private int getPossibleNewSlavesCount(SlaveTemplate template) throws AmazonClien * Obtains a agent whose AMI matches the AMI of the given template, and that also has requiredLabel (if requiredLabel is non-null) * forceCreateNew specifies that the creation of a new agent is required. Otherwise, an existing matching agent may be re-used */ - private List getNewOrExistingAvailableSlave(SlaveTemplate t, int number, boolean forceCreateNew) { + private List getNewOrExistingAvailableSlave(SlaveTemplate t, int number, boolean forceCreateNew) throws IOException { try { slaveCountingLock.lock(); int possibleSlavesCount = getPossibleNewSlavesCount(t); @@ -703,24 +704,19 @@ private List getNewOrExistingAvailableSlave(SlaveTemplate t, i return null; } - try { - EnumSet provisionOptions; - if (forceCreateNew) - provisionOptions = EnumSet.of(SlaveTemplate.ProvisionOptions.FORCE_CREATE); - else - provisionOptions = EnumSet.of(SlaveTemplate.ProvisionOptions.ALLOW_CREATE); - - if (number > possibleSlavesCount) { - LOGGER.log(Level.INFO, String.format("%d nodes were requested for the template %s, " + - "but because of instance cap only %d can be provisioned", number, t, possibleSlavesCount)); - number = possibleSlavesCount; - } + EnumSet provisionOptions; + if (forceCreateNew) + provisionOptions = EnumSet.of(SlaveTemplate.ProvisionOptions.FORCE_CREATE); + else + provisionOptions = EnumSet.of(SlaveTemplate.ProvisionOptions.ALLOW_CREATE); - return t.provision(number, provisionOptions); - } catch (IOException e) { - LOGGER.log(Level.WARNING, t + ". Exception during provisioning", e); - return null; + if (number > possibleSlavesCount) { + LOGGER.log(Level.INFO, String.format("%d nodes were requested for the template %s, " + + "but because of instance cap only %d can be provisioned", number, t, possibleSlavesCount)); + number = possibleSlavesCount; } + + return t.provision(number, provisionOptions); } finally { slaveCountingLock.unlock(); } } @@ -761,7 +757,18 @@ public Collection provision(final Label label, int excessWorkload) LOGGER.log(Level.INFO, "{0}. Attempting provision finished, excess workload: " + excessWorkload, t); if (excessWorkload == 0) break; - } catch (AmazonClientException e) { + } catch (AmazonServiceException e) { + LOGGER.log(Level.WARNING, t + ". Exception during provisioning", e); + if (e.getErrorCode().equals("RequestExpired")) { + // JENKINS-71554: A RequestExpired error can indicate that credentials have expired so reconnect + LOGGER.log(Level.INFO, "[JENKINS-71554] Reconnecting to EC2 due to RequestExpired error"); + try { + reconnectToEc2(); + } catch (IOException e2) { + LOGGER.log(Level.WARNING, "Failed to reconnect ec2", e2); + } + } + } catch (AmazonClientException | IOException e) { LOGGER.log(Level.WARNING, t + ". Exception during provisioning", e); } }