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

Commit 855d2a1

Browse files
committed
Split Job functionality into different file
1 parent 715de18 commit 855d2a1

File tree

2 files changed

+217
-203
lines changed

2 files changed

+217
-203
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package scancontrollers
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
10+
executionv1 "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/apis/execution/v1"
11+
util "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/utils"
12+
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"
17+
"sigs.k8s.io/controller-runtime/pkg/client"
18+
)
19+
20+
type jobCompletionType string
21+
22+
const (
23+
completed jobCompletionType = "Completed"
24+
failed jobCompletionType = "Failed"
25+
incomplete jobCompletionType = "Incomplete"
26+
unknown jobCompletionType = "Unknown"
27+
)
28+
29+
func allJobsCompleted(jobs *batch.JobList) jobCompletionType {
30+
hasCompleted := true
31+
32+
for _, job := range jobs.Items {
33+
if job.Status.Failed > 0 {
34+
return failed
35+
} else if job.Status.Succeeded == 0 {
36+
hasCompleted = false
37+
}
38+
}
39+
40+
if hasCompleted {
41+
return completed
42+
}
43+
return incomplete
44+
}
45+
46+
func (r *ScanReconciler) getJobsForScan(scan *executionv1.Scan, labels client.MatchingLabels) (*batch.JobList, error) {
47+
ctx := context.Background()
48+
49+
// check if k8s job for scan was already created
50+
var jobs batch.JobList
51+
if err := r.List(
52+
ctx,
53+
&jobs,
54+
client.InNamespace(scan.Namespace),
55+
client.MatchingField(ownerKey, scan.Name),
56+
labels,
57+
); err != nil {
58+
r.Log.Error(err, "Unable to list child jobs")
59+
return nil, err
60+
}
61+
62+
return &jobs, nil
63+
}
64+
65+
func (r *ScanReconciler) checkIfJobIsCompleted(scan *executionv1.Scan, labels client.MatchingLabels) (jobCompletionType, error) {
66+
jobs, err := r.getJobsForScan(scan, labels)
67+
if err != nil {
68+
return unknown, err
69+
}
70+
71+
r.Log.V(9).Info("Got related jobs", "count", len(jobs.Items))
72+
73+
return allJobsCompleted(jobs), nil
74+
}
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)