Skip to content

Commit

Permalink
fix: generate scan reports for individual completed containers when p…
Browse files Browse the repository at this point in the history
…od scan failed (#1917)

Signed-off-by: chenk <hen.keinan@gmail.com>
  • Loading branch information
chen-keinan committed Mar 18, 2024
1 parent 2ed26a2 commit 2aa20ed
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 24 deletions.
11 changes: 9 additions & 2 deletions pkg/kube/resources.go
Expand Up @@ -52,7 +52,7 @@ func GetContainerImagesFromContainersList(containers []corev1.Container) Contain
// to container images from the specified v1.Job.
// The mapping is encoded as JSON value of the AnnotationContainerImages
// annotation.
func GetContainerImagesFromJob(job *batchv1.Job) (ContainerImages, error) {
func GetContainerImagesFromJob(job *batchv1.Job, completedContainers ...string) (ContainerImages, error) {
var containerImagesAsJSON string
var ok bool

Expand All @@ -64,7 +64,14 @@ func GetContainerImagesFromJob(job *batchv1.Job) (ContainerImages, error) {
if err != nil {
return nil, fmt.Errorf("parsing annotation: %s: %w", trivyoperator.AnnotationContainerImages, err)
}
return containerImages, nil
completed := make(map[string]string)
for _, container := range completedContainers {
if c, ok := containerImages[container]; ok {
completed[container] = c
}

}
return completed, nil
}

// ComputeHash returns a hash value calculated from a given object.
Expand Down
2 changes: 1 addition & 1 deletion pkg/kube/resources_test.go
Expand Up @@ -111,7 +111,7 @@ func TestGetContainerImagesFromJob(t *testing.T) {
"trivy-operator.container-images": `{"nginx":"nginx:1.16","sidecar":"sidecar:1.32.7"}`,
},
},
})
}, []string{"nginx", "sidecar"}...)
require.NoError(t, err)
assert.Equal(t, kube.ContainerImages{
"nginx": "nginx:1.16",
Expand Down
44 changes: 23 additions & 21 deletions pkg/vulnerabilityreport/controller/scanjob.go
Expand Up @@ -75,20 +75,23 @@ func (r *ScanJobController) reconcileJobs() reconcile.Func {
}

switch jobCondition := job.Status.Conditions[0].Type; jobCondition {
case batchv1.JobComplete:
err = r.processCompleteScanJob(ctx, job)
case batchv1.JobFailed:
err = r.processFailedScanJob(ctx, job)
case batchv1.JobComplete, batchv1.JobFailed:
completedContainers, err := r.completedContainers(ctx, job)
if err != nil {
return ctrl.Result{}, r.deleteJob(ctx, job)
}
if len(completedContainers) == 0 {
return ctrl.Result{}, r.deleteJob(ctx, job)
}
return ctrl.Result{}, r.processCompleteScanJob(ctx, job, completedContainers...)

default:
err = fmt.Errorf("unrecognized scan job condition: %v", jobCondition)
return ctrl.Result{}, fmt.Errorf("unrecognized scan job condition: %v", jobCondition)
}

return ctrl.Result{}, err
}

}

func (r *ScanJobController) processCompleteScanJob(ctx context.Context, job *batchv1.Job) error {
func (r *ScanJobController) processCompleteScanJob(ctx context.Context, job *batchv1.Job, completedContainers ...string) error {
log := r.Logger.WithValues("job", fmt.Sprintf("%s/%s", job.Namespace, job.Name))

ownerRef, err := kube.ObjectRefFromObjectMeta(job.ObjectMeta)
Expand All @@ -104,12 +107,6 @@ func (r *ScanJobController) processCompleteScanJob(ctx context.Context, job *bat
}
return fmt.Errorf("getting object from object ref: %w", err)
}

containerImages, err := kube.GetContainerImagesFromJob(job)
if err != nil {
return fmt.Errorf("getting container images: %w", err)
}

podSpecHash, ok := job.Labels[trivyoperator.LabelResourceSpecHash]
if !ok {
return fmt.Errorf("expected label %s not set", trivyoperator.LabelResourceSpecHash)
Expand All @@ -121,6 +118,10 @@ func (r *ScanJobController) processCompleteScanJob(ctx context.Context, job *bat
log.V(1).Info("Job complete")

hasVulnReports := true
containerImages, err := kube.GetContainerImagesFromJob(job, completedContainers...)
if err != nil {
return fmt.Errorf("getting container images: %w", err)
}
if r.Config.VulnerabilityScannerEnabled {
hasVulnReports, err = hasVulnerabilityReports(ctx, r.VulnerabilityReadWriter, ownerRef, podSpecHash, containerImages)
if err != nil {
Expand Down Expand Up @@ -324,29 +325,30 @@ func (r *ScanJobController) processScanJobResults(ctx context.Context,
return vulnerabilityReports, secretReports, sbomReports, nil
}

func (r *ScanJobController) processFailedScanJob(ctx context.Context, scanJob *batchv1.Job) error {
func (r *ScanJobController) completedContainers(ctx context.Context, scanJob *batchv1.Job) ([]string, error) {
log := r.Logger.WithValues("job", fmt.Sprintf("%s/%s", scanJob.Namespace, scanJob.Name))

statuses, err := r.GetTerminatedContainersStatusesByJob(ctx, scanJob)
if err != nil {
if k8sapierror.IsNotFound(err) {
log.V(1).Info("Cached job must have been deleted")
return nil
return []string{}, nil
}
if kube.IsPodControlledByJobNotFound(err) {
log.V(1).Info("Pod must have been deleted")
return r.deleteJob(ctx, scanJob)
return []string{}, nil
}
return err
return nil, err
}
completedContainers := make([]string, 0)
for container, status := range statuses {
if status.ExitCode == 0 {
completedContainers = append(completedContainers, container)
continue
}
log.Error(nil, "Scan job container", "container", container, "status.reason", status.Reason, "status.message", status.Message)
}
log.V(1).Info("Deleting failed scan job")
return r.deleteJob(ctx, scanJob)
return completedContainers, nil
}

func (r *ScanJobController) deleteJob(ctx context.Context, job *batchv1.Job) error {
Expand Down

0 comments on commit 2aa20ed

Please sign in to comment.