1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-29 02:45:06 +00:00

resolving merge conflicts

This commit is contained in:
shravan 2020-01-25 14:55:36 +05:30
commit e1b9a13590
94 changed files with 709 additions and 557 deletions

View file

@ -120,7 +120,7 @@ func main() {
10*time.Second)
// Configuration Data
// dyamically load the configuration from configMap
// dynamically load the configuration from configMap
// - resource filters
// if the configMap is update, the configuration will be updated :D
configData := config.NewConfigData(
@ -147,7 +147,7 @@ func main() {
// POLICY CONTROLLER
// - reconciliation policy and policy violation
// - process policy on existing resources
// - status aggregator: recieves stats when a policy is applied
// - status aggregator: receives stats when a policy is applied
// & updates the policy status
pc, err := policy.NewPolicyController(pclient,
client,

View file

@ -43,7 +43,7 @@ type RequestInfo struct {
type GenerateRequestStatus struct {
State GenerateRequestState `json:"state"`
Message string `json:"message,omitempty"`
// This will track the resoruces that are generated by the generate Policy
// This will track the resources that are generated by the generate Policy
// Will be used during clean up resources
GeneratedResources []ResourceSpec `json:"generatedResources,omitempty"`
}
@ -143,19 +143,25 @@ type Rule struct {
Generation Generation `json:"generate,omitempty"`
}
//Condition defines the evaluation condition
type Condition struct {
Key interface{} `json:"key"`
Operator ConditionOperator `json:"operator"`
Value interface{} `json:"value"`
}
// ConditionOperator defines the type for condition operator
type ConditionOperator string
const (
Equal ConditionOperator = "Equal"
//Equal for Equal operator
Equal ConditionOperator = "Equal"
//NotEqual for NotEqual operator
NotEqual ConditionOperator = "NotEqual"
In ConditionOperator = "In"
NotIn ConditionOperator = "NotIn"
//In for In operator
In ConditionOperator = "In"
//NotIn for NotIn operator
NotIn ConditionOperator = "NotIn"
)
//MatchResources contains resource description of the resources that the rule is to apply on
@ -254,7 +260,7 @@ type RuleStats struct {
// PolicyList is a list of Policy resources
// PolicyViolation stores the information regarinding the resources for which a policy failed to apply
// PolicyViolationTemplate stores the information regarinding the resources for which a policy failed to apply
type PolicyViolationTemplate struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View file

@ -2,6 +2,7 @@ package v1
import "reflect"
//HasMutateOrValidateOrGenerate checks for rule types
func (p ClusterPolicy) HasMutateOrValidateOrGenerate() bool {
for _, rule := range p.Spec.Rules {
if rule.HasMutate() || rule.HasValidate() || rule.HasGenerate() {
@ -11,14 +12,17 @@ func (p ClusterPolicy) HasMutateOrValidateOrGenerate() bool {
return false
}
//HasMutate checks for mutate rule
func (r Rule) HasMutate() bool {
return !reflect.DeepEqual(r.Mutation, Mutation{})
}
//HasValidate checks for validate rule
func (r Rule) HasValidate() bool {
return !reflect.DeepEqual(r.Validation, Validation{})
}
//HasGenerate checks for generate rule
func (r Rule) HasGenerate() bool {
return !reflect.DeepEqual(r.Generation, Generation{})
}

View file

@ -18,24 +18,27 @@ const (
DefaultResync time.Duration = 60 * time.Second
)
// LastReqTime
// LastReqTime stores the lastrequest times for incoming api-requests
type LastReqTime struct {
t time.Time
mu sync.RWMutex
}
//Time returns the lastrequest time
func (t *LastReqTime) Time() time.Time {
t.mu.RLock()
defer t.mu.RUnlock()
return t.t
}
//SetTime stes the lastrequest time
func (t *LastReqTime) SetTime(tm time.Time) {
t.mu.Lock()
defer t.mu.Unlock()
t.t = tm
}
//NewLastReqTime returns a new instance of LastRequestTime store
func NewLastReqTime() *LastReqTime {
return &LastReqTime{
t: time.Now(),
@ -62,9 +65,8 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
glog.V(2).Infof("starting default resync for webhook checker with resync time %d nanoseconds", defaultResync)
maxDeadline := deadline * time.Duration(MaxRetryCount)
ticker := time.NewTicker(defaultResync)
var statuscontrol StatusInterface
/// interface to update and increment kyverno webhook status via annotations
statuscontrol = NewVerifyControl(client, eventGen)
statuscontrol := NewVerifyControl(client, eventGen)
// send the initial update status
if checkIfPolicyWithMutateAndGenerateExists(pLister) {
if err := statuscontrol.SuccessStatus(); err != nil {
@ -73,8 +75,8 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
}
defer ticker.Stop()
// - has recieved request -> set webhookstatus as "True"
// - no requests recieved
// - has received request -> set webhookstatus as "True"
// - no requests received
// -> if greater than deadline, send update request
// -> if greater than maxDeadline, send failed status update
for {
@ -88,8 +90,8 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
// get current time
timeDiff := time.Since(t.Time())
if timeDiff > maxDeadline {
glog.Infof("failed to recieve any request for more than %v ", maxDeadline)
glog.Info("Admission Control failing: Webhook is not recieving requests forwarded by api-server as per webhook configurations")
glog.Infof("failed to receive any request for more than %v ", maxDeadline)
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
// set the status unavailable
if err := statuscontrol.FailedStatus(); err != nil {
glog.Error(err)
@ -97,7 +99,7 @@ func (t *LastReqTime) Run(pLister kyvernolister.ClusterPolicyLister, eventGen ev
continue
}
if timeDiff > deadline {
glog.Info("Admission Control failing: Webhook is not recieving requests forwarded by api-server as per webhook configurations")
glog.Info("Admission Control failing: Webhook is not receiving requests forwarded by api-server as per webhook configurations")
// send request to update the kyverno deployment
if err := statuscontrol.IncrementAnnotation(); err != nil {
glog.Error(err)

View file

@ -53,6 +53,9 @@ type PolicyViolationNamespaceListerExpansion interface{}
// as the lister is specific to a gvk we can harcode the values here
func (pvl *clusterPolicyViolationLister) ListResources(selector labels.Selector) (ret []*kyvernov1.ClusterPolicyViolation, err error) {
policyviolations, err := pvl.List(selector)
if err != nil {
return nil, err
}
for index := range policyviolations {
policyviolations[index].SetGroupVersionKind(kyvernov1.SchemeGroupVersion.WithKind("ClusterPolicyViolation"))
}

View file

@ -8,73 +8,87 @@ import (
clientcmd "k8s.io/client-go/tools/clientcmd"
)
const (
// These constants MUST be equal to the corresponding names in service definition in definitions/install.yaml
KubePolicyNamespace = "kyverno"
WebhookServiceName = "kyverno-svc"
// These constants MUST be equal to the corresponding names in service definition in definitions/install.yaml
MutatingWebhookConfigurationName = "kyverno-resource-mutating-webhook-cfg"
const (
//KubePolicyNamespace default kyverno namespace
KubePolicyNamespace = "kyverno"
//WebhookServiceName default kyverno webhook service name
WebhookServiceName = "kyverno-svc"
//MutatingWebhookConfigurationName default resource mutating webhook configuration name
MutatingWebhookConfigurationName = "kyverno-resource-mutating-webhook-cfg"
//MutatingWebhookConfigurationDebugName default resource mutating webhook configuration name for debug mode
MutatingWebhookConfigurationDebugName = "kyverno-resource-mutating-webhook-cfg-debug"
MutatingWebhookName = "nirmata.kyverno.resource.mutating-webhook"
//MutatingWebhookName default resource mutating webhook name
MutatingWebhookName = "nirmata.kyverno.resource.mutating-webhook"
// ValidatingWebhookConfigurationName = "kyverno-validating-webhook-cfg"
// ValidatingWebhookConfigurationDebug = "kyverno-validating-webhook-cfg-debug"
// ValidatingWebhookName = "nirmata.kyverno.policy-validating-webhook"
VerifyMutatingWebhookConfigurationName = "kyverno-verify-mutating-webhook-cfg"
//VerifyMutatingWebhookConfigurationName default verify mutating webhook configuration name
VerifyMutatingWebhookConfigurationName = "kyverno-verify-mutating-webhook-cfg"
//VerifyMutatingWebhookConfigurationDebugName default verify mutating webhook configuration name for debug mode
VerifyMutatingWebhookConfigurationDebugName = "kyverno-verify-mutating-webhook-cfg-debug"
VerifyMutatingWebhookName = "nirmata.kyverno.verify-mutating-webhook"
//VerifyMutatingWebhookName default verify mutating webhook name
VerifyMutatingWebhookName = "nirmata.kyverno.verify-mutating-webhook"
PolicyValidatingWebhookConfigurationName = "kyverno-policy-validating-webhook-cfg"
//PolicyValidatingWebhookConfigurationName default policy validating webhook configuration name
PolicyValidatingWebhookConfigurationName = "kyverno-policy-validating-webhook-cfg"
//PolicyValidatingWebhookConfigurationDebugName default policy validating webhook configuration name for debug mode
PolicyValidatingWebhookConfigurationDebugName = "kyverno-policy-validating-webhook-cfg-debug"
PolicyValidatingWebhookName = "nirmata.kyverno.policy-validating-webhook"
//PolicyValidatingWebhookName default policy validating webhook name
PolicyValidatingWebhookName = "nirmata.kyverno.policy-validating-webhook"
PolicyMutatingWebhookConfigurationName = "kyverno-policy-mutating-webhook-cfg"
//PolicyMutatingWebhookConfigurationName default policy mutating webhook configuration name
PolicyMutatingWebhookConfigurationName = "kyverno-policy-mutating-webhook-cfg"
//PolicyMutatingWebhookConfigurationDebugName default policy mutating webhook configuration name for debug mode
PolicyMutatingWebhookConfigurationDebugName = "kyverno-policy-mutating-webhook-cfg-debug"
PolicyMutatingWebhookName = "nirmata.kyverno.policy-mutating-webhook"
//PolicyMutatingWebhookName default policy mutating webhook name
PolicyMutatingWebhookName = "nirmata.kyverno.policy-mutating-webhook"
// Due to kubernetes issue, we must use next literal constants instead of deployment TypeMeta fields
// Issue: https://github.com/kubernetes/kubernetes/pull/63972
// When the issue is closed, we should use TypeMeta struct instead of this constants
DeploymentKind = "Deployment"
DeploymentAPIVersion = "extensions/v1beta1"
// DeploymentKind define the default deployment resource kind
DeploymentKind = "Deployment"
// DeploymentAPIVersion define the default deployment resource apiVersion
DeploymentAPIVersion = "extensions/v1beta1"
// KubePolicyDeploymentName define the default deployment namespace
KubePolicyDeploymentName = "kyverno"
)
var (
MutatingWebhookServicePath = "/mutate"
ValidatingWebhookServicePath = "/validate"
//MutatingWebhookServicePath is the path for mutation webhook
MutatingWebhookServicePath = "/mutate"
//ValidatingWebhookServicePath is the path for validation webhook
ValidatingWebhookServicePath = "/validate"
//PolicyValidatingWebhookServicePath is the path for policy validation webhook(used to validate policy resource)
PolicyValidatingWebhookServicePath = "/policyvalidate"
PolicyMutatingWebhookServicePath = "/policymutate"
VerifyMutatingWebhookServicePath = "/verifymutate"
SupportedKinds = []string{
"ConfigMap",
"CronJob",
"DaemonSet",
"Deployment",
"Endpoints",
"HorizontalPodAutoscaler",
"Ingress",
"Job",
"LimitRange",
"Namespace",
"NetworkPolicy",
"PersistentVolumeClaim",
"PodDisruptionBudget",
"PodTemplate",
"ResourceQuota",
"Secret",
"Service",
"StatefulSet",
}
//PolicyMutatingWebhookServicePath is the path for policy mutation webhook(used to default)
PolicyMutatingWebhookServicePath = "/policymutate"
//VerifyMutatingWebhookServicePath is the path for verify webhook(used to veryfing if admission control is enabled and active)
VerifyMutatingWebhookServicePath = "/verifymutate"
)
//LogDefaults sets default glog flags
//LogDefaultFlags sets default glog flags
func LogDefaultFlags() {
flag.Set("logtostderr", "true")
flag.Set("stderrthreshold", "WARNING")
var err error
err = flag.Set("logtostderr", "true")
if err != nil {
glog.Fatalf("failed to set flag 'logtostderr' to 'true':%v", err)
}
err = flag.Set("stderrthreshold", "WARNING")
if err != nil {
glog.Fatalf("failed to set flag 'stderrthreshold' to 'WARNING':%v", err)
}
flag.Set("v", "2")
if err != nil {
glog.Fatalf("failed to set flag 'v' to '2':%v", err)
}
}
//CreateClientConfig creates client config

View file

@ -19,8 +19,8 @@ import (
// read the conifgMap with name in env:INIT_CONFIG
// this configmap stores the resources that are to be filtered
const cmNameEnv string = "INIT_CONFIG"
const cmDataField string = "resourceFilters"
// ConfigData stores the configuration
type ConfigData struct {
client kubernetes.Interface
// configMap Name
@ -120,7 +120,7 @@ func (cd *ConfigData) deleteCM(obj interface{}) {
if cm.Name != cd.cmName {
return
}
// remove the configuration paramaters
// remove the configuration parameters
cd.unload(*cm)
}
@ -183,7 +183,7 @@ type k8Resource struct {
Name string
}
//ParseKinds parses the kinds if a single string contains comma seperated kinds
//ParseKinds parses the kinds if a single string contains comma separated kinds
// {"1,2,3","4","5"} => {"1","2","3","4","5"}
func parseKinds(list string) []k8Resource {
resources := []k8Resource{}

View file

@ -119,7 +119,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSigningRequest, maxWaitSeconds uint8) ([]byte, error) {
// TODO: react of SIGINT and SIGTERM
timeStart := time.Now()
for time.Now().Sub(timeStart) < time.Duration(maxWaitSeconds)*time.Second {
for time.Since(timeStart) < time.Duration(maxWaitSeconds)*time.Second {
unstrR, err := c.GetResource(CSRs, "", req.ObjectMeta.Name)
if err != nil {
return nil, err

View file

@ -29,7 +29,6 @@ import (
//Client enables interaction with k8 resource
type Client struct {
client dynamic.Interface
cachedClient discovery.CachedDiscoveryInterface
clientConfig *rest.Config
kclient kubernetes.Interface
DiscoveryClient IDiscovery
@ -63,6 +62,7 @@ func NewClient(config *rest.Config, resync time.Duration, stopCh <-chan struct{}
return &client, nil
}
//NewDynamicSharedInformerFactory returns a new instance of DynamicSharedInformerFactory
func (c *Client) NewDynamicSharedInformerFactory(defaultResync time.Duration) dynamicinformer.DynamicSharedInformerFactory {
return dynamicinformer.NewDynamicSharedInformerFactory(c.client, defaultResync)
}
@ -210,29 +210,17 @@ func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSign
return &csr, nil
}
// Waits until namespace is created with maximum duration maxWaitTimeForNamespaceCreation
func (c *Client) waitUntilNamespaceIsCreated(name string) error {
timeStart := time.Now()
var lastError error
for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime {
_, lastError = c.GetResource(Namespaces, "", name)
if lastError == nil {
break
}
time.Sleep(namespaceCreationWaitInterval)
}
return lastError
}
//IDiscovery provides interface to mange Kind and GVR mapping
type IDiscovery interface {
GetGVRFromKind(kind string) schema.GroupVersionResource
}
// SetDiscovery sets the discovery client implementation
func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
c.DiscoveryClient = discoveryClient
}
//ServerPreferredResources stores the cachedClient instance for discovery client
type ServerPreferredResources struct {
cachedClient discovery.CachedDiscoveryInterface
}

View file

@ -12,8 +12,7 @@ import (
)
const (
// Kind names are case sensitive
//CSRs CertificateSigningRequest
// CSRs CertificateSigningRequest
CSRs string = "CertificateSigningRequest"
// Secrets Secret
Secrets string = "Secret"
@ -25,10 +24,10 @@ const (
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second
const namespaceCreationWaitInterval time.Duration = 100 * time.Millisecond
//---testing utilities
//NewMockClient ---testing utilities
func NewMockClient(scheme *runtime.Scheme, objects ...runtime.Object) (*Client, error) {
client := fake.NewSimpleDynamicClient(scheme, objects...)
// the typed and dynamic client are initalized with similar resources
// the typed and dynamic client are initialized with similar resources
kclient := kubernetesfake.NewSimpleClientset(objects...)
return &Client{
client: client,
@ -91,22 +90,3 @@ func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[
u.Object["spec"] = spec
return u
}
func retry(attempts int, sleep time.Duration, fn func() error) error {
if err := fn(); err != nil {
if s, ok := err.(stop); ok {
return s.error
}
if attempts--; attempts > 0 {
time.Sleep(sleep)
return retry(attempts, 2*sleep, fn)
}
return err
}
return nil
}
// Custom error
type stop struct {
error
}

View file

@ -19,8 +19,8 @@ func CreateElementHandler(element string, pattern interface{}, path string) Vali
switch {
case IsConditionAnchor(element):
return NewConditionAnchorHandler(element, pattern, path)
case IsExistanceAnchor(element):
return NewExistanceHandler(element, pattern, path)
case IsExistenceAnchor(element):
return NewExistenceHandler(element, pattern, path)
case IsEqualityAnchor(element):
return NewEqualityHandler(element, pattern, path)
case IsNegationAnchor(element):
@ -156,30 +156,30 @@ func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resource
return "", nil
}
//NewExistanceHandler returns existence handler
func NewExistanceHandler(anchor string, pattern interface{}, path string) ValidationHandler {
return ExistanceHandler{
//NewExistenceHandler returns existence handler
func NewExistenceHandler(anchor string, pattern interface{}, path string) ValidationHandler {
return ExistenceHandler{
anchor: anchor,
pattern: pattern,
path: path,
}
}
//ExistanceHandler provides handlers to process exitence anchor handler
type ExistanceHandler struct {
//ExistenceHandler provides handlers to process exitence anchor handler
type ExistenceHandler struct {
anchor string
pattern interface{}
path string
}
//Handle processes the existence anchor handler
func (eh ExistanceHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
// skip is used by existance anchor to not process further if condition is not satisfied
func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}) (string, error) {
// skip is used by existence anchor to not process further if condition is not satisfied
anchorKey := removeAnchor(eh.anchor)
currentPath := eh.path + anchorKey + "/"
// check if anchor is present in resource
if value, ok := resourceMap[anchorKey]; ok {
// Existance anchor can only exist on resource value type of list
// Existence anchor can only exist on resource value type of list
switch typedResource := value.(type) {
case []interface{}:
typedPattern, ok := eh.pattern.([]interface{})
@ -194,8 +194,8 @@ func (eh ExistanceHandler) Handle(handler resourceElementHandler, resourceMap ma
}
return validateExistenceListResource(handler, typedResource, typedPatternMap, originPattern, currentPath)
default:
glog.Error("Invalid type: Existance ^ () anchor can be used only on list/array type resource")
return currentPath, fmt.Errorf("Invalid resource type %T: Existance ^ () anchor can be used only on list/array type resource", value)
glog.Error("Invalid type: Existence ^ () anchor can be used only on list/array type resource")
return currentPath, fmt.Errorf("Invalid resource type %T: Existence ^ () anchor can be used only on list/array type resource", value)
}
}
return "", nil
@ -213,15 +213,16 @@ func validateExistenceListResource(handler resourceElementHandler, resourceList
return "", nil
}
}
// none of the existance checks worked, so thats a failure sceanario
// none of the existence checks worked, so thats a failure sceanario
return path, fmt.Errorf("Existence anchor validation failed at path %s", path)
}
//GetAnchorsResourcesFromMap returns map of anchors
func GetAnchorsResourcesFromMap(patternMap map[string]interface{}) (map[string]interface{}, map[string]interface{}) {
anchors := map[string]interface{}{}
resources := map[string]interface{}{}
for key, value := range patternMap {
if IsConditionAnchor(key) || IsExistanceAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
if IsConditionAnchor(key) || IsExistenceAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
anchors[key] = value
continue
}

View file

@ -1,8 +1,9 @@
package anchor
// Anchor function type
// IsAnchor is a function handler
type IsAnchor func(str string) bool
//IsConditionAnchor checks for condition anchor
func IsConditionAnchor(str string) bool {
if len(str) < 2 {
return false
@ -11,6 +12,7 @@ func IsConditionAnchor(str string) bool {
return (str[0] == '(' && str[len(str)-1] == ')')
}
//IsNegationAnchor checks for negation anchor
func IsNegationAnchor(str string) bool {
left := "X("
right := ")"
@ -21,6 +23,7 @@ func IsNegationAnchor(str string) bool {
return (str[:len(left)] == left && str[len(str)-len(right):] == right)
}
// IsAddingAnchor checks for addition anchor
func IsAddingAnchor(key string) bool {
const left = "+("
const right = ")"
@ -32,6 +35,7 @@ func IsAddingAnchor(key string) bool {
return left == key[:len(left)] && right == key[len(key)-len(right):]
}
// IsEqualityAnchor checks for equality anchor
func IsEqualityAnchor(str string) bool {
left := "=("
right := ")"
@ -42,7 +46,8 @@ func IsEqualityAnchor(str string) bool {
return (str[:len(left)] == left && str[len(str)-len(right):] == right)
}
func IsExistanceAnchor(str string) bool {
//IsExistenceAnchor checks for existence anchor
func IsExistenceAnchor(str string) bool {
left := "^("
right := ")"
@ -53,15 +58,14 @@ func IsExistanceAnchor(str string) bool {
return (str[:len(left)] == left && str[len(str)-len(right):] == right)
}
func removeAnchor(key string) string {
if IsConditionAnchor(key) {
return key[1 : len(key)-1]
}
if IsExistanceAnchor(key) || IsAddingAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
if IsExistenceAnchor(key) || IsAddingAnchor(key) || IsEqualityAnchor(key) || IsNegationAnchor(key) {
return key[2 : len(key)-1]
}
return key
}
}

View file

@ -41,18 +41,18 @@ func TestWrappedWithParentheses_Empty(t *testing.T) {
assert.Assert(t, !IsConditionAnchor(str))
}
func TestIsExistanceAnchor_Yes(t *testing.T) {
assert.Assert(t, IsExistanceAnchor("^(abc)"))
func TestIsExistenceAnchor_Yes(t *testing.T) {
assert.Assert(t, IsExistenceAnchor("^(abc)"))
}
func TestIsExistanceAnchor_NoRightBracket(t *testing.T) {
assert.Assert(t, !IsExistanceAnchor("^(abc"))
func TestIsExistenceAnchor_NoRightBracket(t *testing.T) {
assert.Assert(t, !IsExistenceAnchor("^(abc"))
}
func TestIsExistanceAnchor_OnlyHat(t *testing.T) {
assert.Assert(t, !IsExistanceAnchor("^abc"))
func TestIsExistenceAnchor_OnlyHat(t *testing.T) {
assert.Assert(t, !IsExistenceAnchor("^abc"))
}
func TestIsExistanceAnchor_ConditionAnchor(t *testing.T) {
assert.Assert(t, !IsExistanceAnchor("(abc)"))
func TestIsExistenceAnchor_ConditionAnchor(t *testing.T) {
assert.Assert(t, !IsExistenceAnchor("(abc)"))
}

View file

@ -10,15 +10,15 @@ import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
)
//Interface ... normal functions
//Interface to manage context operations
type Interface interface {
// merges the json with context
//AddJSON merges the json with context
AddJSON(dataRaw []byte) error
// merges resource json under request.object
//AddResource merges resource json under request.object
AddResource(dataRaw []byte) error
// merges userInfo json under kyverno.userInfo
//AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo kyverno.UserInfo) error
// merges serrviceaccount
//AddSA merges serrviceaccount
AddSA(userName string) error
EvalInterface
}
@ -58,7 +58,7 @@ func (ctx *Context) AddJSON(dataRaw []byte) error {
return nil
}
//Add data at path: request.object
//AddResource data at path: request.object
func (ctx *Context) AddResource(dataRaw []byte) error {
// unmarshall the resource struct
@ -86,6 +86,7 @@ func (ctx *Context) AddResource(dataRaw []byte) error {
return ctx.AddJSON(objRaw)
}
//AddUserInfo adds userInfo at path request.userInfo
func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
modifiedResource := struct {
Request interface{} `json:"request"`
@ -101,7 +102,7 @@ func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
return ctx.AddJSON(objRaw)
}
// removes prefix 'system:serviceaccount:' and namespace, then loads only username
//AddSA removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
func (ctx *Context) AddSA(userName string) error {
saPrefix := "system:serviceaccount:"
var sa string
@ -121,7 +122,7 @@ func (ctx *Context) AddSA(userName string) error {
saNamespace = groups[0]
}
glog.Infof("Loading variable serviceAccountName with value: %s", saName)
glog.V(4).Infof("Loading variable serviceAccountName with value: %s", saName)
saNameObj := struct {
SA string `json:"serviceAccountName"`
}{
@ -136,7 +137,7 @@ func (ctx *Context) AddSA(userName string) error {
return err
}
glog.Infof("Loading variable serviceAccountNamespace with value: %s", saNamespace)
glog.V(4).Infof("Loading variable serviceAccountNamespace with value: %s", saNamespace)
saNsObj := struct {
SA string `json:"serviceAccountNamespace"`
}{

View file

@ -9,6 +9,7 @@ import (
)
func Test_addResourceAndUserContext(t *testing.T) {
var err error
rawResource := []byte(`
{
"apiVersion": "v1",
@ -54,7 +55,10 @@ func Test_addResourceAndUserContext(t *testing.T) {
var expectedResult string
ctx := NewContext()
ctx.AddResource(rawResource)
err = ctx.AddResource(rawResource)
if err != nil {
t.Error(err)
}
result, err := ctx.Query("request.object.apiVersion")
if err != nil {
t.Error(err)
@ -65,7 +69,10 @@ func Test_addResourceAndUserContext(t *testing.T) {
t.Error("exected result does not match")
}
ctx.AddUserInfo(userRequestInfo)
err = ctx.AddUserInfo(userRequestInfo)
if err != nil {
t.Error(err)
}
result, err = ctx.Query("request.object.apiVersion")
if err != nil {
t.Error(err)
@ -86,7 +93,10 @@ func Test_addResourceAndUserContext(t *testing.T) {
t.Error("exected result does not match")
}
// Add service account Name
ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
t.Error(err)
}
result, err = ctx.Query("serviceAccountName")
if err != nil {
t.Error(err)

View file

@ -13,11 +13,11 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// GenerateNew
// Generate checks for validity of generate rule on the resource
// 1. validate variables to be susbtitute in the general ruleInfo (match,exclude,condition)
// - the caller has to check the ruleResponse to determine whether the path exist
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func GenerateNew(policyContext PolicyContext) (resp response.EngineResponse) {
func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
policy := policyContext.Policy
resource := policyContext.NewResource
admissionInfo := policyContext.AdmissionInfo

View file

@ -22,7 +22,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/variables"
)
// processOverlay processes mutation overlay on the resource
// ProcessOverlay processes mutation overlay on the resource
func ProcessOverlay(ctx context.EvalInterface, rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
startTime := time.Now()
glog.V(4).Infof("started applying overlay rule %q (%v)", rule.Name, startTime)
@ -111,7 +111,7 @@ func ProcessOverlay(ctx context.EvalInterface, rule kyverno.Rule, resource unstr
return resp, resource
}
// rule application succesfuly
// rule application successfully
resp.Success = true
resp.Message = fmt.Sprintf("successfully processed overlay")
resp.Patches = patches

View file

@ -23,7 +23,7 @@ func checkConditions(resource, overlay interface{}, path string) (string, overla
// resource item exists but has different type
// return false if anchor exists in overlay
// conditon never be true in this case
// condition never be true in this case
if reflect.TypeOf(resource) != reflect.TypeOf(overlay) {
if hasNestedAnchors(overlay) {
glog.V(4).Infof("Found anchor on different types of element at path %s: overlay %T, resource %T", path, overlay, resource)

View file

@ -19,6 +19,7 @@ func applyPatch(resource []byte, patchRaw []byte) ([]byte, error) {
return utils.ApplyPatches(resource, patchesList)
}
//ProcessPatches applies the patches on the resource and returns the patched resource
func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp response.RuleResponse, patchedResource unstructured.Unstructured) {
startTime := time.Now()
glog.V(4).Infof("started JSON patch rule %q (%v)", rule.Name, startTime)
@ -82,9 +83,9 @@ func ProcessPatches(rule kyverno.Rule, resource unstructured.Unstructured) (resp
return resp, resource
}
// JSON patches processed succesfully
// JSON patches processed successfully
resp.Success = true
resp.Message = fmt.Sprintf("succesfully process JSON patches")
resp.Message = fmt.Sprintf("successfully process JSON patches")
resp.Patches = patches
return resp, patchedResource
}

View file

@ -174,10 +174,6 @@ func assertEqDataImpl(t *testing.T, expected, actual []byte, formatModifier stri
}
}
func assertEqData(t *testing.T, expected, actual []byte) {
assertEqDataImpl(t, expected, actual, "%x")
}
func assertEqStringAndData(t *testing.T, str string, data []byte) {
assertEqDataImpl(t, []byte(str), data, "%s")
}

View file

@ -10,7 +10,7 @@ func removeAnchor(key string) string {
return key[1 : len(key)-1]
}
if anchor.IsExistanceAnchor(key) || anchor.IsAddingAnchor(key) || anchor.IsEqualityAnchor(key) || anchor.IsNegationAnchor(key) {
if anchor.IsExistenceAnchor(key) || anchor.IsAddingAnchor(key) || anchor.IsEqualityAnchor(key) || anchor.IsNegationAnchor(key) {
return key[2 : len(key)-1]
}

View file

@ -17,9 +17,12 @@ import (
)
const (
PodControllers = "DaemonSet,Deployment,Job,StatefulSet"
//PodControllers stores the list of Pod-controllers in csv string
PodControllers = "DaemonSet,Deployment,Job,StatefulSet"
//PodControllersAnnotation defines the annotation key for Pod-Controllers
PodControllersAnnotation = "pod-policies.kyverno.io/autogen-controllers"
PodTemplateAnnotation = "pod-policies.kyverno.io/autogen-applied"
//PodTemplateAnnotation defines the annotation key for Pod-Template
PodTemplateAnnotation = "pod-policies.kyverno.io/autogen-applied"
)
// Mutate performs mutation. Overlay first and then mutation patches
@ -34,7 +37,7 @@ func Mutate(policyContext PolicyContext) (resp response.EngineResponse) {
defer endMutateResultResponse(&resp, startTime)
incrementAppliedRuleCount := func() {
// rules applied succesfully count
// rules applied successfully count
resp.PolicyResponse.RulesAppliedCount++
}

View file

@ -114,7 +114,7 @@ func Test_variableSubstitutionPathNotExist(t *testing.T) {
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitue-variable"
"name": "substitute-variable"
},
"spec": {
"rules": [

View file

@ -18,10 +18,10 @@ const (
Less Operator = "<"
)
const relativePrefix Operator = "./"
//ReferenceSign defines the operator for anchor reference
const ReferenceSign Operator = "$()"
// getOperatorFromStringPattern parses opeartor from pattern
// GetOperatorFromStringPattern parses opeartor from pattern
func GetOperatorFromStringPattern(pattern string) Operator {
if len(pattern) < 2 {
return Equal

View file

@ -10,10 +10,11 @@ import (
)
const (
//SaPrefix defines the prefix for service accounts
SaPrefix = "system:serviceaccount:"
)
// matchAdmissionInfo return true if the rule can be applied to the request
// MatchAdmissionInfo return true if the rule can be applied to the request
func MatchAdmissionInfo(rule kyverno.Rule, requestInfo kyverno.RequestInfo) bool {
// when processing existing resource, it does not contain requestInfo
// skip permission checking

View file

@ -47,7 +47,7 @@ func (rs ResourceSpec) GetKey() string {
type PolicyStats struct {
// time required to process the policy rules on a resource
ProcessingTime time.Duration `json:"processingTime"`
// Count of rules that were applied succesfully
// Count of rules that were applied successfully
RulesAppliedCount int `json:"rulesAppliedCount"`
}

View file

@ -10,7 +10,6 @@ import (
"github.com/minio/minio/pkg/wildcard"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/context"
"github.com/nirmata/kyverno/pkg/engine/operator"
"github.com/nirmata/kyverno/pkg/engine/response"
"github.com/nirmata/kyverno/pkg/engine/variables"
"github.com/nirmata/kyverno/pkg/utils"
@ -23,7 +22,7 @@ import (
type EngineStats struct {
// average time required to process the policy rules on a resource
ExecutionTime time.Duration
// Count of rules that were applied succesfully
// Count of rules that were applied successfully
RulesAppliedCount int
}
@ -146,12 +145,16 @@ func MatchesResourceDescription(resource unstructured.Unstructured, rule kyverno
}()
}
//Condition type for conditions
type Condition int
const (
// NotEvaluate to not-evaluate to condition
NotEvaluate Condition = 0
Process Condition = 1
Skip Condition = 2
// Process to process the condition
Process Condition = 1
// Skip to skip the condition
Skip Condition = 2
)
// ParseResourceInfoFromObject get kind/namepace/name from resource
@ -219,19 +222,6 @@ func findKind(kinds []string, kindGVK string) bool {
return false
}
func isStringIsReference(str string) bool {
if len(str) < len(operator.ReferenceSign) {
return false
}
return str[0] == '$' && str[1] == '(' && str[len(str)-1] == ')'
}
type resourceInfo struct {
Resource unstructured.Unstructured
Gvk *metav1.GroupVersionKind
}
// validateGeneralRuleInfoVariables validate variable subtition defined in
// - MatchResources
// - ExcludeResources

View file

@ -6,12 +6,17 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
//RuleType defines the type for rule
type RuleType int
const (
//Mutation type for mutation rule
Mutation RuleType = iota
//Validation type for validation rule
Validation
//Generation type for generation rule
Generation
//All type for other rule operations(future)
All
)
@ -73,6 +78,7 @@ func JoinPatches(patches [][]byte) []byte {
return result
}
//ConvertToUnstructured converts the resource to unstructured format
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data)
@ -82,7 +88,7 @@ func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
return resource, nil
}
// getAnchorsFromMap gets the conditional anchor map
// GetAnchorsFromMap gets the conditional anchor map
func GetAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})

View file

@ -1,9 +1,9 @@
package utils
import(
"testing"
import (
"encoding/json"
"gotest.tools/assert"
"testing"
)
func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) {
@ -19,8 +19,10 @@ func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) {
}`)
var unmarshalled map[string]interface{}
json.Unmarshal(rawMap, &unmarshalled)
err := json.Unmarshal(rawMap, &unmarshalled)
if err != nil {
t.Error(err)
}
actualMap := GetAnchorsFromMap(unmarshalled)
assert.Assert(t, len(actualMap) == 0)
}
}

View file

@ -488,9 +488,19 @@ func Test_validateGeneralRuleInfoVariables(t *testing.T) {
assert.NilError(t, json.Unmarshal(policyRaw, &policy))
ctx := context.NewContext()
ctx.AddResource(rawResource)
ctx.AddUserInfo(userReqInfo)
ctx.AddSA("system:serviceaccount:test:testuser")
var err error
err = ctx.AddResource(rawResource)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
err = ctx.AddSA("system:serviceaccount:test:testuser")
if err != nil {
t.Error(err)
}
expectPaths := []string{"request.userInfo.username1", "request.object.namespace", ""}

View file

@ -3,47 +3,18 @@ package validate
import (
"fmt"
"strconv"
"github.com/nirmata/kyverno/pkg/engine/operator"
)
//ValidationFailureReason defeins type for Validation Failure reason
type ValidationFailureReason int
const (
// PathNotPresent if path is not present
PathNotPresent ValidationFailureReason = iota
// Rulefailure if the rule failed
Rulefailure
)
func isStringIsReference(str string) bool {
if len(str) < len(operator.ReferenceSign) {
return false
}
return str[0] == '$' && str[1] == '(' && str[len(str)-1] == ')'
}
// convertToFloat converts string and any other value to float64
func convertToFloat(value interface{}) (float64, error) {
switch typed := value.(type) {
case string:
var err error
floatValue, err := strconv.ParseFloat(typed, 64)
if err != nil {
return 0, err
}
return floatValue, nil
case float64:
return typed, nil
case int64:
return float64(typed), nil
case int:
return float64(typed), nil
default:
return 0, fmt.Errorf("Could not convert %T to float64", value)
}
}
// convertToString converts value to string
func convertToString(value interface{}) (string, error) {
switch typed := value.(type) {
@ -74,6 +45,7 @@ func getRawKeyIfWrappedWithAttributes(str string) string {
}
}
//ValidationError stores error for validation error
type ValidationError struct {
StatusCode ValidationFailureReason
ErrorMsg string

View file

@ -55,7 +55,7 @@ func ValidateValueWithPattern(value, pattern interface{}) bool {
func validateValueWithMapPattern(value interface{}, typedPattern map[string]interface{}) bool {
// verify the type of the resource value is map[string]interface,
// we only check for existance of object, not the equality of content and value
// we only check for existence of object, not the equality of content and value
//TODO: check if adding
_, ok := value.(map[string]interface{})
if !ok {

View file

@ -15,7 +15,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/variables"
)
// validateResourceWithPattern is a start of element-by-element validation process
// ValidateResourceWithPattern is a start of element-by-element validation process
// It assumes that validation is started from root, so "/" is passed
func ValidateResourceWithPattern(ctx context.EvalInterface, resource, pattern interface{}) (string, ValidationError) {
// if referenced path is not present, we skip processing the rule and report violation
@ -93,7 +93,7 @@ func validateMap(resourceMap, patternMap map[string]interface{}, origPattern int
for key, patternElement := range anchors {
// get handler for each pattern in the pattern
// - Conditional
// - Existance
// - Existence
// - Equality
handler := anchor.CreateElementHandler(key, patternElement, path)
handlerPath, err := handler.Handle(validateResourceElement, resourceMap, origPattern)
@ -274,3 +274,11 @@ func validateArrayOfMaps(resourceMapArray []interface{}, patternMap map[string]i
}
return "", nil
}
func isStringIsReference(str string) bool {
if len(str) < len(operator.ReferenceSign) {
return false
}
return str[0] == '$' && str[1] == '(' && str[len(str)-1] == ')'
}

View file

@ -37,7 +37,7 @@ func Validate(policyContext PolicyContext) (resp response.EngineResponse) {
resp := validateResource(ctx, policy, newR, admissionInfo)
startResultResponse(resp, policy, newR)
defer endResultResponse(resp, startTime)
// set PatchedResource with orgin resource if empty
// set PatchedResource with origin resource if empty
// in order to create policy violation
if reflect.DeepEqual(resp.PatchedResource, unstructured.Unstructured{}) {
resp.PatchedResource = newR
@ -79,11 +79,11 @@ func startResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPo
func endResultResponse(resp *response.EngineResponse, startTime time.Time) {
resp.PolicyResponse.ProcessingTime = time.Since(startTime)
glog.V(4).Infof("Finished applying validation rules policy %v (%v)", resp.PolicyResponse.Policy, resp.PolicyResponse.ProcessingTime)
glog.V(4).Infof("Validation Rules appplied succesfully count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
glog.V(4).Infof("Validation Rules appplied successfully count %v for policy %q", resp.PolicyResponse.RulesAppliedCount, resp.PolicyResponse.Policy)
}
func incrementAppliedCount(resp *response.EngineResponse) {
// rules applied succesfully count
// rules applied successfully count
resp.PolicyResponse.RulesAppliedCount++
}
@ -134,7 +134,7 @@ func validateResource(ctx context.EvalInterface, policy kyverno.ClusterPolicy, r
}
func isSameResponse(oldResponse, newResponse *response.EngineResponse) bool {
// if the respones are same then return true
// if the response are same then return true
return isSamePolicyResponse(oldResponse.PolicyResponse, newResponse.PolicyResponse)
}
@ -203,14 +203,14 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
return resp
}
// rule application succesful
glog.V(4).Infof("rule %s pattern validated succesfully on resource %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
// rule application successful
glog.V(4).Infof("rule %s pattern validated successfully on resource %s/%s/%s", rule.Name, resource.GetKind(), resource.GetNamespace(), resource.GetName())
resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' succeeded.", rule.Name)
return resp
}
// using anyPattern we can define multiple patterns and only one of them has to be succesfully validated
// using anyPattern we can define multiple patterns and only one of them has to be successfully validated
// return directly if one pattern succeed
// if none succeed, report violation / policyerror(TODO)
if rule.Validation.AnyPattern != nil {
@ -218,9 +218,9 @@ func validatePatterns(ctx context.EvalInterface, resource unstructured.Unstructu
var failedPaths, invalidPaths []string
for index, pattern := range rule.Validation.AnyPattern {
path, err := validate.ValidateResourceWithPattern(ctx, resource.Object, pattern)
// this pattern was succesfully validated
// this pattern was successfully validated
if reflect.DeepEqual(err, validate.ValidationError{}) {
glog.V(4).Infof("anyPattern %v succesfully validated on resource %s/%s/%s", pattern, resource.GetKind(), resource.GetNamespace(), resource.GetName())
glog.V(4).Infof("anyPattern %v successfully validated on resource %s/%s/%s", pattern, resource.GetKind(), resource.GetNamespace(), resource.GetName())
resp.Success = true
resp.Message = fmt.Sprintf("Validation rule '%s' anyPattern[%d] succeeded.", rule.Name, index)
return resp

View file

@ -1457,7 +1457,7 @@ func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitue-variable"
"name": "substitute-variable"
},
"spec": {
"rules": [
@ -1528,7 +1528,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies(t *t
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitue-variable"
"name": "substitute-variable"
},
"spec": {
"rules": [
@ -1620,7 +1620,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *test
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitue-variable"
"name": "substitute-variable"
},
"spec": {
"rules": [
@ -1710,7 +1710,7 @@ func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatter
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitue-variable"
"name": "substitute-variable"
},
"spec": {
"rules": [

View file

@ -7,6 +7,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/variables/operator"
)
//Evaluate evaluates the condition
func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
// get handler for the operator
handle := operator.CreateOperatorHandler(ctx, condition.Operator, SubstituteVariables)
@ -16,6 +17,7 @@ func Evaluate(ctx context.EvalInterface, condition kyverno.Condition) bool {
return handle.Evaluate(condition.Key, condition.Value)
}
//EvaluateConditions evaluates multiple conditions
func EvaluateConditions(ctx context.EvalInterface, conditions []kyverno.Condition) bool {
// AND the conditions
for _, condition := range conditions {

View file

@ -299,12 +299,20 @@ func Test_Eval_NoEqual_Const_float64_Fail(t *testing.T) {
func Test_Eval_Equal_Const_object_Pass(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`{ "dir": { "file1": "a" } }`)
obj2Raw := []byte(`{ "dir": { "file1": "a" } }`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -319,12 +327,20 @@ func Test_Eval_Equal_Const_object_Pass(t *testing.T) {
func Test_Eval_Equal_Const_object_Fail(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`{ "dir": { "file1": "a" } }`)
obj2Raw := []byte(`{ "dir": { "file1": "b" } }`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -339,12 +355,20 @@ func Test_Eval_Equal_Const_object_Fail(t *testing.T) {
func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`{ "dir": { "file1": "a" } }`)
obj2Raw := []byte(`{ "dir": { "file1": "b" } }`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -359,12 +383,20 @@ func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) {
func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`{ "dir": { "file1": "a" } }`)
obj2Raw := []byte(`{ "dir": { "file1": "a" } }`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -381,12 +413,20 @@ func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) {
func Test_Eval_Equal_Const_list_Pass(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
obj2Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -401,12 +441,18 @@ func Test_Eval_Equal_Const_list_Pass(t *testing.T) {
func Test_Eval_Equal_Const_list_Fail(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
obj2Raw := []byte(`[ { "name": "b", "file": "a" }, { "name": "b", "file": "b" } ]`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -421,12 +467,18 @@ func Test_Eval_Equal_Const_list_Fail(t *testing.T) {
func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
obj2Raw := []byte(`[ { "name": "b", "file": "a" }, { "name": "b", "file": "b" } ]`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -441,12 +493,18 @@ func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) {
func Test_Eval_NotEqual_Const_list_Fail(t *testing.T) {
ctx := context.NewContext()
var err error
obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
obj2Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`)
var obj1, obj2 interface{}
json.Unmarshal(obj1Raw, &obj1)
json.Unmarshal(obj2Raw, &obj2)
err = json.Unmarshal(obj1Raw, &obj1)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(obj2Raw, &obj2)
if err != nil {
t.Error(err)
}
// no variables
condition := kyverno.Condition{
Key: obj1,
@ -477,7 +535,10 @@ func Test_Eval_Equal_Var_Pass(t *testing.T) {
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err := ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
condition := kyverno.Condition{
Key: "{{request.object.metadata.name}}",
Operator: kyverno.Equal,
@ -505,7 +566,10 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) {
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err := ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
condition := kyverno.Condition{
Key: "{{request.object.metadata.name}}",
Operator: kyverno.Equal,

View file

@ -9,6 +9,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/context"
)
//NewEqualHandler returns handler to manage Equal operations
func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
return EqualHandler{
ctx: ctx,
@ -16,11 +17,13 @@ func NewEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionH
}
}
//EqualHandler provides implementation to handle NotEqual Operator
type EqualHandler struct {
ctx context.EvalInterface
subHandler VariableSubstitutionHandler
}
//Evaluate evaluates expression with Equal Operator
func (eh EqualHandler) Evaluate(key, value interface{}) bool {
// substitute the variables
nKey := eh.subHandler(eh.ctx, key)

View file

@ -9,6 +9,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/context"
)
//NewNotEqualHandler returns handler to manage NotEqual operations
func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstitutionHandler) OperatorHandler {
return NotEqualHandler{
ctx: ctx,
@ -16,11 +17,13 @@ func NewNotEqualHandler(ctx context.EvalInterface, subHandler VariableSubstituti
}
}
//NotEqualHandler provides implementation to handle NotEqual Operator
type NotEqualHandler struct {
ctx context.EvalInterface
subHandler VariableSubstitutionHandler
}
//Evaluate evaluates expression with NotEqual Operator
func (neh NotEqualHandler) Evaluate(key, value interface{}) bool {
// substitute the variables
nKey := neh.subHandler(neh.ctx, key)

View file

@ -6,6 +6,7 @@ import (
"github.com/nirmata/kyverno/pkg/engine/context"
)
//OperatorHandler provides interface to manage types
type OperatorHandler interface {
Evaluate(key, value interface{}) bool
validateValuewithBoolPattern(key bool, value interface{}) bool
@ -15,8 +16,10 @@ type OperatorHandler interface {
validateValueWithSlicePattern(key []interface{}, value interface{}) bool
}
//VariableSubstitutionHandler defines the handler function for variable substitution
type VariableSubstitutionHandler = func(ctx context.EvalInterface, pattern interface{}) interface{}
//CreateOperatorHandler returns the operator handler based on the operator used in condition
func CreateOperatorHandler(ctx context.EvalInterface, op kyverno.ConditionOperator, subHandler VariableSubstitutionHandler) OperatorHandler {
switch op {
case kyverno.Equal:

View file

@ -1,6 +1,7 @@
package variables
import (
"fmt"
"regexp"
"strings"
@ -42,6 +43,7 @@ func extractVariables(pattern interface{}) [][]string {
case string:
return extractValue(typedPattern)
default:
fmt.Printf("variable type %T", typedPattern)
return nil
}
}

View file

@ -37,7 +37,9 @@ func Test_ExtractVariables(t *testing.T) {
`)
var pattern interface{}
json.Unmarshal(patternRaw, &pattern)
if err := json.Unmarshal(patternRaw, &pattern); err != nil {
t.Error(err)
}
vars := extractVariables(pattern)
@ -95,10 +97,16 @@ func Test_ValidateVariables_NoVariable(t *testing.T) {
assert.NilError(t, json.Unmarshal(patternRaw, &pattern))
assert.NilError(t, json.Unmarshal(resourceRaw, &resource))
var err error
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(userReqInfo)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
invalidPaths := ValidateVariables(ctx, pattern)
assert.Assert(t, len(invalidPaths) == 0)
}
@ -152,8 +160,15 @@ func Test_ValidateVariables(t *testing.T) {
assert.NilError(t, json.Unmarshal(resourceRaw, &resource))
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(userReqInfo)
var err error
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
invalidPaths := ValidateVariables(ctx, pattern)
assert.Assert(t, len(invalidPaths) > 0)

View file

@ -96,7 +96,7 @@ func getValueQuery(ctx context.EvalInterface, valuePattern string) interface{} {
return newVal
}
// we do not support mutliple substitution per statement for non-string types
// we do not support multiple substitution per statement for non-string types
for _, value := range varMap {
return value
}

View file

@ -59,12 +59,27 @@ func Test_variablesub1(t *testing.T) {
resultMap := []byte(`{"data":{"rules":[{"apiGroups":[""],"resourceNames":["temp"],"resources":["namespaces"],"verbs":["*"]}]},"kind":"ClusterRole","name":"ns-owner-user1"}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(userReqInfo)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -125,12 +140,29 @@ func Test_variablesub_multiple(t *testing.T) {
resultMap := []byte(`{"data":{"rules":[{"apiGroups":[""],"resourceNames":["temp"],"resources":["namespaces"],"verbs":["*"]}]},"kind":"ClusterRole","name":"ns-owner-n1-user1-bindings"}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(userReqInfo)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -188,12 +220,29 @@ func Test_variablesubstitution(t *testing.T) {
},
}
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(userReqInfo)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
err = ctx.AddUserInfo(userReqInfo)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -231,12 +280,24 @@ func Test_variableSubstitutionValue(t *testing.T) {
resultMap := []byte(`{"spec":{"name":"temp"}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -271,12 +332,24 @@ func Test_variableSubstitutionValueOperatorNotEqual(t *testing.T) {
resultMap := []byte(`{"spec":{"name":"!temp"}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -313,12 +386,24 @@ func Test_variableSubstitutionValueFail(t *testing.T) {
resultMap := []byte(`{"spec":{"name":null}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -360,12 +445,24 @@ func Test_variableSubstitutionObject(t *testing.T) {
resultMap := []byte(`{"spec":{"variable":{"var1":"temp1","var2":"temp2","varNested":{"var1":"temp1"}}}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -408,12 +505,24 @@ func Test_variableSubstitutionObjectOperatorNotEqualFail(t *testing.T) {
resultMap := []byte(`{"spec":{"variable":null}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {
@ -457,12 +566,24 @@ func Test_variableSubstitutionMultipleObject(t *testing.T) {
resultMap := []byte(`{"spec":{"var":"temp1","variable":{"var1":"temp1","var2":"temp2","varNested":{"var1":"temp1"}}}}`)
var pattern, resource interface{}
json.Unmarshal(patternMap, &pattern)
json.Unmarshal(resourceRaw, &resource)
var err error
err = json.Unmarshal(patternMap, &pattern)
if err != nil {
t.Error(err)
}
err = json.Unmarshal(resourceRaw, &resource)
if err != nil {
t.Error(err)
}
// context
ctx := context.NewContext()
ctx.AddResource(resourceRaw)
err = ctx.AddResource(resourceRaw)
if err != nil {
t.Error(err)
}
value := SubstituteVariables(ctx, pattern)
resultRaw, err := json.Marshal(value)
if err != nil {

View file

@ -85,7 +85,7 @@ func (gen *Generator) Add(infos ...Info) {
if info.Name == "" {
// dont create event for resources with generateName
// as the name is not generated yet
glog.V(4).Infof("recieved info %v, not creating an event as the resource has not been assigned a name yet", info)
glog.V(4).Infof("received info %v, not creating an event as the resource has not been assigned a name yet", info)
continue
}
gen.queue.Add(info)

View file

@ -2,8 +2,6 @@ package event
const eventWorkQueueName = "kyverno-events"
const eventWorkerThreadCount = 1
const workQueueRetryLimit = 5
//Info defines the event details

View file

@ -35,7 +35,7 @@ func (c *Controller) processGR(gr kyverno.GenerateRequest) error {
createTime := gr.GetCreationTimestamp()
if time.Since(createTime.UTC()) > timeout {
// the GR was in state ["",Failed] for more than timeout
glog.V(4).Infof("GR %s was not processed succesfully in %d minutes", gr.Name, timoutMins)
glog.V(4).Infof("GR %s was not processed successfully in %d minutes", gr.Name, timoutMins)
glog.V(4).Infof("delete GR %s", gr.Name)
return c.control.Delete(gr.Name)
}
@ -60,7 +60,7 @@ func deleteGeneratedResources(client *dclient.Client, gr kyverno.GenerateRequest
if err != nil {
return err
}
}
return nil
}

View file

@ -25,6 +25,7 @@ const (
maxRetries = 5
)
//Controller manages life-cycle of generate-requests
type Controller struct {
// dyanmic client implementation
client *dclient.Client
@ -54,6 +55,7 @@ type Controller struct {
nsInformer informers.GenericInformer
}
//NewController returns a new controller instance to manage generate-requests
func NewController(
kyvernoclient *kyvernoclient.Clientset,
client *dclient.Client,
@ -106,10 +108,10 @@ func (c *Controller) deleteGenericResource(obj interface{}) {
glog.Errorf("failed to Generate Requests for resource %s/%s/%s: %v", r.GetKind(), r.GetNamespace(), r.GetName(), err)
return
}
// re-evaluate the GR as the resource was deleted
for _, gr := range grs {
c.enqueueGR(gr)
}
// re-evaluate the GR as the resource was deleted
for _, gr := range grs {
c.enqueueGR(gr)
}
}
func (c *Controller) deletePolicy(obj interface{}) {
@ -179,6 +181,7 @@ func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
c.queue.Add(key)
}
//Run starts the generate-request re-conciliation loop
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer c.queue.ShutDown()

View file

@ -5,14 +5,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// ControlInterface manages resource deletes
type ControlInterface interface {
Delete(gr string) error
}
//Control provides implementation to manage resource
type Control struct {
client kyvernoclient.Interface
}
//Delete deletes the specified resource
func (c Control) Delete(gr string) error {
return c.client.KyvernoV1().GenerateRequests("kyverno").Delete(gr,&metav1.DeleteOptions{})
return c.client.KyvernoV1().GenerateRequests("kyverno").Delete(gr, &metav1.DeleteOptions{})
}

View file

@ -25,6 +25,7 @@ const (
maxRetries = 5
)
// Controller manages the life-cycle for Generate-Requests and applies generate rule
type Controller struct {
// dyanmic client implementation
client *dclient.Client
@ -58,6 +59,7 @@ type Controller struct {
nsInformer informers.GenericInformer
}
//NewController returns an instance of the Generate-Request Controller
func NewController(
kyvernoclient *kyvernoclient.Clientset,
client *dclient.Client,

View file

@ -2,7 +2,7 @@ package generate
import "fmt"
// DATA
// ParseFailed stores the resource that failed to parse
type ParseFailed struct {
spec interface{}
parseError error
@ -12,10 +12,12 @@ func (e *ParseFailed) Error() string {
return fmt.Sprintf("failed to parse the resource spec %v: %v", e.spec, e.parseError.Error())
}
//NewParseFailed returns a new ParseFailed error
func NewParseFailed(spec interface{}, err error) *ParseFailed {
return &ParseFailed{spec: spec, parseError: err}
}
//Violation stores the rule that violated
type Violation struct {
rule string
err error
@ -25,10 +27,12 @@ func (e *Violation) Error() string {
return fmt.Sprintf("creating Violation; error %s", e.err)
}
//NewViolation returns a new Violation error
func NewViolation(rule string, err error) *Violation {
return &Violation{rule: rule, err: err}
}
// NotFound stores the resource that was not found
type NotFound struct {
kind string
namespace string
@ -39,10 +43,12 @@ func (e *NotFound) Error() string {
return fmt.Sprintf("resource %s/%s/%s not present", e.kind, e.namespace, e.name)
}
//NewNotFound returns a new NotFound error
func NewNotFound(kind, namespace, name string) *NotFound {
return &NotFound{kind: kind, namespace: namespace, name: name}
}
//ConfigNotFound stores the config information
type ConfigNotFound struct {
config interface{}
kind string
@ -54,6 +60,7 @@ func (e *ConfigNotFound) Error() string {
return fmt.Sprintf("configuration %v, not present in resource %s/%s/%s", e.config, e.kind, e.namespace, e.name)
}
//NewConfigNotFound returns a new NewConfigNotFound error
func NewConfigNotFound(config interface{}, kind, namespace, name string) *ConfigNotFound {
return &ConfigNotFound{config: config, kind: kind, namespace: namespace, name: name}
}

View file

@ -66,10 +66,21 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
glog.V(4).Infof("failed to marshal resource: %v", err)
return nil, err
}
ctx.AddResource(resourceRaw)
ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddResource(resourceRaw)
if err != nil {
glog.Infof("Failed to load resource in context: %v", err)
return nil, err
}
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
if err != nil {
glog.Infof("Failed to load userInfo in context: %v", err)
return nil, err
}
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil {
glog.Infof("Failed to load serviceAccount in context: %v", err)
return nil, err
}
policyContext := engine.PolicyContext{
NewResource: resource,
@ -79,7 +90,7 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
}
// check if the policy still applies to the resource
engineResponse := engine.GenerateNew(policyContext)
engineResponse := engine.Generate(policyContext)
if len(engineResponse.PolicyResponse.Rules) == 0 {
glog.V(4).Infof("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)

View file

@ -14,8 +14,8 @@ import (
func reportEvents(err error, eventGen event.Interface, gr kyverno.GenerateRequest, resource unstructured.Unstructured) {
if err == nil {
// Success Events
// - resource -> policy rule applied succesfully
// - policy -> rule succesfully applied on resource
// - resource -> policy rule applied successfully
// - policy -> rule successfully applied on resource
events := successEvents(gr, resource)
eventGen.Add(events...)
return
@ -95,7 +95,7 @@ func successEvents(gr kyverno.GenerateRequest, resource unstructured.Unstructure
pe.Name = gr.Spec.Policy
pe.Reason = event.PolicyApplied.String()
pe.Source = event.GeneratePolicyController
pe.Message = fmt.Sprintf("applied succesfully on resource %s/%s/%s", resource.GetKind(), resource.GetNamespace(), resource.GetName())
pe.Message = fmt.Sprintf("applied successfully on resource %s/%s/%s", resource.GetKind(), resource.GetNamespace(), resource.GetName())
events = append(events, pe)
// Resource
@ -105,7 +105,7 @@ func successEvents(gr kyverno.GenerateRequest, resource unstructured.Unstructure
re.Name = resource.GetName()
re.Reason = event.PolicyApplied.String()
re.Source = event.GeneratePolicyController
re.Message = fmt.Sprintf("policy %s succesfully applied", gr.Spec.Policy)
re.Message = fmt.Sprintf("policy %s successfully applied", gr.Spec.Policy)
events = append(events, re)
return events

View file

@ -6,6 +6,7 @@ import (
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
)
//StatusControlInterface provides interface to update status subresource
type StatusControlInterface interface {
Failed(gr kyverno.GenerateRequest, message string, genResources []kyverno.ResourceSpec) error
Success(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error
@ -16,7 +17,7 @@ type StatusControl struct {
client kyvernoclient.Interface
}
//FailedGR sets gr status.state to failed with message
//Failed sets gr status.state to failed with message
func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genResources []kyverno.ResourceSpec) error {
gr.Status.State = kyverno.Failed
gr.Status.Message = message
@ -31,7 +32,7 @@ func (sc StatusControl) Failed(gr kyverno.GenerateRequest, message string, genRe
return nil
}
// SuccessGR sets the gr status.state to completed and clears message
// Success sets the gr status.state to completed and clears message
func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyverno.ResourceSpec) error {
gr.Status.State = kyverno.Completed
gr.Status.Message = ""

View file

@ -112,7 +112,7 @@ func applyPolicyOnRaw(policy *kyverno.ClusterPolicy, rawResource []byte, gvk *me
glog.Warning(r.Message)
}
} else if len(engineResponse.PolicyResponse.Rules) > 0 {
glog.Infof("Mutation from policy %s has applied succesfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
glog.Infof("Mutation from policy %s has applied successfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
// Process Validation
engineResponse := engine.Validate(engine.PolicyContext{Policy: *policy, NewResource: *resource})
@ -124,7 +124,7 @@ func applyPolicyOnRaw(policy *kyverno.ClusterPolicy, rawResource []byte, gvk *me
}
return patchedResource, fmt.Errorf("policy %s on resource %s/%s not satisfied", policy.Name, rname, rns)
} else if len(engineResponse.PolicyResponse.Rules) > 0 {
glog.Infof("Validation from policy %s has applied succesfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
glog.Infof("Validation from policy %s has applied successfully to %s %s/%s", policy.Name, gvk.Kind, rname, rns)
}
}
return patchedResource, nil

View file

@ -94,6 +94,8 @@ func scanDir(dir string) ([]string, error) {
return res[1:], nil
}
//ConvertToUnstructured converts the resource to unstructured format
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data)

View file

@ -173,7 +173,7 @@ func (nsc *NamespaceController) Run(workers int, stopCh <-chan struct{}) {
return
}
for i := 0; i < workerCount; i++ {
for i := 0; i < workers; i++ {
go wait.Until(nsc.worker, time.Second, stopCh)
}
<-stopCh

View file

@ -98,7 +98,7 @@ func (nsc *NamespaceController) processNamespace(namespace corev1.Namespace) []r
ns := unstructured.Unstructured{Object: unstr}
// get all the policies that have a generate rule and resource description satifies the namespace
// get all the policies that have a generate rule and resource description satisfies the namespace
// apply policy on resource
policies := listpolicies(ns, nsc.pMetaStore)
var engineResponses []response.EngineResponse
@ -233,7 +233,7 @@ func applyPolicy(client *client.Client, resource unstructured.Unstructured, p ky
Client: client,
Context: ctx,
}
engineResponse := engine.GenerateNew(policyContext)
engineResponse := engine.Generate(policyContext)
// gather stats
gatherStat(p.Name, engineResponse.PolicyResponse)
//send stats

View file

@ -1,7 +0,0 @@
package namespace
const (
wqNamespace string = "namespace"
workerCount int = 1
wqRetryLimit int = 5
)

View file

@ -129,7 +129,7 @@ func getFailedOverallRuleInfo(resource unstructured.Unstructured, engineResponse
return response.EngineResponse{}, err
}
if !jsonpatch.Equal(patchedResource, rawResource) {
glog.V(4).Infof("policy %s rule %s condition not satisifed by existing resource", engineResponse.PolicyResponse.Policy, rule.Name)
glog.V(4).Infof("policy %s rule %s condition not satisfied by existing resource", engineResponse.PolicyResponse.Policy, rule.Name)
engineResponse.PolicyResponse.Rules[index].Success = false
engineResponse.PolicyResponse.Rules[index].Message = fmt.Sprintf("mutation json patches not found at resource path %s", extractPatchPath(rule.Patches))
}

View file

@ -8,7 +8,6 @@ import (
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
"github.com/nirmata/kyverno/pkg/engine/response"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)
@ -88,18 +87,3 @@ func getNamespacedPV(nspvLister kyvernolister.PolicyViolationLister, policyName,
return kyverno.PolicyViolation{}, nil
}
func converLabelToSelector(labelMap map[string]string) (labels.Selector, error) {
ls := &metav1.LabelSelector{}
err := metav1.Convert_Map_string_To_string_To_v1_LabelSelector(&labelMap, ls, nil)
if err != nil {
return nil, err
}
policyViolationSelector, err := metav1.LabelSelectorAsSelector(ls)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %v", err)
}
return policyViolationSelector, nil
}

View file

@ -37,8 +37,6 @@ const (
maxRetries = 15
)
var controllerKind = kyverno.SchemeGroupVersion.WithKind("ClusterPolicy")
// PolicyController is responsible for synchronizing Policy objects stored
// in the system with the corresponding policy violations
type PolicyController struct {
@ -69,7 +67,7 @@ type PolicyController struct {
rm resourceManager
// helpers to validate against current loaded configuration
configHandler config.Interface
// recieves stats and aggregates details
// receives stats and aggregates details
statusAggregator *PolicyStatusAggregator
// store to hold policy meta data for faster lookup
pMetaStore policystore.UpdateInterface
@ -187,7 +185,10 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
curP := cur.(*kyverno.ClusterPolicy)
// TODO: optimize this : policy meta-store
// Update policy-> (remove,add)
pc.pMetaStore.UnRegister(*oldP)
err := pc.pMetaStore.UnRegister(*oldP)
if err != nil {
glog.Infof("Failed to unregister policy %s", oldP.Name)
}
pc.pMetaStore.Register(*curP)
// Only process policies that are enabled for "background" execution
@ -229,7 +230,9 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
}
glog.V(4).Infof("Deleting Policy %s", p.Name)
// Unregister from policy meta-store
pc.pMetaStore.UnRegister(*p)
if err := pc.pMetaStore.UnRegister(*p); err != nil {
glog.Infof("failed to unregister policy %s", p.Name)
}
// we process policies that are not set of background processing as we need to perform policy violation
// cleanup when a policy is deleted.
pc.enqueuePolicy(p)
@ -446,7 +449,7 @@ type RealPVControl struct {
Recorder record.EventRecorder
}
//DeletePolicyViolation deletes the policy violation
//DeleteClusterPolicyViolation deletes the policy violation
func (r RealPVControl) DeleteClusterPolicyViolation(name string) error {
return r.Client.KyvernoV1().ClusterPolicyViolations().Delete(name, &metav1.DeleteOptions{})
}

View file

@ -40,7 +40,7 @@ func (pc *PolicyController) processExistingResources(policy kyverno.ClusterPolic
// apply the policy on each
glog.V(4).Infof("apply policy %s with resource version %s on resource %s/%s/%s with resource version %s", policy.Name, policy.ResourceVersion, resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
engineResponse := applyPolicy(policy, resource, pc.statusAggregator)
// get engine response for mutation & validation indipendently
// get engine response for mutation & validation independently
engineResponses = append(engineResponses, engineResponse...)
// post-processing, register the resource as processed
pc.rm.RegisterResource(policy.GetName(), policy.GetResourceVersion(), resource.GetKind(), resource.GetNamespace(), resource.GetName(), resource.GetResourceVersion())
@ -225,12 +225,16 @@ func excludeResources(included map[string]unstructured.Unstructured, exclude kyv
}
}
//Condition defines condition type
type Condition int
const (
//NotEvaluate to not evaluate condition
NotEvaluate Condition = 0
Process Condition = 1
Skip Condition = 2
// Process to evaluate condition
Process Condition = 1
// Skip to ignore/skip the condition
Skip Condition = 2
)
// merge b into a map
@ -239,47 +243,6 @@ func mergeresources(a, b map[string]unstructured.Unstructured) {
a[k] = v
}
}
func mergeLabelSectors(include, exclude *metav1.LabelSelector) *metav1.LabelSelector {
if exclude == nil {
return include
}
// negate the exclude information
// copy the label selector
//TODO: support exclude expressions in exclude
ls := include.DeepCopy()
for k, v := range exclude.MatchLabels {
lsreq := metav1.LabelSelectorRequirement{
Key: k,
Operator: metav1.LabelSelectorOpNotIn,
Values: []string{v},
}
ls.MatchExpressions = append(ls.MatchExpressions, lsreq)
}
return ls
}
func kindIsExcluded(kind string, list []string) bool {
for _, b := range list {
if b == kind {
return true
}
}
return false
}
func excludeNamespaces(namespaces, excludeNs []string) []string {
if len(excludeNs) == 0 {
return namespaces
}
filteredNamespaces := []string{}
for _, n := range namespaces {
if utils.ContainsNamepace(excludeNs, n) {
continue
}
filteredNamespaces = append(filteredNamespaces, n)
}
return filteredNamespaces
}
func getAllNamespaces(client *client.Client) []string {
var namespaces []string

View file

@ -14,7 +14,7 @@ import (
type PolicyStatusAggregator struct {
// time since we start aggregating the stats
startTime time.Time
// channel to recieve stats
// channel to receive stats
ch chan PolicyStat
//TODO: lock based on key, possibly sync.Map ?
//sync RW for policyData
@ -47,13 +47,13 @@ func (psa *PolicyStatusAggregator) Run(workers int, stopCh <-chan struct{}) {
}
func (psa *PolicyStatusAggregator) process() {
// As mutation and validation are handled seperately
// ideally we need to combine the exection time from both for a policy
// As mutation and validation are handled separately
// ideally we need to combine the execution time from both for a policy
// but its tricky to detect here the type of rules policy contains
// so we dont combine the results, but instead compute the execution time for
// mutation & validation rules seperately
// mutation & validation rules separately
for r := range psa.ch {
glog.V(4).Infof("recieved policy stats %v", r)
glog.V(4).Infof("received policy stats %v", r)
psa.aggregate(r)
}
}
@ -178,6 +178,7 @@ type PolicyStat struct {
Stats PolicyStatInfo
}
//PolicyStatInfo provides statistics for policy
type PolicyStatInfo struct {
MutationExecutionTime time.Duration
ValidationExecutionTime time.Duration
@ -187,6 +188,7 @@ type PolicyStatInfo struct {
Rules []RuleStatinfo
}
//RuleStatinfo provides statistics for rule
type RuleStatinfo struct {
RuleName string
ExecutionTime time.Duration

View file

@ -275,14 +275,14 @@ func validateValidation(v kyverno.Validation) (string, error) {
}
if v.Pattern != nil {
if path, err := validatePattern(v.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistanceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
if path, err := validatePattern(v.Pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("pattern.%s", path), err
}
}
if len(v.AnyPattern) != 0 {
for i, pattern := range v.AnyPattern {
if path, err := validatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistanceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
if path, err := validatePattern(pattern, "/", []anchor.IsAnchor{anchor.IsConditionAnchor, anchor.IsExistenceAnchor, anchor.IsEqualityAnchor, anchor.IsNegationAnchor}); err != nil {
return fmt.Sprintf("anyPattern[%d].%s", i, path), err
}
}
@ -329,7 +329,7 @@ func validateGeneration(gen kyverno.Generation) (string, error) {
//TODO: is this required ?? as anchors can only be on pattern and not resource
// we can add this check by not sure if its needed here
if path, err := validatePattern(gen.Data, "/", []anchor.IsAnchor{}); err != nil {
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resoruces: %v", err)
return fmt.Sprintf("data.%s", path), fmt.Errorf("anchors not supported on generate resources: %v", err)
}
}
return "", nil
@ -378,16 +378,16 @@ func validateMap(patternMap map[string]interface{}, path string, supportedAnchor
return path + "/" + key, fmt.Errorf("Unsupported anchor %s", key)
}
// addition check for existance anchor
// addition check for existence anchor
// value must be of type list
if anchor.IsExistanceAnchor(key) {
if anchor.IsExistenceAnchor(key) {
typedValue, ok := value.([]interface{})
if !ok {
return path + "/" + key, fmt.Errorf("Existance anchor should have value of type list")
return path + "/" + key, fmt.Errorf("Existence anchor should have value of type list")
}
// validate there is only one entry in the list
if len(typedValue) == 0 || len(typedValue) > 1 {
return path + "/" + key, fmt.Errorf("Existance anchor: single value expected, multiple specified")
return path + "/" + key, fmt.Errorf("Existence anchor: single value expected, multiple specified")
}
}
}

View file

@ -500,7 +500,6 @@ func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
if _, err := validateValidation(validation); err != nil {
assert.Assert(t, err != nil)
}
rawValidation = nil
rawValidation = []byte(`
{
"message": "validate container security contexts",
@ -567,7 +566,6 @@ func Test_Validate_Validate_ValidAnchor(t *testing.T) {
}
// case 2
rawValidate = nil
validate = kyverno.Validation{}
rawValidate = []byte(`
{

View file

@ -20,9 +20,8 @@ func (pc *PolicyController) removeResourceWebhookConfiguration() error {
}
glog.V(4).Info("no policies with mutating or validating webhook configurations, remove resource webhook configuration if one exists")
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
return nil
return pc.resourceWebhookWatcher.RemoveResourceWebhookConfiguration()
}
func (pc *PolicyController) registerResourceWebhookConfiguration() {

View file

@ -230,7 +230,10 @@ func Test_Operations(t *testing.T) {
}
// Remove
store.UnRegister(policy1)
err = store.UnRegister(policy1)
if err != nil {
t.Error(err)
}
retPolicies, err = store.LookUp("Pod", "")
if err != nil {
t.Error(err)

View file

@ -8,9 +8,10 @@ import (
"github.com/nirmata/kyverno/pkg/engine/response"
)
//GeneratePVsFromEngineResponse generate Violations from engine responses
func GeneratePVsFromEngineResponse(ers []response.EngineResponse) (pvInfos []Info) {
for _, er := range ers {
// ignore creation of PV for resoruces that are yet to be assigned a name
// ignore creation of PV for resources that are yet to be assigned a name
if er.PolicyResponse.Resource.Name == "" {
glog.V(4).Infof("resource %v, has not been assigned a name, not creating a policy violation for it", er.PolicyResponse.Resource)
continue

View file

@ -11,7 +11,7 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
ers := []response.EngineResponse{
response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: "test-substitue-variable",
Policy: "test-substitute-variable",
Resource: response.ResourceSpec{
Kind: "Pod",
Name: "test",
@ -36,7 +36,7 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
},
response.EngineResponse{
PolicyResponse: response.PolicyResponse{
Policy: "test-substitue-variable2",
Policy: "test-substitute-variable2",
Resource: response.ResourceSpec{
Kind: "Pod",
Name: "test",
@ -44,7 +44,7 @@ func Test_GeneratePVsFromEngineResponse_PathNotExist(t *testing.T) {
},
Rules: []response.RuleResponse{
response.RuleResponse{
Name: "test-path-not-exist-accross-policy",
Name: "test-path-not-exist-across-policy",
Type: "Mutation",
Message: "referenced paths are not present: request.object.metadata.name1",
Success: true,

View file

@ -214,10 +214,9 @@ func (gen *Generator) processNextWorkitem() bool {
}
func (gen *Generator) syncHandler(info Info) error {
glog.V(4).Infof("recieved info:%v", info)
glog.V(4).Infof("received info:%v", info)
var handler pvGenerator
var builder Builder
builder = newPvBuilder()
builder := newPvBuilder()
if info.Resource.GetNamespace() == "" {
// cluster scope resource generate a clusterpolicy violation
handler = newClusterPV(gen.dclient, gen.cpvLister, gen.kyvernoInterface)

View file

@ -111,6 +111,6 @@ func (nspv *namespacedPV) updatePV(newPv, oldPv *kyverno.PolicyViolation) error
if err != nil {
return fmt.Errorf("failed to update namespaced polciy violation: %v", err)
}
glog.Infof("namespced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
glog.Infof("namespaced policy violation updated for resource %v", newPv.Spec.ResourceSpec)
return nil
}

View file

@ -7,7 +7,6 @@ import (
"io/ioutil"
"os"
ospath "path"
"path/filepath"
"reflect"
"testing"
@ -51,19 +50,19 @@ type sExpected struct {
type sMutation struct {
// path to the patched resource to be compared with
PatchedResource string `yaml:"patchedresource,omitempty"`
// expected respone from the policy engine
// expected response from the policy engine
PolicyResponse response.PolicyResponse `yaml:"policyresponse"`
}
type sValidation struct {
// expected respone from the policy engine
// expected response from the policy engine
PolicyResponse response.PolicyResponse `yaml:"policyresponse"`
}
type sGeneration struct {
// generated resources
GeneratedResources []kyverno.ResourceSpec `yaml:"generatedResources"`
// expected respone from the policy engine
// expected response from the policy engine
PolicyResponse response.PolicyResponse `yaml:"policyresponse"`
}
@ -81,7 +80,7 @@ func loadScenario(t *testing.T, path string) (*scenarioT, error) {
}
var testCases []scaseT
// load test cases seperated by '---'
// load test cases separated by '---'
// each test case defines an input & expected result
scenariosBytes := bytes.Split(fileBytes, []byte("---"))
for _, scenarioBytes := range scenariosBytes {
@ -109,24 +108,6 @@ func loadFile(t *testing.T, path string) ([]byte, error) {
return ioutil.ReadFile(path)
}
//getFiles loads all scneario files in specified folder path
func getFiles(t *testing.T, folder string) ([]string, error) {
t.Logf("loading scneario files for folder %s", folder)
files, err := ioutil.ReadDir(folder)
if err != nil {
glog.Error(err)
return nil, err
}
var yamls []string
for _, file := range files {
if filepath.Ext(file.Name()) == ".yml" || filepath.Ext(file.Name()) == ".yaml" {
yamls = append(yamls, ospath.Join(folder, file.Name()))
}
}
return yamls, nil
}
func runScenario(t *testing.T, s *scenarioT) bool {
for _, tc := range s.testCases {
runTestCase(t, tc)
@ -179,7 +160,7 @@ func runTestCase(t *testing.T, tc scaseT) bool {
Client: client,
}
er = engine.GenerateNew(policyContext)
er = engine.Generate(policyContext)
t.Log(("---Generation---"))
validateResponse(t, er.PolicyResponse, tc.Expected.Generation.PolicyResponse)
// Expected generate resource will be in same namesapces as resource
@ -238,10 +219,10 @@ func validateResponse(t *testing.T, er response.PolicyResponse, expected respons
}
// cant do deepEquals and the stats will be different, or we nil those fields and then do a comparison
// forcing only the fields that are specified to be comprared
// doing a field by fields comparsion will allow us to provied more details logs and granular error reporting
// doing a field by fields comparison will allow us to provied more details logs and granular error reporting
// check policy name is same :P
if er.Policy != expected.Policy {
t.Errorf("Policy name: expected %s, recieved %s", expected.Policy, er.Policy)
t.Errorf("Policy name: expected %s, received %s", expected.Policy, er.Policy)
}
// compare resource spec
compareResourceSpec(t, er.Resource, expected.Resource)
@ -257,7 +238,7 @@ func validateResponse(t *testing.T, er response.PolicyResponse, expected respons
}
if len(er.Rules) == len(expected.Rules) {
// if there are rules being applied then we compare the rule response
// as the rules are applied in the order defined, the comparions of rules will be in order
// as the rules are applied in the order defined, the comparison of rules will be in order
for index, r := range expected.Rules {
compareRules(t, er.Rules[index], r)
}
@ -267,7 +248,7 @@ func validateResponse(t *testing.T, er response.PolicyResponse, expected respons
func compareResourceSpec(t *testing.T, resource response.ResourceSpec, expectedResource response.ResourceSpec) {
// kind
if resource.Kind != expectedResource.Kind {
t.Errorf("kind: expected %s, recieved %s", expectedResource.Kind, resource.Kind)
t.Errorf("kind: expected %s, received %s", expectedResource.Kind, resource.Kind)
}
// //TODO apiVersion
// if resource.APIVersion != expectedResource.APIVersion {
@ -276,28 +257,28 @@ func compareResourceSpec(t *testing.T, resource response.ResourceSpec, expectedR
// namespace
if resource.Namespace != expectedResource.Namespace {
t.Errorf("namespace: expected %s, recieved %s", expectedResource.Namespace, resource.Namespace)
t.Errorf("namespace: expected %s, received %s", expectedResource.Namespace, resource.Namespace)
}
// name
if resource.Name != expectedResource.Name {
t.Errorf("name: expected %s, recieved %s", expectedResource.Name, resource.Name)
t.Errorf("name: expected %s, received %s", expectedResource.Name, resource.Name)
}
}
func compareRules(t *testing.T, rule response.RuleResponse, expectedRule response.RuleResponse) {
// name
if rule.Name != expectedRule.Name {
t.Errorf("rule name: expected %s, recieved %+v", expectedRule.Name, rule.Name)
t.Errorf("rule name: expected %s, received %+v", expectedRule.Name, rule.Name)
// as the rule names dont match no need to compare the rest of the information
}
// type
if rule.Type != expectedRule.Type {
t.Errorf("rule type: expected %s, recieved %s", expectedRule.Type, rule.Type)
t.Errorf("rule type: expected %s, received %s", expectedRule.Type, rule.Type)
}
// message
// compare messages if expected rule message is not empty
if expectedRule.Message != "" && rule.Message != expectedRule.Message {
t.Errorf("rule message: expected %s, recieved %s", expectedRule.Message, rule.Message)
t.Errorf("rule message: expected %s, received %s", expectedRule.Message, rule.Message)
}
// //TODO patches
// if reflect.DeepEqual(rule.Patches, expectedRule.Patches) {
@ -306,7 +287,7 @@ func compareRules(t *testing.T, rule response.RuleResponse, expectedRule respons
// success
if rule.Success != expectedRule.Success {
t.Errorf("rule success: expected %t, recieved %t", expectedRule.Success, rule.Success)
t.Errorf("rule success: expected %t, received %t", expectedRule.Success, rule.Success)
}
}

View file

@ -9,8 +9,7 @@ import (
)
const (
defaultYamlSeparator = "---"
projectPath = "src/github.com/nirmata/kyverno"
projectPath = "src/github.com/nirmata/kyverno"
)
// LoadFile loads file in byte buffer
@ -38,6 +37,7 @@ func getResourceFromKind(kind string) string {
return ""
}
//ConvertToUnstructured converts a resource to unstructured format
func ConvertToUnstructured(data []byte) (*unstructured.Unstructured, error) {
resource := &unstructured.Unstructured{}
err := resource.UnmarshalJSON(data)

View file

@ -18,6 +18,7 @@ const (
rolekind = "Role"
)
//GetRoleRef gets the list of roles and cluster roles for the incoming api-request
func GetRoleRef(rbLister rbaclister.RoleBindingLister, crbLister rbaclister.ClusterRoleBindingLister, request *v1beta1.AdmissionRequest) (roles []string, clusterRoles []string, err error) {
// rolebindings
roleBindings, err := rbLister.List(labels.NewSelector())

View file

@ -7,10 +7,10 @@ import (
"github.com/minio/minio/pkg/wildcard"
client "github.com/nirmata/kyverno/pkg/dclient"
dclient "github.com/nirmata/kyverno/pkg/dclient"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
dclient "github.com/nirmata/kyverno/pkg/dclient"
)
//Contains Check if strint is contained in a list of string
@ -75,6 +75,8 @@ func CRDInstalled(discovery client.IDiscovery) bool {
return true
}
//CleanupOldCrd deletes any existing NamespacedPolicyViolation resources in cluster
// If resource violates policy, new Violations will be generated
func CleanupOldCrd(client *dclient.Client) {
gvr := client.DiscoveryClient.GetGVRFromKind("NamespacedPolicyViolation")
if !reflect.DeepEqual(gvr, (schema.GroupVersionResource{})) {

View file

@ -75,6 +75,6 @@ func (wrc *WebhookRegistrationClient) removeVerifyWebhookMutatingWebhookConfig(w
} else if err != nil {
glog.Errorf("failed to delete verify webhook configuration %s: %v", mutatingConfig, err)
} else {
glog.V(4).Infof("succesfully deleted verify webhook configuration %s", mutatingConfig)
glog.V(4).Infof("successfully deleted verify webhook configuration %s", mutatingConfig)
}
}

View file

@ -6,7 +6,6 @@ import (
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/config"
admregapi "k8s.io/api/admissionregistration/v1beta1"
errorsapi "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@ -105,43 +104,3 @@ func (wrc *WebhookRegistrationClient) contructDebugPolicyMutatingWebhookConfig(c
},
}
}
// removePolicyWebhookConfigurations removes mutating and validating webhook configurations, if already presnt
// webhookConfigurations are re-created later
func (wrc *WebhookRegistrationClient) removePolicyWebhookConfigurations() {
// Validating webhook configuration
var err error
var validatingConfig string
if wrc.serverIP != "" {
validatingConfig = config.PolicyValidatingWebhookConfigurationDebugName
} else {
validatingConfig = config.PolicyValidatingWebhookConfigurationName
}
glog.V(4).Infof("removing webhook configuration %s", validatingConfig)
err = wrc.client.DeleteResource(ValidatingWebhookConfigurationKind, "", validatingConfig, false)
if errorsapi.IsNotFound(err) {
glog.V(4).Infof("policy webhook configuration %s, does not exits. not deleting", validatingConfig)
} else if err != nil {
glog.Errorf("failed to delete policy webhook configuration %s: %v", validatingConfig, err)
} else {
glog.V(4).Infof("succesfully deleted policy webhook configuration %s", validatingConfig)
}
// Mutating webhook configuration
var mutatingConfig string
if wrc.serverIP != "" {
mutatingConfig = config.PolicyMutatingWebhookConfigurationDebugName
} else {
mutatingConfig = config.PolicyMutatingWebhookConfigurationName
}
glog.V(4).Infof("removing webhook configuration %s", mutatingConfig)
err = wrc.client.DeleteResource(MutatingWebhookConfigurationKind, "", mutatingConfig, false)
if errorsapi.IsNotFound(err) {
glog.V(4).Infof("policy webhook configuration %s, does not exits. not deleting", mutatingConfig)
} else if err != nil {
glog.Errorf("failed to delete policy webhook configuration %s: %v", mutatingConfig, err)
} else {
glog.V(4).Infof("succesfully deleted policy webhook configuration %s", mutatingConfig)
}
}

View file

@ -14,7 +14,9 @@ import (
)
const (
MutatingWebhookConfigurationKind string = "MutatingWebhookConfiguration"
//MutatingWebhookConfigurationKind defines the kind for MutatingWebhookConfiguration
MutatingWebhookConfigurationKind string = "MutatingWebhookConfiguration"
//ValidatingWebhookConfigurationKind defines the kind for ValidatingWebhookConfiguration
ValidatingWebhookConfigurationKind string = "ValidatingWebhookConfiguration"
)
@ -236,7 +238,9 @@ func (wrc *WebhookRegistrationClient) removeWebhookConfigurations() {
// TODO: re-work with RemoveResourceMutatingWebhookConfiguration, as the only difference is wg handling
func (wrc *WebhookRegistrationClient) removeResourceMutatingWebhookConfiguration(wg *sync.WaitGroup) {
defer wg.Done()
wrc.RemoveResourceMutatingWebhookConfiguration()
if err := wrc.RemoveResourceMutatingWebhookConfiguration(); err != nil {
glog.Error(err)
}
}
// delete policy mutating webhookconfigurations
@ -258,7 +262,7 @@ func (wrc *WebhookRegistrationClient) removePolicyMutatingWebhookConfiguration(w
} else if err != nil {
glog.Errorf("failed to delete policy webhook configuration %s: %v", mutatingConfig, err)
} else {
glog.V(4).Infof("succesfully deleted policy webhook configuration %s", mutatingConfig)
glog.V(4).Infof("successfully deleted policy webhook configuration %s", mutatingConfig)
}
}
@ -280,6 +284,6 @@ func (wrc *WebhookRegistrationClient) removePolicyValidatingWebhookConfiguration
} else if err != nil {
glog.Errorf("failed to delete policy webhook configuration %s: %v", validatingConfig, err)
} else {
glog.V(4).Infof("succesfully deleted policy webhook configuration %s", validatingConfig)
glog.V(4).Infof("successfully deleted policy webhook configuration %s", validatingConfig)
}
}

View file

@ -11,6 +11,7 @@ import (
cache "k8s.io/client-go/tools/cache"
)
//ResourceWebhookRegister manages the resource webhook registration
type ResourceWebhookRegister struct {
// pendingCreation indicates the status of resource webhook creation
pendingCreation *abool.AtomicBool
@ -21,6 +22,7 @@ type ResourceWebhookRegister struct {
webhookRegistrationClient *WebhookRegistrationClient
}
// NewResourceWebhookRegister returns a new instance of ResourceWebhookRegister manager
func NewResourceWebhookRegister(
lastReqTime *checker.LastReqTime,
mconfigwebhookinformer mconfiginformer.MutatingWebhookConfigurationInformer,
@ -35,6 +37,7 @@ func NewResourceWebhookRegister(
}
}
//RegisterResourceWebhook registers a resource webhook
func (rww *ResourceWebhookRegister) RegisterResourceWebhook() {
// drop the request if creation is in processing
if rww.pendingCreation.IsSet() {
@ -72,6 +75,7 @@ func (rww *ResourceWebhookRegister) RegisterResourceWebhook() {
}
}
//Run starts the ResourceWebhookRegister manager
func (rww *ResourceWebhookRegister) Run(stopCh <-chan struct{}) {
// wait for cache to populate first time
if !cache.WaitForCacheSync(stopCh, rww.mwebhookconfigSynced) {
@ -79,6 +83,7 @@ func (rww *ResourceWebhookRegister) Run(stopCh <-chan struct{}) {
}
}
// RemoveResourceWebhookConfiguration removes the resource webhook configurations
func (rww *ResourceWebhookRegister) RemoveResourceWebhookConfiguration() error {
var err error
// check informer cache

View file

@ -92,19 +92,6 @@ func (i *ArrayFlags) Set(value string) error {
return nil
}
// extract the kinds that the policy rules apply to
func getApplicableKindsForPolicy(p *kyverno.ClusterPolicy) []string {
kinds := []string{}
// iterate over the rules an identify all kinds
// Matching
for _, rule := range p.Spec.Rules {
for _, k := range rule.MatchResources.Kinds {
kinds = append(kinds, k)
}
}
return kinds
}
// Policy Reporting Modes
const (
Enforce = "enforce" // blocks the request on failure

View file

@ -12,17 +12,20 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
)
//GenerateRequests provides interface to manage generate requests
type GenerateRequests interface {
Create(gr kyverno.GenerateRequestSpec) error
}
// Generator defines the implmentation to mange generate request resource
type Generator struct {
// channel to recieve request
// channel to receive request
ch chan kyverno.GenerateRequestSpec
client *kyvernoclient.Clientset
stopCh <-chan struct{}
}
//NewGenerator returns a new instance of Generate-Request resource generator
func NewGenerator(client *kyvernoclient.Clientset, stopCh <-chan struct{}) *Generator {
gen := &Generator{
ch: make(chan kyverno.GenerateRequestSpec, 1000),
@ -32,7 +35,7 @@ func NewGenerator(client *kyvernoclient.Clientset, stopCh <-chan struct{}) *Gene
return gen
}
// blocking if channel is full
//Create to create generate request resoruce (blocking call if channel is full)
func (g *Generator) Create(gr kyverno.GenerateRequestSpec) error {
glog.V(4).Infof("create GR %v", gr)
// Send to channel
@ -60,7 +63,7 @@ func (g *Generator) Run(workers int) {
func (g *Generator) process() {
for r := range g.ch {
glog.V(4).Infof("recived generate request %v", r)
glog.V(4).Infof("received generate request %v", r)
if err := g.generate(r); err != nil {
glog.Errorf("Failed to create Generate Request CR: %v", err)
}
@ -75,7 +78,7 @@ func (g *Generator) generate(grSpec kyverno.GenerateRequestSpec) error {
return nil
}
// -> recieving channel to take requests to create request
// -> receiving channel to take requests to create request
// use worker pattern to read and create the CR resource
func retryCreateResource(client *kyvernoclient.Clientset, grSpec kyverno.GenerateRequestSpec) error {

View file

@ -11,6 +11,7 @@ import (
v1beta1 "k8s.io/api/admission/v1beta1"
)
//HandleGenerate handles admission-requests for policies with generate rules
func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, policies []kyverno.ClusterPolicy, patchedResource []byte, roles, clusterRoles []string) (bool, string) {
var engineResponses []response.EngineResponse
@ -33,10 +34,19 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
// build context
ctx := context.NewContext()
// load incoming resource into the context
ctx.AddResource(request.Object.Raw)
ctx.AddUserInfo(userRequestInfo)
err = ctx.AddResource(request.Object.Raw)
if err != nil {
glog.Infof("Failed to load resource in context:%v", err)
}
err = ctx.AddUserInfo(userRequestInfo)
if err != nil {
glog.Infof("Failed to load userInfo in context:%v", err)
}
// load service account in context
ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
glog.Infof("Failed to load service account in context:%v", err)
}
policyContext := engine.PolicyContext{
NewResource: *resource,
@ -47,7 +57,7 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
// engine.Generate returns a list of rules that are applicable on this resource
for _, policy := range policies {
policyContext.Policy = policy
engineResponse := engine.GenerateNew(policyContext)
engineResponse := engine.Generate(policyContext)
if len(engineResponse.PolicyResponse.Rules) > 0 {
// some generate rules do apply to the resource
engineResponses = append(engineResponses, engineResponse)

View file

@ -67,10 +67,21 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou
// build context
ctx := context.NewContext()
var err error
// load incoming resource into the context
ctx.AddResource(request.Object.Raw)
ctx.AddUserInfo(userRequestInfo)
ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddResource(request.Object.Raw)
if err != nil {
glog.Infof("Failed to load resource in context:%v", err)
}
err = ctx.AddUserInfo(userRequestInfo)
if err != nil {
glog.Infof("Failed to load userInfo in context:%v", err)
}
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
glog.Infof("Failed to load service account in context:%v", err)
}
policyContext := engine.PolicyContext{
NewResource: resource,
@ -98,7 +109,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest, resou
}
// gather patches
patches = append(patches, engineResponse.GetPatches()...)
glog.V(4).Infof("Mutation from policy %s has applied succesfully to %s %s/%s", policy.Name, request.Kind.Kind, resource.GetNamespace(), resource.GetName())
glog.V(4).Infof("Mutation from policy %s has applied successfully to %s %s/%s", policy.Name, request.Kind.Kind, resource.GetNamespace(), resource.GetName())
policyContext.NewResource = engineResponse.PatchedResource
}

View file

@ -136,7 +136,7 @@ func defaultvalidationFailureAction(policy *kyverno.ClusterPolicy) ([]byte, stri
// scenario A: not exist, set default to "all", which generates on all pod controllers
// - if name / selector exist in resource description -> skip
// as these fields may not be applicable to pod controllers
// scenario B: "none", user explicitely disable this feature -> skip
// scenario B: "none", user explicitly disable this feature -> skip
// scenario C: some certain controllers that user set -> generate on defined controllers
// copy entrie match / exclude block, it's users' responsibility to
// make sure all fields are applicable to pod cotrollers

View file

@ -42,12 +42,3 @@ func (ws *WebhookServer) handlePolicyValidation(request *v1beta1.AdmissionReques
}
return admissionResp
}
func failResponseWithMsg(msg string) *v1beta1.AdmissionResponse {
return &v1beta1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Message: msg,
},
}
}

View file

@ -80,7 +80,7 @@ func generateEvents(engineResponses []response.EngineResponse, onUpdate bool) []
return events
}
if !onUpdate {
// All policies were applied succesfully
// All policies were applied successfully
// CREATE
for _, er := range engineResponses {
successRules := er.GetSuccessRules()

View file

@ -140,7 +140,7 @@ func NewWebhookServer(
// Main server endpoint for all requests
func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
// for every request recieved on the ep update last request time,
// for every request received on the ep update last request time,
// this is used to verify admission control
ws.lastReqTime.SetTime(time.Now())
admissionReview := ws.bodyToAdmissionReview(r, w)
@ -159,7 +159,7 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
request := admissionReview.Request
switch r.URL.Path {
case config.VerifyMutatingWebhookServicePath:
// we do not apply filters as this endpoint is used explicity
// we do not apply filters as this endpoint is used explicitly
// to watch kyveno deployment and verify if admission control is enabled
admissionReview.Response = ws.handleVerifyRequest(request)
case config.MutatingWebhookServicePath:

View file

@ -67,9 +67,20 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest, pol
// build context
ctx := context.NewContext()
// load incoming resource into the context
ctx.AddResource(request.Object.Raw)
ctx.AddUserInfo(userRequestInfo)
ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
err = ctx.AddResource(request.Object.Raw)
if err != nil {
glog.Infof("Failed to load resource in context:%v", err)
}
err = ctx.AddUserInfo(userRequestInfo)
if err != nil {
glog.Infof("Failed to load userInfo in context:%v", err)
}
err = ctx.AddSA(userRequestInfo.AdmissionUserInfo.Username)
if err != nil {
glog.Infof("Failed to load service account in context:%v", err)
}
policyContext := engine.PolicyContext{
NewResource: newR,

View file

@ -10,13 +10,13 @@ expected:
- name: add-label
type: Mutation
messages:
- "Rule add-label: Patches succesfully applied."
- "Rule add-label: Patches successfully applied."
validation:
rules:
- name: check-image
type : Validation
messages:
- "Rule check-image: Validation succesfully."
- "Rule check-image: Validation successfully."
---
input:
policy: test/scenarios/cli/policy_deployment.yaml
@ -29,10 +29,10 @@ expected:
- name: add-label
type: Mutation
messages:
- "Rule add-label: Patches succesfully applied."
- "Rule add-label: Patches successfully applied."
validation:
rules:
- name: check-image
type : Validation
messages:
- "Rule check-image: Validation succesfully."
- "Rule check-image: Validation successfully."

View file

@ -14,11 +14,11 @@ expected:
- name: "Basic config generator for all namespaces"
type: Generation
messages:
- "Rule Basic config generator for all namespaces: Generation succesfully."
- "Rule Basic config generator for all namespaces: Generation successfully."
- name: "Basic clone config generator for all namespaces"
type: Generation
messages:
- "Rule Basic clone config generator for all namespaces: Generation succesfully."
- "Rule Basic clone config generator for all namespaces: Generation successfully."
---
input:
@ -36,11 +36,11 @@ expected:
- name: "copy-comfigmap"
type: Generation
messages:
- "Rule copy-comfigmap: Generation succesfully."
- "Rule copy-comfigmap: Generation successfully."
- name: "zk-kafka-address"
type: Generation
messages:
- "Rule zk-kafka-address: Generation succesfully."
- "Rule zk-kafka-address: Generation successfully."
---
input:
@ -55,4 +55,4 @@ expected:
- name: deny-all-traffic
type: Generation
messages:
- "Rule deny-all-traffic: Generation succesfully."
- "Rule deny-all-traffic: Generation successfully."

View file

@ -10,4 +10,4 @@ expected:
- name: set-image-pull-policy
type: Mutation
messages:
- "Rule set-image-pull-policy: Overlay succesfully applied."
- "Rule set-image-pull-policy: Overlay successfully applied."

View file

@ -10,4 +10,4 @@ expected:
- name: pEP
type: Mutation
messages:
- "Rule pEP: Patches succesfully applied."
- "Rule pEP: Patches successfully applied."

View file

@ -16,4 +16,4 @@ expected:
- name: pEP
type: Mutation
success: true
message: succesfully process JSON patches
message: successfully process JSON patches