2017-06-08 15:01:08 +00:00
|
|
|
package connector
|
|
|
|
|
|
|
|
import (
|
2017-06-14 13:11:40 +00:00
|
|
|
"fmt"
|
2018-01-30 10:54:13 +00:00
|
|
|
"sort"
|
2019-05-22 16:58:55 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2017-06-14 13:11:40 +00:00
|
|
|
|
2017-06-08 15:01:08 +00:00
|
|
|
"github.com/bcicen/ctop/container"
|
|
|
|
"github.com/bcicen/ctop/logging"
|
|
|
|
)
|
|
|
|
|
2018-01-29 12:47:10 +00:00
|
|
|
var (
|
|
|
|
log = logging.Init()
|
2019-05-22 16:58:55 +00:00
|
|
|
enabled = make(map[string]ConnectorFn)
|
2018-01-29 12:47:10 +00:00
|
|
|
)
|
2017-06-08 15:01:08 +00:00
|
|
|
|
2019-05-22 16:58:55 +00:00
|
|
|
type ConnectorFn func() (Connector, error)
|
|
|
|
|
|
|
|
type Connector interface {
|
|
|
|
// All returns a pre-sorted container.Containers of all discovered containers
|
|
|
|
All() container.Containers
|
|
|
|
// Get returns a single container.Container by ID
|
|
|
|
Get(string) (*container.Container, bool)
|
|
|
|
// Wait waits for the underlying connection to be lost before returning
|
|
|
|
Wait() struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConnectorSuper provides initial connection and retry on failure for
|
|
|
|
// an undlerying Connector type
|
|
|
|
type ConnectorSuper struct {
|
|
|
|
conn Connector
|
|
|
|
connFn ConnectorFn
|
|
|
|
err error
|
|
|
|
lock sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConnectorSuper(connFn ConnectorFn) *ConnectorSuper {
|
|
|
|
cs := &ConnectorSuper{
|
|
|
|
connFn: connFn,
|
|
|
|
err: fmt.Errorf("connecting..."),
|
|
|
|
}
|
|
|
|
go cs.loop()
|
|
|
|
return cs
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the underlying Connector, or nil and an error
|
|
|
|
// if the Connector is not yet initialized or is disconnected.
|
|
|
|
func (cs *ConnectorSuper) Get() (Connector, error) {
|
|
|
|
cs.lock.RLock()
|
|
|
|
defer cs.lock.RUnlock()
|
|
|
|
if cs.err != nil {
|
|
|
|
return nil, cs.err
|
|
|
|
}
|
|
|
|
return cs.conn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *ConnectorSuper) setError(err error) {
|
|
|
|
cs.lock.Lock()
|
|
|
|
defer cs.lock.Unlock()
|
|
|
|
cs.err = err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cs *ConnectorSuper) loop() {
|
|
|
|
const interval = 3
|
|
|
|
for {
|
|
|
|
log.Infof("initializing connector")
|
|
|
|
|
|
|
|
conn, err := cs.connFn()
|
|
|
|
if err != nil {
|
2019-05-22 17:38:01 +00:00
|
|
|
cs.setError(err)
|
2019-05-22 16:58:55 +00:00
|
|
|
log.Errorf("failed to initialize connector: %s (%T)", err, err)
|
|
|
|
log.Errorf("retrying in %ds", interval)
|
|
|
|
time.Sleep(interval * time.Second)
|
|
|
|
} else {
|
|
|
|
cs.conn = conn
|
|
|
|
cs.setError(nil)
|
|
|
|
log.Infof("successfully initialized connector")
|
|
|
|
|
|
|
|
// wait until connection closed
|
|
|
|
cs.conn.Wait()
|
|
|
|
cs.setError(fmt.Errorf("attempting to reconnect..."))
|
|
|
|
log.Infof("connector closed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 02:33:29 +00:00
|
|
|
// Enabled returns names for all enabled connectors on the current platform
|
2018-01-30 10:54:13 +00:00
|
|
|
func Enabled() (a []string) {
|
|
|
|
for k, _ := range enabled {
|
|
|
|
a = append(a, k)
|
|
|
|
}
|
|
|
|
sort.Strings(a)
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
2019-05-22 16:58:55 +00:00
|
|
|
// ByName returns a ConnectorSuper for a given name, or error if the connector
|
|
|
|
// does not exists on the current platform
|
|
|
|
func ByName(s string) (*ConnectorSuper, error) {
|
2018-01-30 10:54:13 +00:00
|
|
|
if cfn, ok := enabled[s]; ok {
|
2019-05-22 16:58:55 +00:00
|
|
|
return NewConnectorSuper(cfn), nil
|
2017-06-14 13:11:40 +00:00
|
|
|
}
|
2018-01-30 10:54:13 +00:00
|
|
|
return nil, fmt.Errorf("invalid connector type \"%s\"", s)
|
2017-06-14 13:11:40 +00:00
|
|
|
}
|