Skip to content

Commit fa30d1d

Browse files
Fix limits cause incomplete update for existing silences
This commit fixes a bug where limits can cause an incomplete update for existing silences, where the old silence can be expired but the new silence cannot be created because it would execeed the maximum number of silences. Signed-off-by: George Robinson <[email protected]>
1 parent 7e2cd80 commit fa30d1d

File tree

2 files changed

+55
-22
lines changed

2 files changed

+55
-22
lines changed

silence/silence.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -609,16 +609,8 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) {
609609
return "", ErrNotFound
610610
}
611611

612-
if ok {
613-
if canUpdate(prev, sil, now) {
614-
return sil.Id, s.setSilence(sil, now, false)
615-
}
616-
if getState(prev, s.nowUTC()) != types.SilenceStateExpired {
617-
// We cannot update the silence, expire the old one.
618-
if err := s.expire(prev.Id); err != nil {
619-
return "", fmt.Errorf("expire previous silence: %w", err)
620-
}
621-
}
612+
if ok && canUpdate(prev, sil, now) {
613+
return sil.Id, s.setSilence(sil, now, false)
622614
}
623615

624616
// If we got here it's either a new silence or a replacing one.
@@ -628,6 +620,13 @@ func (s *Silences) Set(sil *pb.Silence) (string, error) {
628620
}
629621
}
630622

623+
if ok && getState(prev, s.nowUTC()) != types.SilenceStateExpired {
624+
// We cannot update the silence, expire the old one.
625+
if err := s.expire(prev.Id); err != nil {
626+
return "", fmt.Errorf("expire previous silence: %w", err)
627+
}
628+
}
629+
631630
uid, err := uuid.NewV4()
632631
if err != nil {
633632
return "", fmt.Errorf("generate uuid: %w", err)

silence/silence_test.go

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ func TestSilenceLimits(t *testing.T) {
481481
// Insert sil2 should fail because maximum number of silences
482482
// has been exceeded.
483483
sil2 := &pb.Silence{
484-
Matchers: []*pb.Matcher{{Name: "a", Pattern: "b"}},
484+
Matchers: []*pb.Matcher{{Name: "c", Pattern: "d"}},
485485
StartsAt: time.Now(),
486486
EndsAt: time.Now().Add(5 * time.Minute),
487487
}
@@ -500,11 +500,7 @@ func TestSilenceLimits(t *testing.T) {
500500
require.NoError(t, err)
501501
require.NotEqual(t, "", id2)
502502

503-
// Should be able to update sil2 without hitting the limit.
504-
_, err = s.Set(sil2)
505-
require.NoError(t, err)
506-
507-
// Expire sil2.
503+
// Expire sil2 and run the GC.
508504
require.NoError(t, s.Expire(id2))
509505
n, err = s.GC()
510506
require.NoError(t, err)
@@ -514,16 +510,16 @@ func TestSilenceLimits(t *testing.T) {
514510
sil3 := &pb.Silence{
515511
Matchers: []*pb.Matcher{
516512
{
517-
Name: strings.Repeat("a", 2<<9),
518-
Pattern: strings.Repeat("b", 2<<9),
513+
Name: strings.Repeat("e", 2<<9),
514+
Pattern: strings.Repeat("f", 2<<9),
519515
},
520516
{
521-
Name: strings.Repeat("c", 2<<9),
522-
Pattern: strings.Repeat("d", 2<<9),
517+
Name: strings.Repeat("g", 2<<9),
518+
Pattern: strings.Repeat("h", 2<<9),
523519
},
524520
},
525-
CreatedBy: strings.Repeat("e", 2<<9),
526-
Comment: strings.Repeat("f", 2<<9),
521+
CreatedBy: strings.Repeat("i", 2<<9),
522+
Comment: strings.Repeat("j", 2<<9),
527523
StartsAt: time.Now(),
528524
EndsAt: time.Now().Add(5 * time.Minute),
529525
}
@@ -533,6 +529,44 @@ func TestSilenceLimits(t *testing.T) {
533529
// due to padding.
534530
require.Contains(t, err.Error(), "silence exceeded maximum size")
535531
require.Equal(t, "", id3)
532+
533+
// Should be able to insert sil4 and then update it without modifications.
534+
sil4 := &pb.Silence{
535+
Matchers: []*pb.Matcher{{Name: "k", Pattern: "l"}},
536+
StartsAt: time.Now(),
537+
EndsAt: time.Now().Add(5 * time.Minute),
538+
}
539+
id4, err := s.Set(sil4)
540+
require.NoError(t, err)
541+
require.NotEqual(t, "", id4)
542+
543+
// Update without modifications.
544+
updateId4, err := s.Set(sil4)
545+
require.NoError(t, err)
546+
require.Equal(t, id4, updateId4)
547+
548+
// Should be able to update the comment.
549+
sil5 := cloneSilence(sil4)
550+
sil5.Comment = "m"
551+
id5, err := s.Set(sil5)
552+
require.NoError(t, err)
553+
require.Equal(t, id4, id5)
554+
555+
// Should not be able to update the start and end time as this requires
556+
// sil5 to be expired and a new silence to be created. However, this would
557+
// exceed the maximum number of silences, which counts both active and
558+
// expired silences.
559+
sil6 := cloneSilence(sil5)
560+
sil6.StartsAt = time.Now().Add(5 * time.Minute)
561+
sil6.EndsAt = time.Now().Add(10 * time.Minute)
562+
id6, err := s.Set(sil6)
563+
require.EqualError(t, err, "exceeded maximum number of silences: 1 (limit: 1)")
564+
require.Equal(t, "", id6)
565+
566+
// sil5 should not be expired because the update failed.
567+
sil5, err = s.QueryOne(QIDs(sil5.Id))
568+
require.NoError(t, err)
569+
require.Equal(t, types.SilenceStateActive, getState(sil5, s.nowUTC()))
536570
}
537571

538572
func TestSetActiveSilence(t *testing.T) {

0 commit comments

Comments
 (0)