Skip to content

Commit

Permalink
Add option to apply caps only on undead pods
Browse files Browse the repository at this point in the history
A pod can be in one of five phases: running, pending, succeeded, failed
or unknown. The pods which are not in the running/pending phase do not
consume any CPU/Memory resources, they just need to be GC'ed. If, in the
scenario when a cap has been specified on a k8s cloud (single namespace)
and let's say 40% of the count are in the 'failed' phase, and 60% are
'runnning/pending', newer pods will not be spawned in that namespace,
since the plugin will count all those pods for instance/pod cap and even
though it could have spawned 40% more pods, it won't and jobs will
starve. This patch adds an option to calculate the cap for pods only in
the 'running' or 'pending' phase, on a cloud level and on a pod template
level.
  • Loading branch information
nehaljwani committed Nov 19, 2017
1 parent 708821c commit dcb8b00
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -91,6 +92,8 @@ public class KubernetesCloud extends Cloud {

private boolean skipTlsVerify;

private boolean capOnlyOnUnDeadPods;

private String namespace;
private String jenkinsUrl;
@CheckForNull
Expand Down Expand Up @@ -220,6 +223,15 @@ public String getJenkinsUrl() {
return jenkinsUrl;
}

@DataBoundSetter
public void setCapOnlyOnUnDeadPods(boolean capOnlyOnUnDeadPods) {
this.capOnlyOnUnDeadPods = capOnlyOnUnDeadPods;
}

public boolean isCapOnlyOnUnDeadPods() {
return capOnlyOnUnDeadPods;
}

/**
* Returns Jenkins URL to be used by agents launched by this cloud. Always ends with a trailing slash.
*
Expand Down Expand Up @@ -424,6 +436,22 @@ private boolean addProvisionedSlave(@Nonnull PodTemplate template, @CheckForNull
PodList namedList = client.pods().inNamespace(templateNamespace).withLabels(labelsMap).list();
List<Pod> namedListItems = namedList.getItems();

if (this.isCapOnlyOnUnDeadPods()) {
slaveListItems = slaveListItems.stream()
.filter(x -> x.getStatus()
.getPhase().toLowerCase()
.matches("(running|pending)"))
.collect(Collectors.toList());
}

if (template.isCapOnlyOnUnDeadPods()) {
namedListItems = namedListItems.stream()
.filter(x -> x.getStatus()
.getPhase().toLowerCase()
.matches("(running|pending)"))
.collect(Collectors.toList());
}

if (slaveListItems != null && containerCap <= slaveListItems.size()) {
LOGGER.log(Level.INFO,
"Total container cap of {0} reached, not provisioning: {1} running or errored in namespace {2}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public class PodTemplate extends AbstractDescribableImpl<PodTemplate> implements

private boolean privileged;

private boolean capOnlyOnUnDeadPods;

private boolean alwaysPullImage;

private String command;
Expand Down Expand Up @@ -394,6 +396,15 @@ public boolean isAlwaysPullImage() {
return getFirstContainer().map(ContainerTemplate::isAlwaysPullImage).orElse(false);
}

@DataBoundSetter
public void setCapOnlyOnUnDeadPods(boolean capOnlyOnUnDeadPods) {
this.capOnlyOnUnDeadPods = capOnlyOnUnDeadPods;
}

public boolean isCapOnlyOnUnDeadPods() {
return capOnlyOnUnDeadPods;
}

public List<TemplateEnvVar> getEnvVars() {
if (envVars == null) {
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
<f:textbox default="10"/>
</f:entry>

<f:entry field="capOnlyOnUnDeadPods" title="${%Apply cap only on alive pods}">
<f:checkbox/>
</f:entry>

<f:entry title="${%Max connections to Kubernetes API}" field="maxRequestsPerHostStr">
<f:textbox default="32"/>
</f:entry>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
<f:textbox/>
</f:entry>

<f:entry field="capOnlyOnUnDeadPods" title="${%Apply cap only on alive pods}">
<f:checkbox/>
</f:entry>

<f:entry field="idleMinutesStr" title="${%Time in minutes to retain slave when idle}">
<f:textbox/>
</f:entry>
Expand Down

0 comments on commit dcb8b00

Please sign in to comment.