|
24 | 24 | package hudson.plugins.ec2;
|
25 | 25 |
|
26 | 26 | import com.amazonaws.ClientConfiguration;
|
| 27 | + |
27 | 28 | import hudson.ProxyConfiguration;
|
28 | 29 | import hudson.model.Computer;
|
29 | 30 | import hudson.model.Descriptor;
|
|
58 | 59 |
|
59 | 60 | import jenkins.model.Jenkins;
|
60 | 61 | import jenkins.slaves.iterators.api.NodeIterator;
|
| 62 | + |
| 63 | +import org.apache.commons.lang.StringUtils; |
61 | 64 | import org.kohsuke.stapler.QueryParameter;
|
62 | 65 | import org.kohsuke.stapler.StaplerRequest;
|
63 | 66 | import org.kohsuke.stapler.StaplerResponse;
|
|
76 | 79 | import com.amazonaws.services.ec2.model.KeyPairInfo;
|
77 | 80 | import com.amazonaws.services.ec2.model.Reservation;
|
78 | 81 | import com.amazonaws.services.ec2.model.SpotInstanceRequest;
|
| 82 | +import com.amazonaws.services.ec2.model.Tag; |
79 | 83 | import com.amazonaws.services.s3.AmazonS3;
|
80 | 84 | import com.amazonaws.services.s3.AmazonS3Client;
|
81 | 85 | import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
|
@@ -206,21 +210,74 @@ public synchronized KeyPair getKeyPair() throws AmazonClientException, IOExcepti
|
206 | 210 | * @param ami If AMI is left null, then all instances are counted.
|
207 | 211 | * <p>
|
208 | 212 | * This includes those instances that may be started outside Hudson.
|
| 213 | + * @param tags |
209 | 214 | */
|
210 |
| - public int countCurrentEC2Slaves(String ami) throws AmazonClientException { |
| 215 | + public int countCurrentEC2Slaves(String ami, List<EC2Tag> tags) throws AmazonClientException { |
211 | 216 | int n=0;
|
212 | 217 | for (Reservation r : connect().describeInstances().getReservations()) {
|
213 | 218 | for (Instance i : r.getInstances()) {
|
214 |
| - if (ami == null || ami.equals(i.getImageId())) { |
| 219 | + if (looksLikeEc2ProvisionedSlave(i, tags, ami)) { |
215 | 220 | InstanceStateName stateName = InstanceStateName.fromValue(i.getState().getName());
|
216 |
| - if (stateName == InstanceStateName.Pending || stateName == InstanceStateName.Running) |
| 221 | + if (stateName == InstanceStateName.Pending || stateName == InstanceStateName.Running) { |
217 | 222 | n++;
|
| 223 | + } |
218 | 224 | }
|
219 | 225 | }
|
220 | 226 | }
|
221 | 227 | return n;
|
222 | 228 | }
|
223 | 229 |
|
| 230 | + /** |
| 231 | + * This method does check if the slave might be provisionde by this plugin. It does so by |
| 232 | + * checking if the slave has the same AMI id and the tags match the tags as configured by |
| 233 | + * the plugin. If there are no tags configured, the tags are ignored. |
| 234 | + * |
| 235 | + * JENKINS-19845 |
| 236 | + * |
| 237 | + * @param i |
| 238 | + * @param tags |
| 239 | + * @param ami |
| 240 | + * @return |
| 241 | + */ |
| 242 | + private boolean looksLikeEc2ProvisionedSlave(Instance i, List<EC2Tag> tags, String ami) { |
| 243 | + // Check if the ami matches |
| 244 | + if (ami == null || StringUtils.equals(ami, i.getImageId())) { |
| 245 | + if (tags == null || tags.isEmpty()) { |
| 246 | + return true; |
| 247 | + } |
| 248 | + return equalsTags(tags, i.getTags()); |
| 249 | + } |
| 250 | + return false; |
| 251 | + } |
| 252 | + |
| 253 | + /** |
| 254 | + * Returns true if there is a tag where both the key and value are equal. |
| 255 | + * @param configuredTags |
| 256 | + * @param instanceTags |
| 257 | + * @return true if there is a tag where both the key and value are equal. |
| 258 | + */ |
| 259 | + private boolean equalsTags(List<EC2Tag> configuredTags, List<Tag> instanceTags) { |
| 260 | + for (Tag instanceTag : instanceTags) { |
| 261 | + for (EC2Tag ec2Tag : configuredTags) { |
| 262 | + if (equalsTag(instanceTag, ec2Tag)) { |
| 263 | + return true; |
| 264 | + } |
| 265 | + } |
| 266 | + } |
| 267 | + return false; |
| 268 | + } |
| 269 | + |
| 270 | + /** |
| 271 | + * Returns true if both the key and value are equal. |
| 272 | + * @param instanceTag |
| 273 | + * @param ec2Tag |
| 274 | + * @return true if both the key and value are equal |
| 275 | + */ |
| 276 | + private boolean equalsTag(Tag instanceTag, EC2Tag ec2Tag) { |
| 277 | + return StringUtils.equals(instanceTag.getKey(), ec2Tag.getName()) |
| 278 | + && StringUtils.equals(instanceTag.getValue(), ec2Tag.getValue()); |
| 279 | + } |
| 280 | + |
224 | 281 | /**
|
225 | 282 | * Debug command to attach to a running instance.
|
226 | 283 | */
|
@@ -266,10 +323,11 @@ public void doProvision(StaplerRequest req, StaplerResponse rsp, @QueryParameter
|
266 | 323 | * Check for the count of EC2 slaves and determine if a new slave can be added.
|
267 | 324 | * Takes into account both what Amazon reports as well as an internal count
|
268 | 325 | * of slaves currently being "provisioned".
|
| 326 | + * @param tags |
269 | 327 | */
|
270 |
| - private boolean addProvisionedSlave(String ami, int amiCap) throws AmazonClientException { |
271 |
| - int estimatedTotalSlaves = countCurrentEC2Slaves(null); |
272 |
| - int estimatedAmiSlaves = countCurrentEC2Slaves(ami); |
| 328 | + private boolean addProvisionedSlave(String ami, List<EC2Tag> tags, int amiCap) throws AmazonClientException { |
| 329 | + int estimatedTotalSlaves = countCurrentEC2Slaves(null, null); |
| 330 | + int estimatedAmiSlaves = countCurrentEC2Slaves(ami, tags); |
273 | 331 |
|
274 | 332 | synchronized (provisioningAmis) {
|
275 | 333 | int currentProvisioning;
|
@@ -358,7 +416,7 @@ public Collection<PlannedNode> provision(Label label, int excessWorkload) {
|
358 | 416 |
|
359 | 417 | while (excessWorkload>0) {
|
360 | 418 |
|
361 |
| - if (!addProvisionedSlave(t.ami, amiCap)) { |
| 419 | + if (!addProvisionedSlave(t.ami, t.getTags(), amiCap)) { |
362 | 420 | break;
|
363 | 421 | }
|
364 | 422 |
|
|
0 commit comments