@@ -20,6 +20,7 @@ import (
2020 "context"
2121 "fmt"
2222 "strings"
23+ "time"
2324
2425 authzv1 "k8s.io/api/authorization/v1"
2526 corev1 "k8s.io/api/core/v1"
@@ -30,6 +31,7 @@ import (
3031 "k8s.io/apimachinery/pkg/labels"
3132 "k8s.io/apimachinery/pkg/runtime/schema"
3233 "k8s.io/apimachinery/pkg/types"
34+ "k8s.io/apimachinery/pkg/util/wait"
3335 authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
3436 "k8s.io/klog/v2"
3537 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -173,6 +175,72 @@ func (m *Manager) HandleResources(
173175 }, nil
174176}
175177
178+ // CreateAPIServiceExportRequest creates an APIServiceExportRequest in the given namespace
179+ // on the provider cluster and waits for it to be reconciled (Succeeded or Failed).
180+ func (m * Manager ) CreateAPIServiceExportRequest (
181+ ctx context.Context ,
182+ cluster , namespace , name string ,
183+ spec kubebindv1alpha2.APIServiceExportRequestSpec ,
184+ ) (* kubebindv1alpha2.APIServiceExportRequest , error ) {
185+ logger := klog .FromContext (ctx ).WithValues ("namespace" , namespace , "name" , name )
186+
187+ cl , err := m .manager .GetCluster (ctx , cluster )
188+ if err != nil {
189+ return nil , fmt .Errorf ("failed to get cluster client: %w" , err )
190+ }
191+ c := cl .GetClient ()
192+
193+ exportRequest := & kubebindv1alpha2.APIServiceExportRequest {
194+ ObjectMeta : metav1.ObjectMeta {
195+ Name : name ,
196+ Namespace : namespace ,
197+ },
198+ Spec : spec ,
199+ }
200+
201+ // Create the APIServiceExportRequest, handling name conflicts
202+ if err := c .Create (ctx , exportRequest ); err != nil {
203+ if ! errors .IsAlreadyExists (err ) {
204+ return nil , fmt .Errorf ("failed to create APIServiceExportRequest: %w" , err )
205+ }
206+ // Name conflict: use generateName
207+ exportRequest .Name = ""
208+ exportRequest .GenerateName = name + "-"
209+ if err := c .Create (ctx , exportRequest ); err != nil {
210+ return nil , fmt .Errorf ("failed to create APIServiceExportRequest with generated name: %w" , err )
211+ }
212+ }
213+
214+ createdName := exportRequest .Name
215+ logger = logger .WithValues ("createdName" , createdName )
216+ logger .Info ("Created APIServiceExportRequest, waiting for reconciliation" )
217+
218+ // Poll until reconciled
219+ var result * kubebindv1alpha2.APIServiceExportRequest
220+ if err := wait .PollUntilContextTimeout (ctx , 1 * time .Second , 60 * time .Second , true , func (ctx context.Context ) (bool , error ) {
221+ req := & kubebindv1alpha2.APIServiceExportRequest {}
222+ if err := c .Get (ctx , types.NamespacedName {Namespace : namespace , Name : createdName }, req ); err != nil {
223+ if errors .IsNotFound (err ) {
224+ return false , fmt .Errorf ("APIServiceExportRequest %s was deleted" , createdName )
225+ }
226+ return false , err
227+ }
228+ if req .Status .Phase == kubebindv1alpha2 .APIServiceExportRequestPhaseSucceeded {
229+ result = req
230+ return true , nil
231+ }
232+ if req .Status .Phase == kubebindv1alpha2 .APIServiceExportRequestPhaseFailed {
233+ return false , fmt .Errorf ("APIServiceExportRequest failed: %s" , req .Status .TerminalMessage )
234+ }
235+ return false , nil
236+ }); err != nil {
237+ return nil , fmt .Errorf ("waiting for APIServiceExportRequest: %w" , err )
238+ }
239+
240+ logger .Info ("APIServiceExportRequest reconciled successfully" )
241+ return result , nil
242+ }
243+
176244func (m * Manager ) ListCustomResourceDefinitions (ctx context.Context , cluster string , selector labels.Selector ) (* apiextensionsv1.CustomResourceDefinitionList , error ) {
177245 cl , err := m .manager .GetCluster (ctx , cluster )
178246 if err != nil {
0 commit comments