diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index 4e4669d9f7..9b96618b91 100644 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -5,6 +5,8 @@ import ( "flag" "time" + "github.com/nirmata/kyverno/pkg/openapi" + "k8s.io/client-go/discovery" "github.com/golang/glog" @@ -212,7 +214,7 @@ func main() { glog.Fatalf("OpenApiDoc request failed: %v\n", err) } - if err := policy.UseCustomOpenApiDocument(openApiDoc); err != nil { + if err := openapi.UseCustomOpenApiDocument(openApiDoc); err != nil { glog.Fatalf("Could not set custom OpenApi document: %v\n", err) } diff --git a/pkg/engine/policy/utils.go b/pkg/engine/policy/utils.go deleted file mode 100644 index 52d83d0df4..0000000000 --- a/pkg/engine/policy/utils.go +++ /dev/null @@ -1,11 +0,0 @@ -package policy - -//Contains Check if strint is contained in a list of string -func containString(list []string, element string) bool { - for _, e := range list { - if e == element { - return true - } - } - return false -} diff --git a/pkg/policy/validation.go b/pkg/openapi/validation.go similarity index 74% rename from pkg/policy/validation.go rename to pkg/openapi/validation.go index 310be7c74f..7f49b91bef 100644 --- a/pkg/policy/validation.go +++ b/pkg/openapi/validation.go @@ -1,4 +1,4 @@ -package policy +package openapi import ( "fmt" @@ -24,7 +24,7 @@ import ( "gopkg.in/yaml.v2" ) -var validationGlobalState struct { +var openApiGlobalState struct { document *openapi_v2.Document definitions map[string]*openapi_v2.Schema kindToDefinitionName map[string]string @@ -46,31 +46,31 @@ func UseCustomOpenApiDocument(customDoc []byte) error { return err } - validationGlobalState.document, err = openapi_v2.NewDocument(spec, compiler.NewContext("$root", nil)) + openApiGlobalState.document, err = openapi_v2.NewDocument(spec, compiler.NewContext("$root", nil)) if err != nil { return err } - validationGlobalState.definitions = make(map[string]*openapi_v2.Schema) - validationGlobalState.kindToDefinitionName = make(map[string]string) - for _, definition := range validationGlobalState.document.GetDefinitions().AdditionalProperties { - validationGlobalState.definitions[definition.GetName()] = definition.GetValue() + openApiGlobalState.definitions = make(map[string]*openapi_v2.Schema) + openApiGlobalState.kindToDefinitionName = make(map[string]string) + for _, definition := range openApiGlobalState.document.GetDefinitions().AdditionalProperties { + openApiGlobalState.definitions[definition.GetName()] = definition.GetValue() path := strings.Split(definition.GetName(), ".") - validationGlobalState.kindToDefinitionName[path[len(path)-1]] = definition.GetName() + openApiGlobalState.kindToDefinitionName[path[len(path)-1]] = definition.GetName() } - validationGlobalState.models, err = proto.NewOpenAPIData(validationGlobalState.document) + openApiGlobalState.models, err = proto.NewOpenAPIData(openApiGlobalState.document) if err != nil { return err } - validationGlobalState.isSet = true + openApiGlobalState.isSet = true return nil } func ValidatePolicyMutation(policy v1.ClusterPolicy) error { - if !validationGlobalState.isSet { + if !openApiGlobalState.isSet { glog.V(4).Info("Cannot Validate policy: Validation global state not set") return nil } @@ -89,7 +89,7 @@ func ValidatePolicyMutation(policy v1.ClusterPolicy) error { newPolicy := policy newPolicy.Spec.Rules = rules - resource, _ := generateEmptyResource(validationGlobalState.definitions[validationGlobalState.kindToDefinitionName[kind]]).(map[string]interface{}) + resource, _ := generateEmptyResource(openApiGlobalState.definitions[openApiGlobalState.kindToDefinitionName[kind]]).(map[string]interface{}) newResource := unstructured.Unstructured{Object: resource} newResource.SetKind(kind) policyContext := engine.PolicyContext{ @@ -117,14 +117,14 @@ func ValidatePolicyMutation(policy v1.ClusterPolicy) error { } func ValidateResource(patchedResource interface{}, kind string) error { - if !validationGlobalState.isSet { + if !openApiGlobalState.isSet { glog.V(4).Info("Cannot Validate resource: Validation global state not set") return nil } - kind = validationGlobalState.kindToDefinitionName[kind] + kind = openApiGlobalState.kindToDefinitionName[kind] - schema := validationGlobalState.models.LookupModel(kind) + schema := openApiGlobalState.models.LookupModel(kind) if schema == nil { return fmt.Errorf("pre-validation: couldn't find model %s", kind) } @@ -142,27 +142,27 @@ func ValidateResource(patchedResource interface{}, kind string) error { } func setValidationGlobalState() error { - if !validationGlobalState.isSet { + if !openApiGlobalState.isSet { var err error - validationGlobalState.document, err = getSchemaDocument() + openApiGlobalState.document, err = getSchemaDocument() if err != nil { return err } - validationGlobalState.definitions = make(map[string]*openapi_v2.Schema) - validationGlobalState.kindToDefinitionName = make(map[string]string) - for _, definition := range validationGlobalState.document.GetDefinitions().AdditionalProperties { - validationGlobalState.definitions[definition.GetName()] = definition.GetValue() + openApiGlobalState.definitions = make(map[string]*openapi_v2.Schema) + openApiGlobalState.kindToDefinitionName = make(map[string]string) + for _, definition := range openApiGlobalState.document.GetDefinitions().AdditionalProperties { + openApiGlobalState.definitions[definition.GetName()] = definition.GetValue() path := strings.Split(definition.GetName(), ".") - validationGlobalState.kindToDefinitionName[path[len(path)-1]] = definition.GetName() + openApiGlobalState.kindToDefinitionName[path[len(path)-1]] = definition.GetName() } - validationGlobalState.models, err = proto.NewOpenAPIData(validationGlobalState.document) + openApiGlobalState.models, err = proto.NewOpenAPIData(openApiGlobalState.document) if err != nil { return err } - validationGlobalState.isSet = true + openApiGlobalState.isSet = true } return nil } @@ -182,7 +182,7 @@ func generateEmptyResource(kindSchema *openapi_v2.Schema) interface{} { types := kindSchema.GetType().GetValue() if kindSchema.GetXRef() != "" { - return generateEmptyResource(validationGlobalState.definitions[strings.TrimPrefix(kindSchema.GetXRef(), "#/definitions/")]) + return generateEmptyResource(openApiGlobalState.definitions[strings.TrimPrefix(kindSchema.GetXRef(), "#/definitions/")]) } if len(types) != 1 { diff --git a/pkg/policy/validation_test.go b/pkg/openapi/validation_test.go similarity index 99% rename from pkg/policy/validation_test.go rename to pkg/openapi/validation_test.go index b42aea0cbf..4c6c8ac2a6 100644 --- a/pkg/policy/validation_test.go +++ b/pkg/openapi/validation_test.go @@ -1,4 +1,4 @@ -package policy +package openapi import ( "encoding/json" diff --git a/pkg/engine/policy/background.go b/pkg/policy/background.go similarity index 100% rename from pkg/engine/policy/background.go rename to pkg/policy/background.go diff --git a/pkg/policy/controller.go b/pkg/policy/controller.go index 1dbca0611a..ad1c654d32 100644 --- a/pkg/policy/controller.go +++ b/pkg/policy/controller.go @@ -13,7 +13,6 @@ import ( kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1" "github.com/nirmata/kyverno/pkg/config" client "github.com/nirmata/kyverno/pkg/dclient" - "github.com/nirmata/kyverno/pkg/engine/policy" "github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/policystore" "github.com/nirmata/kyverno/pkg/policyviolation" @@ -164,7 +163,7 @@ func (pc *PolicyController) addPolicy(obj interface{}) { // TODO: code might seem vague, awaiting resolution of issue https://github.com/nirmata/kyverno/issues/598 if p.Spec.Background == nil { // if userInfo is not defined in policy we process the policy - if err := policy.ContainsUserInfo(*p); err != nil { + if err := ContainsUserInfo(*p); err != nil { return } } else { @@ -173,7 +172,7 @@ func (pc *PolicyController) addPolicy(obj interface{}) { } // If userInfo is used then skip the policy // ideally this should be handled by background flag only - if err := policy.ContainsUserInfo(*p); err != nil { + if err := ContainsUserInfo(*p); err != nil { // contains userInfo used in policy return } @@ -196,7 +195,7 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) { // TODO: code might seem vague, awaiting resolution of issue https://github.com/nirmata/kyverno/issues/598 if curP.Spec.Background == nil { // if userInfo is not defined in policy we process the policy - if err := policy.ContainsUserInfo(*curP); err != nil { + if err := ContainsUserInfo(*curP); err != nil { return } } else { @@ -205,7 +204,7 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) { } // If userInfo is used then skip the policy // ideally this should be handled by background flag only - if err := policy.ContainsUserInfo(*curP); err != nil { + if err := ContainsUserInfo(*curP); err != nil { // contains userInfo used in policy return } diff --git a/pkg/policy/utils.go b/pkg/policy/utils.go index 45c3150983..52d83d0df4 100644 --- a/pkg/policy/utils.go +++ b/pkg/policy/utils.go @@ -1,17 +1,11 @@ package policy -import kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" - -// reEvaulatePolicy checks if the policy needs to be re-evaulated -// during re-evaulation we remove all the old policy violations and re-create new ones -// - Rule count changes -// - Rule resource description changes -// - Rule operation changes -// - Rule name changed -func reEvaulatePolicy(curP, oldP *kyverno.ClusterPolicy) bool { - // count of rules changed - if len(curP.Spec.Rules) != len(curP.Spec.Rules) { - +//Contains Check if strint is contained in a list of string +func containString(list []string, element string) bool { + for _, e := range list { + if e == element { + return true + } } - return true + return false } diff --git a/pkg/engine/policy/validate.go b/pkg/policy/validate.go similarity index 98% rename from pkg/engine/policy/validate.go rename to pkg/policy/validate.go index b6e4fd6b28..f74fcf9669 100644 --- a/pkg/engine/policy/validate.go +++ b/pkg/policy/validate.go @@ -8,6 +8,8 @@ import ( "strconv" "strings" + "github.com/nirmata/kyverno/pkg/openapi" + kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" "github.com/nirmata/kyverno/pkg/engine/anchor" rbacv1 "k8s.io/api/rbac/v1" @@ -70,6 +72,11 @@ func Validate(p kyverno.ClusterPolicy) error { } } } + + if err := openapi.ValidatePolicyMutation(p); err != nil { + return fmt.Errorf("Failed to validate policy: %v", err) + } + return nil } diff --git a/pkg/engine/policy/validate_test.go b/pkg/policy/validate_test.go similarity index 100% rename from pkg/engine/policy/validate_test.go rename to pkg/policy/validate_test.go diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go index c8c949e606..90bedb1519 100644 --- a/pkg/webhooks/mutation.go +++ b/pkg/webhooks/mutation.go @@ -9,6 +9,7 @@ import ( "github.com/nirmata/kyverno/pkg/engine/context" "github.com/nirmata/kyverno/pkg/engine/response" engineutils "github.com/nirmata/kyverno/pkg/engine/utils" + "github.com/nirmata/kyverno/pkg/openapi" policyctr "github.com/nirmata/kyverno/pkg/policy" "github.com/nirmata/kyverno/pkg/policyviolation" "github.com/nirmata/kyverno/pkg/utils" @@ -90,7 +91,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou glog.V(4).Infof("Failed to apply policy %s on resource %s/%s\n", policy.Name, resource.GetNamespace(), resource.GetName()) continue } - err := policyctr.ValidateResource(engineResponse.PatchedResource.UnstructuredContent(), engineResponse.PatchedResource.GetKind()) + err := openapi.ValidateResource(engineResponse.PatchedResource.UnstructuredContent(), engineResponse.PatchedResource.GetKind()) if err != nil { glog.V(4).Infoln(err) continue diff --git a/pkg/webhooks/policyvalidation.go b/pkg/webhooks/policyvalidation.go index 222bcd19b5..1e3991be50 100644 --- a/pkg/webhooks/policyvalidation.go +++ b/pkg/webhooks/policyvalidation.go @@ -4,11 +4,9 @@ import ( "encoding/json" "fmt" - policy2 "github.com/nirmata/kyverno/pkg/policy" - "github.com/golang/glog" kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1" - policyvalidate "github.com/nirmata/kyverno/pkg/engine/policy" + policyvalidate "github.com/nirmata/kyverno/pkg/policy" v1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -37,16 +35,6 @@ func (ws *WebhookServer) handlePolicyValidation(request *v1beta1.AdmissionReques }, } } - - if err := policy2.ValidatePolicyMutation(*policy); err != nil { - admissionResp = &v1beta1.AdmissionResponse{ - Allowed: false, - Result: &metav1.Status{ - Message: err.Error(), - }, - } - } - if admissionResp.Allowed { // if the policy contains mutating & validation rules and it config does not exist we create one // queue the request