mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
commit
2f25d5a351
10 changed files with 323 additions and 58 deletions
pkg
engine
kyverno/apply
result
webhooks
|
@ -23,14 +23,9 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk)
|
||||
if !ok {
|
||||
ruleApplicationResult.AddMessagef("Rule %s is not applicable to resource\n", rule.Name)
|
||||
policyResult = result.Append(policyResult, &ruleApplicationResult)
|
||||
continue
|
||||
}
|
||||
|
||||
// Process Overlay
|
||||
|
||||
if rule.Mutation.Overlay != nil {
|
||||
overlayPatches, ruleResult := ProcessOverlay(rule.Mutation.Overlay, rawResource, gvk)
|
||||
} else {
|
||||
// Process Overlay
|
||||
overlayPatches, ruleResult := ProcessOverlay(rule, rawResource, gvk)
|
||||
if result.Success != ruleResult.GetReason() {
|
||||
ruleApplicationResult.MergeWith(&ruleResult)
|
||||
ruleApplicationResult.AddMessagef("Overlay application has failed for rule %s in policy %s\n", rule.Name, policy.ObjectMeta.Name)
|
||||
|
@ -38,13 +33,9 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
ruleApplicationResult.AddMessagef("Success")
|
||||
allPatches = append(allPatches, overlayPatches...)
|
||||
}
|
||||
}
|
||||
|
||||
// Process Patches
|
||||
|
||||
if rule.Mutation.Patches != nil {
|
||||
rulePatches, ruleResult := ProcessPatches(rule.Mutation.Patches, patchedDocument)
|
||||
|
||||
// Process Patches
|
||||
rulePatches, ruleResult := ProcessPatches(rule, patchedDocument)
|
||||
if result.Success != ruleResult.GetReason() {
|
||||
ruleApplicationResult.MergeWith(&ruleResult)
|
||||
ruleApplicationResult.AddMessagef("Patches application has failed for rule %s in policy %s\n", rule.Name, policy.ObjectMeta.Name)
|
||||
|
@ -53,6 +44,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
|||
allPatches = append(allPatches, rulePatches...)
|
||||
}
|
||||
}
|
||||
policyResult = result.Append(policyResult, &ruleApplicationResult)
|
||||
}
|
||||
|
||||
return allPatches, policyResult
|
||||
|
|
|
@ -7,23 +7,24 @@ import (
|
|||
"strconv"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
"github.com/nirmata/kyverno/pkg/result"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ProcessOverlay handles validating admission request
|
||||
// Checks the target resourse for rules defined in the policy
|
||||
func ProcessOverlay(overlay interface{}, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, result.RuleApplicationResult) {
|
||||
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, result.RuleApplicationResult) {
|
||||
overlayApplicationResult := result.NewRuleApplicationResult(rule.Name)
|
||||
if rule.Mutation == nil || rule.Mutation.Overlay == nil {
|
||||
return nil, overlayApplicationResult
|
||||
}
|
||||
|
||||
var resource interface{}
|
||||
var appliedPatches []PatchBytes
|
||||
json.Unmarshal(rawResource, &resource)
|
||||
|
||||
overlayApplicationResult := result.NewRuleApplicationResult("")
|
||||
if overlay == nil {
|
||||
return nil, overlayApplicationResult
|
||||
}
|
||||
|
||||
patch := applyOverlay(resource, overlay, "/", &overlayApplicationResult)
|
||||
patch := applyOverlay(resource, *rule.Mutation.Overlay, "/", &overlayApplicationResult)
|
||||
if overlayApplicationResult.GetReason() == result.Success {
|
||||
appliedPatches = append(appliedPatches, patch...)
|
||||
}
|
||||
|
@ -213,7 +214,7 @@ func processSubtree(overlay interface{}, path string, op string, res *result.Rul
|
|||
// check the patch
|
||||
_, err := jsonpatch.DecodePatch([]byte("[" + patchStr + "]"))
|
||||
if err != nil {
|
||||
res.FailWithMessagef("Failed to make '%s' patch from an overlay for path %s", op, path)
|
||||
res.FailWithMessagef("Failed to make '%s' patch from an overlay '%s' for path %s", op, value, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -234,3 +234,82 @@ func TestApplyOverlay_TestInsertToArray(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
assert.Assert(t, patched != nil)
|
||||
}
|
||||
|
||||
func TestApplyOverlay_ImagePullPolicy(t *testing.T) {
|
||||
overlayRaw := []byte(`{
|
||||
"spec": {
|
||||
"template": {
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"(image)": "*:latest",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
resourceRaw := []byte(`{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": "nginx-deployment",
|
||||
"labels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ghost",
|
||||
"image": "ghost:latest"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
var resource, overlay interface{}
|
||||
|
||||
json.Unmarshal(resourceRaw, &resource)
|
||||
json.Unmarshal(overlayRaw, &overlay)
|
||||
|
||||
res := result.NewRuleApplicationResult("")
|
||||
patches := applyOverlay(resource, overlay, "/", &res)
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patches) != 0)
|
||||
|
||||
doc, err := ApplyPatches(resourceRaw, patches)
|
||||
assert.NilError(t, err)
|
||||
expectedResult := []byte(`{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"nginx-deployment","labels":{"app":"nginx"}},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"nginx"}},"template":{"metadata":{"labels":{"app":"nginx"}},"spec":{"containers":[{"image":"nginx:latest","imagePullPolicy":"IfNotPresent","name":"nginx","ports":[{"containerPort":8080.000000},{"containerPort":80}]},{"image":"ghost:latest","imagePullPolicy":"IfNotPresent","name":"ghost","ports":[{"containerPort":8080.000000}]}]}}}}`)
|
||||
compareJsonAsMap(t, expectedResult, doc)
|
||||
}
|
||||
|
|
|
@ -14,9 +14,10 @@ type PatchBytes []byte
|
|||
|
||||
// ProcessPatches Returns array from separate patches that can be applied to the document
|
||||
// Returns error ONLY in case when creation of resource should be denied.
|
||||
func ProcessPatches(patches []kubepolicy.Patch, resource []byte) ([]PatchBytes, result.RuleApplicationResult) {
|
||||
res := result.RuleApplicationResult{
|
||||
Reason: result.Success,
|
||||
func ProcessPatches(rule kubepolicy.Rule, resource []byte) ([]PatchBytes, result.RuleApplicationResult) {
|
||||
res := result.NewRuleApplicationResult(rule.Name)
|
||||
if rule.Mutation == nil || len(rule.Mutation.Patches) == 0 {
|
||||
return nil, res
|
||||
}
|
||||
|
||||
if len(resource) == 0 {
|
||||
|
@ -27,7 +28,7 @@ func ProcessPatches(patches []kubepolicy.Patch, resource []byte) ([]PatchBytes,
|
|||
|
||||
var allPatches []PatchBytes
|
||||
patchedDocument := resource
|
||||
for i, patch := range patches {
|
||||
for i, patch := range rule.Mutation.Patches {
|
||||
patchRaw, err := json.Marshal(patch)
|
||||
if err != nil {
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ const endpointsDocument string = `{
|
|||
}`
|
||||
|
||||
func TestProcessPatches_EmptyPatches(t *testing.T) {
|
||||
var empty []types.Patch
|
||||
patches, res := ProcessPatches(empty, []byte(endpointsDocument))
|
||||
var emptyRule = types.Rule{}
|
||||
patches, res := ProcessPatches(emptyRule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patches) == 0)
|
||||
}
|
||||
|
@ -48,33 +48,47 @@ func makeAddIsMutatedLabelPatch() types.Patch {
|
|||
}
|
||||
}
|
||||
|
||||
func makeRuleWithPatch(patch types.Patch) types.Rule {
|
||||
patches := []types.Patch{patch}
|
||||
return makeRuleWithPatches(patches)
|
||||
}
|
||||
|
||||
func makeRuleWithPatches(patches []types.Patch) types.Rule {
|
||||
mutation := types.Mutation{
|
||||
Patches: patches,
|
||||
}
|
||||
return types.Rule{
|
||||
Mutation: &mutation,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessPatches_EmptyDocument(t *testing.T) {
|
||||
var patches []types.Patch
|
||||
patches = append(patches, makeAddIsMutatedLabelPatch())
|
||||
patchesBytes, res := ProcessPatches(patches, nil)
|
||||
rule := makeRuleWithPatch(makeAddIsMutatedLabelPatch())
|
||||
patchesBytes, res := ProcessPatches(rule, nil)
|
||||
assert.Assert(t, res.ToError() != nil)
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
||||
func TestProcessPatches_AllEmpty(t *testing.T) {
|
||||
patchesBytes, res := ProcessPatches(nil, nil)
|
||||
assert.Assert(t, res.ToError() != nil)
|
||||
emptyRule := types.Rule{}
|
||||
patchesBytes, res := ProcessPatches(emptyRule, nil)
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
||||
func TestProcessPatches_AddPathDoesntExist(t *testing.T) {
|
||||
patch := makeAddIsMutatedLabelPatch()
|
||||
patch.Path = "/metadata/additional/is-mutated"
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatch(patch)
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
||||
func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
|
||||
patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatch(patch)
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -82,8 +96,8 @@ func TestProcessPatches_RemovePathDoesntExist(t *testing.T) {
|
|||
func TestProcessPatches_AddAndRemovePathsDontExist_EmptyResult(t *testing.T) {
|
||||
patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patch2 := types.Patch{Path: "/spec/labels/label3", Operation: "add", Value: "label3Value"}
|
||||
patches := []types.Patch{patch1, patch2}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatches([]types.Patch{patch1, patch2})
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -92,8 +106,8 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
|||
patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patch2 := types.Patch{Path: "/spec/labels/label2", Operation: "remove", Value: "label2Value"}
|
||||
patch3 := types.Patch{Path: "/metadata/labels/label3", Operation: "add", Value: "label3Value"}
|
||||
patches := []types.Patch{patch1, patch2, patch3}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatches([]types.Patch{patch1, patch2, patch3})
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 1)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label3","op":"add","value":"label3Value"}`, patchesBytes[0])
|
||||
|
@ -101,8 +115,8 @@ func TestProcessPatches_AddAndRemovePathsDontExist_ContinueOnError_NotEmptyResul
|
|||
|
||||
func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
|
||||
patch := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patches := []types.Patch{patch}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatch(patch)
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 0)
|
||||
}
|
||||
|
@ -110,8 +124,8 @@ func TestProcessPatches_RemovePathDoesntExist_EmptyResult(t *testing.T) {
|
|||
func TestProcessPatches_RemovePathDoesntExist_NotEmptyResult(t *testing.T) {
|
||||
patch1 := types.Patch{Path: "/metadata/labels/is-mutated", Operation: "remove"}
|
||||
patch2 := types.Patch{Path: "/metadata/labels/label2", Operation: "add", Value: "label2Value"}
|
||||
patches := []types.Patch{patch1, patch2}
|
||||
patchesBytes, res := ProcessPatches(patches, []byte(endpointsDocument))
|
||||
rule := makeRuleWithPatches([]types.Patch{patch1, patch2})
|
||||
patchesBytes, res := ProcessPatches(rule, []byte(endpointsDocument))
|
||||
assert.NilError(t, res.ToError())
|
||||
assert.Assert(t, len(patchesBytes) == 1)
|
||||
assertEqStringAndData(t, `{"path":"/metadata/labels/label2","op":"add","value":"label2Value"}`, patchesBytes[0])
|
||||
|
|
|
@ -57,7 +57,7 @@ func validateResourceElement(value, pattern interface{}, path string) result.Rul
|
|||
case map[string]interface{}:
|
||||
typedValue, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", pattern, value, path)
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, pattern, value)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -65,12 +65,12 @@ func validateResourceElement(value, pattern interface{}, path string) result.Rul
|
|||
case []interface{}:
|
||||
typedValue, ok := value.([]interface{})
|
||||
if !ok {
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", pattern, value, path)
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", path, pattern, value)
|
||||
return res
|
||||
}
|
||||
|
||||
return validateArray(typedValue, typedPattern, path)
|
||||
case string, float64, int, int64, bool:
|
||||
case string, float64, int, int64, bool, nil:
|
||||
if !ValidateValueWithPattern(value, pattern) {
|
||||
res.FailWithMessagef("Failed to validate value %v with pattern %v. Path: %s", value, pattern, path)
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ func validateArray(resourceArray, patternArray []interface{}, path string) resul
|
|||
currentPath := path + strconv.Itoa(i) + "/"
|
||||
resource, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", pattern, value, currentPath)
|
||||
res.FailWithMessagef("Pattern and resource have different structures. Path: %s. Expected %T, found %T", currentPath, pattern, value)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ func validateArray(resourceArray, patternArray []interface{}, path string) resul
|
|||
res.Messages = append(res.Messages, mapValidationResult.Messages...)
|
||||
}
|
||||
}
|
||||
case string, float64, int, int64, bool:
|
||||
case string, float64, int, int64, bool, nil:
|
||||
for _, value := range resourceArray {
|
||||
if !ValidateValueWithPattern(value, pattern) {
|
||||
res.FailWithMessagef("Failed to validate value %v with pattern %v. Path: %s", value, pattern, path)
|
||||
|
|
|
@ -692,6 +692,185 @@ func TestValidateMap_AsteriskFieldIsMissing(t *testing.T) {
|
|||
assert.Assert(t, res.ToError() != nil)
|
||||
}
|
||||
|
||||
func TestValidateMap_livenessProbeIsNull(t *testing.T) {
|
||||
rawPattern := []byte(`{
|
||||
"spec":{
|
||||
"template":{
|
||||
"spec":{
|
||||
"containers":[
|
||||
{
|
||||
"name":"*",
|
||||
"livenessProbe":null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
rawMap := []byte(`{
|
||||
"apiVersion":"apps/v1",
|
||||
"kind":"StatefulSet",
|
||||
"metadata":{
|
||||
"name":"game-web",
|
||||
"labels":{
|
||||
"originalLabel":"isHere"
|
||||
}
|
||||
},
|
||||
"spec":{
|
||||
"selector":{
|
||||
"matchLabels":{
|
||||
"app":"nginxo"
|
||||
}
|
||||
},
|
||||
"serviceName":"nginxo",
|
||||
"replicas":3,
|
||||
"template":{
|
||||
"metadata":{
|
||||
"labels":{
|
||||
"app":"nginxo"
|
||||
}
|
||||
},
|
||||
"spec":{
|
||||
"terminationGracePeriodSeconds":10,
|
||||
"containers":[
|
||||
{
|
||||
"name":"nginxo",
|
||||
"image":"k8s.gcr.io/nginx-but-no-slim:0.8",
|
||||
"ports":[
|
||||
{
|
||||
"containerPort":8780,
|
||||
"name":"webp"
|
||||
}
|
||||
],
|
||||
"volumeMounts":[
|
||||
{
|
||||
"name":"www",
|
||||
"mountPath":"/usr/share/nginxo/html"
|
||||
}
|
||||
],
|
||||
"livenessProbe":null
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"volumeClaimTemplates":[
|
||||
{
|
||||
"metadata":{
|
||||
"name":"www"
|
||||
},
|
||||
"spec":{
|
||||
"accessModes":[
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"storageClassName":"my-storage-class",
|
||||
"resources":{
|
||||
"requests":{
|
||||
"storage":"1Gi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`)
|
||||
|
||||
var pattern, resource map[string]interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
|
||||
res := validateMap(resource, pattern, "/")
|
||||
assert.NilError(t, res.ToError())
|
||||
}
|
||||
|
||||
func TestValidateMap_livenessProbeIsMissing(t *testing.T) {
|
||||
rawPattern := []byte(`{
|
||||
"spec":{
|
||||
"template":{
|
||||
"spec":{
|
||||
"containers":[
|
||||
{
|
||||
"name":"*",
|
||||
"livenessProbe" : null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`)
|
||||
rawMap := []byte(`{
|
||||
"apiVersion":"apps/v1",
|
||||
"kind":"StatefulSet",
|
||||
"metadata":{
|
||||
"name":"game-web",
|
||||
"labels":{
|
||||
"originalLabel":"isHere"
|
||||
}
|
||||
},
|
||||
"spec":{
|
||||
"selector":{
|
||||
"matchLabels":{
|
||||
"app":"nginxo"
|
||||
}
|
||||
},
|
||||
"serviceName":"nginxo",
|
||||
"replicas":3,
|
||||
"template":{
|
||||
"metadata":{
|
||||
"labels":{
|
||||
"app":"nginxo"
|
||||
}
|
||||
},
|
||||
"spec":{
|
||||
"terminationGracePeriodSeconds":10,
|
||||
"containers":[
|
||||
{
|
||||
"name":"nginxo",
|
||||
"image":"k8s.gcr.io/nginx-but-no-slim:0.8",
|
||||
"ports":[
|
||||
{
|
||||
"containerPort":8780,
|
||||
"name":"webp"
|
||||
}
|
||||
],
|
||||
"volumeMounts":[
|
||||
{
|
||||
"name":"www",
|
||||
"mountPath":"/usr/share/nginxo/html"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"volumeClaimTemplates":[
|
||||
{
|
||||
"metadata":{
|
||||
"name":"www"
|
||||
},
|
||||
"spec":{
|
||||
"accessModes":[
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"storageClassName":"my-storage-class",
|
||||
"resources":{
|
||||
"requests":{
|
||||
"storage":"1Gi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`)
|
||||
|
||||
var pattern, resource map[string]interface{}
|
||||
json.Unmarshal(rawPattern, &pattern)
|
||||
json.Unmarshal(rawMap, &resource)
|
||||
|
||||
res := validateMap(resource, pattern, "/")
|
||||
assert.NilError(t, res.ToError())
|
||||
}
|
||||
|
||||
func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
||||
rawPattern := []byte(`[
|
||||
{
|
||||
|
|
|
@ -51,7 +51,6 @@ func NewCmdApply(in io.Reader, out, errout io.Writer) *cobra.Command {
|
|||
}
|
||||
|
||||
func complete(kubeconfig string, args []string) (*kubepolicy.Policy, []*resourceInfo) {
|
||||
|
||||
policyDir, resourceDir, err := validateDir(args)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to parse file path, err: %v\n", err)
|
||||
|
@ -61,14 +60,14 @@ func complete(kubeconfig string, args []string) (*kubepolicy.Policy, []*resource
|
|||
// extract policy
|
||||
policy, err := extractPolicy(policyDir)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to extract policy: %v\n", err)
|
||||
glog.Errorf("Failed to extract policy: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// extract rawResource
|
||||
resources, err := extractResource(resourceDir, kubeconfig)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to parse resource: %v", err)
|
||||
glog.Errorf("Failed to parse resource: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -98,8 +97,8 @@ func applyPolicyOnRaw(policy *kubepolicy.Policy, rawResource []byte, gvk *metav1
|
|||
patches, result := engine.Mutate(*policy, rawResource, *gvk)
|
||||
|
||||
err := result.ToError()
|
||||
var patchedResource []byte
|
||||
if err == nil {
|
||||
patchedResource := rawResource
|
||||
if err == nil && len(patches) != 0 {
|
||||
patchedResource, err = engine.ApplyPatches(rawResource, patches)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to apply mutation patches:\n%v", err)
|
||||
|
|
|
@ -14,7 +14,7 @@ const (
|
|||
TabIndent Indent = "\t"
|
||||
)
|
||||
|
||||
// Result is an interface that is used for result polymorphic behavio
|
||||
// Result is an interface that is used for result polymorphic behavior
|
||||
type Result interface {
|
||||
String() string
|
||||
StringWithIndent(indent string) string
|
||||
|
|
|
@ -153,7 +153,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
}
|
||||
}
|
||||
|
||||
message := admissionResult.String()
|
||||
message := "\n" + admissionResult.String()
|
||||
glog.Info(message)
|
||||
|
||||
if admissionResult.GetReason() == result.Success {
|
||||
|
@ -195,7 +195,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
}
|
||||
}
|
||||
|
||||
message := admissionResult.String()
|
||||
message := "\n" + admissionResult.String()
|
||||
glog.Info(message)
|
||||
|
||||
// Generation loop after all validation succeeded
|
||||
|
|
Loading…
Add table
Reference in a new issue