Skip to content

[WIP] Implement support for verbs in PermissionClaims #3402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
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
28 changes: 14 additions & 14 deletions cli/pkg/bind/plugin/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (

"github.com/kcp-dev/kcp/cli/pkg/base"
pluginhelpers "github.com/kcp-dev/kcp/cli/pkg/helpers"
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
)

Expand All @@ -55,9 +55,9 @@ type BindOptions struct {
RejectedPermissionClaims []string

// acceptedPermissionClaims is the parsed list of accepted permission claims for the APIBinding parsed from AcceptedPermissionClaims.
acceptedPermissionClaims []apisv1alpha1.AcceptablePermissionClaim
acceptedPermissionClaims []apisv1alpha2.AcceptablePermissionClaim
// rejectedPermissionClaims is the parsed list of rejected permission claims for the APIBinding parsed from RejectedPermissionClaims.
rejectedPermissionClaims []apisv1alpha1.AcceptablePermissionClaim
rejectedPermissionClaims []apisv1alpha2.AcceptablePermissionClaim
}

// NewBindOptions returns new BindOptions.
Expand Down Expand Up @@ -156,13 +156,13 @@ func (b *BindOptions) Run(ctx context.Context) error {
return fmt.Errorf("current URL %q does not point to workspace", config.Host)
}

binding := &apisv1alpha1.APIBinding{
binding := &apisv1alpha2.APIBinding{
ObjectMeta: metav1.ObjectMeta{
Name: apiBindingName,
},
Spec: apisv1alpha1.APIBindingSpec{
Reference: apisv1alpha1.BindingReference{
Export: &apisv1alpha1.ExportBindingReference{
Spec: apisv1alpha2.APIBindingSpec{
Reference: apisv1alpha2.BindingReference{
Export: &apisv1alpha2.ExportBindingReference{
Path: path.String(),
Name: apiExportName,
},
Expand All @@ -182,7 +182,7 @@ func (b *BindOptions) Run(ctx context.Context) error {
return err
}

createdBinding, err := kcpclient.Cluster(currentClusterName).ApisV1alpha1().APIBindings().Create(ctx, binding, metav1.CreateOptions{})
createdBinding, err := kcpclient.Cluster(currentClusterName).ApisV1alpha2().APIBindings().Create(ctx, binding, metav1.CreateOptions{})
if err != nil {
return err
}
Expand All @@ -192,13 +192,13 @@ func (b *BindOptions) Run(ctx context.Context) error {
}

// wait for phase to be bound
if createdBinding.Status.Phase != apisv1alpha1.APIBindingPhaseBound {
if createdBinding.Status.Phase != apisv1alpha2.APIBindingPhaseBound {
if err := wait.PollUntilContextTimeout(ctx, time.Millisecond*500, b.BindWaitTimeout, true, func(ctx context.Context) (done bool, err error) {
createdBinding, err := kcpclient.Cluster(currentClusterName).ApisV1alpha1().APIBindings().Get(ctx, binding.Name, metav1.GetOptions{})
createdBinding, err := kcpclient.Cluster(currentClusterName).ApisV1alpha2().APIBindings().Get(ctx, binding.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
if createdBinding.Status.Phase == apisv1alpha1.APIBindingPhaseBound {
if createdBinding.Status.Phase == apisv1alpha2.APIBindingPhaseBound {
return true, nil
}
return false, nil
Expand All @@ -220,7 +220,7 @@ func (b *BindOptions) parsePermissionClaim(claim string, accepted bool) error {
return fmt.Errorf("invalid permission claim %q", claim)
}

parsedClaim := apisv1alpha1.AcceptablePermissionClaim{}
parsedClaim := apisv1alpha2.AcceptablePermissionClaim{}
resource := claimParts[0]
group := claimParts[1]
if group == "core" {
Expand All @@ -230,9 +230,9 @@ func (b *BindOptions) parsePermissionClaim(claim string, accepted bool) error {
parsedClaim.Group = group
parsedClaim.Resource = resource
if accepted {
parsedClaim.State = apisv1alpha1.ClaimAccepted
parsedClaim.State = apisv1alpha2.ClaimAccepted
} else {
parsedClaim.State = apisv1alpha1.ClaimRejected
parsedClaim.State = apisv1alpha2.ClaimRejected
}
// TODO(mjudeikis): Once we add support for selectors/
parsedClaim.All = true
Expand Down
8 changes: 4 additions & 4 deletions cli/pkg/claims/plugin/claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (

"github.com/kcp-dev/kcp/cli/pkg/base"
pluginhelpers "github.com/kcp-dev/kcp/cli/pkg/helpers"
apiv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
apiv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
)

Expand Down Expand Up @@ -104,16 +104,16 @@ func (g *GetAPIBindingOptions) Run(ctx context.Context) error {
}

allErrors := []error{}
apibindings := []apiv1alpha1.APIBinding{}
apibindings := []apiv1alpha2.APIBinding{}
// List permission claims for all bindings in current workspace.
if g.allBindings {
bindings, err := kcpClusterClient.Cluster(currentClusterName).ApisV1alpha1().APIBindings().List(ctx, metav1.ListOptions{})
bindings, err := kcpClusterClient.Cluster(currentClusterName).ApisV1alpha2().APIBindings().List(ctx, metav1.ListOptions{})
if err != nil {
return fmt.Errorf("error listing apibindings in %q workspace: %w", currentClusterName, err)
}
apibindings = append(apibindings, bindings.Items...)
} else {
binding, err := kcpClusterClient.Cluster(currentClusterName).ApisV1alpha1().APIBindings().Get(ctx, g.APIBindingName, metav1.GetOptions{})
binding, err := kcpClusterClient.Cluster(currentClusterName).ApisV1alpha2().APIBindings().Get(ctx, g.APIBindingName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("error finding apibinding: %w", err)
}
Expand Down
22 changes: 15 additions & 7 deletions cli/pkg/workspace/plugin/use.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
Expand All @@ -38,7 +39,7 @@ import (

"github.com/kcp-dev/kcp/cli/pkg/base"
pluginhelpers "github.com/kcp-dev/kcp/cli/pkg/helpers"
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
"github.com/kcp-dev/kcp/sdk/apis/core"
tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
Expand All @@ -63,7 +64,7 @@ type UseWorkspaceOptions struct {

// for testing
modifyConfig func(configAccess clientcmd.ConfigAccess, newConfig *clientcmdapi.Config) error
getAPIBindings func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha1.APIBinding, error)
getAPIBindings func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha2.APIBinding, error)
userHomeDir func() (string, error)
}

Expand Down Expand Up @@ -420,13 +421,13 @@ func (o *UseWorkspaceOptions) parseCurrentLogicalCluster() (*url.URL, *logicalcl
}

// getAPIBindings retrieves APIBindings within the workspace.
func getAPIBindings(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha1.APIBinding, error) {
func getAPIBindings(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha2.APIBinding, error) {
_, clusterName, err := pluginhelpers.ParseClusterURL(host)
if err != nil {
return nil, err
}

apiBindings, err := kcpClusterClient.Cluster(clusterName).ApisV1alpha1().APIBindings().List(ctx, metav1.ListOptions{})
apiBindings, err := kcpClusterClient.Cluster(clusterName).ApisV1alpha2().APIBindings().List(ctx, metav1.ListOptions{})
// If the user is not allowed to view APIBindings in the workspace, there's nothing to show.
if apierrors.IsForbidden(err) {
return nil, nil
Expand All @@ -439,23 +440,30 @@ func getAPIBindings(ctx context.Context, kcpClusterClient kcpclientset.ClusterIn
}

// findUnresolvedPermissionClaims finds and reports any APIBindings that do not specify permission claims matching those on the target APIExport.
func findUnresolvedPermissionClaims(out io.Writer, apiBindings []apisv1alpha1.APIBinding) error {
func findUnresolvedPermissionClaims(out io.Writer, apiBindings []apisv1alpha2.APIBinding) error {
for _, binding := range apiBindings {
for _, exportedClaim := range binding.Status.ExportPermissionClaims {
var found, ack bool
var found, ack, verbsMatch bool
var verbsExpected, verbsActual sets.Set[string]
for _, specClaim := range binding.Spec.PermissionClaims {
if !exportedClaim.Equal(specClaim.PermissionClaim) {
continue
}
found = true
ack = (specClaim.State == apisv1alpha1.ClaimAccepted) || specClaim.State == apisv1alpha1.ClaimRejected
ack = (specClaim.State == apisv1alpha2.ClaimAccepted) || specClaim.State == apisv1alpha2.ClaimRejected
verbsExpected = sets.New(exportedClaim.Verbs...)
verbsActual = sets.New(specClaim.Verbs...)
verbsMatch = verbsActual.Difference(verbsExpected).Len() == 0 && verbsExpected.Difference(verbsActual).Len() == 0
}
if !found {
fmt.Fprintf(out, "Warning: claim for %s exported but not specified on APIBinding %s\nAdd this claim to the APIBinding's Spec.\n", exportedClaim.String(), binding.Name)
}
if !ack {
fmt.Fprintf(out, "Warning: claim for %s specified on APIBinding %s but not accepted or rejected.\n", exportedClaim.String(), binding.Name)
}
if !verbsMatch {
fmt.Fprintf(out, "Warning: allowed verbs (%s) on claim for %s on APIBinding %s do not match expected verbs (%s).\n", strings.Join(verbsActual.UnsortedList(), ","), exportedClaim.String(), binding.Name, strings.Join(verbsExpected.UnsortedList(), ","))
}
}
}
return nil
Expand Down
62 changes: 31 additions & 31 deletions cli/pkg/workspace/plugin/use_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
kcptesting "github.com/kcp-dev/client-go/third_party/k8s.io/client-go/testing"
"github.com/kcp-dev/logicalcluster/v3"

apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
"github.com/kcp-dev/kcp/sdk/apis/core"
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
Expand Down Expand Up @@ -68,7 +68,7 @@ func TestUse(t *testing.T) {
discovery map[logicalcluster.Path][]*metav1.APIResourceList
discoveryErrors map[logicalcluster.Path]error
unready map[logicalcluster.Path]map[string]bool // unready workspaces
apiBindings []apisv1alpha1.APIBinding // APIBindings that exist in the destination workspace, if any
apiBindings []apisv1alpha2.APIBinding // APIBindings that exist in the destination workspace, if any
destination string // workspace set to 'current' at the end of execution
short bool

Expand Down Expand Up @@ -468,9 +468,9 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimAccepted).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimAccepted).
WithExportClaim("test.kcp.io", "test", "abcdef").
Build(),
},
Expand All @@ -486,7 +486,7 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", "").
WithExportClaim("test.kcp.io", "test", "abcdef").
Expand All @@ -508,9 +508,9 @@ func TestUse(t *testing.T) {
param: "~",
expected: NewKubeconfig().WithKcpCurrent(homeWorkspace.String()).WithKcpPrevious("root:foo").Build(),
destination: homeWorkspace.String(),
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimAccepted).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimAccepted).
WithExportClaim("test.kcp.io", "test", "abcdef").
WithExportClaim("", "configmaps", "").
Build(),
Expand All @@ -530,9 +530,9 @@ func TestUse(t *testing.T) {
param: "-",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimAccepted).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimAccepted).
WithExportClaim("test.kcp.io", "test", "abcdef").
WithExportClaim("", "configmaps", "").
Build(),
Expand All @@ -553,9 +553,9 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimRejected).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimRejected).
WithExportClaim("test.kcp.io", "test", "abcdef").
Build(),
},
Expand All @@ -573,9 +573,9 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimAccepted).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimAccepted).
WithExportClaim("test.kcp.io", "test", "abcdef").
Build(),
},
Expand All @@ -593,9 +593,9 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha1.ClaimAccepted).
WithPermissionClaim("test.kcp.io", "test", "abcdef", apisv1alpha2.ClaimAccepted).
WithExportClaim("test.kcp.io", "test", "abcdef").
WithExportClaim("", "configmaps", "").
Build(),
Expand All @@ -616,7 +616,7 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", "").
WithExportClaim("test.kcp.io", "test", "abcdef").
Expand All @@ -638,7 +638,7 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", "").
WithExportClaim("test.kcp.io", "test", "abcdef").
Expand All @@ -662,7 +662,7 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithPermissionClaim("test.kcp.io", "test", "abcdef", "").
WithExportClaim("test.kcp.io", "test", "abcdef").
Expand All @@ -686,7 +686,7 @@ func TestUse(t *testing.T) {
param: "bar",
expected: NewKubeconfig().WithKcpCurrent("root:foo:bar").WithKcpPrevious("root:foo").Build(),
destination: "root:foo:bar",
apiBindings: []apisv1alpha1.APIBinding{
apiBindings: []apisv1alpha2.APIBinding{
newBindingBuilder("a").
WithExportClaim("test.kcp.io", "test", "abcdef").
WithExportClaim("", "configmaps", "").
Expand Down Expand Up @@ -791,14 +791,14 @@ func TestUse(t *testing.T) {
})

// return nothing in the default case.
getAPIBindings := func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha1.APIBinding, error) {
getAPIBindings := func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha2.APIBinding, error) {
return nil, nil
}

if tt.destination != "" {
// Add APIBindings to our Clientset if we have them
if len(tt.apiBindings) > 0 {
getAPIBindings = func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha1.APIBinding, error) {
getAPIBindings = func(ctx context.Context, kcpClusterClient kcpclientset.ClusterInterface, host string) ([]apisv1alpha2.APIBinding, error) {
return tt.apiBindings, nil
}
}
Expand Down Expand Up @@ -946,7 +946,7 @@ func (c errorDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
}

type bindingBuilder struct {
apisv1alpha1.APIBinding
apisv1alpha2.APIBinding
}

func newBindingBuilder(name string) *bindingBuilder {
Expand All @@ -957,14 +957,14 @@ func newBindingBuilder(name string) *bindingBuilder {
return b
}

func (b *bindingBuilder) WithPermissionClaim(group, resource, identityHash string, state apisv1alpha1.AcceptablePermissionClaimState) *bindingBuilder {
func (b *bindingBuilder) WithPermissionClaim(group, resource, identityHash string, state apisv1alpha2.AcceptablePermissionClaimState) *bindingBuilder {
if len(b.Spec.PermissionClaims) == 0 {
b.Spec.PermissionClaims = make([]apisv1alpha1.AcceptablePermissionClaim, 0)
b.Spec.PermissionClaims = make([]apisv1alpha2.AcceptablePermissionClaim, 0)
}

pc := apisv1alpha1.AcceptablePermissionClaim{
PermissionClaim: apisv1alpha1.PermissionClaim{
GroupResource: apisv1alpha1.GroupResource{
pc := apisv1alpha2.AcceptablePermissionClaim{
PermissionClaim: apisv1alpha2.PermissionClaim{
GroupResource: apisv1alpha2.GroupResource{
Group: group,
Resource: resource,
},
Expand All @@ -982,11 +982,11 @@ func (b *bindingBuilder) WithPermissionClaim(group, resource, identityHash strin

func (b *bindingBuilder) WithExportClaim(group, resource, identityHash string) *bindingBuilder {
if len(b.Status.ExportPermissionClaims) == 0 {
b.Status.ExportPermissionClaims = make([]apisv1alpha1.PermissionClaim, 0)
b.Status.ExportPermissionClaims = make([]apisv1alpha2.PermissionClaim, 0)
}

pc := apisv1alpha1.PermissionClaim{
GroupResource: apisv1alpha1.GroupResource{
pc := apisv1alpha2.PermissionClaim{
GroupResource: apisv1alpha2.GroupResource{
Group: group,
Resource: resource,
},
Expand All @@ -997,6 +997,6 @@ func (b *bindingBuilder) WithExportClaim(group, resource, identityHash string) *
return b
}

func (b *bindingBuilder) Build() apisv1alpha1.APIBinding {
func (b *bindingBuilder) Build() apisv1alpha2.APIBinding {
return b.APIBinding
}
Loading