Skip to content

Commit 0ce8c8a

Browse files
committed
add path annotation to apibindings
On-behalf-of: @SAP [email protected] Signed-off-by: Mangirdas Judeikis <[email protected]>
1 parent fa4e118 commit 0ce8c8a

File tree

5 files changed

+37
-1
lines changed

5 files changed

+37
-1
lines changed

pkg/admission/apibinding/apibinding_admission.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ import (
4242
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
4343
"github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2/permissionclaims"
4444
"github.com/kcp-dev/kcp/sdk/apis/core"
45+
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
4546
kcpinformers "github.com/kcp-dev/kcp/sdk/client/informers/externalversions"
47+
corev1alpha1listers "github.com/kcp-dev/kcp/sdk/client/listers/core/v1alpha1"
4648
)
4749

4850
const (
@@ -69,6 +71,11 @@ type apiBindingAdmission struct {
6971

7072
getAPIExport func(path logicalcluster.Path, name string) (*apisv1alpha2.APIExport, error)
7173

74+
logicalClusterLister corev1alpha1listers.LogicalClusterClusterLister
75+
// getLogicalCluster is a convenience function for easier unit testing,
76+
// it reads a LogicalCluster resource with the given name and from the given cluster.
77+
getLogicalCluster func(clusterName logicalcluster.Name, name string) (*corev1alpha1.LogicalCluster, error)
78+
7279
apiExportIndexer cache.Indexer
7380
cacheAPIExportIndexer cache.Indexer
7481

@@ -324,6 +331,15 @@ func (o *apiBindingAdmission) SetKcpInformers(local, global kcpinformers.SharedI
324331
o.apiExportIndexer = local.Apis().V1alpha2().APIExports().Informer().GetIndexer()
325332
o.cacheAPIExportIndexer = global.Apis().V1alpha2().APIExports().Informer().GetIndexer()
326333

334+
logicalClusterReady := local.Core().V1alpha1().LogicalClusters().Informer().HasSynced
335+
o.SetReadyFunc(func() bool {
336+
return logicalClusterReady()
337+
})
338+
o.logicalClusterLister = local.Core().V1alpha1().LogicalClusters().Lister()
339+
o.getLogicalCluster = func(clusterName logicalcluster.Name, name string) (*corev1alpha1.LogicalCluster, error) {
340+
return o.logicalClusterLister.Cluster(clusterName).Get(name)
341+
}
342+
327343
indexers.AddIfNotPresentOrDie(local.Tenancy().V1alpha1().WorkspaceTypes().Informer().GetIndexer(), cache.Indexers{
328344
indexers.ByLogicalClusterPathAndName: indexers.IndexByLogicalClusterPathAndName,
329345
})

pkg/admission/apibinding/apibinding_interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type apiBinding interface {
3030
Validate() field.ErrorList
3131
ValidateUpdate(oldBinding apiBinding) field.ErrorList
3232
ToUnstructured() (map[string]interface{}, error)
33+
GetAnnotations() map[string]string
3334
}
3435

3536
type bindingReference interface {

pkg/admission/apibinding/apibinding_v1alpha1.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func (b *apiBindingV1alpha1) SetLabels(labels map[string]string) {
5252
b.binding.Labels = labels
5353
}
5454

55+
func (b apiBindingV1alpha1) GetAnnotations() map[string]string {
56+
return b.binding.Annotations
57+
}
58+
5559
func (b *apiBindingV1alpha1) Validate() field.ErrorList {
5660
return apisv1alpha1.ValidateAPIBinding(b.binding)
5761
}

pkg/admission/apibinding/apibinding_v1alpha2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func (b *apiBindingV1alpha2) SetLabels(labels map[string]string) {
5252
b.binding.Labels = labels
5353
}
5454

55+
func (b apiBindingV1alpha2) GetAnnotations() map[string]string {
56+
return b.binding.Annotations
57+
}
58+
5559
func (b apiBindingV1alpha2) Validate() field.ErrorList {
5660
return apisv1alpha2.ValidateAPIBinding(b.binding)
5761
}

pkg/admission/pathannotation/pathannotation_admission.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"io"
23+
"strings"
2324

2425
apierrors "k8s.io/apimachinery/pkg/api/errors"
2526
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -69,6 +70,7 @@ type pathAnnotationPlugin struct {
6970

7071
var pathAnnotationResources = sets.New[string](
7172
apisv1alpha2.Resource("apiexports").String(),
73+
apisv1alpha2.Resource("apibindings").String(),
7274
tenancyv1alpha1.Resource("workspacetypes").String(),
7375
)
7476

@@ -105,6 +107,10 @@ func (p *pathAnnotationPlugin) Admit(ctx context.Context, a admission.Attributes
105107

106108
logicalCluster, err := p.getLogicalCluster(clusterName, corev1alpha1.LogicalClusterName)
107109
if err != nil {
110+
// We skip adding annotation if the logical cluster is not found during creation of apibindings. This is racy during workspace bootstrap.
111+
if apierrors.IsNotFound(err) && (a.GetResource().GroupResource() == apisv1alpha2.Resource("apibindings") && strings.Contains(a.GetName(), "kcp.io")) {
112+
return nil
113+
}
108114
return admission.NewForbidden(a, fmt.Errorf("cannot get this workspace: %w", err))
109115
}
110116
thisPath := logicalCluster.Annotations[core.LogicalClusterPathAnnotationKey]
@@ -133,7 +139,12 @@ func (p *pathAnnotationPlugin) Validate(ctx context.Context, a admission.Attribu
133139
return nil
134140
}
135141

136-
if a.GetResource().GroupResource() == corev1alpha1.Resource("logicalclusters") {
142+
// We don't validate LogicalCluster resources themselves.
143+
// In addition, we skip validation for apibindings whose name contains "kcp.io" (system bindings),
144+
// as during bootstrap of the workspace its racy with creation of the LogicalCluster resource.
145+
// They will be eventually labeled, it will just takes a bit longer.
146+
if a.GetResource().GroupResource() == corev1alpha1.Resource("logicalclusters") ||
147+
(a.GetResource().GroupResource() == apisv1alpha2.Resource("apibindings") && strings.Contains(a.GetName(), "kcp.io")) {
137148
return nil
138149
}
139150

0 commit comments

Comments
 (0)