expose Polaris.PodSpec for PodSpec targeted checks (#793)

* Add a template `Polaris` variable, expose `Polaris.PodSpec` for checks of `target: PodSpec`.

Polaris checks that are `target: PodSpec` have reflected the original
resource (such as a pod-controller) in the Go template, instead of
reflecting the pod `spec` field. This update makes the PodSpec available
in a new template variable `Polaris.PodSpec`.
This commit is contained in:
ivanfetch-fw
2022-07-12 08:04:17 -06:00
committed by GitHub
parent 1c09ce9e09
commit ccaa384cd0
3 changed files with 44 additions and 1 deletions
+2
View File
@@ -134,6 +134,8 @@ schema:
const: "{{ .metadata.name }}"
```
Note that the object available via the template is the full object, and not the object implied by the `target`. A check that specifies `target: PodSpec` can directly access the pod specification via the built-in template variable `.Polaris.PodSpec`.
You can also use the full [Go template syntax](https://golang.org/pkg/text/template/), though
you may need to specify your schema as a string in order to use concepts like `range`. E.g.
this check ensures that at least one of the object's labels is present in `matchLabels`:
+15
View File
@@ -17,6 +17,7 @@ package kube
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
@@ -475,3 +476,17 @@ func (resources *ResourceProvider) addResourceFromString(contents string) error
}
return err
}
// SerializePod converts a typed PodSpec into a map[string]interface{}
func SerializePod(pod *corev1.PodSpec) (map[string]interface{}, error) {
podJSON, err := json.Marshal(pod)
if err != nil {
return nil, err
}
podMap := make(map[string]interface{})
err = json.Unmarshal(podJSON, &podMap)
if err != nil {
return nil, err
}
return podMap, nil
}
+27 -1
View File
@@ -27,6 +27,7 @@ import (
"gomodules.xyz/jsonpatch/v2"
corev1 "k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
@@ -64,13 +65,38 @@ func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCas
if !check.IsActionable(test.Target, test.Resource.Kind, test.IsInitContianer) {
return nil, nil
}
checkPtr, err := check.TemplateForResource(test.Resource.Resource.Object)
templateInput, err := getTemplateInput(test)
if err != nil {
return nil, err
}
checkPtr, err := check.TemplateForResource(templateInput)
if err != nil {
return nil, err
}
return checkPtr, nil
}
// getTemplateInput augments a schemaTestCase.Resource.Resource.Object with
// Polaris built-in variables. The result can be used as input for
// CheckSchema.TemplateForResource().
func getTemplateInput(test schemaTestCase) (map[string]interface{}, error) {
templateInput := test.Resource.Resource.Object
if templateInput == nil {
return nil, nil
}
if test.Target == config.TargetPodSpec {
podSpecMap, err := kube.SerializePod(test.Resource.PodSpec)
if err != nil {
return nil, err
}
err = unstructured.SetNestedMap(templateInput, podSpecMap, "Polaris", "PodSpec")
if err != nil {
return nil, err
}
}
return templateInput, nil
}
func makeResult(conf *config.Configuration, check *config.SchemaCheck, passes bool, issues []jsonschema.ValError) ResultMessage {
details := []string{}
for _, issue := range issues {