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

Commit 6c22afd

Browse files
committed
Add basic scan scheduling logic for targets
1 parent 00f0364 commit 6c22afd

File tree

7 files changed

+162
-20
lines changed

7 files changed

+162
-20
lines changed

operator/api/v1/target_types.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ type TargetStatus struct {
4242
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
4343
// Important: Run "make" to regenerate code after modifying this file
4444
State string `json:"state,omitempty"`
45+
46+
LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"`
4547
}
4648

4749
// +kubebuilder:object:root=true
4850
// +kubebuilder:subresource:status
49-
51+
// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.spec.type`,description="Target Type"
52+
// +kubebuilder:printcolumn:name="Address",type=string,JSONPath=`.spec.address`,description="Target Address"
5053
// Target is the Schema for the targets API
5154
type Target struct {
5255
metav1.TypeMeta `json:",inline"`

operator/api/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
---
3+
apiVersion: apiextensions.k8s.io/v1beta1
4+
kind: CustomResourceDefinition
5+
metadata:
6+
creationTimestamp: null
7+
name: targets.scans.experimental.securecodebox.io
8+
spec:
9+
additionalPrinterColumns:
10+
- JSONPath: .spec.type
11+
description: Target Type
12+
name: Type
13+
type: string
14+
- JSONPath: .spec.address
15+
description: Target Address
16+
name: Address
17+
type: string
18+
group: scans.experimental.securecodebox.io
19+
names:
20+
kind: Target
21+
plural: targets
22+
scope: ""
23+
subresources:
24+
status: {}
25+
validation:
26+
openAPIV3Schema:
27+
description: Target is the Schema for the targets API
28+
properties:
29+
apiVersion:
30+
description: 'APIVersion defines the versioned schema of this representation
31+
of an object. Servers should convert recognized schemas to the latest
32+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
33+
type: string
34+
kind:
35+
description: 'Kind is a string value representing the REST resource this
36+
object represents. Servers may infer this from the endpoint the client
37+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
38+
type: string
39+
metadata:
40+
type: object
41+
spec:
42+
description: TargetSpec defines the desired state of Target
43+
properties:
44+
address:
45+
description: Foo is an example field of Target. Edit Target_types.go
46+
to remove/update
47+
type: string
48+
type:
49+
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
50+
Important: Run "make" to regenerate code after modifying this file'
51+
enum:
52+
- Host
53+
- IPRange
54+
- Domain
55+
type: string
56+
type: object
57+
status:
58+
description: TargetStatus defines the observed state of Target
59+
properties:
60+
lastScheduleTime:
61+
format: date-time
62+
type: string
63+
state:
64+
description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
65+
of cluster Important: Run "make" to regenerate code after modifying
66+
this file'
67+
type: string
68+
type: object
69+
type: object
70+
version: v1
71+
versions:
72+
- name: v1
73+
served: true
74+
storage: true
75+
status:
76+
acceptedNames:
77+
kind: ""
78+
plural: ""
79+
conditions: []
80+
storedVersions: []

operator/config/rbac/role.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,23 @@ rules:
9797
- get
9898
- list
9999
- watch
100+
- apiGroups:
101+
- scans.experimental.securecodebox.io
102+
resources:
103+
- targets
104+
verbs:
105+
- create
106+
- delete
107+
- get
108+
- list
109+
- patch
110+
- update
111+
- watch
112+
- apiGroups:
113+
- scans.experimental.securecodebox.io
114+
resources:
115+
- targets/status
116+
verbs:
117+
- get
118+
- patch
119+
- update
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: scans.experimental.securecodebox.io/v1
22
kind: Target
33
metadata:
4-
name: target-sample
4+
name: juice-shop
55
spec:
6-
# Add fields here
7-
foo: bar
6+
type: "Host"
7+
address: "juice-shop.demo-targets.svc"

operator/controllers/scan_controller.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,6 @@ func (r *ScanReconciler) SetupWithManager(mgr ctrl.Manager) error {
776776
panic(err)
777777
}
778778

779-
// Todo: Better config management
780-
781779
if err := mgr.GetFieldIndexer().IndexField(&batch.Job{}, ownerKey, func(rawObj runtime.Object) []string {
782780
// grab the job object, extract the owner...
783781
job := rawObj.(*batch.Job)

operator/controllers/target_controller.go

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,21 @@ package controllers
1818

1919
import (
2020
"context"
21+
"time"
2122

2223
"github.com/go-logr/logr"
24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2325
"k8s.io/apimachinery/pkg/runtime"
2426
ctrl "sigs.k8s.io/controller-runtime"
27+
2528
"sigs.k8s.io/controller-runtime/pkg/client"
2629

2730
scansv1 "experimental.securecodebox.io/api/v1"
2831
)
2932

33+
// ScanInterval defines how often a Target should be scanned
34+
var ScanInterval time.Duration = 1 * time.Minute
35+
3036
// TargetReconciler reconciles a Target object
3137
type TargetReconciler struct {
3238
client.Client
@@ -41,34 +47,65 @@ func (r *TargetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
4147
ctx := context.Background()
4248
log := r.Log.WithValues("target", req.NamespacedName)
4349

44-
// your logic here
45-
46-
log.Info("Starting Target Reconciler")
47-
4850
var target scansv1.Target
4951
err := r.Get(ctx, req.NamespacedName, &target)
5052
if err != nil {
5153
return ctrl.Result{}, client.IgnoreNotFound(err)
5254
}
5355

54-
if target.Status.State == "" {
55-
target.Status.State = "Scanning"
56+
var childScans scansv1.ScanList
57+
if err := r.List(ctx, &childScans, client.InNamespace(req.Namespace), client.MatchingFields{ownerKey: req.Name}); err != nil {
58+
log.Error(err, "unable to list child Scans")
59+
return ctrl.Result{}, err
5660
}
57-
switch target.Status.State {
58-
case "Scanning":
59-
switch target.Spec.Type {
60-
case "Host":
6161

62+
var nextSchedule time.Time
63+
if target.Status.LastScheduleTime != nil {
64+
nextSchedule = target.Status.LastScheduleTime.Add(ScanInterval)
65+
} else {
66+
nextSchedule = time.Now().Add(-1 * time.Second)
67+
}
68+
69+
// check if it is time to start the scans
70+
if !time.Now().Before(nextSchedule) {
71+
// It's time!
72+
log.Info("Should start scans here")
73+
74+
var now metav1.Time = metav1.Now()
75+
target.Status.LastScheduleTime = &now
76+
if err := r.Status().Update(ctx, &target); err != nil {
77+
log.Error(err, "unable to update Targets status")
78+
return ctrl.Result{}, err
6279
}
63-
case "Sleeping":
64-
// TODO: Reschedule
80+
81+
// Recalculate next schedule
82+
nextSchedule = time.Now().Add(ScanInterval)
6583
}
6684

67-
return ctrl.Result{}, nil
85+
return ctrl.Result{RequeueAfter: nextSchedule.Sub(time.Now())}, nil
6886
}
6987

7088
func (r *TargetReconciler) SetupWithManager(mgr ctrl.Manager) error {
89+
if err := mgr.GetFieldIndexer().IndexField(&scansv1.Scan{}, ownerKey, func(rawObj runtime.Object) []string {
90+
// grab the job object, extract the owner...
91+
scan := rawObj.(*scansv1.Scan)
92+
owner := metav1.GetControllerOf(scan)
93+
if owner == nil {
94+
return nil
95+
}
96+
// ...make sure it's a Scan belonging to a Target...
97+
if owner.APIVersion != apiGVStr || owner.Kind != "Target" {
98+
return nil
99+
}
100+
101+
// ...and if so, return it
102+
return []string{owner.Name}
103+
}); err != nil {
104+
return err
105+
}
106+
71107
return ctrl.NewControllerManagedBy(mgr).
72108
For(&scansv1.Target{}).
109+
Owns(&scansv1.Scan{}).
73110
Complete(r)
74111
}

0 commit comments

Comments
 (0)