Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature silenced change #5048

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ func newClient(ctx context.Context, config *Config, backend *Backend) (*clientv3
cfg.LogTimestampLayout = config.EtcdLogTimestampLayout
cfg.ClientLogLevel = config.EtcdClientLogLevel

// set misc configurations here
cfg.DefaultSilencedExpiryTime = config.DefaultSilencedExpiryTime
cfg.MaxSilencedExpiryTimeAllowed = config.MaxSilencedExpiryTimeAllowed

// Heartbeat interval
if config.EtcdHeartbeatInterval > 0 {
cfg.TickMs = config.EtcdHeartbeatInterval
Expand Down Expand Up @@ -328,6 +332,13 @@ func Initialize(ctx context.Context, config *Config) (*Backend, error) {

// Create the store, which lives on top of etcd
stor := etcdstore.NewStore(b.Client, config.EtcdName)

// set config details
scfg := etcdstore.Config{}
scfg.DefaultSilencedExpiryTime = config.DefaultSilencedExpiryTime
scfg.MaxSilencedExpiryTimeAllowed = config.MaxSilencedExpiryTimeAllowed
etcdstore.SetConfig(scfg, stor)

b.Store = stor
storv2 := etcdstorev2.NewStore(b.Client)
var storev2Proxy storev2.Proxy
Expand Down
15 changes: 15 additions & 0 deletions backend/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ const (
flagLabels = "labels"
flagAnnotations = "annotations"

// silenced expiry flags
flagMaxSilencedExpiryTimeAllowed = "max-silenced-expiry-time-allowed"
flagDefaultSilencedExpiryTime = "default-silenced-expiry-time"

// Etcd flag constants
flagEtcdClientURLs = "etcd-client-urls"
flagEtcdListenClientURLs = "etcd-listen-client-urls"
Expand Down Expand Up @@ -255,6 +259,9 @@ func StartCommand(initialize InitializeFunc) *cobra.Command {
CacheDir: viper.GetString(flagCacheDir),
StateDir: viper.GetString(flagStateDir),

DefaultSilencedExpiryTime: viper.GetDuration(flagDefaultSilencedExpiryTime),
MaxSilencedExpiryTimeAllowed: viper.GetDuration(flagMaxSilencedExpiryTimeAllowed),

EtcdAdvertiseClientURLs: viper.GetStringSlice(flagEtcdAdvertiseClientURLs),
EtcdListenClientURLs: viper.GetStringSlice(flagEtcdListenClientURLs),
EtcdClientURLs: fallbackStringSlice(flagEtcdClientURLs, flagEtcdAdvertiseClientURLs),
Expand Down Expand Up @@ -448,6 +455,10 @@ func handleConfig(cmd *cobra.Command, arguments []string, server bool) error {
viper.SetDefault(flagEventLogBufferSize, 100000)
viper.SetDefault(flagEventLogFile, "")
viper.SetDefault(flagEventLogParallelEncoders, false)

// default silenced value are set for 1 day = 1440m
viper.SetDefault(flagMaxSilencedExpiryTimeAllowed, "1440m")
viper.SetDefault(flagDefaultSilencedExpiryTime, "1440m")
}

// Etcd defaults
Expand Down Expand Up @@ -583,6 +594,10 @@ func flagSet(server bool) *pflag.FlagSet {
flagSet.Duration(flagPlatformMetricsLoggingInterval, viper.GetDuration(flagPlatformMetricsLoggingInterval), "platform metrics logging interval")
flagSet.String(flagPlatformMetricsLogFile, viper.GetString(flagPlatformMetricsLogFile), "platform metrics log file path")

// silenced configuration flags
flagSet.Duration(flagDefaultSilencedExpiryTime, viper.GetDuration(flagDefaultSilencedExpiryTime), "Default expiry time for silenced if not set in minutes")
flagSet.Duration(flagMaxSilencedExpiryTimeAllowed, viper.GetDuration(flagMaxSilencedExpiryTimeAllowed), "Maximum expiry time allowed for silenced in minutes")

// Etcd server flags
flagSet.StringSlice(flagEtcdPeerURLs, viper.GetStringSlice(flagEtcdPeerURLs), "list of URLs to listen on for peer traffic")
_ = flagSet.SetAnnotation(flagEtcdPeerURLs, "categories", []string{"store"})
Expand Down
4 changes: 4 additions & 0 deletions backend/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,8 @@ type Config struct {
EventLogBufferWait time.Duration
EventLogFile string
EventLogParallelEncoders bool

// expiry setting for silences
DefaultSilencedExpiryTime time.Duration
MaxSilencedExpiryTimeAllowed time.Duration
}
10 changes: 10 additions & 0 deletions backend/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ func init() {
logutil.DefaultZapLoggerConfig.EncoderConfig.EncodeLevel = sensuLevelEncoder
}

// MiscConfig is struct to hold miscellaneous configurations for etcd
type MiscConfig struct {
DefaultSilencedExpiryTime time.Duration

MaxSilencedExpiryTimeAllowed time.Duration
}

// Config is a configuration for the embedded etcd
type Config struct {
DataDir string
Expand Down Expand Up @@ -107,6 +114,9 @@ type Config struct {
LogTimestampLayout string

UnsafeNoFsync bool

// holding store specific configuration
MiscConfig
}

// TLSInfo wraps etcd transport TLSInfo
Expand Down
16 changes: 16 additions & 0 deletions backend/store/etcd/silenced_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ func (s *Store) UpdateSilencedEntry(ctx context.Context, silenced *corev2.Silenc
if err := silenced.Validate(); err != nil {
return &store.ErrNotValid{Err: err}
}
allowedMaxTime := time.Now().Add(s.cfg.MaxSilencedExpiryTimeAllowed).Unix()

// check for maximum allowed duration for silenced allowed
if silenced.ExpireAt > 0 && (silenced.ExpireAt > allowedMaxTime) {
err := errors.New("silenced crossed maximum duration allowed")
return &store.ErrThreshold{Err: err}
}

if silenced.ExpireAt == 0 && silenced.Expire > 0 {
start := time.Now()
Expand All @@ -216,6 +223,15 @@ func (s *Store) UpdateSilencedEntry(ctx context.Context, silenced *corev2.Silenc
silenced.ExpireAt = start.Add(time.Duration(silenced.Expire) * time.Second).Unix()
}

// set default silenced expiry time configured in backend yaml file
if silenced.Expire <= 0 && silenced.ExpireAt == 0 {
start := time.Now()
if silenced.Begin > 0 {
start = time.Unix(silenced.Begin, 0)
}
silenced.ExpireAt = start.Add(s.cfg.DefaultSilencedExpiryTime).Unix()
}

silencedBytes, err := proto.Marshal(silenced)
if err != nil {
return &store.ErrEncode{Err: err}
Expand Down
39 changes: 34 additions & 5 deletions backend/store/etcd/silenced_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,17 @@ func TestSilencedStorage(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, entry)
assert.Equal(t, "subscription:*", entry.Name)
// Entries without expirations should return -1
assert.Equal(t, int64(-1), entry.Expire)

// check entries without -1 expiry
assert.NotEqual(t, int64(-1), entry.Expire)

// Delete silenced entry by name
err = store.DeleteSilencedEntryByName(ctx, silenced.Name)
assert.NoError(t, err)

// Update a silenced entry's expire time
silenced.Expire = 2
silenced.ExpireAt = 0
err = store.UpdateSilencedEntry(ctx, silenced)
assert.NoError(t, err)

Expand All @@ -100,6 +102,7 @@ func TestSilencedStorageWithExpire(t *testing.T) {
silenced := types.FixtureSilenced("subscription:checkname")
silenced.Namespace = "default"
silenced.Expire = 15
silenced.ExpireAt = 0
ctx := context.WithValue(context.Background(), types.NamespaceKey, silenced.Namespace)

err := store.UpdateSilencedEntry(ctx, silenced)
Expand All @@ -120,9 +123,9 @@ func TestSilencedStorageWithBegin(t *testing.T) {
silenced := types.FixtureSilenced("subscription:checkname")
silenced.Namespace = "default"
// set a begin time in the future
silenced.Begin = time.Date(1970, 01, 01, 01, 00, 00, 00, time.UTC).Unix()
silenced.Begin = time.Now().Add(time.Duration(1) * time.Second).Unix()
// current time is before the start time
currentTime := time.Date(1970, 01, 01, 00, 00, 00, 00, time.UTC).Unix()
currentTime := time.Now().Unix()
ctx := context.WithValue(context.Background(), types.NamespaceKey, silenced.Namespace)

err := store.UpdateSilencedEntry(ctx, silenced)
Expand All @@ -137,8 +140,11 @@ func TestSilencedStorageWithBegin(t *testing.T) {
require.NotNil(t, entry)
assert.False(t, entry.Begin < currentTime)

// Wait for begin time to elapse current time. i.e let silencing begin
time.Sleep(3 * time.Second)

// reset current time to be ahead of begin time
currentTime = time.Date(1970, 01, 01, 02, 00, 00, 00, time.UTC).Unix()
currentTime = time.Now().Unix()
assert.True(t, entry.Begin < currentTime)
})
}
Expand Down Expand Up @@ -168,3 +174,26 @@ func TestSilencedStorageWithBeginAndExpire(t *testing.T) {
assert.Equal(t, entry.Expire, int64(15))
})
}

func TestSilencedStorageWithMaxAllowedThresholdExpiry(t *testing.T) {
testWithEtcd(t, func(store store.Store) {
silenced := types.FixtureSilenced("subscription:checkname")
silenced.Namespace = "default"
silenced.ExpireAt = time.Now().Add(time.Duration(30000) * time.Second).Unix()
// set a begin time
silenced.Begin = time.Now().Unix()
ctx := context.WithValue(context.Background(), types.NamespaceKey, silenced.Namespace)

err := store.UpdateSilencedEntry(ctx, silenced)

// assert that error is thrown for breaching max expiry time allowed
assert.Error(t, err)

entry, err := store.GetSilencedEntryByName(ctx, silenced.Name)

// assert that entry is nil
assert.NoError(t, err)
assert.Nil(t, entry)

})
}
11 changes: 11 additions & 0 deletions backend/store/etcd/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"path"
"reflect"
"strings"
"time"

"github.com/gogo/protobuf/proto"
"github.com/sensu/sensu-go/backend/store"
Expand All @@ -22,10 +23,16 @@ const (
EtcdRoot = "/sensu.io"
)

type Config struct {
DefaultSilencedExpiryTime time.Duration
MaxSilencedExpiryTimeAllowed time.Duration
}

// Store is an implementation of the sensu-go/backend/store.Store iface.
type Store struct {
client *clientv3.Client
keepalivesPath string
cfg Config
}

// NewStore creates a new Store.
Expand All @@ -38,6 +45,10 @@ func NewStore(client *clientv3.Client, name string) *Store {
return store
}

func SetConfig(cfg Config, store *Store) {
store.cfg = cfg
}

// Create the given key with the serialized object.
func Create(ctx context.Context, client *clientv3.Client, key, namespace string, object interface{}) error {
bytes, err := marshal(object)
Expand Down
13 changes: 11 additions & 2 deletions backend/store/etcd/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"context"
"encoding/json"
"fmt"
"testing"

"github.com/gogo/protobuf/proto"
corev2 "github.com/sensu/core/v2"
"github.com/sensu/sensu-go/backend/etcd"
Expand All @@ -18,6 +16,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.etcd.io/etcd/client/v3"
"testing"
"time"
)

func testWithEtcd(t *testing.T, f func(store.Store)) {
Expand All @@ -28,6 +28,9 @@ func testWithEtcd(t *testing.T, f func(store.Store)) {

s := NewStore(client, e.Name())

s.cfg.MaxSilencedExpiryTimeAllowed = time.Duration(3000 * time.Second)
s.cfg.DefaultSilencedExpiryTime = time.Duration(3000 * time.Second)

// Mock a default namespace
require.NoError(t, s.CreateNamespace(context.Background(), types.FixtureNamespace("default")))

Expand All @@ -42,6 +45,9 @@ func testWithEtcdStore(t *testing.T, f func(*Store)) {

s := NewStore(client, e.Name())

s.cfg.MaxSilencedExpiryTimeAllowed = time.Duration(3000 * time.Second)
s.cfg.DefaultSilencedExpiryTime = time.Duration(3000 * time.Second)

// Mock a default namespace
require.NoError(t, s.CreateNamespace(context.Background(), types.FixtureNamespace("default")))

Expand All @@ -56,6 +62,9 @@ func testWithEtcdClient(t *testing.T, f func(store.Store, *clientv3.Client)) {

s := NewStore(client, e.Name())

s.cfg.MaxSilencedExpiryTimeAllowed = time.Duration(3000 * time.Second)
s.cfg.DefaultSilencedExpiryTime = time.Duration(3000 * time.Second)

// Mock a default namespace
require.NoError(t, s.CreateNamespace(context.Background(), types.FixtureNamespace("default")))

Expand Down
8 changes: 8 additions & 0 deletions backend/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ type ErrNotValid struct {
Err error
}

type ErrThreshold struct {
Err error
}

func (e *ErrThreshold) Error() string {
return fmt.Sprintf("Threshold reached: %s", e.Err.Error())
}

func (e *ErrNotValid) Error() string {
return fmt.Sprintf("resource is invalid: %s", e.Err.Error())
}
Expand Down
Loading