mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
![Sebastiaan van Stijn](/assets/img/avatar_default.png)
Relevant changes; - swarmkit#2681 Handle an edge case in CA rotation where we reclaim CA service from an external CA - swarmkit#2750 Use gometalinter; switch from x/net/context -> context Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
256 lines
6.1 KiB
Go
256 lines
6.1 KiB
Go
package metrics
|
|
|
|
import (
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
"github.com/docker/go-events"
|
|
metrics "github.com/docker/go-metrics"
|
|
"github.com/docker/swarmkit/api"
|
|
"github.com/docker/swarmkit/manager/state/store"
|
|
)
|
|
|
|
var (
|
|
ns = metrics.NewNamespace("swarm", "manager", nil)
|
|
|
|
// counts of the various objects in swarmkit
|
|
nodesMetric metrics.LabeledGauge
|
|
tasksMetric metrics.LabeledGauge
|
|
|
|
// none of these objects have state, so they're just regular gauges
|
|
servicesMetric metrics.Gauge
|
|
networksMetric metrics.Gauge
|
|
secretsMetric metrics.Gauge
|
|
configsMetric metrics.Gauge
|
|
)
|
|
|
|
func init() {
|
|
nodesMetric = ns.NewLabeledGauge("nodes", "The number of nodes", "", "state")
|
|
tasksMetric = ns.NewLabeledGauge("tasks", "The number of tasks in the cluster object store", metrics.Total, "state")
|
|
servicesMetric = ns.NewGauge("services", "The number of services in the cluster object store", metrics.Total)
|
|
networksMetric = ns.NewGauge("networks", "The number of networks in the cluster object store", metrics.Total)
|
|
secretsMetric = ns.NewGauge("secrets", "The number of secrets in the cluster object store", metrics.Total)
|
|
configsMetric = ns.NewGauge("configs", "The number of configs in the cluster object store", metrics.Total)
|
|
|
|
resetMetrics()
|
|
|
|
metrics.Register(ns)
|
|
}
|
|
|
|
// Collector collects swarmkit metrics
|
|
type Collector struct {
|
|
store *store.MemoryStore
|
|
|
|
// stopChan signals to the state machine to stop running.
|
|
stopChan chan struct{}
|
|
// doneChan is closed when the state machine terminates.
|
|
doneChan chan struct{}
|
|
}
|
|
|
|
// NewCollector creates a new metrics collector
|
|
func NewCollector(store *store.MemoryStore) *Collector {
|
|
return &Collector{
|
|
store: store,
|
|
stopChan: make(chan struct{}),
|
|
doneChan: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// Run contains the collector event loop
|
|
func (c *Collector) Run(ctx context.Context) error {
|
|
defer close(c.doneChan)
|
|
|
|
watcher, cancel, err := store.ViewAndWatch(c.store, func(readTx store.ReadTx) error {
|
|
nodes, err := store.FindNodes(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tasks, err := store.FindTasks(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
services, err := store.FindServices(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
networks, err := store.FindNetworks(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
secrets, err := store.FindSecrets(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
configs, err := store.FindConfigs(readTx, store.All)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, obj := range nodes {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
for _, obj := range tasks {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
for _, obj := range services {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
for _, obj := range networks {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
for _, obj := range secrets {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
for _, obj := range configs {
|
|
c.handleEvent(obj.EventCreate())
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer cancel()
|
|
|
|
for {
|
|
select {
|
|
case event := <-watcher:
|
|
c.handleEvent(event)
|
|
case <-c.stopChan:
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stop stops the collector.
|
|
func (c *Collector) Stop() {
|
|
close(c.stopChan)
|
|
<-c.doneChan
|
|
|
|
// Clean the metrics on exit.
|
|
resetMetrics()
|
|
}
|
|
|
|
// resetMetrics resets all metrics to their default (base) value
|
|
func resetMetrics() {
|
|
for _, state := range api.NodeStatus_State_name {
|
|
nodesMetric.WithValues(strings.ToLower(state)).Set(0)
|
|
}
|
|
for _, state := range api.TaskState_name {
|
|
tasksMetric.WithValues(strings.ToLower(state)).Set(0)
|
|
}
|
|
servicesMetric.Set(0)
|
|
networksMetric.Set(0)
|
|
secretsMetric.Set(0)
|
|
configsMetric.Set(0)
|
|
|
|
}
|
|
|
|
// handleEvent handles a single incoming cluster event.
|
|
func (c *Collector) handleEvent(event events.Event) {
|
|
switch event.(type) {
|
|
case api.EventNode:
|
|
c.handleNodeEvent(event)
|
|
case api.EventTask:
|
|
c.handleTaskEvent(event)
|
|
case api.EventService:
|
|
c.handleServiceEvent(event)
|
|
case api.EventNetwork:
|
|
c.handleNetworkEvent(event)
|
|
case api.EventSecret:
|
|
c.handleSecretsEvent(event)
|
|
case api.EventConfig:
|
|
c.handleConfigsEvent(event)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleNodeEvent(event events.Event) {
|
|
var prevNode, newNode *api.Node
|
|
|
|
switch v := event.(type) {
|
|
case api.EventCreateNode:
|
|
prevNode, newNode = nil, v.Node
|
|
case api.EventUpdateNode:
|
|
prevNode, newNode = v.OldNode, v.Node
|
|
case api.EventDeleteNode:
|
|
prevNode, newNode = v.Node, nil
|
|
}
|
|
|
|
// Skip updates if nothing changed.
|
|
if prevNode != nil && newNode != nil && prevNode.Status.State == newNode.Status.State {
|
|
return
|
|
}
|
|
|
|
if prevNode != nil {
|
|
nodesMetric.WithValues(strings.ToLower(prevNode.Status.State.String())).Dec(1)
|
|
}
|
|
if newNode != nil {
|
|
nodesMetric.WithValues(strings.ToLower(newNode.Status.State.String())).Inc(1)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleTaskEvent(event events.Event) {
|
|
var prevTask, newTask *api.Task
|
|
|
|
switch v := event.(type) {
|
|
case api.EventCreateTask:
|
|
prevTask, newTask = nil, v.Task
|
|
case api.EventUpdateTask:
|
|
prevTask, newTask = v.OldTask, v.Task
|
|
case api.EventDeleteTask:
|
|
prevTask, newTask = v.Task, nil
|
|
}
|
|
|
|
// Skip updates if nothing changed.
|
|
if prevTask != nil && newTask != nil && prevTask.Status.State == newTask.Status.State {
|
|
return
|
|
}
|
|
|
|
if prevTask != nil {
|
|
tasksMetric.WithValues(
|
|
strings.ToLower(prevTask.Status.State.String()),
|
|
).Dec(1)
|
|
}
|
|
if newTask != nil {
|
|
tasksMetric.WithValues(
|
|
strings.ToLower(newTask.Status.State.String()),
|
|
).Inc(1)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleServiceEvent(event events.Event) {
|
|
switch event.(type) {
|
|
case api.EventCreateService:
|
|
servicesMetric.Inc(1)
|
|
case api.EventDeleteService:
|
|
servicesMetric.Dec(1)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleNetworkEvent(event events.Event) {
|
|
switch event.(type) {
|
|
case api.EventCreateNetwork:
|
|
networksMetric.Inc(1)
|
|
case api.EventDeleteNetwork:
|
|
networksMetric.Dec(1)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleSecretsEvent(event events.Event) {
|
|
switch event.(type) {
|
|
case api.EventCreateSecret:
|
|
secretsMetric.Inc(1)
|
|
case api.EventDeleteSecret:
|
|
secretsMetric.Dec(1)
|
|
}
|
|
}
|
|
|
|
func (c *Collector) handleConfigsEvent(event events.Event) {
|
|
switch event.(type) {
|
|
case api.EventCreateConfig:
|
|
configsMetric.Inc(1)
|
|
case api.EventDeleteConfig:
|
|
configsMetric.Dec(1)
|
|
}
|
|
}
|