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.
77 lines
2.1 KiB
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)
|
|
}
|
|
|