2019-02-12 16:55:14 +02:00
|
|
|
package controller
|
2019-02-11 19:49:27 +02:00
|
|
|
|
|
|
|
import (
|
2019-03-04 20:40:02 +02:00
|
|
|
"errors"
|
2019-05-06 09:12:37 -07:00
|
|
|
"fmt"
|
2019-03-04 20:40:02 +02:00
|
|
|
"log"
|
|
|
|
"os"
|
2019-03-13 12:57:04 +02:00
|
|
|
"sort"
|
2019-03-04 20:40:02 +02:00
|
|
|
"time"
|
|
|
|
|
2019-05-07 13:26:54 -07:00
|
|
|
controllerinterfaces "github.com/nirmata/kube-policy/controller/interfaces"
|
2019-05-06 09:12:37 -07:00
|
|
|
kubeClient "github.com/nirmata/kube-policy/kubeclient"
|
2019-03-04 20:40:02 +02:00
|
|
|
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
|
|
|
clientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
|
2019-03-07 17:42:37 +02:00
|
|
|
policies "github.com/nirmata/kube-policy/pkg/client/clientset/versioned/typed/policy/v1alpha1"
|
2019-03-04 20:40:02 +02:00
|
|
|
informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
|
|
|
|
lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
|
2019-05-06 09:12:37 -07:00
|
|
|
event "github.com/nirmata/kube-policy/pkg/event"
|
2019-05-07 13:26:54 -07:00
|
|
|
eventinterfaces "github.com/nirmata/kube-policy/pkg/event/interfaces"
|
2019-05-06 09:12:37 -07:00
|
|
|
eventutils "github.com/nirmata/kube-policy/pkg/event/utils"
|
2019-04-29 14:34:54 -07:00
|
|
|
violation "github.com/nirmata/kube-policy/pkg/violation"
|
2019-05-07 13:26:54 -07:00
|
|
|
violationinterfaces "github.com/nirmata/kube-policy/pkg/violation/interfaces"
|
2019-05-06 09:12:37 -07:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
mergetypes "k8s.io/apimachinery/pkg/types"
|
|
|
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
|
|
"k8s.io/client-go/rest"
|
|
|
|
"k8s.io/client-go/tools/cache"
|
2019-02-11 19:49:27 +02:00
|
|
|
)
|
|
|
|
|
2019-05-06 09:12:37 -07:00
|
|
|
// PolicyController API
|
|
|
|
type PolicyController interface {
|
2019-05-07 13:26:54 -07:00
|
|
|
controllerinterfaces.PolicyGetter
|
|
|
|
controllerinterfaces.PolicyHandlers
|
|
|
|
Run(stopCh <-chan struct{})
|
2019-05-06 09:12:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//policyController for CRD
|
|
|
|
type policyController struct {
|
2019-03-04 20:40:02 +02:00
|
|
|
policyInformerFactory informers.SharedInformerFactory
|
|
|
|
policyLister lister.PolicyLister
|
2019-03-07 17:42:37 +02:00
|
|
|
policiesInterface policies.PolicyInterface
|
2019-03-04 20:40:02 +02:00
|
|
|
logger *log.Logger
|
2019-05-07 13:26:54 -07:00
|
|
|
violationBuilder violationinterfaces.ViolationGenerator
|
|
|
|
eventBuilder eventinterfaces.BuilderInternal
|
2019-02-11 19:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-02-21 20:31:18 +02:00
|
|
|
// NewPolicyController from cmd args
|
2019-05-06 09:12:37 -07:00
|
|
|
func NewPolicyController(config *rest.Config, logger *log.Logger, kubeClient *kubeClient.KubeClient) (PolicyController, error) {
|
2019-03-04 20:40:02 +02:00
|
|
|
if logger == nil {
|
|
|
|
logger = log.New(os.Stdout, "Policy Controller: ", log.LstdFlags|log.Lshortfile)
|
|
|
|
}
|
|
|
|
|
|
|
|
if config == nil {
|
|
|
|
return nil, errors.New("Client Config should be set for controller")
|
|
|
|
}
|
|
|
|
|
|
|
|
policyClientset, err := clientset.NewForConfig(config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-06 09:12:37 -07:00
|
|
|
policyInformerFactory := informers.NewSharedInformerFactory(policyClientset, 0)
|
2019-03-04 20:40:02 +02:00
|
|
|
policyInformer := policyInformerFactory.Nirmata().V1alpha1().Policies()
|
|
|
|
|
2019-05-06 09:12:37 -07:00
|
|
|
// generate Event builder
|
|
|
|
eventBuilder, err := event.NewEventBuilder(kubeClient, logger)
|
2019-04-29 14:34:54 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-06 09:12:37 -07:00
|
|
|
|
|
|
|
// generate Violation builer
|
|
|
|
violationBuilder, err := violation.NewViolationBuilder(kubeClient, eventBuilder, logger)
|
|
|
|
|
|
|
|
controller := &policyController{
|
2019-03-04 20:40:02 +02:00
|
|
|
policyInformerFactory: policyInformerFactory,
|
|
|
|
policyLister: policyInformer.Lister(),
|
2019-03-07 17:42:37 +02:00
|
|
|
policiesInterface: policyClientset.NirmataV1alpha1().Policies("default"),
|
2019-03-04 20:40:02 +02:00
|
|
|
logger: logger,
|
2019-05-06 09:12:37 -07:00
|
|
|
violationBuilder: violationBuilder,
|
|
|
|
eventBuilder: eventBuilder,
|
2019-03-04 20:40:02 +02:00
|
|
|
}
|
|
|
|
policyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
2019-05-07 13:26:54 -07:00
|
|
|
AddFunc: controller.CreatePolicyHandler,
|
|
|
|
UpdateFunc: controller.UpdatePolicyHandler,
|
|
|
|
DeleteFunc: controller.DeletePolicyHandler,
|
2019-03-04 20:40:02 +02:00
|
|
|
})
|
2019-05-06 09:12:37 -07:00
|
|
|
// Set the controller
|
|
|
|
eventBuilder.SetController(controller)
|
|
|
|
violationBuilder.SetController(controller)
|
2019-03-04 20:40:02 +02:00
|
|
|
return controller, nil
|
2019-02-11 19:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) GetCacheInformerSync() cache.InformerSynced {
|
|
|
|
return c.policyInformerFactory.Nirmata().V1alpha1().Policies().Informer().HasSynced
|
|
|
|
}
|
|
|
|
|
2019-02-11 19:49:27 +02:00
|
|
|
// Run is main controller thread
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) Run(stopCh <-chan struct{}) {
|
2019-03-04 20:40:02 +02:00
|
|
|
c.policyInformerFactory.Start(stopCh)
|
2019-05-06 09:12:37 -07:00
|
|
|
c.eventBuilder.Run(eventutils.EventWorkerThreadCount, stopCh)
|
2019-02-13 20:44:43 +02:00
|
|
|
}
|
|
|
|
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) GetPolicies() ([]types.Policy, error) {
|
2019-03-04 20:40:02 +02:00
|
|
|
// Create nil Selector to grab all the policies
|
|
|
|
selector := labels.NewSelector()
|
|
|
|
cachedPolicies, err := c.policyLister.List(selector)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf("Error: %v", err)
|
2019-05-06 09:12:37 -07:00
|
|
|
return nil, err
|
2019-03-04 20:40:02 +02:00
|
|
|
}
|
2019-02-21 18:13:21 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
var policies []types.Policy
|
|
|
|
for _, elem := range cachedPolicies {
|
|
|
|
policies = append(policies, *elem.DeepCopy())
|
|
|
|
}
|
2019-02-21 18:13:21 +02:00
|
|
|
|
2019-03-13 12:57:04 +02:00
|
|
|
sort.Slice(policies, func(i, j int) bool {
|
|
|
|
return policies[i].CreationTimestamp.Time.Before(policies[j].CreationTimestamp.Time)
|
|
|
|
})
|
2019-05-06 09:12:37 -07:00
|
|
|
return policies, nil
|
2019-02-11 19:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-03-07 17:57:43 +02:00
|
|
|
// Writes error message to the policy logs in status section
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) LogPolicyError(name, text string) {
|
2019-03-07 17:42:37 +02:00
|
|
|
c.addPolicyLog(name, "[ERROR] "+text)
|
|
|
|
}
|
|
|
|
|
2019-03-07 17:57:43 +02:00
|
|
|
// Writes info message to the policy logs in status section
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) LogPolicyInfo(name, text string) {
|
2019-03-07 17:42:37 +02:00
|
|
|
c.addPolicyLog(name, "[ INFO] "+text)
|
|
|
|
}
|
|
|
|
|
2019-03-07 17:57:43 +02:00
|
|
|
// This is the maximum number of records that can be written to the log object of the policy.
|
|
|
|
// If this number is exceeded, the older entries will be deleted.
|
|
|
|
const policyLogMaxRecords int = 50
|
2019-03-07 17:42:37 +02:00
|
|
|
|
|
|
|
// Appends given log text to the status/logs array.
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) addPolicyLog(name, text string) {
|
2019-03-07 17:42:37 +02:00
|
|
|
getOptions := metav1.GetOptions{
|
|
|
|
ResourceVersion: "1",
|
|
|
|
IncludeUninitialized: true,
|
|
|
|
}
|
|
|
|
policy, err := c.policiesInterface.Get(name, getOptions)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf("Unable to get policy %s: %s", name, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add new log record
|
|
|
|
text = time.Now().Format("2006 Jan 02 15:04:05.999 ") + text
|
2019-05-06 09:12:37 -07:00
|
|
|
policy.Status.Logs = append(policy.Status.Logs, text)
|
|
|
|
// Pop front extra log records
|
|
|
|
logsCount := len(policy.Status.Logs)
|
|
|
|
if logsCount > policyLogMaxRecords {
|
|
|
|
policy.Status.Logs = policy.Status.Logs[logsCount-policyLogMaxRecords:]
|
|
|
|
}
|
2019-03-07 17:42:37 +02:00
|
|
|
// Save logs to policy object
|
|
|
|
_, err = c.policiesInterface.UpdateStatus(policy)
|
|
|
|
if err != nil {
|
|
|
|
c.logger.Printf("Unable to update logs for policy %s: %s", name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-07 13:26:54 -07:00
|
|
|
func (c *policyController) CreatePolicyHandler(resource interface{}) {
|
|
|
|
key := c.GetResourceKey(resource)
|
2019-03-07 17:42:37 +02:00
|
|
|
c.logger.Printf("Policy created: %s", key)
|
2019-02-13 20:44:43 +02:00
|
|
|
}
|
|
|
|
|
2019-05-07 13:26:54 -07:00
|
|
|
func (c *policyController) UpdatePolicyHandler(oldResource, newResource interface{}) {
|
|
|
|
oldKey := c.GetResourceKey(oldResource)
|
|
|
|
newKey := c.GetResourceKey(newResource)
|
2019-03-07 17:42:37 +02:00
|
|
|
c.logger.Printf("Policy %s updated to %s", oldKey, newKey)
|
2019-02-11 19:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-05-07 13:26:54 -07:00
|
|
|
func (c *policyController) DeletePolicyHandler(resource interface{}) {
|
|
|
|
key := c.GetResourceKey(resource)
|
2019-03-07 17:42:37 +02:00
|
|
|
c.logger.Printf("Policy deleted: %s", key)
|
2019-02-11 19:49:27 +02:00
|
|
|
}
|
|
|
|
|
2019-05-07 13:26:54 -07:00
|
|
|
func (c *policyController) GetResourceKey(resource interface{}) string {
|
2019-03-04 20:40:02 +02:00
|
|
|
if key, err := cache.MetaNamespaceKeyFunc(resource); err != nil {
|
2019-03-07 17:42:37 +02:00
|
|
|
c.logger.Fatalf("Error retrieving policy key: %v", err)
|
2019-03-04 20:40:02 +02:00
|
|
|
} else {
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
return ""
|
2019-02-21 18:13:21 +02:00
|
|
|
}
|
2019-05-06 09:12:37 -07:00
|
|
|
func (c *policyController) GetPolicy(name string) (*types.Policy, error) {
|
|
|
|
policyNamespace, policyName, err := cache.SplitMetaNamespaceKey(name)
|
|
|
|
if err != nil {
|
|
|
|
utilruntime.HandleError(fmt.Errorf("invalid resource key: %s", name))
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return c.getPolicyInterface(policyNamespace).Get(policyName)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *policyController) getPolicyInterface(namespace string) lister.PolicyNamespaceLister {
|
|
|
|
return c.policyLister.Policies(namespace)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *policyController) PatchPolicy(policy string, pt mergetypes.PatchType, data []byte) (*types.Policy, error) {
|
|
|
|
return c.policiesInterface.Patch(policy, pt, data)
|
|
|
|
}
|
2019-05-06 17:03:37 -07:00
|
|
|
|
|
|
|
func (c *policyController) UpdatePolicyViolations(updatedPolicy *types.Policy) error {
|
|
|
|
_, err := c.policiesInterface.UpdateStatus(updatedPolicy)
|
|
|
|
return err
|
|
|
|
}
|