vitess.io/vitess@v0.16.2/go/vt/vtadmin/cluster/discovery/discovery.go (about)

     1  /*
     2  Copyright 2020 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package discovery
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/spf13/pflag"
    26  
    27  	vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin"
    28  )
    29  
    30  var (
    31  	// ErrImplementationNotRegistered is returned from discovery.New if it is
    32  	// called with an unknown implementation.
    33  	ErrImplementationNotRegistered = errors.New("no discovery factory registered for implementation")
    34  	// ErrNoVTGates should be returned from DiscoverVTGate* methods when they
    35  	// are unable to find any vtgates for the given filter/query/tags.
    36  	ErrNoVTGates = errors.New("no vtgates found")
    37  	// ErrNoVtctlds should be returned from DiscoverVtctld* methods when they
    38  	// are unable to find any vtctlds for the given filter/query/tags.
    39  	ErrNoVtctlds = errors.New("no vtctlds found")
    40  )
    41  
    42  // Discovery defines the interface that service discovery plugins must
    43  // implement. See ConsulDiscovery for an example implementation.
    44  type Discovery interface {
    45  	// DiscoverVTGate returns a vtgate found in the discovery service.
    46  	// Tags can optionally be used to filter the set of potential gates further.
    47  	// Which gate in a set of found gates is returned is not specified by the
    48  	// interface, and can be implementation-specific.
    49  	DiscoverVTGate(ctx context.Context, tags []string) (*vtadminpb.VTGate, error)
    50  	// DiscoverVTGateAddr returns the address of a of vtgate found in the
    51  	// discovery service. Tags can optionally be used to filter the set of
    52  	// potential gates further. Which gate in a set of found gates is used to
    53  	// return an address is not specified by the interface, and can be
    54  	// implementation-specific.
    55  	DiscoverVTGateAddr(ctx context.Context, tags []string) (string, error)
    56  	// DiscoverVTGateAddrs returns a list of addresses of vtgates found in the
    57  	// discovery service. This is semantically equivalent to the result of
    58  	// DiscoverVTGateAddr for each gate returned by a call to DiscoverVTGates.
    59  	DiscoverVTGateAddrs(ctx context.Context, tags []string) ([]string, error)
    60  	// DiscoverVTGates returns a list of vtgates found in the discovery service.
    61  	// Tags can optionally be used to filter gates. Order of the gates is not
    62  	// specified by the interface, and can be implementation-specific.
    63  	DiscoverVTGates(ctx context.Context, tags []string) ([]*vtadminpb.VTGate, error)
    64  	// DiscoverVtctld returns a vtctld found in the discovery service.
    65  	// Tags can optionally be used to filter the set of potential vtctlds
    66  	// further. Which vtctld in a set of found vtctlds is returned is not
    67  	// specified by the interface, and can be implementation-specific.
    68  	DiscoverVtctld(ctx context.Context, tags []string) (*vtadminpb.Vtctld, error)
    69  	// DiscoverVtctldAddr returns the address of a vtctld found in the discovery
    70  	// service. Tags can optionally be used to filter the set of potential
    71  	// vtctlds further. Which vtctld in a set of potential vtctld is used to
    72  	// return an address is not specified by the interface, and can be
    73  	// implementation-specific.
    74  	DiscoverVtctldAddr(ctx context.Context, tags []string) (string, error)
    75  	// DiscoverVtctldAddrs returns a list of addresses of vtctlds found in the
    76  	// discovery service. This is semantically equivalent to the result of
    77  	// DiscoverVtctldAddr for each gate returned by a call to DiscoverVtctlds.
    78  	DiscoverVtctldAddrs(ctx context.Context, tags []string) ([]string, error)
    79  	// DiscoverVtctlds returns a list of vtctlds found in the discovery service.
    80  	// Tags can optionally be used to filter vtctlds. Order of the vtctlds is
    81  	// not specified by the interface, and can be implementation-specific.
    82  	DiscoverVtctlds(ctx context.Context, tags []string) ([]*vtadminpb.Vtctld, error)
    83  }
    84  
    85  // Factory represents a function that can create a Discovery implementation.
    86  // This package will provide several implementations and register them for use.
    87  // The flags FlagSet is provided for convenience, but also to hint to plugin
    88  // developers that they should expect the args to be in a format compatible with
    89  // pflag.
    90  type Factory func(cluster *vtadminpb.Cluster, flags *pflag.FlagSet, args []string) (Discovery, error)
    91  
    92  // nolint:gochecknoglobals
    93  var registry = map[string]Factory{}
    94  var registryMu sync.Mutex
    95  
    96  // Register registers a factory for the given implementation name. Attempting
    97  // to register multiple factories for the same implementation name causes a
    98  // panic.
    99  func Register(name string, factory Factory) {
   100  	registryMu.Lock()
   101  	defer registryMu.Unlock()
   102  
   103  	_, ok := registry[name]
   104  	if ok {
   105  		panic("[discovery] factory already registered for " + name)
   106  	}
   107  
   108  	registry[name] = factory
   109  }
   110  
   111  // New returns a Discovery implementation using the registered factory for the
   112  // implementation. Usage of the args slice is dependent on the implementation's
   113  // factory.
   114  func New(impl string, cluster *vtadminpb.Cluster, args []string) (Discovery, error) {
   115  	registryMu.Lock()
   116  	factory, ok := registry[impl]
   117  	registryMu.Unlock()
   118  
   119  	if !ok {
   120  		return nil, fmt.Errorf("%w %s", ErrImplementationNotRegistered, impl)
   121  	}
   122  
   123  	return factory(cluster, pflag.NewFlagSet("discovery:"+impl, pflag.ContinueOnError), args)
   124  }
   125  
   126  func init() { // nolint:gochecknoinits
   127  	Register("consul", NewConsul)
   128  	Register("staticfile", NewStaticFile)
   129  	Register("dynamic", NewDynamic)
   130  }