diff --git a/test/framework/cluster_proxy.go b/test/framework/cluster_proxy.go index b1fe5b8e9f2b..843a97c3ba66 100644 --- a/test/framework/cluster_proxy.go +++ b/test/framework/cluster_proxy.go @@ -24,10 +24,12 @@ import ( "os" "path" goruntime "runtime" + "time" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -41,6 +43,11 @@ import ( "sigs.k8s.io/cluster-api/test/infrastructure/container" ) +const ( + retryableOperationInterval = 3 * time.Second + retryableOperationTimeout = 1 * time.Minute +) + // ClusterProxy defines the behavior of a type that acts as an intermediary with an existing Kubernetes cluster. // It should work with any Kubernetes cluster, no matter if the Cluster was created by a bootstrap.ClusterProvider, // by Cluster API (a workload cluster or a self-hosted cluster) or else. @@ -168,8 +175,18 @@ func (p *clusterProxy) GetScheme() *runtime.Scheme { func (p *clusterProxy) GetClient() client.Client { config := p.GetRESTConfig() - c, err := client.New(config, client.Options{Scheme: p.scheme}) - Expect(err).ToNot(HaveOccurred(), "Failed to get controller-runtime client") + var c client.Client + var newClientErr error + err := wait.PollImmediate(retryableOperationInterval, retryableOperationTimeout, func() (bool, error) { + c, newClientErr = client.New(config, client.Options{Scheme: p.scheme}) + if newClientErr != nil { + return false, nil //nolint:nilerr + } + return true, nil + }) + errorString := "Failed to get controller-runtime client" + Expect(newClientErr).ToNot(HaveOccurred(), errorString) + Expect(err).ToNot(HaveOccurred(), errorString) return c }