@@ -18,13 +18,17 @@ package network
18
18
19
19
import (
20
20
"context"
21
+ "fmt"
21
22
"strings"
22
23
"time"
23
24
24
25
networkingv1beta1 "k8s.io/api/networking/v1beta1"
26
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
25
27
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ types "k8s.io/apimachinery/pkg/types"
26
29
"k8s.io/apimachinery/pkg/util/intstr"
27
30
"k8s.io/apimachinery/pkg/util/wait"
31
+ "k8s.io/apimachinery/pkg/watch"
28
32
clientset "k8s.io/client-go/kubernetes"
29
33
"k8s.io/kubernetes/test/e2e/framework"
30
34
@@ -39,7 +43,7 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
39
43
})
40
44
41
45
ginkgo .It ("should set default value on new IngressClass" , func () {
42
- ingressClass1 , err := createIngressClass (cs , "ingressclass1" , true )
46
+ ingressClass1 , err := createIngressClass (cs , "ingressclass1" , true , f . UniqueName )
43
47
framework .ExpectNoError (err )
44
48
defer deleteIngressClass (cs , ingressClass1 .Name )
45
49
@@ -54,7 +58,7 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
54
58
})
55
59
56
60
ginkgo .It ("should not set default value if no default IngressClass" , func () {
57
- ingressClass1 , err := createIngressClass (cs , "ingressclass1" , false )
61
+ ingressClass1 , err := createIngressClass (cs , "ingressclass1" , false , f . UniqueName )
58
62
framework .ExpectNoError (err )
59
63
defer deleteIngressClass (cs , ingressClass1 .Name )
60
64
@@ -67,11 +71,11 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
67
71
})
68
72
69
73
ginkgo .It ("should prevent Ingress creation if more than 1 IngressClass marked as default" , func () {
70
- ingressClass1 , err := createIngressClass (cs , "ingressclass1" , true )
74
+ ingressClass1 , err := createIngressClass (cs , "ingressclass1" , true , f . UniqueName )
71
75
framework .ExpectNoError (err )
72
76
defer deleteIngressClass (cs , ingressClass1 .Name )
73
77
74
- ingressClass2 , err := createIngressClass (cs , "ingressclass2" , true )
78
+ ingressClass2 , err := createIngressClass (cs , "ingressclass2" , true , f . UniqueName )
75
79
framework .ExpectNoError (err )
76
80
defer deleteIngressClass (cs , ingressClass2 .Name )
77
81
@@ -93,10 +97,14 @@ var _ = SIGDescribe("IngressClass [Feature:Ingress]", func() {
93
97
94
98
})
95
99
96
- func createIngressClass (cs clientset.Interface , name string , isDefault bool ) (* networkingv1beta1.IngressClass , error ) {
100
+ func createIngressClass (cs clientset.Interface , name string , isDefault bool , uniqueName string ) (* networkingv1beta1.IngressClass , error ) {
97
101
ingressClass := & networkingv1beta1.IngressClass {
98
102
ObjectMeta : metav1.ObjectMeta {
99
103
Name : name ,
104
+ Labels : map [string ]string {
105
+ "ingressclass" : uniqueName ,
106
+ "special-label" : "generic" ,
107
+ },
100
108
},
101
109
Spec : networkingv1beta1.IngressClassSpec {
102
110
Controller : "example.com/controller" ,
@@ -128,3 +136,148 @@ func deleteIngressClass(cs clientset.Interface, name string) {
128
136
err := cs .NetworkingV1beta1 ().IngressClasses ().Delete (context .TODO (), name , metav1.DeleteOptions {})
129
137
framework .ExpectNoError (err )
130
138
}
139
+
140
+ var _ = SIGDescribe ("IngressClass API" , func () {
141
+ f := framework .NewDefaultFramework ("ingressclass" )
142
+ var cs clientset.Interface
143
+ ginkgo .BeforeEach (func () {
144
+ cs = f .ClientSet
145
+ })
146
+ /*
147
+ Release: v1.19
148
+ Testname: IngressClass API
149
+ Description:
150
+ - The networking.k8s.io API group MUST exist in the /apis discovery document.
151
+ - The networking.k8s.io/v1beta1 API group/version MUST exist in the /apis/networking.k8s.io discovery document.
152
+ - The IngressClasses resources MUST exist in the /apis/networking.k8s.io/v1beta1 discovery document.
153
+ - The IngressClass resource must support create, get, list, watch, update, patch, delete, and deletecollection.
154
+ */
155
+ ginkgo .It (" should support creating IngressClass API operations" , func () {
156
+
157
+ // Setup
158
+ icClient := f .ClientSet .NetworkingV1beta1 ().IngressClasses ()
159
+ icVersion := "v1beta1"
160
+
161
+ // Discovery
162
+ ginkgo .By ("getting /apis" )
163
+ {
164
+ discoveryGroups , err := f .ClientSet .Discovery ().ServerGroups ()
165
+ framework .ExpectNoError (err )
166
+ found := false
167
+ for _ , group := range discoveryGroups .Groups {
168
+ if group .Name == networkingv1beta1 .GroupName {
169
+ for _ , version := range group .Versions {
170
+ if version .Version == icVersion {
171
+ found = true
172
+ break
173
+ }
174
+ }
175
+ }
176
+ }
177
+ framework .ExpectEqual (found , true , fmt .Sprintf ("expected networking API group/version, got %#v" , discoveryGroups .Groups ))
178
+ }
179
+ ginkgo .By ("getting /apis/networking.k8s.io" )
180
+ {
181
+ group := & metav1.APIGroup {}
182
+ err := f .ClientSet .Discovery ().RESTClient ().Get ().AbsPath ("/apis/networking.k8s.io" ).Do (context .TODO ()).Into (group )
183
+ framework .ExpectNoError (err )
184
+ found := false
185
+ for _ , version := range group .Versions {
186
+ if version .Version == icVersion {
187
+ found = true
188
+ break
189
+ }
190
+ }
191
+ framework .ExpectEqual (found , true , fmt .Sprintf ("expected networking API version, got %#v" , group .Versions ))
192
+ }
193
+
194
+ ginkgo .By ("getting /apis/networking.k8s.io" + icVersion )
195
+ {
196
+ resources , err := f .ClientSet .Discovery ().ServerResourcesForGroupVersion (networkingv1beta1 .SchemeGroupVersion .String ())
197
+ framework .ExpectNoError (err )
198
+ foundIC := false
199
+ for _ , resource := range resources .APIResources {
200
+ switch resource .Name {
201
+ case "ingressclasses" :
202
+ foundIC = true
203
+ }
204
+ }
205
+ framework .ExpectEqual (foundIC , true , fmt .Sprintf ("expected ingressclasses, got %#v" , resources .APIResources ))
206
+ }
207
+
208
+ // IngressClass resource create/read/update/watch verbs
209
+ ginkgo .By ("creating" )
210
+ ingressClass1 , err := createIngressClass (cs , "ingressclass1" , true , f .UniqueName )
211
+ framework .ExpectNoError (err )
212
+ _ , err = createIngressClass (cs , "ingressclass2" , true , f .UniqueName )
213
+ framework .ExpectNoError (err )
214
+ _ , err = createIngressClass (cs , "ingressclass3" , true , f .UniqueName )
215
+ framework .ExpectNoError (err )
216
+
217
+ ginkgo .By ("getting" )
218
+ gottenIC , err := icClient .Get (context .TODO (), ingressClass1 .Name , metav1.GetOptions {})
219
+ framework .ExpectNoError (err )
220
+ framework .ExpectEqual (gottenIC .UID , ingressClass1 .UID )
221
+ framework .ExpectEqual (gottenIC .UID , ingressClass1 .UID )
222
+
223
+ ginkgo .By ("listing" )
224
+ ics , err := icClient .List (context .TODO (), metav1.ListOptions {LabelSelector : "special-label=generic" })
225
+ framework .ExpectNoError (err )
226
+ framework .ExpectEqual (len (ics .Items ), 3 , "filtered list should have 3 items" )
227
+
228
+ ginkgo .By ("watching" )
229
+ framework .Logf ("starting watch" )
230
+ icWatch , err := icClient .Watch (context .TODO (), metav1.ListOptions {ResourceVersion : ics .ResourceVersion , LabelSelector : "ingressclass=" + f .UniqueName })
231
+ framework .ExpectNoError (err )
232
+
233
+ ginkgo .By ("patching" )
234
+ patchedIC , err := icClient .Patch (context .TODO (), ingressClass1 .Name , types .MergePatchType , []byte (`{"metadata":{"annotations":{"patched":"true"}}}` ), metav1.PatchOptions {})
235
+ framework .ExpectNoError (err )
236
+ framework .ExpectEqual (patchedIC .Annotations ["patched" ], "true" , "patched object should have the applied annotation" )
237
+
238
+ ginkgo .By ("updating" )
239
+ icToUpdate := patchedIC .DeepCopy ()
240
+ icToUpdate .Annotations ["updated" ] = "true"
241
+ updatedIC , err := icClient .Update (context .TODO (), icToUpdate , metav1.UpdateOptions {})
242
+ framework .ExpectNoError (err )
243
+ framework .ExpectEqual (updatedIC .Annotations ["updated" ], "true" , "updated object should have the applied annotation" )
244
+
245
+ framework .Logf ("waiting for watch events with expected annotations" )
246
+ for sawAnnotations := false ; ! sawAnnotations ; {
247
+ select {
248
+ case evt , ok := <- icWatch .ResultChan ():
249
+ framework .ExpectEqual (ok , true , "watch channel should not close" )
250
+ framework .ExpectEqual (evt .Type , watch .Modified )
251
+ watchedIngress , isIngress := evt .Object .(* networkingv1beta1.IngressClass )
252
+ framework .ExpectEqual (isIngress , true , fmt .Sprintf ("expected Ingress, got %T" , evt .Object ))
253
+ if watchedIngress .Annotations ["patched" ] == "true" {
254
+ framework .Logf ("saw patched and updated annotations" )
255
+ sawAnnotations = true
256
+ icWatch .Stop ()
257
+ } else {
258
+ framework .Logf ("missing expected annotations, waiting: %#v" , watchedIngress .Annotations )
259
+ }
260
+ case <- time .After (wait .ForeverTestTimeout ):
261
+ framework .Fail ("timed out waiting for watch event" )
262
+ }
263
+ }
264
+
265
+ // IngressClass resource delete operations
266
+ ginkgo .By ("deleting" )
267
+ err = icClient .Delete (context .TODO (), ingressClass1 .Name , metav1.DeleteOptions {})
268
+ framework .ExpectNoError (err )
269
+ _ , err = icClient .Get (context .TODO (), ingressClass1 .Name , metav1.GetOptions {})
270
+ framework .ExpectEqual (apierrors .IsNotFound (err ), true , fmt .Sprintf ("expected 404, got %#v" , err ))
271
+ ics , err = icClient .List (context .TODO (), metav1.ListOptions {LabelSelector : "ingressclass=" + f .UniqueName })
272
+ framework .ExpectNoError (err )
273
+ framework .ExpectEqual (len (ics .Items ), 2 , "filtered list should have 2 items" )
274
+
275
+ ginkgo .By ("deleting a collection" )
276
+ err = icClient .DeleteCollection (context .TODO (), metav1.DeleteOptions {}, metav1.ListOptions {LabelSelector : "ingressclass=" + f .UniqueName })
277
+ framework .ExpectNoError (err )
278
+ ics , err = icClient .List (context .TODO (), metav1.ListOptions {LabelSelector : "ingressclass=" + f .UniqueName })
279
+ framework .ExpectNoError (err )
280
+ framework .ExpectEqual (len (ics .Items ), 0 , "filtered list should have 0 items" )
281
+ })
282
+
283
+ })
0 commit comments