From 27a2eaecd30e813e6465636791fb41b0a2783b6a Mon Sep 17 00:00:00 2001
From: Peter Wagner
Date: Mon, 19 Dec 2016 14:28:01 -0500
Subject: [PATCH 1/4] Scale executors by LaunchSpecification weight
This works nicely with a SpotFleet weighted by vCPU count (easy in the
management console).
---
.../jenkins/ec2fleet/EC2FleetCloud.java | 24 +++++++++++---
.../jenkins/ec2fleet/FleetStateStats.java | 33 +++++++++++++++++--
.../jenkins/ec2fleet/cloud/FleetNode.java | 2 +-
.../ec2fleet/EC2FleetCloud/config.jelly | 4 +++
.../jenkins/ec2fleet/EC2FleetCloudTest.java | 20 +++++------
.../ec2fleet/ProvisionIntegrationTest.java | 8 ++---
.../ec2fleet/RealEc2ApiIntegrationTest.java | 4 +--
.../jenkins/ec2fleet/UiIntegrationTest.java | 22 ++++++-------
8 files changed, 83 insertions(+), 34 deletions(-)
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
index 976402d4..c5db472a 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
@@ -97,6 +97,7 @@ public class EC2FleetCloud extends Cloud {
private final Integer numExecutors;
private final boolean addNodeOnlyIfRunning;
private final boolean restrictUsage;
+ private final boolean scaleExecutorsByWeight;
private transient Set plannedNodesCache;
// fleetInstancesCache contains all Jenkins nodes known to be in the fleet, not in dyingFleetInstancesCache
@@ -120,7 +121,8 @@ public EC2FleetCloud(final String name,
final Integer maxSize,
final Integer numExecutors,
final boolean addNodeOnlyIfRunning,
- final boolean restrictUsage) {
+ final boolean restrictUsage,
+ final boolean scaleExecutorsByWeight) {
super(StringUtils.isBlank(name) ? FLEET_CLOUD_ID : name);
initCaches();
this.credentialsId = credentialsId;
@@ -138,6 +140,7 @@ public EC2FleetCloud(final String name,
this.numExecutors = numExecutors;
this.addNodeOnlyIfRunning = addNodeOnlyIfRunning;
this.restrictUsage = restrictUsage;
+ this.scaleExecutorsByWeight = scaleExecutorsByWeight;
}
/**
@@ -198,6 +201,10 @@ public Integer getNumExecutors() {
return numExecutors;
}
+ public boolean isScaleExecutorsByWeight() {
+ return scaleExecutorsByWeight;
+ }
+
public String getJvmSettings() {
return "";
}
@@ -365,7 +372,7 @@ public synchronized FleetStateStats updateStatus() {
StringUtils.join(newFleetInstances, ", ") + "]");
}
for (final String instanceId : newFleetInstances) {
- addNewSlave(ec2, instanceId);
+ addNewSlave(ec2, instanceId, stats);
}
} catch (final Exception ex) {
LOGGER.log(Level.WARNING, "Unable to add a new instance.", ex);
@@ -465,7 +472,7 @@ private synchronized void removeNode(String instanceId) {
}
}
- private void addNewSlave(final AmazonEC2 ec2, final String instanceId) throws Exception {
+ private void addNewSlave(final AmazonEC2 ec2, final String instanceId, FleetStateStats stats) throws Exception {
// Generate a random FS root if one isn't specified
String effectiveFsRoot = fsRoot;
if (StringUtils.isBlank(effectiveFsRoot)) {
@@ -487,9 +494,18 @@ private void addNewSlave(final AmazonEC2 ec2, final String instanceId) throws Ex
// Check if we have the address to use. Nodes don't get it immediately.
if (address == null) return; // Wait some more...
+ int numExecutors;
+ if (scaleExecutorsByWeight) {
+ Double instanceTypeWeight = stats.getInstanceTypeWeight(instance.getInstanceType());
+ Double instanceWeight = Math.ceil(this.numExecutors * instanceTypeWeight);
+ numExecutors = instanceWeight.intValue();
+ } else {
+ numExecutors = this.numExecutors;
+ }
+
final Node.Mode nodeMode = restrictUsage ? Node.Mode.EXCLUSIVE : Node.Mode.NORMAL;
final FleetNode slave = new FleetNode(instanceId, "Fleet slave for " + instanceId,
- effectiveFsRoot, numExecutors.toString(), nodeMode, labelString, new ArrayList>(),
+ effectiveFsRoot, numExecutors, nodeMode, labelString, new ArrayList>(),
name, computerConnector.launch(address, TaskListener.NULL));
// Initialize our retention strategy
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java b/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
index f44dc7f0..13b1ecc4 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
@@ -6,12 +6,16 @@
import com.amazonaws.services.ec2.model.DescribeSpotFleetInstancesResult;
import com.amazonaws.services.ec2.model.DescribeSpotFleetRequestsRequest;
import com.amazonaws.services.ec2.model.DescribeSpotFleetRequestsResult;
+import com.amazonaws.services.ec2.model.SpotFleetLaunchSpecification;
import com.amazonaws.services.ec2.model.SpotFleetRequestConfig;
+import com.amazonaws.services.ec2.model.SpotFleetRequestConfigData;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
@@ -19,7 +23,8 @@
*/
@SuppressWarnings("unused")
public final class FleetStateStats {
-
+ private static
+ final double DEFAULT_WEIGHT = 1.0;
private @Nonnull
final String fleetId;
private @Nonnegative
@@ -31,17 +36,21 @@ public final class FleetStateStats {
private @Nonnull
final Set instances;
private @Nonnull
+ final Map instanceTypeWeights;
+ private @Nonnull
final String label;
public FleetStateStats(final @Nonnull String fleetId,
final int numDesired, final @Nonnull String state,
final @Nonnull Set instances,
+ final @Nonnull Map instanceTypeWeights,
final @Nonnull String label) {
this.fleetId = fleetId;
this.numActive = instances.size();
this.numDesired = numDesired;
this.state = state;
this.instances = instances;
+ this.instanceTypeWeights=instanceTypeWeights;
this.label = label;
}
@@ -68,6 +77,12 @@ public Set getInstances() {
return instances;
}
+ @Nonnull
+ public Double getInstanceTypeWeight(String instanceType) {
+ Double instanceTypeWeight = instanceTypeWeights.get(instanceType);
+ return instanceTypeWeight == null ? DEFAULT_WEIGHT : instanceTypeWeight;
+ }
+
@Nonnull
public String getLabel() {
return label;
@@ -95,10 +110,24 @@ public static FleetStateStats readClusterState(final AmazonEC2 ec2, final String
throw new IllegalStateException("Fleet " + fleetId + " can't be described");
final SpotFleetRequestConfig fleetConfig = fleet.getSpotFleetRequestConfigs().get(0);
+ final SpotFleetRequestConfigData fleetRequestConfig = fleetConfig.getSpotFleetRequestConfig();
+
+ // Index configured instance types by weight:
+ final Map instanceTypeWeight = new HashMap<>();
+ for (SpotFleetLaunchSpecification launchSpecification : fleetRequestConfig.getLaunchSpecifications()) {
+ final String instanceType = launchSpecification.getInstanceType();
+ final Double instanceWeight = launchSpecification.getWeightedCapacity();
+ final Double existingWeight = instanceTypeWeight.get(instanceType);
+ if (instanceWeight == null || (existingWeight != null && existingWeight > instanceWeight)) {
+ continue;
+ }
+ instanceTypeWeight.put(instanceType, instanceWeight);
+ }
return new FleetStateStats(fleetId,
- fleetConfig.getSpotFleetRequestConfig().getTargetCapacity(),
+ fleetRequestConfig.getTargetCapacity(),
fleetConfig.getSpotFleetRequestState(), instances,
+ Collections.unmodifiableMap(instanceTypeWeight),
label);
}
}
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/cloud/FleetNode.java b/src/main/java/com/amazon/jenkins/ec2fleet/cloud/FleetNode.java
index 2996eab4..fc723dbd 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/cloud/FleetNode.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/cloud/FleetNode.java
@@ -17,7 +17,7 @@ public class FleetNode extends Slave implements EphemeralNode {
private final String cloudName;
- public FleetNode(final String name, final String nodeDescription, final String remoteFS, final String numExecutors, final Mode mode, final String label,
+ public FleetNode(final String name, final String nodeDescription, final String remoteFS, final int numExecutors, final Mode mode, final String label,
final List extends NodeProperty>> nodeProperties, final String cloudName, ComputerLauncher launcher) throws IOException, Descriptor.FormException {
super(name, nodeDescription, remoteFS, numExecutors, mode, label,
launcher, RetentionStrategy.NOOP, nodeProperties);
diff --git a/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/config.jelly b/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/config.jelly
index 1ef35628..edf4203e 100644
--- a/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/config.jelly
+++ b/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/config.jelly
@@ -64,6 +64,10 @@
+
+
+
+
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
index bc5deee4..49dc54ae 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
@@ -109,7 +109,7 @@ public void provision_fleetIsEmpty() {
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
null, null, null, null, false,
- false, 0, 0, 1, 1, false, false);
+ false, 0, 0, 1, 1, false, false, false);
// when
Collection r = fleetCloud.provision(null, 1);
@@ -146,7 +146,7 @@ public void updateStatus_doNothingWhenFleetIsEmpty() {
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"fleetId", null, null, null, false,
- false, 0, 0, 1, 1, false, false);
+ false, 0, 0, 1, 1, false, false, false);
// when
FleetStateStats stats = fleetCloud.updateStatus();
@@ -207,7 +207,7 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed() throws IOException {
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
- false, 0, 0, 1, 1, false, false);
+ false, 0, 0, 1, 1, false, false, false);
ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
Mockito.doNothing().when(jenkins).addNode(nodeCaptor.capture());
@@ -275,7 +275,7 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed_restrictUsage() throws I
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
- false, 0, 0, 1, 1, false, true);
+ false, 0, 0, 1, 1, false, true, false);
ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
Mockito.doNothing().when(jenkins).addNode(nodeCaptor.capture());
@@ -498,7 +498,7 @@ public void getDisplayName_returnDefaultWhenNull() {
null, null, null, null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertEquals(ec2FleetCloud.getDisplayName(), EC2FleetCloud.FLEET_CLOUD_ID);
}
@@ -508,7 +508,7 @@ public void getDisplayName_returnDisplayName() {
"CloudName", null, null, null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertEquals(ec2FleetCloud.getDisplayName(), "CloudName");
}
@@ -518,7 +518,7 @@ public void getAwsCredentialsId_returnNull_whenNoCredentialsIdOrAwsCredentialsId
null, null, null, null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertNull(ec2FleetCloud.getAwsCredentialsId());
}
@@ -528,7 +528,7 @@ public void getAwsCredentialsId_returnValue_whenCredentialsIdPresent() {
null, null, "Opa", null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertEquals("Opa", ec2FleetCloud.getAwsCredentialsId());
}
@@ -538,7 +538,7 @@ public void getAwsCredentialsId_returnValue_whenAwsCredentialsIdPresent() {
null, "Opa", null, null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertEquals("Opa", ec2FleetCloud.getAwsCredentialsId());
}
@@ -548,7 +548,7 @@ public void getAwsCredentialsId_returnAwsCredentialsId_whenAwsCredentialsIdAndCr
null, "A", "B", null, null,
null, null, null, false,
false, null, null, null,
- null, false, false);
+ null, false, false, false);
Assert.assertEquals("A", ec2FleetCloud.getAwsCredentialsId());
}
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
index 1bf44630..e4be2c48 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
@@ -123,7 +123,7 @@ public void should_not_do_anything_if_fleet_is_empty_and_max_size_isreached() th
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region", "fId",
"momo", null, computerConnector, false, false,
- 0, 0, 0, 1, false, false);
+ 0, 0, 0, 1, false, false, false);
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
@@ -163,7 +163,7 @@ public void should_add_planned_if_capacity_required_but_not_described_yet() thro
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region", "fId",
"momo", null, computerConnector, false, false,
- 0, 0, 10, 1, false, false);
+ 0, 0, 10, 1, false, false, false);
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
@@ -232,7 +232,7 @@ public void should_convert_planed_to_node_if_describe_instance() throws Exceptio
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region", "fId",
"momo", null, computerConnector, false, false,
- 0, 0, 10, 1, false, false);
+ 0, 0, 10, 1, false, false, false);
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
@@ -314,7 +314,7 @@ public void should_not_convert_planned_to_node_if_state_is_not_running_and_check
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region", "fId",
"momo", null, computerConnector, false, false,
- 0, 0, 10, 1, true, false);
+ 0, 0, 10, 1, true, false, false);
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
index f9011463..d0ff845f 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
@@ -50,7 +50,7 @@ public void shouldSuccessfullyUpdatePluginWithFleetStatus() throws Exception {
public void run(AmazonEC2 amazonEC2, String fleetId) throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud("", "credId", null, null, fleetId,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud);
// 10 sec refresh time so wait
@@ -82,7 +82,7 @@ public void shouldSuccessfullyUpdateBigFleetPluginWithFleetStatus() throws Excep
public void run(AmazonEC2 amazonEC2, String fleetId) throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, null, fleetId,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud);
final long start = System.currentTimeMillis();
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
index 44f0945a..c14b84f3 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
@@ -44,7 +44,7 @@ public void shouldFindThePluginByShortName() {
public void shouldShowInConfigurationClouds() throws IOException, SAXException {
Cloud cloud = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -57,12 +57,12 @@ public void shouldShowInConfigurationClouds() throws IOException, SAXException {
public void shouldShowMultipleClouds() throws IOException, SAXException {
Cloud cloud1 = new EC2FleetCloud("a", null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud1);
Cloud cloud2 = new EC2FleetCloud("b", null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -78,12 +78,12 @@ public void shouldShowMultipleClouds() throws IOException, SAXException {
public void shouldShowMultipleCloudsWithDefaultName() throws IOException, SAXException {
Cloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud1);
Cloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -99,12 +99,12 @@ public void shouldShowMultipleCloudsWithDefaultName() throws IOException, SAXExc
public void shouldUpdateProperCloudWhenMultiple() throws IOException, SAXException {
EC2FleetCloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -122,12 +122,12 @@ public void shouldUpdateProperCloudWhenMultiple() throws IOException, SAXExcepti
public void shouldGetFirstWhenMultipleCloudWithSameName() {
EC2FleetCloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud2);
assertSame(cloud1, j.jenkins.getCloud("FleetCloud"));
@@ -137,12 +137,12 @@ public void shouldGetFirstWhenMultipleCloudWithSameName() {
public void shouldGetProperWhenMultipleWithDiffName() {
EC2FleetCloud cloud1 = new EC2FleetCloud("a", null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud("b", null, null, null, null,
null, null, null, false, false,
- 0, 0, 0, 0, false, false);
+ 0, 0, 0, 0, false, false, false);
j.jenkins.clouds.add(cloud2);
assertSame(cloud1, j.jenkins.getCloud("a"));
From e8ffd2ef60387c9f3692607a4071fa90a60685f7 Mon Sep 17 00:00:00 2001
From: Artem Stasiuk
Date: Wed, 3 Jul 2019 18:04:43 -0700
Subject: [PATCH 2/4] Rebase of #32 allow to scale number of executors by
weight
---
.../jenkins/ec2fleet/EC2FleetCloud.java | 19 +-
.../amazon/jenkins/ec2fleet/EC2FleetNode.java | 5 +-
.../jenkins/ec2fleet/FleetStateStats.java | 62 ++-
.../help-scaleExecutorsByWeight.html | 64 +++
.../ec2fleet/AutoResubmitIntegrationTest.java | 6 +-
.../jenkins/ec2fleet/EC2FleetCloudTest.java | 382 ++++++++++++++++--
.../jenkins/ec2fleet/FleetStateStatsTest.java | 159 ++++++++
.../ec2fleet/ProvisionIntegrationTest.java | 13 +-
.../ec2fleet/RealEc2ApiIntegrationTest.java | 4 +-
.../jenkins/ec2fleet/UiIntegrationTest.java | 22 +-
10 files changed, 631 insertions(+), 105 deletions(-)
create mode 100644 src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/help-scaleExecutorsByWeight.html
create mode 100644 src/test/java/com/amazon/jenkins/ec2fleet/FleetStateStatsTest.java
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
index b4f4ab1c..0683f06a 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java
@@ -507,25 +507,26 @@ private void addNewSlave(final AmazonEC2 ec2, final String instanceId, FleetStat
if (address == null) return; // Wait some more...
// Generate a random FS root if one isn't specified
- String effectiveFsRoot = fsRoot;
- if (StringUtils.isBlank(effectiveFsRoot)) {
+ final String effectiveFsRoot;
+ if (StringUtils.isBlank(fsRoot)) {
effectiveFsRoot = "/tmp/jenkins-" + UUID.randomUUID().toString().substring(0, 8);
+ } else {
+ effectiveFsRoot = fsRoot;
}
- int numExecutors;
- if (scaleExecutorsByWeight) {
- Double instanceTypeWeight = stats.getInstanceTypeWeight(instance.getInstanceType());
- Double instanceWeight = Math.ceil(this.numExecutors * instanceTypeWeight);
- numExecutors = instanceWeight.intValue();
+ final Double instanceTypeWeight = stats.getInstanceTypeWeights().get(instance.getInstanceType());
+ final int effectiveNumExecutors;
+ if (scaleExecutorsByWeight && instanceTypeWeight != null) {
+ effectiveNumExecutors = (int) Math.max(Math.round(numExecutors * instanceTypeWeight), 1);
} else {
- numExecutors = this.numExecutors;
+ effectiveNumExecutors = numExecutors;
}
final EC2FleetAutoResubmitComputerLauncher computerLauncher = new EC2FleetAutoResubmitComputerLauncher(
computerConnector.launch(address, TaskListener.NULL), disableTaskResubmit);
final Node.Mode nodeMode = restrictUsage ? Node.Mode.EXCLUSIVE : Node.Mode.NORMAL;
final EC2FleetNode node = new EC2FleetNode(instanceId, "Fleet slave for " + instanceId,
- effectiveFsRoot, numExecutors.toString(), nodeMode, labelString, new ArrayList>(),
+ effectiveFsRoot, effectiveNumExecutors, nodeMode, labelString, new ArrayList>(),
name, computerLauncher);
// Initialize our retention strategy
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetNode.java b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetNode.java
index 51958a48..ec2e211b 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetNode.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetNode.java
@@ -17,8 +17,9 @@ public class EC2FleetNode extends Slave implements EphemeralNode {
private final String cloudName;
- public FleetNode(final String name, final String nodeDescription, final String remoteFS, final int numExecutors, final Mode mode, final String label,
- final List extends NodeProperty>> nodeProperties, final String cloudName, ComputerLauncher launcher) throws IOException, Descriptor.FormException {
+ @SuppressWarnings("WeakerAccess")
+ public EC2FleetNode(final String name, final String nodeDescription, final String remoteFS, final int numExecutors, final Mode mode, final String label,
+ final List extends NodeProperty>> nodeProperties, final String cloudName, ComputerLauncher launcher) throws IOException, Descriptor.FormException {
super(name, nodeDescription, remoteFS, numExecutors, mode, label,
launcher, RetentionStrategy.NOOP, nodeProperties);
this.cloudName = cloudName;
diff --git a/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java b/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
index 13b1ecc4..ab52c4e2 100644
--- a/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
+++ b/src/main/java/com/amazon/jenkins/ec2fleet/FleetStateStats.java
@@ -12,6 +12,7 @@
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -21,37 +22,33 @@
/**
* @see EC2FleetCloud
*/
-@SuppressWarnings("unused")
+@SuppressWarnings({"unused", "WeakerAccess"})
+@ThreadSafe
public final class FleetStateStats {
- private static
- final double DEFAULT_WEIGHT = 1.0;
- private @Nonnull
- final String fleetId;
- private @Nonnegative
- final int numActive;
- private @Nonnegative
- final int numDesired;
- private @Nonnull
- final String state;
- private @Nonnull
- final Set instances;
- private @Nonnull
- final Map instanceTypeWeights;
- private @Nonnull
- final String label;
+
+ @Nonnull
+ private final String fleetId;
+ @Nonnegative
+ private final int numActive;
+ @Nonnegative
+ private final int numDesired;
+ @Nonnull
+ private final String state;
+ @Nonnull
+ private final Set instances;
+ @Nonnull
+ private final Map instanceTypeWeights;
public FleetStateStats(final @Nonnull String fleetId,
final int numDesired, final @Nonnull String state,
final @Nonnull Set instances,
- final @Nonnull Map instanceTypeWeights,
- final @Nonnull String label) {
+ final @Nonnull Map instanceTypeWeights) {
this.fleetId = fleetId;
this.numActive = instances.size();
this.numDesired = numDesired;
this.state = state;
this.instances = instances;
- this.instanceTypeWeights=instanceTypeWeights;
- this.label = label;
+ this.instanceTypeWeights = instanceTypeWeights;
}
@Nonnull
@@ -78,14 +75,8 @@ public Set getInstances() {
}
@Nonnull
- public Double getInstanceTypeWeight(String instanceType) {
- Double instanceTypeWeight = instanceTypeWeights.get(instanceType);
- return instanceTypeWeight == null ? DEFAULT_WEIGHT : instanceTypeWeight;
- }
-
- @Nonnull
- public String getLabel() {
- return label;
+ public Map getInstanceTypeWeights() {
+ return instanceTypeWeights;
}
public static FleetStateStats readClusterState(final AmazonEC2 ec2, final String fleetId, final String label) {
@@ -113,21 +104,22 @@ public static FleetStateStats readClusterState(final AmazonEC2 ec2, final String
final SpotFleetRequestConfigData fleetRequestConfig = fleetConfig.getSpotFleetRequestConfig();
// Index configured instance types by weight:
- final Map instanceTypeWeight = new HashMap<>();
+ final Map instanceTypeWeights = new HashMap<>();
for (SpotFleetLaunchSpecification launchSpecification : fleetRequestConfig.getLaunchSpecifications()) {
final String instanceType = launchSpecification.getInstanceType();
+ if (instanceType == null) continue;
+
final Double instanceWeight = launchSpecification.getWeightedCapacity();
- final Double existingWeight = instanceTypeWeight.get(instanceType);
- if (instanceWeight == null || (existingWeight != null && existingWeight > instanceWeight)) {
+ final Double existingWeight = instanceTypeWeights.get(instanceType);
+ if (instanceWeight == null || (existingWeight != null && existingWeight > instanceWeight)) {
continue;
}
- instanceTypeWeight.put(instanceType, instanceWeight);
+ instanceTypeWeights.put(instanceType, instanceWeight);
}
return new FleetStateStats(fleetId,
fleetRequestConfig.getTargetCapacity(),
fleetConfig.getSpotFleetRequestState(), instances,
- Collections.unmodifiableMap(instanceTypeWeight),
- label);
+ instanceTypeWeights);
}
}
diff --git a/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/help-scaleExecutorsByWeight.html b/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/help-scaleExecutorsByWeight.html
new file mode 100644
index 00000000..22b6a472
--- /dev/null
+++ b/src/main/resources/com/amazon/jenkins/ec2fleet/EC2FleetCloud/help-scaleExecutorsByWeight.html
@@ -0,0 +1,64 @@
+If unchecked which is default, plugin will not use
+instance
+ weight
+information to scale number of executors per node, and just set number of executors defined in
+configuration field Number of Executors
+
+
+ When it's checked, plugin consumes instance weight information provided by Launch Specification
+ and uses it to scale node number of executors from configuration field Number of Executors
+ Note current implementation doesn't support Launch Template only Launch Specification
+
+
+
+ Example (here instance type from launch specification match with
+ launched instance type):
+
+
+
+
+ Number of Executors |
+ Instance Weight |
+ Effective Number of Executors |
+
+
+
+
+ 1 |
+ 1 |
+ 1 |
+
+
+ 1 |
+ 0.5 |
+ 1 |
+
+
+ 1 |
+ 0.1 |
+ 1 |
+
+
+ 10 |
+ 0.1 |
+ 1 |
+
+
+ 1 |
+ 1.5 |
+ 2 |
+
+
+ 1 |
+ 1.44 |
+ 1 |
+
+
+
+
+
+
+ Plugin always set number of executors at least one.
+ If launched instance type doesn't match any weight in launch specification
+ regular number of executors will be used without any scale.
+
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/AutoResubmitIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/AutoResubmitIntegrationTest.java
index 55cc45e6..153c0789 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/AutoResubmitIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/AutoResubmitIntegrationTest.java
@@ -79,7 +79,7 @@ public void should_successfully_resubmit_freestyle_task() throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, new SingleLocalComputerConnector(j), false, false,
0, 0, 10, 1, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
List rs = getQueueTaskFutures(1);
@@ -115,7 +115,7 @@ public void should_successfully_resubmit_parametrized_task() throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, new SingleLocalComputerConnector(j), false, false,
0, 0, 10, 1, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
List rs = new ArrayList<>();
@@ -171,7 +171,7 @@ public void should_not_resubmit_if_disabled() throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, new SingleLocalComputerConnector(j), false, false,
0, 0, 10, 1, false, false,
- true, 0, 0);
+ true, 0, 0, false);
j.jenkins.clouds.add(cloud);
List rs = getQueueTaskFutures(1);
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
index 4c0843b6..0157efcf 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudTest.java
@@ -15,6 +15,7 @@
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.Region;
import com.amazonaws.services.ec2.model.Reservation;
+import com.amazonaws.services.ec2.model.SpotFleetLaunchSpecification;
import com.amazonaws.services.ec2.model.SpotFleetRequestConfig;
import com.amazonaws.services.ec2.model.SpotFleetRequestConfigData;
import hudson.ExtensionList;
@@ -70,6 +71,9 @@ public class EC2FleetCloudTest {
@Mock
private EC2Api ec2Api;
+ @Mock
+ private AmazonEC2 amazonEC2;
+
@Before
public void before() {
spotFleetRequestConfig1 = new SpotFleetRequestConfig();
@@ -89,6 +93,8 @@ public void before() {
Registry.setEc2Api(ec2Api);
+ PowerMockito.mockStatic(LabelFinder.class);
+
PowerMockito.mockStatic(Jenkins.class);
PowerMockito.when(Jenkins.getInstance()).thenReturn(jenkins);
}
@@ -101,7 +107,6 @@ public void after() {
@Test
public void provision_fleetIsEmpty() {
// given
- AmazonEC2 amazonEC2 = mock(AmazonEC2.class);
when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
@@ -120,7 +125,7 @@ public void provision_fleetIsEmpty() {
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"", null, null, null, null, false,
false, 0, 0, 1, 1, false,
- false, false, 0, 0);
+ false, false, 0, 0, false);
// when
Collection r = fleetCloud.provision(null, 1);
@@ -132,7 +137,6 @@ public void provision_fleetIsEmpty() {
@Test
public void updateStatus_doNothingWhenFleetIsEmpty() {
// given
- AmazonEC2 amazonEC2 = mock(AmazonEC2.class);
when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
@@ -151,7 +155,8 @@ public void updateStatus_doNothingWhenFleetIsEmpty() {
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"", "fleetId", null, null, null, false,
false, 0, 0, 1, 1,
- false, false, false, 0, 0);
+ false, false, false, 0,
+ 0, false);
// when
FleetStateStats stats = fleetCloud.updateStatus();
@@ -165,9 +170,6 @@ public void updateStatus_doNothingWhenFleetIsEmpty() {
@Test
public void updateStatus_shouldAddNodeIfAnyNewDescribed() throws IOException {
// given
- PowerMockito.mockStatic(LabelFinder.class);
-
- AmazonEC2 amazonEC2 = mock(AmazonEC2.class);
when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult();
@@ -196,20 +198,13 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed() throws IOException {
when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
.thenReturn(describeSpotFleetRequestsResult);
- when(jenkins.getNodesObject()).thenReturn(mock(Nodes.class));
-
- // mock
- ExtensionList labelFinder = mock(ExtensionList.class);
- when(labelFinder.iterator()).thenReturn(Collections.emptyIterator());
- PowerMockito.when(LabelFinder.all()).thenReturn(labelFinder);
-
- // mocking part of node creation process Jenkins.getInstance().getLabelAtom(l)
- when(jenkins.getLabelAtom(anyString())).thenReturn(new LabelAtom("mock-label"));
+ mockNodeCreatingPart();
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
false, 0, 0, 1, 1,
- false, false, false, 0, 0);
+ false, false, false,
+ 0, 0, false);
ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
doNothing().when(jenkins).addNode(nodeCaptor.capture());
@@ -230,9 +225,6 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed() throws IOException {
@Test
public void updateStatus_shouldAddNodeIfAnyNewDescribed_restrictUsage() throws IOException {
// given
- PowerMockito.mockStatic(LabelFinder.class);
-
- AmazonEC2 amazonEC2 = mock(AmazonEC2.class);
when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult();
@@ -261,20 +253,13 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed_restrictUsage() throws I
when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
.thenReturn(describeSpotFleetRequestsResult);
- when(jenkins.getNodesObject()).thenReturn(mock(Nodes.class));
-
- // mock
- ExtensionList labelFinder = mock(ExtensionList.class);
- when(labelFinder.iterator()).thenReturn(Collections.emptyIterator());
- PowerMockito.when(LabelFinder.all()).thenReturn(labelFinder);
-
- // mocking part of node creation process Jenkins.getInstance().getLabelAtom(l)
- when(jenkins.getLabelAtom(anyString())).thenReturn(new LabelAtom("mock-label"));
+ mockNodeCreatingPart();
EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
"", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
false, 0, 0, 1, 1, false,
- true, false, 0, 0);
+ true, false,
+ 0, 0, false);
ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
doNothing().when(jenkins).addNode(nodeCaptor.capture());
@@ -292,6 +277,308 @@ public void updateStatus_shouldAddNodeIfAnyNewDescribed_restrictUsage() throws I
assertEquals(Node.Mode.EXCLUSIVE, actualFleetNode.getMode());
}
+ @Test
+ public void updateStatus_shouldAddNodeWithNumExecutors_whenWeightProvidedButNotEnabled() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult();
+ final String instanceType = "t";
+ describeInstancesResult.withReservations(
+ new Reservation().withInstances(new Instance()
+ .withPublicIpAddress("p-ip")
+ .withInstanceType(instanceType)
+ .withInstanceId("i-0")));
+
+ when(amazonEC2.describeInstances(any(DescribeInstancesRequest.class)))
+ .thenReturn(describeInstancesResult);
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId("i-0")
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(
+ new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType(instanceType)
+ .withWeightedCapacity(1.1))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, false);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(1, actualFleetNode.getNumExecutors());
+ }
+
+ @Test
+ public void updateStatus_shouldAddNodeWithScaledNumExecutors_whenWeightPresentAndEnabled() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ final String instanceType = "t";
+ final String instanceId = "i-0";
+ mockDescribeInstances(instanceId, instanceType);
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId(instanceId)
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(
+ new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType(instanceType)
+ .withWeightedCapacity(2.0))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, true);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(2, actualFleetNode.getNumExecutors());
+ }
+
+ @Test
+ public void updateStatus_shouldAddNodeWithNumExecutors_whenWeightPresentAndEnabledButForDiffType() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ mockDescribeInstances("i-0", "t");
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId("i-0")
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(
+ new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType("non-t")
+ .withWeightedCapacity(2.0))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, true);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(1, actualFleetNode.getNumExecutors());
+ }
+
+ @Test
+ public void updateStatus_shouldAddNodeWithRoundToLowScaledNumExecutors_whenWeightPresentAndEnabled() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ final String instanceId = "i-0";
+ final String instanceType = "t";
+ mockDescribeInstances(instanceId, instanceType);
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId(instanceId)
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType(instanceType)
+ .withWeightedCapacity(1.44))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, true);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(1, actualFleetNode.getNumExecutors());
+ }
+
+ @Test
+ public void updateStatus_shouldAddNodeWithRoundToLowScaledNumExecutors_whenWeightPresentAndEnabled1() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ final String instanceId = "i-0";
+ final String instanceType = "t";
+ mockDescribeInstances(instanceId, instanceType);
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId(instanceId)
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType("t")
+ .withWeightedCapacity(1.5))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, true);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(2, actualFleetNode.getNumExecutors());
+ }
+
+ @Test
+ public void updateStatus_shouldAddNodeWithScaledToOneNumExecutors_whenWeightPresentButLessOneAndEnabled() throws IOException {
+ // given
+ when(ec2Api.connect(any(String.class), any(String.class), anyString())).thenReturn(amazonEC2);
+
+ final String instanceId = "i-0";
+ final String instanceType = "t";
+ mockDescribeInstances(instanceId, instanceType);
+
+ DescribeSpotFleetInstancesResult describeSpotFleetInstancesResult = new DescribeSpotFleetInstancesResult();
+ describeSpotFleetInstancesResult.setActiveInstances(Arrays.asList(
+ new ActiveInstance().withInstanceId(instanceId)
+ ));
+
+ when(amazonEC2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(describeSpotFleetInstancesResult);
+
+ DescribeSpotFleetRequestsResult describeSpotFleetRequestsResult = new DescribeSpotFleetRequestsResult();
+ describeSpotFleetRequestsResult.setSpotFleetRequestConfigs(Arrays.asList(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState("active")
+ .withSpotFleetRequestConfig(new SpotFleetRequestConfigData()
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification()
+ .withInstanceType("t")
+ .withWeightedCapacity(0.1))
+ .withTargetCapacity(0))));
+ when(amazonEC2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(describeSpotFleetRequestsResult);
+
+ mockNodeCreatingPart();
+
+ EC2FleetCloud fleetCloud = new EC2FleetCloud(null, "credId", null, "region",
+ "", "fleetId", null, null, PowerMockito.mock(ComputerConnector.class), false,
+ false, 0, 0, 1, 1, false,
+ true, false,
+ 0, 0, true);
+
+ ArgumentCaptor nodeCaptor = ArgumentCaptor.forClass(Node.class);
+ doNothing().when(jenkins).addNode(nodeCaptor.capture());
+
+ // when
+ fleetCloud.updateStatus();
+
+ // then
+ Node actualFleetNode = nodeCaptor.getValue();
+ assertEquals(1, actualFleetNode.getNumExecutors());
+ }
+
@Test
public void descriptorImpl_doFillRegionItems_returnStaticRegionsIfApiCallFailed() {
AmazonEC2Client amazonEC2Client = mock(AmazonEC2Client.class);
@@ -489,7 +776,7 @@ public void getDisplayName_returnDefaultWhenNull() {
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
assertEquals(ec2FleetCloud.getDisplayName(), EC2FleetCloud.FLEET_CLOUD_ID);
}
@@ -500,7 +787,7 @@ public void getDisplayName_returnDisplayName() {
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
assertEquals(ec2FleetCloud.getDisplayName(), "CloudName");
}
@@ -511,7 +798,7 @@ public void getAwsCredentialsId_returnNull_whenNoCredentialsIdOrAwsCredentialsId
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
Assert.assertNull(ec2FleetCloud.getAwsCredentialsId());
}
@@ -522,7 +809,7 @@ public void getAwsCredentialsId_returnValue_whenCredentialsIdPresent() {
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
assertEquals("Opa", ec2FleetCloud.getAwsCredentialsId());
}
@@ -533,7 +820,7 @@ public void getAwsCredentialsId_returnValue_whenAwsCredentialsIdPresent() {
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
assertEquals("Opa", ec2FleetCloud.getAwsCredentialsId());
}
@@ -544,8 +831,31 @@ public void getAwsCredentialsId_returnAwsCredentialsId_whenAwsCredentialsIdAndCr
null, null, null, false,
false, null, null, null,
null, false, false, false
- , 0, 0);
+ , 0, 0, false);
assertEquals("A", ec2FleetCloud.getAwsCredentialsId());
}
+ private void mockNodeCreatingPart() {
+ when(jenkins.getNodesObject()).thenReturn(mock(Nodes.class));
+
+ ExtensionList labelFinder = mock(ExtensionList.class);
+ when(labelFinder.iterator()).thenReturn(Collections.emptyIterator());
+ PowerMockito.when(LabelFinder.all()).thenReturn(labelFinder);
+
+ // mocking part of node creation process Jenkins.getInstance().getLabelAtom(l)
+ when(jenkins.getLabelAtom(anyString())).thenReturn(new LabelAtom("mock-label"));
+ }
+
+ private void mockDescribeInstances(String instanceId, String instanceType) {
+ DescribeInstancesResult describeInstancesResult = new DescribeInstancesResult();
+ describeInstancesResult.withReservations(
+ new Reservation().withInstances(new Instance()
+ .withPublicIpAddress("p-ip")
+ .withInstanceType(instanceType)
+ .withInstanceId(instanceId)));
+
+ when(amazonEC2.describeInstances(any(DescribeInstancesRequest.class)))
+ .thenReturn(describeInstancesResult);
+ }
+
}
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/FleetStateStatsTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/FleetStateStatsTest.java
new file mode 100644
index 00000000..943e74fc
--- /dev/null
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/FleetStateStatsTest.java
@@ -0,0 +1,159 @@
+package com.amazon.jenkins.ec2fleet;
+
+import com.amazonaws.services.ec2.AmazonEC2;
+import com.amazonaws.services.ec2.model.ActiveInstance;
+import com.amazonaws.services.ec2.model.BatchState;
+import com.amazonaws.services.ec2.model.DescribeSpotFleetInstancesRequest;
+import com.amazonaws.services.ec2.model.DescribeSpotFleetInstancesResult;
+import com.amazonaws.services.ec2.model.DescribeSpotFleetRequestsRequest;
+import com.amazonaws.services.ec2.model.DescribeSpotFleetRequestsResult;
+import com.amazonaws.services.ec2.model.LaunchTemplateConfig;
+import com.amazonaws.services.ec2.model.SpotFleetLaunchSpecification;
+import com.amazonaws.services.ec2.model.SpotFleetRequestConfig;
+import com.amazonaws.services.ec2.model.SpotFleetRequestConfigData;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Collections;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class FleetStateStatsTest {
+
+ @Mock
+ private AmazonEC2 ec2;
+
+ @Before
+ public void before() {
+ when(ec2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(new DescribeSpotFleetInstancesResult());
+
+ when(ec2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(new DescribeSpotFleetRequestsResult()
+ .withSpotFleetRequestConfigs(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestConfig(
+ new SpotFleetRequestConfigData()
+ .withTargetCapacity(0))));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void readClusterState_failIfNoFleet() {
+ when(ec2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(new DescribeSpotFleetRequestsResult());
+
+ FleetStateStats.readClusterState(ec2, "f", "");
+ }
+
+ @Test
+ public void readClusterState_returnFleetInfo() {
+ when(ec2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(new DescribeSpotFleetRequestsResult()
+ .withSpotFleetRequestConfigs(
+ new SpotFleetRequestConfig()
+ .withSpotFleetRequestState(BatchState.Active)
+ .withSpotFleetRequestConfig(
+ new SpotFleetRequestConfigData()
+ .withTargetCapacity(12))));
+
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f-id", "");
+
+ Assert.assertEquals("f-id", stats.getFleetId());
+ Assert.assertEquals("active", stats.getState());
+ Assert.assertEquals(12, stats.getNumDesired());
+ }
+
+ @Test
+ public void readClusterState_returnEmptyIfNoInstancesForFleet() {
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(Collections.emptySet(), stats.getInstances());
+ Assert.assertEquals(0, stats.getNumActive());
+ }
+
+ @Test
+ public void readClusterState_returnAllDescribedInstancesForFleet() {
+ when(ec2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(new DescribeSpotFleetInstancesResult()
+ .withActiveInstances(
+ new ActiveInstance().withInstanceId("i-1"),
+ new ActiveInstance().withInstanceId("i-2")));
+
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(ImmutableSet.of("i-1", "i-2"), stats.getInstances());
+ Assert.assertEquals(2, stats.getNumActive());
+ verify(ec2).describeSpotFleetInstances(new DescribeSpotFleetInstancesRequest()
+ .withSpotFleetRequestId("f"));
+ }
+
+ @Test
+ public void readClusterState_returnAllPagesDescribedInstancesForFleet() {
+ when(ec2.describeSpotFleetInstances(any(DescribeSpotFleetInstancesRequest.class)))
+ .thenReturn(new DescribeSpotFleetInstancesResult()
+ .withNextToken("p1")
+ .withActiveInstances(new ActiveInstance().withInstanceId("i-1")))
+ .thenReturn(new DescribeSpotFleetInstancesResult()
+ .withActiveInstances(new ActiveInstance().withInstanceId("i-2")));
+
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(ImmutableSet.of("i-1", "i-2"), stats.getInstances());
+ Assert.assertEquals(2, stats.getNumActive());
+ verify(ec2).describeSpotFleetInstances(new DescribeSpotFleetInstancesRequest()
+ .withSpotFleetRequestId("f").withNextToken("p1"));
+ verify(ec2).describeSpotFleetInstances(new DescribeSpotFleetInstancesRequest()
+ .withSpotFleetRequestId("f"));
+ }
+
+ @Test
+ public void readClusterState_returnEmptyInstanceTypeWeightsIfNoInformation() {
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(Collections.emptyMap(), stats.getInstanceTypeWeights());
+ }
+
+ @Test
+ public void readClusterState_returnInstanceTypeWeightsFromLaunchSpecification() {
+ when(ec2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(new DescribeSpotFleetRequestsResult()
+ .withSpotFleetRequestConfigs(new SpotFleetRequestConfig()
+ .withSpotFleetRequestState(BatchState.Active)
+ .withSpotFleetRequestConfig(new SpotFleetRequestConfigData()
+ .withTargetCapacity(1)
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification().withInstanceType("t1").withWeightedCapacity(0.1),
+ new SpotFleetLaunchSpecification().withInstanceType("t2").withWeightedCapacity(12.0)))));
+
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(ImmutableMap.of("t1", 0.1, "t2", 12.0), stats.getInstanceTypeWeights());
+ }
+
+ @Test
+ public void readClusterState_returnInstanceTypeWeightsForLaunchSpecificationIfItHasIt() {
+ when(ec2.describeSpotFleetRequests(any(DescribeSpotFleetRequestsRequest.class)))
+ .thenReturn(new DescribeSpotFleetRequestsResult()
+ .withSpotFleetRequestConfigs(new SpotFleetRequestConfig()
+ .withSpotFleetRequestState(BatchState.Active)
+ .withSpotFleetRequestConfig(new SpotFleetRequestConfigData()
+ .withTargetCapacity(1)
+ .withLaunchSpecifications(
+ new SpotFleetLaunchSpecification().withInstanceType("t1"),
+ new SpotFleetLaunchSpecification().withWeightedCapacity(12.0)))));
+
+ FleetStateStats stats = FleetStateStats.readClusterState(ec2, "f", "");
+
+ Assert.assertEquals(Collections.emptyMap(), stats.getInstanceTypeWeights());
+ }
+
+}
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
index 99ed0e94..55371912 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/ProvisionIntegrationTest.java
@@ -20,7 +20,6 @@
import hudson.model.queue.QueueTaskFuture;
import hudson.slaves.ComputerConnector;
import hudson.slaves.ComputerLauncher;
-import jenkins.model.Jenkins;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
@@ -50,7 +49,7 @@ public void dont_provide_any_planned_if_empty_and_reached_max_capacity() throws
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 0, 1, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
@@ -93,7 +92,7 @@ public void should_add_planned_if_capacity_required_but_not_described_yet() thro
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 10, 1, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
mockEc2ApiToDescribeFleetNotInstanceWhenModified();
@@ -125,7 +124,7 @@ public void should_keep_planned_node_until_node_will_not_be_online_so_jenkins_wi
EC2FleetCloud cloud = spy(new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 10, 1, false, false,
- false, 300, 15));
+ false, 300, 15, false));
j.jenkins.clouds.add(cloud);
mockEc2ApiToDescribeInstancesWhenModified(InstanceStateName.Running);
@@ -151,7 +150,7 @@ public void should_not_keep_planned_node_if_configured_so_jenkins_will_overprovi
final EC2FleetCloud cloud = spy(new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 10, 1, false, false,
- false, 0, 0));
+ false, 0, 0, false));
j.jenkins.clouds.add(cloud);
mockEc2ApiToDescribeInstancesWhenModified(InstanceStateName.Running);
@@ -176,7 +175,7 @@ public void should_not_allow_jenkins_to_provision_if_address_not_available() thr
EC2FleetCloud cloud = spy(new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 10, 1, false, false,
- false, 0, 0));
+ false, 0, 0, false));
j.jenkins.clouds.add(cloud);
EC2Api ec2Api = mock(EC2Api.class);
@@ -228,7 +227,7 @@ public void should_not_convert_planned_to_node_if_state_is_not_running_and_check
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, "region",
null, "fId", "momo", null, computerConnector, false, false,
0, 0, 10, 1, true, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
mockEc2ApiToDescribeInstancesWhenModified(InstanceStateName.Pending);
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
index 8456e2b1..fb051f15 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/RealEc2ApiIntegrationTest.java
@@ -51,7 +51,7 @@ public void run(AmazonEC2 amazonEC2, String fleetId) throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud("", "credId", null, null, null, fleetId,
null, null, null, false, false,
0, 0, 0, 0, false, false,
- false,0, 0);
+ false,0, 0, false);
j.jenkins.clouds.add(cloud);
// 10 sec refresh time so wait
@@ -84,7 +84,7 @@ public void run(AmazonEC2 amazonEC2, String fleetId) throws Exception {
EC2FleetCloud cloud = new EC2FleetCloud(null, "credId", null, null, null, fleetId,
null, null, null, false, false,
0, 0, 0, 0, false, false,
- false,0, 0);
+ false,0, 0, false);
j.jenkins.clouds.add(cloud);
final long start = System.currentTimeMillis();
diff --git a/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java b/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
index 091f0794..7f7357ca 100644
--- a/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
+++ b/src/test/java/com/amazon/jenkins/ec2fleet/UiIntegrationTest.java
@@ -45,7 +45,7 @@ public void shouldShowInConfigurationClouds() throws IOException, SAXException {
Cloud cloud = new EC2FleetCloud(null, null, null, null, null, null,
null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -59,13 +59,13 @@ public void shouldShowMultipleClouds() throws IOException, SAXException {
Cloud cloud1 = new EC2FleetCloud("a", null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud1);
Cloud cloud2 = new EC2FleetCloud("b", null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -82,13 +82,13 @@ public void shouldShowMultipleCloudsWithDefaultName() throws IOException, SAXExc
Cloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud1);
Cloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -105,13 +105,13 @@ public void shouldUpdateProperCloudWhenMultiple() throws IOException, SAXExcepti
EC2FleetCloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud2);
HtmlPage page = j.createWebClient().goTo("configure");
@@ -130,13 +130,13 @@ public void shouldGetFirstWhenMultipleCloudWithSameName() {
EC2FleetCloud cloud1 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud(null, null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud2);
assertSame(cloud1, j.jenkins.getCloud("FleetCloud"));
@@ -147,13 +147,13 @@ public void shouldGetProperWhenMultipleWithDiffName() {
EC2FleetCloud cloud1 = new EC2FleetCloud("a", null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud1);
EC2FleetCloud cloud2 = new EC2FleetCloud("b", null, null, null, null,
null, null, null, null, false, false,
0, 0, 0, 0, false, false,
- false, 0, 0);
+ false, 0, 0, false);
j.jenkins.clouds.add(cloud2);
assertSame(cloud1, j.jenkins.getCloud("a"));
From 78a5f5da2b0cfe5bac3c0862141f1c9f3fb52903 Mon Sep 17 00:00:00 2001
From: Artem Stasiuk
Date: Wed, 3 Jul 2019 18:34:24 -0700
Subject: [PATCH 3/4] Trigger build
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 6f2cb36a..e23d79b0 100644
--- a/README.md
+++ b/README.md
@@ -187,6 +187,7 @@ jenkins.clouds.add(ec2FleetCloud)
jenkins.save()
```
+
# Development
Plugin usage statistic per Jenkins version [here](https://stats.jenkins.io/pluginversions/ec2-fleet.html)
From 5f2791f3bf83462b4e139d51c16edc12bc51dad6 Mon Sep 17 00:00:00 2001
From: Artem Stasiuk
Date: Wed, 3 Jul 2019 18:43:41 -0700
Subject: [PATCH 4/4] Trigger build
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index e23d79b0..6f2cb36a 100644
--- a/README.md
+++ b/README.md
@@ -187,7 +187,6 @@ jenkins.clouds.add(ec2FleetCloud)
jenkins.save()
```
-
# Development
Plugin usage statistic per Jenkins version [here](https://stats.jenkins.io/pluginversions/ec2-fleet.html)