|
19 | 19 | import edu.umd.cs.findbugs.annotations.CheckForNull;
|
20 | 20 | import edu.umd.cs.findbugs.annotations.NonNull;
|
21 | 21 | import hudson.Util;
|
22 |
| -import hudson.model.Queue; |
| 22 | +import hudson.model.Label; |
23 | 23 | import io.fabric8.kubernetes.api.model.ContainerStatus;
|
24 | 24 | import io.fabric8.kubernetes.api.model.ObjectMeta;
|
25 | 25 | import io.fabric8.kubernetes.api.model.Pod;
|
26 | 26 | import io.fabric8.kubernetes.api.model.PodStatus;
|
27 | 27 | import io.fabric8.kubernetes.client.KubernetesClient;
|
28 | 28 | import io.fabric8.kubernetes.client.KubernetesClientException;
|
| 29 | +import java.util.Arrays; |
29 | 30 | import java.util.Collections;
|
30 | 31 | import java.util.List;
|
31 |
| -import java.util.Map; |
| 32 | +import java.util.Optional; |
32 | 33 | import java.util.function.Predicate;
|
33 | 34 | import java.util.logging.Level;
|
34 | 35 | import java.util.logging.Logger;
|
35 | 36 | import java.util.stream.Collectors;
|
36 | 37 | import jenkins.model.Jenkins;
|
37 | 38 | import org.apache.commons.lang.StringUtils;
|
| 39 | +import org.csanchez.jenkins.plugins.kubernetes.pipeline.PodTemplateStepExecution; |
38 | 40 |
|
39 | 41 | public final class PodUtils {
|
| 42 | + private PodUtils() {} |
| 43 | + |
40 | 44 | private static final Logger LOGGER = Logger.getLogger(PodUtils.class.getName());
|
41 | 45 |
|
42 | 46 | public static final Predicate<ContainerStatus> CONTAINER_IS_TERMINATED =
|
@@ -66,52 +70,56 @@ public static List<ContainerStatus> getContainers(Pod pod, Predicate<ContainerSt
|
66 | 70 | }
|
67 | 71 |
|
68 | 72 | /**
|
69 |
| - * Cancel queue items matching the given pod. |
70 |
| - * It uses the annotation "runUrl" added to the pod to do the matching. |
71 |
| - * |
72 |
| - * It uses the current thread context to list item queues, |
| 73 | + * <p>Cancel queue items matching the given pod. |
| 74 | + * <p>The queue item has to have a task url matching the pod "runUrl"-annotation |
| 75 | + * and the queue item assigned label needs to match the label jenkins/label of the pod. |
| 76 | + * <p>It uses the current thread context to list item queues, |
73 | 77 | * so make sure to be in the right context before calling this method.
|
74 | 78 | *
|
75 | 79 | * @param pod The pod to cancel items for.
|
76 | 80 | * @param reason The reason the item are being cancelled.
|
77 | 81 | */
|
78 | 82 | public static void cancelQueueItemFor(Pod pod, String reason) {
|
79 |
| - Queue q = Jenkins.get().getQueue(); |
80 |
| - boolean cancelled = false; |
81 |
| - ObjectMeta metadata = pod.getMetadata(); |
| 83 | + var metadata = pod.getMetadata(); |
82 | 84 | if (metadata == null) {
|
83 | 85 | return;
|
84 | 86 | }
|
85 |
| - Map<String, String> annotations = metadata.getAnnotations(); |
| 87 | + String podName = metadata.getName(); |
| 88 | + String podNamespace = metadata.getNamespace(); |
| 89 | + String podDisplayName = podNamespace + "/" + podName; |
| 90 | + var annotations = metadata.getAnnotations(); |
86 | 91 | if (annotations == null) {
|
87 |
| - LOGGER.log(Level.FINE, "Pod .metadata.annotations is null: {0}/{1}", new Object[] { |
88 |
| - metadata.getNamespace(), metadata.getName() |
89 |
| - }); |
| 92 | + LOGGER.log(Level.FINE, () -> "Pod " + podDisplayName + " .metadata.annotations is null"); |
90 | 93 | return;
|
91 | 94 | }
|
92 |
| - String runUrl = annotations.get("runUrl"); |
| 95 | + var runUrl = annotations.get(PodTemplateStepExecution.POD_ANNOTATION_RUN_URL); |
93 | 96 | if (runUrl == null) {
|
94 |
| - LOGGER.log(Level.FINE, "Pod .metadata.annotations.runUrl is null: {0}/{1}", new Object[] { |
95 |
| - metadata.getNamespace(), metadata.getName() |
96 |
| - }); |
| 97 | + LOGGER.log(Level.FINE, () -> "Pod " + podDisplayName + " .metadata.annotations.runUrl is null"); |
97 | 98 | return;
|
98 | 99 | }
|
99 |
| - for (Queue.Item item : q.getItems()) { |
100 |
| - Queue.Task task = item.task; |
101 |
| - if (runUrl.equals(task.getUrl())) { |
102 |
| - LOGGER.log(Level.FINE, "Cancelling queue item: \"{0}\"\n{1}", new Object[] { |
103 |
| - task.getDisplayName(), !StringUtils.isBlank(reason) ? "due to " + reason : "" |
104 |
| - }); |
105 |
| - q.cancel(item); |
106 |
| - cancelled = true; |
107 |
| - break; |
108 |
| - } |
109 |
| - } |
110 |
| - if (!cancelled) { |
111 |
| - LOGGER.log(Level.FINE, "No queue item found for pod: {0}/{1}", new Object[] { |
112 |
| - metadata.getNamespace(), metadata.getName() |
113 |
| - }); |
| 100 | + var labels = metadata.getLabels(); |
| 101 | + if (labels == null) { |
| 102 | + LOGGER.log(Level.FINE, () -> "Pod " + podDisplayName + " .metadata.labels is null"); |
| 103 | + return; |
114 | 104 | }
|
| 105 | + var jenkinsLabel = labels.get(PodTemplate.JENKINS_LABEL); |
| 106 | + var queue = Jenkins.get().getQueue(); |
| 107 | + Arrays.stream(queue.getItems()) |
| 108 | + .filter(item -> item.getTask().getUrl().equals(runUrl)) |
| 109 | + .filter(item -> Optional.ofNullable(item.getAssignedLabel()) |
| 110 | + .map(Label::getName) |
| 111 | + .map(name -> PodTemplateUtils.sanitizeLabel(name).equals(jenkinsLabel)) |
| 112 | + .orElse(false)) |
| 113 | + .findFirst() |
| 114 | + .ifPresentOrElse( |
| 115 | + item -> { |
| 116 | + LOGGER.log( |
| 117 | + Level.FINE, |
| 118 | + () -> "Cancelling queue item: \"" + item.task.getDisplayName() + "\"\n" |
| 119 | + + (!StringUtils.isBlank(reason) ? "due to " + reason : "")); |
| 120 | + queue.cancel(item); |
| 121 | + }, |
| 122 | + () -> LOGGER.log(Level.FINE, () -> "No queue item found for pod " + podDisplayName)); |
115 | 123 | }
|
116 | 124 |
|
117 | 125 | @CheckForNull
|
|
0 commit comments