mirror of
https://github.com/ngrok/ngrok-operator.git
synced 2026-05-17 16:50:44 +00:00
aa1781d348
* chore: Update to go 1.26.1 Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Run 'go fix ./...' for go 1.26.1 Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Upgrade go modules Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> * chore: Fix deprecations and linter warnings Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com> --------- Signed-off-by: Jonathan Stacks <jonstacks@users.noreply.github.com>
251 lines
8.8 KiB
Go
251 lines
8.8 KiB
Go
package ingress
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
ngrok "github.com/ngrok/ngrok-api-go/v7"
|
|
ingressv1alpha1 "github.com/ngrok/ngrok-operator/api/ingress/v1alpha1"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
var _ = Describe("IPPolicyReconciler", func() {
|
|
const (
|
|
timeout = 10 * time.Second
|
|
interval = 250 * time.Millisecond
|
|
)
|
|
|
|
var (
|
|
ctx context.Context
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
ctx = GinkgoT().Context()
|
|
})
|
|
|
|
AfterEach(func() {
|
|
ipPolicyClient.Reset()
|
|
})
|
|
|
|
It("creates IPPolicy and configures rules", func() {
|
|
ip := &ingressv1alpha1.IPPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-ip-policy", Namespace: "default"},
|
|
Spec: ingressv1alpha1.IPPolicySpec{
|
|
Metadata: "test",
|
|
},
|
|
}
|
|
ip.Spec.Rules = []ingressv1alpha1.IPPolicyRule{
|
|
{CIDR: "10.0.0.0/8", Action: "allow", Description: "desc1"},
|
|
{CIDR: "192.168.1.0/24", Action: "deny", Description: "desc2"},
|
|
}
|
|
|
|
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
|
|
|
|
Eventually(func() []string {
|
|
items := ipPolicyRuleClient.Items()
|
|
out := []string{}
|
|
for _, it := range items {
|
|
out = append(out, it.CIDR)
|
|
}
|
|
return out
|
|
}, timeout, interval).Should(ContainElements("10.0.0.0/8", "192.168.1.0/24"))
|
|
})
|
|
|
|
It("updates existing rule descriptions", func() {
|
|
ip := &ingressv1alpha1.IPPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-ip-policy-update", Namespace: "default"},
|
|
Spec: ingressv1alpha1.IPPolicySpec{
|
|
Metadata: "test",
|
|
},
|
|
}
|
|
ip.Spec.Rules = []ingressv1alpha1.IPPolicyRule{
|
|
{CIDR: "10.0.0.0/8", Action: "allow", Description: "orig"},
|
|
}
|
|
|
|
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
|
|
|
|
Eventually(func() []string {
|
|
items := ipPolicyRuleClient.Items()
|
|
out := []string{}
|
|
for _, it := range items {
|
|
out = append(out, it.Description)
|
|
}
|
|
return out
|
|
}, timeout, interval).Should(ContainElement("orig"))
|
|
|
|
patch := client.MergeFrom(ip.DeepCopy())
|
|
ip.Spec.Rules[0].Description = "updated"
|
|
Expect(k8sClient.Patch(ctx, ip, patch)).To(Succeed())
|
|
|
|
Eventually(func() []string {
|
|
items := ipPolicyRuleClient.Items()
|
|
out := []string{}
|
|
for _, it := range items {
|
|
out = append(out, it.Description)
|
|
}
|
|
return out
|
|
}, timeout, interval).Should(ContainElement("updated"))
|
|
})
|
|
|
|
It("deletes obsolete rules", func() {
|
|
ip := &ingressv1alpha1.IPPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-ip-policy-del", Namespace: "default"},
|
|
Spec: ingressv1alpha1.IPPolicySpec{
|
|
Metadata: "test",
|
|
},
|
|
}
|
|
ip.Spec.Rules = []ingressv1alpha1.IPPolicyRule{
|
|
{CIDR: "10.0.0.0/8", Action: "allow", Description: "orig"},
|
|
}
|
|
|
|
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
|
|
|
|
Eventually(func() []string {
|
|
items := ipPolicyRuleClient.Items()
|
|
out := []string{}
|
|
for _, it := range items {
|
|
out = append(out, it.CIDR)
|
|
}
|
|
return out
|
|
}, timeout, interval).Should(ContainElement("10.0.0.0/8"))
|
|
|
|
patch := client.MergeFrom(ip.DeepCopy())
|
|
ip.Spec.Rules = []ingressv1alpha1.IPPolicyRule{}
|
|
Expect(k8sClient.Patch(ctx, ip, patch)).To(Succeed())
|
|
|
|
Eventually(func() int {
|
|
count := 0
|
|
for _, it := range ipPolicyRuleClient.Items() {
|
|
if it.IPPolicy.ID == ip.Status.ID {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}, timeout, interval).Should(Equal(0))
|
|
})
|
|
|
|
It("sets Created condition for existing IP Policy", func() {
|
|
By("creating an IP Policy")
|
|
ip := &ingressv1alpha1.IPPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-existing-policy", Namespace: "default"},
|
|
Spec: ingressv1alpha1.IPPolicySpec{
|
|
Metadata: "test",
|
|
},
|
|
}
|
|
ip.Spec.Description = "test-existing"
|
|
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
|
|
|
|
By("waiting for the IP Policy to be created")
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyCreated, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyReady, metav1.ConditionTrue)
|
|
|
|
By("clearning the status conditions to simulate existing ip policy")
|
|
Eventually(func(g Gomega) {
|
|
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(ip), ip)
|
|
g.Expect(err).NotTo(HaveOccurred())
|
|
|
|
ip.Status.Conditions = []metav1.Condition{}
|
|
err = k8sClient.Status().Update(ctx, ip)
|
|
g.Expect(err).NotTo(HaveOccurred())
|
|
}, timeout, interval).Should(Succeed())
|
|
|
|
By("verifying the created and ready conditions are set again")
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyCreated, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyReady, metav1.ConditionTrue)
|
|
})
|
|
|
|
It("sets Created condition for existing IP Policy with rules", func() {
|
|
By("creating an IPPolicy resource with rules")
|
|
ip := &ingressv1alpha1.IPPolicy{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "test-existing-policy-rules", Namespace: "default"},
|
|
Spec: ingressv1alpha1.IPPolicySpec{
|
|
Metadata: "test",
|
|
},
|
|
}
|
|
ip.Spec.Description = "test-with-rules"
|
|
ip.Spec.Rules = []ingressv1alpha1.IPPolicyRule{{CIDR: "10.0.0.0/8", Action: "allow"}}
|
|
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
|
|
|
|
By("waiting for the IP Policy to be created")
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyCreated, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyReady, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyRulesConfigured, metav1.ConditionTrue)
|
|
|
|
By("clearing the status conditions to simulate an existing ip policy")
|
|
Eventually(func(g Gomega) {
|
|
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(ip), ip)
|
|
g.Expect(err).NotTo(HaveOccurred())
|
|
|
|
ip.Status.Conditions = []metav1.Condition{}
|
|
err = k8sClient.Status().Update(ctx, ip)
|
|
g.Expect(err).NotTo(HaveOccurred())
|
|
}, timeout, interval).Should(Succeed())
|
|
|
|
By("verifying the created, rules configured, and ready conditions are set again")
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyCreated, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyReady, metav1.ConditionTrue)
|
|
kginkgo.EventuallyIPPolicyHasCondition(ctx, ip, ConditionIPPolicyRulesConfigured, metav1.ConditionTrue)
|
|
})
|
|
})
|
|
|
|
var _ = Describe("IPPolicyDiff", func() {
|
|
It("computes creates, deletes and updates correctly", func() {
|
|
remoteRules := []*ngrok.IPPolicyRule{
|
|
{ID: "1", CIDR: "192.168.1.0/25", Action: IPPolicyRuleActionAllow, Description: "a"},
|
|
{ID: "2", CIDR: "192.168.128.0/25", Action: IPPolicyRuleActionDeny, Description: "aa"},
|
|
{ID: "3", CIDR: "172.16.0.0/16", Action: IPPolicyRuleActionAllow, Description: "aaa"},
|
|
{ID: "4", CIDR: "172.17.0.0/16", Action: IPPolicyRuleActionDeny, Description: "aaaa"},
|
|
{ID: "5", CIDR: "172.19.0.0/16", Action: IPPolicyRuleActionAllow, Description: "aaaaa"},
|
|
}
|
|
|
|
changedDescriptionRule := ingressv1alpha1.IPPolicyRule{
|
|
CIDR: "172.19.0.0/16", Action: IPPolicyRuleActionAllow, Description: "b",
|
|
}
|
|
|
|
specRules := []ingressv1alpha1.IPPolicyRule{
|
|
{CIDR: "192.168.1.0/25", Action: IPPolicyRuleActionDeny},
|
|
{CIDR: "192.168.128.0/25", Action: IPPolicyRuleActionAllow},
|
|
{CIDR: "10.0.0.0/8", Action: IPPolicyRuleActionDeny},
|
|
{CIDR: "172.18.0.0/16", Action: IPPolicyRuleActionAllow},
|
|
changedDescriptionRule,
|
|
}
|
|
|
|
diff := newIPPolicyDiff("test", remoteRules, specRules)
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsDelete()).To(BeEmpty())
|
|
Expect(diff.NeedsUpdate()).To(BeEmpty())
|
|
Expect(diff.NeedsCreate()).To(Equal([]*ngrok.IPPolicyRuleCreate{{IPPolicyID: "test", CIDR: specRules[2].CIDR, Action: new(IPPolicyRuleActionDeny)}}))
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsUpdate()).To(BeEmpty())
|
|
Expect(diff.NeedsDelete()).To(Equal([]*ngrok.IPPolicyRule{remoteRules[0]}))
|
|
Expect(diff.NeedsCreate()).To(Equal([]*ngrok.IPPolicyRuleCreate{{IPPolicyID: "test", CIDR: specRules[0].CIDR, Action: new(IPPolicyRuleActionDeny)}}))
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsUpdate()).To(BeEmpty())
|
|
Expect(diff.NeedsDelete()).To(Equal([]*ngrok.IPPolicyRule{remoteRules[1]}))
|
|
Expect(diff.NeedsCreate()).To(Equal([]*ngrok.IPPolicyRuleCreate{{IPPolicyID: "test", CIDR: specRules[1].CIDR, Action: new(IPPolicyRuleActionAllow)}}))
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsUpdate()).To(BeEmpty())
|
|
Expect(diff.NeedsDelete()).To(BeEmpty())
|
|
Expect(diff.NeedsCreate()).To(Equal([]*ngrok.IPPolicyRuleCreate{{IPPolicyID: "test", CIDR: specRules[3].CIDR, Action: new(IPPolicyRuleActionAllow)}}))
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsUpdate()).To(BeEmpty())
|
|
Expect(diff.NeedsDelete()).To(Equal([]*ngrok.IPPolicyRule{remoteRules[2], remoteRules[3]}))
|
|
Expect(diff.NeedsCreate()).To(BeEmpty())
|
|
|
|
Expect(diff.Next()).To(BeTrue())
|
|
Expect(diff.NeedsDelete()).To(BeEmpty())
|
|
Expect(diff.NeedsCreate()).To(BeEmpty())
|
|
Expect(diff.NeedsUpdate()).To(Equal([]*ngrok.IPPolicyRuleUpdate{{ID: "5", CIDR: new("172.19.0.0/16"), Description: new("b"), Metadata: new("")}}))
|
|
|
|
Expect(diff.Next()).To(BeFalse())
|
|
})
|
|
})
|