mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-31 03:45:17 +00:00
Merge branch 'develop' into 25_CLI-tool
This commit is contained in:
commit
fae1a4b058
6 changed files with 206 additions and 206 deletions
|
@ -18,35 +18,20 @@ type GenerationResponse struct {
|
||||||
// TODO: extend kubeclient(will change to dynamic client) to create resources
|
// TODO: extend kubeclient(will change to dynamic client) to create resources
|
||||||
func Generate(policy kubepolicy.Policy, rawResource []byte, kubeClient *kubeClient.KubeClient, gvk metav1.GroupVersionKind) {
|
func Generate(policy kubepolicy.Policy, rawResource []byte, kubeClient *kubeClient.KubeClient, gvk metav1.GroupVersionKind) {
|
||||||
// configMapGenerator and secretGenerator can be applied only to namespaces
|
// configMapGenerator and secretGenerator can be applied only to namespaces
|
||||||
|
// TODO: support for any resource
|
||||||
if gvk.Kind != "Namespace" {
|
if gvk.Kind != "Namespace" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
|
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk)
|
||||||
// Checks for preconditions
|
|
||||||
// TODO: Rework PolicyEngine interface that it receives not a policy, but mutation object for
|
|
||||||
// Mutate, validation for Validate and so on. It will allow to bring this checks outside of PolicyEngine
|
|
||||||
// to common part as far as they present for all: mutation, validation, generation
|
|
||||||
|
|
||||||
err := rule.Validate()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid structure: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid data: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Printf("Rule is not applicable to the request: rule name = %s in policy %s \n", rule.Name, policy.ObjectMeta.Name)
|
log.Printf("Rule is not applicable to the request: rule name = %s in policy %s \n", rule.Name, policy.ObjectMeta.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = applyRuleGenerator(rawResource, rule.Generation, kubeClient)
|
err := applyRuleGenerator(rawResource, rule.Generation, kubeClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to apply rule generator: %v", err)
|
log.Printf("Failed to apply rule generator: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -60,10 +45,7 @@ func applyRuleGenerator(rawResource []byte, generator *kubepolicy.Generation, ku
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := generator.Validate()
|
var err error
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Generator for '%s/%s' is invalid: %s", generator.Kind, generator.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace := ParseNameFromObject(rawResource)
|
namespace := ParseNameFromObject(rawResource)
|
||||||
switch generator.Kind {
|
switch generator.Kind {
|
||||||
|
|
|
@ -15,40 +15,23 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
||||||
var processedPatches []mutation.PatchBytes
|
var processedPatches []mutation.PatchBytes
|
||||||
patchedDocument := rawResource
|
patchedDocument := rawResource
|
||||||
|
|
||||||
for i, rule := range policy.Spec.Rules {
|
for _, rule := range policy.Spec.Rules {
|
||||||
|
|
||||||
// Checks for preconditions
|
|
||||||
// TODO: Rework PolicyEngine interface that it receives not a policy, but mutation object for
|
|
||||||
// Mutate, validation for Validate and so on. It will allow to bring this checks outside of PolicyEngine
|
|
||||||
// to common part as far as they present for all: mutation, validation, generation
|
|
||||||
|
|
||||||
err := rule.Validate()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid structure: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid data: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
log.Printf("Rule is not applicable to the request: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule.Mutation == nil {
|
if rule.Mutation == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Rule \"%s\" is not applicable to resource\n", rule.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Process Overlay
|
// Process Overlay
|
||||||
|
|
||||||
if rule.Mutation.Overlay != nil {
|
if rule.Mutation.Overlay != nil {
|
||||||
overlayPatches, err := mutation.ProcessOverlay(rule.Mutation.Overlay, rawResource)
|
overlayPatches, err := mutation.ProcessOverlay(rule.Mutation.Overlay, rawResource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Overlay application failed: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
log.Printf("Overlay application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||||
} else {
|
} else {
|
||||||
policyPatches = append(policyPatches, overlayPatches...)
|
policyPatches = append(policyPatches, overlayPatches...)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +42,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
|
||||||
if rule.Mutation.Patches != nil {
|
if rule.Mutation.Patches != nil {
|
||||||
processedPatches, patchedDocument, err = mutation.ProcessPatches(rule.Mutation.Patches, patchedDocument)
|
processedPatches, patchedDocument, err = mutation.ProcessPatches(rule.Mutation.Patches, patchedDocument)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Patches application failed: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
log.Printf("Patches application has failed for rule %s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
|
||||||
} else {
|
} else {
|
||||||
policyPatches = append(policyPatches, processedPatches...)
|
policyPatches = append(policyPatches, processedPatches...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceMeetsRules checks requests kind, name and labels to fit the policy
|
// ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule
|
||||||
func ResourceMeetsRules(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) (bool, error) {
|
func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.ResourceDescription, gvk metav1.GroupVersionKind) bool {
|
||||||
if description.Kind != gvk.Kind {
|
if description.Kind != gvk.Kind {
|
||||||
return false, nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceRaw != nil {
|
if resourceRaw != nil {
|
||||||
|
@ -24,7 +24,7 @@ func ResourceMeetsRules(resourceRaw []byte, description kubepolicy.ResourceDescr
|
||||||
if description.Name != nil {
|
if description.Name != nil {
|
||||||
|
|
||||||
if !wildcard.Match(*description.Name, name) {
|
if !wildcard.Match(*description.Name, name) {
|
||||||
return false, nil
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,18 +32,18 @@ func ResourceMeetsRules(resourceRaw []byte, description kubepolicy.ResourceDescr
|
||||||
selector, err := metav1.LabelSelectorAsSelector(description.Selector)
|
selector, err := metav1.LabelSelectorAsSelector(description.Selector)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
labelMap := ParseLabelsFromMetadata(meta)
|
labelMap := ParseLabelsFromMetadata(meta)
|
||||||
|
|
||||||
if !selector.Matches(labelMap) {
|
if !selector.Matches(labelMap) {
|
||||||
return false, nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, nil
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseMetadataFromObject(bytes []byte) map[string]interface{} {
|
func ParseMetadataFromObject(bytes []byte) map[string]interface{} {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: This operators are already implemented in kubernetes
|
// Operator is string alias that represents selection operators enum
|
||||||
type Operator string
|
type Operator string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -25,66 +25,50 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Refactor using State pattern
|
// TODO: Refactor using State pattern
|
||||||
|
// TODO: Return Events and pass all checks to get all validation errors (not )
|
||||||
|
|
||||||
// Validate handles validating admission request
|
// Validate handles validating admission request
|
||||||
// Checks the target resourse for rules defined in the policy
|
// Checks the target resourse for rules defined in the policy
|
||||||
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) bool {
|
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) error {
|
||||||
var resource interface{}
|
var resource interface{}
|
||||||
json.Unmarshal(rawResource, &resource)
|
json.Unmarshal(rawResource, &resource)
|
||||||
|
|
||||||
allowed := true
|
for _, rule := range policy.Spec.Rules {
|
||||||
for i, rule := range policy.Spec.Rules {
|
|
||||||
|
|
||||||
// Checks for preconditions
|
|
||||||
// TODO: Rework PolicyEngine interface that it receives not a policy, but mutation object for
|
|
||||||
// Mutate, validation for Validate and so on. It will allow to bring this checks outside of PolicyEngine
|
|
||||||
// to common part as far as they present for all: mutation, validation, generation
|
|
||||||
|
|
||||||
err := rule.Validate()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid structure: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := ResourceMeetsRules(rawResource, rule.ResourceDescription, gvk)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Rule has invalid data: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
log.Printf("Rule is not applicable to the request: rule number = %d, rule name = %s in policy %s, err: %v\n", i, rule.Name, policy.ObjectMeta.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule.Validation == nil {
|
if rule.Validation == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validateMap(resource, rule.Validation.Pattern) {
|
ok := ResourceMeetsDescription(rawResource, rule.ResourceDescription, gvk)
|
||||||
log.Printf("Validation with the rule %s has failed: %s\n", rule.Name, *rule.Validation.Message)
|
if !ok {
|
||||||
allowed = false
|
log.Printf("Rule \"%s\" is not applicable to resource\n", rule.Name)
|
||||||
} else {
|
continue
|
||||||
log.Printf("Validation rule %s is successful\n", rule.Name)
|
}
|
||||||
|
|
||||||
|
if err := validateMap(resource, rule.Validation.Pattern); err != nil {
|
||||||
|
message := *rule.Validation.Message
|
||||||
|
if len(message) == 0 {
|
||||||
|
message = fmt.Sprintf("%v", err)
|
||||||
|
} else {
|
||||||
|
message = fmt.Sprintf("%s, %s", message, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%s: %s", *rule.Validation.Message, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allowed
|
log.Println("Validation is successful")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateMap(resourcePart, patternPart interface{}) bool {
|
func validateMap(resourcePart, patternPart interface{}) error {
|
||||||
pattern, ok := patternPart.(map[string]interface{})
|
pattern, ok := patternPart.(map[string]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected Map, found %T\n", patternPart)
|
return fmt.Errorf("expected map, found %T", patternPart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource, ok := resourcePart.(map[string]interface{})
|
resource, ok := resourcePart.(map[string]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected Map, found %T\n", resourcePart)
|
return fmt.Errorf("expected map, found %T", resourcePart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range pattern {
|
for key, value := range pattern {
|
||||||
|
@ -92,98 +76,106 @@ func validateMap(resourcePart, patternPart interface{}) bool {
|
||||||
key = key[1 : len(key)-1]
|
key = key[1 : len(key)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validateMapElement(resource[key], value) {
|
if err := validateMapElement(resource[key], value); err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateArray(resourcePart, patternPart interface{}) bool {
|
func validateArray(resourcePart, patternPart interface{}) error {
|
||||||
patternArray, ok := patternPart.([]interface{})
|
patternArray, ok := patternPart.([]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected array, found %T\n", patternPart)
|
return fmt.Errorf("expected array, found %T", patternPart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceArray, ok := resourcePart.([]interface{})
|
resourceArray, ok := resourcePart.([]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected array, found %T\n", resourcePart)
|
return fmt.Errorf("expected array, found %T", resourcePart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch pattern := patternArray[0].(type) {
|
switch pattern := patternArray[0].(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
anchors, err := getAnchorsFromMap(pattern)
|
anchors, err := getAnchorsFromMap(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Validating error: %v\n", err)
|
return err
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, value := range resourceArray {
|
for _, value := range resourceArray {
|
||||||
resource, ok := value.(map[string]interface{})
|
resource, ok := value.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected Map, found %T\n", resourcePart)
|
return fmt.Errorf("expected array, found %T", resourcePart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if skipArrayObject(resource, anchors) {
|
if skipArrayObject(resource, anchors) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validateMap(resource, pattern) {
|
if err := validateMap(resource, pattern); err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
default:
|
default:
|
||||||
for _, value := range resourceArray {
|
for _, value := range resourceArray {
|
||||||
if !checkSingleValue(value, patternArray[0]) {
|
if err := checkSingleValue(value, patternArray[0]); err != nil {
|
||||||
return false
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateMapElement(resourcePart, patternPart interface{}) bool {
|
func validateMapElement(resourcePart, patternPart interface{}) error {
|
||||||
switch pattern := patternPart.(type) {
|
switch pattern := patternPart.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
dictionary, ok := resourcePart.(map[string]interface{})
|
dictionary, ok := resourcePart.(map[string]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
return fmt.Errorf("expected %T, found %T", patternPart, resourcePart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateMap(dictionary, pattern)
|
return validateMap(dictionary, pattern)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
array, ok := resourcePart.([]interface{})
|
array, ok := resourcePart.([]interface{})
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
return fmt.Errorf("expected %T, found %T", patternPart, resourcePart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return validateArray(array, pattern)
|
return validateArray(array, pattern)
|
||||||
case string:
|
case string:
|
||||||
str, ok := resourcePart.(string)
|
return checkSingleValue(resourcePart, patternPart)
|
||||||
|
case float64:
|
||||||
if !ok {
|
switch num := resourcePart.(type) {
|
||||||
fmt.Printf("Validating error: expected %T, found %T\n", patternPart, resourcePart)
|
case float64:
|
||||||
return false
|
if num != pattern {
|
||||||
|
return fmt.Errorf("%f not equal %f", num, pattern)
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if float64(num) != pattern {
|
||||||
|
return fmt.Errorf("%d not equal %f", num, pattern)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("expected %T, found %T", patternPart, resourcePart)
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
switch num := resourcePart.(type) {
|
||||||
|
case float64:
|
||||||
|
if num != float64(pattern) {
|
||||||
|
return fmt.Errorf("%f not equal %d", num, pattern)
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if float64(num) != float64(num) {
|
||||||
|
return fmt.Errorf("%d not equal %d", num, pattern)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("expected %T, found %T", patternPart, resourcePart)
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkSingleValue(str, pattern)
|
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Validating error: unknown type in map: %T\n", patternPart)
|
return fmt.Errorf("validating error: unknown type in map: %T", patternPart)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAnchorsFromMap(pattern map[string]interface{}) (map[string]interface{}, error) {
|
func getAnchorsFromMap(pattern map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
@ -207,7 +199,7 @@ func skipArrayObject(object, anchors map[string]interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !checkSingleValue(value, pattern) {
|
if err := checkSingleValue(value, pattern); err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +207,7 @@ func skipArrayObject(object, anchors map[string]interface{}) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSingleValue(value, pattern interface{}) bool {
|
func checkSingleValue(value, pattern interface{}) error {
|
||||||
switch typedPattern := pattern.(type) {
|
switch typedPattern := pattern.(type) {
|
||||||
case string:
|
case string:
|
||||||
switch typedValue := value.(type) {
|
switch typedValue := value.(type) {
|
||||||
|
@ -226,46 +218,54 @@ func checkSingleValue(value, pattern interface{}) bool {
|
||||||
case int:
|
case int:
|
||||||
return checkForOperator(float64(typedValue), typedPattern)
|
return checkForOperator(float64(typedValue), typedPattern)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Validating error: expected string or numerical type, found %T, pattern: %s\n", value, typedPattern)
|
return fmt.Errorf("expected string or numerical type, found %T, pattern: %s", value, typedPattern)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
case float64:
|
case float64:
|
||||||
num, ok := value.(float64)
|
num, ok := value.(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected float, found %T\n", value)
|
return fmt.Errorf("expected float, found %T", value)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return typedPattern == num
|
if typedPattern != num {
|
||||||
|
return fmt.Errorf("value %f is not equal to pattern %f", value, typedPattern)
|
||||||
|
}
|
||||||
case int:
|
case int:
|
||||||
num, ok := value.(int)
|
num, ok := value.(int)
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Printf("Validating error: expected int, found %T\n", value)
|
return fmt.Errorf("expected int, found %T", value)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return typedPattern == num
|
if typedPattern != num {
|
||||||
|
return fmt.Errorf("value %d is not equal to pattern %d", num, typedPattern)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Validating error: expected pattern (string or numerical type), found %T\n", pattern)
|
return fmt.Errorf("expected pattern (string or numerical type), found %T", pattern)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkForWildcard(value, pattern string) bool {
|
func checkForWildcard(value, pattern string) error {
|
||||||
return wildcard.Match(pattern, value)
|
if !wildcard.Match(pattern, value) {
|
||||||
|
return fmt.Errorf("wildcard check has failed. Pattern: \"%s\". Value: \"%s\"", pattern, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkForOperator(value float64, pattern string) bool {
|
func checkForOperator(value float64, pattern string) error {
|
||||||
operators := strings.Split(pattern, "|")
|
operators := strings.Split(pattern, "|")
|
||||||
|
|
||||||
for _, operator := range operators {
|
for _, operator := range operators {
|
||||||
operator = strings.Replace(operator, " ", "", -1)
|
operator = strings.Replace(operator, " ", "", -1)
|
||||||
|
|
||||||
|
// At least one success - return nil
|
||||||
if checkSingleOperator(value, operator) {
|
if checkSingleOperator(value, operator) {
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return fmt.Errorf("operator check has failed. Pattern: \"%s\". Value: \"%f\"", pattern, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSingleOperator(value float64, pattern string) bool {
|
func checkSingleOperator(value float64, pattern string) bool {
|
||||||
|
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
kubepolicy "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) {
|
func TestWrappedWithParentheses_StringIsWrappedWithParentheses(t *testing.T) {
|
||||||
|
@ -62,190 +64,190 @@ func TestCheckForWildcard_LeftAsteriskTest(t *testing.T) {
|
||||||
value = "leftmiddle"
|
value = "leftmiddle"
|
||||||
middle := "middle"
|
middle := "middle"
|
||||||
|
|
||||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
assert.Assert(t, checkForWildcard(value, pattern) != nil)
|
||||||
assert.Assert(t, !checkForWildcard(middle, pattern))
|
assert.Assert(t, checkForWildcard(middle, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckForWildcard_MiddleAsteriskTest(t *testing.T) {
|
func TestCheckForWildcard_MiddleAsteriskTest(t *testing.T) {
|
||||||
pattern := "ab*ba"
|
pattern := "ab*ba"
|
||||||
value := "abbba"
|
value := "abbeba"
|
||||||
assert.Assert(t, checkForWildcard(value, pattern))
|
assert.NilError(t, checkForWildcard(value, pattern))
|
||||||
|
|
||||||
value = "abbca"
|
value = "abbca"
|
||||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
assert.Assert(t, checkForWildcard(value, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckForWildcard_QuestionMark(t *testing.T) {
|
func TestCheckForWildcard_QuestionMark(t *testing.T) {
|
||||||
pattern := "ab?ba"
|
pattern := "ab?ba"
|
||||||
value := "abbba"
|
value := "abbba"
|
||||||
assert.Assert(t, checkForWildcard(value, pattern))
|
assert.NilError(t, checkForWildcard(value, pattern))
|
||||||
|
|
||||||
value = "abbbba"
|
value = "abbbba"
|
||||||
assert.Assert(t, !checkForWildcard(value, pattern))
|
assert.Assert(t, checkForWildcard(value, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckInt(t *testing.T) {
|
func TestCheckSingleValue_CheckInt(t *testing.T) {
|
||||||
pattern := 89
|
pattern := 89
|
||||||
value := 89
|
value := 89
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
value = 202
|
value = 202
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckFloat(t *testing.T) {
|
func TestCheckSingleValue_CheckFloat(t *testing.T) {
|
||||||
pattern := 89.9091
|
pattern := 89.9091
|
||||||
value := 89.9091
|
value := 89.9091
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
value = 89.9092
|
value = 89.9092
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorMoreEqual(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorMoreEqual(t *testing.T) {
|
||||||
pattern := " >= 89 "
|
pattern := " >= 89 "
|
||||||
value := 89
|
value := 89
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = ">=10.0001"
|
pattern = ">=10.0001"
|
||||||
floatValue := 89.901
|
floatValue := 89.901
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorMoreEqualFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorMoreEqualFail(t *testing.T) {
|
||||||
pattern := " >= 90 "
|
pattern := " >= 90 "
|
||||||
value := 89
|
value := 89
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = ">=910.0001"
|
pattern = ">=910.0001"
|
||||||
floatValue := 89.901
|
floatValue := 89.901
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorLessEqual(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorLessEqual(t *testing.T) {
|
||||||
pattern := " <= 1 "
|
pattern := " <= 1 "
|
||||||
value := 1
|
value := 1
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = "<=10.0001"
|
pattern = "<=10.0001"
|
||||||
floatValue := 1.901
|
floatValue := 1.901
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorLessEqualFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorLessEqualFail(t *testing.T) {
|
||||||
pattern := " <= 0.1558 "
|
pattern := " <= 0.1558 "
|
||||||
value := 1
|
value := 1
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = "<=10.0001"
|
pattern = "<=10.0001"
|
||||||
floatValue := 12.901
|
floatValue := 12.901
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorMore(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorMore(t *testing.T) {
|
||||||
pattern := " > 10 "
|
pattern := " > 10 "
|
||||||
value := 89
|
value := 89
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = ">10.0001"
|
pattern = ">10.0001"
|
||||||
floatValue := 89.901
|
floatValue := 89.901
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorMoreFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorMoreFail(t *testing.T) {
|
||||||
pattern := " > 89 "
|
pattern := " > 89 "
|
||||||
value := 89
|
value := 89
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = ">910.0001"
|
pattern = ">910.0001"
|
||||||
floatValue := 89.901
|
floatValue := 89.901
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorLess(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorLess(t *testing.T) {
|
||||||
pattern := " < 10 "
|
pattern := " < 10 "
|
||||||
value := 9
|
value := 9
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = "<10.0001"
|
pattern = "<10.0001"
|
||||||
floatValue := 9.901
|
floatValue := 9.901
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorLessFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorLessFail(t *testing.T) {
|
||||||
pattern := " < 10 "
|
pattern := " < 10 "
|
||||||
value := 10
|
value := 10
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = "<10.0001"
|
pattern = "<10.0001"
|
||||||
floatValue := 19.901
|
floatValue := 19.901
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorNotEqual(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorNotEqual(t *testing.T) {
|
||||||
pattern := " != 10 "
|
pattern := " != 10 "
|
||||||
value := 9.99999
|
value := 9.99999
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = "!=10.0001"
|
pattern = "!=10.0001"
|
||||||
floatValue := 10.0000
|
floatValue := 10.0000
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorNotEqualFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorNotEqualFail(t *testing.T) {
|
||||||
pattern := " != 9.99999 "
|
pattern := " != 9.99999 "
|
||||||
value := 9.99999
|
value := 9.99999
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = "!=10"
|
pattern = "!=10"
|
||||||
floatValue := 10
|
floatValue := 10
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorEqual(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorEqual(t *testing.T) {
|
||||||
pattern := " 10.000001 "
|
pattern := " 10.000001 "
|
||||||
value := 10.000001
|
value := 10.000001
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = "10.000000"
|
pattern = "10.000000"
|
||||||
floatValue := 10
|
floatValue := 10
|
||||||
assert.Assert(t, checkSingleValue(floatValue, pattern))
|
assert.NilError(t, checkSingleValue(floatValue, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckOperatorEqualFail(t *testing.T) {
|
func TestCheckSingleValue_CheckOperatorEqualFail(t *testing.T) {
|
||||||
pattern := " 10.000000 "
|
pattern := " 10.000000 "
|
||||||
value := 10.000001
|
value := 10.000001
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = "10.000001"
|
pattern = "10.000001"
|
||||||
floatValue := 10
|
floatValue := 10
|
||||||
assert.Assert(t, !checkSingleValue(floatValue, pattern))
|
assert.Assert(t, checkSingleValue(floatValue, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckSeveralOperators(t *testing.T) {
|
func TestCheckSingleValue_CheckSeveralOperators(t *testing.T) {
|
||||||
pattern := " <-1 | 10.000001 "
|
pattern := " <-1 | 10.000001 "
|
||||||
value := 10.000001
|
value := 10.000001
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
value = -30
|
value = -30
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
value = 5
|
value = 5
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckSingleValue_CheckWildcard(t *testing.T) {
|
func TestCheckSingleValue_CheckWildcard(t *testing.T) {
|
||||||
pattern := "nirmata_*"
|
pattern := "nirmata_*"
|
||||||
value := "nirmata_awesome"
|
value := "nirmata_awesome"
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
|
|
||||||
pattern = "nirmata_*"
|
pattern = "nirmata_*"
|
||||||
value = "spasex_awesome"
|
value = "spasex_awesome"
|
||||||
assert.Assert(t, !checkSingleValue(value, pattern))
|
assert.Assert(t, checkSingleValue(value, pattern) != nil)
|
||||||
|
|
||||||
pattern = "g?t"
|
pattern = "g?t"
|
||||||
value = "git"
|
value = "git"
|
||||||
assert.Assert(t, checkSingleValue(value, pattern))
|
assert.NilError(t, checkSingleValue(value, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkipArrayObject_OneAnchor(t *testing.T) {
|
func TestSkipArrayObject_OneAnchor(t *testing.T) {
|
||||||
|
@ -330,7 +332,7 @@ func TestValidateMapElement_TwoElementsInArrayOnePass(t *testing.T) {
|
||||||
json.Unmarshal(rawPattern, &pattern)
|
json.Unmarshal(rawPattern, &pattern)
|
||||||
json.Unmarshal(rawMap, &resource)
|
json.Unmarshal(rawMap, &resource)
|
||||||
|
|
||||||
assert.Assert(t, validateMapElement(resource, pattern))
|
assert.NilError(t, validateMapElement(resource, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
||||||
|
@ -341,7 +343,7 @@ func TestValidateMapElement_OneElementInArrayPass(t *testing.T) {
|
||||||
json.Unmarshal(rawPattern, &pattern)
|
json.Unmarshal(rawPattern, &pattern)
|
||||||
json.Unmarshal(rawMap, &resource)
|
json.Unmarshal(rawMap, &resource)
|
||||||
|
|
||||||
assert.Assert(t, validateMapElement(resource, pattern))
|
assert.NilError(t, validateMapElement(resource, pattern))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
||||||
|
@ -352,5 +354,33 @@ func TestValidateMapElement_OneElementInArrayNotPass(t *testing.T) {
|
||||||
json.Unmarshal(rawPattern, &pattern)
|
json.Unmarshal(rawPattern, &pattern)
|
||||||
json.Unmarshal(rawMap, &resource)
|
json.Unmarshal(rawMap, &resource)
|
||||||
|
|
||||||
assert.Assert(t, !validateMapElement(resource, pattern))
|
assert.Assert(t, validateMapElement(resource, pattern) != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidate_ServiceTest(t *testing.T) {
|
||||||
|
rawPolicy := []byte(`{ "apiVersion": "kubepolicy.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-service" }, "spec": { "rules": [ { "name": "ps1", "resource": { "kind": "Service", "name": "game-service*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/secretLabel", "op": "replace", "value": "weKnow" }, { "path": "/metadata/labels/originalLabel", "op": "remove" }, { "path": "/spec/selector/app", "op": "replace", "value": "mutedApp" } ] }, "validate": { "message": "This resource is broken", "pattern": { "spec": { "ports": [ { "name": "hs", "protocol": 32 } ] } } } } ] } }`)
|
||||||
|
rawResource := []byte(`{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "game-service", "labels": { "originalLabel": "isHere", "secretLabel": "thisIsMySecret" } }, "spec": { "selector": { "app": "MyApp" }, "ports": [ { "name": "http", "protocol": "TCP", "port": 80, "targetPort": 9376 } ] } }`)
|
||||||
|
|
||||||
|
var policy kubepolicy.Policy
|
||||||
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
|
|
||||||
|
gvk := metav1.GroupVersionKind{
|
||||||
|
Kind: "Service",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Assert(t, Validate(policy, rawResource, gvk) != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidate_MapHasFloats(t *testing.T) {
|
||||||
|
rawPolicy := []byte(`{ "apiVersion": "kubepolicy.nirmata.io/v1alpha1", "kind": "Policy", "metadata": { "name": "policy-deployment-changed" }, "spec": { "rules": [ { "name": "First policy v2", "resource": { "kind": "Deployment", "name": "nginx-*" }, "mutate": { "patches": [ { "path": "/metadata/labels/isMutated", "op": "add", "value": "true" }, { "path": "/metadata/labels/app", "op": "replace", "value": "nginx_is_mutated" } ] }, "validate": { "message": "replicas number is wrong", "pattern": { "metadata": { "labels": { "app": "*" } }, "spec": { "replicas": 3 } } } } ] } }`)
|
||||||
|
rawResource := []byte(`{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": { "name": "nginx-deployment", "labels": { "app": "nginx" } }, "spec": { "replicas": 3, "selector": { "matchLabels": { "app": "nginx" } }, "template": { "metadata": { "labels": { "app": "nginx" } }, "spec": { "containers": [ { "name": "nginx", "image": "nginx:1.7.9", "ports": [ { "containerPort": 80 } ] } ] } } } }`)
|
||||||
|
|
||||||
|
var policy kubepolicy.Policy
|
||||||
|
json.Unmarshal(rawPolicy, &policy)
|
||||||
|
|
||||||
|
gvk := metav1.GroupVersionKind{
|
||||||
|
Kind: "Deployment",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NilError(t, Validate(policy, rawResource, gvk))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ import (
|
||||||
"github.com/nirmata/kube-policy/pkg/engine/mutation"
|
"github.com/nirmata/kube-policy/pkg/engine/mutation"
|
||||||
tlsutils "github.com/nirmata/kube-policy/pkg/tls"
|
tlsutils "github.com/nirmata/kube-policy/pkg/tls"
|
||||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebhookServer contains configured TLS server with MutationWebhook.
|
// WebhookServer contains configured TLS server with MutationWebhook.
|
||||||
|
@ -139,7 +139,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
||||||
|
|
||||||
policies, err := ws.policyLister.List(labels.NewSelector())
|
policies, err := ws.policyLister.List(labels.NewSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(err)
|
ws.logger.Printf("%v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
||||||
if len(policyPatches) > 0 {
|
if len(policyPatches) > 0 {
|
||||||
namespace := engine.ParseNamespaceFromObject(request.Object.Raw)
|
namespace := engine.ParseNamespaceFromObject(request.Object.Raw)
|
||||||
name := engine.ParseNameFromObject(request.Object.Raw)
|
name := engine.ParseNameFromObject(request.Object.Raw)
|
||||||
ws.logger.Printf("Policy %s applied to %s %s/%s", policy.Name, request.Kind.Kind, namespace, name)
|
ws.logger.Printf("Mutation from policy %s has applied to %s %s/%s", policy.Name, request.Kind.Kind, namespace, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,30 +172,35 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
||||||
|
|
||||||
policies, err := ws.policyLister.List(labels.NewSelector())
|
policies, err := ws.policyLister.List(labels.NewSelector())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(err)
|
ws.logger.Printf("%v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed := true
|
|
||||||
for _, policy := range policies {
|
for _, policy := range policies {
|
||||||
// validation
|
// validation
|
||||||
ws.logger.Printf("Validating resource with policy %s with %d rules", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
ws.logger.Printf("Validating resource with policy %s with %d rules", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||||
|
|
||||||
if ok := engine.Validate(*policy, request.Object.Raw, request.Kind); !ok {
|
if err := engine.Validate(*policy, request.Object.Raw, request.Kind); err != nil {
|
||||||
ws.logger.Printf("Validation has failed: %v\n", err)
|
message := fmt.Sprintf("validation has failed: %s", err.Error())
|
||||||
utilruntime.HandleError(err)
|
ws.logger.Println(message)
|
||||||
allowed = false
|
|
||||||
} else {
|
return &v1beta1.AdmissionResponse{
|
||||||
ws.logger.Println("Validation is successful")
|
Allowed: false,
|
||||||
|
Result: &metav1.Status{
|
||||||
|
Message: message,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generation
|
// generation
|
||||||
engine.Generate(*policy, request.Object.Raw, ws.kubeClient, request.Kind)
|
engine.Generate(*policy, request.Object.Raw, ws.kubeClient, request.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ws.logger.Println("Validation is successful")
|
||||||
return &v1beta1.AdmissionResponse{
|
return &v1beta1.AdmissionResponse{
|
||||||
Allowed: allowed,
|
Allowed: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bodyToAdmissionReview creates AdmissionReview object from request body
|
// bodyToAdmissionReview creates AdmissionReview object from request body
|
||||||
|
|
Loading…
Add table
Reference in a new issue