Add roles to project
[ZITADOPER-1]
This commit is contained in:
@@ -79,6 +79,21 @@ spec:
|
||||
type: boolean
|
||||
projectRoleCheck:
|
||||
type: boolean
|
||||
roles:
|
||||
items:
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
key:
|
||||
type: string
|
||||
required:
|
||||
- displayName
|
||||
- group
|
||||
- key
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- organizationRef
|
||||
type: object
|
||||
|
||||
@@ -26,6 +26,12 @@ import (
|
||||
// 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.
|
||||
|
||||
type Role struct {
|
||||
Key string `json:"key"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Group string `json:"group"`
|
||||
}
|
||||
|
||||
// ProjectSpec defines the desired state of Project
|
||||
type ProjectSpec struct {
|
||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||
@@ -35,6 +41,8 @@ type ProjectSpec struct {
|
||||
// +operator-sdk:csv:customresourcedefinitions:type=spec
|
||||
OrganizationRef OrganizationRef `json:"organizationRef"`
|
||||
// +optional
|
||||
Roles []Role `json:"roles"`
|
||||
// +optional
|
||||
ProjectRoleAssertion bool `json:"projectRoleAssertion,omitempty"`
|
||||
// +optional
|
||||
ProjectRoleCheck bool `json:"projectRoleCheck,omitempty"`
|
||||
|
||||
@@ -399,7 +399,7 @@ func (in *Project) DeepCopyInto(out *Project) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
@@ -473,6 +473,11 @@ func (in *ProjectRef) DeepCopy() *ProjectRef {
|
||||
func (in *ProjectSpec) DeepCopyInto(out *ProjectSpec) {
|
||||
*out = *in
|
||||
out.OrganizationRef = in.OrganizationRef
|
||||
if in.Roles != nil {
|
||||
in, out := &in.Roles, &out.Roles
|
||||
*out = make([]Role, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectSpec.
|
||||
@@ -507,6 +512,21 @@ func (in *ProjectStatus) DeepCopy() *ProjectStatus {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Role) DeepCopyInto(out *Role) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Role.
|
||||
func (in *Role) DeepCopy() *Role {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Role)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ZitadelCluster) DeepCopyInto(out *ZitadelCluster) {
|
||||
*out = *in
|
||||
|
||||
@@ -80,6 +80,21 @@ spec:
|
||||
type: boolean
|
||||
projectRoleCheck:
|
||||
type: boolean
|
||||
roles:
|
||||
items:
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
group:
|
||||
type: string
|
||||
key:
|
||||
type: string
|
||||
required:
|
||||
- displayName
|
||||
- group
|
||||
- key
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- organizationRef
|
||||
type: object
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||
"golang.org/x/exp/maps"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -91,7 +92,32 @@ func newWrappedProjectReconciler(client client.Client, refResolver *zitadelv1alp
|
||||
}
|
||||
}
|
||||
|
||||
type projectReconcilePhase struct {
|
||||
Name string
|
||||
Reconcile func(context.Context, *management.Client) error
|
||||
}
|
||||
|
||||
func (wr *wrappedProjectReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error {
|
||||
phases := []projectReconcilePhase{
|
||||
{
|
||||
Name: "project",
|
||||
Reconcile: wr.reconcileProject,
|
||||
},
|
||||
{
|
||||
Name: "roles",
|
||||
Reconcile: wr.reconcileRoles,
|
||||
},
|
||||
}
|
||||
for _, p := range phases {
|
||||
err := p.Reconcile(ctx, ztdClient)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wr *wrappedProjectReconciler) reconcileProject(ctx context.Context, ztdClient *management.Client) error {
|
||||
org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -138,6 +164,59 @@ func (wr *wrappedProjectReconciler) Reconcile(ctx context.Context, ztdClient *ma
|
||||
return wr.Client.Status().Patch(ctx, wr.project, patch)
|
||||
}
|
||||
|
||||
func (wr *wrappedProjectReconciler) reconcileRoles(ctx context.Context, ztdClient *management.Client) error {
|
||||
org, err := wr.refResolver.OrganizationRef(ctx, &wr.project.Spec.OrganizationRef, wr.project.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := ztdClient.ListProjectRoles(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.ListProjectRolesRequest{
|
||||
ProjectId: wr.project.Status.ProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not list project roles: %v", err)
|
||||
}
|
||||
roles := map[string]*pb.BulkAddProjectRolesRequest_Role{}
|
||||
deleteRoles := []*pb.BulkAddProjectRolesRequest_Role{}
|
||||
for _, role := range wr.project.Spec.Roles {
|
||||
roles[role.Key] = &pb.BulkAddProjectRolesRequest_Role{
|
||||
Key: role.Key,
|
||||
DisplayName: role.DisplayName,
|
||||
Group: role.Group,
|
||||
}
|
||||
}
|
||||
|
||||
for _, role := range resp.Result {
|
||||
if r, ok := roles[role.Key]; ok {
|
||||
if r.DisplayName != role.DisplayName || r.Group != role.Group {
|
||||
deleteRoles = append(deleteRoles, r)
|
||||
} else {
|
||||
delete(roles, role.Key)
|
||||
}
|
||||
} else {
|
||||
delete(roles, role.Key)
|
||||
}
|
||||
}
|
||||
|
||||
for _, dRole := range deleteRoles {
|
||||
if _, err = ztdClient.RemoveProjectRole(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.RemoveProjectRoleRequest{
|
||||
ProjectId: wr.project.Status.ProjectId,
|
||||
RoleKey: dRole.Key,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Error removing project role: %v", err)
|
||||
}
|
||||
}
|
||||
if len(roles) > 0 {
|
||||
_, err = ztdClient.BulkAddProjectRoles(middleware.SetOrgID(ctx, org.Status.OrgId), &pb.BulkAddProjectRolesRequest{
|
||||
ProjectId: wr.project.Status.ProjectId,
|
||||
Roles: maps.Values(roles)})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not add roles to project: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wr *wrappedProjectReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error {
|
||||
patch := client.MergeFrom(wr.project.DeepCopy())
|
||||
patcher(&wr.project.Status)
|
||||
|
||||
Reference in New Issue
Block a user