mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-06 13:26:26 +00:00
Add rbac and annotation test cases
Signed-off-by: Ming <mqiu@vmware.com>
This commit is contained in:
1
changelogs/unreleased/4455-mqiu
Normal file
1
changelogs/unreleased/4455-mqiu
Normal file
@@ -0,0 +1 @@
|
||||
Add rbac and annotation test cases
|
||||
117
test/e2e/basic/resources-check/namespaces.go
Normal file
117
test/e2e/basic/resources-check/namespaces.go
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the Licensm.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apachm.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 Licensm.
|
||||
*/
|
||||
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
. "github.com/vmware-tanzu/velero/test/e2e"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/test"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/util/k8s"
|
||||
)
|
||||
|
||||
type MultiNSBackup struct {
|
||||
TestCase
|
||||
IsScalTest bool
|
||||
NSExcluded *[]string
|
||||
TimeoutDuration time.Duration
|
||||
}
|
||||
|
||||
func (m *MultiNSBackup) Init() error {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
UUIDgen, _ = uuid.NewRandom()
|
||||
m.BackupName = "backup-" + UUIDgen.String()
|
||||
m.RestoreName = "restore-" + UUIDgen.String()
|
||||
m.NSBaseName = "nstest-" + UUIDgen.String()
|
||||
m.Client = TestClientInstance
|
||||
m.NSExcluded = &[]string{}
|
||||
|
||||
// Currently it's hard to build a large list of namespaces to include and wildcards do not work so instead
|
||||
// we will exclude all of the namespaces that existed prior to the test from the backup
|
||||
namespaces, err := m.Client.ClientGo.CoreV1().Namespaces().List(context.Background(), v1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve namespaces")
|
||||
}
|
||||
|
||||
for _, excludeNamespace := range namespaces.Items {
|
||||
*m.NSExcluded = append(*m.NSExcluded, excludeNamespace.Name)
|
||||
}
|
||||
|
||||
if m.IsScalTest {
|
||||
m.NamespacesTotal = 2500
|
||||
m.TimeoutDuration = time.Hour * 2
|
||||
m.TestMsg = &TestMSG{
|
||||
Text: "When I create 2500 namespaces should be successfully backed up and restored",
|
||||
FailedMSG: "Failed to successfully backup and restore multiple namespaces",
|
||||
}
|
||||
} else {
|
||||
m.NamespacesTotal = 2
|
||||
m.TimeoutDuration = time.Minute * 5
|
||||
m.TestMsg = &TestMSG{
|
||||
Text: "When I create 2 namespaces should be successfully backed up and restored",
|
||||
FailedMSG: "Failed to successfully backup and restore multiple namespaces",
|
||||
}
|
||||
}
|
||||
|
||||
m.BackupArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "backup", m.BackupName,
|
||||
"--exclude-namespaces", strings.Join(*m.NSExcluded, ","),
|
||||
"--default-volumes-to-restic", "--wait",
|
||||
}
|
||||
|
||||
m.RestoreArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "restore", m.RestoreName,
|
||||
"--from-backup", m.BackupName, "--wait",
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MultiNSBackup) CreateResources() error {
|
||||
m.Ctx, _ = context.WithTimeout(context.Background(), m.TimeoutDuration)
|
||||
fmt.Printf("Creating namespaces ...\n")
|
||||
for nsNum := 0; nsNum < m.NamespacesTotal; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", m.NSBaseName, nsNum)
|
||||
if err := CreateNamespace(m.Ctx, m.Client, createNSName); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create namespace %s", createNSName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MultiNSBackup) Verify() error {
|
||||
// Verify that we got back all of the namespaces we created
|
||||
for nsNum := 0; nsNum < m.NamespacesTotal; nsNum++ {
|
||||
checkNSName := fmt.Sprintf("%s-%00000d", m.NSBaseName, nsNum)
|
||||
checkNS, err := GetNamespace(m.Ctx, m.Client, checkNSName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test namespace %s", checkNSName)
|
||||
}
|
||||
if checkNS.Name != checkNSName {
|
||||
return errors.Errorf("Retrieved namespace for %s has name %s instead", checkNSName, checkNS.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
101
test/e2e/basic/resources-check/namespaces_annotation.go
Normal file
101
test/e2e/basic/resources-check/namespaces_annotation.go
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
. "github.com/vmware-tanzu/velero/test/e2e"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/test"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/util/k8s"
|
||||
)
|
||||
|
||||
type NSAnnotationCase struct {
|
||||
TestCase
|
||||
}
|
||||
|
||||
func (n *NSAnnotationCase) Init() error {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
UUIDgen, _ = uuid.NewRandom()
|
||||
n.BackupName = "backup-namespace-annotations" + UUIDgen.String()
|
||||
n.RestoreName = "restore-namespace-annotations" + UUIDgen.String()
|
||||
n.NSBaseName = "namespace-annotations-" + UUIDgen.String()
|
||||
n.NamespacesTotal = 1
|
||||
n.NSIncluded = &[]string{}
|
||||
n.Client = TestClientInstance
|
||||
for nsNum := 0; nsNum < n.NamespacesTotal; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", n.NSBaseName, nsNum)
|
||||
*n.NSIncluded = append(*n.NSIncluded, createNSName)
|
||||
}
|
||||
n.TestMsg = &TestMSG{
|
||||
Desc: "Backup/restore namespace annotation test",
|
||||
Text: "Should be successfully backed up and restored including annotations",
|
||||
FailedMSG: "Failed to successfully backup and restore multiple namespaces",
|
||||
}
|
||||
n.BackupArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "backup", n.BackupName,
|
||||
"--include-namespaces", strings.Join(*n.NSIncluded, ","),
|
||||
"--default-volumes-to-restic", "--wait",
|
||||
}
|
||||
|
||||
n.RestoreArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "restore", n.RestoreName,
|
||||
"--from-backup", n.BackupName, "--wait",
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NSAnnotationCase) CreateResources() error {
|
||||
n.Ctx, _ = context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
for nsNum := 0; nsNum < n.NamespacesTotal; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", n.NSBaseName, nsNum)
|
||||
createAnnotationName := fmt.Sprintf("annotation-%s-%00000d", n.NSBaseName, nsNum)
|
||||
if err := CreateNamespaceWithAnnotation(n.Ctx, n.Client, createNSName, map[string]string{"testAnnotation": createAnnotationName}); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create namespace %s", createNSName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NSAnnotationCase) Verify() error {
|
||||
for nsNum := 0; nsNum < n.NamespacesTotal; nsNum++ {
|
||||
checkNSName := fmt.Sprintf("%s-%00000d", n.NSBaseName, nsNum)
|
||||
checkAnnoName := fmt.Sprintf("annotation-%s-%00000d", n.NSBaseName, nsNum)
|
||||
checkNS, err := GetNamespace(n.Ctx, n.Client, checkNSName)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test namespace %s", checkNSName)
|
||||
}
|
||||
if checkNS.Name != checkNSName {
|
||||
return errors.Errorf("Retrieved namespace for %s has name %s instead", checkNSName, checkNS.Name)
|
||||
}
|
||||
|
||||
c := checkNS.ObjectMeta.Annotations["testAnnotation"]
|
||||
|
||||
if c != checkAnnoName {
|
||||
return errors.Errorf("Retrieved annotation for %s has name %s instead", checkAnnoName, c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
188
test/e2e/basic/resources-check/rbac.go
Normal file
188
test/e2e/basic/resources-check/rbac.go
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the Licensm.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apachm.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 Licensm.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2021 the Velero contributors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package basic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
. "github.com/vmware-tanzu/velero/test/e2e"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/test"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/util/k8s"
|
||||
)
|
||||
|
||||
type RBACCase struct {
|
||||
TestCase
|
||||
}
|
||||
|
||||
func (r *RBACCase) Init() error {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
UUIDgen, _ = uuid.NewRandom()
|
||||
r.BackupName = "backup-rbac" + UUIDgen.String()
|
||||
r.RestoreName = "restore-rbac" + UUIDgen.String()
|
||||
r.NSBaseName = "rabc-" + UUIDgen.String()
|
||||
r.NamespacesTotal = 1
|
||||
r.NSIncluded = &[]string{}
|
||||
for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", r.NSBaseName, nsNum)
|
||||
*r.NSIncluded = append(*r.NSIncluded, createNSName)
|
||||
}
|
||||
r.TestMsg = &TestMSG{
|
||||
Desc: "Backup/restore of Namespaced Scoped and Cluster Scoped RBAC",
|
||||
Text: "should be successfully backed up and restored",
|
||||
FailedMSG: "Failed to successfully backup and restore RBAC",
|
||||
}
|
||||
r.BackupArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "backup", r.BackupName,
|
||||
"--include-namespaces", strings.Join(*r.NSIncluded, ","),
|
||||
"--default-volumes-to-restic", "--wait",
|
||||
}
|
||||
|
||||
r.RestoreArgs = []string{
|
||||
"create", "--namespace", VeleroCfg.VeleroNamespace, "restore", r.RestoreName,
|
||||
"--from-backup", r.BackupName, "--wait",
|
||||
}
|
||||
r.Client = TestClientInstance
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RBACCase) CreateResources() error {
|
||||
r.Ctx, _ = context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", r.NSBaseName, nsNum)
|
||||
fmt.Printf("Creating namespaces ...%s\n", createNSName)
|
||||
if err := CreateNamespace(r.Ctx, r.Client, createNSName); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create namespace %s", createNSName)
|
||||
}
|
||||
serviceAccountName := fmt.Sprintf("service-account-%s-%00000d", r.NSBaseName, nsNum)
|
||||
fmt.Printf("Creating service account ...%s\n", createNSName)
|
||||
if err := CreateServiceAccount(r.Ctx, r.Client, createNSName, serviceAccountName); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create service account %s", serviceAccountName)
|
||||
}
|
||||
clusterRoleName := fmt.Sprintf("clusterrole-%s-%00000d", r.NSBaseName, nsNum)
|
||||
clusterRoleBindingName := fmt.Sprintf("clusterrolebinding-%s-%00000d", r.NSBaseName, nsNum)
|
||||
if err := CreateRBACWithBindingSA(r.Ctx, r.Client, createNSName, serviceAccountName, clusterRoleName, clusterRoleBindingName); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create cluster role %s with role binding %s", clusterRoleName, clusterRoleBindingName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RBACCase) Verify() error {
|
||||
for nsNum := 0; nsNum < r.NamespacesTotal; nsNum++ {
|
||||
checkNSName := fmt.Sprintf("%s-%00000d", r.NSBaseName, nsNum)
|
||||
checkServiceAccountName := fmt.Sprintf("service-account-%s-%00000d", r.NSBaseName, nsNum)
|
||||
checkClusterRoleName := fmt.Sprintf("clusterrole-%s-%00000d", r.NSBaseName, nsNum)
|
||||
checkClusterRoleBindingName := fmt.Sprintf("clusterrolebinding-%s-%00000d", r.NSBaseName, nsNum)
|
||||
|
||||
checkNS, err := GetNamespace(r.Ctx, r.Client, checkNSName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test namespace %s", checkNSName)
|
||||
}
|
||||
if checkNS.Name != checkNSName {
|
||||
return errors.Errorf("Retrieved namespace for %s has name %s instead", checkNSName, checkNS.Name)
|
||||
}
|
||||
|
||||
//getting service account from the restore
|
||||
checkSA, err := GetServiceAccount(r.Ctx, r.Client, checkNSName, checkServiceAccountName)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test service account %s", checkSA)
|
||||
}
|
||||
|
||||
if checkSA.Name != checkServiceAccountName {
|
||||
return errors.Errorf("Retrieved service account for %s has name %s instead", checkServiceAccountName, checkSA.Name)
|
||||
}
|
||||
|
||||
//getting cluster role from the restore
|
||||
checkClusterRole, err := GetClusterRole(r.Ctx, r.Client, checkClusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test cluster role %s", checkClusterRole)
|
||||
}
|
||||
|
||||
if checkSA.Name != checkServiceAccountName {
|
||||
return errors.Errorf("Retrieved cluster role for %s has name %s instead", checkClusterRoleName, checkClusterRole.Name)
|
||||
}
|
||||
|
||||
//getting cluster role binding from the restore
|
||||
checkClusterRoleBinding, err := GetClusterRoleBinding(r.Ctx, r.Client, checkClusterRoleBindingName)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test cluster role binding %s", checkClusterRoleBinding)
|
||||
}
|
||||
|
||||
if checkClusterRoleBinding.Name != checkClusterRoleBindingName {
|
||||
return errors.Errorf("Retrieved cluster role binding for %s has name %s instead", checkClusterRoleBindingName, checkClusterRoleBinding.Name)
|
||||
}
|
||||
|
||||
//check if the role binding maps to service account
|
||||
checkSubjects := checkClusterRoleBinding.Subjects[0].Name
|
||||
|
||||
if checkSubjects != checkServiceAccountName {
|
||||
return errors.Errorf("Retrieved cluster role binding for %s has name %s instead", checkServiceAccountName, checkSubjects)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RBACCase) Destroy() error {
|
||||
//cleanup clusterrole
|
||||
err := CleanupClusterRole(r.Ctx, r.Client, r.NSBaseName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not cleanup clusterroles")
|
||||
}
|
||||
|
||||
//cleanup cluster rolebinding
|
||||
err = CleanupClusterRoleBinding(r.Ctx, r.Client, r.NSBaseName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not cleanup clusterrolebindings")
|
||||
}
|
||||
|
||||
err = CleanupNamespacesWithPoll(r.Ctx, r.Client, r.NSBaseName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could cleanup retrieve namespaces")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RBACCase) Clean() error {
|
||||
return r.Destroy()
|
||||
}
|
||||
45
test/e2e/basic/resources-check/resources_check.go
Normal file
45
test/e2e/basic/resources-check/resources_check.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the Licensm.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apachm.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 Licensm.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2021 the Velero contributors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package basic
|
||||
|
||||
import . "github.com/vmware-tanzu/velero/test/e2e/test"
|
||||
|
||||
func GetResourcesCheckTestCases() []VeleroBackupRestoreTest {
|
||||
return []VeleroBackupRestoreTest{
|
||||
&NSAnnotationCase{},
|
||||
&MultiNSBackup{IsScalTest: false},
|
||||
&RBACCase{},
|
||||
}
|
||||
}
|
||||
|
||||
var ResourcesCheckTest func() = TestFuncWithMultiIt(GetResourcesCheckTestCases())
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
. "github.com/vmware-tanzu/velero/test/e2e"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/backup"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/basic"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/basic/resources-check"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/resource-filtering"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/scale"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/upgrade"
|
||||
@@ -67,7 +68,7 @@ var _ = Describe("[Restic] Velero tests on cluster using the plugin provider for
|
||||
|
||||
var _ = Describe("[Snapshot] Velero tests on cluster using the plugin provider for object storage and snapshots for volume backups", BackupRestoreWithSnapshots)
|
||||
|
||||
var _ = Describe("[Basic] Backup/restore of 2 namespaces", BasicBackupRestore)
|
||||
var _ = Describe("[Basic] Backup/restore of cluster resources", ResourcesCheckTest)
|
||||
|
||||
var _ = Describe("[Scale] Backup/restore of 2500 namespaces", MultiNSBackupRestore)
|
||||
|
||||
|
||||
@@ -17,141 +17,8 @@ limitations under the License.
|
||||
package scale
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/util/k8s"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/util/velero"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
. "github.com/vmware-tanzu/velero/test/e2e"
|
||||
basic "github.com/vmware-tanzu/velero/test/e2e/basic/resources-check"
|
||||
. "github.com/vmware-tanzu/velero/test/e2e/test"
|
||||
)
|
||||
|
||||
func BasicBackupRestore() {
|
||||
|
||||
client, err := NewTestClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client for multiple namespace tests")
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
flag.Parse()
|
||||
UUIDgen, err = uuid.NewRandom()
|
||||
Expect(err).To(Succeed())
|
||||
if VeleroCfg.InstallVelero {
|
||||
Expect(VeleroInstall(context.Background(), &VeleroCfg, "", false)).To(Succeed())
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
if VeleroCfg.InstallVelero {
|
||||
err := VeleroUninstall(context.Background(), VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace)
|
||||
Expect(err).To(Succeed())
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
Context("When I create 2 namespaces", func() {
|
||||
It("should be successfully backed up and restored", func() {
|
||||
backupName := "backup-" + UUIDgen.String()
|
||||
restoreName := "restore-" + UUIDgen.String()
|
||||
fiveMinTimeout, _ := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
Expect(RunMultipleNamespaceTest(fiveMinTimeout, client, "nstest-"+UUIDgen.String(), 2,
|
||||
backupName, restoreName)).To(Succeed(), "Failed to successfully backup and restore multiple namespaces")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func MultiNSBackupRestore() {
|
||||
|
||||
client, err := NewTestClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client for multiple namespace tests")
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
flag.Parse()
|
||||
UUIDgen, err = uuid.NewRandom()
|
||||
Expect(err).To(Succeed())
|
||||
if VeleroCfg.InstallVelero {
|
||||
Expect(VeleroInstall(context.Background(), &VeleroCfg, "", false)).To(Succeed())
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
if VeleroCfg.InstallVelero {
|
||||
err := VeleroUninstall(context.Background(), VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace)
|
||||
Expect(err).To(Succeed())
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
Context("When I create 2500 namespaces", func() {
|
||||
It("should be successfully backed up and restored", func() {
|
||||
backupName := "backup-" + UUIDgen.String()
|
||||
restoreName := "restore-" + UUIDgen.String()
|
||||
twoHourTimeout, _ := context.WithTimeout(context.Background(), 2*time.Hour)
|
||||
Expect(RunMultipleNamespaceTest(twoHourTimeout, client, "nstest-"+UUIDgen.String(), 2500,
|
||||
backupName, restoreName)).To(Succeed(), "Failed to successfully backup and restore multiple namespaces")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func RunMultipleNamespaceTest(ctx context.Context, client TestClient, nsBaseName string, numberOfNamespaces int, backupName string, restoreName string) error {
|
||||
defer CleanupNamespaces(context.Background(), client, nsBaseName) // Run at exit for final cleanup
|
||||
var excludeNamespaces []string
|
||||
|
||||
// Currently it's hard to build a large list of namespaces to include and wildcards do not work so instead
|
||||
// we will exclude all of the namespaces that existed prior to the test from the backup
|
||||
namespaces, err := client.ClientGo.CoreV1().Namespaces().List(ctx, v1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve namespaces")
|
||||
}
|
||||
|
||||
for _, excludeNamespace := range namespaces.Items {
|
||||
excludeNamespaces = append(excludeNamespaces, excludeNamespace.Name)
|
||||
}
|
||||
|
||||
fmt.Printf("Creating namespaces ...\n")
|
||||
for nsNum := 0; nsNum < numberOfNamespaces; nsNum++ {
|
||||
createNSName := fmt.Sprintf("%s-%00000d", nsBaseName, nsNum)
|
||||
if err := CreateNamespace(ctx, client, createNSName); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create namespace %s", createNSName)
|
||||
}
|
||||
}
|
||||
if err := VeleroBackupExcludeNamespaces(ctx, VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace, backupName, excludeNamespaces); err != nil {
|
||||
RunDebug(context.Background(), VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace, backupName, "")
|
||||
return errors.Wrapf(err, "Failed to backup backup namespaces %s-*", nsBaseName)
|
||||
}
|
||||
|
||||
err = CleanupNamespaces(ctx, client, nsBaseName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could cleanup retrieve namespaces")
|
||||
}
|
||||
|
||||
err = VeleroRestore(ctx, VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace, restoreName, backupName)
|
||||
if err != nil {
|
||||
RunDebug(context.Background(), VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace, "", restoreName)
|
||||
return errors.Wrap(err, "Restore failed")
|
||||
}
|
||||
|
||||
// Verify that we got back all of the namespaces we created
|
||||
for nsNum := 0; nsNum < numberOfNamespaces; nsNum++ {
|
||||
checkNSName := fmt.Sprintf("%s-%00000d", nsBaseName, nsNum)
|
||||
checkNS, err := GetNamespace(ctx, client, checkNSName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not retrieve test namespace %s", checkNSName)
|
||||
}
|
||||
if checkNS.Name != checkNSName {
|
||||
return errors.Errorf("Retrieved namespace for %s has name %s instead", checkNSName, checkNS.Name)
|
||||
}
|
||||
}
|
||||
// Cleanup is automatic on the way out
|
||||
return nil
|
||||
}
|
||||
var MultiNSBackupRestore func() = TestFunc(&basic.MultiNSBackup{IsScalTest: true})
|
||||
|
||||
@@ -92,6 +92,43 @@ func TestFunc(test VeleroBackupRestoreTest) func() {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuncWithMultiIt(tests []VeleroBackupRestoreTest) func() {
|
||||
return func() {
|
||||
var err error
|
||||
var countIt int
|
||||
TestClientInstance, err = NewTestClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client for backup tests")
|
||||
for k := range tests {
|
||||
Expect(tests[k].Init()).To(Succeed(), fmt.Sprintf("Failed to instantiate test %s case", tests[k].GetTestMsg().Desc))
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
flag.Parse()
|
||||
if VeleroCfg.InstallVelero {
|
||||
if countIt == 0 {
|
||||
Expect(VeleroInstall(context.Background(), &VeleroCfg, "", false)).To(Succeed())
|
||||
}
|
||||
countIt++
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
if VeleroCfg.InstallVelero {
|
||||
if countIt == len(tests) {
|
||||
Expect(VeleroUninstall(context.Background(), VeleroCfg.VeleroCLI, VeleroCfg.VeleroNamespace)).To((Succeed()))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
for k := range tests {
|
||||
curTest := tests[k]
|
||||
It(curTest.GetTestMsg().Text, func() {
|
||||
Expect(RunTestCase(curTest)).To(Succeed(), curTest.GetTestMsg().FailedMSG)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestCase) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ func CreateNamespaceWithLabel(ctx context.Context, client TestClient, namespace
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateNamespaceWithAnnotation(ctx context.Context, client TestClient, namespace string, annotation map[string]string) error {
|
||||
ns := builder.ForNamespace(namespace).Result()
|
||||
ns.ObjectMeta.Annotations = annotation
|
||||
_, err := client.ClientGo.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetNamespace(ctx context.Context, client TestClient, namespace string) (*corev1api.Namespace, error) {
|
||||
return client.ClientGo.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
114
test/e2e/util/k8s/rbac.go
Normal file
114
test/e2e/util/k8s/rbac.go
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func CreateRBACWithBindingSA(ctx context.Context, client TestClient, namespace string, serviceaccount string, clusterrole string, clusterrolebinding string) error {
|
||||
role := &v1.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterrole,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = client.ClientGo.RbacV1().ClusterRoles().Create(ctx, role, metav1.CreateOptions{})
|
||||
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
//creating role binding and binding it to the test service account
|
||||
rolebinding := &v1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterrolebinding,
|
||||
},
|
||||
Subjects: []v1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: serviceaccount,
|
||||
Namespace: namespace,
|
||||
},
|
||||
},
|
||||
RoleRef: v1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
Name: clusterrole,
|
||||
},
|
||||
}
|
||||
|
||||
_, err = client.ClientGo.RbacV1().ClusterRoleBindings().Create(ctx, rolebinding, metav1.CreateOptions{})
|
||||
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetClusterRole(ctx context.Context, client TestClient, role string) (*v1.ClusterRole, error) {
|
||||
return client.ClientGo.RbacV1().ClusterRoles().Get(ctx, role, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func GetClusterRoleBinding(ctx context.Context, client TestClient, rolebinding string) (*v1.ClusterRoleBinding, error) {
|
||||
return client.ClientGo.RbacV1().ClusterRoleBindings().Get(ctx, rolebinding, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func CleanupClusterRole(ctx context.Context, client TestClient, nsBaseName string) error {
|
||||
|
||||
clusterroles, err := client.ClientGo.RbacV1().ClusterRoles().List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve clusterroles")
|
||||
}
|
||||
|
||||
for _, checkClusterRole := range clusterroles.Items {
|
||||
if strings.HasPrefix(checkClusterRole.Name, "clusterrole-"+nsBaseName) {
|
||||
fmt.Printf("Cleaning up clusterrole %s\n", checkClusterRole.Name)
|
||||
err = client.ClientGo.RbacV1().ClusterRoles().Delete(ctx, checkClusterRole.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not delete clusterrole %s", checkClusterRole.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CleanupClusterRoleBinding(ctx context.Context, client TestClient, nsBaseName string) error {
|
||||
|
||||
clusterrolebindings, err := client.ClientGo.RbacV1().ClusterRoleBindings().List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve clusterrolebindings")
|
||||
}
|
||||
|
||||
for _, checkClusterRoleBinding := range clusterrolebindings.Items {
|
||||
if strings.HasPrefix(checkClusterRoleBinding.Name, "clusterrolebinding-"+nsBaseName) {
|
||||
fmt.Printf("Cleaning up clusterrolebinding %s\n", checkClusterRoleBinding.Name)
|
||||
err = client.ClientGo.RbacV1().ClusterRoleBindings().Delete(ctx, checkClusterRoleBinding.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not delete clusterrolebinding %s", checkClusterRoleBinding.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -64,3 +64,23 @@ func PatchServiceAccountWithImagePullSecret(ctx context.Context, client TestClie
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateServiceAccount(ctx context.Context, client TestClient, namespace string, serviceaccount string) error {
|
||||
sa := &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: serviceaccount,
|
||||
},
|
||||
AutomountServiceAccountToken: nil,
|
||||
}
|
||||
|
||||
_, err = client.ClientGo.CoreV1().ServiceAccounts(namespace).Create(ctx, sa, metav1.CreateOptions{})
|
||||
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetServiceAccount(ctx context.Context, client TestClient, namespace string, serviceAccount string) (*corev1.ServiceAccount, error) {
|
||||
return client.ClientGo.CoreV1().ServiceAccounts(namespace).Get(ctx, serviceAccount, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user