From d5e8e94b608dbdaf9367292bb618b8d80668059e Mon Sep 17 00:00:00 2001 From: Gavin Burris <66969321+GavinBurris42@users.noreply.github.com> Date: Fri, 3 Nov 2023 12:16:10 -0500 Subject: [PATCH] Updated Fleet Label Cloud and created tests for CasC (#418) * Added support for the CreateFleet API * Fixed EC2CreateFleet usage of launch template overrides for retreiving instance type and weight capacity * Added EC2CreateFleet to list of all fleets * Created tests for EC2CreateFleet * Made revisions to EC2CreateFleet. Updated tests to include testing for getStateBatch and isCreateFleet methods * Rename all occurances of EC2Fleet to Fleet, and rename CreateFleet to EC2Fleet * Renaming instances of 'EC2Fleet' to 'Fleet' * Updated comment noting the usage of EC2Fleets as a Fleet * Add permision checks and add missing permissions for EC2Fleets, fleets created by the CreateFleet API * Change the fleet cloud name for the Jenkins CasC field for backwards compatability. Added ggburris to the list of contributors * Removed commented out code and fixed indentations * Changed the fleet label cloud name for the Jenkins CasC field for backwards compatibility * Fixed EC2Fleet naming mistakes * Updated Fleet Label Cloud and created tests for CasC * Change naming ec2Fleet to eC2Fleet for CasC * @Change naming ec2FleetLabel to eC2FleetLabel for CasC * Removed testing print statements --------- Co-authored-by: Prathibha Datta Kumar --- .../jenkins/ec2fleet/FleetLabelCloud.java | 19 +-- ...leetLabelCloudConfigurationAsCodeTest.java | 113 ++++++++++++++++++ .../empty-name-configuration-as-code.yml | 8 ++ .../max-configuration-as-code.yml | 26 ++++ .../min-configuration-as-code.yml | 4 + .../name-required-configuration-as-code.yml | 9 ++ 6 files changed, 171 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/amazon/jenkins/ec2fleet/FleetLabelCloudConfigurationAsCodeTest.java create mode 100644 src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/empty-name-configuration-as-code.yml create mode 100644 src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/max-configuration-as-code.yml create mode 100644 src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/min-configuration-as-code.yml create mode 100644 src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/name-required-configuration-as-code.yml diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/FleetLabelCloud.java b/src/main/java/com/amazon/jenkins/ec2fleet/FleetLabelCloud.java index a25265bb..7669c2ee 100644 --- a/src/main/java/com/amazon/jenkins/ec2fleet/FleetLabelCloud.java +++ b/src/main/java/com/amazon/jenkins/ec2fleet/FleetLabelCloud.java @@ -116,9 +116,9 @@ public FleetLabelCloud(final String name, final boolean privateIpUsed, final boolean alwaysReconnect, final Integer idleMinutes, - final Integer minSize, - final Integer maxSize, - final Integer numExecutors, + final int minSize, + final int maxSize, + final int numExecutors, final boolean restrictUsage, final boolean disableTaskResubmit, final Integer initOnlineTimeoutSec, @@ -136,9 +136,12 @@ public FleetLabelCloud(final String name, this.idleMinutes = idleMinutes; this.privateIpUsed = privateIpUsed; this.alwaysReconnect = alwaysReconnect; - this.minSize = minSize; + if (minSize < 0) { + warning("Cloud parameter 'minSize' can't be less than 0, setting to 0"); + } + this.minSize = Math.max(0, minSize); this.maxSize = maxSize; - this.numExecutors = numExecutors; + this.numExecutors = Math.max(numExecutors, 1); this.restrictUsage = restrictUsage; this.disableTaskResubmit = disableTaskResubmit; this.initOnlineTimeoutSec = initOnlineTimeoutSec; @@ -204,15 +207,15 @@ public int getIdleMinutes() { return (idleMinutes != null) ? idleMinutes : 0; } - public Integer getMaxSize() { + public int getMaxSize() { return maxSize; } - public Integer getMinSize() { + public int getMinSize() { return minSize; } - public Integer getNumExecutors() { + public int getNumExecutors() { return numExecutors; } diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/FleetLabelCloudConfigurationAsCodeTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/FleetLabelCloudConfigurationAsCodeTest.java new file mode 100644 index 00000000..2e8b1710 --- /dev/null +++ b/src/test/java/com/amazon/jenkins/ec2fleet/FleetLabelCloudConfigurationAsCodeTest.java @@ -0,0 +1,113 @@ +package com.amazon.jenkins.ec2fleet; + +import com.amazon.jenkins.ec2fleet.fleet.Fleet; +import com.amazon.jenkins.ec2fleet.fleet.Fleets; +import hudson.plugins.sshslaves.SSHConnector; +import hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy; +import io.jenkins.plugins.casc.ConfiguratorException; +import io.jenkins.plugins.casc.misc.ConfiguredWithCode; +import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FleetLabelCloudConfigurationAsCodeTest { + @Rule + public JenkinsRule jenkinsRule = new JenkinsConfiguredWithCodeRule(); + + @Before + public void before() { + final Fleet fleet = mock(Fleet.class); + Fleets.setGet(fleet); + when(fleet.getState(anyString(), anyString(), nullable(String.class), anyString())) + .thenReturn(new FleetStateStats("", 2, FleetStateStats.State.active(), new HashSet<>(Arrays.asList("i-1", "i-2")), Collections.emptyMap())); + } + + @Test + @ConfiguredWithCode( + value = "FleetLabelCloud/name-required-configuration-as-code.yml", + expected = ConfiguratorException.class, + message = "error configuring 'jenkins' with class io.jenkins.plugins.casc.core.JenkinsConfigurator configurator") + public void configurationWithNullName_shouldFail() { + } + + @Test + @ConfiguredWithCode("FleetLabelCloud/min-configuration-as-code.yml") + public void shouldCreateCloudFromMinConfiguration() { + assertEquals(jenkinsRule.jenkins.clouds.size(), 1); + FleetLabelCloud cloud = (FleetLabelCloud) jenkinsRule.jenkins.clouds.getByName("ec2-fleet-label"); + + assertEquals("ec2-fleet-label", cloud.name); + assertNull(cloud.getRegion()); + assertNull(cloud.getEndpoint()); + assertNull(cloud.getFsRoot()); + assertFalse(cloud.isPrivateIpUsed()); + assertFalse(cloud.isAlwaysReconnect()); + assertEquals(cloud.getIdleMinutes(), 0); + assertEquals(cloud.getMinSize(), 0); + assertEquals(cloud.getMaxSize(), 0); + assertEquals(cloud.getNumExecutors(), 1); + assertFalse(cloud.isRestrictUsage()); + assertEquals(cloud.getInitOnlineTimeoutSec(), 180); + assertEquals(cloud.getInitOnlineCheckIntervalSec(), 15); + assertEquals(cloud.getCloudStatusIntervalSec(), 10); + assertFalse(cloud.isDisableTaskResubmit()); + assertFalse(cloud.isNoDelayProvision()); + assertNull(cloud.getEc2KeyPairName()); + } + + @Test + @ConfiguredWithCode("FleetLabelCloud/max-configuration-as-code.yml") + public void shouldCreateCloudFromMaxConfiguration() { + assertEquals(jenkinsRule.jenkins.clouds.size(), 1); + FleetLabelCloud cloud = (FleetLabelCloud) jenkinsRule.jenkins.clouds.getByName("ec2-fleet-label"); + + assertEquals("ec2-fleet-label", cloud.name); + assertEquals(cloud.getRegion(), "us-east-2"); + assertEquals(cloud.getEndpoint(), "http://a.com"); + assertEquals(cloud.getFsRoot(), "my-root"); + assertTrue(cloud.isPrivateIpUsed()); + assertTrue(cloud.isAlwaysReconnect()); + assertEquals(cloud.getIdleMinutes(), 22); + assertEquals(cloud.getMinSize(), 11); + assertEquals(cloud.getMaxSize(), 75); + assertEquals(cloud.getNumExecutors(), 24); + assertFalse(cloud.isRestrictUsage()); + assertEquals(cloud.getInitOnlineTimeoutSec(), 267); + assertEquals(cloud.getInitOnlineCheckIntervalSec(), 13); + assertEquals(cloud.getCloudStatusIntervalSec(), 11); + assertTrue(cloud.isDisableTaskResubmit()); + assertFalse(cloud.isNoDelayProvision()); + assertEquals(cloud.getAwsCredentialsId(), "xx"); + assertEquals(cloud.getEc2KeyPairName(), "keyPairName"); + + SSHConnector sshConnector = (SSHConnector) cloud.getComputerConnector(); + assertEquals(sshConnector.getSshHostKeyVerificationStrategy().getClass(), NonVerifyingKeyVerificationStrategy.class); + } + + @Test + @ConfiguredWithCode("FleetLabelCloud/empty-name-configuration-as-code.yml") + public void configurationWithEmptyName_shouldUseDefault() { + assertEquals(jenkinsRule.jenkins.clouds.size(), 3); + + for (FleetLabelCloud cloud : jenkinsRule.jenkins.clouds.getAll(FleetLabelCloud.class)){ + + assertTrue(cloud.name.startsWith(FleetLabelCloud.BASE_DEFAULT_FLEET_CLOUD_ID)); + assertEquals(("FleetLabelCloud".length() + CloudNames.SUFFIX_LENGTH + 1), cloud.name.length()); + } + } +} diff --git a/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/empty-name-configuration-as-code.yml b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/empty-name-configuration-as-code.yml new file mode 100644 index 00000000..3136e6c3 --- /dev/null +++ b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/empty-name-configuration-as-code.yml @@ -0,0 +1,8 @@ +jenkins: + clouds: + - eC2FleetLabel: + name: "" + - eC2FleetLabel: + name: "" + - eC2FleetLabel: + name: "" \ No newline at end of file diff --git a/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/max-configuration-as-code.yml b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/max-configuration-as-code.yml new file mode 100644 index 00000000..58e571d3 --- /dev/null +++ b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/max-configuration-as-code.yml @@ -0,0 +1,26 @@ +jenkins: + clouds: + - eC2FleetLabel: + name: ec2-fleet-label + awsCredentialsId: xx + computerConnector: + sshConnector: + credentialsId: cred + sshHostKeyVerificationStrategy: + NonVerifyingKeyVerificationStrategy + region: us-east-2 + endpoint: http://a.com + fsRoot: my-root + privateIpUsed: true + alwaysReconnect: true + idleMinutes: 22 + minSize: 11 + maxSize: 75 + numExecutors: 24 + restrictUsage: false + initOnlineTimeoutSec: 267 + initOnlineCheckIntervalSec: 13 + cloudStatusIntervalSec: 11 + disableTaskResubmit: true + noDelayProvision: false + ec2KeyPairName: "keyPairName" \ No newline at end of file diff --git a/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/min-configuration-as-code.yml b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/min-configuration-as-code.yml new file mode 100644 index 00000000..7d4a9c46 --- /dev/null +++ b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/min-configuration-as-code.yml @@ -0,0 +1,4 @@ +jenkins: + clouds: + - eC2FleetLabel: + name: ec2-fleet-label \ No newline at end of file diff --git a/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/name-required-configuration-as-code.yml b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/name-required-configuration-as-code.yml new file mode 100644 index 00000000..864d4485 --- /dev/null +++ b/src/test/resources/com/amazon/jenkins/ec2fleet/FleetLabelCloud/name-required-configuration-as-code.yml @@ -0,0 +1,9 @@ +jenkins: + clouds: + - eC2FleetLabel: + awsCredentialsId: xx + region: us-east-2 + idleMinutes: 33 + minSize: 15 + maxSize: 90 + numExecutors: 12 \ No newline at end of file