Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,7 @@ func (r *reconciler) ensureExports(ctx context.Context, cl client.Client, existi
}

// Validate validates if the APIServiceExportRequest is in a valid state.
// Currently it validates if all requested schemas are of the same scope and
// if claimable apis are allowed and valid.
//
// TODO: Move this to validatingAdmissionWebhook as this is not really part of reconciliation.
// https://github.com/kube-bind/kube-bind/issues/325
// Currently it validates if all requested schemas are of the same scope.
func (r *reconciler) validate(ctx context.Context, cl client.Client, req *kubebindv1alpha2.APIServiceExportRequest) error {
exportedSchemas, err := r.getExportedSchemas(ctx, cl)
if err != nil {
Expand Down Expand Up @@ -371,56 +367,9 @@ func (r *reconciler) validate(ctx context.Context, cl client.Client, req *kubebi
}
}

// Add validation if claimable apis are valid here
for _, claim := range req.Spec.PermissionClaims {
if !isClaimableAPI(claim) {
conditions.MarkFalse(
req,
kubebindv1alpha2.APIServiceExportConditionPermissionClaim,
"InvalidPermissionClaim",
conditionsapi.ConditionSeverityError,
"Resource %s is not a valid claimable API",
claim.GroupResource.String(),
)
req.Status.Phase = kubebindv1alpha2.APIServiceExportRequestPhaseFailed
req.Status.TerminalMessage = conditions.GetMessage(req, kubebindv1alpha2.APIServiceExportConditionPermissionClaim)
return fmt.Errorf("resource %s is not a valid claimable API", claim.GroupResource.String())
}
}

// Add validation for duplicate group/resource combinations
seenGroupResources := make(map[string]bool)
for _, claim := range req.Spec.PermissionClaims {
key := claim.Group + "/" + claim.Resource
if seenGroupResources[key] {
conditions.MarkFalse(
req,
kubebindv1alpha2.APIServiceExportConditionPermissionClaim,
"DuplicatePermissionClaim",
conditionsapi.ConditionSeverityError,
"Duplicate permission claim found for group/resource %s",
claim.GroupResource.String(),
)
req.Status.Phase = kubebindv1alpha2.APIServiceExportRequestPhaseFailed
req.Status.TerminalMessage = conditions.GetMessage(req, kubebindv1alpha2.APIServiceExportConditionPermissionClaim)
return fmt.Errorf("duplicate permission claim found for group/resource %s", claim.GroupResource.String())
}
seenGroupResources[key] = true
}

return nil
}

// isClaimableAPI checks if a permission claim is for a claimable API.
func isClaimableAPI(claim kubebindv1alpha2.PermissionClaim) bool {
for _, api := range kubebindv1alpha2.ClaimableAPIs {
if claim.Group == api.GroupVersionResource.Group && claim.Resource == api.Names.Plural {
return true
}
}
return false
}

func (r *reconciler) ensureAPIServiceNamespaces(ctx context.Context, cl client.Client, cache cache.Cache, req *kubebindv1alpha2.APIServiceExportRequest) error {
logger := klog.FromContext(ctx)

Expand Down
2 changes: 1 addition & 1 deletion contrib/kcp/deploy/resources/apiexport-kube-bind.io.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ spec:
crd: {}
- group: kube-bind.io
name: apiserviceexportrequests
schema: v260220-f03e1ee.apiserviceexportrequests.kube-bind.io
schema: v260608-edcd0b51.apiserviceexportrequests.kube-bind.io
storage:
crd: {}
- group: kube-bind.io
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: apis.kcp.io/v1alpha1
kind: APIResourceSchema
metadata:
name: v260220-f03e1ee.apiserviceexportrequests.kube-bind.io
name: v260608-edcd0b51.apiserviceexportrequests.kube-bind.io
spec:
conversion:
strategy: None
Expand Down Expand Up @@ -384,6 +384,10 @@ spec:
x-kubernetes-validations:
- message: permissionClaims are immutable
rule: self == oldSelf
- message: Resource is not a valid claimable API
rule: self.all(c, (c.group == '' && c.resource == 'configmaps') ||
(c.group == '' && c.resource == 'secrets') || (c.group == '' &&
c.resource == 'serviceaccounts'))
resources:
description: resources is a list of resources that should be exported.
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ spec:
x-kubernetes-validations:
- message: permissionClaims are immutable
rule: self == oldSelf
- message: Resource is not a valid claimable API
rule: self.all(c, (c.group == '' && c.resource == 'configmaps')
|| (c.group == '' && c.resource == 'secrets') || (c.group == ''
&& c.resource == 'serviceaccounts'))
resources:
description: resources is a list of resources that should be exported.
items:
Expand Down
4 changes: 4 additions & 0 deletions deploy/crd/kube-bind.io_apiserviceexportrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,10 @@ spec:
x-kubernetes-validations:
- message: permissionClaims are immutable
rule: self == oldSelf
- message: Resource is not a valid claimable API
rule: self.all(c, (c.group == '' && c.resource == 'configmaps')
|| (c.group == '' && c.resource == 'secrets') || (c.group == ''
&& c.resource == 'serviceaccounts'))
resources:
description: resources is a list of resources that should be exported.
items:
Expand Down
5 changes: 4 additions & 1 deletion sdk/apis/kubebind/v1alpha2/apiserviceexportrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ type APIServiceExportRequestSpec struct {
// Access is granted per GroupResource.
//
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="permissionClaims are immutable"
// +kubebuilder:validation:XListType=map
// +kubebuilder:validation:XListMapKey=resource
// +kubebuilder:validation:XListMapKey=group
// +kubebuilder:validation:XValidation:rule="self.all(c, (c.group == '' && c.resource == 'configmaps') || (c.group == '' && c.resource == 'secrets') || (c.group == '' && c.resource == 'serviceaccounts'))",message="Resource is not a valid claimable API"
PermissionClaims []PermissionClaim `json:"permissionClaims,omitempty"`

// namespaces specifies the namespaces to bootstrap as part of this request.
// When objects originate from provider side, the consumer does not always know the necessary details.
// This field allows provider to pre-heat the necessary namespaces on provider side by creating
Expand Down