Skip to content

Commit

Permalink
expose Polaris.PodSpec for PodSpec targeted checks (#793)
Browse files Browse the repository at this point in the history
* 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`.
  • Loading branch information
ivanfetch-wt authored Jul 12, 2022
1 parent 1c09ce9 commit ccaa384
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
2 changes: 2 additions & 0 deletions docs/customization/custom-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Expand Down
15 changes: 15 additions & 0 deletions pkg/kube/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package kube
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -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
}
28 changes: 27 additions & 1 deletion pkg/validator/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit ccaa384

Please sign in to comment.