You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tailscale/k8s-operator/tsclient/provider.go

77 lines
2.1 KiB

// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package tsclient
import (
"errors"
"fmt"
"sync"
)
type (
// The Provider type is used to manage multiple Client implementations for different tailnets.
Provider struct {
defaultClient Client
mu sync.RWMutex
clients map[string]Client
readiness map[string]bool
}
)
var (
// ErrClientNotFound is the error given when calling Provider.For with a tailnet that has not yet been registered
// with the provider.
ErrClientNotFound = errors.New("client not found")
// ErrNotReady is the error given when calling Provider.For with a tailnet that has not yet been declared as
// ready to use by the operator.
ErrNotReady = errors.New("tailnet not ready")
)
// NewProvider returns a new instance of the Provider type that uses the given Client implementation as the default
// client. This client will be given when calling Provider.For with a blank tailnet name.
func NewProvider(defaultClient Client) *Provider {
return &Provider{
defaultClient: defaultClient,
clients: make(map[string]Client),
readiness: make(map[string]bool),
}
}
// Add a Client implementation for a given tailnet.
func (p *Provider) Add(tailnet string, client Client, ready bool) {
p.mu.Lock()
defer p.mu.Unlock()
p.clients[tailnet] = client
p.readiness[tailnet] = ready
}
// Remove the Client implementation associated with the given tailnet.
func (p *Provider) Remove(tailnet string) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.clients, tailnet)
}
// For returns a Client implementation associated with the given tailnet. Returns ErrClientNotFound if the given
// tailnet does not exist. Use a blank tailnet name to obtain the default Client.
func (p *Provider) For(tailnet string) (Client, error) {
if tailnet == "" {
return p.defaultClient, nil
}
p.mu.RLock()
defer p.mu.RUnlock()
if client, ok := p.clients[tailnet]; ok {
if ready, _ := p.readiness[tailnet]; !ready {
return nil, fmt.Errorf("%w: %s", ErrNotReady, tailnet)
}
return client, nil
}
return nil, fmt.Errorf("%w: %s", ErrClientNotFound, tailnet)
}