Skip to content

Commit

Permalink
using custom checks in marvin plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusfm committed May 16, 2023
1 parent 7758cf9 commit 924133d
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~
$(KUSTOMIZE) build config/crd | kubectl apply -f -
@kubectl apply -f config/samples/zora_v1alpha1_plugin_popeye.yaml
@kubectl apply -f config/samples/zora_v1alpha1_plugin_marvin.yaml
@kubectl apply -f config/rbac/zora_clusterissue_editor_role.yaml
@kubectl apply -f config/rbac/zora_plugins_role.yaml
@kubectl create -f config/rbac/zora_plugins_role_binding.yaml || true

.PHONY: uninstall
Expand Down
3 changes: 3 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package main

import (
"flag"
"fmt"
"net/http"
"os"
"strings"
Expand Down Expand Up @@ -150,6 +151,8 @@ func main() {
ServiceAccountName: cronJobServiceAccount,
OnUpdate: onClusterScanUpdate,
OnDelete: onClusterScanDelete,
KubexnsImage: kubexnsImage,
ChecksConfigMap: fmt.Sprintf("%s/%s", checksConfigMapNamespace, checksConfigMapName),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ClusterScan")
os.Exit(1)
Expand Down
51 changes: 51 additions & 0 deletions config/rbac/zora_plugins_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2022 Undistro Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
app.kubernetes.io/instance: zora-plugins-role
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: zora
app.kubernetes.io/part-of: zora
app.kubernetes.io/managed-by: kustomize
name: zora-plugins
rules:
- apiGroups:
- zora.undistro.io
resources:
- clusterissues
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- zora.undistro.io
resources:
- clusterissues/status
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
2 changes: 1 addition & 1 deletion config/rbac/zora_plugins_role_binding.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ metadata:
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: clusterissues-editor
name: zora-plugins
subjects: []
4 changes: 3 additions & 1 deletion config/samples/zora_v1alpha1_plugin_marvin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ spec:
- -c
- |
start=$(date +%s)
mkdir -p $(CUSTOM_CHECKS_PATH)
ls -lh $(CUSTOM_CHECKS_PATH)
echo Scanning...
/marvin scan --disable-annotation-skip -o json -v 2 --kubeconfig $(KUBECONFIG) > $(DONE_DIR)/results.json
/marvin scan --disable-annotation-skip -f $(CUSTOM_CHECKS_PATH) -o json -v 2 --kubeconfig $(KUBECONFIG) > $(DONE_DIR)/results.json
exitcode=$(echo $?)
if [ $exitcode -ne 0 ]; then
echo "ERROR" > $(DONE_DIR)/error
Expand Down
4 changes: 4 additions & 0 deletions internal/controller/zora/clusterscan_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type ClusterScanReconciler struct {
WorkerImage string
ClusterRoleBindingName string
ServiceAccountName string
KubexnsImage string
ChecksConfigMap string
OnUpdate saas.ClusterScanHook
OnDelete saas.ClusterScanHook
}
Expand Down Expand Up @@ -202,6 +204,8 @@ func (r *ClusterScanReconciler) reconcile(ctx context.Context, clusterscan *v1al
WorkerImage: r.WorkerImage,
ServiceAccountName: r.ServiceAccountName,
Suspend: notReadyErr != nil,
KubexnsImage: r.KubexnsImage,
ChecksConfigMap: r.ChecksConfigMap,
}

result, err := ctrl.CreateOrUpdate(ctx, r.Client, cronJob, cronJobMutator.Mutate)
Expand Down
58 changes: 53 additions & 5 deletions pkg/plugins/cronjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import (
)

const (
checksVolumeName = "custom-checks"
checksPath = "/custom-checks"
workerContainerName = "worker"
kubeconfigVolumeName = "kubeconfig"
kubeconfigMountPath = "/etc/zora"
Expand All @@ -47,19 +49,22 @@ var (
Value: resultsDir,
},
}
// commonVolumeMounts volume mounts to be used in worker and plugin containers
// commonVolumeMounts represents the volume mounts to be used in worker and plugin containers
commonVolumeMounts = []corev1.VolumeMount{
{
Name: resultsVolumeName,
MountPath: resultsDir,
},
}
// pluginVolumeMounts volume mounts to be used in plugin container
pluginVolumeMounts = append(commonVolumeMounts, corev1.VolumeMount{
// pluginVolumes represents the volume mounts to be used in plugin container
pluginVolumes = append(commonVolumeMounts, corev1.VolumeMount{
Name: kubeconfigVolumeName,
ReadOnly: true,
MountPath: kubeconfigMountPath,
})

// customChecksVolume represents the volume mount to be used in the init container
customChecksVolume = corev1.VolumeMount{Name: checksVolumeName, MountPath: checksPath}
)

func NewCronJob(name, namespace string) *batchv1.CronJob {
Expand All @@ -76,6 +81,8 @@ type CronJobMutator struct {
WorkerImage string
ServiceAccountName string
Suspend bool
KubexnsImage string
ChecksConfigMap string
}

// Mutate returns a function which mutates the existing CronJob into it's desired state.
Expand Down Expand Up @@ -116,11 +123,29 @@ func (r *CronJobMutator) Mutate() error {
Name: resultsVolumeName,
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
},
{
Name: checksVolumeName,
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
},
}
r.Existing.Spec.JobTemplate.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{
RunAsNonRoot: pointer.Bool(true),
}

if pointer.BoolDeref(r.Plugin.Spec.MountCustomChecksVolume, false) {
initContainer := r.initContainer()
if len(r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers) == 0 {
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers = []corev1.Container{initContainer}
} else {
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].Name = initContainer.Name
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].Image = initContainer.Image
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].Env = initContainer.Env
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].VolumeMounts = initContainer.VolumeMounts
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = initContainer.ImagePullPolicy
r.Existing.Spec.JobTemplate.Spec.Template.Spec.InitContainers[0].Resources = initContainer.Resources
}
}

desiredContainers := map[string]corev1.Container{
workerContainerName: r.workerContainer(),
r.Plugin.Name: r.pluginContainer(),
Expand Down Expand Up @@ -168,7 +193,7 @@ func (r *CronJobMutator) workerContainer() corev1.Container {

// pluginContainer returns a Container for Plugin
func (r *CronJobMutator) pluginContainer() corev1.Container {
return corev1.Container{
c := corev1.Container{
Name: r.Plugin.Name,
Image: r.Plugin.Spec.Image,
Command: r.Plugin.Spec.Command,
Expand All @@ -178,7 +203,27 @@ func (r *CronJobMutator) pluginContainer() corev1.Container {
Resources: r.Plugin.Spec.Resources,
ImagePullPolicy: r.Plugin.Spec.GetImagePullPolicy(),
SecurityContext: r.Plugin.Spec.SecurityContext,
VolumeMounts: pluginVolumeMounts,
VolumeMounts: pluginVolumes,
}
if pointer.BoolDeref(r.Plugin.Spec.MountCustomChecksVolume, false) {
c.VolumeMounts = append(c.VolumeMounts, customChecksVolume)
}
return c
}

// initContainer returns an init container to mount custom checks
func (r *CronJobMutator) initContainer() corev1.Container {
return corev1.Container{
Name: "checks",
Image: r.KubexnsImage,
Env: []corev1.EnvVar{
{Name: "DIR", Value: checksPath},
{Name: "CONFIGMAPS", Value: r.ChecksConfigMap},
{Name: "IGNORE_NOT_FOUND", Value: "true"},
},
VolumeMounts: []corev1.VolumeMount{customChecksVolume},
ImagePullPolicy: corev1.PullIfNotPresent,
Resources: r.Plugin.Spec.Resources,
}
}

Expand All @@ -200,6 +245,9 @@ func (r *CronJobMutator) pluginEnv() []corev1.EnvVar {
Value: r.Existing.ObjectMeta.Name,
},
)
if pointer.BoolDeref(r.Plugin.Spec.MountCustomChecksVolume, false) {
p = append(p, corev1.EnvVar{Name: "CUSTOM_CHECKS_PATH", Value: checksVolumeName})
}
return p
}

Expand Down

0 comments on commit 924133d

Please sign in to comment.