Skip to content

Commit

Permalink
Run conformance tests as project admin (#5596)
Browse files Browse the repository at this point in the history
* Create RBAC according to the test namespace

* most tests will use just the serviceAccount that has the same name as
the test namespace
* tests using ApiServerSource will user serviceAccount that is named as
follows: ${namespace}-eventwatcher

* Script for creating necessary RBAC for conformance tests

* Readme for running Conformance tests as project admin

* Fix imports

* Minor update for readme

* Fix goimport

* Do not fail if ServiceAccount already exists

* Fix goftm

* Mark tests requiring cluster-admin with specific build tag

* Move the creation of SA,Role,RoleBinding close to namespace creation

* since the name of the resources is aligned with the name of the
namespace it makes sense to create them only once, at the same time as
the namespace

* Formatting

* Move remaining creation of SA,Role,RoleBinding
  • Loading branch information
mgencur authored Aug 2, 2021
1 parent 486c349 commit a8a3063
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 102 deletions.
24 changes: 23 additions & 1 deletion test/conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Conformance tests verifies knative eventing implementation for expected behavior
described in
[specification](https://github.com/knative/eventing/tree/main/docs/spec).

## Running performance tests
## Running conformance tests

Run test with e2e tag and optionally select conformance test

Expand All @@ -31,3 +31,25 @@ can specify:
go test -v -tags e2e knative.dev/eventing/test/conformance -brokername=foo -brokernamespace=bar -run TestBrokerV1Beta1DataPlaneIngress

```

## Running conformance tests as a project admin

It is possible to run the conformance tests by a user with reduced privileges, e.g. project admin.
Some tests require cluster-admin privileges and those tests are excluded from execution in this case.
Running the conformance tests then consists of these steps:
1. The cluster admin creates test namespaces and required RBAC. Each test requires a separate namespace.
By default, the namespace names consist of `eventing-e2e` prefix and numeric suffix starting from 0:
`eventing-e2e0`, `eventing-e2e1`, etc. The prefix can be configured using the EVENTING_E2E_NAMESPACE env
variable. There's a helper script in the current folder that will create all the required resources:
```shell
NUM_NAMESPACES=40 ./create-namespace-rbac.sh
```
Note: The number of required namespaces might grow over time.
1. The project admin runs the test suite with specific flags:
```shell
go test -v -tags=e2e,project_admin -count=1 ./test/conformance \
-reusenamespace \
-kubeconfig=$PROJECT_ADMIN_KUBECONFIG
```
The $PROJECT_ADMIN_KUBECONFIG's user is expected to be a project admin for all the
created namespaces.
1 change: 1 addition & 0 deletions test/conformance/broker_tracing_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2019 The Knative Authors
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2020 The Knative Authors
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2020 The Knative Authors
Expand Down
1 change: 1 addition & 0 deletions test/conformance/channel_crd_metadata_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2020 The Knative Authors
Expand Down
1 change: 1 addition & 0 deletions test/conformance/channel_tracing_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2019 The Knative Authors
Expand Down
110 changes: 110 additions & 0 deletions test/conformance/create-namespace-rbac.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash

# Copyright 2021 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This script creates test namespaces together with ServiceAccounts, Roles,
# RoleBindings for conformance tests. This script is useful when tests are
# run with --reusenamespace option in restricted environments. See README.md
# for more information.

set -Eeuo pipefail

NUM_NAMESPACES=${NUM_NAMESPACES:?"Pass the NUM_NAMESPACES env variable"}
EVENTING_E2E_NAMESPACE="${EVENTING_E2E_NAMESPACE:-eventing-e2e}"

for i in $(seq 0 "$(("$NUM_NAMESPACES" - 1))"); do
cat <<EOF | sed "s/__NAME__/${EVENTING_E2E_NAMESPACE}${i}/" | kubectl apply -f -
---
apiVersion: v1
kind: Namespace
metadata:
name: __NAME__
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: __NAME__
namespace: __NAME__
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: __NAME__
namespace: __NAME__
rules:
- apiGroups:
- ""
resources:
- events
verbs:
- '*'
- apiGroups:
- ""
resources:
- pods
verbs:
- get
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: __NAME__
namespace: __NAME__
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: __NAME__
subjects:
- kind: ServiceAccount
name: __NAME__
namespace: __NAME__
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: __NAME__-eventwatcher
namespace: __NAME__
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: __NAME__-eventwatcher
namespace: __NAME__
rules:
- apiGroups:
- ""
resources:
- pods
- events
verbs:
- get
- list
- watch
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: __NAME__-eventwatcher
namespace: __NAME__
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: __NAME__-eventwatcher
subjects:
- kind: ServiceAccount
name: __NAME__-eventwatcher
namespace: __NAME__
EOF
done
4 changes: 1 addition & 3 deletions test/conformance/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ import (
)

const (
roleName = "event-watcher-r"
serviceAccountName = "event-watcher-sa"
recordEventsAPIPodName = "api-server-source-logger-pod"
recordEventsPingPodName = "ping-source-logger-pod"
)
Expand Down Expand Up @@ -89,7 +87,7 @@ func addSourcesInitializers() {
testlib.ApiServerSourceTypeMeta,
setupclientoptions.ApiServerSourceV1ClientSetupOption(
ctx, apiSrcName, "Reference",
recordEventsAPIPodName, roleName, serviceAccountName),
recordEventsAPIPodName),
)
sourcesTestRunner.AddComponentSetupClientOption(
testlib.PingSourceTypeMeta,
Expand Down
1 change: 1 addition & 0 deletions test/conformance/source_crd_metadata_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2020 The Knative Authors
Expand Down
1 change: 1 addition & 0 deletions test/conformance/source_crd_rbac_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2021 The Knative Authors
Expand Down
1 change: 1 addition & 0 deletions test/conformance/source_crd_registry_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build e2e
// +build !project_admin

/*
Copyright 2020 The Knative Authors
Expand Down
65 changes: 30 additions & 35 deletions test/lib/creation.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ func (c *Client) CreateServiceAccountOrFail(saName string) {
sa := resources.ServiceAccount(saName, namespace)
sas := c.Kube.CoreV1().ServiceAccounts(namespace)
c.T.Logf("Creating service account %+v", sa)
if _, err := sas.Create(context.Background(), sa, metav1.CreateOptions{}); err != nil {
if _, err := sas.Create(context.Background(), sa, metav1.CreateOptions{}); err != nil && !apierrs.IsAlreadyExists(err) {
c.T.Fatalf("Failed to create service account %q: %v", saName, err)
}
c.Tracker.Add(coreAPIGroup, coreAPIVersion, "serviceaccounts", namespace, saName)
Expand Down Expand Up @@ -552,8 +552,7 @@ func (c *Client) CreateRoleOrFail(r *rbacv1.Role) {
}

const (
ClusterRoleKind = "ClusterRole"
RoleKind = "Role"
RoleKind = "Role"
)

// CreateRoleBindingOrFail will create a RoleBinding or fail the test if there is an error.
Expand Down Expand Up @@ -582,38 +581,6 @@ func (c *Client) CreateClusterRoleBindingOrFail(saName, crName, crbName string)
c.Tracker.Add(rbacAPIGroup, rbacAPIVersion, "clusterrolebindings", "", crb.GetName())
}

const (
// the two ServiceAccounts are required for creating new Brokers in the current namespace
saIngressName = "eventing-broker-ingress"
saFilterName = "eventing-broker-filter"

// the ClusterRoles are preinstalled in Knative Eventing setup
crIngressName = "eventing-broker-ingress"
crFilterName = "eventing-broker-filter"
)

// CreateRBACResourcesForBrokers creates required RBAC resources for creating Brokers,
// see https://github.com/knative/docs/blob/main/docs/eventing/broker-trigger.md - Manual Setup.
func (c *Client) CreateRBACResourcesForBrokers() {
c.CreateServiceAccountOrFail(saIngressName)
c.CreateServiceAccountOrFail(saFilterName)
// The two RoleBindings are required for running Brokers correctly.
c.CreateRoleBindingOrFail(
saIngressName,
ClusterRoleKind,
crIngressName,
fmt.Sprintf("%s-%s", saIngressName, crIngressName),
c.Namespace,
)
c.CreateRoleBindingOrFail(
saFilterName,
ClusterRoleKind,
crFilterName,
fmt.Sprintf("%s-%s", saFilterName, crFilterName),
c.Namespace,
)
}

func (c *Client) applyAdditionalEnv(pod *corev1.PodSpec) {
for i := 0; i < len(pod.Containers); i++ {
pod.Containers[i].Env = append(pod.Containers[i].Env, c.tracingEnv)
Expand All @@ -622,3 +589,31 @@ func (c *Client) applyAdditionalEnv(pod *corev1.PodSpec) {
}
}
}

func CreateRBACPodsEventsGetListWatch(client *Client, name string) {
client.CreateServiceAccountOrFail(name)
client.CreateRoleOrFail(resources.Role(name,
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"pods", "events"},
Verbs: []string{"get", "list", "watch"}}),
))
client.CreateRoleBindingOrFail(name, RoleKind, name, name, client.Namespace)
}

func CreateRBACPodsGetEventsAll(client *Client, name string) {
client.CreateServiceAccountOrFail(name)
client.CreateRoleOrFail(resources.Role(name,
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{"get"},
}),
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"events"},
Verbs: []string{rbacv1.VerbAll},
}),
))
client.CreateRoleBindingOrFail(name, RoleKind, name, name, client.Namespace)
}
36 changes: 2 additions & 34 deletions test/lib/recordevents/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ import (
cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/uuid"
pkgtest "knative.dev/pkg/test"

testlib "knative.dev/eventing/test/lib"
"knative.dev/eventing/test/lib/resources"
)

type EventRecordOption = func(*corev1.Pod, *testlib.Client) error
Expand Down Expand Up @@ -136,28 +134,13 @@ func serializeHeaders(headers map[string]string) string {

// DeployEventRecordOrFail deploys the recordevents image with necessary sa, roles, rb to execute the image
func DeployEventRecordOrFail(ctx context.Context, client *testlib.Client, name string, options ...EventRecordOption) *corev1.Pod {
client.CreateServiceAccountOrFail(name)
client.CreateRoleOrFail(resources.Role(name,
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{"get"},
}),
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"events"},
Verbs: []string{rbacv1.VerbAll},
}),
))
client.CreateRoleBindingOrFail(name, "Role", name, name, client.Namespace)

options = append(
options,
testlib.WithService(name),
envOption("EVENT_GENERATORS", "receiver"),
)

eventRecordPod := recordEventsPod("recordevents", name, name)
eventRecordPod := recordEventsPod("recordevents", name, client.Namespace)
client.CreatePodOrFail(eventRecordPod, options...)
err := pkgtest.WaitForPodRunning(ctx, client.Kube, name, client.Namespace)
if err != nil {
Expand All @@ -169,28 +152,13 @@ func DeployEventRecordOrFail(ctx context.Context, client *testlib.Client, name s

// DeployEventSenderOrFail deploys the recordevents image with necessary sa, roles, rb to execute the image
func DeployEventSenderOrFail(ctx context.Context, client *testlib.Client, name string, sink string, options ...EventRecordOption) *corev1.Pod {
client.CreateServiceAccountOrFail(name)
client.CreateRoleOrFail(resources.Role(name,
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"pods"},
Verbs: []string{"get"},
}),
resources.WithRuleForRole(&rbacv1.PolicyRule{
APIGroups: []string{""},
Resources: []string{"events"},
Verbs: []string{rbacv1.VerbAll},
}),
))
client.CreateRoleBindingOrFail(name, "Role", name, name, client.Namespace)

options = append(
options,
envOption("EVENT_GENERATORS", "sender"),
envOption("SINK", sink),
)

eventRecordPod := recordEventsPod("recordevents", name, name)
eventRecordPod := recordEventsPod("recordevents", name, client.Namespace)
client.CreatePodOrFail(eventRecordPod, options...)
err := pkgtest.WaitForPodRunning(ctx, client.Kube, name, client.Namespace)
if err != nil {
Expand Down
Loading

0 comments on commit a8a3063

Please sign in to comment.