github.com/interconnectedcloud/qdr-operator@v0.0.0-20210826174505-576d2b33dac7/test/e2e/framework/namespace.go (about) 1 // Copyright 2017 The Interconnectedcloud Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package framework 16 17 import ( 18 "fmt" 19 "strings" 20 "sync" 21 "time" 22 23 e2elog "github.com/interconnectedcloud/qdr-operator/test/e2e/framework/log" 24 corev1 "k8s.io/api/core/v1" 25 apierrors "k8s.io/apimachinery/pkg/api/errors" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/util/wait" 28 clientset "k8s.io/client-go/kubernetes" 29 30 "github.com/onsi/ginkgo" 31 "github.com/onsi/gomega" 32 ) 33 34 const ( 35 // namespaceNamePrefix is the prefix used when creating namespaces with a random name. 36 namespaceNamePrefix = "qdr-operator-e2e-" 37 NamespaceCleanupTimeout = 2 * time.Minute 38 ) 39 40 func createTestNamespace(client clientset.Interface, name string, labels map[string]string) *corev1.Namespace { 41 ginkgo.By(fmt.Sprintf("Creating a namespace %s to execute the test in", name)) 42 namespace := createNamespace(client, name, labels) 43 return namespace 44 } 45 46 func createNamespace(client clientset.Interface, name string, labels map[string]string) *corev1.Namespace { 47 namespaceObj := &corev1.Namespace{ 48 ObjectMeta: metav1.ObjectMeta{ 49 Name: name, 50 Labels: labels, 51 }, 52 } 53 54 namespace, err := client.CoreV1().Namespaces().Create(namespaceObj) 55 gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Error creating namespace %v", namespaceObj) 56 return namespace 57 } 58 59 // CreateNamespace creates a namespace for e2e testing. 60 func (f *Framework) CreateNamespace(clientSet *clientset.Clientset, 61 baseName string, labels map[string]string) *corev1.Namespace { 62 63 ns := createTestNamespace(clientSet, baseName, labels) 64 f.AddNamespacesToDelete(ns) 65 return ns 66 } 67 68 func (f *Framework) AddNamespacesToDelete(namespaces ...*corev1.Namespace) { 69 for _, ns := range namespaces { 70 if ns == nil { 71 continue 72 } 73 f.namespacesToDelete = append(f.namespacesToDelete, ns) 74 } 75 } 76 77 func generateNamespace(client clientset.Interface, baseName string, labels map[string]string) *corev1.Namespace { 78 namespaceObj := &corev1.Namespace{ 79 ObjectMeta: metav1.ObjectMeta{ 80 GenerateName: fmt.Sprintf("e2e-%v-", baseName), 81 Labels: labels, 82 }, 83 } 84 85 namespace, err := client.CoreV1().Namespaces().Create(namespaceObj) 86 gomega.Expect(err).NotTo(gomega.HaveOccurred(), "Error generating namespace %v", namespaceObj) 87 return namespace 88 } 89 90 // GenerateNamespace creates a namespace with a random name. 91 func (f *Framework) GenerateNamespace() (*corev1.Namespace, error) { 92 return f.KubeClient.CoreV1().Namespaces().Create(&corev1.Namespace{ 93 ObjectMeta: metav1.ObjectMeta{ 94 GenerateName: namespaceNamePrefix, 95 }, 96 }) 97 } 98 99 func deleteNamespace(client clientset.Interface, namespaceName string) error { 100 101 return client.CoreV1().Namespaces().Delete( 102 namespaceName, 103 &metav1.DeleteOptions{}) 104 105 } 106 107 func (f *Framework) DeleteNamespace(ns *corev1.Namespace) []error { 108 var errors []error 109 110 if err := deleteNamespace(f.KubeClient, ns.Name); err != nil { 111 switch { 112 case apierrors.IsNotFound(err): 113 e2elog.Logf("Namespace was already deleted") 114 case apierrors.IsConflict(err): 115 e2elog.Logf("Namespace scheduled for deletion, resources being purged") 116 default: 117 e2elog.Logf("Failed deleting namespace") 118 errors = append(errors, err) 119 } 120 } 121 122 return errors 123 } 124 125 // DeleteNamespaces deletes all namespaces that match the given delete and skip filters. 126 // Filter is by simple strings.Contains; first skip filter, then delete filter. 127 // Returns the list of deleted namespaces or an error. 128 func DeleteNamespaces(c clientset.Interface, deleteFilter, skipFilter []string) ([]string, error) { 129 ginkgo.By("Deleting namespaces") 130 nsList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{}) 131 ExpectNoError(err, "Failed to get namespace list") 132 var deleted []string 133 var wg sync.WaitGroup 134 OUTER: 135 for _, item := range nsList.Items { 136 if skipFilter != nil { 137 for _, pattern := range skipFilter { 138 if strings.Contains(item.Name, pattern) { 139 continue OUTER 140 } 141 } 142 } 143 if deleteFilter != nil { 144 var shouldDelete bool 145 for _, pattern := range deleteFilter { 146 if strings.Contains(item.Name, pattern) { 147 shouldDelete = true 148 break 149 } 150 } 151 if !shouldDelete { 152 continue OUTER 153 } 154 } 155 wg.Add(1) 156 deleted = append(deleted, item.Name) 157 go func(nsName string) { 158 defer wg.Done() 159 defer ginkgo.GinkgoRecover() 160 gomega.Expect(c.CoreV1().Namespaces().Delete(nsName, nil)).To(gomega.Succeed()) 161 e2elog.Logf("namespace : %v api call to delete is complete ", nsName) 162 }(item.Name) 163 } 164 wg.Wait() 165 return deleted, nil 166 } 167 168 // WaitForNamespacesDeleted waits for the namespaces to be deleted. 169 func WaitForNamespacesDeleted(c clientset.Interface, namespaces []string, timeout time.Duration) error { 170 ginkgo.By("Waiting for namespaces to vanish") 171 nsMap := map[string]bool{} 172 for _, ns := range namespaces { 173 nsMap[ns] = true 174 } 175 176 return wait.Poll(2*time.Second, timeout, 177 func() (bool, error) { 178 nsList, err := c.CoreV1().Namespaces().List(metav1.ListOptions{}) 179 if err != nil { 180 return false, err 181 } 182 for _, item := range nsList.Items { 183 if _, ok := nsMap[item.Name]; ok { 184 return false, nil 185 } 186 } 187 return true, nil 188 }) 189 }