diff --git a/pom.xml b/pom.xml index 7e3390dd7..ad7f305a1 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,29 @@ THE SOFTWARE. HEAD + + 1.6.2 + + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + + + junit + junit + 4.12 + test + bouncycastle diff --git a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java index 4ef900ac5..67c62bbf2 100644 --- a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java +++ b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java @@ -42,6 +42,7 @@ import java.io.PrintStream; import java.net.URL; import java.util.*; +import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletException; @@ -421,18 +422,7 @@ private EC2AbstractSlave provisionOndemand(TaskListener listener) throws AmazonC /* Now that we have our instance, we can set tags on it */ if (inst_tags != null) { - for (int i = 0; i < 5; i++) { - try { - updateRemoteTags(ec2, inst_tags, inst.getInstanceId()); - break; - } catch (AmazonServiceException e) { - if (e.getErrorCode().equals("InvalidInstanceRequestID.NotFound")) { - Thread.sleep(5000); - continue; - } - throw e; - } - } + updateRemoteTags(ec2, inst_tags, "InvalidInstanceID.NotFound", inst.getInstanceId()); // That was a remote request - we should also update our local instance data. inst.setTags(inst_tags); @@ -676,18 +666,7 @@ private EC2AbstractSlave provisionSpot(TaskListener listener) throws AmazonClien /* Now that we have our Spot request, we can set tags on it */ if (inst_tags != null) { - for (int i = 0; i < 5; i++) { - try { - updateRemoteTags(ec2, inst_tags, spotInstReq.getSpotInstanceRequestId()); - break; - } catch (AmazonServiceException e) { - if (e.getErrorCode().equals("InvalidSpotInstanceRequestID.NotFound")) { - Thread.sleep(5000); - continue; - } - throw e; - } - } + updateRemoteTags(ec2, inst_tags, "InvalidSpotInstanceRequestID.NotFound", spotInstReq.getSpotInstanceRequestId()); // That was a remote request - we should also update our local instance data. spotInstReq.setTags(inst_tags); @@ -724,12 +703,29 @@ private KeyPair getKeyPair(AmazonEC2 ec2) throws IOException, AmazonClientExcept } /** - * Update the tags stored in EC2 with the specified information + * Update the tags stored in EC2 with the specified information. + * Re-try 5 times if instances isn't up by catchErrorCode - e.g. InvalidSpotInstanceRequestID.NotFound or InvalidInstanceRequestID.NotFound + * @param ec2 + * @param inst_tags + * @param catchErrorCode + * @param params + * @throws InterruptedException */ - private void updateRemoteTags(AmazonEC2 ec2, Collection inst_tags, String... params) { - CreateTagsRequest tag_request = new CreateTagsRequest(); - tag_request.withResources(params).setTags(inst_tags); - ec2.createTags(tag_request); + private void updateRemoteTags(AmazonEC2 ec2, Collection inst_tags, String catchErrorCode, String... params) throws InterruptedException { + for (int i = 0; i < 5; i++) { + try { + CreateTagsRequest tag_request = new CreateTagsRequest(); + tag_request.withResources(params).setTags(inst_tags); + ec2.createTags(tag_request); + break; + } catch (AmazonServiceException e) { + if (e.getErrorCode().equals(catchErrorCode)) { + Thread.sleep(5000); + continue; + } + LOGGER.log(Level.SEVERE, e.getErrorMessage(), e); + } + } } /** diff --git a/src/test/java/hudson/plugins/ec2/SlaveTemplateUnitTest.java b/src/test/java/hudson/plugins/ec2/SlaveTemplateUnitTest.java new file mode 100644 index 000000000..3ce5f9476 --- /dev/null +++ b/src/test/java/hudson/plugins/ec2/SlaveTemplateUnitTest.java @@ -0,0 +1,146 @@ +package hudson.plugins.ec2; + +import com.amazonaws.AmazonServiceException; +import com.amazonaws.services.ec2.AmazonEC2; +import com.amazonaws.services.ec2.AmazonEC2Client; +import com.amazonaws.services.ec2.model.InstanceType; +import com.amazonaws.services.ec2.model.Tag; +import hudson.model.Node; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class SlaveTemplateUnitTest { + + Logger logger; + TestHandler handler; + + @Before + public void setUp() throws Exception { + AmazonEC2Cloud.testMode = true; + + handler = new TestHandler(); + logger = Logger.getLogger(SlaveTemplate.class.getName()); + logger.addHandler(handler); + } + + @After + public void tearDown() throws Exception { + AmazonEC2Cloud.testMode = false; + } + + @Test + public void testUpdateRemoteTags() throws Exception { + AmazonEC2 ec2 = new AmazonEC2Client() { + @Override + public void createTags(com.amazonaws.services.ec2.model.CreateTagsRequest createTagsRequest) { + + } + }; + + String ami = "ami1"; + String description = "foo ami"; + + EC2Tag tag1 = new EC2Tag("name1", "value1"); + EC2Tag tag2 = new EC2Tag("name2", "value2"); + List tags = new ArrayList(); + tags.add(tag1); + tags.add(tag2); + String instanceId = "123"; + + SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", tags, null, false, null, "", true, false, "", false, "") { + @Override + protected Object readResolve() { + return null; + } + }; + + ArrayList awsTags = new ArrayList(); + awsTags.add(new Tag(EC2Tag.TAG_NAME_JENKINS_SLAVE_TYPE, "value1")); + awsTags.add(new Tag(EC2Tag.TAG_NAME_JENKINS_SLAVE_TYPE, "value2")); + + final Object params[] = {ec2, awsTags, "InvalidInstanceRequestID.NotFound", instanceId}; + Whitebox.invokeMethod(orig, "updateRemoteTags", params); + assertEquals(0, handler.getRecords().size()); + } + + @Test + public void testUpdateRemoteTagsInstanceNotFound() throws Exception { + AmazonEC2 ec2 = new AmazonEC2Client() { + @Override + public void createTags(com.amazonaws.services.ec2.model.CreateTagsRequest createTagsRequest) { + AmazonServiceException e = new AmazonServiceException("Instance not found - InvalidInstanceRequestID.NotFound"); + e.setErrorCode("InvalidInstanceRequestID.NotFound"); + throw e; + } + }; + + String ami = "ami1"; + String description = "foo ami"; + + EC2Tag tag1 = new EC2Tag("name1", "value1"); + EC2Tag tag2 = new EC2Tag("name2", "value2"); + List tags = new ArrayList(); + tags.add(tag1); + tags.add(tag2); + String instanceId = "123"; + + SlaveTemplate orig = new SlaveTemplate(ami, EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, "ttt", Node.Mode.NORMAL, description, "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", tags, null, false, null, "", true, false, "", false, "") { + @Override + protected Object readResolve() { + return null; + } + }; + + ArrayList awsTags = new ArrayList(); + awsTags.add(new Tag(EC2Tag.TAG_NAME_JENKINS_SLAVE_TYPE, "value1")); + awsTags.add(new Tag(EC2Tag.TAG_NAME_JENKINS_SLAVE_TYPE, "value2")); + + final Object params[] = {ec2, awsTags, "InvalidSpotInstanceRequestID.NotFound", instanceId}; + Whitebox.invokeMethod(orig, "updateRemoteTags", params); + + assertEquals(5, handler.getRecords().size()); + + Iterator logs = handler.getRecords().iterator(); + while (logs.hasNext()) { + String log = logs.next().getMessage(); + assertTrue(log.contains("Instance not found - InvalidInstanceRequestID.NotFound")); + } + + } +} + +class TestHandler extends Handler { + private List records = new LinkedList(); + + @Override + public void close() throws SecurityException { + } + + @Override + public void flush() { + } + + @Override + public void publish(LogRecord record) { + records.add(record); + } + + public List getRecords() { + return records; + } +} +