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

Commit 715de18

Browse files
committed
Extract hook_reconciler from scan_controller
1 parent d077709 commit 715de18

File tree

2 files changed

+280
-270
lines changed

2 files changed

+280
-270
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
package scancontrollers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
executionv1 "github.com/secureCodeBox/secureCodeBox-v2-alpha/operator/apis/execution/v1"
8+
"k8s.io/apimachinery/pkg/types"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
)
11+
12+
func (r *ScanReconciler) setHookStatus(scan *executionv1.Scan) error {
13+
// Set (pending) Hook status on the scan
14+
ctx := context.Background()
15+
var scanCompletionHooks executionv1.ScanCompletionHookList
16+
17+
if err := r.List(ctx, &scanCompletionHooks, client.InNamespace(scan.Namespace)); err != nil {
18+
r.Log.V(7).Info("Unable to fetch ScanCompletionHooks")
19+
return err
20+
}
21+
22+
r.Log.Info("Found ScanCompletionHooks", "ScanCompletionHooks", len(scanCompletionHooks.Items))
23+
24+
readAndWriteHooks := []executionv1.ScanCompletionHook{}
25+
// filter all ReadAndWriteHooks in the scamCompletionHooks list
26+
for _, hook := range scanCompletionHooks.Items {
27+
if hook.Spec.Type == executionv1.ReadAndWrite {
28+
readAndWriteHooks = append(readAndWriteHooks, hook)
29+
}
30+
}
31+
32+
r.Log.Info("Found ReadAndWriteHooks", "ReadAndWriteHooks", len(readAndWriteHooks))
33+
34+
hookStatus := []executionv1.HookStatus{}
35+
36+
for _, hook := range readAndWriteHooks {
37+
hookStatus = append(hookStatus, executionv1.HookStatus{
38+
HookName: hook.Name,
39+
State: executionv1.Pending,
40+
})
41+
}
42+
43+
scan.Status.State = "ReadAndWriteHookProcessing"
44+
scan.Status.ReadAndWriteHookStatus = hookStatus
45+
46+
if err := r.Status().Update(ctx, scan); err != nil {
47+
r.Log.Error(err, "unable to update Scan status")
48+
return err
49+
}
50+
51+
return nil
52+
}
53+
54+
func (r *ScanReconciler) executeReadAndWriteHooks(scan *executionv1.Scan) error {
55+
// Get the first Hook Status which is not completed.
56+
ctx := context.Background()
57+
var nonCompletedHook *executionv1.HookStatus
58+
59+
for _, hook := range scan.Status.ReadAndWriteHookStatus {
60+
if hook.State != executionv1.Completed {
61+
nonCompletedHook = &hook
62+
break
63+
}
64+
}
65+
66+
// If nil then all hooks are done
67+
if nonCompletedHook == nil {
68+
scan.Status.State = "ReadAndWriteHookCompleted"
69+
if err := r.Status().Update(ctx, scan); err != nil {
70+
r.Log.Error(err, "unable to update Scan status")
71+
return err
72+
}
73+
return nil
74+
}
75+
76+
switch nonCompletedHook.State {
77+
case executionv1.Pending:
78+
rawFileURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile)
79+
if err != nil {
80+
return err
81+
}
82+
findingsFileURL, err := r.PresignedGetURL(scan.UID, "findings.json")
83+
if err != nil {
84+
return err
85+
}
86+
87+
rawFileUploadURL, err := r.PresignedPutURL(scan.UID, scan.Status.RawResultFile)
88+
if err != nil {
89+
return err
90+
}
91+
findingsUploadURL, err := r.PresignedPutURL(scan.UID, "findings.json")
92+
if err != nil {
93+
return err
94+
}
95+
96+
var hook executionv1.ScanCompletionHook
97+
if err := r.Get(ctx, types.NamespacedName{Name: nonCompletedHook.HookName, Namespace: scan.Namespace}, &hook); err != nil {
98+
r.Log.Error(err, "Failed to get ReadAndWrite Hook for HookStatus")
99+
return err
100+
}
101+
102+
jobs, err := r.getJobsForScan(scan, client.MatchingLabels{
103+
"experimental.securecodebox.io/job-type": "read-and-write-hook",
104+
"experimental.securecodebox.io/hook-name": nonCompletedHook.HookName,
105+
})
106+
if err != nil {
107+
return err
108+
}
109+
if len(jobs.Items) > 0 {
110+
// Job already exists
111+
return nil
112+
}
113+
114+
jobName, err := r.createJobForHook(
115+
&hook,
116+
scan,
117+
[]string{
118+
rawFileURL,
119+
findingsFileURL,
120+
rawFileUploadURL,
121+
findingsUploadURL,
122+
},
123+
)
124+
125+
// Update the currently executed hook status to "InProgress"
126+
err = r.updateHookStatus(scan, executionv1.HookStatus{
127+
HookName: nonCompletedHook.HookName,
128+
JobName: jobName,
129+
State: executionv1.InProgress,
130+
})
131+
return err
132+
case executionv1.InProgress:
133+
jobStatus, err := r.checkIfJobIsCompleted(scan, client.MatchingLabels{
134+
"experimental.securecodebox.io/job-type": "read-and-write-hook",
135+
"experimental.securecodebox.io/hook-name": nonCompletedHook.HookName,
136+
})
137+
if err != nil {
138+
r.Log.Error(err, "Failed to check job status for ReadAndWrite Hook")
139+
return err
140+
}
141+
switch jobStatus {
142+
case completed:
143+
// Job is completed => set current Hook to completed
144+
err = r.updateHookStatus(scan, executionv1.HookStatus{
145+
HookName: nonCompletedHook.HookName,
146+
JobName: nonCompletedHook.JobName,
147+
State: executionv1.Completed,
148+
})
149+
return err
150+
case incomplete:
151+
// Still waiting for job to finish
152+
return nil
153+
case failed:
154+
for i, hookStatus := range scan.Status.ReadAndWriteHookStatus {
155+
if hookStatus.HookName == nonCompletedHook.HookName {
156+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Failed
157+
} else if hookStatus.State == executionv1.Pending {
158+
scan.Status.ReadAndWriteHookStatus[i].State = executionv1.Cancelled
159+
}
160+
}
161+
scan.Status.State = "Errored"
162+
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)
163+
if err := r.Status().Update(ctx, scan); err != nil {
164+
r.Log.Error(err, "unable to update Scan status")
165+
return err
166+
}
167+
}
168+
}
169+
170+
return nil
171+
}
172+
173+
func (r *ScanReconciler) startReadOnlyHooks(scan *executionv1.Scan) error {
174+
ctx := context.Background()
175+
176+
var scanCompletionHooks executionv1.ScanCompletionHookList
177+
178+
if err := r.List(ctx, &scanCompletionHooks, client.InNamespace(scan.Namespace)); err != nil {
179+
r.Log.V(7).Info("Unable to fetch ScanCompletionHooks")
180+
return err
181+
}
182+
183+
r.Log.Info("Found ScanCompletionHooks", "ScanCompletionHooks", len(scanCompletionHooks.Items))
184+
185+
readOnlyHooks := []executionv1.ScanCompletionHook{}
186+
// filter all ReadOnlyHooks in the scamCompletionHooks list
187+
for _, hook := range scanCompletionHooks.Items {
188+
if hook.Spec.Type == executionv1.ReadOnly {
189+
readOnlyHooks = append(readOnlyHooks, hook)
190+
}
191+
}
192+
193+
r.Log.Info("Found ReadOnlyHooks", "ReadOnlyHooks", len(readOnlyHooks))
194+
195+
// If the readOnlyHooks list is empty, nothing more to do
196+
if len(readOnlyHooks) == 0 {
197+
r.Log.Info("Marked scan as done as without running ReadOnly hooks as non were configured", "ScanName", scan.Name)
198+
scan.Status.State = "Done"
199+
if err := r.Status().Update(ctx, scan); err != nil {
200+
r.Log.Error(err, "Unable to update Scan status")
201+
return err
202+
}
203+
return nil
204+
}
205+
206+
// Get all read-only-hooks for scan to later check that they weren't already created
207+
jobs, err := r.getJobsForScan(scan, client.MatchingLabels{
208+
"experimental.securecodebox.io/job-type": "read-only-hook",
209+
})
210+
if err != nil {
211+
return err
212+
}
213+
214+
for _, hook := range readOnlyHooks {
215+
// Check if hook was already executed
216+
if containsJobForHook(jobs, hook) == true {
217+
r.Log.V(4).Info("Skipping creation of job for hook '%s' as it already exists", hook.Name)
218+
// Job was already created
219+
continue
220+
}
221+
222+
rawFileURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile)
223+
if err != nil {
224+
return err
225+
}
226+
findingsFileURL, err := r.PresignedGetURL(scan.UID, "findings.json")
227+
if err != nil {
228+
return err
229+
}
230+
231+
jobName, err := r.createJobForHook(
232+
&hook,
233+
scan,
234+
[]string{
235+
rawFileURL,
236+
findingsFileURL,
237+
},
238+
)
239+
if err != nil {
240+
r.Log.Error(err, "Unable to create Job for ReadOnlyHook", "job", jobName)
241+
return err
242+
}
243+
}
244+
scan.Status.State = "ReadOnlyHookProcessing"
245+
if err := r.Status().Update(ctx, scan); err != nil {
246+
r.Log.Error(err, "Unable to update Scan status")
247+
return err
248+
}
249+
r.Log.Info("Started ReadOnlyHook", "ReadOnlyHookCount", len(readOnlyHooks))
250+
return nil
251+
}
252+
253+
func (r *ScanReconciler) checkIfReadOnlyHookIsCompleted(scan *executionv1.Scan) error {
254+
ctx := context.Background()
255+
readOnlyHookCompletion, err := r.checkIfJobIsCompleted(scan, client.MatchingLabels{"experimental.securecodebox.io/job-type": "read-only-hook"})
256+
if err != nil {
257+
return err
258+
}
259+
260+
if readOnlyHookCompletion == completed {
261+
r.Log.V(7).Info("All ReadOnlyHooks have completed")
262+
scan.Status.State = "Done"
263+
if err := r.Status().Update(ctx, scan); err != nil {
264+
r.Log.Error(err, "Unable to update Scan status")
265+
return err
266+
}
267+
} else if readOnlyHookCompletion == failed {
268+
r.Log.Info("At least one ReadOnlyHook failed")
269+
scan.Status.State = "Errored"
270+
scan.Status.ErrorDescription = "At least one ReadOnlyHook failed, check the hooks kubernetes jobs related to the scan for more details."
271+
if err := r.Status().Update(ctx, scan); err != nil {
272+
r.Log.Error(err, "Unable to update Scan status")
273+
return err
274+
}
275+
}
276+
277+
// ReadOnlyHook(s) are still running. At least some of them are.
278+
// Waiting until all are done.
279+
return nil
280+
}

0 commit comments

Comments
 (0)