Skip to content

Commit

Permalink
fix(core): Make controllers to update CRDs status
Browse files Browse the repository at this point in the history
Signed-off-by: Anurag Rajawat <[email protected]>
  • Loading branch information
anurag-rajawat committed Feb 14, 2024
1 parent 20b9ba9 commit ac7a09d
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 281 deletions.
112 changes: 82 additions & 30 deletions internal/controller/clustersecurityintentbinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@ import (
"context"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

v1 "github.com/5GSEC/nimbus/api/v1"
"github.com/5GSEC/nimbus/pkg/processor/intentbinder"
"github.com/5GSEC/nimbus/pkg/processor/policybuilder"
)

var csibUpdated bool

// ClusterSecurityIntentBindingReconciler reconciles a ClusterSecurityIntentBinding object
type ClusterSecurityIntentBindingReconciler struct {
client.Client
Expand Down Expand Up @@ -45,61 +50,108 @@ func (r *ClusterSecurityIntentBindingReconciler) Reconcile(ctx context.Context,
return ctrl.Result{}, err
}

if csib.Status.Status == "" || csib.Status.Status == StatusPending {
csib.Status.Status = StatusCreated
if err := r.Status().Update(ctx, csib); err != nil {
logger.Error(err, "failed to update ClusterSecurityIntentBinding status", "ClusterSecurityIntentBinding.Name", csib.Name)
return ctrl.Result{}, err
}
// Let's re-fetch the ClusterSecurityIntentBinding CR after updating the status
// so that we have the latest state of the resource on the cluster.
if err := r.Get(ctx, req.NamespacedName, csib); err != nil {
logger.Error(err, "failed to re-fetch ClusterSecurityIntentBinding", "ClusterSecurityIntentBinding.Name", csib.Name)
return ctrl.Result{}, err
}
if csibUpdated {
logger.Info("ClusterSecurityIntentBinding modified", "ClusterSecurityIntentBinding.Name", csib.Name)
} else {
logger.Info("ClusterSecurityIntentBinding found", "ClusterSecurityIntentBinding.Name", csib.Name)
return ctrl.Result{}, nil
}

bindingInfo := intentbinder.MatchAndBindIntentsGlobal(ctx, r.Client, csib)

clusterNp, err := policybuilder.BuildClusterNimbusPolicy(ctx, r.Client, r.Scheme, bindingInfo)
intents := intentbinder.ExtractIntents(ctx, r.Client, csib)
clusterNp, err := policybuilder.BuildClusterNimbusPolicy(ctx, r.Scheme, csib, intents)
if err != nil {
logger.Error(err, "failed to build ClusterNimbusPolicy")
return ctrl.Result{}, err
}

existingClusterNp := &v1.ClusterNimbusPolicy{}
err = r.Get(ctx, types.NamespacedName{Name: req.Name}, existingClusterNp)
if err != nil && errors.IsNotFound(err) {
if err := r.Create(ctx, clusterNp); err != nil {
logger.Error(err, "failed to create ClusterNimbusPolicy", "ClusterNimbusPolicy.Name", clusterNp.Name)
return ctrl.Result{}, err
if err != nil {
if errors.IsNotFound(err) {
if err := r.Create(ctx, clusterNp); err != nil {
logger.Error(err, "failed to create ClusterNimbusPolicy", "ClusterNimbusPolicy.Name", clusterNp.Name)
return ctrl.Result{}, err
}
logger.Info("ClusterNimbusPolicy created", "ClusterNimbusPolicy.Name", clusterNp.Name)
if err = r.updateStatus(ctx, clusterNp); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
return ctrl.Result{}, nil
logger.Error(err, "failed to get ClusterNimbusPolicy", "ClusterNimbusPolicy.Name", clusterNp.Name)
return ctrl.Result{}, err
}
clusterNp.ObjectMeta = existingClusterNp.ObjectMeta

// TODO: Try with backoff just like NP
clusterNp.ObjectMeta.ResourceVersion = existingClusterNp.ObjectMeta.ResourceVersion
if err := r.Update(ctx, clusterNp); err != nil {
logger.Error(err, "failed to update ClusterNimbusPolicy")
return ctrl.Result{}, err
}
logger.Info("ClusterNimbusPolicy modified", "ClusterNimbusPolicy.Name", clusterNp.Name)

if clusterNp.Status.Status == "" || clusterNp.Status.Status == StatusPending {
clusterNp.Status.Status = StatusCreated
if err := r.Status().Update(ctx, clusterNp); err != nil {
logger.Error(err, "failed to update ClusterNimbusPolicy status", "ClusterNimbusPolicy.Name", clusterNp.Name)
return ctrl.Result{}, err
}
logger.Info("ClusterNimbusPolicy created", "ClusterNimbusPolicy.Name", clusterNp.Name)
if err = r.updateStatus(ctx, clusterNp); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterSecurityIntentBindingReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1.ClusterSecurityIntentBinding{}).
WithEventFilter(
predicate.Funcs{
UpdateFunc: r.updateFn,
},
).
Owns(&v1.ClusterNimbusPolicy{}).
Complete(r)
}

// updateFn returns true if the ClusterSecurityIntentBinding or ClusterNimbusPolicy spec has been updated.
func (r *ClusterSecurityIntentBindingReconciler) updateFn(updateEvent event.UpdateEvent) bool {
switch updateEvent.ObjectOld.(type) {
case *v1.ClusterSecurityIntentBinding:
csibUpdated = isSpecUpdated(updateEvent, "csib")
return csibUpdated
case *v1.ClusterNimbusPolicy:
return isSpecUpdated(updateEvent, "cwnp")
default:
return false
}
}

func (r *ClusterSecurityIntentBindingReconciler) updateStatus(ctx context.Context, cwnp *v1.ClusterNimbusPolicy) error {
logger := log.FromContext(ctx)
name := cwnp.Name

cwnp.Status = v1.ClusterNimbusPolicyStatus{
Status: StatusCreated,
LastUpdated: metav1.Now(),
}
if err := r.Status().Update(ctx, cwnp); err != nil {
logger.Error(err, "failed to update ClusterNimbusPolicy status", "ClusterNimbusPolicy.Name", name)
return err
}

existingCsib := &v1.ClusterSecurityIntentBinding{}
if err := r.Get(ctx, types.NamespacedName{Name: name}, existingCsib); err != nil {
logger.Error(err, "failed to get ClusterSecurityIntentBinding", "ClusterSecurityIntentBinding.Name", name)
return err
}

intentsCount, intentsName := extractBoundIntentsInfo(existingCsib.Spec.Intents)
existingCsib.Status = v1.ClusterSecurityIntentBindingStatus{
Status: StatusCreated,
LastUpdated: metav1.Now(),
NumberOfBoundIntents: intentsCount,
BoundIntents: intentsName,
ClusterNimbusPolicy: name,
}
if err := r.Status().Update(ctx, existingCsib); err != nil {
logger.Error(err, "failed to update ClusterNimbusPolicy status", "ClusterNimbusPolicy.Name", name)
return err
}

return nil
}
57 changes: 37 additions & 20 deletions internal/controller/securityintent_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import (
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"

v1 "github.com/5GSEC/nimbus/api/v1"
)

var siUpdated bool

type SecurityIntentReconciler struct {
client.Client
Scheme *runtime.Scheme
Expand Down Expand Up @@ -46,6 +50,11 @@ func (r *SecurityIntentReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, err
}

if err = r.updateStatus(ctx, si); err != nil {
logger.Error(err, "failed to update SecurityIntent status", "SecurityIntent.Name", si.Name)
return ctrl.Result{}, err
}

var sibList v1.SecurityIntentBindingList
if err := r.List(ctx, &sibList, client.InNamespace(req.Namespace)); err != nil {
logger.Error(err, "unable to list SecurityIntentBindings for update")
Expand All @@ -67,26 +76,28 @@ func (r *SecurityIntentReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}
}

if si.Status.Status == "" || si.Status.Status == StatusPending {
si.Status.Status = StatusCreated
if err = r.Status().Update(ctx, si); err != nil {
logger.Error(err, "failed to update SecurityIntent status", "SecurityIntent.Name", si.Name)
return ctrl.Result{}, err
}

// Let's re-fetch the SecurityIntent Custom Resource after updating the status so
// that we have the latest state of the resource on the cluster.
if err = r.Get(ctx, types.NamespacedName{Name: si.Name, Namespace: si.Namespace}, si); err != nil {
logger.Error(err, "failed to re-fetch SecurityIntent", "SecurityIntent.Name", si.Name)
return ctrl.Result{}, err
}

if !siUpdated {
logger.Info("SecurityIntent found", "SecurityIntent.Name", si.Name)
} else {
logger.Info("SecurityIntent modified", "SecurityIntent.Name", si.Name)
}

return ctrl.Result{}, nil
}

// SetupWithManager sets up the reconciler with the provided manager.
func (r *SecurityIntentReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Set up the controller to manage SecurityIntent resources.
return ctrl.NewControllerManagedBy(mgr).
For(&v1.SecurityIntent{}).
WithEventFilter(
predicate.Funcs{
UpdateFunc: r.updateFn,
},
).
Complete(r)
}

// Update related SecurityIntentBindings after SecurityIntent deletion
func (r *SecurityIntentReconciler) updateRelatedSIBs(ctx context.Context, req ctrl.Request) error {
var sibList v1.SecurityIntentBindingList
Expand Down Expand Up @@ -120,10 +131,16 @@ func (r *SecurityIntentReconciler) updateRelatedSIBs(ctx context.Context, req ct
return nil
}

// SetupWithManager sets up the reconciler with the provided manager.
func (r *SecurityIntentReconciler) SetupWithManager(mgr ctrl.Manager) error {
// Set up the controller to manage SecurityIntent resources.
return ctrl.NewControllerManagedBy(mgr).
For(&v1.SecurityIntent{}).
Complete(r)
func (r *SecurityIntentReconciler) updateFn(updateEvent event.UpdateEvent) bool {
siUpdated = isSpecUpdated(updateEvent, "si")
return siUpdated
}

func (r *SecurityIntentReconciler) updateStatus(ctx context.Context, si *v1.SecurityIntent) error {
si.Status = v1.SecurityIntentStatus{
ID: si.Spec.Intent.ID,
Action: si.Spec.Intent.Action,
Status: StatusCreated,
}
return r.Status().Update(ctx, si)
}
Loading

0 comments on commit ac7a09d

Please sign in to comment.