diff --git a/pkg/reconciler/workload/synctarget/synctarget_reconcile.go b/pkg/reconciler/workload/synctarget/synctarget_reconcile.go index e9c1fb3efc3..81c9b6b3a9b 100644 --- a/pkg/reconciler/workload/synctarget/synctarget_reconcile.go +++ b/pkg/reconciler/workload/synctarget/synctarget_reconcile.go @@ -46,17 +46,18 @@ func (c *Controller) reconcile(ctx context.Context, syncTarget *workloadv1alpha1 desiredURLs := map[string]workloadv1alpha1.VirtualWorkspace{} + var rootShardKey string for _, workspaceShard := range workspaceShards { - if workspaceShard.Spec.ExternalURL != "" { - sharedExternalURL, err := url.Parse(workspaceShard.Spec.ExternalURL) + if workspaceShard.Spec.VirtualWorkspaceURL != "" { + shardVWURL, err := url.Parse(workspaceShard.Spec.VirtualWorkspaceURL) if err != nil { - logger.Error(err, "failed to parse workspaceShard.Spec.ExternalURL") + logger.Error(err, "failed to parse workspaceShard.Spec.VirtualWorkspaceURL") return nil, err } - syncerVirtualWorkspaceURL := *sharedExternalURL + syncerVirtualWorkspaceURL := *shardVWURL syncerVirtualWorkspaceURL.Path = path.Join( - sharedExternalURL.Path, + shardVWURL.Path, virtualworkspacesoptions.DefaultRootPathPrefix, syncerbuilder.SyncerVirtualWorkspaceName, logicalcluster.From(syncTargetCopy).String(), @@ -64,9 +65,9 @@ func (c *Controller) reconcile(ctx context.Context, syncTarget *workloadv1alpha1 string(syncTargetCopy.UID), ) - upsyncerVirtualWorkspaceURL := *sharedExternalURL + upsyncerVirtualWorkspaceURL := *shardVWURL (&upsyncerVirtualWorkspaceURL).Path = path.Join( - sharedExternalURL.Path, + shardVWURL.Path, virtualworkspacesoptions.DefaultRootPathPrefix, syncerbuilder.UpsyncerVirtualWorkspaceName, logicalcluster.From(syncTargetCopy).String(), @@ -77,16 +78,26 @@ func (c *Controller) reconcile(ctx context.Context, syncTarget *workloadv1alpha1 syncerURL := (&syncerVirtualWorkspaceURL).String() upsyncerURL := (&upsyncerVirtualWorkspaceURL).String() - desiredURLs[sharedExternalURL.String()] = workloadv1alpha1.VirtualWorkspace{ + if workspaceShard.Name == corev1alpha1.RootShard { + rootShardKey = shardVWURL.String() + } + desiredURLs[shardVWURL.String()] = workloadv1alpha1.VirtualWorkspace{ SyncerURL: syncerURL, UpsyncerURL: upsyncerURL, } } } - // Let's always add the desired URL in the same order, which will be the order of the - // corresponding shard URLs + // Let's always add the desired URLs in the same order: + // - urls for the root shard will always be added at the first place, + // in order to ensure compatibility with the shard-unaware Syncer + // - urls for other shards which will be added in the lexical order of the + // corresponding shard URLs. var desiredVirtualWorkspaces []workloadv1alpha1.VirtualWorkspace //nolint:prealloc + if rootShardVWURLs, ok := desiredURLs[rootShardKey]; ok { + desiredVirtualWorkspaces = append(desiredVirtualWorkspaces, rootShardVWURLs) + delete(desiredURLs, rootShardKey) + } for _, shardURL := range sets.StringKeySet(desiredURLs).List() { desiredVirtualWorkspaces = append(desiredVirtualWorkspaces, desiredURLs[shardURL]) } diff --git a/pkg/reconciler/workload/synctarget/synctarget_reconcile_test.go b/pkg/reconciler/workload/synctarget/synctarget_reconcile_test.go index 4c253852702..b4922a381e1 100644 --- a/pkg/reconciler/workload/synctarget/synctarget_reconcile_test.go +++ b/pkg/reconciler/workload/synctarget/synctarget_reconcile_test.go @@ -44,8 +44,8 @@ func TestReconciler(t *testing.T) { Name: "root", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host/", }, }, }, @@ -96,8 +96,8 @@ func TestReconciler(t *testing.T) { Name: "root2", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-2/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-2/", }, }, { @@ -105,8 +105,8 @@ func TestReconciler(t *testing.T) { Name: "root3", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-3/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-3/", }, }, { @@ -114,8 +114,8 @@ func TestReconciler(t *testing.T) { Name: "root", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-1/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-1/", }, }, }, @@ -167,15 +167,93 @@ func TestReconciler(t *testing.T) { }, expectError: false, }, - "SyncTarget with multiple Shards with duplicated ExternalURLs results in a deduplicated list of URLs on the SyncTarget": { + "SyncTarget and multiple Shards, but root shard always first": { + workspaceShards: []*corev1alpha1.Shard{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "root2", + }, + Spec: corev1alpha1.ShardSpec{ + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-2/", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "root3", + }, + Spec: corev1alpha1.ShardSpec{ + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-3/", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "root", + }, + Spec: corev1alpha1.ShardSpec{ + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-10/", + }, + }, + }, + syncTarget: &workloadv1alpha1.SyncTarget{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Annotations: map[string]string{ + logicalcluster.AnnotationKey: "demo:root:yourworkspace", + }, + }, + Spec: workloadv1alpha1.SyncTargetSpec{ + Unschedulable: false, + EvictAfter: nil, + }, + Status: workloadv1alpha1.SyncTargetStatus{ + VirtualWorkspaces: []workloadv1alpha1.VirtualWorkspace{}, + }, + }, + expectedSyncTarget: &workloadv1alpha1.SyncTarget{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Annotations: map[string]string{ + logicalcluster.AnnotationKey: "demo:root:yourworkspace", + }, + Labels: map[string]string{ + "internal.workload.kcp.io/key": "aPXkBdRsTD8gXESO47r9qXmkr2kaG5qaox5C8r", + }, + }, + Spec: workloadv1alpha1.SyncTargetSpec{ + Unschedulable: false, + EvictAfter: nil, + }, + Status: workloadv1alpha1.SyncTargetStatus{ + VirtualWorkspaces: []workloadv1alpha1.VirtualWorkspace{ + { + SyncerURL: "http://external-host-10/services/syncer/demo:root:yourworkspace/test-cluster", + UpsyncerURL: "http://external-host-10/services/upsyncer/demo:root:yourworkspace/test-cluster", + }, + { + SyncerURL: "http://external-host-2/services/syncer/demo:root:yourworkspace/test-cluster", + UpsyncerURL: "http://external-host-2/services/upsyncer/demo:root:yourworkspace/test-cluster", + }, + { + SyncerURL: "http://external-host-3/services/syncer/demo:root:yourworkspace/test-cluster", + UpsyncerURL: "http://external-host-3/services/upsyncer/demo:root:yourworkspace/test-cluster", + }, + }, + }, + }, + expectError: false, + }, + "SyncTarget with multiple Shards with duplicated VirtualWorkspaceURLs results in a deduplicated list of URLs on the SyncTarget": { workspaceShards: []*corev1alpha1.Shard{ { ObjectMeta: metav1.ObjectMeta{ Name: "root", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-1/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-1/", }, }, { @@ -183,8 +261,8 @@ func TestReconciler(t *testing.T) { Name: "root2", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-1/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-1/", }, }, { @@ -192,8 +270,8 @@ func TestReconciler(t *testing.T) { Name: "root3", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-3/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-3/", }, }, }, @@ -282,8 +360,8 @@ func TestReconciler(t *testing.T) { Name: "root", }, Spec: corev1alpha1.ShardSpec{ - BaseURL: "http://1.2.3.4/", - ExternalURL: "http://external-host-1/", + BaseURL: "http://1.2.3.4/", + VirtualWorkspaceURL: "http://external-host-1/", }, }, }, diff --git a/test/e2e/framework/kcp.go b/test/e2e/framework/kcp.go index bc9fd6da309..10bdd74b264 100644 --- a/test/e2e/framework/kcp.go +++ b/test/e2e/framework/kcp.go @@ -421,6 +421,7 @@ type RunningServer interface { BaseConfig(t *testing.T) *rest.Config RootShardSystemMasterBaseConfig(t *testing.T) *rest.Config ShardSystemMasterBaseConfig(t *testing.T, shard string) *rest.Config + ShardNames() []string Artifact(t *testing.T, producer func() (runtime.Object, error)) ClientCAUserConfig(t *testing.T, config *rest.Config, name string, groups ...string) *rest.Config CADirectory() string @@ -853,6 +854,10 @@ func (c *kcpServer) ShardSystemMasterBaseConfig(t *testing.T, shard string) *res return c.RootShardSystemMasterBaseConfig(t) } +func (c *kcpServer) ShardNames() []string { + return []string{corev1alpha1.RootShard} +} + // RawConfig exposes a copy of the client config for this server. func (c *kcpServer) RawConfig() (clientcmdapi.Config, error) { c.lock.Lock() @@ -1117,6 +1122,10 @@ func (s *unmanagedKCPServer) ShardSystemMasterBaseConfig(t *testing.T, shard str return wrappedCfg } +func (s *unmanagedKCPServer) ShardNames() []string { + return sets.StringKeySet(s.shardCfgs).List() +} + func (s *unmanagedKCPServer) Artifact(t *testing.T, producer func() (runtime.Object, error)) { t.Helper() artifact(t, s, producer) diff --git a/test/e2e/framework/syncer.go b/test/e2e/framework/syncer.go index bb6a8266089..695511a8427 100644 --- a/test/e2e/framework/syncer.go +++ b/test/e2e/framework/syncer.go @@ -56,6 +56,7 @@ import ( "github.com/kcp-dev/kcp/pkg/syncer" "github.com/kcp-dev/kcp/pkg/syncer/shared" apiresourcev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apiresource/v1alpha1" + scheduling1alpha1 "github.com/kcp-dev/kcp/sdk/apis/scheduling/v1alpha1" tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1" conditionsv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/third_party/conditions/apis/conditions/v1alpha1" "github.com/kcp-dev/kcp/sdk/apis/third_party/conditions/util/conditions" @@ -259,6 +260,8 @@ func (sf *syncerFixture) CreateSyncTargetAndApplyToDownstream(t *testing.T) *app kcpClusterClient, err := kcpclientset.NewForConfig(upstreamCfg) require.NoError(t, err, "error creating upstream kcp client") + gather(upstreamClusterDynamic.Cluster(sf.syncTargetPath), workloadv1alpha1.SchemeGroupVersion.WithResource("synctargets")) + gather(upstreamClusterDynamic.Cluster(sf.syncTargetPath), scheduling1alpha1.SchemeGroupVersion.WithResource("locations")) gather(upstreamClusterDynamic.Cluster(sf.syncTargetPath), apiresourcev1alpha1.SchemeGroupVersion.WithResource("apiresourceimports")) gather(upstreamClusterDynamic.Cluster(sf.syncTargetPath), apiresourcev1alpha1.SchemeGroupVersion.WithResource("negotiatedapiresources")) gather(upstreamClusterDynamic.Cluster(sf.syncTargetPath), corev1.SchemeGroupVersion.WithResource("namespaces")) @@ -310,42 +313,27 @@ func (sf *syncerFixture) CreateSyncTargetAndApplyToDownstream(t *testing.T) *app ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - rawConfig, err := sf.upstreamServer.RawConfig() - require.NoError(t, err) - kcpClusterClient, err := kcpclientset.NewForConfig(syncerConfig.UpstreamConfig) require.NoError(t, err) - var virtualWorkspaceURL string var syncTargetClusterName logicalcluster.Name - Eventually(t, func() (success bool, reason string) { - syncTarget, err := kcpClusterClient.Cluster(syncerConfig.SyncTargetPath).WorkloadV1alpha1().SyncTargets().Get(ctx, syncerConfig.SyncTargetName, metav1.GetOptions{}) - require.NoError(t, err) - if len(syncTarget.Status.VirtualWorkspaces) != 1 { - return false, "" - } - virtualWorkspaceURL = syncTarget.Status.VirtualWorkspaces[0].SyncerURL - syncTargetClusterName = logicalcluster.From(syncTarget) - return true, "Virtual workspace URL is available" - }, wait.ForeverTestTimeout, 100*time.Millisecond, "Syncer Virtual Workspace URL not available") - - virtualWorkspaceRawConfig := rawConfig.DeepCopy() - virtualWorkspaceRawConfig.Clusters["syncer"] = rawConfig.Clusters["base"].DeepCopy() - virtualWorkspaceRawConfig.Clusters["syncer"].Server = virtualWorkspaceURL - virtualWorkspaceRawConfig.Contexts["syncer"] = rawConfig.Contexts["base"].DeepCopy() - virtualWorkspaceRawConfig.Contexts["syncer"].Cluster = "syncer" - virtualWorkspaceRawConfig.Clusters["upsyncer"] = rawConfig.Clusters["base"].DeepCopy() - virtualWorkspaceRawConfig.Clusters["upsyncer"].Server = strings.Replace(virtualWorkspaceURL, "/services/syncer/", "/services/upsyncer/", 1) - virtualWorkspaceRawConfig.Contexts["upsyncer"] = rawConfig.Contexts["base"].DeepCopy() - virtualWorkspaceRawConfig.Contexts["upsyncer"].Cluster = "upsyncer" - syncerVWConfig, err := clientcmd.NewNonInteractiveClientConfig(*virtualWorkspaceRawConfig, "syncer", nil, nil).ClientConfig() - require.NoError(t, err) - syncerVWConfig = rest.AddUserAgent(rest.CopyConfig(syncerVWConfig), t.Name()) - require.NoError(t, err) - upsyncerVWConfig, err := clientcmd.NewNonInteractiveClientConfig(*virtualWorkspaceRawConfig, "upsyncer", nil, nil).ClientConfig() - require.NoError(t, err) - upsyncerVWConfig = rest.AddUserAgent(rest.CopyConfig(upsyncerVWConfig), t.Name()) + syncTarget, err := kcpClusterClient.Cluster(syncerConfig.SyncTargetPath).WorkloadV1alpha1().SyncTargets().Get(ctx, syncerConfig.SyncTargetName, metav1.GetOptions{}) require.NoError(t, err) + syncTargetClusterName = logicalcluster.From(syncTarget) + + getVWURLs := func(toURL func(workloadv1alpha1.VirtualWorkspace) string) func() []string { + return func() []string { + syncTarget, err := kcpClusterClient.Cluster(syncerConfig.SyncTargetPath).WorkloadV1alpha1().SyncTargets().Get(ctx, syncerConfig.SyncTargetName, metav1.GetOptions{}) + require.NoError(t, err) + + var urls []string + for _, vw := range syncTarget.Status.VirtualWorkspaces { + urls = append(urls, toURL(vw)) + } + return urls + } + } + return &appliedSyncerFixture{ syncerFixture: *sf, @@ -356,8 +344,8 @@ func (sf *syncerFixture) CreateSyncTargetAndApplyToDownstream(t *testing.T) *app DownstreamKubeClient: downstreamKubeClient, DownstreamKubeconfigPath: downstreamKubeconfigPath, - SyncerVirtualWorkspaceConfig: syncerVWConfig, - UpsyncerVirtualWorkspaceConfig: upsyncerVWConfig, + GetSyncerVirtualWorkspaceURLs: getVWURLs(func(vw workloadv1alpha1.VirtualWorkspace) string { return vw.SyncerURL }), + GetUpsyncerVirtualWorkspaceURLs: getVWURLs(func(vw workloadv1alpha1.VirtualWorkspace) string { return vw.UpsyncerURL }), } } @@ -571,8 +559,8 @@ type appliedSyncerFixture struct { DownstreamKubeClient kubernetesclient.Interface DownstreamKubeconfigPath string - SyncerVirtualWorkspaceConfig *rest.Config - UpsyncerVirtualWorkspaceConfig *rest.Config + GetSyncerVirtualWorkspaceURLs func() []string + GetUpsyncerVirtualWorkspaceURLs func() []string stopHeartBeat context.CancelFunc stopSyncerTunnel context.CancelFunc diff --git a/test/e2e/reconciler/deployment/deployment_coordinator_test.go b/test/e2e/reconciler/deployment/deployment_coordinator_test.go index f2f0894bf16..fe72a3172bd 100644 --- a/test/e2e/reconciler/deployment/deployment_coordinator_test.go +++ b/test/e2e/reconciler/deployment/deployment_coordinator_test.go @@ -210,7 +210,7 @@ func TestDeploymentCoordinator(t *testing.T) { } }, wait.ForeverTestTimeout, time.Millisecond*100, "should create the deployment after the deployments resource is available in workspace %q", workspace.clusterName) - t.Logf("Wait for the workload in workspace %q to be started and available with 4 replicas", workspace.clusterName) + t.Logf("Wait for the workload in workspace %q to be started and available with %d replicas", workspace.clusterName, workspace.requestedReplicas) func() { defer dumpEventsAndPods(wkspDownstreamInfo) diff --git a/test/e2e/reconciler/scheduling/upsynced_scheduling_test.go b/test/e2e/reconciler/scheduling/upsynced_scheduling_test.go index 023224dedae..1dbc9e86b39 100644 --- a/test/e2e/reconciler/scheduling/upsynced_scheduling_test.go +++ b/test/e2e/reconciler/scheduling/upsynced_scheduling_test.go @@ -30,6 +30,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/rest" "github.com/kcp-dev/kcp/sdk/apis/third_party/conditions/util/conditions" workloadv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/workload/v1alpha1" @@ -124,7 +125,15 @@ func TestUpsyncedScheduling(t *testing.T) { } // Create a client that uses the upsyncer URL - upsyncerKCPClient, err := kcpkubernetesclientset.NewForConfig(syncerFixture.UpsyncerVirtualWorkspaceConfig) + upsyncerVirtualWorkspaceConfig := rest.CopyConfig(upstreamConfig) + var upsyncerVirtualWorkspaceURL string + framework.Eventually(t, func() (found bool, message string) { + upsyncerVirtualWorkspaceURL, found, err = framework.VirtualWorkspaceURL(ctx, upstreamKcpClient, userWs, syncerFixture.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + upsyncerVirtualWorkspaceConfig.Host = upsyncerVirtualWorkspaceURL + upsyncerKCPClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVirtualWorkspaceConfig) require.NoError(t, err) _, err = upsyncerKCPClient.Cluster(userWsName.Path()).CoreV1().Pods(upstreamNamespace.Name).Create(ctx, &pod, metav1.CreateOptions{}) diff --git a/test/e2e/syncer/tunnels_test.go b/test/e2e/syncer/tunnels_test.go index c4465099a33..5587cf39300 100644 --- a/test/e2e/syncer/tunnels_test.go +++ b/test/e2e/syncer/tunnels_test.go @@ -36,6 +36,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "github.com/kcp-dev/kcp/pkg/syncer/shared" workloadv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/workload/v1alpha1" @@ -377,7 +378,15 @@ func TestSyncerTunnelFilter(t *testing.T) { require.NoError(t, err) // Create a pod on the upstream namespace that looks like the downstream pod being upsynced. - upsyncedClient, err := kcpkubernetesclientset.NewForConfig(syncerFixture.UpsyncerVirtualWorkspaceConfig) + upsyncerVirtualWorkspaceConfig := rest.CopyConfig(kcpServer.BaseConfig(t)) + var upsyncerVirtualWorkspaceURL string + framework.Eventually(t, func() (found bool, message string) { + upsyncerVirtualWorkspaceURL, found, err = framework.VirtualWorkspaceURL(ctx, kcpClient, userWs, syncerFixture.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + upsyncerVirtualWorkspaceConfig.Host = upsyncerVirtualWorkspaceURL + upsyncedClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVirtualWorkspaceConfig) require.NoError(t, err) upsyncedPod, err := upsyncedClient.CoreV1().Pods().Cluster(userWsName.Path()).Namespace(upstreamNs.Name).Create(ctx, &corev1.Pod{ diff --git a/test/e2e/virtual/syncer/virtualworkspace_test.go b/test/e2e/virtual/syncer/virtualworkspace_test.go index ce88b7af1d5..13d2fb945e1 100644 --- a/test/e2e/virtual/syncer/virtualworkspace_test.go +++ b/test/e2e/virtual/syncer/virtualworkspace_test.go @@ -45,6 +45,7 @@ import ( "github.com/kcp-dev/kcp/config/rootcompute" "github.com/kcp-dev/kcp/pkg/syncer/shared" schedulingv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/scheduling/v1alpha1" + tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1" workloadv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/workload/v1alpha1" kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster" kubefixtures "github.com/kcp-dev/kcp/test/e2e/fixtures/kube" @@ -211,6 +212,8 @@ func TestSyncerVirtualWorkspace(t *testing.T) { kubeClusterClient, err := kcpkubernetesclientset.NewForConfig(server.BaseConfig(t)) require.NoError(t, err) + kcpClusterClient, err := kcpclientset.NewForConfig(server.BaseConfig(t)) + require.NoError(t, err) wildwestClusterClient, err := wildwestclientset.NewForConfig(server.BaseConfig(t)) require.NoError(t, err) @@ -222,6 +225,10 @@ func TestSyncerVirtualWorkspace(t *testing.T) { name: "isolated API domains per syncer", work: func(t *testing.T, testCaseWorkspace logicalcluster.Path) { t.Helper() + + ctx, cancelFunc := context.WithCancel(context.Background()) + t.Cleanup(cancelFunc) + kubelikeLocationWorkspacePath, kubelikeLocationWorkspace := framework.NewWorkspaceFixture(t, server, testCaseWorkspace, framework.WithName("kubelike-locations"), framework.TODO_WithoutMultiShardSupport()) kubelikeLocationWorkspaceClusterName := logicalcluster.Name(kubelikeLocationWorkspace.Spec.Cluster) logWithTimestampf(t, "Deploying syncer into workspace %s", kubelikeLocationWorkspacePath) @@ -265,17 +272,21 @@ func TestSyncerVirtualWorkspace(t *testing.T) { }), ).CreateSyncTargetAndApplyToDownstream(t).StartAPIImporter(t).StartHeartBeat(t) - kubelikeVWDiscoverClusterClient, err := kcpdiscovery.NewForConfig(kubelikeSyncer.SyncerVirtualWorkspaceConfig) - require.NoError(t, err) - // We need to get a resource in the "root:compute" cluster to get the logical cluster name, in this case we use the // kubernetes APIExport, as we know that it exists. - kcpClusterClient, err := kcpclientset.NewForConfig(server.BaseConfig(t)) - require.NoError(t, err) export, err := kcpClusterClient.Cluster(rootcompute.RootComputeClusterName).ApisV1alpha1().APIExports().Get(context.Background(), "kubernetes", metav1.GetOptions{}) require.NoError(t, err) rootComputeLogicalCluster := logicalcluster.From(export) + kubelikeVWDiscoverConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + kubelikeVWDiscoverConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, kubelikeLocationWorkspace, kubelikeSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + kubelikeVWDiscoverClusterClient, err := kcpdiscovery.NewForConfig(kubelikeVWDiscoverConfig) + require.NoError(t, err) + logWithTimestampf(t, "Check discovery in kubelike virtual workspace") framework.Eventually(t, func() (bool, string) { _, kubelikeAPIResourceLists, err := kubelikeVWDiscoverClusterClient.ServerGroupsAndResources() @@ -288,8 +299,15 @@ func TestSyncerVirtualWorkspace(t *testing.T) { return len(diff) == 0, diff }, wait.ForeverTestTimeout, time.Millisecond*100) + wildwestVWDiscoverConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWDiscoverConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, wildwestLocationWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + wildwestVWDiscoverClusterClient, err := kcpdiscovery.NewForConfig(wildwestVWDiscoverConfig) + logWithTimestampf(t, "Check discovery in wildwest virtual workspace") - wildwestVWDiscoverClusterClient, err := kcpdiscovery.NewForConfig(wildwestSyncer.SyncerVirtualWorkspaceConfig) require.NoError(t, err) framework.Eventually(t, func() (bool, string) { _, wildwestAPIResourceLists, err := wildwestVWDiscoverClusterClient.ServerGroupsAndResources() @@ -335,7 +353,7 @@ func TestSyncerVirtualWorkspace(t *testing.T) { ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - wildwestLocationPath, _ := framework.NewWorkspaceFixture(t, server, testCaseWorkspace, framework.WithName("wildwest-locations"), framework.TODO_WithoutMultiShardSupport()) + wildwestLocationPath, wildwestLocationWorkspace := framework.NewWorkspaceFixture(t, server, testCaseWorkspace, framework.WithName("wildwest-locations"), framework.TODO_WithoutMultiShardSupport()) logWithTimestampf(t, "Deploying syncer into workspace %s", wildwestLocationPath) wildwestSyncer := framework.NewSyncerFixture(t, server, wildwestLocationPath, @@ -381,9 +399,15 @@ func TestSyncerVirtualWorkspace(t *testing.T) { return token1 != "" && token2 != "", fmt.Sprintf("token1=%q - token2=%q", token1, token2) }, wait.ForeverTestTimeout, time.Millisecond*100, "token secret for default service account not created") - configUser1 := framework.ConfigWithToken(token1, wildwestSyncer.SyncerVirtualWorkspaceConfig) + wildwestVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, wildwestLocationWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") - configUser2 := framework.ConfigWithToken(token2, wildwestSyncer.SyncerVirtualWorkspaceConfig) + configUser1 := framework.ConfigWithToken(token1, wildwestVWConfig) + configUser2 := framework.ConfigWithToken(token2, wildwestVWConfig) vwClusterClientUser1, err := wildwestclientset.NewForConfig(configUser1) require.NoError(t, err) @@ -503,7 +527,13 @@ func TestSyncerVirtualWorkspace(t *testing.T) { }, metav1.CreateOptions{}) require.NoError(t, err) - vwClusterClient, err := wildwestclientset.NewForConfig(wildwestSyncer.SyncerVirtualWorkspaceConfig) + wildwestVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, wildwestLocationWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwClusterClient, err := wildwestclientset.NewForConfig(wildwestVWConfig) require.NoError(t, err) logWithTimestampf(t, "Verify there is one cowboy via direct access") @@ -655,7 +685,13 @@ func TestSyncerVirtualWorkspace(t *testing.T) { }, metav1.CreateOptions{}) require.NoError(t, err) - vwClusterClient, err := wildwestclientset.NewForConfig(wildwestSyncer.SyncerVirtualWorkspaceConfig) + wildwestVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwClusterClient, err := wildwestclientset.NewForConfig(wildwestVWConfig) require.NoError(t, err) logWithTimestampf(t, "Verify there is one cowboy via direct access") @@ -892,10 +928,22 @@ func TestSyncerVirtualWorkspace(t *testing.T) { }, metav1.CreateOptions{}) require.NoError(t, err) - vwNorthClusterClient, err := wildwestclientset.NewForConfig(wildwestNorthSyncer.SyncerVirtualWorkspaceConfig) + wildwestNorthVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestNorthVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestNorthSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwNorthClusterClient, err := wildwestclientset.NewForConfig(wildwestNorthVWConfig) require.NoError(t, err) - vwSouthClusterClient, err := wildwestclientset.NewForConfig(wildwestSouthSyncer.SyncerVirtualWorkspaceConfig) + wildwestSouthVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestSouthVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestSouthSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwSouthClusterClient, err := wildwestclientset.NewForConfig(wildwestSouthVWConfig) require.NoError(t, err) logWithTimestampf(t, "Verify there is one cowboy via direct access") @@ -1103,9 +1151,21 @@ func TestSyncerVirtualWorkspace(t *testing.T) { return true, "" }, wait.ForeverTestTimeout, time.Millisecond*100) - vwNorthClusterClient, err := wildwestclientset.NewForConfig(wildwestNorthSyncer.SyncerVirtualWorkspaceConfig) + wildwestNorthVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestNorthVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestNorthSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwNorthClusterClient, err := wildwestclientset.NewForConfig(wildwestNorthVWConfig) require.NoError(t, err) - vwSouthClusterClient, err := wildwestclientset.NewForConfig(wildwestSouthSyncer.SyncerVirtualWorkspaceConfig) + wildwestSouthVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestSouthVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestSouthSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwSouthClusterClient, err := wildwestclientset.NewForConfig(wildwestSouthVWConfig) require.NoError(t, err) logWithTimestampf(t, "Wait until the north virtual workspace has the resource type") @@ -1375,7 +1435,13 @@ func TestSyncerVirtualWorkspace(t *testing.T) { require.NoError(t, err) require.Len(t, kcpCowboys.Items, 1) - vwClusterClient, err := wildwestclientset.NewForConfig(wildwestSyncer.SyncerVirtualWorkspaceConfig) + wildwestVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwClusterClient, err := wildwestclientset.NewForConfig(wildwestVWConfig) require.NoError(t, err) logWithTimestampf(t, "Wait until the virtual workspace has the resource") @@ -1475,7 +1541,13 @@ func TestSyncerVirtualWorkspace(t *testing.T) { }, metav1.CreateOptions{}) require.NoError(t, err) - vwClusterClient, err := wildwestclientset.NewForConfig(wildwestSyncer.SyncerVirtualWorkspaceConfig) + wildwestVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + wildwestVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, consumerWorkspace, wildwestSyncer.GetSyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Syncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Syncer virtual workspace URL not found") + vwClusterClient, err := wildwestclientset.NewForConfig(wildwestVWConfig) require.NoError(t, err) logWithTimestampf(t, "Verify there is one cowboy via direct access") @@ -1595,19 +1667,28 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { kubeClusterClient, err := kcpkubernetesclientset.NewForConfig(server.BaseConfig(t)) require.NoError(t, err) + kcpClusterClient, err := kcpclientset.NewForConfig(server.BaseConfig(t)) + require.NoError(t, err) + var testCases = []struct { name string - work func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) + work func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) }{ { name: "list kcp resources through upsyncer virtual workspace", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) pv := &corev1.PersistentVolume{ @@ -1645,13 +1726,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "create a persistentvolume in kcp through upsyncer virtual workspace", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) pv := &corev1.PersistentVolume{ @@ -1692,13 +1779,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "create a persistentvolume in kcp through upsyncer virtual workspace with a resource transformation", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) pv := &corev1.PersistentVolume{ @@ -1738,13 +1831,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "try to create a persistentvolume in kcp through upsyncer virtual workspace, without the statelabel set to Upsync, should fail", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) pv := &corev1.PersistentVolume{ @@ -1774,13 +1873,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "update a persistentvolume in kcp through upsyncer virtual workspace", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) logWithTimestampf(t, "Creating a persistentvolume in the kubelike source cluster...") @@ -1827,13 +1932,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "update a persistentvolume in kcp through upsyncer virtual workspace, try to remove the upsync state label, expect error.", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) logWithTimestampf(t, "Creating a persistentvolume in the kubelike source cluster...") @@ -1883,13 +1994,19 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { }, { name: "Delete a persistentvolume in kcp through upsyncer virtual workspace", - work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, path logicalcluster.Path, syncTargetKey string) { + work: func(t *testing.T, syncer *framework.StartedSyncerFixture, clusterName logicalcluster.Name, ws *tenancyv1alpha1.Workspace, path logicalcluster.Path, syncTargetKey string) { t.Helper() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) - kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(syncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, ws, syncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeSyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) logWithTimestampf(t, "Creating a persistentvolume in the kubelike source cluster...") @@ -1973,7 +2090,13 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { return true, "" }, wait.ForeverTestTimeout, time.Millisecond*100) - kubelikeUpsyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncer.UpsyncerVirtualWorkspaceConfig) + upsyncerVWConfig := rest.CopyConfig(server.BaseConfig(t)) + framework.Eventually(t, func() (found bool, message string) { + upsyncerVWConfig.Host, found, err = framework.VirtualWorkspaceURL(ctx, kcpClusterClient, upsyncerWS, upsyncer.GetUpsyncerVirtualWorkspaceURLs()) + require.NoError(t, err) + return found, "Upsyncer virtual workspace URL not found" + }, wait.ForeverTestTimeout, time.Millisecond*100, "Upsyncer virtual workspace URL not found") + kubelikeUpsyncerVWClient, err := kcpkubernetesclientset.NewForConfig(upsyncerVWConfig) require.NoError(t, err) logWithTimestampf(t, "Waiting for the persistentvolumes to be available in the upsyncer virtual workspace...") @@ -1988,7 +2111,7 @@ func TestUpsyncerVirtualWorkspace(t *testing.T) { syncTargetKey := upsyncer.ToSyncTargetKey() logWithTimestampf(t, "Starting test...") - testCase.work(t, upsyncer, upsyncerClusterName, upsyncerPath, syncTargetKey) + testCase.work(t, upsyncer, upsyncerClusterName, upsyncerWS, upsyncerPath, syncTargetKey) }) } }