@@ -10,8 +10,6 @@ import (
10
10
"reflect"
11
11
"strings"
12
12
13
- "github.com/pkg/errors"
14
-
15
13
corev1 "k8s.io/api/core/v1"
16
14
apierrors "k8s.io/apimachinery/pkg/api/errors"
17
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -36,10 +34,10 @@ import (
36
34
buildmetrics "github.com/shipwright-io/build/pkg/metrics"
37
35
)
38
36
39
- // succeedStatus default status for the Build CRD
40
- const succeedStatus string = "Succeeded "
41
- const namespace string = "namespace "
42
- const name string = "name"
37
+ const (
38
+ namespace string = "namespace "
39
+ name string = "name "
40
+ )
43
41
44
42
type setOwnerReferenceFunc func (owner , object metav1.Object , scheme * runtime.Scheme ) error
45
43
@@ -235,67 +233,60 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result,
235
233
236
234
// Populate the status struct with default values
237
235
b .Status .Registered = corev1 .ConditionFalse
238
- b .Status .Reason = succeedStatus
236
+ b .Status .Reason = build . SucceedStatus
239
237
240
238
// Validate if remote repository exists
241
239
if b .Spec .Source .SecretRef == nil {
242
240
if err := r .validateSourceURL (ctx , b , b .Spec .Source .URL ); err != nil {
243
- b .Status .Reason = err .Error ()
244
- if updateErr := r .client .Status ().Update (ctx , b ); updateErr != nil {
245
- return reconcile.Result {}, updateErr
246
- }
247
- return reconcile.Result {}, nil
241
+ MarkBuildStatus (b , build .RemoteRepositoryUnreachable , err .Error ())
242
+ return r .UpdateBuildStatusAndRetreat (ctx , b )
248
243
}
249
244
}
250
245
251
246
// Validate if the referenced secrets exist in the namespace
252
- var secretNames [] string
247
+ secretRefMap := map [ string ]build. BuildReason {}
253
248
if b .Spec .Output .SecretRef != nil && b .Spec .Output .SecretRef .Name != "" {
254
- secretNames = append ( secretNames , b .Spec .Output .SecretRef .Name )
249
+ secretRefMap [ b .Spec .Output .SecretRef .Name ] = build . SpecOutputSecretRefNotFound
255
250
}
256
251
if b .Spec .Source .SecretRef != nil && b .Spec .Source .SecretRef .Name != "" {
257
- secretNames = append ( secretNames , b .Spec .Source .SecretRef .Name )
252
+ secretRefMap [ b .Spec .Source .SecretRef .Name ] = build . SpecSourceSecretRefNotFound
258
253
}
259
254
if b .Spec .BuilderImage != nil && b .Spec .BuilderImage .SecretRef != nil && b .Spec .BuilderImage .SecretRef .Name != "" {
260
- secretNames = append ( secretNames , b .Spec .BuilderImage .SecretRef .Name )
255
+ secretRefMap [ b .Spec .BuilderImage .SecretRef .Name ] = build . SpecRuntimeSecretRefNotFound
261
256
}
262
257
263
- if len (secretNames ) > 0 {
264
- if err := r .validateSecrets (ctx , secretNames , b .Namespace ); err != nil {
265
- b .Status .Reason = err .Error ()
266
- if updateErr := r .client .Status ().Update (ctx , b ); updateErr != nil {
267
- // return an error in case of transient failure, and expect the next
268
- // reconciliation to be able to update the Status of the object
269
- return reconcile.Result {}, fmt .Errorf ("errors: %v %v" , err , updateErr )
270
- }
271
- // The Secret Resource watcher will Reconcile again once the missing
272
- // secret is created, therefore no need to return an error and enter on an infinite
273
- // reconciliation
274
- return reconcile.Result {}, nil
258
+ // Validate if the referenced secrets exist
259
+ if len (secretRefMap ) > 0 {
260
+ if err := r .validateSecrets (ctx , secretRefMap , b ); err != nil {
261
+ return reconcile.Result {}, err
262
+ }
263
+
264
+ if b .Status .Reason != build .SucceedStatus {
265
+ return r .UpdateBuildStatusAndRetreat (ctx , b )
275
266
}
276
267
}
277
268
278
- // Validate if the build strategy is defined
269
+ // Validate if the referenced strategy exists
279
270
if b .Spec .StrategyRef != nil {
280
- if err := r .validateStrategyRef (ctx , b .Spec .StrategyRef , b .Namespace ); err != nil {
281
- b .Status .Reason = err .Error ()
282
- updateErr := r .client .Status ().Update (ctx , b )
283
- return reconcile.Result {}, fmt .Errorf ("errors: %v %v" , err , updateErr )
271
+ if err := r .validateStrategyRef (ctx , b ); err != nil {
272
+ return reconcile.Result {}, err
273
+ }
274
+
275
+ if b .Status .Reason != build .SucceedStatus {
276
+ return r .UpdateBuildStatusAndRetreat (ctx , b )
284
277
}
285
278
ctxlog .Info (ctx , "buildStrategy found" , namespace , b .Namespace , name , b .Name , "strategy" , b .Spec .StrategyRef .Name )
286
279
}
287
280
288
- // validate if "spec.runtime" attributes are valid
281
+ // Validate "spec.runtime" attributes
289
282
if utils .IsRuntimeDefined (b ) {
290
- if err := r .validateRuntime (b .Spec .Runtime ); err != nil {
291
- ctxlog .Error (ctx , err , "failed validating runtime attributes" , "Build" , b .Name )
292
- b .Status .Reason = err .Error ()
293
- updateErr := r .client .Status ().Update (ctx , b )
294
- return reconcile.Result {}, fmt .Errorf ("errors: %v %v" , err , updateErr )
283
+ if r .validateRuntimeFailed (b ) {
284
+ return r .UpdateBuildStatusAndRetreat (ctx , b )
295
285
}
296
286
}
297
287
298
288
b .Status .Registered = corev1 .ConditionTrue
289
+ b .Status .Message = build .AllValidationsSucceeded
299
290
err = r .client .Status ().Update (ctx , b )
300
291
if err != nil {
301
292
return reconcile.Result {}, err
@@ -308,114 +299,85 @@ func (r *ReconcileBuild) Reconcile(request reconcile.Request) (reconcile.Result,
308
299
return reconcile.Result {}, nil
309
300
}
310
301
311
- func (r * ReconcileBuild ) validateRuntime (runtime * build.Runtime ) error {
312
- if len (runtime .Paths ) == 0 {
313
- return fmt .Errorf ("the property 'spec.runtime.paths' must not be empty" )
302
+ // UpdateBuildStatusAndRetreat returns an error if an update fails, this should force
303
+ // a new reconcile until the API call succeeds. If return is nil, no further reconciliations
304
+ // will take place
305
+ func (r * ReconcileBuild ) UpdateBuildStatusAndRetreat (ctx context.Context , b * build.Build ) (reconcile.Result , error ) {
306
+ if err := r .client .Status ().Update (ctx , b ); err != nil {
307
+ return reconcile.Result {}, err
314
308
}
315
- return nil
309
+ return reconcile. Result {}, nil
316
310
}
317
311
318
- func (r * ReconcileBuild ) validateStrategyRef (ctx context.Context , s * build.StrategyRef , ns string ) error {
319
- if s .Kind != nil {
320
- switch * s .Kind {
312
+ func (r * ReconcileBuild ) validateRuntimeFailed (b * build.Build ) bool {
313
+ if len (b .Spec .Runtime .Paths ) == 0 {
314
+ MarkBuildStatus (b , build .RuntimePathsCanNotBeEmpty , "the property 'spec.runtime.paths' must not be empty" )
315
+ return true
316
+ }
317
+ return false
318
+ }
319
+
320
+ func (r * ReconcileBuild ) validateStrategyRef (ctx context.Context , b * build.Build ) error {
321
+
322
+ if b .Spec .StrategyRef .Kind != nil {
323
+ switch * b .Spec .StrategyRef .Kind {
321
324
case build .NamespacedBuildStrategyKind :
322
- if err := r .validateBuildStrategy (ctx , s . Name , ns ); err != nil {
325
+ if err := r .validateBuildStrategy (ctx , b . Spec . StrategyRef . Name , b ); err != nil {
323
326
return err
324
327
}
325
328
case build .ClusterBuildStrategyKind :
326
- if err := r .validateClusterBuildStrategy (ctx , s . Name ); err != nil {
329
+ if err := r .validateClusterBuildStrategy (ctx , b . Spec . StrategyRef . Name , b ); err != nil {
327
330
return err
328
331
}
329
332
default :
330
- return fmt .Errorf ("unknown strategy %v" , * s .Kind )
333
+ return fmt .Errorf ("unknown strategy kind: %v" , * b . Spec . StrategyRef .Kind )
331
334
}
332
335
} else {
333
336
ctxlog .Info (ctx , "buildStrategy kind is nil, use default NamespacedBuildStrategyKind" )
334
- if err := r .validateBuildStrategy (ctx , s . Name , ns ); err != nil {
337
+ if err := r .validateBuildStrategy (ctx , b . Spec . StrategyRef . Name , b ); err != nil {
335
338
return err
336
339
}
337
340
}
341
+
338
342
return nil
339
343
}
340
344
341
- func (r * ReconcileBuild ) validateBuildStrategy (ctx context.Context , n string , ns string ) error {
342
- list := & build.BuildStrategyList {}
343
-
344
- if err := r .client .List (ctx , list , & client.ListOptions {Namespace : ns }); err != nil {
345
- return errors .Wrapf (err , "listing BuildStrategies in ns %s failed" , ns )
346
- }
347
-
348
- if len (list .Items ) == 0 {
349
- return errors .Errorf ("none BuildStrategies found in namespace %s" , ns )
345
+ func (r * ReconcileBuild ) validateBuildStrategy (ctx context.Context , strategyName string , b * build.Build ) error {
346
+ buildStrategy := & build.BuildStrategy {}
347
+ if err := r .client .Get (ctx , types.NamespacedName {Name : strategyName , Namespace : b .Namespace }, buildStrategy ); err != nil && ! apierrors .IsNotFound (err ) {
348
+ return err
349
+ } else if apierrors .IsNotFound (err ) {
350
+ MarkBuildStatus (b , build .BuildStrategyNotFound , fmt .Sprintf ("buildStrategy %s does not exist in namespace %s" , b .Spec .StrategyRef .Name , b .Namespace ))
350
351
}
351
352
352
- if len (list .Items ) > 0 {
353
- for _ , s := range list .Items {
354
- if s .Name == n {
355
- return nil
356
- }
357
- }
358
- return fmt .Errorf ("buildStrategy %s does not exist in namespace %s" , n , ns )
359
- }
360
353
return nil
361
354
}
362
355
363
- func (r * ReconcileBuild ) validateClusterBuildStrategy (ctx context.Context , n string ) error {
364
- list := & build.ClusterBuildStrategyList {}
365
-
366
- if err := r .client .List (ctx , list ); err != nil {
367
- return errors .Wrapf (err , "listing ClusterBuildStrategies failed" )
368
- }
369
-
370
- if len (list .Items ) == 0 {
371
- return errors .Errorf ("no ClusterBuildStrategies found" )
372
- }
373
-
374
- if len (list .Items ) > 0 {
375
- for _ , s := range list .Items {
376
- if s .Name == n {
377
- return nil
378
- }
379
- }
380
- return fmt .Errorf ("clusterBuildStrategy %s does not exist" , n )
356
+ func (r * ReconcileBuild ) validateClusterBuildStrategy (ctx context.Context , strategyName string , b * build.Build ) error {
357
+ clusterBuildStrategy := & build.ClusterBuildStrategy {}
358
+ if err := r .client .Get (ctx , types.NamespacedName {Name : strategyName }, clusterBuildStrategy ); err != nil && ! apierrors .IsNotFound (err ) {
359
+ return err
360
+ } else if apierrors .IsNotFound (err ) {
361
+ MarkBuildStatus (b , build .ClusterBuildStrategyNotFound , fmt .Sprintf ("clusterBuildStrategy %s does not exist" , b .Spec .StrategyRef .Name ))
381
362
}
382
363
return nil
383
364
}
384
- func (r * ReconcileBuild ) validateSecrets (ctx context.Context , secretNames []string , ns string ) error {
385
- list := & corev1.SecretList {}
386
-
387
- if err := r .client .List (
388
- ctx ,
389
- list ,
390
- & client.ListOptions {
391
- Namespace : ns ,
392
- },
393
- ); err != nil {
394
- return errors .Wrapf (err , "listing secrets in namespace %s failed" , ns )
395
- }
396
365
397
- if len (list .Items ) == 0 {
398
- return errors .Errorf ("there are no secrets in namespace %s" , ns )
399
- }
366
+ func (r * ReconcileBuild ) validateSecrets (ctx context.Context , secretNames map [string ]build.BuildReason , b * build.Build ) error {
400
367
401
- var lookUp = map [string ]bool {}
402
- for _ , secretName := range secretNames {
403
- lookUp [secretName ] = false
404
- }
405
- for _ , secret := range list .Items {
406
- lookUp [secret .Name ] = true
407
- }
408
368
var missingSecrets []string
409
- for name , found := range lookUp {
410
- if ! found {
411
- missingSecrets = append (missingSecrets , name )
369
+ secret := & corev1.Secret {}
370
+ for refSecret , secretType := range secretNames {
371
+ if err := r .client .Get (ctx , types.NamespacedName {Name : refSecret , Namespace : b .Namespace }, secret ); err != nil && ! apierrors .IsNotFound (err ) {
372
+ return err
373
+ } else if apierrors .IsNotFound (err ) {
374
+ MarkBuildStatus (b , secretType , fmt .Sprintf ("referenced secret %s not found" , refSecret ))
375
+ missingSecrets = append (missingSecrets , refSecret )
412
376
}
413
377
}
414
378
415
379
if len (missingSecrets ) > 1 {
416
- return fmt .Errorf ("secrets %s do not exist" , strings .Join (missingSecrets , ", " ))
417
- } else if len (missingSecrets ) > 0 {
418
- return fmt .Errorf ("secret %s does not exist" , missingSecrets [0 ])
380
+ MarkBuildStatus (b , build .MultipleSecretRefNotFound , fmt .Sprintf ("missing secrets are %s" , strings .Join (missingSecrets , "," )))
419
381
}
420
382
421
383
return nil
@@ -436,7 +398,7 @@ func (r *ReconcileBuild) validateBuildRunOwnerReferences(ctx context.Context, b
436
398
for _ , buildRun := range buildRunList .Items {
437
399
if index := r .validateBuildOwnerReference (buildRun .OwnerReferences , b ); index == - 1 {
438
400
if err := r .setOwnerReferenceFunc (b , & buildRun , r .scheme ); err != nil {
439
- b . Status . Reason = fmt .Sprintf ("unexpected error when trying to set the ownerreference: %v" , err )
401
+ MarkBuildStatus ( b , build . SetOwnerReferenceFailed , fmt .Sprintf ("unexpected error when trying to set the ownerreference: %v" , err ) )
440
402
if err := r .client .Status ().Update (ctx , b ); err != nil {
441
403
return err
442
404
}
@@ -520,3 +482,9 @@ func buildSecretRefAnnotationExist(annotation map[string]string) (string, bool)
520
482
}
521
483
return "" , false
522
484
}
485
+
486
+ // MarkBuildStatus sets the Build Status fields
487
+ func MarkBuildStatus (b * build.Build , reason build.BuildReason , msg string ) {
488
+ b .Status .Reason = reason
489
+ b .Status .Message = msg
490
+ }
0 commit comments