@@ -27,6 +27,7 @@ import (
2727 "github.com/spf13/cobra"
2828
2929 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+ "k8s.io/apimachinery/pkg/runtime/schema"
3031 "k8s.io/apimachinery/pkg/util/wait"
3132 "k8s.io/cli-runtime/pkg/genericclioptions"
3233 "k8s.io/client-go/rest"
@@ -35,6 +36,9 @@ import (
3536
3637 "github.com/kcp-dev/kcp/cli/pkg/base"
3738 pluginhelpers "github.com/kcp-dev/kcp/cli/pkg/helpers"
39+ apishelpers "github.com/kcp-dev/kcp/cli/pkg/helpers/apis/apis"
40+ "github.com/kcp-dev/kcp/sdk/apis/apis"
41+ apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
3842 apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
3943 kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
4044)
@@ -143,77 +147,114 @@ func (b *BindOptions) Run(ctx context.Context) error {
143147 return err
144148 }
145149
146- path , apiExportName := logicalcluster .NewPath (b .APIExportRef ).Split ()
147-
148- // if a custom name is not provided, default it to <apiExportname>.
149- apiBindingName := b .APIBindingName
150- if apiBindingName == "" {
151- apiBindingName = apiExportName
152- }
153-
154150 _ , currentClusterName , err := pluginhelpers .ParseClusterURL (config .Host )
155151 if err != nil {
156152 return fmt .Errorf ("current URL %q does not point to workspace" , config .Host )
157153 }
158154
159- binding := & apisv1alpha2.APIBinding {
160- ObjectMeta : metav1.ObjectMeta {
161- Name : apiBindingName ,
162- },
163- Spec : apisv1alpha2.APIBindingSpec {
164- Reference : apisv1alpha2.BindingReference {
165- Export : & apisv1alpha2.ExportBindingReference {
166- Path : path .String (),
167- Name : apiExportName ,
168- },
169- },
170- },
155+ preferredAPIBindingVersion , err := pluginhelpers .PreferredVersion (config , schema.GroupResource {
156+ Group : apis .GroupName ,
157+ Resource : "apibindings" ,
158+ })
159+ if err != nil {
160+ return fmt .Errorf ("service discovery failed: %w" , err )
171161 }
172162
173- if len (b .acceptedPermissionClaims ) > 0 {
174- binding .Spec .PermissionClaims = b .acceptedPermissionClaims
175- }
176- if len (b .rejectedPermissionClaims ) > 0 {
177- binding .Spec .PermissionClaims = append (binding .Spec .PermissionClaims , b .rejectedPermissionClaims ... )
163+ apiBinding , err := b .newAPIBinding (preferredAPIBindingVersion )
164+ if err != nil {
165+ return fmt .Errorf ("failed to create APIBinding: %w" , err )
178166 }
179167
180- kcpclient , err := newKCPClusterClient (config )
168+ kcpClusterClient , err := newKCPClusterClient (config )
181169 if err != nil {
182170 return err
183171 }
184172
185- createdBinding , err := kcpclient .Cluster (currentClusterName ).ApisV1alpha2 ().APIBindings ().Create (ctx , binding , metav1.CreateOptions {})
186- if err != nil {
187- return err
173+ if err := apiBinding .Create (ctx , kcpClusterClient .Cluster (currentClusterName )); err != nil {
174+ return fmt .Errorf ("failed to create APIBinding: %w" , err )
188175 }
189176
190- if _ , err := fmt .Fprintf (b .Out , "apibinding %s created. Waiting to successfully bind ...\n " , binding .Name ); err != nil {
177+ if _ , err := fmt .Fprintf (b .Out , "apibinding %s created. Waiting to successfully bind ...\n " , apiBinding .Name () ); err != nil {
191178 return err
192179 }
193180
194181 // wait for phase to be bound
195- if createdBinding .Status .Phase != apisv1alpha2 .APIBindingPhaseBound {
196- if err := wait .PollUntilContextTimeout (ctx , time .Millisecond * 500 , b .BindWaitTimeout , true , func (ctx context.Context ) (done bool , err error ) {
197- createdBinding , err := kcpclient .Cluster (currentClusterName ).ApisV1alpha2 ().APIBindings ().Get (ctx , binding .Name , metav1.GetOptions {})
198- if err != nil {
182+ if ! apiBinding .IsBound () {
183+ if err := wait .PollUntilContextTimeout (ctx , time .Millisecond * 500 , b .BindWaitTimeout , true , func (ctx context.Context ) (bool , error ) {
184+ if err := apiBinding .Refresh (ctx , kcpClusterClient .Cluster (currentClusterName )); err != nil {
199185 return false , err
200186 }
201- if createdBinding .Status .Phase == apisv1alpha2 .APIBindingPhaseBound {
202- return true , nil
203- }
204- return false , nil
187+
188+ return apiBinding .IsBound (), nil
205189 }); err != nil {
206- return fmt .Errorf ("could not bind %s: %w" , binding .Name , err )
190+ return fmt .Errorf ("could not bind %s: %w" , apiBinding .Name () , err )
207191 }
208192 }
209193
210- if _ , err := fmt .Fprintf (b .Out , "%s created and bound.\n " , binding .Name ); err != nil {
194+ if _ , err := fmt .Fprintf (b .Out , "%s created and bound.\n " , apiBinding .Name () ); err != nil {
211195 return err
212196 }
213197
214198 return nil
215199}
216200
201+ func (b * BindOptions ) newAPIBinding (preferredAPIBindingVersion string ) (apishelpers.APIBinding , error ) {
202+ path , apiExportName := logicalcluster .NewPath (b .APIExportRef ).Split ()
203+
204+ // if a custom name is not provided, default it to <apiExportname>.
205+ apiBindingName := b .APIBindingName
206+ if apiBindingName == "" {
207+ apiBindingName = apiExportName
208+ }
209+
210+ var binding apishelpers.APIBinding
211+
212+ switch preferredAPIBindingVersion {
213+ case "v1alpha2" :
214+ binding = apishelpers .NewAPIBinding (& apisv1alpha2.APIBinding {
215+ ObjectMeta : metav1.ObjectMeta {
216+ Name : apiBindingName ,
217+ },
218+ Spec : apisv1alpha2.APIBindingSpec {
219+ Reference : apisv1alpha2.BindingReference {
220+ Export : & apisv1alpha2.ExportBindingReference {
221+ Path : path .String (),
222+ Name : apiExportName ,
223+ },
224+ },
225+ },
226+ })
227+
228+ case "v1alpha1" :
229+ binding = apishelpers .NewAPIBinding (& apisv1alpha1.APIBinding {
230+ ObjectMeta : metav1.ObjectMeta {
231+ Name : apiBindingName ,
232+ },
233+ Spec : apisv1alpha1.APIBindingSpec {
234+ Reference : apisv1alpha1.BindingReference {
235+ Export : & apisv1alpha1.ExportBindingReference {
236+ Path : path .String (),
237+ Name : apiExportName ,
238+ },
239+ },
240+ },
241+ })
242+
243+ default :
244+ return nil , fmt .Errorf ("%s is not supported by this plugin" , preferredAPIBindingVersion )
245+ }
246+
247+ claims := []apisv1alpha2.AcceptablePermissionClaim {}
248+ claims = append (claims , b .acceptedPermissionClaims ... )
249+ claims = append (claims , b .rejectedPermissionClaims ... )
250+
251+ if err := binding .SetPermissionClaims (claims ); err != nil {
252+ return nil , fmt .Errorf ("invalid permission claims: %w" , err )
253+ }
254+
255+ return binding , nil
256+ }
257+
217258func (b * BindOptions ) parsePermissionClaim (claim string , accepted bool ) error {
218259 claimParts := strings .SplitN (claim , "." , 2 )
219260 if len (claimParts ) != 2 {
0 commit comments