Skip to content

Commit ecb2419

Browse files
committed
implement a build cache for build watch events that come before bc events for bc creation, then trigger build job when bc arrives
1 parent 37c5bec commit ecb2419

File tree

5 files changed

+113
-4
lines changed

5 files changed

+113
-4
lines changed

src/main/java/io/fabric8/jenkins/openshiftsync/BuildConfigToJobMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public class BuildConfigToJobMapper {
5555

5656
public static FlowDefinition mapBuildConfigToFlow(BuildConfig bc)
5757
throws IOException {
58-
if (!OpenShiftUtils.isJenkinsBuildConfig(bc)) {
58+
if (!OpenShiftUtils.isPipelineStrategyBuildConfig(bc)) {
5959
return null;
6060
}
6161

src/main/java/io/fabric8/jenkins/openshiftsync/BuildConfigWatcher.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public void doRun() {
9999
e);
100100
}
101101
}
102+
// poke the BuildWatcher builds with no BC list and see if we
103+
// can create job
104+
// runs for premature builds
105+
BuildWatcher.flushBuildsWithNoBCList();
102106
}
103107
};
104108
}
@@ -139,6 +143,10 @@ public synchronized void eventReceived(Watcher.Action action,
139143
modifyEventToJenkinsJob(buildConfig);
140144
break;
141145
}
146+
// if bc event came after build events, let's
147+
// poke the BuildWatcher builds with no BC list to create job
148+
// runs
149+
BuildWatcher.flushBuildsWithNoBCList();
142150
} catch (Exception e) {
143151
logger.log(Level.WARNING, "Caught: " + e, e);
144152
}
@@ -163,7 +171,7 @@ private void updateJob(WorkflowJob job, InputStream jobStream,
163171
}
164172

165173
private void upsertJob(final BuildConfig buildConfig) throws Exception {
166-
if (isJenkinsBuildConfig(buildConfig)) {
174+
if (isPipelineStrategyBuildConfig(buildConfig)) {
167175
// sync on intern of name should guarantee sync on same actual obj
168176
synchronized (buildConfig.getMetadata().getUid().intern()) {
169177
ACL.impersonate(ACL.SYSTEM,
@@ -298,7 +306,7 @@ public Void call() throws Exception {
298306

299307
private synchronized void modifyEventToJenkinsJob(BuildConfig buildConfig)
300308
throws Exception {
301-
if (isJenkinsBuildConfig(buildConfig)) {
309+
if (isPipelineStrategyBuildConfig(buildConfig)) {
302310
upsertJob(buildConfig);
303311
return;
304312
}

src/main/java/io/fabric8/jenkins/openshiftsync/BuildWatcher.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.Collections;
3535
import java.util.Comparator;
3636
import java.util.HashMap;
37+
import java.util.HashSet;
3738
import java.util.List;
3839
import java.util.Map;
3940
import java.util.logging.Level;
@@ -55,6 +56,18 @@ public class BuildWatcher extends BaseWatcher implements Watcher<Build> {
5556
private static final Logger logger = Logger.getLogger(BuildWatcher.class
5657
.getName());
5758

59+
// the fabric8 classes like Build have equal/hashcode annotations that
60+
// should allow
61+
// us to index via the objects themselves;
62+
// now that listing interval is 5 minutes (used to be 10 seconds), we have
63+
// seen
64+
// timing windows where if the build watch events come before build config
65+
// watch events
66+
// when both are created in a simultaneous fashion, there is an up to 5
67+
// minute delay
68+
// before the job run gets kicked off
69+
private static final HashSet<Build> buildsWithNoBCList = new HashSet<Build>();
70+
5871
@SuppressFBWarnings("EI_EXPOSE_REP2")
5972
public BuildWatcher(String[] namespaces) {
6073
super(namespaces);
@@ -69,6 +82,11 @@ public void doRun() {
6982
logger.fine("No Openshift Token credential defined.");
7083
return;
7184
}
85+
// prior to finding new builds poke the BuildWatcher builds with
86+
// no BC list and see if we
87+
// can create job runs for premature builds we already know
88+
// about
89+
BuildWatcher.flushBuildsWithNoBCList();
7290
for (String namespace : namespaces) {
7391
try {
7492
logger.fine("listing Build resources");
@@ -113,6 +131,8 @@ public void start() {
113131
@SuppressFBWarnings("SF_SWITCH_NO_DEFAULT")
114132
@Override
115133
public synchronized void eventReceived(Action action, Build build) {
134+
if (!OpenShiftUtils.isPipelineStrategyBuild(build))
135+
return;
116136
try {
117137
switch (action) {
118138
case ADDED:
@@ -151,6 +171,8 @@ public int compare(Build b1, Build b2) {
151171
Map<BuildConfig, List<Build>> buildConfigBuildMap = new HashMap<>(
152172
items.size());
153173
for (Build b : items) {
174+
if (!OpenShiftUtils.isPipelineStrategyBuild(b))
175+
continue;
154176
String buildConfigName = b.getStatus().getConfig().getName();
155177
if (StringUtils.isEmpty(buildConfigName)) {
156178
continue;
@@ -163,6 +185,9 @@ public int compare(Build b1, Build b2) {
163185
.inNamespace(namespace).withName(buildConfigName)
164186
.get();
165187
if (bc == null) {
188+
// if the bc is not there via a REST get, then it is not
189+
// going to be, and we are not handling manual creation
190+
// of pipeline build objects, so don't bother with "no bc list"
166191
continue;
167192
}
168193
buildConfigMap.put(bcMapKey, bc);
@@ -185,11 +210,25 @@ public int compare(Build b1, Build b2) {
185210
}
186211
WorkflowJob job = getJobFromBuildConfig(bc);
187212
if (job == null) {
213+
List<Build> builds = buildConfigBuilds.getValue();
214+
for (Build b : builds) {
215+
logger.info("skipping listed new build "
216+
+ b.getMetadata().getName()
217+
+ " no job at this time");
218+
addBuildToNoBCList(b);
219+
}
188220
continue;
189221
}
190222
BuildConfigProjectProperty bcp = job
191223
.getProperty(BuildConfigProjectProperty.class);
192224
if (bcp == null) {
225+
List<Build> builds = buildConfigBuilds.getValue();
226+
for (Build b : builds) {
227+
logger.info("skipping listed new build "
228+
+ b.getMetadata().getName()
229+
+ " no prop at this time");
230+
addBuildToNoBCList(b);
231+
}
193232
continue;
194233
}
195234
List<Build> builds = buildConfigBuilds.getValue();
@@ -204,12 +243,20 @@ private static synchronized void modifyEventToJenkinsJobRun(Build build) {
204243
WorkflowJob job = getJobFromBuild(build);
205244
if (job != null) {
206245
cancelBuild(job, build);
246+
} else {
247+
removeBuildFromNoBCList(build);
207248
}
249+
} else {
250+
// see if any pre-BC cached builds can now be flushed
251+
flushBuildsWithNoBCList();
208252
}
209253
}
210254

211255
public static synchronized boolean addEventToJenkinsJobRun(Build build)
212256
throws IOException {
257+
// should have been caught upstack, but just in case since public method
258+
if (!OpenShiftUtils.isPipelineStrategyBuild(build))
259+
return false;
213260
BuildStatus status = build.getStatus();
214261
if (status != null) {
215262
if (isCancelled(status)) {
@@ -225,9 +272,48 @@ public static synchronized boolean addEventToJenkinsJobRun(Build build)
225272
if (job != null) {
226273
return triggerJob(job, build);
227274
}
275+
logger.info("skipping watch event for build "
276+
+ build.getMetadata().getName() + " no job at this time");
277+
addBuildToNoBCList(build);
228278
return false;
229279
}
230280

281+
public static synchronized void addBuildToNoBCList(Build build) {
282+
// should have been caught upstack, but just in case since public method
283+
if (!OpenShiftUtils.isPipelineStrategyBuild(build))
284+
return;
285+
buildsWithNoBCList.add(build);
286+
}
287+
288+
private static synchronized void removeBuildFromNoBCList(Build build) {
289+
buildsWithNoBCList.remove(build);
290+
}
291+
292+
private static synchronized void clearNoBCList() {
293+
buildsWithNoBCList.clear();
294+
}
295+
296+
// trigger any builds whose watch events arrived before the
297+
// corresponding build config watch events
298+
public static synchronized void flushBuildsWithNoBCList() {
299+
HashSet<Build> clone = (HashSet<Build>) buildsWithNoBCList.clone();
300+
clearNoBCList();
301+
for (Build build : clone) {
302+
WorkflowJob job = getJobFromBuild(build);
303+
if (job != null)
304+
try {
305+
logger.info("triggering job run for previously skipped build "
306+
+ build.getMetadata().getName());
307+
triggerJob(job, build);
308+
} catch (IOException e) {
309+
logger.log(Level.WARNING, "flushCachedBuilds", e);
310+
}
311+
else
312+
addBuildToNoBCList(build);
313+
}
314+
315+
}
316+
231317
// innerDeleteEventToJenkinsJobRun is the actual delete logic at the heart
232318
// of deleteEventToJenkinsJobRun
233319
// that is either in a sync block or not based on the presence of a BC uid
@@ -243,6 +329,10 @@ public Void call() throws Exception {
243329
return null;
244330
}
245331
});
332+
} else {
333+
// in case build was created and deleted quickly, prior to seeing BC
334+
// event, clear out from pre-BC cache
335+
removeBuildFromNoBCList(build);
246336
}
247337
}
248338

src/main/java/io/fabric8/jenkins/openshiftsync/JenkinsUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ public int compare(Build b1, Build b2) {
623623
boolean jobIsBuilding = job.isBuilding();
624624
for (int i = 0; i < builds.size(); i++) {
625625
Build b = builds.get(i);
626+
if (!OpenShiftUtils.isPipelineStrategyBuild(b))
627+
continue;
626628
// For SerialLatestOnly we should try to cancel all builds before
627629
// the latest one requested.
628630
if (isSerialLatestOnly) {

src/main/java/io/fabric8/jenkins/openshiftsync/OpenShiftUtils.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public synchronized static void shutdownOpenShiftClient() {
124124
* @return true if this is an OpenShift BuildConfig which should be mirrored
125125
* to a Jenkins Job
126126
*/
127-
public static boolean isJenkinsBuildConfig(BuildConfig bc) {
127+
public static boolean isPipelineStrategyBuildConfig(BuildConfig bc) {
128128
if (BuildConfigToJobMapper.JENKINS_PIPELINE_BUILD_STRATEGY
129129
.equalsIgnoreCase(bc.getSpec().getStrategy().getType())
130130
&& bc.getSpec().getStrategy().getJenkinsPipelineStrategy() != null) {
@@ -144,6 +144,15 @@ public static boolean isJenkinsBuildConfig(BuildConfig bc) {
144144
return false;
145145
}
146146

147+
public static boolean isPipelineStrategyBuild(Build b) {
148+
if (BuildConfigToJobMapper.JENKINS_PIPELINE_BUILD_STRATEGY
149+
.equalsIgnoreCase(b.getSpec().getStrategy().getType())
150+
&& b.getSpec().getStrategy().getJenkinsPipelineStrategy() != null) {
151+
return true;
152+
}
153+
return false;
154+
}
155+
147156
/**
148157
* Finds the Jenkins job name for the given {@link BuildConfig}.
149158
*

0 commit comments

Comments
 (0)