66import java .util .logging .Logger ;
77
88import edu .umd .cs .findbugs .annotations .NonNull ;
9+ import net .jcip .annotations .GuardedBy ;
910import org .kohsuke .accmod .Restricted ;
1011import org .kohsuke .accmod .restrictions .NoExternalUse ;
1112
2627public final class KubernetesProvisioningLimits {
2728 private static final Logger LOGGER = Logger .getLogger (KubernetesProvisioningLimits .class .getName ());
2829
30+ @ GuardedBy ("this" )
31+ private boolean init ;
32+
2933 /**
3034 * Tracks current number of kubernetes agents per pod template
3135 */
@@ -36,22 +40,26 @@ public final class KubernetesProvisioningLimits {
3640 */
3741 private final Map <String , Integer > cloudCounts = new HashMap <>();
3842
39- @ Initializer (after = InitMilestone .SYSTEM_CONFIG_LOADED )
40- public static void init () {
41- // We don't want anything to be provisioned while we do the initial count.
42- Queue .withLock (() -> {
43- final KubernetesProvisioningLimits instance = get ();
44- synchronized (instance ) {
43+ /**
44+ * Initialize limits counter
45+ * @return whether the instance was already initialized before this call.
46+ */
47+ private synchronized boolean initInstance () {
48+ boolean previousInit = init ;
49+ if (!init ) {
50+ Queue .withLock (() -> {
4551 Jenkins .get ().getNodes ()
4652 .stream ()
4753 .filter (KubernetesSlave .class ::isInstance )
4854 .map (KubernetesSlave .class ::cast )
4955 .forEach (node -> {
50- instance .cloudCounts .put (node .getCloudName (), instance .getGlobalCount (node .getCloudName ()) + node .getNumExecutors ());
51- instance .podTemplateCounts .put (node .getTemplateId (), instance .getPodTemplateCount (node .getTemplateId ()) + node .getNumExecutors ());
52- });
53- }
54- });
56+ cloudCounts .put (node .getCloudName (), getGlobalCount (node .getCloudName ()) + node .getNumExecutors ());
57+ podTemplateCounts .put (node .getTemplateId (), getPodTemplateCount (node .getTemplateId ()) + node .getNumExecutors ());
58+ });
59+ });
60+ init = true ;
61+ }
62+ return previousInit ;
5563 }
5664
5765 /**
@@ -68,6 +76,7 @@ public static KubernetesProvisioningLimits get() {
6876 * @param numExecutors the number of executors (pretty much always 1)
6977 */
7078 public synchronized boolean register (@ NonNull KubernetesCloud cloud , @ NonNull PodTemplate podTemplate , int numExecutors ) {
79+ initInstance ();
7180 int newGlobalCount = getGlobalCount (cloud .name ) + numExecutors ;
7281 if (newGlobalCount <= cloud .getContainerCap ()) {
7382 int newPodTemplateCount = getPodTemplateCount (podTemplate .getId ()) + numExecutors ;
@@ -96,19 +105,21 @@ public synchronized boolean register(@NonNull KubernetesCloud cloud, @NonNull Po
96105 * @param numExecutors the number of executors (pretty much always 1)
97106 */
98107 public synchronized void unregister (@ NonNull KubernetesCloud cloud , @ NonNull PodTemplate podTemplate , int numExecutors ) {
99- int newGlobalCount = getGlobalCount (cloud .name ) - numExecutors ;
100- if (newGlobalCount < 0 ) {
101- LOGGER .log (Level .WARNING , "Global count for " + cloud .name + " went below zero. There is likely a bug in kubernetes-plugin" );
102- }
103- cloudCounts .put (cloud .name , Math .max (0 , newGlobalCount ));
104- LOGGER .log (Level .FINEST , () -> cloud .name + " global limit: " + Math .max (0 , newGlobalCount ) + "/" + cloud .getContainerCap ());
108+ if (initInstance ()) {
109+ int newGlobalCount = getGlobalCount (cloud .name ) - numExecutors ;
110+ if (newGlobalCount < 0 ) {
111+ LOGGER .log (Level .WARNING , "Global count for " + cloud .name + " went below zero. There is likely a bug in kubernetes-plugin" );
112+ }
113+ cloudCounts .put (cloud .name , Math .max (0 , newGlobalCount ));
114+ LOGGER .log (Level .FINEST , () -> cloud .name + " global limit: " + Math .max (0 , newGlobalCount ) + "/" + cloud .getContainerCap ());
105115
106- int newPodTemplateCount = getPodTemplateCount (podTemplate .getId ()) - numExecutors ;
107- if (newPodTemplateCount < 0 ) {
108- LOGGER .log (Level .WARNING , "Pod template count for " + podTemplate .getName () + " went below zero. There is likely a bug in kubernetes-plugin" );
116+ int newPodTemplateCount = getPodTemplateCount (podTemplate .getId ()) - numExecutors ;
117+ if (newPodTemplateCount < 0 ) {
118+ LOGGER .log (Level .WARNING , "Pod template count for " + podTemplate .getName () + " went below zero. There is likely a bug in kubernetes-plugin" );
119+ }
120+ podTemplateCounts .put (podTemplate .getId (), Math .max (0 , newPodTemplateCount ));
121+ LOGGER .log (Level .FINEST , () -> podTemplate .getName () + " template limit: " + Math .max (0 , newPodTemplateCount ) + "/" + podTemplate .getInstanceCap ());
109122 }
110- podTemplateCounts .put (podTemplate .getId (), Math .max (0 , newPodTemplateCount ));
111- LOGGER .log (Level .FINEST , () -> podTemplate .getName () + " template limit: " + Math .max (0 , newPodTemplateCount ) + "/" + podTemplate .getInstanceCap ());
112123 }
113124
114125 @ NonNull
@@ -128,10 +139,11 @@ public static class NodeListenerImpl extends NodeListener {
128139 @ Override
129140 protected void onDeleted (@ NonNull Node node ) {
130141 if (node instanceof KubernetesSlave ) {
142+ KubernetesProvisioningLimits instance = KubernetesProvisioningLimits .get ();
131143 KubernetesSlave kubernetesNode = (KubernetesSlave ) node ;
132144 PodTemplate template = kubernetesNode .getTemplateOrNull ();
133145 if (template != null ) {
134- KubernetesProvisioningLimits . get () .unregister (kubernetesNode .getKubernetesCloud (), template , node .getNumExecutors ());
146+ instance .unregister (kubernetesNode .getKubernetesCloud (), template , node .getNumExecutors ());
135147 }
136148 }
137149 }
0 commit comments