package gencontroller import ( "encoding/json" "fmt" "strings" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/golang/glog" "github.com/nirmata/kyverno/pkg/annotations" v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" "github.com/nirmata/kyverno/pkg/engine" event "github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/info" violation "github.com/nirmata/kyverno/pkg/violation" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" ) func (c *Controller) processNamespace(ns *corev1.Namespace) error { //Get all policies and then verify if the namespace matches any of the defined selectors policies, err := c.listPolicies(ns) if err != nil { return err } // process policy on namespace for _, p := range policies { c.processPolicy(ns, p) } return nil } func (c *Controller) listPolicies(ns *corev1.Namespace) ([]*v1alpha1.Policy, error) { var fpolicies []*v1alpha1.Policy policies, err := c.policyLister.List(labels.NewSelector()) if err != nil { glog.Error("Unable to connect to policy controller. Unable to access policies not applying GENERATION rules") return nil, err } for _, p := range policies { // Check if the policy contains a generatoin rule for _, r := range p.Spec.Rules { if r.Generation != nil { // Check if the resource meets the description data, err := json.Marshal(ns) if err != nil { glog.Error(err) continue } // convert types of GVK nsGvk := schema.FromAPIVersionAndKind("v1", "Namespace") // Hardcode as we have a informer on specified gvk gvk := metav1.GroupVersionKind{Group: nsGvk.Group, Kind: nsGvk.Kind, Version: nsGvk.Version} if engine.ResourceMeetsDescription(data, r.MatchResources.ResourceDescription, r.ExcludeResources.ResourceDescription, gvk) { fpolicies = append(fpolicies, p) break } } } } return fpolicies, nil } func (c *Controller) processPolicy(ns *corev1.Namespace, p *v1alpha1.Policy) { var eventInfo *event.Info var onViolation bool var msg string policyInfo := info.NewPolicyInfo(p.Name, "Namespace", ns.Name, "", p.Spec.ValidationFailureAction) // Namespace has no namespace..WOW // convert to unstructured unstrMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ns) if err != nil { glog.Error(err) return } unstObj := unstructured.Unstructured{Object: unstrMap} ruleInfos := engine.Generate(c.client, p, unstObj) policyInfo.AddRuleInfos(ruleInfos) // generate annotations on namespace c.createAnnotations(policyInfo) //TODO generate namespace on created resources if !policyInfo.IsSuccessful() { glog.Infof("Failed to apply policy %s on resource %s %s", p.Name, ns.Kind, ns.Name) for _, r := range ruleInfos { glog.Warning(r.Msgs) if msg = strings.Join(r.Msgs, " "); strings.Contains(msg, "rule configuration not present in resource") { onViolation = true msg = fmt.Sprintf(`Resource creation violates generate rule '%s' of policy '%s'`, r.Name, policyInfo.Name) } } if onViolation { glog.Infof("Adding violation for generation rule of policy %s\n", policyInfo.Name) // Policy Violation v := violation.BuldNewViolation(policyInfo.Name, policyInfo.RKind, policyInfo.RNamespace, policyInfo.RName, event.PolicyViolation.String(), policyInfo.GetFailedRules()) c.violationBuilder.Add(v) } else { // Event eventInfo = event.NewEvent(policyKind, "", policyInfo.Name, event.RequestBlocked, event.FPolicyApplyBlockCreate, policyInfo.RName, policyInfo.GetRuleNames(false)) glog.V(2).Infof("Request blocked event info has prepared for %s/%s\n", policyKind, policyInfo.Name) c.eventController.Add(eventInfo) } return } glog.Infof("Generation from policy %s has succesfully applied to %s/%s", p.Name, policyInfo.RKind, policyInfo.RName) eventInfo = event.NewEvent(policyInfo.RKind, policyInfo.RNamespace, policyInfo.RName, event.PolicyApplied, event.SRulesApply, policyInfo.GetRuleNames(true), policyInfo.Name) glog.V(2).Infof("Success event info has prepared for %s/%s\n", policyInfo.RKind, policyInfo.RName) c.eventController.Add(eventInfo) } func (c *Controller) createAnnotations(pi *info.PolicyInfo) { //get resource obj, err := c.client.GetResource(pi.RKind, pi.RNamespace, pi.RName) if err != nil { glog.Error(err) return } // add annotation for policy application ann := obj.GetAnnotations() // Generation rules ann, gpatch, err := annotations.AddPolicyJSONPatch(ann, pi, info.Generation) if err != nil { glog.Error(err) return } if gpatch == nil { // nothing to patch return } // add the anotation to the resource _, err = c.client.PatchResource(pi.RKind, pi.RNamespace, pi.RName, gpatch) if err != nil { glog.Error(err) return } }