Skip to content

Commit

Permalink
Add Group CRD
Browse files Browse the repository at this point in the history
  • Loading branch information
assafad1 committed Jan 6, 2025
1 parent b9c3e24 commit bc6e47c
Show file tree
Hide file tree
Showing 19 changed files with 1,294 additions and 40 deletions.
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,13 @@ resources:
kind: Scope
path: github.com/coralogix/coralogix-operator/api/coralogix/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: coralogix.com
group: coralogix
kind: Group
path: github.com/coralogix/coralogix-operator/api/coralogix/v1alpha1
version: v1alpha1
version: "3"
221 changes: 221 additions & 0 deletions api/coralogix/v1alpha1/group_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// Copyright 2024 Coralogix Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
"context"
"errors"
"fmt"
"strconv"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"

cxsdk "github.com/coralogix/coralogix-management-sdk/go"
)

// GroupSpec defines the desired state of Group.
type GroupSpec struct {
Name string `json:"name"`

Description *string `json:"description,omitempty"`

// +optional
Members []Member `json:"members,omitempty"`

CustomRoles []GroupCustomRole `json:"customRoles"`

// +optional
Scope *GroupScope `json:"scope,omitempty"`
}

type Member struct {
UserName string `json:"userName"`
}

type GroupCustomRole struct {
CustomRoleRef string `json:"customRoleRef"`
}

type GroupScope struct {
ScopeRef string `json:"scopeRef"`
}

func (g *Group) ExtractCreateGroupRequest(
ctx context.Context, k8sClient client.Client,
cxClient *cxsdk.ClientSet) (*cxsdk.CreateTeamGroupRequest, error) {
usersIds, err := g.ExtractUsersIds(ctx, cxClient)
if err != nil {
return nil, err
}

rolesIds, err := g.ExtractRolesIds(k8sClient)
if err != nil {
return nil, err
}

scopeId, err := g.ExtractScopeId(k8sClient)
if err != nil {
return nil, err
}

return &cxsdk.CreateTeamGroupRequest{
Name: g.Spec.Name,
Description: g.Spec.Description,
UserIds: usersIds,
RoleIds: rolesIds,
NextGenScopeId: scopeId,
}, nil
}

func (g *Group) ExtractUpdateGroupRequest(
ctx context.Context, k8sClient client.Client, cxClient *cxsdk.ClientSet,
groupID *string) (*cxsdk.UpdateTeamGroupRequest, error) {
usersIds, err := g.ExtractUsersIds(ctx, cxClient)
if err != nil {
return nil, err
}

rolesIds, err := g.ExtractRolesIds(k8sClient)
if err != nil {
return nil, err
}

scopeId, err := g.ExtractScopeId(k8sClient)
if err != nil {
return nil, err
}

id, err := strconv.Atoi(*groupID)
if err != nil {
return nil, err
}

return &cxsdk.UpdateTeamGroupRequest{
GroupId: ptr.To(cxsdk.TeamGroupID{Id: uint32(id)}),
Name: g.Spec.Name,
Description: g.Spec.Description,
UserUpdates: ptr.To(cxsdk.UpdateTeamGroupRequestUserUpdates{UserIds: usersIds}),
RoleUpdates: ptr.To(cxsdk.UpdateTeamGroupRequestRoleUpdates{RoleIds: rolesIds}),
NextGenScopeId: scopeId,
}, nil
}

func (g *Group) ExtractUsersIds(ctx context.Context, cxClient *cxsdk.ClientSet) ([]*cxsdk.UserID, error) {
users, err := cxClient.Users().List(ctx)
if err != nil {
return nil, err
}

var usersIds []*cxsdk.UserID
var errs error
for _, member := range g.Spec.Members {
found := false
for _, user := range users {
if user.UserName == member.UserName {
found = true
usersIds = append(usersIds, &cxsdk.UserID{Id: *user.ID})
break
}
}
if !found {
errs = errors.Join(errs, fmt.Errorf("user %s not found", member.UserName))
}
}

if errs != nil {
return nil, errs
}

return usersIds, nil
}

func (g *Group) ExtractRolesIds(k8sClient client.Client) ([]*cxsdk.RoleID, error) {
var rolesIds []*cxsdk.RoleID
var errs error
for _, customRole := range g.Spec.CustomRoles {
cr := &CustomRole{}
if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: customRole.CustomRoleRef, Namespace: g.Namespace}, cr); err != nil {
errs = errors.Join(errs, err)
continue
}

if cr.Status.ID == nil {
errs = errors.Join(errs, fmt.Errorf("ID is not populated for CustomRole %s", customRole.CustomRoleRef))
continue
}

roleID, err := strconv.Atoi(*cr.Status.ID)
if err != nil {
errs = errors.Join(errs, err)
} else {
rolesIds = append(rolesIds, &cxsdk.RoleID{Id: uint32(roleID)})
}
}

if errs != nil {
return nil, errs
}

return rolesIds, nil
}

func (g *Group) ExtractScopeId(k8sClient client.Client) (*string, error) {
if g.Spec.Scope == nil {
return nil, nil
}

sc := &Scope{}
if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: g.Spec.Scope.ScopeRef, Namespace: g.Namespace}, sc); err != nil {
return nil, err
}

if sc.Status.ID == nil {
return nil, fmt.Errorf("ID is not populated for Scope %s", g.Spec.Scope.ScopeRef)
}

return sc.Status.ID, nil
}

// GroupStatus defines the observed state of Group.
type GroupStatus struct {
ID *string `json:"id,"`
}

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

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

Spec GroupSpec `json:"spec,omitempty"`
Status GroupStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

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

func init() {
SchemeBuilder.Register(&Group{}, &GroupList{})
}
Loading

0 comments on commit bc6e47c

Please sign in to comment.