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

Commit e6f4e76

Browse files
committed
Extract executeReadAndWriteHooks from reconciler func
1 parent 2acb8b5 commit e6f4e76

File tree

1 file changed

+191
-184
lines changed

1 file changed

+191
-184
lines changed

operator/controllers/execution/scan_controller.go

Lines changed: 191 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -115,191 +115,8 @@ func (r *ScanReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
115115
case "ParseCompleted":
116116
err = r.setHookStatus(&scan)
117117
case "ReadAndWriteHookProcessing":
118-
// First Array entry which is not Completed.
119-
var nonCompletedHook *executionv1.HookStatus
118+
err = r.executeReadAndWriteHooks(&scan)
120119

121-
for _, hook := range scan.Status.ReadAndWriteHookStatus {
122-
if hook.State != executionv1.Completed {
123-
nonCompletedHook = &hook
124-
break
125-
}
126-
}
127-
128-
if nonCompletedHook == nil {
129-
scan.Status.State = "ReadAndWriteHookCompleted"
130-
if err := r.Status().Update(ctx, &scan); err != nil {
131-
r.Log.Error(err, "unable to update Scan status")
132-
return ctrl.Result{}, err
133-
}
134-
return ctrl.Result{}, nil
135-
}
136-
137-
if nonCompletedHook.State == executionv1.Pending {
138-
rules := []rbacv1.PolicyRule{
139-
{
140-
APIGroups: []string{"execution.experimental.securecodebox.io"},
141-
Resources: []string{"scans"},
142-
Verbs: []string{"get"},
143-
},
144-
}
145-
serviceAccountName := "scan-completion-hook"
146-
r.ensureServiceAccountExists(
147-
scan.Namespace,
148-
serviceAccountName,
149-
"ScanCompletionHooks need to access the current scan to view where its results are stored",
150-
rules,
151-
)
152-
153-
rawFileURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile)
154-
if err != nil {
155-
return ctrl.Result{}, err
156-
}
157-
findingsFileURL, err := r.PresignedGetURL(scan.UID, "findings.json")
158-
if err != nil {
159-
return ctrl.Result{}, err
160-
}
161-
162-
bucketName := os.Getenv("S3_BUCKET")
163-
rawFileUploadURL, err := r.MinioClient.PresignedPutObject(bucketName, fmt.Sprintf("scan-%s/%s", scan.UID, scan.Status.RawResultFile), 12*time.Hour)
164-
if err != nil {
165-
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
166-
return ctrl.Result{}, err
167-
}
168-
findingsUploadURL, err := r.MinioClient.PresignedPutObject(bucketName, fmt.Sprintf("scan-%s/findings.json", scan.UID), 12*time.Hour)
169-
if err != nil {
170-
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
171-
return ctrl.Result{}, err
172-
}
173-
174-
var hook executionv1.ScanCompletionHook
175-
err = r.Get(ctx, types.NamespacedName{Name: nonCompletedHook.HookName, Namespace: scan.Namespace}, &hook)
176-
if err != nil {
177-
r.Log.Error(err, "Failed to get ReadAndWrite Hook for HookStatus")
178-
return ctrl.Result{}, err
179-
}
180-
181-
standardEnvVars := []corev1.EnvVar{
182-
{
183-
Name: "NAMESPACE",
184-
ValueFrom: &corev1.EnvVarSource{
185-
FieldRef: &corev1.ObjectFieldSelector{
186-
FieldPath: "metadata.namespace",
187-
},
188-
},
189-
},
190-
{
191-
Name: "SCAN_NAME",
192-
Value: scan.Name,
193-
},
194-
}
195-
196-
// Starting a new job based on the current ReadAndWrite Hook
197-
labels := scan.ObjectMeta.DeepCopy().Labels
198-
if labels == nil {
199-
labels = make(map[string]string)
200-
}
201-
labels["experimental.securecodebox.io/job-type"] = "read-and-write-hook"
202-
var backOffLimit int32 = 3
203-
job := &batch.Job{
204-
ObjectMeta: metav1.ObjectMeta{
205-
Annotations: make(map[string]string),
206-
Name: fmt.Sprintf("%s-%s", hook.Name, scan.Name),
207-
Namespace: scan.Namespace,
208-
Labels: labels,
209-
},
210-
Spec: batch.JobSpec{
211-
BackoffLimit: &backOffLimit,
212-
Template: corev1.PodTemplateSpec{
213-
ObjectMeta: metav1.ObjectMeta{
214-
Annotations: map[string]string{
215-
"auto-discovery.experimental.securecodebox.io/ignore": "true",
216-
},
217-
},
218-
Spec: corev1.PodSpec{
219-
ServiceAccountName: serviceAccountName,
220-
RestartPolicy: corev1.RestartPolicyNever,
221-
Containers: []corev1.Container{
222-
{
223-
Name: "hook",
224-
Image: hook.Spec.Image,
225-
Args: []string{
226-
rawFileURL,
227-
findingsFileURL,
228-
rawFileUploadURL.String(),
229-
findingsUploadURL.String(),
230-
},
231-
Env: append(hook.Spec.Env, standardEnvVars...),
232-
ImagePullPolicy: "IfNotPresent",
233-
},
234-
},
235-
},
236-
},
237-
TTLSecondsAfterFinished: nil,
238-
},
239-
}
240-
if err := ctrl.SetControllerReference(&scan, job, r.Scheme); err != nil {
241-
r.Log.Error(err, "Unable to set controllerReference on job", "job", job)
242-
return ctrl.Result{}, err
243-
}
244-
245-
if err := r.Create(ctx, job); err != nil {
246-
r.Log.Error(err, "Unable to create Job for ReadOnlyHook", "job", job)
247-
return ctrl.Result{}, err
248-
}
249-
250-
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
251-
if hookStatus.HookName == nonCompletedHook.HookName {
252-
scan.Status.ReadAndWriteHookStatus[i].JobName = job.Name
253-
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.InProgress
254-
}
255-
}
256-
257-
if err := r.Status().Update(ctx, &scan); err != nil {
258-
r.Log.Error(err, "unable to update Scan status")
259-
return ctrl.Result{}, err
260-
}
261-
return ctrl.Result{}, err
262-
}
263-
264-
if nonCompletedHook.State == executionv1.InProgress {
265-
jobStatus, err := r.checkIfJobIsCompleted(nonCompletedHook.JobName, scan.Namespace)
266-
if err != nil {
267-
r.Log.Error(err, "Failed to check job status for ReadAndWrite Hook")
268-
return ctrl.Result{}, err
269-
}
270-
switch jobStatus {
271-
case completed:
272-
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
273-
if hookStatus.HookName == nonCompletedHook.HookName {
274-
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Completed
275-
}
276-
}
277-
278-
if err := r.Status().Update(ctx, &scan); err != nil {
279-
r.Log.Error(err, "unable to update Scan status")
280-
return ctrl.Result{}, err
281-
}
282-
return ctrl.Result{}, err
283-
case incomplete:
284-
// Still waiting for job to finish
285-
return ctrl.Result{}, err
286-
287-
case failed:
288-
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
289-
if hookStatus.HookName == nonCompletedHook.HookName {
290-
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Failed
291-
} else if hookStatus.State == executionv1.Pending {
292-
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Cancelled
293-
}
294-
}
295-
scan.Status.State = "Errored"
296-
scan.Status.ErrorDescription = fmt.Sprintf("Failed to execute ReadAndWrite Hook '%s' in job '%s'. Check the logs of the hook for more information.", nonCompletedHook.HookName, nonCompletedHook.JobName)
297-
if err := r.Status().Update(ctx, &scan); err != nil {
298-
r.Log.Error(err, "unable to update Scan status")
299-
return ctrl.Result{}, err
300-
}
301-
}
302-
}
303120
case "ReadAndWriteHookCompleted":
304121
err = r.startReadOnlyHooks(&scan)
305122
case "ReadOnlyHookProcessing":
@@ -1197,3 +1014,193 @@ func (r *ScanReconciler) setHookStatus(scan *executionv1.Scan) error {
11971014

11981015
return nil
11991016
}
1017+
1018+
func (r *ScanReconciler) executeReadAndWriteHooks(scan *executionv1.Scan) error {
1019+
// First Array entry which is not Completed.
1020+
ctx := context.Background()
1021+
var nonCompletedHook *executionv1.HookStatus
1022+
1023+
for _, hook := range scan.Status.ReadAndWriteHookStatus {
1024+
if hook.State != executionv1.Completed {
1025+
nonCompletedHook = &hook
1026+
break
1027+
}
1028+
}
1029+
1030+
if nonCompletedHook == nil {
1031+
scan.Status.State = "ReadAndWriteHookCompleted"
1032+
if err := r.Status().Update(ctx, scan); err != nil {
1033+
r.Log.Error(err, "unable to update Scan status")
1034+
return err
1035+
}
1036+
return nil
1037+
}
1038+
1039+
if nonCompletedHook.State == executionv1.Pending {
1040+
rules := []rbacv1.PolicyRule{
1041+
{
1042+
APIGroups: []string{"execution.experimental.securecodebox.io"},
1043+
Resources: []string{"scans"},
1044+
Verbs: []string{"get"},
1045+
},
1046+
}
1047+
serviceAccountName := "scan-completion-hook"
1048+
r.ensureServiceAccountExists(
1049+
scan.Namespace,
1050+
serviceAccountName,
1051+
"ScanCompletionHooks need to access the current scan to view where its results are stored",
1052+
rules,
1053+
)
1054+
1055+
rawFileURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile)
1056+
if err != nil {
1057+
return err
1058+
}
1059+
findingsFileURL, err := r.PresignedGetURL(scan.UID, "findings.json")
1060+
if err != nil {
1061+
return err
1062+
}
1063+
1064+
bucketName := os.Getenv("S3_BUCKET")
1065+
rawFileUploadURL, err := r.MinioClient.PresignedPutObject(bucketName, fmt.Sprintf("scan-%s/%s", scan.UID, scan.Status.RawResultFile), 12*time.Hour)
1066+
if err != nil {
1067+
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
1068+
return err
1069+
}
1070+
findingsUploadURL, err := r.MinioClient.PresignedPutObject(bucketName, fmt.Sprintf("scan-%s/findings.json", scan.UID), 12*time.Hour)
1071+
if err != nil {
1072+
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
1073+
return err
1074+
}
1075+
1076+
var hook executionv1.ScanCompletionHook
1077+
err = r.Get(ctx, types.NamespacedName{Name: nonCompletedHook.HookName, Namespace: scan.Namespace}, &hook)
1078+
if err != nil {
1079+
r.Log.Error(err, "Failed to get ReadAndWrite Hook for HookStatus")
1080+
return err
1081+
}
1082+
1083+
standardEnvVars := []corev1.EnvVar{
1084+
{
1085+
Name: "NAMESPACE",
1086+
ValueFrom: &corev1.EnvVarSource{
1087+
FieldRef: &corev1.ObjectFieldSelector{
1088+
FieldPath: "metadata.namespace",
1089+
},
1090+
},
1091+
},
1092+
{
1093+
Name: "SCAN_NAME",
1094+
Value: scan.Name,
1095+
},
1096+
}
1097+
1098+
// Starting a new job based on the current ReadAndWrite Hook
1099+
labels := scan.ObjectMeta.DeepCopy().Labels
1100+
if labels == nil {
1101+
labels = make(map[string]string)
1102+
}
1103+
labels["experimental.securecodebox.io/job-type"] = "read-and-write-hook"
1104+
var backOffLimit int32 = 3
1105+
job := &batch.Job{
1106+
ObjectMeta: metav1.ObjectMeta{
1107+
Annotations: make(map[string]string),
1108+
Name: fmt.Sprintf("%s-%s", hook.Name, scan.Name),
1109+
Namespace: scan.Namespace,
1110+
Labels: labels,
1111+
},
1112+
Spec: batch.JobSpec{
1113+
BackoffLimit: &backOffLimit,
1114+
Template: corev1.PodTemplateSpec{
1115+
ObjectMeta: metav1.ObjectMeta{
1116+
Annotations: map[string]string{
1117+
"auto-discovery.experimental.securecodebox.io/ignore": "true",
1118+
},
1119+
},
1120+
Spec: corev1.PodSpec{
1121+
ServiceAccountName: serviceAccountName,
1122+
RestartPolicy: corev1.RestartPolicyNever,
1123+
Containers: []corev1.Container{
1124+
{
1125+
Name: "hook",
1126+
Image: hook.Spec.Image,
1127+
Args: []string{
1128+
rawFileURL,
1129+
findingsFileURL,
1130+
rawFileUploadURL.String(),
1131+
findingsUploadURL.String(),
1132+
},
1133+
Env: append(hook.Spec.Env, standardEnvVars...),
1134+
ImagePullPolicy: "IfNotPresent",
1135+
},
1136+
},
1137+
},
1138+
},
1139+
TTLSecondsAfterFinished: nil,
1140+
},
1141+
}
1142+
if err := ctrl.SetControllerReference(scan, job, r.Scheme); err != nil {
1143+
r.Log.Error(err, "Unable to set controllerReference on job", "job", job)
1144+
return err
1145+
}
1146+
1147+
if err := r.Create(ctx, job); err != nil {
1148+
r.Log.Error(err, "Unable to create Job for ReadOnlyHook", "job", job)
1149+
return err
1150+
}
1151+
1152+
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
1153+
if hookStatus.HookName == nonCompletedHook.HookName {
1154+
scan.Status.ReadAndWriteHookStatus[i].JobName = job.Name
1155+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.InProgress
1156+
}
1157+
}
1158+
1159+
if err := r.Status().Update(ctx, scan); err != nil {
1160+
r.Log.Error(err, "unable to update Scan status")
1161+
return err
1162+
}
1163+
return err
1164+
}
1165+
1166+
if nonCompletedHook.State == executionv1.InProgress {
1167+
jobStatus, err := r.checkIfJobIsCompleted(nonCompletedHook.JobName, scan.Namespace)
1168+
if err != nil {
1169+
r.Log.Error(err, "Failed to check job status for ReadAndWrite Hook")
1170+
return err
1171+
}
1172+
switch jobStatus {
1173+
case completed:
1174+
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
1175+
if hookStatus.HookName == nonCompletedHook.HookName {
1176+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Completed
1177+
}
1178+
}
1179+
1180+
if err := r.Status().Update(ctx, scan); err != nil {
1181+
r.Log.Error(err, "unable to update Scan status")
1182+
return err
1183+
}
1184+
return err
1185+
case incomplete:
1186+
// Still waiting for job to finish
1187+
return err
1188+
1189+
case failed:
1190+
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
1191+
if hookStatus.HookName == nonCompletedHook.HookName {
1192+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Failed
1193+
} else if hookStatus.State == executionv1.Pending {
1194+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Cancelled
1195+
}
1196+
}
1197+
scan.Status.State = "Errored"
1198+
scan.Status.ErrorDescription = fmt.Sprintf("Failed to execute ReadAndWrite Hook '%s' in job '%s'. Check the logs of the hook for more information.", nonCompletedHook.HookName, nonCompletedHook.JobName)
1199+
if err := r.Status().Update(ctx, scan); err != nil {
1200+
r.Log.Error(err, "unable to update Scan status")
1201+
return err
1202+
}
1203+
}
1204+
}
1205+
return nil
1206+
}

0 commit comments

Comments
 (0)