1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

initial client & controller test

This commit is contained in:
shivdudhani 2019-06-11 14:35:26 -07:00
parent 4ce925ccf0
commit a8d3dd79ee
5 changed files with 352 additions and 28 deletions

View file

@ -1 +1,105 @@
package controller
import (
"testing"
"github.com/golang/glog"
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/sharedinformer"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/sample-controller/pkg/signals"
)
func TestCreatePolicy(t *testing.T) {
f := newFixture(t)
// new policy is added to policy lister and explictly passed to sync-handler
// to process the existing
policy := newPolicy("test-policy")
f.policyLister = append(f.policyLister, policy)
f.objects = append(f.objects, policy)
// run controller
f.runControler("test-policy")
}
func (f *fixture) runControler(policyName string) {
policyInformerFactory, err := sharedinformer.NewFakeSharedInformerFactory()
if err != nil {
f.t.Fatal(err)
}
// new controller
policyController := NewPolicyController(
f.Client,
policyInformerFactory,
nil,
nil)
stopCh := signals.SetupSignalHandler()
// start informer & controller
policyInformerFactory.Run(stopCh)
if err = policyController.Run(stopCh); err != nil {
glog.Fatalf("Error running PolicyController: %v\n", err)
}
// add policy to the informer
for _, p := range f.policyLister {
policyInformerFactory.GetInfomer().GetIndexer().Add(p)
}
// sync handler
// reads the policy from the policy lister and processes them
err = policyController.syncHandler(policyName)
if err != nil {
f.t.Fatal(err)
}
policyController.Stop()
}
type fixture struct {
t *testing.T
Client *client.Client
policyLister []*types.Policy
objects []runtime.Object
}
func newFixture(t *testing.T) *fixture {
f := &fixture{}
f.t = t
return f
}
// create mock client with initial resouces
// set registered resources for gvr
func (f *fixture) setupFixture() {
scheme := runtime.NewScheme()
fclient, err := client.NewMockClient(scheme, f.objects...)
if err != nil {
f.t.Fatal(err)
}
regresource := map[string]string{"kyverno.io/v1alpha1": "policys"}
fclient.SetDiscovery(client.NewFakeDiscoveryClient(regresource))
}
func newPolicy(name string) *types.Policy {
return &types.Policy{
TypeMeta: metav1.TypeMeta{APIVersion: types.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
}
func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": apiVersion,
"kind": kind,
"metadata": map[string]interface{}{
"namespace": namespace,
"name": name,
},
},
}
}

View file

@ -27,15 +27,16 @@ import (
//Client enables interaction with k8 resource
type Client struct {
client dynamic.Interface
cachedClient discovery.CachedDiscoveryInterface
clientConfig *rest.Config
kclient *kubernetes.Clientset
client dynamic.Interface
cachedClient discovery.CachedDiscoveryInterface
clientConfig *rest.Config
kclient kubernetes.Interface
discoveryClient IDiscovery
}
//NewClient creates new instance of client
func NewClient(config *rest.Config) (*Client, error) {
client, err := dynamic.NewForConfig(config)
dclient, err := dynamic.NewForConfig(config)
if err != nil {
return nil, err
}
@ -44,13 +45,15 @@ func NewClient(config *rest.Config) (*Client, error) {
if err != nil {
return nil, err
}
return &Client{
client: client,
client := Client{
client: dclient,
clientConfig: config,
kclient: kclient,
cachedClient: memory.NewMemCacheClient(kclient.Discovery()),
}, nil
}
// Set discovery client
discoveryClient := ServerPreferredResources{memory.NewMemCacheClient(kclient.Discovery())}
client.SetDiscovery(discoveryClient)
return &client, nil
}
//GetKubePolicyDeployment returns kube policy depoyment value
@ -100,7 +103,7 @@ func (c *Client) getGroupVersionMapper(resource string) schema.GroupVersionResou
//TODO: add checks to see if the resource is supported
//TODO: build the resource list dynamically( by querying the registered resources)
//TODO: the error scenarios
return c.getGVR(resource)
return c.discoveryClient.getGVR(resource)
}
// GetResource returns the resource in unstructured/json format
@ -156,24 +159,10 @@ func convertToUnstructured(obj interface{}) *unstructured.Unstructured {
return &unstructured.Unstructured{Object: unstructuredObj}
}
//ConvertToRuntimeObject converts unstructed to runtime.Object runtime instance
func ConvertToRuntimeObject(obj *unstructured.Unstructured) (*runtime.Object, error) {
scheme := runtime.NewScheme()
gvk := obj.GroupVersionKind()
runtimeObj, err := scheme.New(gvk)
if err != nil {
return nil, err
}
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &runtimeObj); err != nil {
return nil, err
}
return &runtimeObj, nil
}
// GenerateResource creates resource of the specified kind(supports 'clone' & 'data')
func (c *Client) GenerateResource(generator types.Generation, namespace string) error {
var err error
rGVR := c.getGVRFromKind(generator.Kind)
rGVR := c.discoveryClient.getGVRFromKind(generator.Kind)
resource := &unstructured.Unstructured{}
var rdata map[string]interface{}
@ -244,7 +233,20 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error {
return lastError
}
func (c *Client) getGVR(resource string) schema.GroupVersionResource {
type IDiscovery interface {
getGVR(resource string) schema.GroupVersionResource
getGVRFromKind(kind string) schema.GroupVersionResource
}
func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
c.discoveryClient = discoveryClient
}
type ServerPreferredResources struct {
cachedClient discovery.CachedDiscoveryInterface
}
func (c ServerPreferredResources) getGVR(resource string) schema.GroupVersionResource {
emptyGVR := schema.GroupVersionResource{}
serverresources, err := c.cachedClient.ServerPreferredResources()
if err != nil {
@ -268,7 +270,7 @@ func (c *Client) getGVR(resource string) schema.GroupVersionResource {
//To-do: measure performance
//To-do: evaluate DefaultRESTMapper to fetch kind->resource mapping
func (c *Client) getGVRFromKind(kind string) schema.GroupVersionResource {
func (c ServerPreferredResources) getGVRFromKind(kind string) schema.GroupVersionResource {
emptyGVR := schema.GroupVersionResource{}
serverresources, err := c.cachedClient.ServerPreferredResources()
if err != nil {

View file

@ -1,6 +1,160 @@
package client
import (
"fmt"
"testing"
policytypes "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)
// GetResource
// ListResource
// CreateResource
// getGroupVersionMapper (valid and invalid resources)
//NewMockClient creates a mock client
// - dynamic client
// - kubernetes client
// - objects to initialize the client
func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": apiVersion,
"kind": kind,
"metadata": map[string]interface{}{
"namespace": namespace,
"name": name,
},
},
}
}
func newUnstructuredWithSpec(apiVersion, kind, namespace, name string, spec map[string]interface{}) *unstructured.Unstructured {
u := newUnstructured(apiVersion, kind, namespace, name)
u.Object["spec"] = spec
return u
}
func TestClient(t *testing.T) {
scheme := runtime.NewScheme()
// init groupversion
regresource := map[string]string{"group/version": "thekinds",
"group2/version": "thekinds",
"v1": "namespaces",
"apps/v1": "deployments"}
// init resources
objects := []runtime.Object{newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"),
newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"),
newUnstructured("apps/v1", "Deployment", "kyverno", "kyverno-deployment"),
}
// Mock Client
client, err := NewMockClient(scheme, objects...)
if err != nil {
t.Fatal(err)
}
// set discovery Client
client.SetDiscovery(NewFakeDiscoveryClient(regresource))
// Get Resource
res, err := client.GetResource("thekinds", "ns-foo", "name-foo")
if err != nil {
t.Fatal(err)
}
fmt.Println(res)
// List Resources
list, err := client.ListResource("thekinds", "ns-foo")
if err != nil {
t.Fatal(err)
}
fmt.Println(len(list.Items))
// DeleteResouce
err = client.DeleteResouce("thekinds", "ns-foo", "name-bar")
if err != nil {
t.Fatal(err)
}
// CreateResource
res, err = client.CreateResource("thekinds", "ns-foo", newUnstructured("group/version", "TheKind", "ns-foo", "name-foo1"))
if err != nil {
t.Fatal(err)
}
// UpdateResource
res, err = client.UpdateResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "bar"}))
if err != nil {
t.Fatal(err)
}
// UpdateStatusResource
res, err = client.UpdateStatusResource("thekinds", "ns-foo", newUnstructuredWithSpec("group/version", "TheKind", "ns-foo", "name-foo1", map[string]interface{}{"foo": "status"}))
if err != nil {
t.Fatal(err)
}
iEvent, err := client.GetEventsInterface()
if err != nil {
t.Fatal(err)
}
eventList, err := iEvent.List(meta.ListOptions{})
if err != nil {
t.Fatal(err)
}
fmt.Println(eventList.Items)
iCSR, err := client.GetCSRInterface()
if err != nil {
t.Fatal(err)
}
csrList, err := iCSR.List(meta.ListOptions{})
if err != nil {
t.Fatal(err)
}
fmt.Println(csrList.Items)
//GenerateResource -> copy From
// 1 create namespace
// 2 generate resource
// create namespace
ns, err := client.CreateResource("namespaces", "", newUnstructured("v1", "Namespace", "", "ns1"))
if err != nil {
t.Fatal(err)
}
gen := policytypes.Generation{Kind: "TheKind",
Name: "gen-kind",
Clone: &policytypes.CloneFrom{Namespace: "ns-foo", Name: "name-foo"}}
err = client.GenerateResource(gen, ns.GetName())
if err != nil {
t.Fatal(err)
}
res, err = client.GetResource("thekinds", "ns1", "gen-kind")
if err != nil {
t.Fatal(err)
}
// GenerateResource -> data
gen = policytypes.Generation{Kind: "TheKind",
Name: "name2-baz-new",
Data: newUnstructured("group2/version", "TheKind", "ns1", "name2-baz-new")}
err = client.GenerateResource(gen, ns.GetName())
if err != nil {
t.Fatal(err)
}
res, err = client.GetResource("thekinds", "ns1", "name2-baz-new")
if err != nil {
t.Fatal(err)
}
// Get Kube Policy Deployment
deploy, err := client.GetKubePolicyDeployment()
if err != nil {
t.Fatal(err)
}
fmt.Println(deploy.GetName())
}

View file

@ -1,7 +1,13 @@
package client
import (
"strings"
"time"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic/fake"
kubernetesfake "k8s.io/client-go/kubernetes/fake"
)
const (
@ -16,3 +22,46 @@ const (
)
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second
const namespaceCreationWaitInterval time.Duration = 100 * time.Millisecond
//---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
kclient := kubernetesfake.NewSimpleClientset(objects...)
return &Client{
client: client,
kclient: kclient,
}, nil
}
// NewFakeDiscoveryClient returns a fakediscovery client
func NewFakeDiscoveryClient(regResources map[string]string) *fakeDiscoveryClient {
registeredResources := make([]schema.GroupVersionResource, len(regResources))
for groupVersion, resource := range regResources {
gv, err := schema.ParseGroupVersion(groupVersion)
if err != nil {
continue
}
registeredResources = append(registeredResources, gv.WithResource(resource))
}
return &fakeDiscoveryClient{registeredResouces: registeredResources}
}
type fakeDiscoveryClient struct {
registeredResouces []schema.GroupVersionResource
}
func (c *fakeDiscoveryClient) getGVR(resource string) schema.GroupVersionResource {
for _, gvr := range c.registeredResouces {
if gvr.Resource == resource {
return gvr
}
}
return schema.GroupVersionResource{}
}
func (c *fakeDiscoveryClient) getGVRFromKind(kind string) schema.GroupVersionResource {
resource := strings.ToLower(kind) + "s"
return c.getGVR(resource)
}

View file

@ -0,0 +1,15 @@
package sharedinformer
import (
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/fake"
informers "github.com/nirmata/kyverno/pkg/client/informers/externalversions"
"k8s.io/apimachinery/pkg/runtime"
)
func NewFakeSharedInformerFactory(objects ...runtime.Object) (SharedInfomer, error) {
fakePolicyClient := fake.NewSimpleClientset(objects...)
policyInformerFactory := informers.NewSharedInformerFactory(fakePolicyClient, 0)
return &sharedInfomer{
policyInformerFactory: policyInformerFactory,
}, nil
}