Compare commits

..
5 Commits
Author SHA1 Message Date
Robert Brennan ff8e66af07 bump version (#587) 2021-07-14 10:26:27 -03:00
jdesouza 01cc5fa642 Fixed repeated names on dashboard (#586)
* Fixed repeated names on dashboard

* Fixed unit test
2021-07-14 09:17:40 -04:00
Robert Brennan cd47487b0b bump version (#578) 2021-06-25 18:06:06 -04:00
Robert Brennan 7e7e553c0d fix dashboard banner (#577) 2021-06-25 17:54:02 -04:00
Robert Brennan 8385fd10e5 fix webhook for top-level resources (#576)
* fix webhook for top-level resources

* delete unused code

* unused imports
2021-06-25 14:42:51 -04:00
10 changed files with 55 additions and 69 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<br>
<h3>Best Practices for Kubernetes Workload Configuration</h3>
<a href="https://github.com/FairwindsOps/polaris">
<img src="https://img.shields.io/static/v1.svg?label=Version&message=4.0.3&color=239922">
<img src="https://img.shields.io/static/v1.svg?label=Version&message=4.0.4&color=239922">
</a>
<a href="https://goreportcard.com/report/github.com/FairwindsOps/polaris">
<img src="https://goreportcard.com/badge/github.com/FairwindsOps/polaris">
+6
View File
@@ -1,6 +1,12 @@
---
sidebarDepth: 0
---
## 4.0.5
* Bugfix for repeated objects on the dashboard
## 4.0.4
* Bugfix for validating webhook and non-pod checks
## 4.0.3
* Fixed bad interaction between `--set-exit-score-below` and `--only-show-failed-tests`
* Dependency updates
+1 -1
View File
@@ -20,7 +20,7 @@ import (
const (
// Version represents the current release version of Polaris
Version = "4.0.3"
Version = "4.0.5"
)
func main() {
+4 -2
View File
@@ -13,8 +13,10 @@
padding-right: 40px;
box-shadow: none;
}
.card.insights img {
max-width: 400px;
.card.transparent {
background-color: transparent;
border: none;
box-shadow: none;
}
.card.insights a {
background-color: #20162D;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 66 KiB

+6 -4
View File
@@ -83,10 +83,12 @@
</div>
</div>
<div id="insights" class="card insights py-2">
<img class="align-self-center" src="static/images/FW_Insights_Polaris.svg" />
<span>Fairwinds, the company behind Polaris, now offers Fairwinds Insights, a multi-cluster, multi-user Kubernetes configuration validation and policy enforcement platform. Fairwinds Insights can help you avoid errors that lead to wasted time, compute costs, and increased risk.</span>
<a class="col-auto py-1 px-3 mt-2 align-self-center" href="https://www.fairwinds.com/polaris-user-insights-demo?utm_source=polaris&utm_medium=polaris&utm_campaign=polaris" target="_blank">Try Insights</a>
<div class="card transparent">
<a class="align-self-center"
target="_blank"
href="https://www.fairwinds.com/polaris-user-insights-demo?utm_source=polaris&utm_medium=ad&utm_campaign=polarisad">
<img src="static/images/FW_Insights_Polaris.svg" />
</a>
</div>
<div id="categories" class="card category">
+6 -8
View File
@@ -25,24 +25,23 @@ type GenericResource struct {
}
// NewGenericResourceFromUnstructured creates a workload from an unstructured.Unstructured
func NewGenericResourceFromUnstructured(unst *unstructured.Unstructured) (GenericResource, error) {
func NewGenericResourceFromUnstructured(unst unstructured.Unstructured) (GenericResource, error) {
workload := GenericResource{
Kind: unst.GetKind(),
Resource: *unst,
Resource: unst,
}
objMeta, err := meta.Accessor(unst)
objMeta, err := meta.Accessor(&unst)
if err != nil {
return workload, err
}
workload.ObjectMeta = objMeta
b, err := json.Marshal(unst)
b, err := json.Marshal(&unst)
if err != nil {
return workload, err
}
workload.OriginalObjectJSON = b
m := make(map[string]interface{})
err = json.Unmarshal(b, &m)
if err != nil {
@@ -61,7 +60,6 @@ func NewGenericResourceFromUnstructured(unst *unstructured.Unstructured) (Generi
}
workload.PodSpec = &podSpec
}
return workload, nil
}
@@ -101,7 +99,7 @@ func NewGenericResourceFromBytes(contentBytes []byte) (GenericResource, error) {
if err != nil {
return GenericResource{}, err
}
return NewGenericResourceFromUnstructured(&unst)
return NewGenericResourceFromUnstructured(unst)
}
// ResolveControllerFromPod builds a new workload for a given Pod
@@ -161,7 +159,7 @@ func resolveControllerFromPod(ctx context.Context, podResource kubeAPICoreV1.Pod
if lastKey != "" {
unst := objectCache[lastKey]
return NewGenericResourceFromUnstructured(&unst)
return NewGenericResourceFromUnstructured(unst)
}
workload, err := NewGenericResourceFromPod(podResource, podResource)
if err != nil {
+2 -2
View File
@@ -168,7 +168,7 @@ func CreateResourceProviderFromResource(ctx context.Context, workload string) (*
logrus.Errorf("Could not find workload %s: %v", workload, err)
return nil, err
}
workloadObj, err := NewGenericResourceFromUnstructured(obj)
workloadObj, err := NewGenericResourceFromUnstructured(*obj)
if err != nil {
logrus.Errorf("Could not parse workload %s: %v", workload, err)
return nil, err
@@ -298,7 +298,7 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
return nil, err
}
for _, obj := range objects.Items {
res, err := NewGenericResourceFromUnstructured(&obj)
res, err := NewGenericResourceFromUnstructured(obj)
if err != nil {
return nil, err
}
+2 -2
View File
@@ -33,7 +33,7 @@ func TestValidatePDB(t *testing.T) {
},
}
pdb := unstructured.Unstructured{}
res, err := kube.NewGenericResourceFromUnstructured(&pdb)
res, err := kube.NewGenericResourceFromUnstructured(pdb)
res.Kind = "PodDisruptionBudget"
actualResult, err := applyNonControllerSchemaChecks(&c, nil, res)
@@ -70,7 +70,7 @@ func TestValidateIngress(t *testing.T) {
if err != nil {
panic(err)
}
res, err := kube.NewGenericResourceFromUnstructured(&unst)
res, err := kube.NewGenericResourceFromUnstructured(unst)
if err != nil {
panic(err)
}
+27 -49
View File
@@ -16,8 +16,6 @@ package webhook
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -56,37 +54,11 @@ func NewWebhook(mgr manager.Manager, validator Validator) {
mgr.GetWebhookServer().Register(path, &webhook.Admission{Handler: &validator})
}
// GetObjectFromRawRequest returns the pod object and the controller's object from the raw json bytes.
func GetObjectFromRawRequest(raw []byte) (corev1.Pod, interface{}, error) {
pod := corev1.Pod{}
var originalObject interface{}
decoded := map[string]interface{}{}
err := json.Unmarshal(raw, &decoded)
if err != nil {
return pod, originalObject, err
}
podMap := kube.GetPodSpec(decoded)
if podMap == nil {
return pod, originalObject, errors.New("Object does not contain pods")
}
encoded, err := json.Marshal(podMap)
if err != nil {
return pod, originalObject, err
}
err = json.Unmarshal(encoded, &pod.Spec)
if err != nil {
return pod, originalObject, err
}
originalObject = decoded
return pod, originalObject, err
}
func (v *Validator) handleInternal(req admission.Request) (*validator.PodResult, error) {
pod := corev1.Pod{}
var originalObject interface{}
func (v *Validator) handleInternal(req admission.Request) (*validator.Result, error) {
var controller kube.GenericResource
var err error
if req.AdmissionRequest.Kind.Kind == "Pod" {
pod := corev1.Pod{}
err := v.decoder.Decode(req, &pod)
if err != nil {
return nil, err
@@ -95,58 +67,64 @@ func (v *Validator) handleInternal(req admission.Request) (*validator.PodResult,
logrus.Infof("Allowing owned pod %s/%s to pass through webhook", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name)
return nil, nil
}
originalObject = pod
controller, err = kube.NewGenericResourceFromPod(pod, pod)
} else {
pod, originalObject, err = GetObjectFromRawRequest(req.Object.Raw)
controller, err = kube.NewGenericResourceFromBytes(req.Object.Raw)
}
controller, err := kube.NewGenericResourceFromPod(pod, originalObject)
if err != nil {
return nil, err
}
controller.Kind = req.AdmissionRequest.Kind.Kind
var controllerResult validator.Result
// TODO: consider enabling multi-resource checks
controllerResult, err = validator.ApplyAllSchemaChecks(&v.Config, nil, controller)
controllerResult, err := validator.ApplyAllSchemaChecks(&v.Config, nil, controller)
if err != nil {
return nil, err
}
return controllerResult.PodResult, nil
return &controllerResult, nil
}
// Handle for Validator to run validation checks.
func (v *Validator) Handle(ctx context.Context, req admission.Request) admission.Response {
logrus.Info("Starting request")
podResult, err := v.handleInternal(req)
result, err := v.handleInternal(req)
if err != nil {
logrus.Errorf("Error validating request: %v", err)
return admission.Errored(http.StatusBadRequest, err)
}
allowed := true
reason := ""
if podResult != nil {
numDangers := podResult.GetSummary().Dangers
if result != nil {
numDangers := result.GetSummary().Dangers
if numDangers > 0 {
allowed = false
reason = getFailureReason(*podResult)
reason = getFailureReason(*result)
}
logrus.Infof("%d validation errors found when validating %s", numDangers, podResult.Name)
logrus.Infof("%d validation errors found when validating %s", numDangers, result.Name)
}
return admission.ValidationResponse(allowed, reason)
}
func getFailureReason(podResult validator.PodResult) string {
func getFailureReason(result validator.Result) string {
reason := "\nPolaris prevented this deployment due to configuration problems:\n"
for _, message := range podResult.Results {
for _, message := range result.Results {
if !message.Success && message.Severity == config.SeverityDanger {
reason += fmt.Sprintf("- Pod: %s\n", message.Message)
reason += fmt.Sprintf("- %s: %s\n", result.Kind, message.Message)
}
}
for _, containerResult := range podResult.ContainerResults {
for _, message := range containerResult.Results {
podResult := result.PodResult
if podResult != nil {
for _, message := range podResult.Results {
if !message.Success && message.Severity == config.SeverityDanger {
reason += fmt.Sprintf("- Container %s: %s\n", containerResult.Name, message.Message)
reason += fmt.Sprintf("- Pod: %s\n", message.Message)
}
}
for _, containerResult := range podResult.ContainerResults {
for _, message := range containerResult.Results {
if !message.Success && message.Severity == config.SeverityDanger {
reason += fmt.Sprintf("- Container %s: %s\n", containerResult.Name, message.Message)
}
}
}
}