1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
package client
import (
"crypto/tls"
"net/url"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/go-logr/logr"
"github.com/prometheus/client_golang/prometheus"
)
const (
defaultTCPEndpoint = "tcp:127.0.0.1:6640"
defaultSSLEndpoint = "ssl:127.0.0.1:6640"
defaultUnixEndpoint = "unix:/var/run/openvswitch/ovsdb.sock"
)
type options struct {
endpoints []string
tlsConfig *tls.Config
reconnect bool
leaderOnly bool
timeout time.Duration
backoff backoff.BackOff
logger *logr.Logger
registry prometheus.Registerer
shouldRegisterMetrics bool // in case metrics are changed after-the-fact
metricNamespace string // prometheus metric namespace
metricSubsystem string // prometheus metric subsystem
inactivityTimeout time.Duration
}
type Option func(o *options) error
func newOptions(opts ...Option) (*options, error) {
o := &options{}
for _, opt := range opts {
if err := opt(o); err != nil {
return nil, err
}
}
// if no endpoints are supplied, use the default unix socket
if len(o.endpoints) == 0 {
o.endpoints = []string{defaultUnixEndpoint}
}
return o, nil
}
// WithTLSConfig sets the tls.Config for use by the client
func WithTLSConfig(cfg *tls.Config) Option {
return func(o *options) error {
o.tlsConfig = cfg
return nil
}
}
// WithEndpoint sets the endpoint to be used by the client
// It can be used multiple times, and the first endpoint that
// successfully connects will be used.
// Endpoints are specified in OVSDB Connection Format
// For more details, see the ovsdb(7) man page
func WithEndpoint(endpoint string) Option {
return func(o *options) error {
ep, err := url.Parse(endpoint)
if err != nil {
return err
}
switch ep.Scheme {
case UNIX:
if len(ep.Path) == 0 {
o.endpoints = append(o.endpoints, defaultUnixEndpoint)
return nil
}
case TCP:
if len(ep.Opaque) == 0 {
o.endpoints = append(o.endpoints, defaultTCPEndpoint)
return nil
}
case SSL:
if len(ep.Opaque) == 0 {
o.endpoints = append(o.endpoints, defaultSSLEndpoint)
return nil
}
}
o.endpoints = append(o.endpoints, endpoint)
return nil
}
}
// WithLeaderOnly tells the client to treat endpoints that are clustered
// and not the leader as down.
func WithLeaderOnly(leaderOnly bool) Option {
return func(o *options) error {
o.leaderOnly = leaderOnly
return nil
}
}
// WithReconnect tells the client to automatically reconnect when
// disconnected. The timeout is used to construct the context on
// each call to Connect, while backoff dictates the backoff
// algorithm to use. Using WithReconnect implies that
// requested transactions will block until the client has fully reconnected,
// rather than immediately returning an error if there is no connection.
func WithReconnect(timeout time.Duration, backoff backoff.BackOff) Option {
return func(o *options) error {
o.reconnect = true
o.timeout = timeout
o.backoff = backoff
return nil
}
}
// WithInactivityCheck tells the client to send Echo request to ovsdb server periodically
// upon inactivityTimeout. When Echo request fails, then it attempts to reconnect
// with server. The inactivity check is performed as long as the connection is established.
// The reconnectTimeout argument is used to construct the context on each call to Connect,
// while reconnectBackoff dictates the backoff algorithm to use.
func WithInactivityCheck(inactivityTimeout, reconnectTimeout time.Duration,
reconnectBackoff backoff.BackOff) Option {
return func(o *options) error {
o.reconnect = true
o.timeout = reconnectTimeout
o.backoff = reconnectBackoff
o.inactivityTimeout = inactivityTimeout
return nil
}
}
// WithLogger allows setting a specific log sink. Otherwise, the default
// go log package is used.
func WithLogger(l *logr.Logger) Option {
return func(o *options) error {
o.logger = l
return nil
}
}
// WithMetricsRegistry allows the user to specify a Prometheus metrics registry.
// If supplied, the metrics as defined in metrics.go will be registered.
func WithMetricsRegistry(r prometheus.Registerer) Option {
return func(o *options) error {
o.registry = r
o.shouldRegisterMetrics = (r != nil)
return nil
}
}
// WithMetricsRegistryNamespaceSubsystem allows the user to specify a Prometheus metrics registry
// and Prometheus metric namespace and subsystem of the component utilizing libovsdb.
// If supplied, the metrics as defined in metrics.go will be registered.
func WithMetricsRegistryNamespaceSubsystem(r prometheus.Registerer, namespace, subsystem string) Option {
if namespace == "" || subsystem == "" {
panic("libovsdb function WithMetricsRegistryNamespaceSubsystem arguments 'namespace' and 'subsystem' must not be empty")
}
return func(o *options) error {
o.registry = r
o.shouldRegisterMetrics = (r != nil)
o.metricNamespace = namespace
o.metricSubsystem = subsystem
return nil
}
}
|