Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete controllers package #270

Merged
merged 14 commits into from
Apr 27, 2020
Prev Previous commit
Next Next commit
refactor webhook to be more generic
  • Loading branch information
rbren committed Apr 24, 2020
commit 0f38d8454d712854e412260f7f6902c5db35984d
9 changes: 6 additions & 3 deletions cmd/polaris/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,13 @@ var webhookCmd = &cobra.Command{
for index, controllerToScan := range config.ControllersToScan {
for innerIndex, supportedAPIType := range controllerToScan.ListSupportedAPIVersions() {
webhookName := strings.ToLower(fmt.Sprintf("%s-%d-%d", controllerToScan, index, innerIndex))
hook := fwebhook.NewWebhook(webhookName, mgr, fwebhook.Validator{Config: config}, supportedAPIType)
if hook != nil {
webhooks = append(webhooks, hook)
hook, err := fwebhook.NewWebhook(webhookName, mgr, fwebhook.Validator{Config: config}, supportedAPIType)
if err != nil {
logrus.Warningf("Couldn't build webhook %s: %v", webhookName, err)
continue
}
webhooks = append(webhooks, hook)
logrus.Infof("%s webhook started", webhookName)
}
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/kube/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ func deduplicateControllers(inputControllers []controllers.GenericController) []
return results
}

func getPodSpec(yaml map[string]interface{}) interface{} {
func GetPodSpec(yaml map[string]interface{}) interface{} {
allowedChildren := []string{"jobTemplate", "spec", "template"}
for _, child := range allowedChildren {
if childYaml, ok := yaml[child]; ok {
return getPodSpec(childYaml.(map[string]interface{}))
return GetPodSpec(childYaml.(map[string]interface{}))
}
}
return yaml
Expand Down Expand Up @@ -221,7 +221,7 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
finalDoc["metadata"] = yamlNode["metadata"]
finalDoc["apiVersion"] = "v1"
finalDoc["kind"] = "Pod"
finalDoc["spec"] = getPodSpec(yamlNode)
finalDoc["spec"] = GetPodSpec(yamlNode)
marshaledYaml, err := yaml.Marshal(finalDoc)
if err != nil {
logrus.Errorf("Could not marshal yaml: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/controllers/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ func NewGenericPodController(originalResource kubeAPICoreV1.Pod, dynamicClientPo
controller.Kind = "Pod"
controller.CreatedTime = controller.GetObjectMeta().CreationTimestamp.Time

owners := controller.GetObjectMeta().OwnerReferences
if dynamicClientPointer == nil || restMapperPointer == nil {
return controller
}
// If an owner exists then set the name to the controller.
// This allows us to handle CRDs creating Controllers or DeploymentConfigs in OpenShift.
owners := controller.GetObjectMeta().OwnerReferences
for len(owners) > 0 {
if len(owners) > 1 {
logrus.Warn("More than 1 owner found")
Expand Down
97 changes: 33 additions & 64 deletions pkg/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@ package webhook

import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
validator "github.com/fairwindsops/polaris/pkg/validator"
"github.com/fairwindsops/polaris/pkg/validator/controllers"

"github.com/sirupsen/logrus"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -64,7 +63,7 @@ func (v *Validator) InjectDecoder(d types.Decoder) error {
var _ admission.Handler = &Validator{}

// NewWebhook creates a validating admission webhook for the apiType.
func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType runtime.Object) *admission.Webhook {
func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType runtime.Object) (*admission.Webhook, error) {
name = fmt.Sprintf("%s.k8s.io", name)
path := fmt.Sprintf("/validating-%s", name)

Expand All @@ -78,86 +77,56 @@ func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType r
Handlers(&validator).
Build()
if err != nil {
logrus.Errorf("Error building webhook: %v", err)
return nil
return nil, err
}
logrus.Info(name + " webhook started")
return webhook
return webhook, nil
}

// Handle for Validator to run validation checks.
func (v *Validator) Handle(ctx context.Context, req types.Request) types.Response {
var err error
var podResult validator.PodResult

func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*validator.PodResult, error) {
pod := corev1.Pod{}
if req.AdmissionRequest.Kind.Kind == "Pod" {
pod := corev1.Pod{}
err = v.decoder.Decode(req, &pod) // err is handled below
nakedPod := controllers.NewNakedPodController(pod)
if err == nil {
podResult, err = validator.ValidatePod(&v.Config, nakedPod)
err := v.decoder.Decode(req, &pod)
if err != nil {
return nil, err
}
} else {
var controller controllers.GenericController
if yes := v.Config.CheckIfKindIsConfiguredForValidation(req.AdmissionRequest.Kind.Kind); !yes {
logrus.Warnf("Skipping, kind (%s) isn't something we are configured to scan", req.AdmissionRequest.Kind.Kind)
return admission.ValidationResponse(true, fmt.Sprintf("Skipping: (%s) isn't something we're configured to scan.", req.AdmissionRequest.Kind.Kind))
decoded := map[string]interface{}{}
err := json.Unmarshal(req.AdmissionRequest.Object.Raw, &decoded)
if err != nil {
return nil, err
}

// We should never hit this case unless something is misconfiured in CheckIfKindIsConfiguredForValidation
controllerType := config.GetSupportedControllerFromString(req.AdmissionRequest.Kind.Kind)
if controllerType == config.Unsupported {
msg := fmt.Errorf("Expected Kind (%s) to be a supported type", req.AdmissionRequest.Kind.Kind)
logrus.Error(msg)
return admission.ErrorResponse(http.StatusInternalServerError, msg)
}

// For each type, perform the scan
// TODO: This isn't really that elegant due to the decoder and NewXXXController setup :( could use love
switch controllerType {
case config.Deployments:
deploy := appsv1.Deployment{}
err = v.decoder.Decode(req, &deploy)
controller = controllers.NewDeploymentController(deploy)
case config.StatefulSets:
statefulSet := appsv1.StatefulSet{}
err = v.decoder.Decode(req, &statefulSet)
controller = controllers.NewStatefulSetController(statefulSet)
case config.DaemonSets:
daemonSet := appsv1.DaemonSet{}
err = v.decoder.Decode(req, &daemonSet)
controller = controllers.NewDaemonSetController(daemonSet)
case config.Jobs:
job := batchv1.Job{}
err = v.decoder.Decode(req, &job)
controller = controllers.NewJobController(job)
case config.CronJobs:
cronJob := batchv1beta1.CronJob{}
err = v.decoder.Decode(req, &cronJob)
controller = controllers.NewCronJobController(cronJob)
case config.ReplicationControllers:
replicationController := corev1.ReplicationController{}
err = v.decoder.Decode(req, &replicationController)
controller = controllers.NewReplicationControllerController(replicationController)
podMap := kube.GetPodSpec(decoded)
encoded, err := json.Marshal(podMap)
if err != nil {
return nil, err
}
if err == nil {
var controllerResult validator.ControllerResult
controllerResult, err = validator.ValidateController(&v.Config, controller)
podResult = controllerResult.PodResult
err = json.Unmarshal(encoded, &pod.Spec)
if err != nil {
return nil, err
}
}
controller := controllers.NewGenericPodController(pod, nil, nil)
controller.Kind = req.AdmissionRequest.Kind.Kind
controllerResult, err := validator.ValidateController(&v.Config, controller)
if err != nil {
return nil, err
}
return &controllerResult.PodResult, nil
}

// Handle for Validator to run validation checks.
func (v *Validator) Handle(ctx context.Context, req types.Request) types.Response {
podResult, err := v.handleInternal(ctx, req)
if err != nil {
logrus.Errorf("Error validating request: %v", err)
return admission.ErrorResponse(http.StatusBadRequest, err)
}

allowed := true
reason := ""
numErrors := podResult.GetSummary().Errors
if numErrors > 0 {
allowed = false
reason = getFailureReason(podResult)
reason = getFailureReason(*podResult)
}
logrus.Infof("%d validation errors found when validating %s", numErrors, podResult.Name)
return admission.ValidationResponse(allowed, reason)
Expand Down