github.com/m3db/m3@v1.5.0/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  // UnmarshalYAML unmarshals an ConfigurationType into a valid type from string.
    63  func (t *ConfigurationType) UnmarshalYAML(unmarshal func(interface{}) error) error {
    64  	var str string
    65  	if err := unmarshal(&str); err != nil {
    66  		return err
    67  	}
    68  
    69  	// If unspecified, use default mode.
    70  	if str == "" {
    71  		*t = ConfigType
    72  
    73  		return nil
    74  	}
    75  
    76  	for _, valid := range validDiscoveryConfigTypes {
    77  		if str == valid.String() {
    78  			*t = valid
    79  
    80  			return nil
    81  		}
    82  	}
    83  
    84  	return fmt.Errorf("invalid ConfigurationType '%s' valid types are: %s",
    85  		str, validDiscoveryConfigTypes)
    86  }
    87  
    88  // String returns the discovery configuration type as a string.
    89  func (t ConfigurationType) String() string {
    90  	switch t {
    91  	case ConfigType:
    92  		return "config"
    93  	case M3DBSingleNodeType:
    94  		return "m3db_single_node"
    95  	case M3DBClusterType:
    96  		return "m3db_cluster"
    97  	case M3AggregatorClusterType:
    98  		return "m3aggregator_cluster"
    99  	}
   100  	return "unknown"
   101  }
   102  
   103  // Configuration defines how services are to be discovered.
   104  type Configuration struct {
   105  	// Type defines the type of discovery configuration being used.
   106  	Type *ConfigurationType `yaml:"type"`
   107  
   108  	// M3DBCluster defines M3DB discovery via etcd.
   109  	M3DBCluster *M3DBClusterDiscoveryConfiguration `yaml:"m3dbCluster"`
   110  
   111  	// M3AggregatorCluster defines M3Aggregator discovery via etcd.
   112  	M3AggregatorCluster *M3AggregatorClusterDiscoveryConfiguration `yaml:"m3AggregatorCluster"`
   113  
   114  	// Config defines a generic definition for service discovery via etcd.
   115  	Config *environment.Configuration `yaml:"config"`
   116  }
   117  
   118  // M3DBClusterDiscoveryConfiguration defines discovery configuration for M3DB.
   119  type M3DBClusterDiscoveryConfiguration struct {
   120  	Env       string   `yaml:"env" validate:"nonzero"`
   121  	Zone      *string  `yaml:"zone"`
   122  	Endpoints []string `yaml:"endpoints"`
   123  }
   124  
   125  // M3AggregatorClusterDiscoveryConfiguration defines discovery configuration for M3Aggregator.
   126  type M3AggregatorClusterDiscoveryConfiguration struct {
   127  	Env       string   `yaml:"env"`
   128  	Zone      *string  `yaml:"zone"`
   129  	Endpoints []string `yaml:"endpoints"`
   130  }
   131  
   132  // EnvironmentConfig provides the environment configuration
   133  // based on the type of discovery configuration set.
   134  func (c *Configuration) EnvironmentConfig(
   135  	hostID string,
   136  ) (environment.Configuration, error) {
   137  	discoveryConfigType := ConfigType
   138  	if c.Type != nil {
   139  		discoveryConfigType = *c.Type
   140  	}
   141  
   142  	switch discoveryConfigType {
   143  	case ConfigType:
   144  		return *c.Config, nil
   145  	case M3DBSingleNodeType:
   146  		return c.m3dbSingleNodeEnvConfig(hostID), nil
   147  	case M3DBClusterType:
   148  		return c.envConfig(
   149  			discoveryConfigType,
   150  			defaultM3DBService,
   151  			c.M3DBCluster.Zone,
   152  			c.M3DBCluster.Env,
   153  			c.M3DBCluster.Endpoints,
   154  		)
   155  	case M3AggregatorClusterType:
   156  		return c.envConfig(
   157  			discoveryConfigType,
   158  			defaultM3AggregatorService,
   159  			c.M3AggregatorCluster.Zone,
   160  			c.M3AggregatorCluster.Env,
   161  			c.M3AggregatorCluster.Endpoints,
   162  		)
   163  	}
   164  
   165  	return environment.Configuration{}, fmt.Errorf("unrecognized discovery type: %d", c.Type)
   166  }
   167  
   168  func (c *Configuration) m3dbSingleNodeEnvConfig(
   169  	hostID string,
   170  ) environment.Configuration {
   171  	return environment.Configuration{
   172  		Services: []*environment.DynamicCluster{
   173  			{
   174  				Service: &etcdclient.Configuration{
   175  					Service:  defaultM3DBService,
   176  					CacheDir: defaultCacheDirectory,
   177  					Zone:     defaultZone,
   178  					Env:      defaultEnvironment,
   179  					ETCDClusters: []etcdclient.ClusterConfig{
   180  						{
   181  							Zone:      defaultZone,
   182  							Endpoints: []string{defaultSingleNodeClusterEndpoint},
   183  						},
   184  					},
   185  				},
   186  			},
   187  		},
   188  		SeedNodes: &environment.SeedNodesConfig{
   189  			InitialCluster: []environment.SeedNode{
   190  				{
   191  					HostID:   hostID,
   192  					Endpoint: defaultSingleNodeClusterSeedEndpoint,
   193  				},
   194  			},
   195  		},
   196  	}
   197  }
   198  
   199  func (c *Configuration) envConfig(
   200  	configType ConfigurationType,
   201  	service string,
   202  	zone *string,
   203  	env string,
   204  	endpoints []string,
   205  ) (environment.Configuration, error) {
   206  	if c == nil {
   207  		err := fmt.Errorf("discovery configuration required for type: %s",
   208  			configType.String())
   209  		return environment.Configuration{}, err
   210  	}
   211  
   212  	validZone := defaultZone
   213  	if zone != nil {
   214  		validZone = *zone
   215  	}
   216  
   217  	return environment.Configuration{
   218  		Services: []*environment.DynamicCluster{
   219  			{
   220  				Service: &etcdclient.Configuration{
   221  					Service:  service,
   222  					CacheDir: defaultCacheDirectory,
   223  					Zone:     validZone,
   224  					Env:      env,
   225  					ETCDClusters: []etcdclient.ClusterConfig{
   226  						{
   227  							Zone:      validZone,
   228  							Endpoints: endpoints,
   229  						},
   230  					},
   231  				},
   232  			},
   233  		},
   234  	}, nil
   235  }