Skip to content

Commit a0d67cf

Browse files
authored
Fix cloud tracking (#383)
* Removing a recently added integ test (need some refactoring to make it work) * Added a warning to cloud name description to prevent users from modifying it * Deleting files related to cloud instance tracking and reassignments * [fix] Remove references of oldId and EC2FleetCloudAware class, remove tracking of cloud instance [refactor] Added instanceId to FleetNode for clarity, added getDescriptor to return sub type [refactor] Dont provision if Jenkins is quieting down and terminating Fix #360 Fix #322
1 parent bb2c33d commit a0d67cf

27 files changed

+311
-702
lines changed

src/main/java/com/amazon/jenkins/ec2fleet/AbstractEC2FleetCloud.java

-4
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,4 @@ protected AbstractEC2FleetCloud(String name) {
1717
public abstract boolean hasExcessCapacity();
1818

1919
public abstract boolean scheduleToTerminate(String instanceId, boolean ignoreMinConstraints, EC2AgentTerminationReason reason);
20-
21-
public abstract String getOldId();
22-
23-
public abstract String getFleet();
2420
}

src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloud.java

+37-44
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.amazon.jenkins.ec2fleet.aws.RegionHelper;
55
import com.amazon.jenkins.ec2fleet.fleet.EC2Fleet;
66
import com.amazon.jenkins.ec2fleet.fleet.EC2Fleets;
7-
import com.amazon.jenkins.ec2fleet.utils.EC2FleetCloudAwareUtils;
87
import com.amazonaws.services.ec2.AmazonEC2;
98
import com.amazonaws.services.ec2.model.Instance;
109
import com.amazonaws.services.ec2.model.InstanceStateName;
@@ -13,6 +12,7 @@
1312
import hudson.Extension;
1413
import hudson.model.Computer;
1514
import hudson.model.Descriptor;
15+
import hudson.model.Failure;
1616
import hudson.model.Label;
1717
import hudson.model.Node;
1818
import hudson.model.Queue;
@@ -86,25 +86,6 @@ public class EC2FleetCloud extends AbstractEC2FleetCloud {
8686
private static final Logger LOGGER = Logger.getLogger(EC2FleetCloud.class.getName());
8787
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
8888

89-
// Counter to keep track of planned nodes per EC2FleetCloud, used in node's display name
90-
private transient AtomicInteger plannedNodeCounter = new AtomicInteger(1);
91-
92-
/**
93-
* Provide unique identifier for this instance of {@link EC2FleetCloud}, <code>transient</code>
94-
* will not be stored. Not available for customer, instead use {@link EC2FleetCloud#name}
95-
* will be used only during Jenkins configuration update <code>config.jelly</code>,
96-
* when new instance of same cloud is created and we need to find old instance and
97-
* repoint resources like {@link Computer} {@link Node} etc.
98-
* <p>
99-
* It's lazy to support old versions which don't have this field at all.
100-
* <p>
101-
* However it's stable, as soon as it will be created and called first uuid will be same
102-
* for all future calls to the same instances of lazy uuid.
103-
*
104-
* @see EC2FleetCloudAware
105-
*/
106-
private transient LazyUuid id;
107-
10889
/**
10990
* Replaced with {@link EC2FleetCloud#awsCredentialsId}
11091
* <p>
@@ -178,9 +159,11 @@ public class EC2FleetCloud extends AbstractEC2FleetCloud {
178159

179160
private transient ArrayList<ScheduledFuture<?>> plannedNodeScheduledFutures;
180161

162+
// Counter to keep track of planned nodes per EC2FleetCloud, used in node's display name
163+
private transient AtomicInteger plannedNodeCounter = new AtomicInteger(1);
164+
181165
@DataBoundConstructor
182166
public EC2FleetCloud(final String name,
183-
final String oldId,
184167
final String awsCredentialsId,
185168
final @Deprecated String credentialsId,
186169
final String region,
@@ -238,8 +221,6 @@ public EC2FleetCloud(final String name,
238221
if (fleet != null) {
239222
this.stats = EC2Fleets.get(fleet).getState(
240223
getAwsCredentialsId(), region, endpoint, getFleet());
241-
// Reassign existing nodes/computer with new reference of cloud
242-
EC2FleetCloudAwareUtils.reassign(fleet, this);
243224
}
244225
}
245226

@@ -259,16 +240,6 @@ public String getAwsCredentialsId() {
259240
return StringUtils.isNotBlank(awsCredentialsId) ? awsCredentialsId : credentialsId;
260241
}
261242

262-
/**
263-
* Called old as will be used by new instance of cloud, for
264-
* which this id is old (not current)
265-
*
266-
* @return id of current cloud
267-
*/
268-
public String getOldId() {
269-
return id.getValue();
270-
}
271-
272243
public boolean isDisableTaskResubmit() {
273244
return disableTaskResubmit;
274245
}
@@ -298,7 +269,6 @@ public String getEndpoint() {
298269
return endpoint;
299270
}
300271

301-
@Override
302272
public String getFleet() {
303273
return fleet;
304274
}
@@ -419,6 +389,15 @@ private synchronized int getNextPlannedNodeCounter() {
419389

420390
@Override
421391
public synchronized Collection<NodeProvisioner.PlannedNode> provision(@Nonnull final Cloud.CloudState cloudState, final int excessWorkload) {
392+
Jenkins jenkinsInstance = Jenkins.get();
393+
if (jenkinsInstance.isQuietingDown()) {
394+
LOGGER.log(Level.FINE, "Not provisioning nodes, Jenkins instance is quieting down");
395+
return Collections.emptyList();
396+
} else if (jenkinsInstance.isTerminating()) {
397+
LOGGER.log(Level.FINE, "Not provisioning nodes, Jenkins instance is terminating");
398+
return Collections.emptyList();
399+
}
400+
422401
fine("excessWorkload %s", excessWorkload);
423402

424403
if (stats == null) {
@@ -469,6 +448,7 @@ public synchronized Collection<NodeProvisioner.PlannedNode> provision(@Nonnull f
469448
// This protects us from leaving planned nodes stranded within Jenkins NodeProvisioner when the Fleet
470449
// is updated or removed before it can scale. After scaling, EC2FleetOnlineChecker will cancel the future
471450
// if something happens to the Fleet.
451+
// TODO: refactor to consolidate logic with EC2FleetOnlineChecker
472452
final ScheduledFuture<?> scheduledFuture = EXECUTOR.schedule(() -> {
473453
if (completableFuture.isDone()) {
474454
return;
@@ -644,7 +624,7 @@ public void run() {
644624

645625
final Set<String> jenkinsInstances = new HashSet<>();
646626
for (final Node node : jenkins.getNodes()) {
647-
if (node instanceof EC2FleetNode && ((EC2FleetNode) node).getCloud().getFleet().equals(fleet)) {
627+
if (node instanceof EC2FleetNode && ((EC2FleetCloud)((EC2FleetNode) node).getCloud()).getFleet().equals(fleet)) {
648628
jenkinsInstances.add(node.getNodeName());
649629
}
650630
}
@@ -776,7 +756,6 @@ public synchronized boolean scheduleToTerminate(final String instanceId, final b
776756
@Override
777757
public boolean canProvision(final Cloud.CloudState cloudState) {
778758
final Label label = cloudState.getLabel();
779-
fine("CanProvision called on fleet: \"" + this.labelString + "\" wanting: \"" + (label == null ? "(unspecified)" : label.getName()) + "\".");
780759
if (fleet == null) {
781760
fine("Fleet/ASG for cloud is null, returning false");
782761
return false;
@@ -786,7 +765,7 @@ public boolean canProvision(final Cloud.CloudState cloudState) {
786765
return false;
787766
}
788767
if (label != null && !Label.parse(this.labelString).containsAll(label.listAtoms())) {
789-
fine("Label '%s' not found within Fleet's labels '%s', returning false", label, this.labelString);
768+
finer("Label '%s' not found within Fleet's labels '%s', returning false", label, this.labelString);
790769
return false;
791770
}
792771
return true;
@@ -798,8 +777,6 @@ private Object readResolve() {
798777
}
799778

800779
private void init() {
801-
id = new LazyUuid();
802-
803780
plannedNodesCache = new HashSet<>();
804781
instanceIdsToTerminate = new HashMap<>();
805782
plannedNodeScheduledFutures = new ArrayList<>();
@@ -864,7 +841,7 @@ private void addNewAgent(final AmazonEC2 ec2, final Instance instance, FleetStat
864841
final Node.Mode nodeMode = restrictUsage ? Node.Mode.EXCLUSIVE : Node.Mode.NORMAL;
865842
final EC2FleetNode node = new EC2FleetNode(instanceId, "Fleet agent for " + instanceId,
866843
effectiveFsRoot, effectiveNumExecutors, nodeMode, labelString, new ArrayList<NodeProperty<?>>(),
867-
this, computerLauncher, maxTotalUses);
844+
this.name, computerLauncher, maxTotalUses);
868845

869846
// Initialize our retention strategy
870847
node.setRetentionStrategy(new EC2RetentionStrategy());
@@ -905,7 +882,7 @@ private int getCurrentSpareInstanceCount(final FleetStateStats currentState, fin
905882
}
906883

907884
// Do not count computer if it is not a part of the given fleet
908-
if (!Objects.equals(((EC2FleetNodeComputer) computer).getCloud().getFleet(), currentState.getFleetId())) {
885+
if (!Objects.equals(((EC2FleetCloud)((EC2FleetNodeComputer) computer).getCloud()).getFleet(), currentState.getFleetId())) {
909886
continue;
910887
}
911888
currentBusyInstances++;
@@ -928,6 +905,10 @@ private void fine(final String msg, final Object... args) {
928905
LOGGER.fine(getLogPrefix() + String.format(msg, args));
929906
}
930907

908+
private void finer(final String msg, final Object... args) {
909+
LOGGER.finer(getLogPrefix() + String.format(msg, args));
910+
}
911+
931912
private void warning(final String msg, final Object... args) {
932913
LOGGER.warning(getLogPrefix() + String.format(msg, args));
933914
}
@@ -936,6 +917,11 @@ private void warning(final Throwable t, final String msg, final Object... args)
936917
LOGGER.log(Level.WARNING, getLogPrefix() + String.format(msg, args), t);
937918
}
938919

920+
@Override
921+
public DescriptorImpl getDescriptor() {
922+
return (DescriptorImpl) super.getDescriptor();
923+
}
924+
939925
@Extension
940926
@SuppressWarnings("unused")
941927
public static class DescriptorImpl extends Descriptor<Cloud> {
@@ -972,6 +958,15 @@ public FormValidation doCheckMaxTotalUses(@QueryParameter String value) {
972958
return FormValidation.error("Maximum Total Uses must be greater or equal to -1");
973959
}
974960

961+
public FormValidation doCheckCloudName(@QueryParameter final String name) {
962+
try {
963+
Jenkins.checkGoodName(name);
964+
} catch (Failure e) {
965+
return FormValidation.error(e.getMessage());
966+
}
967+
return FormValidation.ok();
968+
}
969+
975970
public ListBoxModel doFillFleetItems(@QueryParameter final boolean showAllFleets,
976971
@QueryParameter final String region,
977972
@QueryParameter final String endpoint,
@@ -985,7 +980,7 @@ public ListBoxModel doFillFleetItems(@QueryParameter final boolean showAllFleets
985980
awsCredentialsId, region, endpoint, model, fleet, showAllFleets);
986981
}
987982
} catch (final Exception ex) {
988-
LOGGER.log(Level.WARNING, String.format("Cannot describe fleets in %s or by endpoint %s", region, endpoint), ex);
983+
LOGGER.log(Level.WARNING, String.format("Cannot describe fleets in '%s' or by endpoint '%s'", region, endpoint), ex);
989984
return model;
990985
}
991986

@@ -1026,7 +1021,5 @@ public boolean configure(final StaplerRequest req, final JSONObject formData) th
10261021
save();
10271022
return super.configure(req, formData);
10281023
}
1029-
10301024
}
1031-
10321025
}

src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetCloudAware.java

-23
This file was deleted.

src/main/java/com/amazon/jenkins/ec2fleet/EC2FleetLabelCloud.java

+15-43
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.amazon.jenkins.ec2fleet.aws.RegionHelper;
77
import com.amazon.jenkins.ec2fleet.fleet.EC2Fleets;
88
import com.amazon.jenkins.ec2fleet.fleet.EC2SpotFleet;
9-
import com.amazon.jenkins.ec2fleet.utils.EC2FleetCloudAwareUtils;
109
import com.amazonaws.services.cloudformation.AmazonCloudFormation;
1110
import com.amazonaws.services.cloudformation.model.StackStatus;
1211
import com.amazonaws.services.ec2.AmazonEC2;
@@ -16,7 +15,6 @@
1615
import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsHelper;
1716
import hudson.Extension;
1817
import hudson.model.AbstractProject;
19-
import hudson.model.Computer;
2018
import hudson.model.Descriptor;
2119
import hudson.model.Item;
2220
import hudson.model.Label;
@@ -75,22 +73,6 @@ public class EC2FleetLabelCloud extends AbstractEC2FleetCloud {
7573
private static final SimpleFormatter sf = new SimpleFormatter();
7674
private static final Logger LOGGER = Logger.getLogger(EC2FleetLabelCloud.class.getName());
7775

78-
/**
79-
* Provide unique identifier for this instance of {@link EC2FleetLabelCloud}, <code>transient</code>
80-
* will not be stored. Not available for customer, instead use {@link EC2FleetLabelCloud#name}
81-
* will be used only during Jenkins configuration update <code>config.jelly</code>,
82-
* when new instance of same cloud is created and we need to find old instance and
83-
* repoint resources like {@link Computer} {@link Node} etc.
84-
* <p>
85-
* It's lazy to support old versions which don't have this field at all.
86-
* <p>
87-
* However it's stable, as soon as it will be created and called first uuid will be same
88-
* for all future calls to the same instances of lazy uuid.
89-
*
90-
* @see EC2FleetCloudAware
91-
*/
92-
private transient LazyUuid id;
93-
9476
private final String awsCredentialsId;
9577
private final String region;
9678
private final String endpoint;
@@ -123,7 +105,6 @@ public class EC2FleetLabelCloud extends AbstractEC2FleetCloud {
123105

124106
@DataBoundConstructor
125107
public EC2FleetLabelCloud(final String name,
126-
final String oldId,
127108
final String awsCredentialsId,
128109
final String region,
129110
final String endpoint,
@@ -162,12 +143,6 @@ public EC2FleetLabelCloud(final String name,
162143
this.cloudStatusIntervalSec = cloudStatusIntervalSec;
163144
this.noDelayProvision = noDelayProvision;
164145
this.ec2KeyPairName = ec2KeyPairName;
165-
166-
if (StringUtils.isNotEmpty(oldId)) {
167-
// existent cloud was modified, let's re-assign all dependencies of old cloud instance
168-
// to new one
169-
EC2FleetCloudAwareUtils.reassign(oldId, this);
170-
}
171146
}
172147

173148
public String getEc2KeyPairName() {
@@ -182,22 +157,6 @@ public String getAwsCredentialsId() {
182157
return awsCredentialsId;
183158
}
184159

185-
/**
186-
* Called old as will be used by new instance of cloud, for
187-
* which this id is old (not current)
188-
*
189-
* @return id of current cloud
190-
*/
191-
public String getOldId() {
192-
return id.getValue();
193-
}
194-
195-
@Override
196-
public String getFleet() {
197-
// TODO: We need a way to map existing node/computer's cloud reference rather than relying on oldId
198-
return null;
199-
}
200-
201160
public boolean isDisableTaskResubmit() {
202161
return disableTaskResubmit;
203162
}
@@ -295,6 +254,15 @@ public synchronized boolean hasExcessCapacity() {
295254

296255
@Override
297256
public synchronized Collection<NodeProvisioner.PlannedNode> provision(@Nonnull final Cloud.CloudState cloudState, int excessWorkload) {
257+
Jenkins jenkinsInstance = Jenkins.get();
258+
if (jenkinsInstance.isQuietingDown()) {
259+
LOGGER.log(Level.FINE, "Not provisioning nodes, Jenkins instance is quieting down");
260+
return Collections.emptyList();
261+
} else if (jenkinsInstance.isTerminating()) {
262+
LOGGER.log(Level.FINE, "Not provisioning nodes, Jenkins instance is terminating");
263+
return Collections.emptyList();
264+
}
265+
298266
info("excessWorkload %s", excessWorkload);
299267

300268
final Label label = cloudState.getLabel();
@@ -608,7 +576,6 @@ private Object readResolve() {
608576
}
609577

610578
private void init() {
611-
id = new LazyUuid();
612579
states = new HashMap<>();
613580
}
614581

@@ -653,7 +620,7 @@ private void addNewAgent(
653620
//TODO: Add maxTotalUses to EC2FleetLabelCloud similar to EC2FleetCloud
654621
final EC2FleetNode node = new EC2FleetNode(instanceId, "Fleet agent for " + instanceId,
655622
effectiveFsRoot, effectiveNumExecutors, nodeMode, labelString, new ArrayList<NodeProperty<?>>(),
656-
this, computerLauncher, -1);
623+
this.name, computerLauncher, -1);
657624

658625
// Initialize our retention strategy
659626
node.setRetentionStrategy(new EC2RetentionStrategy());
@@ -812,6 +779,11 @@ public void run() {
812779
}
813780
}
814781

782+
@Override
783+
public EC2FleetLabelCloud.DescriptorImpl getDescriptor() {
784+
return (EC2FleetLabelCloud.DescriptorImpl) super.getDescriptor();
785+
}
786+
815787
@Extension
816788
@SuppressWarnings("unused")
817789
public static class DescriptorImpl extends Descriptor<Cloud> {

0 commit comments

Comments
 (0)