From 2d21ff4e9f7b7d14e3bbfd91bd34ce8bfe2d0412 Mon Sep 17 00:00:00 2001 From: Antonio Busuladzich Date: Tue, 1 Oct 2024 19:55:44 +0300 Subject: [PATCH 1/3] Added support for programmatic update of a SlaveTemplate --- .../java/hudson/plugins/ec2/EC2Cloud.java | 22 ++++++++++--------- .../java/hudson/plugins/ec2/EC2CloudTest.java | 16 ++++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index fb3670180..76f8d112c 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -87,16 +87,7 @@ import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -226,6 +217,17 @@ public void addTemplate(SlaveTemplate newTemplate) throws Exception { templates = templatesHolder; } + public void updateTemplate(SlaveTemplate newTemplate, String oldTemplateDescription) throws Exception{ + Optional optionalOldTemplate = templates.stream().filter(template -> + Objects.equals(template.description, oldTemplateDescription)).findFirst(); + if (!optionalOldTemplate.isPresent()) + throw new Exception(String.format("A SlaveTemplate with description %s does not exist", oldTemplateDescription)); + int oldTemplateIndex = templates.indexOf(optionalOldTemplate.get()); + List templatesHolder = new ArrayList<>(templates); + templatesHolder.set(oldTemplateIndex, newTemplate); + templates = templatesHolder; + } + private void migratePrivateSshKeyToCredential(String privateKey) { // GET matching private key credential from Credential API if exists Optional keyCredential = SystemCredentialsProvider.getInstance().getCredentials() diff --git a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java index 1fb8de13e..6fc1765ad 100644 --- a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java @@ -19,8 +19,7 @@ import java.util.Collections; import java.util.List; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; @@ -37,6 +36,19 @@ public void testSlaveTemplateAddition() throws Exception { assertNotNull(cloud.getTemplate(orig.description)); } + @Test + public void testSlaveTemplateUpdate() throws Exception{ + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, + "abc", "us-east-1", null, "ghi", + "3", Collections.emptyList(), "roleArn", "roleSessionName"); + SlaveTemplate oldSlaveTemplate = new SlaveTemplate("ami-123", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "OldSlaveDescription", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 0, 0, null, "iamInstanceProfile", true, false, "", false, "", false, false, false, ConnectionStrategy.PUBLIC_IP, -1, null, null, Tenancy.Default, EbsEncryptRootVolume.DEFAULT); + cloud.addTemplate(oldSlaveTemplate); + SlaveTemplate newSlaveTemplate = new SlaveTemplate("ami-456", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "NewSlaveDescription", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 0, 0, null, "iamInstanceProfile", true, false, "", false, "", false, false, false, ConnectionStrategy.PUBLIC_IP, -1, null, null, Tenancy.Default, EbsEncryptRootVolume.DEFAULT); + cloud.updateTemplate(newSlaveTemplate, "OldSlaveDescription"); + assertNull(cloud.getTemplate("OldSlaveDescription")); + assertNotNull(cloud.getTemplate("NewSlaveDescription")); + } + @Test public void testReattachOrphanStoppedNodes() throws Exception { /* Mocked items */ From a89f1e873104dc6ef6edadeb384974a58dce0ea6 Mon Sep 17 00:00:00 2001 From: Antonio Busuladzich Date: Tue, 1 Oct 2024 22:46:48 +0300 Subject: [PATCH 2/3] Added assert for the template order --- src/test/java/hudson/plugins/ec2/EC2CloudTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java index 6fc1765ad..eb0461a21 100644 --- a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java @@ -6,6 +6,7 @@ import com.amazonaws.services.ec2.model.InstanceType; import hudson.model.Node; import jenkins.model.Jenkins; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockedStatic; @@ -42,11 +43,16 @@ public void testSlaveTemplateUpdate() throws Exception{ "abc", "us-east-1", null, "ghi", "3", Collections.emptyList(), "roleArn", "roleSessionName"); SlaveTemplate oldSlaveTemplate = new SlaveTemplate("ami-123", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "OldSlaveDescription", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 0, 0, null, "iamInstanceProfile", true, false, "", false, "", false, false, false, ConnectionStrategy.PUBLIC_IP, -1, null, null, Tenancy.Default, EbsEncryptRootVolume.DEFAULT); + SlaveTemplate secondSlaveTemplate = new SlaveTemplate("ami-123", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "SecondSlaveDescription", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 0, 0, null, "iamInstanceProfile", true, false, "", false, "", false, false, false, ConnectionStrategy.PUBLIC_IP, -1, null, null, Tenancy.Default, EbsEncryptRootVolume.DEFAULT); cloud.addTemplate(oldSlaveTemplate); + cloud.addTemplate(secondSlaveTemplate); SlaveTemplate newSlaveTemplate = new SlaveTemplate("ami-456", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "NewSlaveDescription", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 0, 0, null, "iamInstanceProfile", true, false, "", false, "", false, false, false, ConnectionStrategy.PUBLIC_IP, -1, null, null, Tenancy.Default, EbsEncryptRootVolume.DEFAULT); + int index = cloud.getTemplates().indexOf(oldSlaveTemplate); + cloud.updateTemplate(newSlaveTemplate, "OldSlaveDescription"); assertNull(cloud.getTemplate("OldSlaveDescription")); assertNotNull(cloud.getTemplate("NewSlaveDescription")); + Assert.assertEquals(index, cloud.getTemplates().indexOf(newSlaveTemplate)); // assert order of templates is kept } @Test From 2cf6ccc77455396a2f7f4c75755643208545442f Mon Sep 17 00:00:00 2001 From: Antonio Busuladzich Date: Tue, 8 Oct 2024 00:38:10 +0300 Subject: [PATCH 3/3] Added section to the readme with SlaveTemplate addition and update --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 9db4f92f6..3aeaff214 100644 --- a/README.md +++ b/README.md @@ -483,6 +483,28 @@ jenkins.clouds.add(amazonEC2Cloud) jenkins.save() ``` +## Programmatically adding/updating CloudTemplates + +The plugin supports programmatic addition and update of `CloudTemplates` in an already existing `Cloud` - +both can be accomplished via the Jenkins script console [Jenkins script console](https://wiki.jenkins.io/display/JENKINS/Jenkins+Script+Console). + +Example: + +```java + // Assuming on the Jenkins instance, there exists an EC2Cloud with the name "AwsCloud" + + AmazonEC2Cloud cloud = (AmazonEC2Cloud) Jenkins.get().clouds.stream().filter(cloud1 -> Objects.equals(cloud.getDisplayName(), "AwsCloud")).findFirst().get(); + + SlaveTemplate template = new SlaveTemplate(/*constructor*/); // View available constructors at https://github.com/jenkinsci/ec2-plugin/blob/master/src/main/java/hudson/plugins/ec2/SlaveTemplate.java + + // Adding a template + cloud.addTemplate(template); + + SlaveTemplate template2 = new SlaveTemplate(/*constructor*/); + // Updating a template. Note the description of an existing SlaveTemplate needs to passed in order for there to be a successful update, otherwise an Exception is thrown + cloud.updateTemplate(template2, template.description); +``` + # Security ## Securing the connection to Unix AMIs When you set up a template for a *Unix* instance (`Type AMI` field), you can select the strategy used to guarantee the