diff --git a/examples/cli/resources/ghost.yaml b/examples/cli/ghost.yaml similarity index 100% rename from examples/cli/resources/ghost.yaml rename to examples/cli/ghost.yaml diff --git a/examples/cli/resources/nginx.yaml b/examples/cli/nginx.yaml similarity index 100% rename from examples/cli/resources/nginx.yaml rename to examples/cli/nginx.yaml diff --git a/examples/cli/testScenarios.yaml b/examples/cli/testScenarios.yaml new file mode 100644 index 0000000000..158c4418bd --- /dev/null +++ b/examples/cli/testScenarios.yaml @@ -0,0 +1,21 @@ +# input +policy: policy-deployment +resource: nginx-deployment +initResources: +# expected +mutation: + mPatchedResource: nginx-deployment + reason: Success +validation: + reason: Success +--- +# input +policy: policy-deployment +resource: ghost +initResources: +# expected +mutation: + mPatchedResource: ghost + reason: Success +validation: + reason: Failed \ No newline at end of file diff --git a/examples/generate/configMap_default.yaml b/examples/generate/configMap_default.yaml new file mode 100644 index 0000000000..6fd8cbe74c --- /dev/null +++ b/examples/generate/configMap_default.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-template + namespace: default + labels: + originalLabel : isHere +data: + ui.properties : | + color.good=green + color.bad=red + + game.properties : | + enemies=predators + lives=3 + + configmap.data: | + ns=default + labels=originalLabel + labelscount=1 diff --git a/examples/generate/policy_basic.yaml b/examples/generate/policy_basic.yaml new file mode 100644 index 0000000000..79f92ef081 --- /dev/null +++ b/examples/generate/policy_basic.yaml @@ -0,0 +1,36 @@ +apiVersion : kyverno.io/v1alpha1 +kind : Policy +metadata : + name : basic-policy +spec : + rules: + - name: "Basic config generator for all namespaces" + resource: + kinds: + - Namespace + selector: + matchLabels: + LabelForSelector : "namespace2" + generate: + kind: ConfigMap + name: default-config + clone: + namespace: default + name: config-template + - name: "Basic config generator for all namespaces" + resource: + kinds: + - Namespace + selector: + matchLabels: + LabelForSelector : "namespace2" + generate: + kind: Secret + name: mongo-creds + data: + data: + DB_USER: YWJyYWthZGFicmE= + DB_PASSWORD: YXBwc3dvcmQ= + metadata: + labels: + purpose: mongo diff --git a/examples/generate/testScenarios.yaml b/examples/generate/testScenarios.yaml new file mode 100644 index 0000000000..7cd22052ed --- /dev/null +++ b/examples/generate/testScenarios.yaml @@ -0,0 +1,40 @@ +# input +policy: basic-policy +resource: ns2 +initResources: + - default/config-template +# expected +generation: + resource: + - name: default-config + namespace: ns2 + kind: ConfigMap + - name: mongo-creds + namespace: ns2 + kind: Secret +--- +# input +policy: zk-kafka-address +resource: ns2 +initResources: + - default/game-config +# expected +generation: + resource: + - name: copied-cm + namespace: ns2 + kind: ConfigMap + - name: zk-kafka-address + namespace: ns2 + kind: ConfigMap +--- +# input +policy: default +resource: ns2 +initResources: +# expected +generation: + resource: + - name: deny-all-traffic + namespace: ns2 + kind: NetworkPolicy \ No newline at end of file diff --git a/examples/mutate/overlay/nginx.yaml b/examples/mutate/overlay/nginx.yaml index 20d0713896..bdf22b13cb 100644 --- a/examples/mutate/overlay/nginx.yaml +++ b/examples/mutate/overlay/nginx.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment + creationTimestamp: labels: app: nginx spec: @@ -11,6 +12,7 @@ spec: app: nginx template: metadata: + creationTimestamp: labels: app: nginx spec: diff --git a/examples/mutate/overlay/testScenarios.yaml b/examples/mutate/overlay/testScenarios.yaml new file mode 100644 index 0000000000..e4012f24bb --- /dev/null +++ b/examples/mutate/overlay/testScenarios.yaml @@ -0,0 +1,10 @@ +# input +policy: set-image-pull-policy +resource: nginx-deployment +initResources: +# expected +mutation: + mPatchedResource: nginx-deployment + reason: Success +validation: + reason: Success \ No newline at end of file diff --git a/examples/mutate/patches/testScenarios.yaml b/examples/mutate/patches/testScenarios.yaml new file mode 100644 index 0000000000..df633e58df --- /dev/null +++ b/examples/mutate/patches/testScenarios.yaml @@ -0,0 +1,21 @@ +# input +policy: policy-endpoints +resource: test-endpoint +initResources: +# expected +mutation: + mPatchedResource: test-endpoint + reason: Success +validation: + reason: Success +--- +# input +policy: policy-endpoints +resource: test-endpoint +initResources: +# expected +mutation: + mPatchedResource: test-endpoint + reason: Success +validation: + reason: Success \ No newline at end of file diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 95223e0ffb..d6c067adbf 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -79,6 +79,7 @@ func (f *fixture) setupFixture() { if err != nil { f.t.Fatal(err) } + regresource := []schema.GroupVersionResource{ schema.GroupVersionResource{Group: "kyverno.io", Version: "v1alpha1", diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 0cdbf9f71e..0e1ba167c5 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -34,6 +34,7 @@ func newFixture(t *testing.T) *fixture { schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"}, schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}, } + 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"), @@ -51,6 +52,7 @@ func newFixture(t *testing.T) *fixture { // set discovery Client client.SetDiscovery(NewFakeDiscoveryClient(regResource)) + f := fixture{ t: t, objects: objects, diff --git a/pkg/testrunner/test.go b/pkg/testrunner/test.go new file mode 100644 index 0000000000..f475f2e579 --- /dev/null +++ b/pkg/testrunner/test.go @@ -0,0 +1,180 @@ +package testrunner + +import ( + "fmt" + "testing" + + ospath "path" + + "github.com/golang/glog" + pt "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" + client "github.com/nirmata/kyverno/pkg/dclient" + "github.com/nirmata/kyverno/pkg/engine" + "github.com/nirmata/kyverno/pkg/result" + kscheme "k8s.io/client-go/kubernetes/scheme" +) + +type test struct { + ap string + t *testing.T + testCase *testCase + // input + policy *pt.Policy + tResource *resourceInfo + loadResources []*resourceInfo + // expected + genResources []*resourceInfo + patchedResource *resourceInfo +} + +func (t *test) run() { + var client *client.Client + var err error + //mock client is used if generate is defined + if t.testCase.Expected.Generation != nil { + // create mock client & load resources + client, err = createClient(t.loadResources) + if err != nil { + t.t.Errorf("Unable to create client. err %s", err) + } + // TODO: handle generate + // assuming its namespaces creation + decode := kscheme.Codecs.UniversalDeserializer().Decode + obj, _, err := decode([]byte(t.tResource.rawResource), nil, nil) + _, err = client.CreateResource(getResourceFromKind(t.tResource.gvk.Kind), "", obj, false) + if err != nil { + t.t.Errorf("error while creating namespace %s", err) + } + + } + // apply the policy engine + pr, mResult, vResult, err := t.applyPolicy(t.policy, t.tResource, client) + if err != nil { + t.t.Error(err) + return + } + // Expected Result + t.checkMutationResult(pr, mResult) + t.checkValidationResult(vResult) + t.checkGenerationResult(client) +} + +func (t *test) checkMutationResult(pr *resourceInfo, result result.Result) { + if t.testCase.Expected.Mutation == nil { + glog.Info("No Mutation check defined") + return + } + // patched resource + if !compareResource(pr, t.patchedResource) { + fmt.Printf("Expected Resource %s \n", string(t.patchedResource.rawResource)) + fmt.Printf("Patched Resource %s \n", string(pr.rawResource)) + glog.Warningf("Expected resource %s ", string(pr.rawResource)) + t.t.Error("Patched resources not as expected") + } + // reason + reason := t.testCase.Expected.Mutation.Reason + if len(reason) > 0 && result.GetReason().String() != reason { + t.t.Error("Reason not matching") + } +} + +func (t *test) checkValidationResult(result result.Result) { + if t.testCase.Expected.Validation == nil { + glog.Info("No Validation check defined") + return + } + // reason + reason := t.testCase.Expected.Validation.Reason + if len(reason) > 0 && result.GetReason().String() != reason { + t.t.Error("Reason not matching") + } +} + +func (t *test) checkGenerationResult(client *client.Client) { + if t.testCase.Expected.Generation == nil { + glog.Info("No Generate check defined") + return + } + if client == nil { + glog.Info("client needs to be configured") + } + // check if the expected resources are generated + for _, r := range t.genResources { + n := ParseNameFromObject(r.rawResource) + ns := ParseNamespaceFromObject(r.rawResource) + _, err := client.GetResource(getResourceFromKind(r.gvk.Kind), ns, n) + if err != nil { + t.t.Errorf("Resource %s/%s of kinf %s not found", ns, n, r.gvk.Kind) + } + // compare if the resources are same + //TODO: comapre []bytes vs unstrcutured resource + } +} + +func (t *test) applyPolicy(policy *pt.Policy, + tresource *resourceInfo, + client *client.Client) (*resourceInfo, result.Result, result.Result, error) { + // apply policy on the trigger resource + // Mutate + var vResult result.Result + var patchedResource []byte + mPatches, mResult := engine.Mutate(*policy, tresource.rawResource, *tresource.gvk) + // TODO: only validate if there are no errors in mutate, why? + err := mResult.ToError() + if err == nil && len(mPatches) != 0 { + patchedResource, err = engine.ApplyPatches(tresource.rawResource, mPatches) + if err != nil { + return nil, nil, nil, err + } + // Validate + vResult = engine.Validate(*policy, patchedResource, *tresource.gvk) + } + // Generate + if client != nil { + engine.Generate(client, *policy, tresource.rawResource, *tresource.gvk) + } + // transform the patched Resource into resource Info + ri, err := extractResourceRaw(patchedResource) + if err != nil { + return nil, nil, nil, err + } + // return the results + return ri, mResult, vResult, nil +} + +func NewTest(ap string, t *testing.T, tc *testCase) (*test, error) { + //---INPUT--- + p, err := tc.loadPolicy(ospath.Join(ap, tc.Input.Policy)) + if err != nil { + return nil, err + } + r, err := tc.loadTriggerResource(ap) + if err != nil { + return nil, err + } + + lr, err := tc.loadPreloadedResources(ap) + if err != nil { + return nil, err + } + + //---EXPECTED--- + pr, err := tc.loadPatchedResource(ap) + if err != nil { + return nil, err + } + gr, err := tc.loadGeneratedResources(ap) + if err != nil { + return nil, err + } + return &test{ + ap: ap, + t: t, + testCase: tc, + policy: p, + tResource: r, + loadResources: lr, + genResources: gr, + patchedResource: pr, + }, nil +} diff --git a/pkg/testrunner/testcase.go b/pkg/testrunner/testcase.go new file mode 100644 index 0000000000..1bbdf70291 --- /dev/null +++ b/pkg/testrunner/testcase.go @@ -0,0 +1,178 @@ +package testrunner + +import ( + "bytes" + "encoding/json" + "fmt" + ospath "path" + + "github.com/golang/glog" + pt "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + yaml "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/kubernetes/scheme" +) + +//testCase defines the input and the expected result +// it stores the path to the files that are to be loaded +// for references +type testCase struct { + Input *tInput `yaml:"input"` + Expected *tExpected `yaml:"expected"` +} + +// load resources store the resources that are pre-requisite +// for the test case and are pre-loaded in the client before +/// test case in evaluated +type tInput struct { + Policy string `yaml:"policy"` + Resource string `yaml:"resource"` + LoadResources []string `yaml:"load_resources,omitempty"` +} + +type tExpected struct { + Mutation *tMutation `yaml:"mutation,omitempty"` + Validation *tValidation `yaml:"validation,omitempty"` + Generation *tGeneration `yaml:"generation,omitempty"` +} + +type tMutation struct { + Patched_Resource string `yaml:"patched_resource,omitempty"` + tResult +} + +type tValidation struct { + tResult +} + +type tGeneration struct { + Resources []string `yaml:"resources"` +} + +type tResult struct { + Reason string `yaml:"reason, omitempty"` +} + +func (tc *testCase) policyEngineTest() { + +} +func (tc *testCase) loadPreloadedResources(ap string) ([]*resourceInfo, error) { + return loadResources(ap, tc.Input.LoadResources...) + // return loadResources(ap, tc.Input.LoadResources...) +} + +func (tc *testCase) loadGeneratedResources(ap string) ([]*resourceInfo, error) { + if tc.Expected.Generation == nil { + return nil, nil + } + return loadResources(ap, tc.Expected.Generation.Resources...) +} + +func (tc *testCase) loadPatchedResource(ap string) (*resourceInfo, error) { + if tc.Expected.Mutation == nil { + return nil, nil + } + rs, err := loadResources(ap, tc.Expected.Mutation.Patched_Resource) + if err != nil { + return nil, err + } + if len(rs) != 1 { + glog.Warning("expects single resource mutation but multiple defined, will use first one") + } + return rs[0], nil + +} +func (tc *testCase) loadResources(files []string) ([]*resourceInfo, error) { + lr := []*resourceInfo{} + for _, r := range files { + rs, err := loadResources(r) + if err != nil { + // return as test case will be invalid if a resource cannot be loaded + return nil, err + } + lr = append(lr, rs...) + } + return lr, nil +} + +func (tc *testCase) loadTriggerResource(ap string) (*resourceInfo, error) { + rs, err := loadResources(ap, tc.Input.Resource) + if err != nil { + return nil, err + } + if len(rs) != 1 { + glog.Warning("expects single resource trigger but multiple defined, will use first one") + } + return rs[0], nil + +} + +// Loads a single policy +func (tc *testCase) loadPolicy(file string) (*pt.Policy, error) { + p := &pt.Policy{} + data, err := LoadFile(file) + if err != nil { + return nil, err + } + pBytes, err := yaml.ToJSON(data) + if err != nil { + return nil, err + } + if err := json.Unmarshal(pBytes, p); err != nil { + return nil, err + } + if p.TypeMeta.Kind != "Policy" { + return nil, fmt.Errorf("failed to parse policy") + } + return p, nil +} + +// loads multiple resources +func loadResources(ap string, args ...string) ([]*resourceInfo, error) { + ris := []*resourceInfo{} + for _, file := range args { + data, err := LoadFile(ospath.Join(ap, file)) + if err != nil { + return nil, err + } + dd := bytes.Split(data, []byte(defaultYamlSeparator)) + // resources seperated by yaml seperator + for _, d := range dd { + ri, err := extractResourceRaw(d) + if err != nil { + glog.Errorf("unable to load resource. err: %s ", err) + continue + } + ris = append(ris, ri) + } + } + return ris, nil +} + +func extractResourceRaw(d []byte) (*resourceInfo, error) { + // decode := scheme.Codecs.UniversalDeserializer().Decode + // obj, gvk, err := decode(d, nil, nil) + // if err != nil { + // return nil, err + // } + obj, gvk, err := extractResourceUnMarshalled(d) + // runtime.object to JSON + raw, err := json.Marshal(obj) + if err != nil { + return nil, err + } + return &resourceInfo{rawResource: raw, + gvk: gvk}, nil +} + +func extractResourceUnMarshalled(d []byte) (runtime.Object, *metav1.GroupVersionKind, error) { + decode := scheme.Codecs.UniversalDeserializer().Decode + obj, gvk, err := decode(d, nil, nil) + if err != nil { + return nil, nil, err + } + return obj, &metav1.GroupVersionKind{Group: gvk.Group, + Version: gvk.Version, + Kind: gvk.Kind}, nil +} diff --git a/pkg/testrunner/testrunner.go b/pkg/testrunner/testrunner.go new file mode 100644 index 0000000000..1c217d97b6 --- /dev/null +++ b/pkg/testrunner/testrunner.go @@ -0,0 +1,98 @@ +package testrunner + +import ( + "bytes" + "io/ioutil" + "path/filepath" + "testing" + + "os" + ospath "path" + + "github.com/golang/glog" + "gopkg.in/yaml.v2" +) + +func runner(t *testing.T, relpath string) { + gp := os.Getenv("GOPATH") + ap := ospath.Join(gp, projectPath) + // build load scenarios + path := ospath.Join(ap, relpath) + // Load the scenario files + scenarioFiles := getYAMLfiles(path) + for _, secenarioFile := range scenarioFiles { + sc := newScenario(t, ap, secenarioFile) + if err := sc.load(); err != nil { + t.Error(err) + return + } + // run test cases + sc.run() + } +} + +type scenario struct { + ap string + t *testing.T + path string + tcs []*testCase +} + +func newScenario(t *testing.T, ap string, path string) *scenario { + return &scenario{ + ap: ap, + t: t, + path: path, + } +} + +func getYAMLfiles(path string) (yamls []string) { + fileInfo, err := ioutil.ReadDir(path) + if err != nil { + return nil + } + for _, file := range fileInfo { + if filepath.Ext(file.Name()) == ".yml" || filepath.Ext(file.Name()) == ".yaml" { + yamls = append(yamls, ospath.Join(path, file.Name())) + } + } + return yamls +} +func (sc *scenario) load() error { + // read file + data, err := LoadFile(sc.path) + if err != nil { + return err + } + tcs := []*testCase{} + // load test cases seperated by '---' + // each test case defines an input & expected result + dd := bytes.Split(data, []byte(defaultYamlSeparator)) + for _, d := range dd { + tc := &testCase{} + err := yaml.Unmarshal([]byte(d), tc) + if err != nil { + glog.Warningf("Error while decoding YAML object, err: %s", err) + continue + } + tcs = append(tcs, tc) + } + sc.tcs = tcs + return nil +} + +func (sc *scenario) run() { + if len(sc.tcs) == 0 { + sc.t.Error("No test cases to load") + return + } + + for _, tc := range sc.tcs { + t, err := NewTest(sc.ap, sc.t, tc) + if err != nil { + sc.t.Error(err) + continue + } + t.run() + } +} diff --git a/pkg/testrunner/testrunner_test.go b/pkg/testrunner/testrunner_test.go new file mode 100644 index 0000000000..50d949effd --- /dev/null +++ b/pkg/testrunner/testrunner_test.go @@ -0,0 +1,7 @@ +package testrunner + +import "testing" + +func TestExamples(t *testing.T) { + runner(t, "/test/scenarios") +} diff --git a/pkg/testrunner/utils.go b/pkg/testrunner/utils.go new file mode 100644 index 0000000000..eadd4c3f42 --- /dev/null +++ b/pkg/testrunner/utils.go @@ -0,0 +1,123 @@ +package testrunner + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "os" + + "github.com/golang/glog" + client "github.com/nirmata/kyverno/pkg/dclient" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + kscheme "k8s.io/client-go/kubernetes/scheme" +) + +const ( + defaultYamlSeparator = "---" + projectPath = "src/github.com/nirmata/kyverno" +) + +// LoadFile loads file in byte buffer +func LoadFile(path string) ([]byte, error) { + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil, err + } + return ioutil.ReadFile(path) +} + +type resourceInfo struct { + rawResource []byte + gvk *metav1.GroupVersionKind +} + +func (ri resourceInfo) isSame(other resourceInfo) bool { + // compare gvk + if *ri.gvk != *other.gvk { + return false + } + // compare rawResource + return bytes.Equal(ri.rawResource, other.rawResource) +} + +// compare patched resources +func compareResource(er *resourceInfo, pr *resourceInfo) bool { + if !er.isSame(*pr) { + return false + } + return true +} + +func createClient(resources []*resourceInfo) (*client.Client, error) { + scheme := runtime.NewScheme() + objects := []runtime.Object{} + // registered group versions + regResources := []schema.GroupVersionResource{} + + for _, r := range resources { + // registered gvr + gv := schema.GroupVersion{Group: r.gvk.Group, Version: r.gvk.Version} + gvr := gv.WithResource(getResourceFromKind(r.gvk.Kind)) + regResources = append(regResources, gvr) + decode := kscheme.Codecs.UniversalDeserializer().Decode + obj, _, err := decode([]byte(r.rawResource), nil, nil) + rdata, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj) + if err != nil { + glog.Errorf("failed to load resource. err %s", err) + } + unstr := unstructured.Unstructured{Object: rdata} + objects = append(objects, &unstr) + } + // Mock Client + c, err := client.NewMockClient(scheme, objects...) + if err != nil { + return nil, err + } + c.SetDiscovery(client.NewFakeDiscoveryClient(regResources)) + + return c, nil +} + +var kindToResource = map[string]string{ + "ConfigMap": "configmaps", + "Endpoints": "endpoints", + "Namespace": "namespaces", + "Secret": "secrets", + "Deployment": "deployments", + "NetworkPolicy": "networkpolicies", +} + +func getResourceFromKind(kind string) string { + if resource, ok := kindToResource[kind]; ok { + return resource + } + return "" +} + +//ParseNameFromObject extracts resource name from JSON obj +func ParseNameFromObject(bytes []byte) string { + var objectJSON map[string]interface{} + json.Unmarshal(bytes, &objectJSON) + + meta := objectJSON["metadata"].(map[string]interface{}) + + if name, ok := meta["name"].(string); ok { + return name + } + return "" +} + +// ParseNamespaceFromObject extracts the namespace from the JSON obj +func ParseNamespaceFromObject(bytes []byte) string { + var objectJSON map[string]interface{} + json.Unmarshal(bytes, &objectJSON) + + meta := objectJSON["metadata"].(map[string]interface{}) + + if namespace, ok := meta["namespace"].(string); ok { + return namespace + } + return "" +} diff --git a/test/output/cm_copied_cm.yaml b/test/output/cm_copied_cm.yaml new file mode 100644 index 0000000000..e1ffd57b59 --- /dev/null +++ b/test/output/cm_copied_cm.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +data: + configmap.data: | + ns=default + labels=originalLabel + labelscount=1 + game.properties: | + enemies=predators + lives=3 + ui.properties: "color.good=green\ncolor.bad=red \n" +kind: ConfigMap +metadata: + labels: + originalLabel: isHere + name: copied-cm + namespace: ns2 \ No newline at end of file diff --git a/test/output/cm_default_config.yaml b/test/output/cm_default_config.yaml new file mode 100644 index 0000000000..08ef79a116 --- /dev/null +++ b/test/output/cm_default_config.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +data: + configmap.data: | + ns=default + labels=originalLabel + labelscount=1 + game.properties: | + enemies=predators + lives=3 + ui.properties: "color.good=green\ncolor.bad=red \n" +kind: ConfigMap +metadata: + labels: + originalLabel: isHere + name: default-config + namespace: ns2 \ No newline at end of file diff --git a/test/output/cm_zk-kafka-address.yaml b/test/output/cm_zk-kafka-address.yaml new file mode 100644 index 0000000000..18aaecaa3c --- /dev/null +++ b/test/output/cm_zk-kafka-address.yaml @@ -0,0 +1,8 @@ +data: + KAFKA_ADDRESS: 192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092 + ZK_ADDRESS: 192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181 +kind: ConfigMap +apiVersion: v1 +metadata: + name: zk-kafka-address + namespace: ns2 diff --git a/test/output/ghost.yaml b/test/output/ghost.yaml new file mode 100644 index 0000000000..751db9ec4c --- /dev/null +++ b/test/output/ghost.yaml @@ -0,0 +1,40 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: ghost + creationTimestamp: + labels: + app: nginx_is_mutated + cli: test + isMutated: 'true' + nirmata.io/application.name: ghost + nirmata.io/component: ghost + nirmata.io/deployment.name: ghost +spec: + replicas: 1 + selector: + matchLabels: + nirmata.io/application.name: ghost + nirmata.io/component: ghost + template: + metadata: + creationTimestamp: + labels: + nirmata.io/application.name: ghost + nirmata.io/component: ghost + nirmata.io/deployment.name: ghost + spec: + containers: + - name: ghost + image: nginx:latest + ports: + - containerPort: 8080 + protocol: TCP + resources: {} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 + revisionHistoryLimit: 5 +status: {} diff --git a/test/output/nginx.yaml b/test/output/nginx.yaml new file mode 100644 index 0000000000..9f4c121341 --- /dev/null +++ b/test/output/nginx.yaml @@ -0,0 +1,29 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: nginx-deployment + creationTimestamp: + labels: + app: nginx_is_mutated + cli: test + isMutated: 'true' +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + creationTimestamp: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + resources: {} + imagePullPolicy: Always + strategy: {} +status: {} diff --git a/test/output/np_deny-all-traffic.yaml b/test/output/np_deny-all-traffic.yaml new file mode 100644 index 0000000000..dfe3faab98 --- /dev/null +++ b/test/output/np_deny-all-traffic.yaml @@ -0,0 +1,13 @@ +metadata: + annotations: {} + labels: + policyname: default + name: deny-all-traffic + namespace: ns2 +podSelector: + matchExpressions: [] + matchLabels: {} +policyTypes: [] +spec: +kind: NetworkPolicy +apiVersion: extensions/v1beta1 \ No newline at end of file diff --git a/test/output/op_overlay_nginx.yaml b/test/output/op_overlay_nginx.yaml new file mode 100644 index 0000000000..d59519c5a7 --- /dev/null +++ b/test/output/op_overlay_nginx.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + creationTimestamp: + labels: + app: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + creationTimestamp: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:latest + ports: + - containerPort: 80 + resources: {} + imagePullPolicy: Always + - name: ghost + image: ghost:latest + resources: {} + imagePullPolicy: Always + strategy: {} +status: {} diff --git a/test/output/op_patches_endpoints.yaml b/test/output/op_patches_endpoints.yaml new file mode 100644 index 0000000000..c7ebca73a0 --- /dev/null +++ b/test/output/op_patches_endpoints.yaml @@ -0,0 +1,20 @@ +kind: Endpoints +apiVersion: v1 +metadata: + name: test-endpoint + creationTimestamp: + labels: + label: test +subsets: +- addresses: + - ip: 192.168.10.172 + ports: + - name: load-balancer-connection + port: 80 + protocol: UDP +- addresses: + - ip: 192.168.10.171 + ports: + - name: secure-connection + port: 9663 + protocol: TCP diff --git a/test/output/sc_mongo_cred.yaml b/test/output/sc_mongo_cred.yaml new file mode 100644 index 0000000000..cf004898a8 --- /dev/null +++ b/test/output/sc_mongo_cred.yaml @@ -0,0 +1,8 @@ +data: + DB_PASSWORD: YXBwc3dvcmQ= + DB_USER: YWJyYWthZGFicmE= +metadata: + name: mongo-creds + namespace: ns2 +kind: Secret +apiVersion: v1 \ No newline at end of file diff --git a/test/scenarios/cli.yaml b/test/scenarios/cli.yaml new file mode 100644 index 0000000000..1e9496b983 --- /dev/null +++ b/test/scenarios/cli.yaml @@ -0,0 +1,20 @@ +# file path relative to project root +input: + policy: examples/cli/policy_deployment.yaml + resource: examples/cli/nginx.yaml +expected: + mutation: + patched_resource: test/output/nginx.yaml + reason: Success + validation: + reason: Success +--- +input: + policy: examples/cli/policy_deployment.yaml + resource: examples/cli/ghost.yaml +expected: + mutation: + patched_resource: test/output/ghost.yaml + reason: Success + validation: + reason: Success \ No newline at end of file diff --git a/test/scenarios/generate.yaml b/test/scenarios/generate.yaml new file mode 100644 index 0000000000..b305067a04 --- /dev/null +++ b/test/scenarios/generate.yaml @@ -0,0 +1,30 @@ +# file path relative to project root +input: + policy: examples/generate/policy_basic.yaml + resource: examples/generate/namespace.yaml + load_resources: + - examples/generate/configMap_default.yaml +expected: + generation: + resources: + - test/output/cm_default_config.yaml + - test/output/sc_mongo_cred.yaml +--- +input: + policy: examples/generate/policy_generate.yaml + resource: examples/generate/namespace.yaml + load_resources: + - examples/generate/configMap.yaml +expected: + generation: + resources: + - test/output/cm_copied_cm.yaml + - test/output/cm_zk-kafka-address.yaml +--- +input: + policy: examples/generate/policy_networkPolicy.yaml + resource: examples/generate/namespace.yaml +expected: + generation: + resources: + - test/output/np_deny-all-traffic.yaml \ No newline at end of file diff --git a/test/scenarios/mutate/overlay.yaml b/test/scenarios/mutate/overlay.yaml new file mode 100644 index 0000000000..a2db4326c5 --- /dev/null +++ b/test/scenarios/mutate/overlay.yaml @@ -0,0 +1,8 @@ +# file path relative to project root +input: + policy: examples/mutate/overlay/policy_imagePullPolicy.yaml + resource: examples/mutate/overlay/nginx.yaml +expected: + mutation: + patched_resource: test/output/op_overlay_nginx.yaml + reason: Success \ No newline at end of file diff --git a/test/scenarios/mutate/patches.yaml b/test/scenarios/mutate/patches.yaml new file mode 100644 index 0000000000..70de56af2f --- /dev/null +++ b/test/scenarios/mutate/patches.yaml @@ -0,0 +1,8 @@ +# file path relative to project root +input: + policy: examples/mutate/patches/policy_endpoints.yaml + resource: examples/mutate/patches/endpoints.yaml +expected: + mutation: + patched_resource: test/output/op_patches_endpoints.yaml + reason: Success \ No newline at end of file