github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/discovery/config.go (about)

     1  // Copyright (c) 2020 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  // Package discovery provides discovery configuration.
    22  package discovery
    23  
    24  import (
    25  	"fmt"
    26  
    27  	etcdclient "github.com/m3db/m3/src/cluster/client/etcd"
    28  	"github.com/m3db/m3/src/dbnode/environment"
    29  )
    30  
    31  const (
    32  	defaultEnvironment                   = "default_env"
    33  	defaultZone                          = "embedded"
    34  	defaultM3DBService                   = "m3db"
    35  	defaultM3AggregatorService           = "m3aggregator"
    36  	defaultCacheDirectory                = "/var/lib/m3kv"
    37  	defaultSingleNodeClusterEndpoint     = "127.0.0.1:2379"
    38  	defaultSingleNodeClusterSeedEndpoint = "http://127.0.0.1:2380"
    39  )
    40  
    41  var validDiscoveryConfigTypes = []ConfigurationType{
    42  	ConfigType,
    43  	M3DBSingleNodeType,
    44  	M3DBClusterType,
    45  	M3AggregatorClusterType,
    46  }
    47  
    48  // ConfigurationType defines the type of discovery configuration.
    49  type ConfigurationType uint
    50  
    51  const (
    52  	// ConfigType defines a generic definition for service discovery via etcd.
    53  	ConfigType ConfigurationType = iota
    54  	// M3DBSingleNodeType defines configuration for a single M3DB node via etcd.
    55  	M3DBSingleNodeType
    56  	// M3DBClusterType defines M3DB discovery via etcd.
    57  	M3DBClusterType
    58  	// M3AggregatorClusterType defines M3DB discovery via etcd.
    59  	M3AggregatorClusterType
    60  )
    61  
    62  // MarshalYAML marshals a ConfigurationType.
    63  func (t *ConfigurationType) MarshalYAML() (interface{}, error) {
    64  	return t.String(), nil
    65  }
    66  
    67  // UnmarshalYAML unmarshals an ConfigurationType into a valid type from string.
    68  func (t *ConfigurationType) UnmarshalYAML(unmarshal func(interface{}) error) error {
    69  	var str string
    70  	if err := unmarshal(&str); err != nil {
    71  		return err
    72  	}
    73  
    74  	// If unspecified, use default mode.
    75  	if str == "" {
    76  		*t = ConfigType
    77  
    78  		return nil
    79  	}
    80  
    81  	for _, valid := range validDiscoveryConfigTypes {
    82  		if str == valid.String() {
    83  			*t = valid
    84  
    85  			return nil
    86  		}
    87  	}
    88  
    89  	return fmt.Errorf("invalid ConfigurationType '%s' valid types are: %s",
    90  		str, validDiscoveryConfigTypes)
    91  }
    92  
    93  // String returns the discovery configuration type as a string.
    94  func (t ConfigurationType) String() string {
    95  	switch t {
    96  	case ConfigType:
    97  		return "config"
    98  	case M3DBSingleNodeType:
    99  		return "m3db_single_node"
   100  	case M3DBClusterType:
   101  		return "m3db_cluster"
   102  	case M3AggregatorClusterType:
   103  		return "m3aggregator_cluster"
   104  	}
   105  	return "unknown"
   106  }
   107  
   108  // Configuration defines how services are to be discovered.
   109  type Configuration struct {
   110  	// Type defines the type of discovery configuration being used.
   111  	Type *ConfigurationType `yaml:"type"`
   112  
   113  	// M3DBCluster defines M3DB discovery via etcd.
   114  	M3DBCluster *M3DBClusterDiscoveryConfiguration `yaml:"m3dbCluster"`
   115  
   116  	// M3AggregatorCluster defines M3Aggregator discovery via etcd.
   117  	M3AggregatorCluster *M3AggregatorClusterDiscoveryConfiguration `yaml:"m3AggregatorCluster"`
   118  
   119  	// Config defines a generic definition for service discovery via etcd.
   120  	Config *environment.Configuration `yaml:"config"`
   121  }
   122  
   123  // M3DBClusterDiscoveryConfiguration defines discovery configuration for M3DB.
   124  type M3DBClusterDiscoveryConfiguration struct {
   125  	Env       string   `yaml:"env" validate:"nonzero"`
   126  	Zone      *string  `yaml:"zone"`
   127  	Endpoints []string `yaml:"endpoints"`
   128  }
   129  
   130  // M3AggregatorClusterDiscoveryConfiguration defines discovery configuration for M3Aggregator.
   131  type M3AggregatorClusterDiscoveryConfiguration struct {
   132  	Env       string   `yaml:"env"`
   133  	Zone      *string  `yaml:"zone"`
   134  	Endpoints []string `yaml:"endpoints"`
   135  }
   136  
   137  // EnvironmentConfig provides the environment configuration
   138  // based on the type of discovery configuration set.
   139  func (c *Configuration) EnvironmentConfig(
   140  	hostID string,
   141  ) (environment.Configuration, error) {
   142  	discoveryConfigType := ConfigType
   143  	if c.Type != nil {
   144  		discoveryConfigType = *c.Type
   145  	}
   146  
   147  	switch discoveryConfigType {
   148  	case ConfigType:
   149  		return *c.Config, nil
   150  	case M3DBSingleNodeType:
   151  		return c.m3dbSingleNodeEnvConfig(hostID), nil
   152  	case M3DBClusterType:
   153  		return c.envConfig(
   154  			discoveryConfigType,
   155  			defaultM3DBService,
   156  			c.M3DBCluster.Zone,
   157  			c.M3DBCluster.Env,
   158  			c.M3DBCluster.Endpoints,
   159  		)
   160  	case M3AggregatorClusterType:
   161  		return c.envConfig(
   162  			discoveryConfigType,
   163  			defaultM3AggregatorService,
   164  			c.M3AggregatorCluster.Zone,
   165  			c.M3AggregatorCluster.Env,
   166  			c.M3AggregatorCluster.Endpoints,
   167  		)
   168  	}
   169  
   170  	return environment.Configuration{}, fmt.Errorf("unrecognized discovery type: %d", c.Type)
   171  }
   172  
   173  func (c *Configuration) m3dbSingleNodeEnvConfig(
   174  	hostID string,
   175  ) environment.Configuration {
   176  	return environment.Configuration{
   177  		Services: []*environment.DynamicCluster{
   178  			{
   179  				Service: &etcdclient.Configuration{
   180  					Service:  defaultM3DBService,
   181  					CacheDir: defaultCacheDirectory,
   182  					Zone:     defaultZone,
   183  					Env:      defaultEnvironment,
   184  					ETCDClusters: []etcdclient.ClusterConfig{
   185  						{
   186  							Zone:      defaultZone,
   187  							Endpoints: []string{defaultSingleNodeClusterEndpoint},
   188  						},
   189  					},
   190  				},
   191  			},
   192  		},
   193  		SeedNodes: &environment.SeedNodesConfig{
   194  			InitialCluster: []environment.SeedNode{
   195  				{
   196  					HostID:   hostID,
   197  					Endpoint: defaultSingleNodeClusterSeedEndpoint,
   198  				},
   199  			},
   200  		},
   201  	}
   202  }
   203  
   204  func (c *Configuration) envConfig(
   205  	configType ConfigurationType,
   206  	service string,
   207  	zone *string,
   208  	env string,
   209  	endpoints []string,
   210  ) (environment.Configuration, error) {
   211  	if c == nil {
   212  		err := fmt.Errorf("discovery configuration required for type: %s",
   213  			configType.String())
   214  		return environment.Configuration{}, err
   215  	}
   216  
   217  	validZone := defaultZone
   218  	if zone != nil {
   219  		validZone = *zone
   220  	}
   221  
   222  	return environment.Configuration{
   223  		Services: []*environment.DynamicCluster{
   224  			{
   225  				Service: &etcdclient.Configuration{
   226  					Service:  service,
   227  					CacheDir: defaultCacheDirectory,
   228  					Zone:     validZone,
   229  					Env:      env,
   230  					ETCDClusters: []etcdclient.ClusterConfig{
   231  						{
   232  							Zone:      validZone,
   233  							Endpoints: endpoints,
   234  						},
   235  					},
   236  				},
   237  			},
   238  		},
   239  	}, nil
   240  }