Skip to content

Commit db86fc9

Browse files
committed
Remove outdated vhost limits.
1 parent 918bfb3 commit db86fc9

File tree

4 files changed

+244
-70
lines changed

4 files changed

+244
-70
lines changed

controllers/vhost_controller.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66

7+
rabbithole "github.com/michaelklishin/rabbit-hole/v3"
78
"github.com/rabbitmq/messaging-topology-operator/internal"
89
"github.com/rabbitmq/messaging-topology-operator/rabbitmqclient"
910
ctrl "sigs.k8s.io/controller-runtime"
@@ -30,12 +31,25 @@ func (r *VhostReconciler) DeclareFunc(ctx context.Context, client rabbitmqclient
3031
return err
3132
}
3233

33-
vhostLimits := internal.GenerateVhostLimits(vhost.Spec.VhostLimits)
34-
logger.Info("generated vhost limits", "vhost", vhost.Spec.Name, "limits", vhostLimits)
35-
if len(vhostLimits) > 0 {
36-
err = validateResponse(client.PutVhostLimits(vhost.Spec.Name, vhostLimits))
34+
newVhostLimits := internal.GenerateVhostLimits(vhost.Spec.VhostLimits)
35+
logger.Info("getting existing vhost limits", vhost, vhost.Spec.Name)
36+
existingVhostLimits, err := r.getVhostLimits(client, vhost.Spec.Name)
37+
if err != nil {
38+
return err
39+
}
40+
limitsToDelete := r.vhostLimitsToDelete(existingVhostLimits, newVhostLimits)
41+
if len(limitsToDelete) > 0 {
42+
logger.Info("Deleting outdated vhost limits", "vhost", vhost.Spec.Name, "limits", limitsToDelete)
43+
err = validateResponseForDeletion(client.DeleteVhostLimits(vhost.Spec.Name, limitsToDelete))
44+
if err != nil && !errors.Is(err, NotFound) {
45+
return err
46+
}
47+
}
48+
if len(newVhostLimits) > 0 {
49+
logger.Info("creating new vhost limits", "vhost", vhost.Spec.Name, "limits", newVhostLimits)
50+
return validateResponse(client.PutVhostLimits(vhost.Spec.Name, newVhostLimits))
3751
}
38-
return err
52+
return nil
3953
}
4054

4155
// DeleteFunc deletes vhost from server
@@ -54,3 +68,28 @@ func (r *VhostReconciler) DeleteFunc(ctx context.Context, client rabbitmqclient.
5468
}
5569
return nil
5670
}
71+
72+
func (r *VhostReconciler) vhostLimitsToDelete(existingVhostLimits, newVhostLimits rabbithole.VhostLimitsValues) (limitsToDelete rabbithole.VhostLimits) {
73+
vhostLimitKeys := []string{"max-connections", "max-queues"}
74+
for _, limit := range vhostLimitKeys {
75+
_, oldExists := existingVhostLimits[limit]
76+
_, newExists := newVhostLimits[limit]
77+
if oldExists && !newExists {
78+
limitsToDelete = append(limitsToDelete, limit)
79+
}
80+
}
81+
return limitsToDelete
82+
}
83+
84+
func (r *VhostReconciler) getVhostLimits(client rabbitmqclient.Client, vhost string) (rabbithole.VhostLimitsValues, error) {
85+
vhostLimitsInfo, err := client.GetVhostLimits(vhost)
86+
if errors.Is(err, error(rabbithole404)) {
87+
return rabbithole.VhostLimitsValues{}, nil
88+
} else if err != nil {
89+
return rabbithole.VhostLimitsValues{}, err
90+
}
91+
if len(vhostLimitsInfo) == 0 {
92+
return rabbithole.VhostLimitsValues{}, nil
93+
}
94+
return vhostLimitsInfo[0].Value, nil
95+
}

controllers/vhost_controller_test.go

Lines changed: 120 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
1515
"time"
1616

17+
rabbithole "github.com/michaelklishin/rabbit-hole/v3"
1718
. "github.com/onsi/ginkgo/v2"
1819
. "github.com/onsi/gomega"
1920
. "github.com/onsi/gomega/gstruct"
@@ -159,6 +160,125 @@ var _ = Describe("vhost-controller", func() {
159160
})))
160161
})
161162
})
163+
164+
Context("vhost limits", func() {
165+
var connections, queues int32
166+
167+
When("vhost limits are provided", func() {
168+
BeforeEach(func() {
169+
connections = 708
170+
queues = 509
171+
vhostName = "vhost-with-limits"
172+
vhostLimits = &topology.VhostLimits{
173+
Connections: &connections,
174+
Queues: &queues,
175+
}
176+
fakeRabbitMQClient.PutVhostReturns(&http.Response{
177+
Status: "201 Created",
178+
StatusCode: http.StatusCreated,
179+
}, nil)
180+
fakeRabbitMQClient.PutVhostLimitsReturns(&http.Response{
181+
Status: "200 OK",
182+
StatusCode: http.StatusOK,
183+
}, nil)
184+
fakeRabbitMQClient.GetVhostLimitsReturns(nil, rabbithole.ErrorResponse{
185+
StatusCode: 404,
186+
Message: "Object Not Found",
187+
Reason: "Not Found",
188+
})
189+
})
190+
191+
It("puts the vhost limits", func() {
192+
Expect(k8sClient.Create(ctx, &vhost)).To(Succeed())
193+
Eventually(func() []topology.Condition {
194+
_ = k8sClient.Get(
195+
ctx,
196+
types.NamespacedName{Name: vhost.Name, Namespace: vhost.Namespace},
197+
&vhost,
198+
)
199+
200+
return vhost.Status.Conditions
201+
}).
202+
Within(statusEventsUpdateTimeout).
203+
WithPolling(time.Second).
204+
Should(ContainElement(MatchFields(IgnoreExtras, Fields{
205+
"Type": Equal(topology.ConditionType("Ready")),
206+
"Reason": Equal("SuccessfulCreateOrUpdate"),
207+
"Status": Equal(corev1.ConditionTrue),
208+
})))
209+
210+
Expect(fakeRabbitMQClient.PutVhostLimitsCallCount()).To(BeNumerically(">", 0))
211+
_, vhostLimitsValues := fakeRabbitMQClient.PutVhostLimitsArgsForCall(0)
212+
Expect(len(vhostLimitsValues)).To(Equal(2))
213+
Expect(vhostLimitsValues).To(HaveKeyWithValue("max-connections", int(connections)))
214+
Expect(vhostLimitsValues).To(HaveKeyWithValue("max-queues", int(queues)))
215+
})
216+
})
217+
218+
When("vhost limits are not provided", func() {
219+
BeforeEach(func() {
220+
vhostName = "vhost-without-limits"
221+
fakeRabbitMQClient.GetVhostLimitsReturns(nil, rabbithole.ErrorResponse{
222+
StatusCode: 404,
223+
Message: "Object Not Found",
224+
Reason: "Not Found",
225+
})
226+
})
227+
228+
It("does not set vhost limits", func() {
229+
Expect(k8sClient.Create(ctx, &vhost)).To(Succeed())
230+
Expect(fakeRabbitMQClient.PutVhostLimitsCallCount()).To(Equal(0))
231+
})
232+
})
233+
234+
When("vhost limits are updated", func() {
235+
BeforeEach(func() {
236+
vhostName = "vhost-updated-limits"
237+
queues = 613
238+
vhostLimits = &topology.VhostLimits{
239+
Connections: nil,
240+
Queues: &queues,
241+
}
242+
243+
var vhostLimitsInfo []rabbithole.VhostLimitsInfo
244+
vhostLimitsInfo = append(vhostLimitsInfo, rabbithole.VhostLimitsInfo{
245+
Vhost: vhostName,
246+
Value: rabbithole.VhostLimitsValues{"max-queues": 10, "max-connections": 300},
247+
})
248+
249+
fakeRabbitMQClient.PutVhostReturns(&http.Response{
250+
Status: "201 Created",
251+
StatusCode: http.StatusCreated,
252+
}, nil)
253+
fakeRabbitMQClient.PutVhostLimitsReturns(&http.Response{
254+
Status: "201 Created",
255+
StatusCode: http.StatusCreated,
256+
}, nil)
257+
fakeRabbitMQClient.GetVhostLimitsReturns(vhostLimitsInfo, nil)
258+
fakeRabbitMQClient.DeleteVhostLimitsReturns(&http.Response{
259+
Status: "204 No Content",
260+
StatusCode: http.StatusNoContent,
261+
}, nil)
262+
})
263+
264+
It("updates the provided limits and removes unspecified limits", func() {
265+
Expect(k8sClient.Create(ctx, &vhost)).To(Succeed())
266+
267+
By("deleting the outdated limits")
268+
Expect(fakeRabbitMQClient.DeleteVhostLimitsCallCount()).To(BeNumerically(">", 0))
269+
vhostname, limits := fakeRabbitMQClient.DeleteVhostLimitsArgsForCall(0)
270+
Expect(vhostname).To(Equal(vhostName))
271+
Expect(len(limits)).To(Equal(1))
272+
Expect(limits).To(ContainElement("max-connections"))
273+
274+
By("updating the new limits")
275+
Expect(fakeRabbitMQClient.PutVhostLimitsCallCount()).To(BeNumerically(">", 0))
276+
_, vhostLimitsValues := fakeRabbitMQClient.PutVhostLimitsArgsForCall(0)
277+
Expect(len(vhostLimitsValues)).To(Equal(1))
278+
Expect(fakeRabbitMQClient).To(HaveKeyWithValue("max-queues", int(queues)))
279+
})
280+
})
281+
})
162282
})
163283

164284
Context("deletion", func() {
@@ -254,69 +374,4 @@ var _ = Describe("vhost-controller", func() {
254374
Expect(fakeRabbitMQClient.DeleteVhostCallCount()).To(Equal(0))
255375
})
256376
})
257-
258-
Context("vhost limits", func() {
259-
When("vhost limits are provided", func() {
260-
var connections, queues int32
261-
262-
BeforeEach(func() {
263-
connections = 708
264-
queues = 509
265-
vhostName = "vhost-with-limits"
266-
vhostLimits = &topology.VhostLimits{
267-
Connections: &connections,
268-
Queues: &queues,
269-
}
270-
fakeRabbitMQClient.PutVhostReturns(&http.Response{
271-
Status: "201 Created",
272-
StatusCode: http.StatusCreated,
273-
}, nil)
274-
fakeRabbitMQClient.PutVhostLimitsReturns(&http.Response{
275-
Status: "200 OK",
276-
StatusCode: http.StatusOK,
277-
}, nil)
278-
})
279-
280-
It("puts the vhost limits", func() {
281-
Expect(k8sClient.Create(ctx, &vhost)).To(Succeed())
282-
Eventually(func() []topology.Condition {
283-
_ = k8sClient.Get(
284-
ctx,
285-
types.NamespacedName{Name: vhost.Name, Namespace: vhost.Namespace},
286-
&vhost,
287-
)
288-
289-
return vhost.Status.Conditions
290-
}).
291-
Within(statusEventsUpdateTimeout).
292-
WithPolling(time.Second).
293-
Should(ContainElement(MatchFields(IgnoreExtras, Fields{
294-
"Type": Equal(topology.ConditionType("Ready")),
295-
"Reason": Equal("SuccessfulCreateOrUpdate"),
296-
"Status": Equal(corev1.ConditionTrue),
297-
})))
298-
299-
Expect(fakeRabbitMQClient.PutVhostLimitsCallCount()).To(BeNumerically(">", 0))
300-
_, vhostLimitsValues := fakeRabbitMQClient.PutVhostLimitsArgsForCall(0)
301-
Expect(len(vhostLimitsValues)).To(Equal(2))
302-
connectionLimit, ok := vhostLimitsValues["max-connections"]
303-
Expect(ok).To(BeTrue())
304-
Expect(connectionLimit).To(Equal(int(connections)))
305-
queueLimit, ok := vhostLimitsValues["max-queues"]
306-
Expect(ok).To(BeTrue())
307-
Expect(queueLimit).To(Equal(int(queues)))
308-
})
309-
})
310-
311-
When("vhost limits are not provided", func() {
312-
BeforeEach(func() {
313-
vhostName = "vhost-without-limits"
314-
})
315-
316-
It("does not set vhost limits", func() {
317-
Expect(k8sClient.Create(ctx, &vhost)).To(Succeed())
318-
Expect(fakeRabbitMQClient.PutVhostLimitsCallCount()).To(Equal(0))
319-
})
320-
})
321-
})
322377
})

rabbitmqclient/rabbitmq_client_factory.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type Client interface {
4141
PutVhost(string, rabbithole.VhostSettings) (*http.Response, error)
4242
DeleteVhost(string) (*http.Response, error)
4343
PutVhostLimits(string, rabbithole.VhostLimitsValues) (*http.Response, error)
44+
GetVhostLimits(string) ([]rabbithole.VhostLimitsInfo, error)
4445
DeleteVhostLimits(string, rabbithole.VhostLimits) (*http.Response, error)
4546
PutGlobalParameter(name string, value interface{}) (*http.Response, error)
4647
DeleteGlobalParameter(name string) (*http.Response, error)

rabbitmqclient/rabbitmqclientfakes/fake_client.go

Lines changed: 79 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)