Skip to content

feat: Permission API block #1449

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
domain: clastix.io
layout:
- go.kubebuilder.io/v4
multigroup: true
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
Expand Down Expand Up @@ -64,4 +65,13 @@ resources:
kind: ResourcePoolClaim
path: github.com/projectcapsule/capsule/api/v1beta2
version: v1beta2
- api:
crdVersion: v1
namespaced: true
controller: true
domain: clastix.io
group: capsule
kind: TenantPermission
path: github.com/projectcapsule/capsule/api/capsule/v1aplha2
version: v1aplha2
version: "3"
13 changes: 13 additions & 0 deletions api/v1beta2/permission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package v1beta2

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type PermissionSpec struct {
// Defines roleBindings between the ClusterRole and the Subjet in the Tenants namespaces.
AllowedClusterBindings []metav1.LabelSelectorRequirement `json:"allowedClusterBindings,omitempty"`
}
4 changes: 4 additions & 0 deletions api/v1beta2/tenant_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ type TenantSpec struct {
// If unset, Tenant uses CapsuleConfiguration's forceTenantPrefix
// Optional
ForceTenantPrefix *bool `json:"forceTenantPrefix,omitempty"`
// Specifies RBAC permissions for the Tenant. Capsule will ensure that all namespaces in the Tenant always contain the RoleBinding for the given ClusterRole.
// Capsule will add the subjects to the ClusterRoleBinding, and the RoleBinding will be created in each namespace, or each namespace specified in the namespace selector.
// Optional.
Permissions []PermissionSpec `json:"permissions,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
25 changes: 25 additions & 0 deletions api/v1beta2/tenantpermission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package v1beta2

import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type TenantPermissionSpec struct {
// Defines additional cluster-roles for the specific Owner.
// +kubebuilder:default={admin,capsule-namespace-deleter}
Bindings []string `json:"bindings,omitempty"`
// kubebuilder:validation:Minimum=1
Subjects []rbacv1.Subject `json:"subjects"`
//+kubebuilder:default:=false
ActAsOwner bool `json:"actAsOwner,omitempty"`
}

type TenantPermission struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec TenantPermissionSpec `json:"spec,omitempty"`
}
51 changes: 51 additions & 0 deletions api/v1beta2/tenantpermission_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package v1beta2

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// TenantPermissionSpec defines the desired state of TenantPermission
type TenantPermissionSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// Foo is an example field of TenantPermission. Edit tenantpermission_types.go to remove/update
Foo string `json:"foo,omitempty"`
}

// TenantPermissionStatus defines the observed state of TenantPermission
type TenantPermissionStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// TenantPermission is the Schema for the tenantpermissions API
type TenantPermission struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec TenantPermissionSpec `json:"spec,omitempty"`
Status TenantPermissionStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// TenantPermissionList contains a list of TenantPermission
type TenantPermissionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []TenantPermission `json:"items"`
}

func init() {
SchemeBuilder.Register(&TenantPermission{}, &TenantPermissionList{})
}
72 changes: 72 additions & 0 deletions api/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions controllers/tenantpermission/tenantpermission_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package tenantpermission

import (
"context"

"k8s.io/apimachinery/pkg/runtime"
apierrors "k8s.io/apimachinery/pkg/api/errors"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
)

// TenantPermissionReconciler reconciles a TenantPermission object
type TenantPermissionReconciler struct {
client.Client
Scheme *runtime.Scheme
}

// SetupWithManager sets up the controller with the Manager.
func (r *TenantPermissionReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&capsulev1beta2.TenantPermission{}).
Complete(r)
}

// +kubebuilder:rbac:groups=capsule.clastix.io,resources=tenantpermissions,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=capsule.clastix.io,resources=tenantpermissions/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=capsule.clastix.io,resources=tenantpermissions/finalizers,verbs=update
func (r *TenantPermissionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
_ = log.FromContext(ctx)

// TODO(user): your logic here

tntPermission := &capsulev1beta2.TenantPermission{}
if err := r.client.Get(ctx, req.NamespacedName, tntPermission); err != nil {
if apierrors.IsNotFound(err) != nil {
log.Info("Request object not found, could have been deleted after reconcile request")

return ctrl.Result{}, err
}

return reconcile.Result{}, err
}

return ctrl.Result{}, nil
}
71 changes: 71 additions & 0 deletions e2e/tenantpermission_controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package capsule

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

capsulev1aplha2 "github.com/projectcapsule/capsule/api/capsule/v1aplha2"
)

var _ = Describe("TenantPermission Controller", func() {
Context("When reconciling a resource", func() {
const resourceName = "test-resource"

ctx := context.Background()

typeNamespacedName := types.NamespacedName{
Name: resourceName,
Namespace: "default", // TODO(user):Modify as needed
}
tenantpermission := &capsulev1aplha2.TenantPermission{}

BeforeEach(func() {
By("creating the custom resource for the Kind TenantPermission")
err := k8sClient.Get(ctx, typeNamespacedName, tenantpermission)
if err != nil && errors.IsNotFound(err) {
resource := &capsulev1aplha2.TenantPermission{
ObjectMeta: metav1.ObjectMeta{
Name: resourceName,
Namespace: "default",
},
// TODO(user): Specify other spec details if needed.
}
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
}
})

AfterEach(func() {
// TODO(user): Cleanup logic after each test, like removing the resource instance.
resource := &capsulev1aplha2.TenantPermission{}
err := k8sClient.Get(ctx, typeNamespacedName, resource)
Expect(err).NotTo(HaveOccurred())

By("Cleanup the specific resource instance TenantPermission")
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
})
It("should successfully reconcile the resource", func() {
By("Reconciling the created resource")
controllerReconciler := &TenantPermissionReconciler{
Client: k8sClient,
Scheme: k8sClient.Scheme(),
}

_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
// Example: If you expect a certain status condition after reconciliation, verify it here.
})
})
})
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,8 @@ k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97
k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/cluster-api v1.10.1 h1:5vsLNgQ4SkPudJ1USK532B0SIdJxRsCNKt2DZtBf+ww=
sigs.k8s.io/cluster-api v1.10.1/go.mod h1:aiPMrNPoaJc/GuJ4TCpWX8bVe11+iCJ4HI0f3c9QiJg=
sigs.k8s.io/cluster-api v1.10.2 h1:xfvtNu4Fy/41grL0ryH5xSKQjpJEWdO8HiV2lPCCozQ=
sigs.k8s.io/cluster-api v1.10.2/go.mod h1:/b9Un5Imprib6S7ZOcJitC2ep/5wN72b0pXpMQFfbTw=
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M=
Expand Down
Empty file modified hack/create-user-openshift.sh
100755 → 100644
Empty file.
Empty file modified hack/create-user.sh
100755 → 100644
Empty file.
Empty file modified hack/local-test-with-kind.sh
100755 → 100644
Empty file.
Empty file modified hack/velero-restore.sh
100755 → 100644
Empty file.