@@ -27,9 +27,12 @@ import (
27
27
28
28
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
29
29
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30
31
"k8s.io/apimachinery/pkg/runtime"
32
+ runtimeschema "k8s.io/apimachinery/pkg/runtime/schema"
31
33
"k8s.io/apimachinery/pkg/util/sets"
32
34
"k8s.io/apimachinery/pkg/util/wait"
35
+ "k8s.io/client-go/discovery"
33
36
"k8s.io/client-go/rest"
34
37
"sigs.k8s.io/controller-runtime/pkg/client"
35
38
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -57,11 +60,11 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
57
60
ctx context.Context
58
61
cancel context.CancelFunc
59
62
60
- cli clusterclient.ClusterClient
61
- provider , consumer logicalcluster.Path
62
- consumerWS * tenancyv1alpha1.Workspace
63
- mgr mcmanager.Manager
64
- vwEndpoint string
63
+ cli clusterclient.ClusterClient
64
+ provider , consumer , other logicalcluster.Path
65
+ consumerWS * tenancyv1alpha1.Workspace
66
+ mgr mcmanager.Manager
67
+ vwEndpoint string
65
68
)
66
69
67
70
BeforeAll (func () {
@@ -73,6 +76,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
73
76
74
77
_ , provider = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("provider" ))
75
78
consumerWS , consumer = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("consumer" ))
79
+ _ , other = envtest .NewWorkspaceFixture (GinkgoT (), cli , core .RootCluster .Path (), envtest .WithNamePrefix ("other" ))
76
80
77
81
By (fmt .Sprintf ("creating a schema in the provider workspace %q" , provider ))
78
82
schema := & apisv1alpha1.APIResourceSchema {
@@ -94,6 +98,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
94
98
Raw : []byte (`{"type":"object","properties":{"spec":{"type":"object","properties":{"message":{"type":"string"}}}}}` ),
95
99
},
96
100
Storage : true ,
101
+ Served : true ,
97
102
}},
98
103
},
99
104
}
@@ -127,7 +132,7 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
127
132
err = cli .Cluster (provider ).Create (ctx , endpoitns )
128
133
Expect (err ).NotTo (HaveOccurred ())
129
134
130
- By (fmt .Sprintf ("creating an APIBinding in the consumer workspace %q" , consumer ))
135
+ By (fmt .Sprintf ("creating an APIBinding in the other workspace %q" , other ))
131
136
binding := & apisv1alpha1.APIBinding {
132
137
ObjectMeta : metav1.ObjectMeta {
133
138
Name : "example.com" ,
@@ -141,6 +146,23 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
141
146
},
142
147
},
143
148
}
149
+ err = cli .Cluster (other ).Create (ctx , binding )
150
+ Expect (err ).NotTo (HaveOccurred ())
151
+
152
+ By (fmt .Sprintf ("creating an APIBinding in the consumer workspace %q" , consumer ))
153
+ binding = & apisv1alpha1.APIBinding {
154
+ ObjectMeta : metav1.ObjectMeta {
155
+ Name : "example.com" ,
156
+ },
157
+ Spec : apisv1alpha1.APIBindingSpec {
158
+ Reference : apisv1alpha1.BindingReference {
159
+ Export : & apisv1alpha1.ExportBindingReference {
160
+ Path : provider .String (),
161
+ Name : export .Name ,
162
+ },
163
+ },
164
+ },
165
+ }
144
166
err = cli .Cluster (consumer ).Create (ctx , binding )
145
167
Expect (err ).NotTo (HaveOccurred ())
146
168
@@ -149,35 +171,104 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
149
171
envtest .Eventually (GinkgoT (), func () (bool , string ) {
150
172
err := cli .Cluster (provider ).Get (ctx , client.ObjectKey {Name : "example.com" }, endpoints )
151
173
if err != nil {
152
- return false , fmt .Sprintf ("failed to get APIExportEndpointSlice in %s : %v" , provider , err )
174
+ return false , fmt .Sprintf ("failed to get APIExportEndpointSlice in %q : %v" , provider , err )
153
175
}
154
176
return len (endpoints .Status .APIExportEndpoints ) > 0 , toYAML (GinkgoT (), endpoints )
155
- }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %s " , provider )
177
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see endpoints in APIExportEndpointSlice in %q " , provider )
156
178
vwEndpoint = endpoints .Status .APIExportEndpoints [0 ].URL
179
+
180
+ By (fmt .Sprintf ("waiting until the APIBinding in the consumer workspace %q to be ready" , consumer ))
181
+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
182
+ current := & apisv1alpha1.APIBinding {}
183
+ err := cli .Cluster (consumer ).Get (ctx , client.ObjectKey {Name : "example.com" }, current )
184
+ if err != nil {
185
+ return false , fmt .Sprintf ("failed to get APIBinding in %q: %v" , consumer , err )
186
+ }
187
+ if current .Status .Phase != apisv1alpha1 .APIBindingPhaseBound {
188
+ return false , fmt .Sprintf ("binding not bound:\n \n %s" , toYAML (GinkgoT (), current ))
189
+ }
190
+ return true , ""
191
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for APIBinding in consumer workspace to be ready %q" , consumer )
192
+
193
+ By ("waiting until things can be listed in the consumer workspace" )
194
+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
195
+ u := & unstructured.UnstructuredList {}
196
+ u .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
197
+ err = cli .Cluster (consumer ).List (ctx , u )
198
+ if err != nil {
199
+ return false , fmt .Sprintf ("failed to list things in %s: %v" , consumer , err )
200
+ }
201
+ return true , ""
202
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to wait for things to be listable in consumer workspace %q" , consumer )
157
203
})
158
204
159
205
Describe ("with a multicluster provider and manager" , func () {
160
206
var (
161
207
lock sync.RWMutex
162
208
engaged = sets .NewString ()
209
+ p * virtualworkspace.Provider
163
210
g * errgroup.Group
164
211
cancelGroup context.CancelFunc
165
212
)
166
213
167
214
BeforeAll (func () {
215
+ By ("creating a stone in the consumer workspace" , func () {
216
+ thing := & unstructured.Unstructured {}
217
+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
218
+ thing .SetName ("stone" )
219
+ thing .SetLabels (map [string ]string {"color" : "gray" })
220
+ err := cli .Cluster (consumer ).Create (ctx , thing )
221
+ Expect (err ).NotTo (HaveOccurred ())
222
+ })
223
+
224
+ By ("creating a box in the other workspace" , func () {
225
+ thing := & unstructured.Unstructured {}
226
+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
227
+ thing .SetName ("box" )
228
+ thing .SetLabels (map [string ]string {"color" : "white" })
229
+ err := cli .Cluster (other ).Create (ctx , thing )
230
+ Expect (err ).NotTo (HaveOccurred ())
231
+ })
232
+
168
233
By ("creating a multicluster provider for APIBindings against the apiexport virtual workspace" )
169
234
vwConfig := rest .CopyConfig (kcpConfig )
170
235
vwConfig .Host = vwEndpoint
171
- p , err := virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
236
+ var err error
237
+ p , err = virtualworkspace .New (vwConfig , & apisv1alpha1.APIBinding {}, virtualworkspace.Options {})
172
238
Expect (err ).NotTo (HaveOccurred ())
173
239
240
+ By ("waiting for discovery of the virtual workspace to show 'example.com'" )
241
+ wildcardConfig := rest .CopyConfig (vwConfig )
242
+ wildcardConfig .Host += logicalcluster .Wildcard .RequestPath ()
243
+ disc , err := discovery .NewDiscoveryClientForConfig (wildcardConfig )
244
+ Expect (err ).NotTo (HaveOccurred ())
245
+ envtest .Eventually (GinkgoT (), func () (bool , string ) {
246
+ ret , err := disc .ServerGroups ()
247
+ Expect (err ).NotTo (HaveOccurred ())
248
+ for _ , g := range ret .Groups {
249
+ if g .Name == "example.com" {
250
+ return true , ""
251
+ }
252
+ }
253
+ return false , fmt .Sprintf ("failed to find group example.com in:\n %s" , toYAML (GinkgoT (), ret ))
254
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to find group example.com in the virtual workspace" )
255
+
174
256
By ("creating a manager against the provider workspace" )
175
257
rootConfig := rest .CopyConfig (kcpConfig )
176
258
rootConfig .Host += provider .RequestPath ()
177
259
mgr , err = mcmanager .New (rootConfig , p , mcmanager.Options {})
178
260
Expect (err ).NotTo (HaveOccurred ())
179
261
180
- By ("creating a reconciler for the APIBinding" )
262
+ By ("adding an index on label 'color'" )
263
+ thing := & unstructured.Unstructured {}
264
+ thing .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "Thing" })
265
+ err = mgr .GetFieldIndexer ().IndexField (ctx , thing , "color" , func (obj client.Object ) []string {
266
+ u := obj .(* unstructured.Unstructured )
267
+ return []string {u .GetLabels ()["color" ]}
268
+ })
269
+ Expect (err ).NotTo (HaveOccurred ())
270
+
271
+ By ("creating a reconciler for APIBindings" )
181
272
err = mcbuilder .ControllerManagedBy (mgr ).
182
273
Named ("things" ).
183
274
For (& apisv1alpha1.APIBinding {}).
@@ -211,6 +302,46 @@ var _ = Describe("VirtualWorkspace Provider", Ordered, func() {
211
302
}, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the consumer workspace %q as a cluster" , consumer )
212
303
})
213
304
305
+ It ("sees only the stone in the consumer clusters" , func () {
306
+ consumerCl , err := mgr .GetCluster (ctx , consumerWS .Spec .Cluster )
307
+ Expect (err ).NotTo (HaveOccurred ())
308
+
309
+ envtest .Eventually (GinkgoT (), func () (success bool , reason string ) {
310
+ l := & unstructured.UnstructuredList {}
311
+ l .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
312
+ err = consumerCl .GetCache ().List (ctx , l )
313
+ if err != nil {
314
+ return false , fmt .Sprintf ("failed to list things in the consumer cluster cache: %v" , err )
315
+ }
316
+ if len (l .Items ) != 1 {
317
+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
318
+ } else if name := l .Items [0 ].GetName (); name != "stone" {
319
+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
320
+ }
321
+ return true , ""
322
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone in the consumer cluster" )
323
+ })
324
+
325
+ It ("sees only the stone as grey thing in the consumer clusters" , func () {
326
+ consumerCl , err := mgr .GetCluster (ctx , consumerWS .Spec .Cluster )
327
+ Expect (err ).NotTo (HaveOccurred ())
328
+
329
+ envtest .Eventually (GinkgoT (), func () (success bool , reason string ) {
330
+ l := & unstructured.UnstructuredList {}
331
+ l .SetGroupVersionKind (runtimeschema.GroupVersionKind {Group : "example.com" , Version : "v1" , Kind : "ThingList" })
332
+ err = consumerCl .GetCache ().List (ctx , l , client.MatchingFields {"color" : "gray" })
333
+ if err != nil {
334
+ return false , fmt .Sprintf ("failed to list things in the consumer cluster cache: %v" , err )
335
+ }
336
+ if len (l .Items ) != 1 {
337
+ return false , fmt .Sprintf ("expected 1 item, got %d\n \n %s" , len (l .Items ), toYAML (GinkgoT (), l .Object ))
338
+ } else if name := l .Items [0 ].GetName (); name != "stone" {
339
+ return false , fmt .Sprintf ("expected item name to be stone, got %q\n \n %s" , name , toYAML (GinkgoT (), l .Items [0 ]))
340
+ }
341
+ return true , ""
342
+ }, wait .ForeverTestTimeout , time .Millisecond * 100 , "failed to see the stone as only thing of color 'grey' in the consumer cluster" )
343
+ })
344
+
214
345
AfterAll (func () {
215
346
cancelGroup ()
216
347
err := g .Wait ()
0 commit comments