Skip to content

Commit 83b4315

Browse files
xmudriiembik
authored andcommitted
Correctly convert fields that have vanished from v1alpha2
On-behalf-of: SAP <[email protected]> Signed-off-by: Marvin Beckers <[email protected]>
1 parent 20642f1 commit 83b4315

File tree

3 files changed

+123
-29
lines changed

3 files changed

+123
-29
lines changed

sdk/apis/apis/v1alpha2/types_apibinding_conversion.go

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ const (
2929
AcceptablePermissionClaimsAnnotation = "apis.v1alpha2.kcp.io/acceptable-permission-claims"
3030
)
3131

32-
// v1alpha2 -> v1alpha1
32+
// v1alpha2 -> v1alpha1 conversions.
3333

3434
func Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding(in *APIBinding, out *apisv1alpha1.APIBinding, s kubeconversion.Scope) error {
3535
out.ObjectMeta = *in.ObjectMeta.DeepCopy()
3636

37+
// before converting the spec, figure out which PermissionClaims could not be represented in v1alpha1 and
38+
// retain them via an annotation
3739
_, overhangingAPC, err := Convert_v1alpha2_AcceptablePermissionClaims_To_v1alpha1_AcceptablePermissionClaims(in.Spec.PermissionClaims, s)
3840
if err != nil {
3941
return err
@@ -54,6 +56,8 @@ func Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding(in *APIBinding, out *api
5456
return err
5557
}
5658

59+
// after converting the spec, read the retained information from the annotation and update PermissionClaims
60+
// with All and ResourceSelectors that are not present in v1alpha2 (but saved in the annotation)
5761
if originalPermissionClaims, ok := in.Annotations[PermissionClaimsV1Alpha1Annotation]; ok {
5862
permissionClaims := []apisv1alpha1.AcceptablePermissionClaim{}
5963
if err := json.Unmarshal([]byte(originalPermissionClaims), &permissionClaims); err != nil {
@@ -63,6 +67,7 @@ func Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding(in *APIBinding, out *api
6367
for _, pc := range permissionClaims {
6468
for i, opc := range out.Spec.PermissionClaims {
6569
if pc.PermissionClaim.EqualGRI(opc.PermissionClaim) {
70+
out.Spec.PermissionClaims[i].All = pc.All
6671
out.Spec.PermissionClaims[i].ResourceSelector = pc.ResourceSelector
6772
}
6873
}
@@ -79,9 +84,12 @@ func Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding(in *APIBinding, out *api
7984
return Convert_v1alpha2_APIBindingStatus_To_v1alpha1_APIBindingStatus(&in.Status, &out.Status, s)
8085
}
8186

87+
// Convert_v1alpha2_AcceptablePermissionClaims_To_v1alpha1_AcceptablePermissionClaims converts v1alpha2.AcceptablePermissionClaims
88+
// to v1alpha1.AcceptablePermissionClaims. This is not a loseless conversion, verbs and selectors are lost in this conversion.
89+
// For loseless conversion use Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding.
8290
func Convert_v1alpha2_AcceptablePermissionClaims_To_v1alpha1_AcceptablePermissionClaims(in []AcceptablePermissionClaim, s kubeconversion.Scope) (out []apisv1alpha1.AcceptablePermissionClaim, overhanging []AcceptablePermissionClaim, err error) {
8391
for _, apc := range in {
84-
if len(apc.PermissionClaim.Verbs) == 1 && apc.PermissionClaim.Verbs[0] == "*" {
92+
if len(apc.PermissionClaim.Verbs) == 1 && apc.PermissionClaim.Verbs[0] == "*" && apc.Selector.MatchAll {
8593
var v1apc apisv1alpha1.AcceptablePermissionClaim
8694

8795
if err := Convert_v1alpha2_AcceptablePermissionClaim_To_v1alpha1_AcceptablePermissionClaim(&apc, &v1apc, s); err != nil {
@@ -97,8 +105,9 @@ func Convert_v1alpha2_AcceptablePermissionClaims_To_v1alpha1_AcceptablePermissio
97105
return
98106
}
99107

100-
// Convert_v1alpha2_AcceptablePermissionClaim_To_v1alpha1_AcceptablePermissionClaim converts v1alpha2.AcceptablePermissionClaim to v1alpha1.AcceptablePermissionClaim.
101-
// This is not a lossless conversion.
108+
// Convert_v1alpha2_AcceptablePermissionClaim_To_v1alpha1_AcceptablePermissionClaim converts v1alpha2.AcceptablePermissionClaim
109+
// to v1alpha1.AcceptablePermissionClaim. This is not a lossless conversion, selectors are lost in this conversion.
110+
// For loseless conversion use Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding.
102111
func Convert_v1alpha2_AcceptablePermissionClaim_To_v1alpha1_AcceptablePermissionClaim(in *AcceptablePermissionClaim, out *apisv1alpha1.AcceptablePermissionClaim, s kubeconversion.Scope) error {
103112
if err := Convert_v1alpha2_ScopedPermissionClaim_To_v1alpha1_PermissionClaim(&in.ScopedPermissionClaim, &out.PermissionClaim, s); err != nil {
104113
return err
@@ -107,6 +116,8 @@ func Convert_v1alpha2_AcceptablePermissionClaim_To_v1alpha1_AcceptablePermission
107116
return nil
108117
}
109118

119+
// Convert_v1alpha2_ScopedPermissionClaim_To_v1alpha1_PermissionClaim converts v1alhpa2.ScopedPermissionClaim to v1alpha1.PermissionClaim.
120+
// This is not a lossless conversion, for loseless conversion use Convert_v1alpha2_APIBinding_To_v1alpha1_APIBinding.
110121
func Convert_v1alpha2_ScopedPermissionClaim_To_v1alpha1_PermissionClaim(in *ScopedPermissionClaim, out *apisv1alpha1.PermissionClaim, s kubeconversion.Scope) error {
111122
if err := Convert_v1alpha2_PermissionClaim_To_v1alpha1_PermissionClaim(&in.PermissionClaim, out, s); err != nil {
112123
return err
@@ -115,7 +126,7 @@ func Convert_v1alpha2_ScopedPermissionClaim_To_v1alpha1_PermissionClaim(in *Scop
115126
return nil
116127
}
117128

118-
// v1alpha1 -> v1alpha2
129+
// v1alpha1 -> v1alpha2 conversions.
119130

120131
func Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding(in *apisv1alpha1.APIBinding, out *APIBinding, s kubeconversion.Scope) error {
121132
out.ObjectMeta = *in.ObjectMeta.DeepCopy()
@@ -127,19 +138,25 @@ func Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding(in *apisv1alpha1.APIBind
127138
return err
128139
}
129140

130-
// store acceptable permission claims in annotation. this is necessary for a clean conversion of
141+
// store v1alpha1 acceptable permission claims in annotation. this is necessary for a clean conversion of
131142
// ResourceSelector, which went away in v1alpha2.
132-
if len(in.Spec.PermissionClaims) > 0 {
143+
_, overhangingV1PC, err := Convert_v1alpha1_AcceptablePermissionClaims_To_v1alpha2_AcceptablePermissionClaims(in.Spec.PermissionClaims, s)
144+
if err != nil {
145+
return err
146+
}
147+
if len(overhangingV1PC) > 0 {
133148
if out.Annotations == nil {
134149
out.Annotations = make(map[string]string)
135150
}
136-
encoded, err := json.Marshal(in.Spec.PermissionClaims)
151+
encoded, err := json.Marshal(overhangingV1PC)
137152
if err != nil {
138153
return err
139154
}
140155
out.Annotations[PermissionClaimsV1Alpha1Annotation] = string(encoded)
141156
}
142157

158+
// store v1alpha2 permission claims in annotation. this is necessary for a clean conversion of
159+
// verbs and label selectors, which were not existing in v1alpha1.
143160
if overhangingAPC, ok := in.Annotations[AcceptablePermissionClaimsAnnotation]; ok {
144161
acceptablePermissionClaims := []AcceptablePermissionClaim{}
145162
if err := json.Unmarshal([]byte(overhangingAPC), &acceptablePermissionClaims); err != nil {
@@ -150,6 +167,7 @@ func Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding(in *apisv1alpha1.APIBind
150167
for i, opc := range out.Spec.PermissionClaims {
151168
if pc.EqualGRI(opc.PermissionClaim) {
152169
out.Spec.PermissionClaims[i].PermissionClaim.Verbs = pc.Verbs
170+
out.Spec.PermissionClaims[i].Selector = pc.Selector
153171
}
154172
}
155173
}
@@ -166,48 +184,56 @@ func Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding(in *apisv1alpha1.APIBind
166184
if len(opc.PermissionClaim.Verbs) == 0 {
167185
out.Spec.PermissionClaims[i].PermissionClaim.Verbs = []string{"*"}
168186
}
187+
// This is handling a special case where PermissionClaim had ResourceSelector in v1alpha1.
188+
// That field doesn't exist in v1alpha2 and it always resulted in `MatchAll = true` behavior,
189+
// so we set it here explicitly.
190+
if !opc.Selector.MatchAll && len(opc.Selector.MatchLabels) == 0 && len(opc.Selector.MatchExpressions) == 0 {
191+
out.Spec.PermissionClaims[i].Selector.MatchAll = true
192+
}
169193
}
170194

171195
return nil
172196
}
173197

198+
// Convert_v1alpha1_AcceptablePermissionClaims_To_v1alpha2_AcceptablePermissionClaims converts []v1alpha1.AcceptablePermissionClaim
199+
// to []v1alpha2.AcceptablePermissionClaim. This is not a lossless conversion, for loseless conversion use
200+
// Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding.
174201
func Convert_v1alpha1_AcceptablePermissionClaims_To_v1alpha2_AcceptablePermissionClaims(in []apisv1alpha1.AcceptablePermissionClaim, s kubeconversion.Scope) (out []AcceptablePermissionClaim, overhanging []apisv1alpha1.AcceptablePermissionClaim, err error) {
175-
for _, apc := range in {
176-
// ResourceSelector has been removed from PermissionClaims, we can't cleanly convert it.
177-
if apc.PermissionClaim.All && len(apc.PermissionClaim.ResourceSelector) == 0 {
178-
var v2apc AcceptablePermissionClaim
179-
if err := Convert_v1alpha1_AcceptablePermissionClaim_To_v1alpha2_AcceptablePermissionClaim(&apc, &v2apc, s); err != nil {
202+
for _, pc := range in {
203+
if len(pc.ResourceSelector) > 0 {
204+
overhanging = append(overhanging, pc)
205+
} else {
206+
var v2pc AcceptablePermissionClaim
207+
if err := Convert_v1alpha1_AcceptablePermissionClaim_To_v1alpha2_AcceptablePermissionClaim(&pc, &v2pc, s); err != nil {
180208
return nil, nil, err
181209
}
182-
out = append(out, v2apc)
183-
} else {
184-
overhanging = append(overhanging, apc)
210+
out = append(out, v2pc)
185211
}
186212
}
187213

188-
return
214+
return out, overhanging, nil
189215
}
190216

191-
// Convert_v1alpha1_AcceptablePermissionClaim_To_v1alpha2_AcceptablePermissionClaim converts v1alpha1.AcceptablePermissionClaim to v1alpha2.AcceptablePermissionClaim.
192-
// This is not a lossless conversion.
217+
// Convert_v1alpha1_AcceptablePermissionClaim_To_v1alpha2_AcceptablePermissionClaim converts v1alpha1.AcceptablePermissionClaim
218+
// to v1alpha2.AcceptablePermissionClaim. This is not a lossless conversion, for loseless conversion use
219+
// Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding.
193220
func Convert_v1alpha1_AcceptablePermissionClaim_To_v1alpha2_AcceptablePermissionClaim(in *apisv1alpha1.AcceptablePermissionClaim, out *AcceptablePermissionClaim, s kubeconversion.Scope) error {
194-
if err := Convert_v1alpha1_PermissionClaim_To_v1alpha2_PermissionClaim(&in.PermissionClaim, &out.PermissionClaim, s); err != nil {
221+
if err := Convert_v1alpha1_PermissionClaim_To_v1alpha2_ScopedPermissionClaim(&in.PermissionClaim, &out.ScopedPermissionClaim, s); err != nil {
195222
return err
196223
}
197-
198224
out.State = AcceptablePermissionClaimState(in.State)
199-
out.Selector.MatchAll = in.PermissionClaim.All
200-
if len(out.PermissionClaim.Verbs) == 0 {
201-
out.PermissionClaim.Verbs = []string{"*"}
202-
}
203225

204226
return nil
205227
}
206228

229+
// Convert_v1alpha1_PermissionClaim_To_v1alpha2_ScopedPermissionClaim converts v1alpha1.PermissionClaim
230+
// to v1alpha2.PermissionClaim. This is not a lossless conversion, for loseless conversion use
231+
// Convert_v1alpha1_APIBinding_To_v1alpha2_APIBinding.
207232
func Convert_v1alpha1_PermissionClaim_To_v1alpha2_ScopedPermissionClaim(in *apisv1alpha1.PermissionClaim, out *ScopedPermissionClaim, s kubeconversion.Scope) error {
208233
if err := Convert_v1alpha1_PermissionClaim_To_v1alpha2_PermissionClaim(in, &out.PermissionClaim, s); err != nil {
209234
return err
210235
}
211236
out.Selector.MatchAll = in.All
237+
212238
return nil
213239
}

sdk/apis/apis/v1alpha2/types_apibinding_conversion_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/google/go-cmp/cmp"
2323

24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/runtime"
2526

2627
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
@@ -154,6 +155,66 @@ func TestConvertV1Alpha2APIBindings(t *testing.T) {
154155
}},
155156
},
156157
},
158+
{
159+
Spec: APIBindingSpec{
160+
Reference: BindingReference{
161+
Export: &ExportBindingReference{
162+
Path: "foo",
163+
Name: "bar",
164+
},
165+
},
166+
PermissionClaims: []AcceptablePermissionClaim{{
167+
ScopedPermissionClaim: ScopedPermissionClaim{
168+
PermissionClaim: PermissionClaim{
169+
GroupResource: GroupResource{
170+
Resource: "configmaps",
171+
},
172+
Verbs: []string{"get"},
173+
},
174+
Selector: PermissionClaimSelector{
175+
LabelSelector: metav1.LabelSelector{
176+
MatchLabels: map[string]string{
177+
"test": "label",
178+
},
179+
},
180+
},
181+
},
182+
State: ClaimAccepted,
183+
}},
184+
},
185+
},
186+
{
187+
Spec: APIBindingSpec{
188+
Reference: BindingReference{
189+
Export: &ExportBindingReference{
190+
Path: "foo",
191+
Name: "bar",
192+
},
193+
},
194+
PermissionClaims: []AcceptablePermissionClaim{{
195+
ScopedPermissionClaim: ScopedPermissionClaim{
196+
PermissionClaim: PermissionClaim{
197+
GroupResource: GroupResource{
198+
Resource: "configmaps",
199+
},
200+
Verbs: []string{"get"},
201+
},
202+
Selector: PermissionClaimSelector{
203+
LabelSelector: metav1.LabelSelector{
204+
MatchExpressions: []metav1.LabelSelectorRequirement{
205+
{
206+
Key: "test",
207+
Operator: metav1.LabelSelectorOpIn,
208+
Values: []string{"expression"},
209+
},
210+
},
211+
},
212+
},
213+
},
214+
State: ClaimAccepted,
215+
}},
216+
},
217+
},
157218
}
158219

159220
scheme := runtime.NewScheme()

sdk/apis/apis/v1alpha2/types_apiexport_conversion.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ func Convert_v1alpha2_APIExport_To_v1alpha1_APIExport(in *APIExport, out *apisv1
5151
out.Annotations[ResourceSchemasAnnotation] = string(encoded)
5252
}
5353

54+
// before converting the spec, figure out which PermissionClaims could not be represented in v1alpha1 and
55+
// retain them via an annotation
5456
_, overhangingPC, err := Convert_v1alpha2_PermissionClaims_To_v1alpha1_PermissionClaims(in.Spec.PermissionClaims, s)
5557
if err != nil {
5658
return err
@@ -71,10 +73,12 @@ func Convert_v1alpha2_APIExport_To_v1alpha1_APIExport(in *APIExport, out *apisv1
7173
return err
7274
}
7375

76+
// if the object was converted from v1alpha1 to v1alpha2 to v1alpha1, retain All and ResourceSelector
77+
// fields in PermissionClaims by reading the original (v1alpha1) PermissionClaims from an annotation
7478
if originalPermissionClaims, ok := in.Annotations[PermissionClaimsV1Alpha1Annotation]; ok {
7579
permissionClaims := []apisv1alpha1.PermissionClaim{}
7680
if err := json.Unmarshal([]byte(originalPermissionClaims), &permissionClaims); err != nil {
77-
return fmt.Errorf("failed to decode schemas from JSON: %w", err)
81+
return fmt.Errorf("failed to decode v1alpha1 claims from JSON: %w", err)
7882
}
7983

8084
for _, pc := range permissionClaims {
@@ -138,8 +142,8 @@ func Convert_v1alpha2_PermissionClaims_To_v1alpha1_PermissionClaims(in []Permiss
138142
}
139143

140144
// Convert_v1alpha2_APIExportSpec_To_v1alpha1_APIExportSpec is *not* lossless, as it will drop all non-CRD
141-
// resource schemas present in the APIExport's spec. To have a full, lossless conversion, use
142-
// Convert_v1alpha2_APIExport_To_v1alpha1_APIExport instead.
145+
// resource schemas and all non-wildcard PermissionClaims present in the APIExport's spec.
146+
// To have a full, lossless conversion, use Convert_v1alpha2_APIExport_To_v1alpha1_APIExport instead.
143147
func Convert_v1alpha2_APIExportSpec_To_v1alpha1_APIExportSpec(in *APIExportSpec, out *apisv1alpha1.APIExportSpec, s kubeconversion.Scope) error {
144148
if in.Identity != nil {
145149
out.Identity = &apisv1alpha1.Identity{}
@@ -281,6 +285,9 @@ func Convert_v1alpha1_APIExportSpec_To_v1alpha2_APIExportSpec(in *apisv1alpha1.A
281285
}
282286
}
283287

288+
// This will not convert non-wildcard PermissionClaims verbs and All/ResourceSelector fields. Those are still
289+
// tucked away in an annotation and are converted after this function has completed, in
290+
// Convert_v1alpha1_APIExport_To_v1alpha2_APIExport.
284291
if claims := in.PermissionClaims; claims != nil {
285292
newClaims := []PermissionClaim{}
286293
for _, claim := range claims {
@@ -365,7 +372,7 @@ func Convert_v1alpha1_LatestResourceSchema_To_v1alpha2_ResourceSchema(in []strin
365372
}
366373

367374
// Convert_v1alpha1_PermissionClaim_To_v1alpha2_PermissionClaim ensures we do the default conversion for
368-
// PermissionClaims. Fields "All" and "ResourceSelector" are stored in annotation.
375+
// PermissionClaims. Fields "All", "ResourceSelector", and "Verbs" are stored in relevant annotations.
369376
func Convert_v1alpha1_PermissionClaim_To_v1alpha2_PermissionClaim(in *apisv1alpha1.PermissionClaim, out *PermissionClaim, s kubeconversion.Scope) error {
370377
return autoConvert_v1alpha1_PermissionClaim_To_v1alpha2_PermissionClaim(in, out, s)
371378
}

0 commit comments

Comments
 (0)