-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #392 from heypnus/np/controller
The implementation of network policy controller
- Loading branch information
Showing
17 changed files
with
1,268 additions
and
257 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
195 changes: 195 additions & 0 deletions
195
pkg/controllers/networkpolicy/networkpolicy_controller.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* Copyright © 2024 VMware, Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 */ | ||
|
||
package networkpolicy | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"os" | ||
"runtime" | ||
"time" | ||
|
||
networkingv1 "k8s.io/api/networking/v1" | ||
apimachineryruntime "k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/apimachinery/pkg/util/sets" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
"github.com/vmware-tanzu/nsx-operator/pkg/controllers/common" | ||
"github.com/vmware-tanzu/nsx-operator/pkg/logger" | ||
"github.com/vmware-tanzu/nsx-operator/pkg/metrics" | ||
_ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter" | ||
servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common" | ||
"github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/securitypolicy" | ||
nsxutil "github.com/vmware-tanzu/nsx-operator/pkg/nsx/util" | ||
) | ||
|
||
var ( | ||
log = logger.Log | ||
ResultNormal = common.ResultNormal | ||
ResultRequeue = common.ResultRequeue | ||
ResultRequeueAfter5mins = common.ResultRequeueAfter5mins | ||
MetricResType = common.MetricResTypeNetworkPolicy | ||
) | ||
|
||
// NetworkPolicyReconciler reconciles a NetworkPolicy object | ||
type NetworkPolicyReconciler struct { | ||
Client client.Client | ||
Scheme *apimachineryruntime.Scheme | ||
Service *securitypolicy.SecurityPolicyService | ||
} | ||
|
||
func updateFail(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy, e *error) { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateFailTotal, MetricResType) | ||
} | ||
|
||
func deleteFail(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy, e *error) { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) | ||
} | ||
|
||
func updateSuccess(r *NetworkPolicyReconciler, c *context.Context, o *networkingv1.NetworkPolicy) { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateSuccessTotal, MetricResType) | ||
} | ||
|
||
func deleteSuccess(r *NetworkPolicyReconciler, _ *context.Context, _ *networkingv1.NetworkPolicy) { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) | ||
} | ||
|
||
func (r *NetworkPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
networkPolicy := &networkingv1.NetworkPolicy{} | ||
log.Info("reconciling networkpolicy", "networkpolicy", req.NamespacedName) | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType) | ||
|
||
if err := r.Client.Get(ctx, req.NamespacedName, networkPolicy); err != nil { | ||
log.Error(err, "unable to fetch network policy", "req", req.NamespacedName) | ||
return ResultNormal, client.IgnoreNotFound(err) | ||
} | ||
|
||
if networkPolicy.ObjectMeta.DeletionTimestamp.IsZero() { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType) | ||
if !controllerutil.ContainsFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) { | ||
controllerutil.AddFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) | ||
if err := r.Client.Update(ctx, networkPolicy); err != nil { | ||
log.Error(err, "add finalizer", "networkpolicy", req.NamespacedName) | ||
updateFail(r, &ctx, networkPolicy, &err) | ||
return ResultRequeue, err | ||
} | ||
log.V(1).Info("added finalizer on networkpolicy", "networkpolicy", req.NamespacedName) | ||
} | ||
|
||
if err := r.Service.CreateOrUpdateSecurityPolicy(networkPolicy); err != nil { | ||
if errors.As(err, &nsxutil.RestrictionError{}) { | ||
log.Error(err, err.Error(), "networkpolicy", req.NamespacedName) | ||
updateFail(r, &ctx, networkPolicy, &err) | ||
return ResultNormal, nil | ||
} | ||
log.Error(err, "create or update failed, would retry exponentially", "networkpolicy", req.NamespacedName) | ||
updateFail(r, &ctx, networkPolicy, &err) | ||
return ResultRequeue, err | ||
} | ||
updateSuccess(r, &ctx, networkPolicy) | ||
} else { | ||
if controllerutil.ContainsFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) | ||
if err := r.Service.DeleteSecurityPolicy(networkPolicy, false, servicecommon.ResourceTypeNetworkPolicy); err != nil { | ||
log.Error(err, "deletion failed, would retry exponentially", "networkpolicy", req.NamespacedName) | ||
deleteFail(r, &ctx, networkPolicy, &err) | ||
return ResultRequeue, err | ||
} | ||
controllerutil.RemoveFinalizer(networkPolicy, servicecommon.NetworkPolicyFinalizerName) | ||
if err := r.Client.Update(ctx, networkPolicy); err != nil { | ||
log.Error(err, "deletion failed, would retry exponentially", "networkpolicy", req.NamespacedName) | ||
deleteFail(r, &ctx, networkPolicy, &err) | ||
return ResultRequeue, err | ||
} | ||
log.V(1).Info("removed finalizer", "networkpolicy", req.NamespacedName) | ||
deleteSuccess(r, &ctx, networkPolicy) | ||
} else { | ||
// only print a message because it's not a normal case | ||
log.Info("finalizers cannot be recognized", "networkpolicy", req.NamespacedName) | ||
} | ||
} | ||
|
||
return ResultNormal, nil | ||
} | ||
|
||
func (r *NetworkPolicyReconciler) setupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&networkingv1.NetworkPolicy{}). | ||
WithOptions( | ||
controller.Options{ | ||
MaxConcurrentReconciles: runtime.NumCPU(), | ||
}). | ||
Complete(r) | ||
} | ||
|
||
// Start setup manager and launch GC | ||
func (r *NetworkPolicyReconciler) Start(mgr ctrl.Manager) error { | ||
err := r.setupWithManager(mgr) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
go r.GarbageCollector(make(chan bool), servicecommon.GCInterval) | ||
return nil | ||
} | ||
|
||
// GarbageCollector collect networkpolicy which has been removed from K8s. | ||
// cancel is used to break the loop during UT | ||
func (r *NetworkPolicyReconciler) GarbageCollector(cancel chan bool, timeout time.Duration) { | ||
ctx := context.Background() | ||
log.Info("garbage collector started") | ||
for { | ||
select { | ||
case <-cancel: | ||
return | ||
case <-time.After(timeout): | ||
} | ||
nsxPolicySet := r.Service.ListNetworkPolicyID() | ||
if len(nsxPolicySet) == 0 { | ||
continue | ||
} | ||
policyList := &networkingv1.NetworkPolicyList{} | ||
err := r.Client.List(ctx, policyList) | ||
if err != nil { | ||
log.Error(err, "failed to list NetworkPolicy") | ||
continue | ||
} | ||
|
||
CRPolicySet := sets.NewString() | ||
for _, policy := range policyList.Items { | ||
CRPolicySet.Insert(r.Service.BuildNetworkPolicyAllowPolicyID(string(policy.UID))) | ||
CRPolicySet.Insert(r.Service.BuildNetworkPolicyIsolationPolicyID(string(policy.UID))) | ||
} | ||
|
||
for elem := range nsxPolicySet { | ||
if CRPolicySet.Has(elem) { | ||
continue | ||
} | ||
log.V(1).Info("GC collected NetworkPolicy", "ID", elem) | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteTotal, MetricResType) | ||
err = r.Service.DeleteSecurityPolicy(types.UID(elem), false, servicecommon.ResourceTypeNetworkPolicy) | ||
if err != nil { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteFailTotal, MetricResType) | ||
} else { | ||
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerDeleteSuccessTotal, MetricResType) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func StartNetworkPolicyController(mgr ctrl.Manager, commonService servicecommon.Service) { | ||
networkPolicyReconcile := NetworkPolicyReconciler{ | ||
Client: mgr.GetClient(), | ||
Scheme: mgr.GetScheme(), | ||
} | ||
networkPolicyReconcile.Service = securitypolicy.GetSecurityService(commonService) | ||
if err := networkPolicyReconcile.Start(mgr); err != nil { | ||
log.Error(err, "failed to create controller", "controller", "NetworkPolicy") | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.