Skip to content

Commit

Permalink
Merge pull request #637 from Vlatombe/JENKINS-60055
Browse files Browse the repository at this point in the history
[JENKINS-60055] NoDelayProvisionerStrategy needs to call CloudProvisionerListener
  • Loading branch information
Vlatombe committed Nov 7, 2019
2 parents 6dbed93 + 902edae commit 8972a75
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import hudson.model.Label;
import hudson.model.LoadStatistics;
import hudson.slaves.Cloud;
import hudson.slaves.CloudProvisioningListener;
import hudson.slaves.NodeProvisioner;
import jenkins.model.Jenkins;
import org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud;
Expand Down Expand Up @@ -52,11 +53,17 @@ public NodeProvisioner.StrategyDecision apply(NodeProvisioner.StrategyState stra
List<Cloud> jenkinsClouds = new ArrayList<>(Jenkins.get().clouds);
Collections.shuffle(jenkinsClouds);
for (Cloud cloud : jenkinsClouds) {
int workloadToProvision = currentDemand - availableCapacity;
if (!(cloud instanceof KubernetesCloud)) continue;
if (!cloud.canProvision(label)) continue;

Collection<NodeProvisioner.PlannedNode> plannedNodes = cloud.provision(label, currentDemand - availableCapacity);
for (CloudProvisioningListener cl : CloudProvisioningListener.all()) {
if (cl.canProvision(cloud, strategyState.getLabel(), workloadToProvision) != null) {
continue;
}
}
Collection<NodeProvisioner.PlannedNode> plannedNodes = cloud.provision(label, workloadToProvision);
LOGGER.log(Level.FINE, "Planned {0} new nodes", plannedNodes.size());
fireOnStarted(cloud, strategyState.getLabel(), plannedNodes);
strategyState.recordPendingLaunches(plannedNodes);
availableCapacity += plannedNodes.size();
LOGGER.log(Level.FINE, "After provisioning, available capacity={0}, currentDemand={1}", new Object[]{availableCapacity, currentDemand});
Expand All @@ -72,4 +79,18 @@ public NodeProvisioner.StrategyDecision apply(NodeProvisioner.StrategyState stra
}
}

}
private static void fireOnStarted(final Cloud cloud, final Label label,
final Collection<NodeProvisioner.PlannedNode> plannedNodes) {
for (CloudProvisioningListener cl : CloudProvisioningListener.all()) {
try {
cl.onStarted(cloud, label, plannedNodes);
} catch (Error e) {
throw e;
} catch (Throwable e) {
LOGGER.log(Level.SEVERE, "Unexpected uncaught exception encountered while "
+ "processing onStarted() listener call in " + cl + " for label "
+ label.toString(), e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.csanchez.jenkins.plugins.kubernetes.pipeline;

import hudson.ExtensionList;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.queue.CauseOfBlockage;
import hudson.slaves.Cloud;
import hudson.slaves.CloudProvisioningListener;
import hudson.slaves.NodeProvisioner;
import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.jvnet.hudson.test.TestExtension;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.verification.VerificationMode;

import javax.annotation.Nonnull;
import java.util.Collection;

import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.deletePods;
import static org.csanchez.jenkins.plugins.kubernetes.KubernetesTestUtil.getLabels;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class NoDelayProvisionerStrategyTest extends AbstractKubernetesPipelineTest {
@Mock
CloudProvisioningListener cloudProvisioningListener;

@Before
public void setUp() throws Exception {
CloudProvisionerListenerImpl instance = ExtensionList.lookupSingleton(CloudProvisionerListenerImpl.class);
instance.setDelegate(cloudProvisioningListener);
deletePods(cloud.connect(), getLabels(cloud, this, name), false);
assertNotNull(createJobThenScheduleRun());
}

@TestExtension
public static class CloudProvisionerListenerImpl extends CloudProvisioningListener {
private CloudProvisioningListener delegate;

public void setDelegate(CloudProvisioningListener delegate) {
this.delegate = delegate;
}

@Override
public void onStarted(Cloud cloud, Label label, Collection<NodeProvisioner.PlannedNode> plannedNodes) {
delegate.onStarted(cloud, label, plannedNodes);
}

@Override
public void onComplete(NodeProvisioner.PlannedNode plannedNode, Node node) {
delegate.onComplete(plannedNode, node);
}

@Override
public void onCommit(@Nonnull NodeProvisioner.PlannedNode plannedNode, @Nonnull Node node) {
delegate.onCommit(plannedNode, node);
}

@Override
public void onFailure(NodeProvisioner.PlannedNode plannedNode, Throwable t) {
delegate.onFailure(plannedNode, t);
}

@Override
public void onRollback(@Nonnull NodeProvisioner.PlannedNode plannedNode, @Nonnull Node node, @Nonnull Throwable t) {
delegate.onRollback(plannedNode, node, t);
}

@Override
public CauseOfBlockage canProvision(Cloud cloud, Label label, int numExecutors) {
return delegate.canProvision(cloud, label, numExecutors);
}
}

@Test
public void noDelayProvisionerCallsListener() throws Exception {
when(cloudProvisioningListener.canProvision(any(Cloud.class), any(Label.class), anyInt())).thenReturn(null);
r.assertBuildStatusSuccess(r.waitForCompletion(b));
verify(cloudProvisioningListener, atLeastOnce()).onStarted(eq(cloud), any(), any());
verify(cloudProvisioningListener, atLeastOnce()).canProvision(any(Cloud.class), any(Label.class), anyInt());

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
podTemplate(containers: [
containerTemplate(name: 'busybox', image: 'busybox', ttyEnabled: true, command: '/bin/cat'),
]) {
node (POD_LABEL) {
stage('Run') {
container('busybox') {
sh 'echo foo'
}
}
}
}

0 comments on commit 8972a75

Please sign in to comment.