Skip to content

Commit

Permalink
feat(spacetemplate): implemented merge strategy for rsquotas and Addi…
Browse files Browse the repository at this point in the history
…tionalRoleBinding

Signed-off-by: abelhoula <[email protected]>
  • Loading branch information
abelhoula committed Oct 23, 2023
1 parent 5dd09ed commit 3fababc
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 39 deletions.
4 changes: 1 addition & 3 deletions api/v1alpha1/spacetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,14 @@ type SpaceTemplateSpec struct {

// SpaceTemplateStatus defines the observed state of SpaceTemplate.
type SpaceTemplateStatus struct {
// Status is the status of the cluster.
Status string `json:"status"`
// Conditions List of status conditions to indicate the status of Space
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster, categories={spacetemplate}
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age"
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready"

// SpaceTemplate is the Schema for the spacetemplates API.
Expand Down
13 changes: 4 additions & 9 deletions config/crd/bases/nauticus.io_spacetemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ spec:
scope: Cluster
versions:
- additionalPrinterColumns:
- description: Ready
jsonPath: .status.conditions[?(@.type=='Ready')].status
name: Ready
type: string
- description: Age
jsonPath: .metadata.creationTimestamp
name: Age
type: date
- description: Ready
jsonPath: .status.conditions[?(@.type=='Ready')].status
name: Ready
Expand Down Expand Up @@ -859,11 +859,6 @@ spec:
- type
type: object
type: array
status:
description: Status is the status of the cluster.
type: string
required:
- status
type: object
type: object
served: true
Expand Down
53 changes: 53 additions & 0 deletions config/samples/space_with_tpl_merge.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
apiVersion: nauticus.io/v1alpha1
kind: Space
metadata:
labels:
app.kubernetes.io/name: space
app.kubernetes.io/instance: space-sample
app.kubernetes.io/part-of: nauticus
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/created-by: nauticus
name: space-tpl-ref-merge
spec:
templateRef:
group: nauticus.io/v1alpha1
kind: SpaceTemplate # Specify the Kind of the referenced resource
name: space-tpl-sample # Name of the SpaceTemplate
owners:
- name: smile
kind: User
- name: [email protected]
kind: Group
resourceQuota:
hard:
limits.cpu: "4"
limits.memory: 8Gi
requests.cpu: "2"
requests.memory: 3Gi
additionalRoleBindings:
- roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: viewer
subjects:
- name: dev
kind: Group
- roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: editor
subjects:
- name: ali
kind: User
networkPolicies:
enableDefaultStrictMode: false # false
items:
- policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 1.1.1.1/0
except:
- 192.168.0.0/16
podSelector: { }
21 changes: 1 addition & 20 deletions controllers/shared/utlis.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ package shared
import (
"context"

"github.com/edixos/nauticus/api/v1alpha1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand All @@ -20,24 +19,6 @@ func (r *Reconciler) DeleteObject(ctx context.Context, object client.Object) (er
return nil
}

func (r *Reconciler) FetchSpaceTemplate(ctx context.Context, name string) (*v1alpha1.SpaceTemplate, error) {
spaceTemplate := &v1alpha1.SpaceTemplate{}

err := r.Get(ctx, client.ObjectKey{
Name: name,
}, spaceTemplate)
if err != nil {
if apierrors.IsNotFound(err) {
// SpaceTemplate not found, return
r.Log.Info("SpaceTemplate not found")
}

return nil, err
}

return spaceTemplate, nil
}

func (r *Reconciler) ProcessFailedCondition(ctx context.Context, object ConditionedObject, conditionType string, status metav1.ConditionStatus, reason, message string) {
r.setCondition(object, object.GetGeneration(), conditionType, status, reason, message)
err := r.UpdateStatus(ctx, object)
Expand Down
16 changes: 9 additions & 7 deletions controllers/space/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,17 +135,19 @@ func (r *Reconciler) reconcileSpaceFromTemplate(ctx context.Context, space *naut
}

// Update the existing Space resource with the data from the SpaceTemplate
// Check if specific fields in the Space spec are not provided
if reflect.ValueOf(space.Spec.ResourceQuota).IsZero() {
space.Spec.ResourceQuota = spacetpl.Spec.ResourceQuota
rs, err := r.MergeResourceQuotas(space, spacetpl)
if err == nil {
space.Spec.ResourceQuota = *rs
}

if reflect.ValueOf(space.Spec.AdditionalRoleBindings).IsZero() {
space.Spec.AdditionalRoleBindings = spacetpl.Spec.AdditionalRoleBindings
rb, err := r.MergeRoleBindings(space, spacetpl)
if err == nil {
space.Spec.AdditionalRoleBindings = rb
}

if reflect.ValueOf(space.Spec.NetworkPolicies).IsZero() {
space.Spec.NetworkPolicies = spacetpl.Spec.NetworkPolicies
netPolicies, err := r.MergeNetworkPolicies(space, spacetpl)
if err == nil {
space.Spec.NetworkPolicies.Items = netPolicies.Items
}

if reflect.ValueOf(space.Spec.LimitRanges).IsZero() {
Expand Down
117 changes: 117 additions & 0 deletions controllers/space/utlis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2022-2023 Edixos
// SPDX-License-Identifier: Apache-2.0
package space

import (
"context"
"errors"
"reflect"

nauticusiov1alpha1 "github.com/edixos/nauticus/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"

"sigs.k8s.io/controller-runtime/pkg/client"
)

func (r *Reconciler) FetchSpaceTemplate(ctx context.Context, name string) (*nauticusiov1alpha1.SpaceTemplate, error) {
spaceTemplate := &nauticusiov1alpha1.SpaceTemplate{}

err := r.Get(ctx, client.ObjectKey{
Name: name,
}, spaceTemplate)
if err != nil {
if apierrors.IsNotFound(err) {
// SpaceTemplate not found, return
r.Log.Info("SpaceTemplate not found")
}

return nil, err
}

return spaceTemplate, nil
}

func (r *Reconciler) MergeResourceQuotas(space *nauticusiov1alpha1.Space, spacetpl *nauticusiov1alpha1.SpaceTemplate) (*corev1.ResourceQuotaSpec, error) {
resourceQuotas := &corev1.ResourceQuotaSpec{}
resourceQuotas.Hard = make(corev1.ResourceList)
// Check if resourceQuota is provided in the Space and spaceTemplate
switch {
case !reflect.ValueOf(space.Spec.ResourceQuota).IsZero() && !reflect.ValueOf(spacetpl.Spec.ResourceQuota).IsZero():
overrideResourceQuotas(resourceQuotas, space.Spec.ResourceQuota.Hard, spacetpl.Spec.ResourceQuota.Hard, corev1.ResourceLimitsCPU)
overrideResourceQuotas(resourceQuotas, space.Spec.ResourceQuota.Hard, spacetpl.Spec.ResourceQuota.Hard, corev1.ResourceLimitsMemory)
overrideResourceQuotas(resourceQuotas, space.Spec.ResourceQuota.Hard, spacetpl.Spec.ResourceQuota.Hard, corev1.ResourceRequestsCPU)
overrideResourceQuotas(resourceQuotas, space.Spec.ResourceQuota.Hard, spacetpl.Spec.ResourceQuota.Hard, corev1.ResourceRequestsMemory)
case reflect.ValueOf(space.Spec.ResourceQuota).IsZero() && !reflect.ValueOf(spacetpl.Spec.ResourceQuota).IsZero():
resourceQuotas.Hard = spacetpl.Spec.ResourceQuota.Hard
default:
err := errors.New("both space and spacetpl resource quotas are empty. No merge required")

return resourceQuotas, err
}

return resourceQuotas, nil
}

func (r *Reconciler) MergeRoleBindings(space *nauticusiov1alpha1.Space, spaceTemplate *nauticusiov1alpha1.SpaceTemplate) ([]nauticusiov1alpha1.AdditionalRoleBinding, error) {
mergedRoleBindings := append([]nauticusiov1alpha1.AdditionalRoleBinding{}, space.Spec.AdditionalRoleBindings...)

for _, roleBinding := range spaceTemplate.Spec.AdditionalRoleBindings {
// Check if the role binding already exists in mergedRoleBindings
if !cmpRoleBinding(mergedRoleBindings, roleBinding) {
mergedRoleBindings = append(mergedRoleBindings, roleBinding)
}
}

return mergedRoleBindings, nil
}

func (r *Reconciler) MergeNetworkPolicies(space *nauticusiov1alpha1.Space, spaceTemplate *nauticusiov1alpha1.SpaceTemplate) (nauticusiov1alpha1.NetworkPolicies, error) {
mergedPolicies := space.Spec.NetworkPolicies

// Check if EnableDefaultStrictMode is not provided in the space
if reflect.ValueOf(mergedPolicies.EnableDefaultStrictMode).IsZero() {
mergedPolicies.EnableDefaultStrictMode = spaceTemplate.Spec.NetworkPolicies.EnableDefaultStrictMode
}

for _, templatePolicy := range spaceTemplate.Spec.NetworkPolicies.Items {
// Check if the policy already exists in mergedPolicies
if !cmpNetworkPolicy(mergedPolicies, templatePolicy) {
mergedPolicies.Items = append(mergedPolicies.Items, templatePolicy)
}
}

return mergedPolicies, nil
}

func overrideResourceQuotas(resourceQuotas *corev1.ResourceQuotaSpec, spaceHard, templateHard corev1.ResourceList, resource corev1.ResourceName) {
if spaceValue, exists := spaceHard[resource]; exists {
resourceQuotas.Hard[resource] = spaceValue
} else {
resourceQuotas.Hard[resource] = templateHard[resource]
}
}

func cmpRoleBinding(roleBindings []nauticusiov1alpha1.AdditionalRoleBinding, roleBinding nauticusiov1alpha1.AdditionalRoleBinding) bool {
for _, rb := range roleBindings {
if rb.RoleRef.Name == roleBinding.RoleRef.Name && rb.RoleRef.Kind == roleBinding.RoleRef.Kind {
// Check if subjects are equal
if reflect.DeepEqual(rb.Subjects, roleBinding.Subjects) {
return true
}
}
}

return false
}

func cmpNetworkPolicy(mergedPolicies nauticusiov1alpha1.NetworkPolicies, policy networkingv1.NetworkPolicySpec) bool {
for _, mergedPolicy := range mergedPolicies.Items {
if reflect.DeepEqual(mergedPolicy, policy) {
return true
}
}

return false
}

0 comments on commit 3fababc

Please sign in to comment.