Skip to content
This repository was archived by the owner on Oct 14, 2020. It is now read-only.

Commit 2666a02

Browse files
J12934nigthknight
andcommitted
Move specialized functions into specialized reconcilers
Co-authored-by: Yannik Fuhrmeister <12710254+fuhrmeistery@users.noreply.github.com>
1 parent 7bd80ba commit 2666a02

File tree

5 files changed

+397
-384
lines changed

5 files changed

+397
-384
lines changed

operator/controllers/execution/scans/hook_reconciler.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ import (
55
"fmt"
66

77
executionv1 "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/apis/execution/v1"
8+
util "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/utils"
9+
batch "k8s.io/api/batch/v1"
10+
corev1 "k8s.io/api/core/v1"
11+
rbacv1 "k8s.io/api/rbac/v1"
12+
resource "k8s.io/apimachinery/pkg/api/resource"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
814
"k8s.io/apimachinery/pkg/types"
15+
ctrl "sigs.k8s.io/controller-runtime"
916
"sigs.k8s.io/controller-runtime/pkg/client"
1017
)
1118

@@ -170,6 +177,20 @@ func (r *ScanReconciler) executeReadAndWriteHooks(scan *executionv1.Scan) error
170177
return nil
171178
}
172179

180+
func containsJobForHook(jobs *batch.JobList, hook executionv1.ScanCompletionHook) bool {
181+
if len(jobs.Items) == 0 {
182+
return false
183+
}
184+
185+
for _, job := range jobs.Items {
186+
if job.ObjectMeta.Labels["experimental.securecodebox.io/hook-name"] == hook.Name {
187+
return true
188+
}
189+
}
190+
191+
return false
192+
}
193+
173194
func (r *ScanReconciler) startReadOnlyHooks(scan *executionv1.Scan) error {
174195
ctx := context.Background()
175196

@@ -278,3 +299,129 @@ func (r *ScanReconciler) checkIfReadOnlyHookIsCompleted(scan *executionv1.Scan)
278299
// Waiting until all are done.
279300
return nil
280301
}
302+
303+
func (r *ScanReconciler) createJobForHook(hook *executionv1.ScanCompletionHook, scan *executionv1.Scan, cliArgs []string) (string, error) {
304+
ctx := context.Background()
305+
306+
serviceAccountName := "scan-completion-hook"
307+
if hook.Spec.ServiceAccountName != nil {
308+
// Hook uses a custom ServiceAccount
309+
serviceAccountName = *hook.Spec.ServiceAccountName
310+
} else {
311+
// Check and create a serviceAccount for the hook in its namespace, if it doesn't already exist.
312+
rules := []rbacv1.PolicyRule{
313+
{
314+
APIGroups: []string{"execution.experimental.securecodebox.io"},
315+
Resources: []string{"scans"},
316+
Verbs: []string{"get"},
317+
},
318+
{
319+
APIGroups: []string{"execution.experimental.securecodebox.io"},
320+
Resources: []string{"scans/status"},
321+
Verbs: []string{"get", "patch"},
322+
},
323+
}
324+
325+
r.ensureServiceAccountExists(
326+
hook.Namespace,
327+
serviceAccountName,
328+
"ScanCompletionHooks need to access the current scan to view where its results are stored",
329+
rules,
330+
)
331+
}
332+
333+
standardEnvVars := []corev1.EnvVar{
334+
{
335+
Name: "NAMESPACE",
336+
ValueFrom: &corev1.EnvVarSource{
337+
FieldRef: &corev1.ObjectFieldSelector{
338+
FieldPath: "metadata.namespace",
339+
},
340+
},
341+
},
342+
{
343+
Name: "SCAN_NAME",
344+
Value: scan.Name,
345+
},
346+
}
347+
348+
// Starting a new job based on the current ReadAndWrite Hook
349+
labels := scan.ObjectMeta.DeepCopy().Labels
350+
if labels == nil {
351+
labels = make(map[string]string)
352+
}
353+
if hook.Spec.Type == executionv1.ReadAndWrite {
354+
labels["experimental.securecodebox.io/job-type"] = "read-and-write-hook"
355+
} else if hook.Spec.Type == executionv1.ReadOnly {
356+
labels["experimental.securecodebox.io/job-type"] = "read-only-hook"
357+
}
358+
labels["experimental.securecodebox.io/hook-name"] = hook.Name
359+
360+
var backOffLimit int32 = 3
361+
job := &batch.Job{
362+
ObjectMeta: metav1.ObjectMeta{
363+
Annotations: make(map[string]string),
364+
GenerateName: util.TruncateName(fmt.Sprintf("%s-%s", hook.Name, scan.Name)),
365+
Namespace: scan.Namespace,
366+
Labels: labels,
367+
},
368+
Spec: batch.JobSpec{
369+
BackoffLimit: &backOffLimit,
370+
Template: corev1.PodTemplateSpec{
371+
ObjectMeta: metav1.ObjectMeta{
372+
Annotations: map[string]string{
373+
"auto-discovery.experimental.securecodebox.io/ignore": "true",
374+
},
375+
},
376+
Spec: corev1.PodSpec{
377+
ServiceAccountName: serviceAccountName,
378+
RestartPolicy: corev1.RestartPolicyNever,
379+
ImagePullSecrets: hook.Spec.ImagePullSecrets,
380+
Containers: []corev1.Container{
381+
{
382+
Name: "hook",
383+
Image: hook.Spec.Image,
384+
Args: cliArgs,
385+
Env: append(hook.Spec.Env, standardEnvVars...),
386+
ImagePullPolicy: "IfNotPresent",
387+
Resources: corev1.ResourceRequirements{
388+
Requests: corev1.ResourceList{
389+
corev1.ResourceCPU: resource.MustParse("200m"),
390+
corev1.ResourceMemory: resource.MustParse("100Mi"),
391+
},
392+
Limits: corev1.ResourceList{
393+
corev1.ResourceCPU: resource.MustParse("400m"),
394+
corev1.ResourceMemory: resource.MustParse("200Mi"),
395+
},
396+
},
397+
},
398+
},
399+
},
400+
},
401+
TTLSecondsAfterFinished: nil,
402+
},
403+
}
404+
if err := ctrl.SetControllerReference(scan, job, r.Scheme); err != nil {
405+
r.Log.Error(err, "Unable to set controllerReference on job", "job", job)
406+
return "", err
407+
}
408+
409+
if err := r.Create(ctx, job); err != nil {
410+
return "", err
411+
}
412+
return job.Name, nil
413+
}
414+
415+
func (r *ScanReconciler) updateHookStatus(scan *executionv1.Scan, hookStatus executionv1.HookStatus) error {
416+
for i, hook := range scan.Status.ReadAndWriteHookStatus {
417+
if hook.HookName == hookStatus.HookName {
418+
scan.Status.ReadAndWriteHookStatus[i] = hookStatus
419+
break
420+
}
421+
}
422+
if err := r.Status().Update(context.Background(), scan); err != nil {
423+
r.Log.Error(err, "unable to update Scan status")
424+
return err
425+
}
426+
return nil
427+
}

operator/controllers/execution/scans/job.go

Lines changed: 0 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,9 @@ package scancontrollers
22

33
import (
44
"context"
5-
"errors"
6-
"fmt"
7-
"os"
8-
"path/filepath"
95

106
executionv1 "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/apis/execution/v1"
11-
util "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/utils"
127
batch "k8s.io/api/batch/v1"
13-
corev1 "k8s.io/api/core/v1"
14-
resource "k8s.io/apimachinery/pkg/api/resource"
15-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16-
ctrl "sigs.k8s.io/controller-runtime"
178
"sigs.k8s.io/controller-runtime/pkg/client"
189
)
1910

@@ -72,146 +63,3 @@ func (r *ScanReconciler) checkIfJobIsCompleted(scan *executionv1.Scan, labels cl
7263

7364
return allJobsCompleted(jobs), nil
7465
}
75-
76-
func (r *ScanReconciler) constructJobForScan(scan *executionv1.Scan, scanType *executionv1.ScanType) (*batch.Job, error) {
77-
filename := filepath.Base(scanType.Spec.ExtractResults.Location)
78-
resultUploadURL, err := r.PresignedPutURL(scan.UID, filename)
79-
if err != nil {
80-
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
81-
return nil, err
82-
}
83-
84-
if len(scanType.Spec.JobTemplate.Spec.Template.Spec.Containers) < 1 {
85-
return nil, errors.New("ScanType must at least contain one container in which the scanner is running")
86-
}
87-
88-
labels := scan.ObjectMeta.DeepCopy().Labels
89-
if labels == nil {
90-
labels = make(map[string]string)
91-
}
92-
labels["experimental.securecodebox.io/job-type"] = "scanner"
93-
job := &batch.Job{
94-
ObjectMeta: metav1.ObjectMeta{
95-
Labels: labels,
96-
GenerateName: util.TruncateName(fmt.Sprintf("scan-%s", scan.Name)),
97-
Namespace: scan.Namespace,
98-
},
99-
Spec: *scanType.Spec.JobTemplate.Spec.DeepCopy(),
100-
}
101-
102-
podAnnotations := scanType.Spec.JobTemplate.DeepCopy().Annotations
103-
if podAnnotations == nil {
104-
podAnnotations = make(map[string]string)
105-
}
106-
podAnnotations["experimental.securecodebox.io/job-type"] = "scanner"
107-
job.Spec.Template.Annotations = podAnnotations
108-
109-
job.Spec.Template.Spec.ServiceAccountName = "lurcher"
110-
111-
// merging volume definition from ScanType (if existing) with standard results volume
112-
if job.Spec.Template.Spec.Containers[0].VolumeMounts == nil || len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 {
113-
job.Spec.Template.Spec.Volumes = []corev1.Volume{}
114-
}
115-
job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, corev1.Volume{
116-
Name: "scan-results",
117-
VolumeSource: corev1.VolumeSource{
118-
EmptyDir: &corev1.EmptyDirVolumeSource{},
119-
},
120-
})
121-
122-
// merging volume mounts (for the primary scanner container) from ScanType (if existing) with standard results volume mount
123-
if job.Spec.Template.Spec.Containers[0].VolumeMounts == nil || len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 {
124-
job.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{}
125-
}
126-
job.Spec.Template.Spec.Containers[0].VolumeMounts = append(
127-
job.Spec.Template.Spec.Containers[0].VolumeMounts,
128-
corev1.VolumeMount{
129-
Name: "scan-results",
130-
MountPath: "/home/securecodebox/",
131-
},
132-
)
133-
134-
// Get lurcher image config from env
135-
lurcherImage := os.Getenv("LURCHER_IMAGE")
136-
if lurcherImage == "" {
137-
lurcherImage = "scbexperimental/lurcher:latest"
138-
}
139-
lurcherPullPolicyRaw := os.Getenv("LURCHER_PULL_POLICY")
140-
var lurcherPullPolicy corev1.PullPolicy
141-
switch lurcherPullPolicyRaw {
142-
case "Always":
143-
lurcherPullPolicy = corev1.PullAlways
144-
case "IfNotPresent":
145-
lurcherPullPolicy = corev1.PullIfNotPresent
146-
case "Never":
147-
lurcherPullPolicy = corev1.PullNever
148-
case "":
149-
lurcherPullPolicy = corev1.PullAlways
150-
default:
151-
return nil, fmt.Errorf("Unknown imagePull Policy for lurcher: %s", lurcherPullPolicyRaw)
152-
}
153-
154-
lurcherSidecar := &corev1.Container{
155-
Name: "lurcher",
156-
Image: lurcherImage,
157-
ImagePullPolicy: lurcherPullPolicy,
158-
Args: []string{
159-
"--container",
160-
job.Spec.Template.Spec.Containers[0].Name,
161-
"--file",
162-
scanType.Spec.ExtractResults.Location,
163-
"--url",
164-
resultUploadURL,
165-
},
166-
Env: []corev1.EnvVar{
167-
{
168-
Name: "NAMESPACE",
169-
ValueFrom: &corev1.EnvVarSource{
170-
FieldRef: &corev1.ObjectFieldSelector{
171-
FieldPath: "metadata.namespace",
172-
},
173-
},
174-
},
175-
},
176-
Resources: corev1.ResourceRequirements{
177-
Requests: corev1.ResourceList{
178-
corev1.ResourceCPU: resource.MustParse("20m"),
179-
corev1.ResourceMemory: resource.MustParse("20Mi"),
180-
},
181-
Limits: corev1.ResourceList{
182-
corev1.ResourceCPU: resource.MustParse("100m"),
183-
corev1.ResourceMemory: resource.MustParse("100Mi"),
184-
},
185-
},
186-
VolumeMounts: []corev1.VolumeMount{
187-
{
188-
Name: "scan-results",
189-
MountPath: "/home/securecodebox/",
190-
ReadOnly: true,
191-
},
192-
},
193-
}
194-
195-
job.Spec.Template.Spec.Containers = append(job.Spec.Template.Spec.Containers, *lurcherSidecar)
196-
197-
if err := ctrl.SetControllerReference(scan, job, r.Scheme); err != nil {
198-
return nil, err
199-
}
200-
201-
command := append(
202-
scanType.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command,
203-
scan.Spec.Parameters...,
204-
)
205-
206-
// Merge Env from ScanTemplate with Env defined in scan
207-
job.Spec.Template.Spec.Containers[0].Env = append(
208-
job.Spec.Template.Spec.Containers[0].Env,
209-
scan.Spec.Env...,
210-
)
211-
212-
// Using command over args
213-
job.Spec.Template.Spec.Containers[0].Command = command
214-
job.Spec.Template.Spec.Containers[0].Args = nil
215-
216-
return job, nil
217-
}

0 commit comments

Comments
 (0)