mirror of
https://github.com/YuzuZensai/netbird-kubernetes-operator.git
synced 2026-09-13 10:49:15 +00:00
Add support for multiple policies (#16)
Change policy annotation to support comma-separated list of policies. --------- Co-authored-by: Maycon Santos <mlsmaycon@gmail.com>
This commit is contained in:
co-authored by
Maycon Santos
parent
6a33bffb65
commit
219ee9a0b6
@@ -77,7 +77,7 @@ func (r *NBPolicyReconciler) mapResources(ctx context.Context, nbPolicy *netbird
|
||||
}
|
||||
|
||||
for _, resource := range resources {
|
||||
if resource.Status.PolicyName != nil && *resource.Status.PolicyName == nbPolicy.Name {
|
||||
if resource.Status.PolicyName != nil && util.Contains(util.SplitTrim(*resource.Status.PolicyName, ","), nbPolicy.Name) {
|
||||
// Groups
|
||||
groups = append(groups, resource.Status.Groups...)
|
||||
|
||||
|
||||
@@ -109,82 +109,108 @@ func (r *NBResourceReconciler) handlePolicy(ctx context.Context, req ctrl.Reques
|
||||
return nil
|
||||
}
|
||||
|
||||
updatePolicyStatus := false
|
||||
|
||||
var nbPolicy netbirdiov1.NBPolicy
|
||||
if nbResource.Spec.PolicyName == "" && nbResource.Status.PolicyName != nil {
|
||||
// Remove self reference from policy status
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: *nbResource.Status.PolicyName}, &nbPolicy)
|
||||
nbResource.Status.PolicyName = nil
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
return err
|
||||
}
|
||||
if util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
} else {
|
||||
// Update policy settings if any difference is found
|
||||
if nbResource.Status.PolicyName != nil {
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: *nbResource.Status.PolicyName}, &nbPolicy)
|
||||
if !errors.IsNotFound(err) {
|
||||
policies := util.SplitTrim(*nbResource.Status.PolicyName, ",")
|
||||
for _, policyName := range policies {
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: policyName}, &nbPolicy)
|
||||
nbResource.Status.PolicyName = nil
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", policyName)
|
||||
return err
|
||||
}
|
||||
if util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", policyName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
specPolicies := util.SplitTrim(nbResource.Spec.PolicyName, ",")
|
||||
var statusPolicies []string
|
||||
if nbResource.Status.PolicyName != nil {
|
||||
statusPolicies = util.SplitTrim(*nbResource.Status.PolicyName, ",")
|
||||
}
|
||||
|
||||
if util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||
for _, policy := range specPolicies {
|
||||
updatePolicyStatus := false
|
||||
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: policy}, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", policy)
|
||||
return err
|
||||
}
|
||||
if !util.Contains(statusPolicies, policy) {
|
||||
// New
|
||||
if !util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = append(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
} else {
|
||||
// Check update
|
||||
if !util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = append(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Spec.TCPPorts, nbResource.Status.TCPPorts) {
|
||||
nbResource.Status.TCPPorts = nbResource.Spec.TCPPorts
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Spec.UDPPorts, nbResource.Status.UDPPorts) {
|
||||
nbResource.Status.UDPPorts = nbResource.Spec.UDPPorts
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Status.Groups, groupIDs) {
|
||||
nbResource.Status.Groups = groupIDs
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
}
|
||||
|
||||
if updatePolicyStatus {
|
||||
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", policy)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, policy := range statusPolicies {
|
||||
// Delete
|
||||
if !util.Contains(specPolicies, policy) {
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: policy}, &nbPolicy)
|
||||
if !errors.IsNotFound(err) {
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", policy)
|
||||
return err
|
||||
}
|
||||
|
||||
if util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", policy)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: nbResource.Spec.PolicyName}, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
return err
|
||||
}
|
||||
|
||||
if nbResource.Status.PolicyName == nil || *nbResource.Status.PolicyName != nbPolicy.Name {
|
||||
nbResource.Status.PolicyName = &nbPolicy.Name
|
||||
}
|
||||
|
||||
if !util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = append(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Spec.TCPPorts, nbResource.Status.TCPPorts) {
|
||||
nbResource.Status.TCPPorts = nbResource.Spec.TCPPorts
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Spec.UDPPorts, nbResource.Status.UDPPorts) {
|
||||
nbResource.Status.UDPPorts = nbResource.Spec.UDPPorts
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
|
||||
if !util.Equivalent(nbResource.Status.Groups, groupIDs) {
|
||||
nbResource.Status.Groups = groupIDs
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
updatePolicyStatus = true
|
||||
}
|
||||
}
|
||||
|
||||
if updatePolicyStatus {
|
||||
err := r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
logger.Error(errKubernetesAPI, "error updating NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
return err
|
||||
if nbResource.Status.PolicyName == nil || *nbResource.Status.PolicyName != nbResource.Spec.PolicyName {
|
||||
nbResource.Status.PolicyName = &nbResource.Spec.PolicyName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,20 +428,22 @@ func (r *NBResourceReconciler) handleGroups(ctx context.Context, req ctrl.Reques
|
||||
|
||||
func (r *NBResourceReconciler) handleDelete(ctx context.Context, req ctrl.Request, nbResource *netbirdiov1.NBResource, logger logr.Logger) error {
|
||||
if nbResource.Status.PolicyName != nil {
|
||||
var nbPolicy netbirdiov1.NBPolicy
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: *nbResource.Status.PolicyName}, &nbPolicy)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", nbResource.Spec.PolicyName)
|
||||
return err
|
||||
}
|
||||
|
||||
if !errors.IsNotFound(err) && util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
err = r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
for _, policy := range util.SplitTrim(*nbResource.Status.PolicyName, ",") {
|
||||
var nbPolicy netbirdiov1.NBPolicy
|
||||
err := r.Client.Get(ctx, types.NamespacedName{Name: policy}, &nbPolicy)
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
logger.Error(errKubernetesAPI, "error getting NBPolicy", "err", err, "policyName", policy)
|
||||
return err
|
||||
}
|
||||
|
||||
if !errors.IsNotFound(err) && util.Contains(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String()) {
|
||||
nbPolicy.Status.ManagedServiceList = util.Without(nbPolicy.Status.ManagedServiceList, req.NamespacedName.String())
|
||||
nbPolicy.Status.LastUpdatedAt = &v1.Time{Time: time.Now()}
|
||||
err = r.Client.Status().Update(ctx, &nbPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,6 +414,135 @@ var _ = Describe("NBResource Controller", func() {
|
||||
})
|
||||
})
|
||||
|
||||
When("Multiple Policies are specified", Ordered, func() {
|
||||
BeforeAll(func() {
|
||||
nbPolicy := &netbirdiov1.NBPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-a",
|
||||
},
|
||||
Spec: netbirdiov1.NBPolicySpec{
|
||||
Name: "Test A",
|
||||
SourceGroups: []string{"All"},
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.Create(ctx, nbPolicy)).To(Succeed())
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-b",
|
||||
},
|
||||
Spec: netbirdiov1.NBPolicySpec{
|
||||
Name: "Test B",
|
||||
SourceGroups: []string{"All"},
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.Create(ctx, nbPolicy)).To(Succeed())
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-c",
|
||||
},
|
||||
Spec: netbirdiov1.NBPolicySpec{
|
||||
Name: "Test C",
|
||||
SourceGroups: []string{"All"},
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.Create(ctx, nbPolicy)).To(Succeed())
|
||||
})
|
||||
|
||||
AfterAll(func() {
|
||||
nbPolicy := &netbirdiov1.NBPolicy{}
|
||||
err := k8sClient.Get(ctx, types.NamespacedName{Name: "test-a"}, nbPolicy)
|
||||
if !errors.IsNotFound(err) {
|
||||
Expect(k8sClient.Delete(ctx, nbPolicy)).To(Succeed())
|
||||
}
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
err = k8sClient.Get(ctx, types.NamespacedName{Name: "test-b"}, nbPolicy)
|
||||
if !errors.IsNotFound(err) {
|
||||
Expect(k8sClient.Delete(ctx, nbPolicy)).To(Succeed())
|
||||
}
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
err = k8sClient.Get(ctx, types.NamespacedName{Name: "test-c"}, nbPolicy)
|
||||
if !errors.IsNotFound(err) {
|
||||
Expect(k8sClient.Delete(ctx, nbPolicy)).To(Succeed())
|
||||
}
|
||||
})
|
||||
|
||||
It("should update policies status", func() {
|
||||
nbresource.Spec.PolicyName = "test-a, test-b"
|
||||
Expect(k8sClient.Update(ctx, nbresource)).To(Succeed())
|
||||
|
||||
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||
NamespacedName: typeNamespacedName,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
nbPolicy := &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-a"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).To(ContainElement("default/test-resource"))
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-b"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).To(ContainElement("default/test-resource"))
|
||||
})
|
||||
|
||||
When("Policy is updated", func() {
|
||||
It("should remove old reference and add new reference", func() {
|
||||
nbresource.Spec.PolicyName = "test-b,test-c"
|
||||
Expect(k8sClient.Update(ctx, nbresource)).To(Succeed())
|
||||
|
||||
nbresource.Status.PolicyName = util.Ptr("test-a,test-b")
|
||||
Expect(k8sClient.Status().Update(ctx, nbresource)).To(Succeed())
|
||||
|
||||
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||
NamespacedName: typeNamespacedName,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
nbPolicy := &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-a"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).NotTo(ContainElement("default/test-resource"))
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-b"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).To(ContainElement("default/test-resource"))
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-c"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).To(ContainElement("default/test-resource"))
|
||||
})
|
||||
})
|
||||
|
||||
When("Policy is removed", func() {
|
||||
It("should remove old reference", func() {
|
||||
nbresource.Spec.PolicyName = ""
|
||||
Expect(k8sClient.Update(ctx, nbresource)).To(Succeed())
|
||||
|
||||
nbresource.Status.PolicyName = util.Ptr("test-b,test-c")
|
||||
Expect(k8sClient.Status().Update(ctx, nbresource)).To(Succeed())
|
||||
|
||||
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
|
||||
NamespacedName: typeNamespacedName,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
nbPolicy := &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-a"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).NotTo(ContainElement("default/test-resource"))
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-b"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).NotTo(ContainElement("default/test-resource"))
|
||||
|
||||
nbPolicy = &netbirdiov1.NBPolicy{}
|
||||
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: "test-c"}, nbPolicy)).To(Succeed())
|
||||
Expect(nbPolicy.Status.ManagedServiceList).NotTo(ContainElement("default/test-resource"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("Groups are changed", func() {
|
||||
When("Removed groups are no longer referenced by anything", func() {
|
||||
It("should only remove finalizer", func() {
|
||||
|
||||
Reference in New Issue
Block a user