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

Feature/e2e 575 (#1018)

* added api templates

* E2E test for generate roles, rolebindings, clusterrole and clusterrolebindings

* table driven e2e tests

* table driven e2e tests and go fmt

* removed unwanted vars

* increased sleep time

* removed role generation clone

* increated sleep time

* added rolebinding clone and retry mechanism for get resources

* modified test for clone

* added namespace to role

* added namespace variable

* added git actions job

* changed build name

* removed docker login

* added role verbs

* removed github actions job and rbac file

* added clusterrole test with clone

* fixed travis issue
This commit is contained in:
Mohan B E 2020-08-06 10:46:10 +05:30 committed by GitHub
parent 39de46fe39
commit 6e827f912f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 791 additions and 342 deletions

View file

@ -1,72 +0,0 @@
name: prereleaser
on:
push:
tags:
- '*'
jobs:
releaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Unshallow
run: git fetch --prune --unshallow
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.14
- uses: creekorful/goreportcard-action@v1.0
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
- name : binary build & kustomize
run: |
make kyverno
make initContainer
-
uses: docker/build-push-action@v1
name: kyverno docker build and publish
with:
username: ${{ secrets.DOCKERIO_USERNAME }}
password: ${{ secrets.DOCKERIO_PASSWORD }}
repository: "nirmata/kyverno"
tag_with_sha: true
push: true
path: cmd/kyverno/
dockerfile: cmd/kyverno/Dockerfile
-
uses: docker/build-push-action@v1
name: kyvernopre docker build and publish
with:
username: ${{ secrets.DOCKERIO_USERNAME }}
password: ${{ secrets.DOCKERIO_PASSWORD }}
repository: "nirmata/kyvernopre"
tag_with_sha: true
push: true
path: cmd/initContainer/
dockerfile: cmd/initContainer/Dockerfile
- uses: J12934/helm-gh-pages-action@master
name: Run Helm Publish
with:
access-token: ${{ secrets.ACCESS_TOKEN }}
deploy-branch: gh-pages
charts-folder: charts
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@v0.0.38

View file

@ -123,6 +123,12 @@ code-cov-report: $(CODE_COVERAGE_FILE_TXT)
go tool cover -html=coverage.txt
if [ -a $(CODE_COVERAGE_FILE_HTML) ]; then open $(CODE_COVERAGE_FILE_HTML); fi;
# Test E2E
test-e2e:
$(eval export E2E="ok")
go test ./test/e2e/... -v
$(eval export E2E="")
# godownloader create downloading script for kyverno-cli
godownloader:
godownloader .goreleaser.yml --repo nirmata/kyverno -o ./scripts/install-cli.sh --source="raw"

View file

@ -1,268 +0,0 @@
---
kind: Namespace
apiVersion: v1
metadata:
name: "kyverno"
---
apiVersion: v1
kind: Service
metadata:
namespace: kyverno
name: kyverno-svc
labels:
app: kyverno
spec:
ports:
- port: 443
targetPort: 443
selector:
app: kyverno
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kyverno-service-account
namespace: kyverno
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: kyverno:policyviolations
rules:
- apiGroups: ["kyverno.io"]
resources:
- policyviolations
verbs: ["get", "list", "watch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kyverno:webhook
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kyverno:webhook
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kyverno:userinfo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kyverno:userinfo
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kyverno:customresources
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kyverno:customresources
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kyverno:policycontroller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kyverno:policycontroller
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kyverno:generatecontroller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kyverno:generatecontroller
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:webhook
rules:
# Dynamic creation of webhooks, events & certs
- apiGroups:
- '*'
resources:
- events
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
- certificatesigningrequests
- certificatesigningrequests/approval
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
- certificatesigningrequests/approval
- certificatesigningrequests/status
resourceNames:
- kubernetes.io/legacy-unknown
verbs:
- create
- delete
- get
- update
- watch
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- kubernetes.io/legacy-unknown
verbs:
- approve
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:userinfo
rules:
# get the roleRef for incoming api-request user
- apiGroups:
- "*"
resources:
- roles
- clusterroles
- rolebindings
- clusterrolebindings
- configmaps
verbs:
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:customresources
rules:
# Kyverno CRs
- apiGroups:
- '*'
resources:
- clusterpolicies
- clusterpolicies/status
- clusterpolicyviolations
- clusterpolicyviolations/status
- policyviolations
- policyviolations/status
- generaterequests
- generaterequests/status
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:policycontroller
rules:
# background processing, identify all existing resources
- apiGroups:
- '*'
resources:
- '*'
verbs:
- get
- list
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kyverno:generatecontroller
rules:
# process generate rules to generate resources
- apiGroups:
- "*"
resources:
- namespaces
- networkpolicies
- secrets
- configmaps
- resourcequotas
- limitranges
- clusterroles
- rolebindings
- clusterrolebindings
verbs:
- create
- update
- delete
- get
# dynamic watches on trigger resources for generate rules
# re-evaluate the policy if the resource is updated
- apiGroups:
- '*'
resources:
- namespaces
verbs:
- watch
---
apiVersion: v1
kind: ConfigMap
metadata:
name: init-config
namespace: kyverno
data:
# resource types to be skipped by kyverno policy engine
resourceFilters: "[Event,*,*][*,kube-system,*][*,kube-public,*][*,kube-node-lease,*][Node,*,*][APIService,*,*][TokenReview,*,*][SubjectAccessReview,*,*][*,kyverno,*][Binding,*,*][ReplicaSet,*,*]"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: kyverno:view-policyviolations
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups: ["kyverno.io"]
resources:
- policyviolations
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: kyverno:view-clusterpolicyviolations
labels:
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rules:
- apiGroups: ["kyverno.io"]
resources:
- clusterpolicyviolations
verbs: ["get", "list", "watch"]

2
go.mod
View file

@ -20,6 +20,8 @@ require (
github.com/julienschmidt/httprouter v1.3.0
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/ory/go-acc v0.2.1 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/common v0.4.1

View file

@ -133,7 +133,7 @@ func validateArray(log logr.Logger, resourceArray, patternArray []interface{}, o
return path, err
}
}
}else{
} else {
return "", fmt.Errorf("Validate Array failed, array length mismatch, resource Array len is %d and pattern Array len is %d", len(resourceArray), len(patternArray))
}
}

View file

@ -128,7 +128,7 @@ func (o *Controller) ValidatePolicyMutation(policy v1.ClusterPolicy) error {
newPolicy := *policy.DeepCopy()
newPolicy.Spec.Rules = rules
resource, _ := o.generateEmptyResource(o.definitions[o.kindToDefinitionName[kind]]).(map[string]interface{})
if resource == nil || len(resource) == 0 {
if resource == nil || len(resource) == 0 {
log.Log.V(2).Info("unable to validate resource. OpenApi definition not found", "kind", kind)
return nil
}

117
test/e2e/generate/config.go Normal file
View file

@ -0,0 +1,117 @@
package generate
// E2E Test Config for Role and RoleBinding
// TODO:- Clone for Role and RoleBinding
var RoleTests = []struct {
//TestName - Name of the Test
TestName string
// RoleName - Name of the Role to be Created
RoleName string
// RoleBindingName - Name of the RoleBindingName
RoleBindingName string
// ResourceNamespace - Namespace for which Role and ReleBinding are Created
ResourceNamespace string
// Clone - Set Clone Value
Clone bool
// CloneSourceRoleData - Source Role Name from which Role is Cloned
CloneSourceRoleData []byte
// CloneSourceRoleBindingData - Source RoleBinding Name from which RoleBinding is Cloned
CloneSourceRoleBindingData []byte
// CloneNamespace - Namespace where Roles are Cloned
CloneNamespace string
// Sync - Set Synchronize
Sync bool
// Data - The Yaml file of the ClusterPolicy of the ROle and RoleBinding - ([]byte{})
Data []byte
}{
{
TestName: "test-role-rolebinding-without-clone",
RoleName: "ns-role",
RoleBindingName: "ns-role-binding",
ResourceNamespace: "test",
Clone: false,
Sync: false,
Data: roleRoleBindingYamlWithSync,
},
{
TestName: "test-role-rolebinding-withsync-without-clone",
RoleName: "ns-role",
RoleBindingName: "ns-role-binding",
ResourceNamespace: "test",
Clone: false,
Sync: true,
Data: roleRoleBindingYamlWithSync,
},
{
TestName: "test-role-rolebinding-with-clone",
RoleName: "ns-role",
RoleBindingName: "ns-role-binding",
ResourceNamespace: "test",
Clone: true,
CloneSourceRoleData: sourceRoleYaml,
CloneSourceRoleBindingData: sourceRoleBindingYaml,
CloneNamespace: "default",
Sync: false,
Data: roleRoleBindingYamlWithClone,
},
}
// E2E Test Config for ClusterRole and ClusterRoleBinding
var ClusterRoleTests = []struct {
//TestName - Name of the Test
TestName string
// ClusterRoleName - Name of the ClusterRole to be Created
ClusterRoleName string
// ClusterRoleBindingName - Name of the ClusterRoleBinding
ClusterRoleBindingName string
// ResourceNamespace - Namespace for which Resources are Created
ResourceNamespace string
// Clone - Set Clone Value
Clone bool
// CloneClusterRoleName
ClonerClusterRoleName string
// CloneClusterRoleBindingName
ClonerClusterRoleBindingName string
// CloneSourceRoleData - Source ClusterRole Name from which ClusterRole is Cloned
CloneSourceClusterRoleData []byte
// CloneSourceRoleBindingData - Source ClusterRoleBinding Name from which ClusterRoleBinding is Cloned
CloneSourceClusterRoleBindingData []byte
// CloneNamespace - Namespace where Roles are Cloned
CloneNamespace string
// Sync - Set Synchronize
Sync bool
// Data - The Yaml file of the ClusterPolicy of the ClusterRole and ClusterRoleBinding - ([]byte{})
Data []byte
}{
{
TestName: "test-clusterrole-clusterrolebinding-without-clone",
ClusterRoleName: "ns-cluster-role",
ClusterRoleBindingName: "ns-cluster-role-binding",
ResourceNamespace: "test",
Clone: false,
Sync: false,
Data: genClusterRoleYamlWithSync,
},
{
TestName: "test-clusterrole-clusterrolebinding-with-sync-without-clone",
ClusterRoleName: "ns-cluster-role",
ClusterRoleBindingName: "ns-cluster-role-binding",
ResourceNamespace: "test",
Clone: false,
Sync: true,
Data: genClusterRoleYamlWithSync,
},
{
TestName: "test-clusterrole-clusterrolebinding-with-sync-with-clone",
ClusterRoleName: "ns-cluster-role",
ClusterRoleBindingName: "ns-cluster-role-binding",
ResourceNamespace: "test",
Clone: true,
ClonerClusterRoleName: "base-cluster-role",
ClonerClusterRoleBindingName: "base-cluster-role-binding",
CloneSourceClusterRoleData: baseClusterRoleData,
CloneSourceClusterRoleBindingData: baseClusterRoleBindingData,
Sync: false,
Data: genClusterRoleYamlWithSync,
},
}

View file

@ -0,0 +1,294 @@
package generate
import (
"errors"
"fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"os"
"testing"
"time"
)
var (
// Cluster Polict GVR
clPolGVR = GetGVR("kyverno.io", "v1", "clusterpolicies")
// Namespace GVR
nsGVR = GetGVR("", "v1", "namespaces")
// ClusterRole GVR
crGVR = GetGVR("rbac.authorization.k8s.io", "v1", "clusterroles")
// ClusterRoleBinding GVR
crbGVR = GetGVR("rbac.authorization.k8s.io", "v1", "clusterrolebindings")
// Role GVR
rGVR = GetGVR("rbac.authorization.k8s.io", "v1", "roles")
// RoleBinding GVR
rbGVR = GetGVR("rbac.authorization.k8s.io", "v1", "rolebindings")
// ClusterPolicy Namespace
clPolNS = ""
// Namespace Name
// Hardcoded in YAML Definition
nspace = "test"
)
func Test_ClusterRole_ClusterRoleBinding_Sets(t *testing.T) {
RegisterTestingT(t)
if os.Getenv("E2E") == "" {
t.Skip("Skipping E2E Test")
}
// Generate E2E Client ==================
e2eClient, err := NewE2EClient()
Expect(err).To(BeNil())
// ======================================
// ====== Range Over ClusterRoleTests ==================
for _, tests := range ClusterRoleTests {
By(fmt.Sprintf("Test to generate ClusterRole and ClusterRoleBinding : %s", tests.TestName))
By(fmt.Sprintf("synchronize = %v\t clone = %v", tests.Sync, tests.Clone))
// ======= CleanUp Resources =====
By(fmt.Sprintf("Cleaning Cluster Policies"))
e2eClient.CleanClusterPolicies(clPolGVR)
// If Clone is true Clear Source Resource and Recreate
if tests.Clone {
By("Clone = true, Deleting Source ClusterRole and ClusterRoleBinding")
// Delete ClusterRole to be cloned
e2eClient.DeleteClusteredResource(crGVR, tests.ClonerClusterRoleName)
// Delete ClusterRoleBinding to be cloned
e2eClient.DeleteClusteredResource(crbGVR, tests.ClonerClusterRoleBindingName)
}
// ====================================
// Clear Namespace
By(fmt.Sprintf("Deleting Namespace : %s\n", tests.ResourceNamespace))
e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// Wait Till Deletion of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("Deleting Namespace")
})
// =====================================================
// ======== Create ClusterRole Policy =============
By(fmt.Sprintf("Creating Generate Role Policy in %s", clPolNS))
_, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, clPolNS, tests.Data)
Expect(err).NotTo(HaveOccurred())
// ============================================
// == If Clone is true Create Source Resources ======
if tests.Clone {
By(fmt.Sprintf("Clone = true, Creating Cloner Resources in Namespace : %s", tests.CloneNamespace))
// Create ClusterRole to be cloned
_, err := e2eClient.CreateClusteredResourceYaml(crGVR, tests.CloneSourceClusterRoleData)
Expect(err).NotTo(HaveOccurred())
// Create ClusterRoleBinding to be cloned
_, err = e2eClient.CreateClusteredResourceYaml(crbGVR, tests.CloneSourceClusterRoleBindingData)
Expect(err).NotTo(HaveOccurred())
}
// =================================================
// ======= Create Namespace ==================
By(fmt.Sprintf("Creating Namespace which triggers generate %s \n", clPolNS))
_, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceYaml)
Expect(err).NotTo(HaveOccurred())
// Wait Till Creation of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return err
}
return nil
})
// ===========================================
// ======== Verify ClusterRole Creation =====
By("Verifying ClusterRole")
// Wait Till Creation of ClusterRole
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(crGVR, tests.ClusterRoleName)
if err != nil {
return err
}
return nil
})
rRes, err := e2eClient.GetClusteredResource(crGVR, tests.ClusterRoleName)
Expect(err).NotTo(HaveOccurred())
Expect(rRes.GetName()).To(Equal(tests.ClusterRoleName))
// ============================================
// ======= Verify ClusterRoleBinding Creation ========
By("Verifying ClusterRoleBinding")
rbRes, err := e2eClient.GetClusteredResource(crbGVR, tests.ClusterRoleBindingName)
Expect(err).NotTo(HaveOccurred())
Expect(rbRes.GetName()).To(Equal(tests.ClusterRoleBindingName))
// ============================================
// If Sync=true, Verify that an Error will occour on deletion of created resources
if tests.Sync {
// Delete generated ClusterRoleBinding and It'll Fail
err = e2eClient.DeleteClusteredResource(crbGVR, tests.ClusterRoleBindingName)
Expect(err).To(HaveOccurred())
// Delete generated ClusterRole and It'll Fail
err = e2eClient.DeleteClusteredResource(crGVR, tests.ClusterRoleName)
Expect(err).To(HaveOccurred())
}
// ======= CleanUp Resources =====
e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// Wait Till Deletion of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("Deleting Namespace")
})
By(fmt.Sprintf("Test %s Completed \n\n\n", tests.TestName))
}
}
func Test_Role_RoleBinding_Sets(t *testing.T) {
RegisterTestingT(t)
if os.Getenv("E2E") == "" {
t.Skip("Skipping E2E Test")
}
// Generate E2E Client ==================
e2eClient, err := NewE2EClient()
Expect(err).To(BeNil())
// ======================================
// ====== Range Over RuleTest ==================
for _, tests := range RoleTests {
By(fmt.Sprintf("Test to generate Role and RoleBinding : %s", tests.TestName))
By(fmt.Sprintf("synchronize = %v\t clone = %v", tests.Sync, tests.Clone))
// ======= CleanUp Resources =====
By(fmt.Sprintf("Cleaning Cluster Policies"))
e2eClient.CleanClusterPolicies(clPolGVR)
// Clear Namespace
By(fmt.Sprintf("Deleting Namespace : %s", tests.ResourceNamespace))
e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// If Clone is true Clear Source Resource and Recreate
if tests.Clone {
By(fmt.Sprintf("Clone = true, Deleting Source Role and RoleBinding from Clone Namespace : %s", tests.CloneNamespace))
// Delete Role to be cloned
e2eClient.DeleteNamespacedResource(rGVR, tests.CloneNamespace, tests.RoleName)
// Delete RoleBinding to be cloned
e2eClient.DeleteNamespacedResource(rbGVR, tests.CloneNamespace, tests.RoleBindingName)
}
// Wait Till Deletion of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("Deleting Namespace")
})
// ====================================
// ======== Create Role Policy =============
By(fmt.Sprintf("\nCreating Generate Role Policy in %s", clPolNS))
_, err = e2eClient.CreateNamespacedResourceYaml(clPolGVR, clPolNS, tests.Data)
Expect(err).NotTo(HaveOccurred())
// ============================================
// === If Clone is true Create Source Resources ==
if tests.Clone {
By(fmt.Sprintf("Clone = true, Creating Cloner Resources in Namespace : %s", tests.CloneNamespace))
_, err := e2eClient.CreateNamespacedResourceYaml(rGVR, tests.CloneNamespace, tests.CloneSourceRoleData)
Expect(err).NotTo(HaveOccurred())
_, err = e2eClient.CreateNamespacedResourceYaml(rbGVR, tests.CloneNamespace, tests.CloneSourceRoleBindingData)
Expect(err).NotTo(HaveOccurred())
}
// ================================================
// ======= Create Namespace ==================
By(fmt.Sprintf("Creating Namespace which triggers generate %s", clPolNS))
_, err = e2eClient.CreateClusteredResourceYaml(nsGVR, namespaceYaml)
Expect(err).NotTo(HaveOccurred())
// Wait Till Creation of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return err
}
return nil
})
// ===========================================
// ======== Verify Role Creation =====
By(fmt.Sprintf("Verifying Role in the Namespace : %s", tests.ResourceNamespace))
// Wait Till Creation of Role
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetNamespacedResource(rGVR, tests.ResourceNamespace, tests.RoleName)
if err != nil {
return err
}
return nil
})
rRes, err := e2eClient.GetNamespacedResource(rGVR, tests.ResourceNamespace, tests.RoleName)
Expect(err).NotTo(HaveOccurred())
Expect(rRes.GetName()).To(Equal(tests.RoleName))
// ============================================
// ======= Verify RoleBinding Creation ========
By(fmt.Sprintf("Verifying RoleBinding in the Namespace : %s", tests.ResourceNamespace))
rbRes, err := e2eClient.GetNamespacedResource(rbGVR, tests.ResourceNamespace, tests.RoleBindingName)
Expect(err).NotTo(HaveOccurred())
Expect(rbRes.GetName()).To(Equal(tests.RoleBindingName))
// ============================================
// If Sync=true, Verify that an Error will occour on deletion of created resources
if tests.Sync {
// Delete generated RoleBinding and It'll Fail
By(fmt.Sprintf("Sync : Delete RoleBinding as Namespace %s", tests.ResourceNamespace))
err = e2eClient.DeleteNamespacedResource(rbGVR, tests.ResourceNamespace, tests.RoleBindingName)
Expect(err).To(HaveOccurred())
// Delete generated Role and It'll Fail
By(fmt.Sprintf("Sync : Delete Role as Namespace %s", tests.ResourceNamespace))
err = e2eClient.DeleteNamespacedResource(rGVR, tests.ResourceNamespace, tests.RoleName)
Expect(err).To(HaveOccurred())
}
// ======= CleanUp Resources =====
e2eClient.CleanClusterPolicies(clPolGVR)
// === If Clone is true Delete Source Resources ==
if tests.Clone {
By(fmt.Sprintf("Clone = true, Deleting Cloner Resources in Namespace : %s", tests.CloneNamespace))
e2eClient.DeleteNamespacedResource(rGVR, tests.CloneNamespace, tests.RoleName)
e2eClient.DeleteNamespacedResource(rbGVR, tests.CloneNamespace, tests.RoleBindingName)
}
// ================================================
// Clear Namespace
e2eClient.DeleteClusteredResource(nsGVR, tests.ResourceNamespace)
// Wait Till Deletion of Namespace
GetWithRetry(time.Duration(1), 15, func() error {
_, err := e2eClient.GetClusteredResource(nsGVR, tests.ResourceNamespace)
if err != nil {
return nil
}
return errors.New("Deleting Namespace")
})
// ====================================
By(fmt.Sprintf("Test %s Completed \n\n\n", tests.TestName))
}
}

View file

@ -0,0 +1,247 @@
package generate
// Namespace Description
var namespaceYaml = []byte(`
apiVersion: v1
kind: Namespace
metadata:
name: test
`)
// Cluster Policy to generate Role and RoleBinding with synchronize=true
var roleRoleBindingYamlWithSync = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "gen-role-policy"
spec:
background: false
rules:
- name: "gen-role"
match:
resources:
kinds:
- Namespace
generate:
kind: Role
name: "ns-role"
namespace: "{{request.object.metadata.name}}"
synchronize: true
data:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- name: "gen-role-binding"
match:
resources:
kinds:
- Namespace
generate:
kind: RoleBinding
name: "ns-role-binding"
namespace: "{{request.object.metadata.name}}"
synchronize: true
data:
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: minikube-user
roleRef:
kind: Role
name: ns-role
namespace: "{{request.object.metadata.name}}"
apiGroup: rbac.authorization.k8s.io
`)
// Cluster Policy to generate Role and RoleBinding with Clone
var roleRoleBindingYamlWithClone = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "gen-role-policy"
spec:
background: false
rules:
- name: "gen-role"
match:
resources:
kinds:
- Namespace
generate:
kind: Role
name: "ns-role"
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
kind: Role
name: "ns-role"
namespace: "default"
- name: "gen-role-binding"
match:
resources:
kinds:
- Namespace
generate:
kind: RoleBinding
name: "ns-role-binding"
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
kind: RoleBinding
name: "ns-role-binding"
namespace: default
`)
// Source Role from which ROle is Cloned by generate
var sourceRoleYaml = []byte(`
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: ns-role
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "watch", "list", "delete", "create"]
`)
// Source RoleBinding from which RoleBinding is Cloned by generate
var sourceRoleBindingYaml = []byte(`
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ns-role-binding
namespace: default
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: minikube-user
roleRef:
kind: Role
name: ns-role
apiGroup: rbac.authorization.k8s.io
`)
// ClusterPolicy to generate ClusterRole and ClusterRoleBinding with synchronize = true
var genClusterRoleYamlWithSync = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "gen-cluster-policy"
spec:
background: false
rules:
- name: "gen-cluster-role"
match:
resources:
kinds:
- Namespace
generate:
kind: ClusterRole
name: ns-cluster-role
synchronize: true
data:
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- name: "gen-cluster-role-binding"
match:
resources:
kinds:
- Namespace
generate:
kind: ClusterRoleBinding
name: ns-cluster-role-binding
synchronize: true
data:
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ns-cluster-role
subjects:
- kind: ServiceAccount
name: "kyverno-service-account"
namespace: "{{request.object.metadata.name}}"
`)
// ClusterPolicy to generate ClusterRole and ClusterRoleBinding with clone = true
var genClusterRoleYamlWithClone = []byte(`
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: "gen-cluster-policy"
spec:
background: false
rules:
- name: "gen-cluster-role"
match:
resources:
kinds:
- Namespace
generate:
kind: ClusterRole
name: ns-cluster-role
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
kind: ClusterRole
name: base-cluster-role
namespace: default
- name: "gen-cluster-role-binding"
match:
resources:
kinds:
- Namespace
generate:
kind: ClusterRoleBinding
name: ns-cluster-role-binding
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
kind: ClusterRole
name: base-cluster-role-binding
namespace: default
`)
var baseClusterRoleData = []byte(`
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: base-cluster-role
rules:
- apiGroups:
- "*"
resources:
- namespaces
- networkpolicies
- secrets
- configmaps
- resourcequotas
- limitranges
- roles
- clusterroles
- rolebindings
- clusterrolebindings
verbs:
- create # generate new resources
- get # check the contents of exiting resources
- update # update existing resource, if required configuration defined in policy is not present
- delete # clean-up, if the generate trigger resource is deleted
`)
var baseClusterRoleBindingData = []byte(`
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: base-cluster-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: base-cluster-role
subjects:
- kind: ServiceAccount
name: kyverno-service-account
namespace: kyverno
`)

123
test/e2e/generate/utils.go Normal file
View file

@ -0,0 +1,123 @@
package generate
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
"os"
"sigs.k8s.io/yaml"
"time"
)
type E2EClient struct {
Client dynamic.Interface
}
func NewE2EClient() (*E2EClient, error) {
kubeconfig := os.Getenv("KUBECONFIG")
if kubeconfig == "" {
kubeconfig = os.Getenv("HOME") + "/.kube/config"
}
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}
e2eClient := new(E2EClient)
dClient, err := dynamic.NewForConfig(config)
e2eClient.Client = dClient
return e2eClient, err
}
// GetGVR :- gets GroupVersionResource for dynamic client
func GetGVR(group, version, resource string) schema.GroupVersionResource {
return schema.GroupVersionResource{Group: group, Version: version, Resource: resource}
}
// CleanClusterPolicies ;- Deletes all the cluster policies
func (e2e *E2EClient) CleanClusterPolicies(gvr schema.GroupVersionResource) error {
namespace := ""
res, err := e2e.ListNamespacedResources(gvr, namespace)
if err != nil {
return err
}
for _, r := range res.Items {
err = e2e.DeleteNamespacedResource(gvr, namespace, r.GetName())
if err != nil {
return err
}
}
return nil
}
// GetNamespacedResource ...
func (e2e *E2EClient) GetNamespacedResource(gvr schema.GroupVersionResource, namespace, name string) (*unstructured.Unstructured, error) {
return e2e.Client.Resource(gvr).Namespace(namespace).Get(name, metav1.GetOptions{})
}
// GetClusterResource ...
func (e2e *E2EClient) GetClusteredResource(gvr schema.GroupVersionResource, name string) (*unstructured.Unstructured, error) {
return e2e.Client.Resource(gvr).Get(name, metav1.GetOptions{})
}
// GetWithRetry :- Retry Operation till the end of retry or until it is Passed, retryCount is the Wait duration after each retry,
func GetWithRetry(sleepInterval time.Duration, retryCount int, retryFunc func() error) error {
var err error
for i := 0; i < retryCount; i++ {
err = retryFunc()
if err != nil {
time.Sleep(sleepInterval * time.Second)
continue
}
}
return err
}
// DeleteNamespacedResource ...
func (e2e *E2EClient) DeleteNamespacedResource(gvr schema.GroupVersionResource, namespace, name string) error {
return e2e.Client.Resource(gvr).Namespace(namespace).Delete(name, &metav1.DeleteOptions{})
}
// DeleteClusterResource ...
func (e2e *E2EClient) DeleteClusteredResource(gvr schema.GroupVersionResource, name string) error {
return e2e.Client.Resource(gvr).Delete(name, &metav1.DeleteOptions{})
}
// CreateNamespacedResource ...
func (e2e *E2EClient) CreateNamespacedResource(gvr schema.GroupVersionResource, namespace string, resourceData *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return e2e.Client.Resource(gvr).Namespace(namespace).Create(resourceData, metav1.CreateOptions{})
}
// CreateClusteredResource ...
func (e2e *E2EClient) CreateClusteredResource(gvr schema.GroupVersionResource, resourceData *unstructured.Unstructured) (*unstructured.Unstructured, error) {
return e2e.Client.Resource(gvr).Create(resourceData, metav1.CreateOptions{})
}
// ListNamespacedResources ...
func (e2e *E2EClient) ListNamespacedResources(gvr schema.GroupVersionResource, namespace string) (*unstructured.UnstructuredList, error) {
return e2e.Client.Resource(gvr).Namespace(namespace).List(metav1.ListOptions{})
}
// CreateNamespacedResource creates namespaced resources like Pods, Services, Deployments etc
func (e2e *E2EClient) CreateNamespacedResourceYaml(gvr schema.GroupVersionResource, namespace string, resourceData []byte) (*unstructured.Unstructured, error) {
resource := unstructured.Unstructured{}
err := yaml.Unmarshal(resourceData, &resource)
// fmt.Println(resource)
if err != nil {
return nil, err
}
result, err := e2e.Client.Resource(gvr).Namespace(namespace).Create(&resource, metav1.CreateOptions{})
return result, err
}
// CreateClusteredResource creates cluster resources from YAML like Namespace, ClusterRole, ClusterRoleBinding etc ...
func (e2e *E2EClient) CreateClusteredResourceYaml(gvr schema.GroupVersionResource, resourceData []byte) (*unstructured.Unstructured, error) {
resource := unstructured.Unstructured{}
err := yaml.Unmarshal(resourceData, &resource)
if err != nil {
return nil, err
}
result, err := e2e.CreateClusteredResource(gvr, &resource)
return result, err
}