From 1f6d16bfa281e53f4e2288458e9d50167815b11c Mon Sep 17 00:00:00 2001 From: Simon Plourde Date: Wed, 16 Oct 2019 13:33:19 -0400 Subject: [PATCH] Release 5.14.1 (#3339) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * output yaml separator to file output stream instead of default cmd (#3331) Signed-off-by: Florian Schwab * Fix a panic in wizard bus (#3336) This commit fixes a "send on closed channel" panic that can crash the backend. Signed-off-by: Eric Chlebek * Add prom gauges for schedulerd (#3338) * Add prom gauges for schedulerd * Fix a double-stop bug in the check watcher Signed-off-by: Eric Chlebek * The corev2.AuthProvider interface should embed the Resource int… (#3337) Signed-off-by: Simon Plourde * Add default timeout to bolt.Open (#3322) Signed-off-by: Simon Plourde * Prepare 5.14.1 release Signed-off-by: Simon Plourde --- CHANGELOG.md | 17 +++++++++ agent/queue.go | 10 ++++-- api/core/v2/provider.go | 12 ++----- .../authentication/providers/basic/basic.go | 10 ++++++ backend/messaging/wizard_topic.go | 22 +++++++++--- backend/schedulerd/check_watcher.go | 2 ++ backend/schedulerd/cron_scheduler.go | 2 ++ backend/schedulerd/interval_scheduler.go | 2 ++ backend/schedulerd/roundrobin_cron.go | 2 ++ backend/schedulerd/roundrobin_interval.go | 2 ++ backend/schedulerd/schedulerd.go | 35 +++++++++++++++++++ cli/commands/dump/dump.go | 2 +- 12 files changed, 99 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ef924025..6b9b27e814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ Versioning](http://semver.org/spec/v2.0.0.html). ## Unreleased +### Added +- Added the `APIKey` resource and HTTP API support for POST, GET, and DELETE. +- Added sensuctl commands to manage the `APIKey` resource. +- Added support for api keys to be used in api authentication. + +## [5.14.1] - 2019-10-16 + +### Added +- Added prometheus gauges for check schedulers. + +### Fixed +- Opening an already open Bolt database should not cause sensu-agent to hang +indefinitely. +- [CLI] Dump multiple types as YAML to a file would print separator STDOUT +instead of specified file +- Fixed a bug where Sensu would crash with a panic due to a send on a closed channel. + ## [5.14.0] - 2019-10-08 ### Added diff --git a/agent/queue.go b/agent/queue.go index 2209dffcfb..ad00bdf3a5 100644 --- a/agent/queue.go +++ b/agent/queue.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "sync" + "time" "github.com/sensu/lasr" bolt "go.etcd.io/bbolt" @@ -68,12 +69,15 @@ func newQueue(path string) (queue, error) { return newMemoryQueue(1000), nil } if err := os.MkdirAll(path, 0744|os.ModeDir); err != nil { - return nil, fmt.Errorf("error creating api queue: %s", err) + return nil, fmt.Errorf("could not create directory for api queue (%s): %s", path, err) } queuePath := filepath.Join(path, "queue.db") - db, err := bolt.Open(queuePath, 0644, nil) + // Create and open the database for the queue. The FileMode given here (0600) + // is only temporary since it will be enforced to 0600 when the queue is + // compacted below by the queue.Compact method + db, err := bolt.Open(queuePath, 0600, &bolt.Options{Timeout: 60 * time.Second}) if err != nil { - return nil, fmt.Errorf("error creating api queue: %s", err) + return nil, fmt.Errorf("could not open api queue (%s): %s", queuePath, err) } queue, err := lasr.NewQ(db, "api-buffer") if err != nil { diff --git a/api/core/v2/provider.go b/api/core/v2/provider.go index 135b5f0bf0..10acb078a1 100644 --- a/api/core/v2/provider.go +++ b/api/core/v2/provider.go @@ -6,23 +6,15 @@ import ( // AuthProvider represents an abstracted authentication provider type AuthProvider interface { + Resource + // Authenticate attempts to authenticate a user with its username and password Authenticate(ctx context.Context, username, password string) (*Claims, error) // Refresh renews the user claims with the provider claims Refresh(ctx context.Context, claims *Claims) (*Claims, error) - // GetObjectMeta returns the object metadata for the provider - GetObjectMeta() ObjectMeta // Name returns the provider name (e.g. default) Name() string - // StorePrefix gives the path prefix to this resource in the store - StorePrefix() string // Type returns the provider type (e.g. ldap) Type() string - // URIPath gives the path to the provider - URIPath() string - // Validate checks if the fields in the provider are valid - Validate() error - // SetNamespace sets the namespace of the resource. - SetNamespace(string) } diff --git a/backend/authentication/providers/basic/basic.go b/backend/authentication/providers/basic/basic.go index 8dfd57ba9a..c7b2b2fc60 100644 --- a/backend/authentication/providers/basic/basic.go +++ b/backend/authentication/providers/basic/basic.go @@ -107,3 +107,13 @@ func (p *Provider) claims(username string) corev2.AuthProviderClaims { func (p *Provider) SetNamespace(namespace string) { p.Namespace = namespace } + +// RBACName is not implemented +func (p *Provider) RBACName() string { + return "" +} + +// SetObjectMeta sets the meta of the resource. +func (p *Provider) SetObjectMeta(meta corev2.ObjectMeta) { + p.ObjectMeta = meta +} diff --git a/backend/messaging/wizard_topic.go b/backend/messaging/wizard_topic.go index 48d696f4d9..f1fc1332b1 100644 --- a/backend/messaging/wizard_topic.go +++ b/backend/messaging/wizard_topic.go @@ -24,11 +24,23 @@ func (t *wizardTopic) Send(msg interface{}) { for _, subscriber := range subscribers { topicCounter.WithLabelValues(t.id).Set(float64(len(subscriber.Receiver()))) - select { - case subscriber.Receiver() <- msg: - case <-t.done: - return - } + safeSend(subscriber.Receiver(), msg, t.done) + } +} + +// safeSend can attempt to send to a closed channel without panicking. +// This is only necessary because of a design flaw in wizard bus. Do not +// use this elsewhere. +// +// The topic reads the subscribers and then releases its lock, in Send(). In rare cases, +// cancelling a subscription can lead to a send on a closed channel. +func safeSend(c chan<- interface{}, message interface{}, done chan struct{}) { + defer func() { + _ = recover() + }() + select { + case c <- message: + case <-done: } } diff --git a/backend/schedulerd/check_watcher.go b/backend/schedulerd/check_watcher.go index 00c127799c..c3549691ed 100644 --- a/backend/schedulerd/check_watcher.go +++ b/backend/schedulerd/check_watcher.go @@ -146,6 +146,7 @@ func (c *CheckWatcher) handleWatchEvent(watchEvent store.WatchEventCheckConfig) if err := c.startScheduler(check); err != nil { logger.WithError(err).Error("unable to start check scheduler") } + return } if sched.Type() == GetSchedulerType(check) { logger.Info("restarting scheduler") @@ -155,6 +156,7 @@ func (c *CheckWatcher) handleWatchEvent(watchEvent store.WatchEventCheckConfig) if err := sched.Stop(); err != nil { logger.WithError(err).Error("error stopping check scheduler") } + delete(c.items, key) if err := c.startScheduler(check); err != nil { logger.WithError(err).Error("unable to start check scheduler") } diff --git a/backend/schedulerd/cron_scheduler.go b/backend/schedulerd/cron_scheduler.go index 88c6d24189..b1524b8464 100644 --- a/backend/schedulerd/cron_scheduler.go +++ b/backend/schedulerd/cron_scheduler.go @@ -61,6 +61,7 @@ func (s *CronScheduler) schedule(timer *CronTimer, executor *CheckExecutor) { // Start starts the cron scheduler. func (s *CronScheduler) Start() { + cronCounter.WithLabelValues(s.check.Namespace).Inc() go s.start() } @@ -97,6 +98,7 @@ func (s *CronScheduler) Interrupt(check *corev2.CheckConfig) { // Stop stops the cron scheduler. func (s *CronScheduler) Stop() error { + cronCounter.WithLabelValues(s.check.Namespace).Dec() logger.Info("stopping cron scheduler") s.cancel() diff --git a/backend/schedulerd/interval_scheduler.go b/backend/schedulerd/interval_scheduler.go index 9ed34b0b3d..8418d521c4 100644 --- a/backend/schedulerd/interval_scheduler.go +++ b/backend/schedulerd/interval_scheduler.go @@ -61,6 +61,7 @@ func (s *IntervalScheduler) schedule(timer CheckTimer, executor *CheckExecutor) // Start starts the IntervalScheduler. func (s *IntervalScheduler) Start() { + intervalCounter.WithLabelValues(s.check.Namespace).Inc() go s.start() } @@ -98,6 +99,7 @@ func (s *IntervalScheduler) Interrupt(check *corev2.CheckConfig) { // Stop stops the IntervalScheduler func (s *IntervalScheduler) Stop() error { + intervalCounter.WithLabelValues(s.check.Namespace).Dec() s.logger.Info("stopping scheduler") s.cancel() diff --git a/backend/schedulerd/roundrobin_cron.go b/backend/schedulerd/roundrobin_cron.go index 0ff729d652..18762df172 100644 --- a/backend/schedulerd/roundrobin_cron.go +++ b/backend/schedulerd/roundrobin_cron.go @@ -54,6 +54,7 @@ func NewRoundRobinCronScheduler(ctx context.Context, store store.Store, bus mess // Start starts the scheduler. func (s *RoundRobinCronScheduler) Start() { + rrCronCounter.WithLabelValues(s.check.Namespace).Inc() go s.start() } @@ -192,6 +193,7 @@ func (s *RoundRobinCronScheduler) Interrupt(check *corev2.CheckConfig) { // Stop stops the scheduler func (s *RoundRobinCronScheduler) Stop() error { + rrCronCounter.WithLabelValues(s.check.Namespace).Dec() s.logger.Info("stopping scheduler") s.cancel() return nil diff --git a/backend/schedulerd/roundrobin_interval.go b/backend/schedulerd/roundrobin_interval.go index 971442844d..71ffd32bb3 100644 --- a/backend/schedulerd/roundrobin_interval.go +++ b/backend/schedulerd/roundrobin_interval.go @@ -103,6 +103,7 @@ func (s *RoundRobinIntervalScheduler) updateRings() { // Start starts the round robin interval scheduler. func (s *RoundRobinIntervalScheduler) Start() { + rrIntervalCounter.WithLabelValues(s.check.Namespace).Inc() go s.start() } @@ -213,6 +214,7 @@ func (s *RoundRobinIntervalScheduler) Interrupt(check *corev2.CheckConfig) { // Stop stops the scheduler func (s *RoundRobinIntervalScheduler) Stop() error { + rrIntervalCounter.WithLabelValues(s.check.Namespace).Dec() s.logger.Info("stopping scheduler") s.cancel() return nil diff --git a/backend/schedulerd/schedulerd.go b/backend/schedulerd/schedulerd.go index ccc47e4e7b..c46a56385c 100644 --- a/backend/schedulerd/schedulerd.go +++ b/backend/schedulerd/schedulerd.go @@ -4,6 +4,7 @@ import ( "context" "github.com/coreos/etcd/clientv3" + "github.com/prometheus/client_golang/prometheus" corev2 "github.com/sensu/sensu-go/api/core/v2" "github.com/sensu/sensu-go/backend/messaging" "github.com/sensu/sensu-go/backend/ringv2" @@ -12,6 +13,36 @@ import ( "github.com/sensu/sensu-go/types" ) +var ( + intervalCounter = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "sensu_go_interval_schedulers", + Help: "Number of active interval check schedulers on this backend", + }, + []string{"namespace"}) + + cronCounter = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "sensu_go_cron_schedulers", + Help: "Number of active cron check schedulers on this backend", + }, + []string{"namespace"}) + + rrIntervalCounter = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "sensu_go_round_robin_interval_schedulers", + Help: "Number of active round robin interval check schedulers on this backend.", + }, + []string{"namespace"}) + + rrCronCounter = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "sensu_go_round_robin_cron_schedulers", + Help: "Number of active round robin cron check schedulers on this backend.", + }, + []string{"namespace"}) +) + // Schedulerd handles scheduling check requests for each check's // configured interval and publishing to the message bus. type Schedulerd struct { @@ -67,6 +98,10 @@ func New(ctx context.Context, c Config, opts ...Option) (*Schedulerd, error) { // Start the Scheduler daemon. func (s *Schedulerd) Start() error { + _ = prometheus.Register(intervalCounter) + _ = prometheus.Register(cronCounter) + _ = prometheus.Register(rrIntervalCounter) + _ = prometheus.Register(rrCronCounter) return s.checkWatcher.Start() } diff --git a/cli/commands/dump/dump.go b/cli/commands/dump/dump.go index 3459f3cc62..05fb72c306 100644 --- a/cli/commands/dump/dump.go +++ b/cli/commands/dump/dump.go @@ -264,7 +264,7 @@ func execute(cli *cli.SensuCli) func(*cobra.Command, []string) error { err = helpers.PrintWrappedJSONList(resources, w) case config.FormatYAML: if i > 0 { - _, _ = fmt.Fprintln(cmd.OutOrStdout(), "---") + _, _ = fmt.Fprintln(w, "---") } err = helpers.PrintYAML(resources, w) default: