Skip to content

Commit 9cb2b5a

Browse files
committed
adjust e2e tests
On-behalf-of: @SAP christoph.mewes@sap.com
1 parent 5c6cad5 commit 9cb2b5a

3 files changed

Lines changed: 89 additions & 34 deletions

File tree

backend/controllers/serviceexportrequest/serviceexportrequest_reconcile.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ func (r *reconciler) ensureBoundSchemas(ctx context.Context, cl client.Client, c
167167
// we need to rewrite the BoundSchema's scope accordingly. For all
168168
// other isolation strategies, as well as for namespaced schemas,
169169
// no changes are necessary.
170-
if boundSchema.Spec.Scope == apiextensionsv1.ClusterScoped && r.clusterScopedIsolation == kubebindv1alpha2.IsolationNamespaced {
171-
boundSchema.Spec.Scope = apiextensionsv1.NamespaceScoped
170+
if boundSchema.Spec.Scope == apiextensionsv1.NamespaceScoped && r.clusterScopedIsolation == kubebindv1alpha2.IsolationNamespaced {
171+
boundSchema.Spec.Scope = apiextensionsv1.ClusterScoped
172172
}
173173

174174
if err := r.createBoundSchema(ctx, cl, boundSchema); err != nil {

test/e2e/bind/happy-case_test.go

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ import (
2626

2727
"github.com/stretchr/testify/require"
2828
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
29+
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
2930
"k8s.io/apimachinery/pkg/api/errors"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3132
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3233
"k8s.io/apimachinery/pkg/runtime/schema"
3334
"k8s.io/apimachinery/pkg/util/wait"
3435
"k8s.io/cli-runtime/pkg/genericclioptions"
3536
"k8s.io/client-go/dynamic"
37+
"k8s.io/client-go/rest"
3638
"k8s.io/client-go/util/retry"
3739
"sigs.k8s.io/yaml"
3840

@@ -47,21 +49,25 @@ import (
4749
func TestClusterScoped(t *testing.T) {
4850
t.Parallel()
4951
// name & test type defined by letters - cc - cluster-cluster so its easier to identify failures in the logs.
50-
testHappyCase(t, "cc", apiextensionsv1.ClusterScoped, kubebindv1alpha2.ClusterScope)
52+
testHappyCase(t, "cc-prefixed", apiextensionsv1.ClusterScoped, apiextensionsv1.ClusterScoped, kubebindv1alpha2.ClusterScope, kubebindv1alpha2.IsolationPrefixed)
53+
testHappyCase(t, "cc-none", apiextensionsv1.ClusterScoped, apiextensionsv1.ClusterScoped, kubebindv1alpha2.ClusterScope, kubebindv1alpha2.IsolationNone)
54+
testHappyCase(t, "cc-namespaced", apiextensionsv1.ClusterScoped, apiextensionsv1.NamespaceScoped, kubebindv1alpha2.ClusterScope, kubebindv1alpha2.IsolationNamespaced)
5155
}
5256

5357
func TestNamespacedScoped(t *testing.T) {
5458
t.Parallel()
5559

56-
testHappyCase(t, "nn", apiextensionsv1.NamespaceScoped, kubebindv1alpha2.NamespacedScope)
57-
testHappyCase(t, "nc", apiextensionsv1.NamespaceScoped, kubebindv1alpha2.ClusterScope)
60+
testHappyCase(t, "nn", apiextensionsv1.NamespaceScoped, apiextensionsv1.NamespaceScoped, kubebindv1alpha2.NamespacedScope, "")
61+
testHappyCase(t, "nc", apiextensionsv1.NamespaceScoped, apiextensionsv1.NamespaceScoped, kubebindv1alpha2.ClusterScope, "")
5862
}
5963

6064
func testHappyCase(
6165
t *testing.T,
6266
name string,
63-
resourceScope apiextensionsv1.ResourceScope,
67+
consumerResourceScope apiextensionsv1.ResourceScope,
68+
providerResourceScope apiextensionsv1.ResourceScope,
6469
informerScope kubebindv1alpha2.InformerScope,
70+
isolationStrategy kubebindv1alpha2.Isolation,
6571
) {
6672
ctx, cancel := context.WithCancel(context.Background())
6773
t.Cleanup(cancel) // Commented out to prevent cleanup of kcp assets
@@ -72,24 +78,36 @@ func testHappyCase(
7278
providerConfig, providerKubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t), framework.WithName("%s-provider-%s", name, suffix))
7379

7480
t.Logf("Installing kubebind CRDs")
75-
framework.InstallKubebindCRDs(t, providerConfig)
81+
framework.InstallKubeBindCRDs(t, providerConfig)
7682

7783
t.Logf("Starting backend with random port")
78-
addr, _ := framework.StartBackend(t, "--kubeconfig="+providerKubeconfig, "--listen-address=:0", "--consumer-scope="+string(informerScope))
84+
addr, _ := framework.StartBackend(t,
85+
"--kubeconfig="+providerKubeconfig,
86+
"--listen-address=:0",
87+
"--consumer-scope="+string(informerScope),
88+
"--cluster-scoped-isolation="+string(isolationStrategy),
89+
)
7990

8091
t.Logf("Creating CRD on provider side")
8192
examples.Bootstrap(t, framework.DiscoveryClient(t, providerConfig), framework.DynamicClient(t, providerConfig), nil)
8293

94+
// For namespaced-isolated cluster-scoped objects, the CRD needs to be namespaced on the provider side,
95+
// but cluster-scoped on the consumer side. To make this setup possible without introducing another CRD,
96+
// we will simply "hack" the CRD here on the providerside to make it work.
97+
if providerResourceScope == apiextensionsv1.NamespaceScoped && consumerResourceScope == apiextensionsv1.ClusterScoped {
98+
t.Logf("Changing sheriff CRD scope to namespaced on the provider side")
99+
toggleCRDScope(t, ctx, providerConfig, "sheriffs.wildwest.dev", apiextensionsv1.NamespaceScoped)
100+
}
101+
83102
t.Logf("Creating consumer workspace and starting konnector")
84103
consumerConfig, consumerKubeconfig := framework.NewWorkspace(t, framework.ClientConfig(t), framework.WithName("%s-consumer-%s", name, suffix))
85104
framework.StartKonnector(t, consumerConfig, "--kubeconfig="+consumerKubeconfig)
86105

87106
serviceGVR := schema.GroupVersionResource{Group: "wildwest.dev", Version: "v1alpha1", Resource: "cowboys"}
88-
if resourceScope == apiextensionsv1.ClusterScoped {
89-
serviceGVR = schema.GroupVersionResource{Group: "wildwest.dev", Version: "v1alpha1", Resource: "sheriffs"}
90-
}
91107
templateRef := "cowboys"
92-
if resourceScope == apiextensionsv1.ClusterScoped {
108+
109+
if consumerResourceScope == apiextensionsv1.ClusterScoped {
110+
serviceGVR = schema.GroupVersionResource{Group: "wildwest.dev", Version: "v1alpha1", Resource: "sheriffs"}
93111
templateRef = "sheriffs"
94112
}
95113

@@ -100,8 +118,14 @@ func testHappyCase(
100118
providerBindClient := framework.BindClient(t, providerConfig)
101119

102120
// Instance variables removed - now seeded directly in test
121+
// These two namespaces are where the "main" object resides on each cluster.
103122
consumerNs, providerNs := "wild-west", "unknown"
104123

124+
// When namespaced isolation is used (i.e. cluster-scoped objects on the consumer
125+
// turn into namespaced objects on the provider cluster), permission claimed objects
126+
// are still synced into their respective APIServiceNamespace-managed namespaces.
127+
permClaimNs := "unknown"
128+
105129
// cluster namespace is the main "contract" namespace, i.e. where the BoundSchema and other
106130
// bind-related objects reside.
107131
clusterNs, clusterScopedUpInsName := "unknown", "unknown"
@@ -113,7 +137,7 @@ func testHappyCase(
113137
// For sheriffs: sheriff-badge-credentials (referenced), sheriff-jurisdiction-config (label selector)
114138
var referencedSecretName, labelSelectedSecretName string
115139
var filename string
116-
if resourceScope == apiextensionsv1.NamespaceScoped {
140+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
117141
referencedSecretName = "colt-45-permit" //nolint:gosec
118142
labelSelectedSecretName = "cowboy-gang-affiliation"
119143
filename = "cr-cowboy.yaml"
@@ -368,7 +392,7 @@ func testHappyCase(
368392
// We need to establish namespace only in cluster scope for cluster scoped resources.
369393
// Else we can trust sync object namespace as it will be the same.
370394
if informerScope == kubebindv1alpha2.ClusterScope &&
371-
resourceScope == apiextensionsv1.ClusterScoped {
395+
consumerResourceScope == apiextensionsv1.ClusterScoped {
372396
if providerNs == "unknown" {
373397
t.Fatal("providerNS is not set. Programming error in the test.")
374398
}
@@ -383,14 +407,18 @@ func testHappyCase(
383407

384408
for _, namespace := range namespaces.Items {
385409
if strings.Contains(namespace.Name, consumerNs) && namespace.Status.Namespace != "" {
386-
providerNs = namespace.Status.Namespace
410+
permClaimNs = namespace.Status.Namespace
387411
return true
388412
}
389413
}
390414

391415
return false
392416
}, wait.ForeverTestTimeout, time.Millisecond*100, "waiting for APIServiceNamespace to be created on provider side")
393-
require.NotEmpty(t, providerNs, "No cluster namespaces found")
417+
require.NotEmpty(t, permClaimNs, "No permission claim namespaces found")
418+
419+
t.Logf("permclaim namespace detected as: %q", permClaimNs)
420+
} else {
421+
permClaimNs = providerNs
394422
}
395423
},
396424
},
@@ -399,13 +427,13 @@ func testHappyCase(
399427
step: func(t *testing.T) {
400428
t.Logf("Waiting for referenced secret to be synced to provider side")
401429
require.Eventually(t, func() bool {
402-
_, err := providerCoreClient.Secrets(providerNs).Get(ctx, referencedSecretName, metav1.GetOptions{})
430+
_, err := providerCoreClient.Secrets(permClaimNs).Get(ctx, referencedSecretName, metav1.GetOptions{})
403431
return err == nil
404432
}, time.Minute*2, time.Millisecond*100, "waiting for referenced secret to be synced to provider side")
405433

406434
t.Logf("Waiting for label-selected secret to be synced to provider side")
407435
require.Eventually(t, func() bool {
408-
_, err := providerCoreClient.Secrets(providerNs).Get(ctx, labelSelectedSecretName, metav1.GetOptions{})
436+
_, err := providerCoreClient.Secrets(permClaimNs).Get(ctx, labelSelectedSecretName, metav1.GetOptions{})
409437
return err == nil
410438
}, wait.ForeverTestTimeout, time.Millisecond*100, "waiting for label-selected secret to be synced to provider side")
411439

@@ -424,7 +452,7 @@ func testHappyCase(
424452
name: "instance deleted upstream is recreated",
425453
step: func(t *testing.T) {
426454
var err error
427-
if resourceScope == apiextensionsv1.NamespaceScoped {
455+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
428456
err = providerClient.Namespace(providerNs).Delete(ctx, "test", metav1.DeleteOptions{})
429457
} else {
430458
err = providerClient.Delete(ctx, clusterScopedUpInsName, metav1.DeleteOptions{})
@@ -433,7 +461,7 @@ func testHappyCase(
433461

434462
require.Eventually(t, func() bool {
435463
var err error
436-
if resourceScope == apiextensionsv1.NamespaceScoped {
464+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
437465
_, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
438466
} else {
439467
_, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
@@ -448,13 +476,13 @@ func testHappyCase(
448476
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
449477
var obj *unstructured.Unstructured
450478
var err error
451-
if resourceScope == apiextensionsv1.NamespaceScoped {
479+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
452480
obj, err = consumerClient.Namespace(consumerNs).Get(ctx, "test", metav1.GetOptions{})
453481
} else {
454482
obj, err = consumerClient.Get(ctx, "test", metav1.GetOptions{})
455483
}
456484
require.NoError(t, err)
457-
if resourceScope == apiextensionsv1.NamespaceScoped {
485+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
458486
unstructured.SetNestedField(obj.Object, "Updated cowboy intent", "spec", "intent") //nolint:errcheck
459487
_, err = consumerClient.Namespace(consumerNs).Update(ctx, obj, metav1.UpdateOptions{})
460488
} else {
@@ -468,7 +496,7 @@ func testHappyCase(
468496
require.Eventually(t, func() bool {
469497
var obj *unstructured.Unstructured
470498
var err error
471-
if resourceScope == apiextensionsv1.NamespaceScoped {
499+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
472500
obj, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
473501
} else {
474502
obj, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
@@ -478,7 +506,7 @@ func testHappyCase(
478506
value, _, err = unstructured.NestedString(obj.Object, "spec", "intent")
479507

480508
require.NoError(t, err)
481-
if resourceScope == apiextensionsv1.NamespaceScoped {
509+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
482510
return value == "Updated cowboy intent"
483511
} else {
484512
return value == "Updated sheriff intent"
@@ -492,14 +520,14 @@ func testHappyCase(
492520
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
493521
var obj *unstructured.Unstructured
494522
var err error
495-
if resourceScope == apiextensionsv1.NamespaceScoped {
523+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
496524
obj, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
497525
} else {
498526
obj, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
499527
}
500528
require.NoError(t, err)
501529
unstructured.SetNestedField(obj.Object, "Ready to ride", "status", "result") //nolint:errcheck
502-
if resourceScope == apiextensionsv1.NamespaceScoped {
530+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
503531
_, err = providerClient.Namespace(providerNs).UpdateStatus(ctx, obj, metav1.UpdateOptions{})
504532
} else {
505533
_, err = providerClient.UpdateStatus(ctx, obj, metav1.UpdateOptions{})
@@ -511,7 +539,7 @@ func testHappyCase(
511539
require.Eventually(t, func() bool {
512540
var obj *unstructured.Unstructured
513541
var err error
514-
if resourceScope == apiextensionsv1.NamespaceScoped {
542+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
515543
obj, err = consumerClient.Namespace(consumerNs).Get(ctx, "test", metav1.GetOptions{})
516544
} else {
517545
obj, err = consumerClient.Get(ctx, "test", metav1.GetOptions{})
@@ -529,13 +557,13 @@ func testHappyCase(
529557
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
530558
var obj *unstructured.Unstructured
531559
var err error
532-
if resourceScope == apiextensionsv1.NamespaceScoped {
560+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
533561
obj, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
534562
} else {
535563
obj, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
536564
}
537565
require.NoError(t, err)
538-
if resourceScope == apiextensionsv1.NamespaceScoped {
566+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
539567
unstructured.SetNestedField(obj.Object, "Drifted cowboy intent", "spec", "intent") //nolint:errcheck
540568
_, err = providerClient.Namespace(providerNs).Update(ctx, obj, metav1.UpdateOptions{})
541569
} else {
@@ -549,14 +577,14 @@ func testHappyCase(
549577
require.Eventually(t, func() bool {
550578
var obj *unstructured.Unstructured
551579
var err error
552-
if resourceScope == apiextensionsv1.NamespaceScoped {
580+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
553581
obj, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
554582
} else {
555583
obj, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
556584
}
557585
require.NoError(t, err)
558586
var value string
559-
if resourceScope == apiextensionsv1.NamespaceScoped {
587+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
560588
value, _, err = unstructured.NestedString(obj.Object, "spec", "intent")
561589
require.NoError(t, err)
562590
return value == "Updated cowboy intent"
@@ -572,7 +600,7 @@ func testHappyCase(
572600
name: "instances deleted downstream are deleted upstream",
573601
step: func(t *testing.T) {
574602
var err error
575-
if resourceScope == apiextensionsv1.NamespaceScoped {
603+
if consumerResourceScope == apiextensionsv1.NamespaceScoped {
576604
err = consumerClient.Namespace(consumerNs).Delete(ctx, "test", metav1.DeleteOptions{})
577605
} else {
578606
err = consumerClient.Delete(ctx, "test", metav1.DeleteOptions{})
@@ -581,7 +609,7 @@ func testHappyCase(
581609

582610
require.Eventually(t, func() bool {
583611
var err error
584-
if resourceScope == apiextensionsv1.NamespaceScoped {
612+
if providerResourceScope == apiextensionsv1.NamespaceScoped {
585613
_, err = providerClient.Namespace(providerNs).Get(ctx, "test", metav1.GetOptions{})
586614
} else {
587615
_, err = providerClient.Get(ctx, clusterScopedUpInsName, metav1.GetOptions{})
@@ -677,3 +705,30 @@ func applyMultiDocYAML(ctx context.Context, t *testing.T, dynamicClient dynamic.
677705

678706
return nil
679707
}
708+
709+
func toggleCRDScope(t *testing.T, ctx context.Context, config *rest.Config, name string, scope apiextensionsv1.ResourceScope) {
710+
clientset, err := apiextensionsclient.NewForConfig(config)
711+
require.NoError(t, err)
712+
713+
crdClient := clientset.ApiextensionsV1().CustomResourceDefinitions()
714+
715+
// copy existing CRD
716+
crd, err := crdClient.Get(ctx, name, metav1.GetOptions{})
717+
require.NoError(t, err)
718+
719+
// delete it
720+
require.NoError(t, crdClient.Delete(ctx, name, metav1.DeleteOptions{}))
721+
722+
require.Eventually(t, func() bool {
723+
_, err := crdClient.Get(ctx, name, metav1.GetOptions{})
724+
return errors.IsNotFound(err)
725+
}, wait.ForeverTestTimeout, time.Millisecond*100, "waiting for the CRD to be deleted")
726+
727+
// re-create it
728+
crd.Spec.Scope = scope
729+
crd.ObjectMeta.ResourceVersion = ""
730+
crd.ObjectMeta.UID = ""
731+
crd.ObjectMeta.Generation = 0
732+
_, err = crdClient.Create(ctx, crd, metav1.CreateOptions{})
733+
require.NoError(t, err)
734+
}

test/e2e/framework/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import (
3434
kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
3535
)
3636

37-
func InstallKubebindCRDs(t testing.TB, clientConfig *rest.Config) {
37+
func InstallKubeBindCRDs(t testing.TB, clientConfig *rest.Config) {
3838
crdClient, err := apiextensionsclient.NewForConfig(clientConfig)
3939
require.NoError(t, err)
4040
err = crd.Create(t.Context(),

0 commit comments

Comments
 (0)