github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/localconfig/config.go (about)

     1  // Copyright IBM Corp. All Rights Reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package localconfig
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"path/filepath"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/Shopify/sarama"
    15  	bccsp "github.com/hyperledger/fabric/bccsp/factory"
    16  	"github.com/hyperledger/fabric/common/flogging"
    17  	"github.com/hyperledger/fabric/common/viperutil"
    18  	coreconfig "github.com/hyperledger/fabric/core/config"
    19  	"github.com/spf13/viper"
    20  )
    21  
    22  // Prefix for environment variables.
    23  const Prefix = "ORDERER"
    24  
    25  var logger = flogging.MustGetLogger("localconfig")
    26  
    27  // TopLevel directly corresponds to the orderer config YAML.
    28  // Note, for non 1-1 mappings, you may append
    29  // something like `mapstructure:"weirdFoRMat"` to
    30  // modify the default mapping, see the "Unmarshal"
    31  // section of https://github.com/spf13/viper for more info.
    32  type TopLevel struct {
    33  	General    General
    34  	FileLedger FileLedger
    35  	Kafka      Kafka
    36  	Debug      Debug
    37  	Consensus  interface{}
    38  	Operations Operations
    39  	Metrics    Metrics
    40  }
    41  
    42  // General contains config which should be common among all orderer types.
    43  type General struct {
    44  	ListenAddress     string
    45  	ListenPort        uint16
    46  	TLS               TLS
    47  	Cluster           Cluster
    48  	Keepalive         Keepalive
    49  	ConnectionTimeout time.Duration
    50  	GenesisMethod     string // For compatibility only, will be replaced by BootstrapMethod
    51  	GenesisFile       string // For compatibility only, will be replaced by BootstrapFile
    52  	BootstrapMethod   string
    53  	BootstrapFile     string
    54  	Profile           Profile
    55  	LocalMSPDir       string
    56  	LocalMSPID        string
    57  	BCCSP             *bccsp.FactoryOpts
    58  	Authentication    Authentication
    59  }
    60  
    61  type Cluster struct {
    62  	ListenAddress                        string
    63  	ListenPort                           uint16
    64  	ServerCertificate                    string
    65  	ServerPrivateKey                     string
    66  	ClientCertificate                    string
    67  	ClientPrivateKey                     string
    68  	RootCAs                              []string
    69  	DialTimeout                          time.Duration
    70  	RPCTimeout                           time.Duration
    71  	ReplicationBufferSize                int
    72  	ReplicationPullTimeout               time.Duration
    73  	ReplicationRetryTimeout              time.Duration
    74  	ReplicationBackgroundRefreshInterval time.Duration
    75  	ReplicationMaxRetries                int
    76  	SendBufferSize                       int
    77  	CertExpirationWarningThreshold       time.Duration
    78  	TLSHandshakeTimeShift                time.Duration
    79  }
    80  
    81  // Keepalive contains configuration for gRPC servers.
    82  type Keepalive struct {
    83  	ServerMinInterval time.Duration
    84  	ServerInterval    time.Duration
    85  	ServerTimeout     time.Duration
    86  }
    87  
    88  // TLS contains configuration for TLS connections.
    89  type TLS struct {
    90  	Enabled            bool
    91  	PrivateKey         string
    92  	Certificate        string
    93  	RootCAs            []string
    94  	ClientAuthRequired bool
    95  	ClientRootCAs      []string
    96  }
    97  
    98  // SASLPlain contains configuration for SASL/PLAIN authentication
    99  type SASLPlain struct {
   100  	Enabled  bool
   101  	User     string
   102  	Password string
   103  }
   104  
   105  // Authentication contains configuration parameters related to authenticating
   106  // client messages.
   107  type Authentication struct {
   108  	TimeWindow         time.Duration
   109  	NoExpirationChecks bool
   110  }
   111  
   112  // Profile contains configuration for Go pprof profiling.
   113  type Profile struct {
   114  	Enabled bool
   115  	Address string
   116  }
   117  
   118  // FileLedger contains configuration for the file-based ledger.
   119  type FileLedger struct {
   120  	Location string
   121  	Prefix   string
   122  }
   123  
   124  // Kafka contains configuration for the Kafka-based orderer.
   125  type Kafka struct {
   126  	Retry     Retry
   127  	Verbose   bool
   128  	Version   sarama.KafkaVersion // TODO Move this to global config
   129  	TLS       TLS
   130  	SASLPlain SASLPlain
   131  	Topic     Topic
   132  }
   133  
   134  // Retry contains configuration related to retries and timeouts when the
   135  // connection to the Kafka cluster cannot be established, or when Metadata
   136  // requests needs to be repeated (because the cluster is in the middle of a
   137  // leader election).
   138  type Retry struct {
   139  	ShortInterval   time.Duration
   140  	ShortTotal      time.Duration
   141  	LongInterval    time.Duration
   142  	LongTotal       time.Duration
   143  	NetworkTimeouts NetworkTimeouts
   144  	Metadata        Metadata
   145  	Producer        Producer
   146  	Consumer        Consumer
   147  }
   148  
   149  // NetworkTimeouts contains the socket timeouts for network requests to the
   150  // Kafka cluster.
   151  type NetworkTimeouts struct {
   152  	DialTimeout  time.Duration
   153  	ReadTimeout  time.Duration
   154  	WriteTimeout time.Duration
   155  }
   156  
   157  // Metadata contains configuration for the metadata requests to the Kafka
   158  // cluster.
   159  type Metadata struct {
   160  	RetryMax     int
   161  	RetryBackoff time.Duration
   162  }
   163  
   164  // Producer contains configuration for the producer's retries when failing to
   165  // post a message to a Kafka partition.
   166  type Producer struct {
   167  	RetryMax     int
   168  	RetryBackoff time.Duration
   169  }
   170  
   171  // Consumer contains configuration for the consumer's retries when failing to
   172  // read from a Kafa partition.
   173  type Consumer struct {
   174  	RetryBackoff time.Duration
   175  }
   176  
   177  // Topic contains the settings to use when creating Kafka topics
   178  type Topic struct {
   179  	ReplicationFactor int16
   180  }
   181  
   182  // Debug contains configuration for the orderer's debug parameters.
   183  type Debug struct {
   184  	BroadcastTraceDir string
   185  	DeliverTraceDir   string
   186  }
   187  
   188  // Operations configures the operations endpont for the orderer.
   189  type Operations struct {
   190  	ListenAddress string
   191  	TLS           TLS
   192  }
   193  
   194  // Operations confiures the metrics provider for the orderer.
   195  type Metrics struct {
   196  	Provider string
   197  	Statsd   Statsd
   198  }
   199  
   200  // Statsd provides the configuration required to emit statsd metrics from the orderer.
   201  type Statsd struct {
   202  	Network       string
   203  	Address       string
   204  	WriteInterval time.Duration
   205  	Prefix        string
   206  }
   207  
   208  // Defaults carries the default orderer configuration values.
   209  var Defaults = TopLevel{
   210  	General: General{
   211  		ListenAddress:   "127.0.0.1",
   212  		ListenPort:      7050,
   213  		BootstrapMethod: "file",
   214  		BootstrapFile:   "genesisblock",
   215  		Profile: Profile{
   216  			Enabled: false,
   217  			Address: "0.0.0.0:6060",
   218  		},
   219  		Cluster: Cluster{
   220  			ReplicationMaxRetries:                12,
   221  			RPCTimeout:                           time.Second * 7,
   222  			DialTimeout:                          time.Second * 5,
   223  			ReplicationBufferSize:                20971520,
   224  			SendBufferSize:                       10,
   225  			ReplicationBackgroundRefreshInterval: time.Minute * 5,
   226  			ReplicationRetryTimeout:              time.Second * 5,
   227  			ReplicationPullTimeout:               time.Second * 5,
   228  			CertExpirationWarningThreshold:       time.Hour * 24 * 7,
   229  		},
   230  		LocalMSPDir: "msp",
   231  		LocalMSPID:  "SampleOrg",
   232  		BCCSP:       bccsp.GetDefaultOpts(),
   233  		Authentication: Authentication{
   234  			TimeWindow: time.Duration(15 * time.Minute),
   235  		},
   236  	},
   237  	FileLedger: FileLedger{
   238  		Location: "/var/hyperledger/production/orderer",
   239  		Prefix:   "hyperledger-fabric-ordererledger",
   240  	},
   241  	Kafka: Kafka{
   242  		Retry: Retry{
   243  			ShortInterval: 1 * time.Minute,
   244  			ShortTotal:    10 * time.Minute,
   245  			LongInterval:  10 * time.Minute,
   246  			LongTotal:     12 * time.Hour,
   247  			NetworkTimeouts: NetworkTimeouts{
   248  				DialTimeout:  30 * time.Second,
   249  				ReadTimeout:  30 * time.Second,
   250  				WriteTimeout: 30 * time.Second,
   251  			},
   252  			Metadata: Metadata{
   253  				RetryBackoff: 250 * time.Millisecond,
   254  				RetryMax:     3,
   255  			},
   256  			Producer: Producer{
   257  				RetryBackoff: 100 * time.Millisecond,
   258  				RetryMax:     3,
   259  			},
   260  			Consumer: Consumer{
   261  				RetryBackoff: 2 * time.Second,
   262  			},
   263  		},
   264  		Verbose: false,
   265  		Version: sarama.V0_10_2_0,
   266  		TLS: TLS{
   267  			Enabled: false,
   268  		},
   269  		Topic: Topic{
   270  			ReplicationFactor: 3,
   271  		},
   272  	},
   273  	Debug: Debug{
   274  		BroadcastTraceDir: "",
   275  		DeliverTraceDir:   "",
   276  	},
   277  	Operations: Operations{
   278  		ListenAddress: "127.0.0.1:0",
   279  	},
   280  	Metrics: Metrics{
   281  		Provider: "disabled",
   282  	},
   283  }
   284  
   285  // Load parses the orderer YAML file and environment, producing
   286  // a struct suitable for config use, returning error on failure.
   287  func Load() (*TopLevel, error) {
   288  	return cache.load()
   289  }
   290  
   291  // configCache stores marshalled bytes of config structures that produced from
   292  // EnhancedExactUnmarshal. Cache key is the path of the configuration file that was used.
   293  type configCache struct {
   294  	mutex sync.Mutex
   295  	cache map[string][]byte
   296  }
   297  
   298  var cache = &configCache{}
   299  
   300  // Load will load the configuration and cache it on the first call; subsequent
   301  // calls will return a clone of the configuration that was previously loaded.
   302  func (c *configCache) load() (*TopLevel, error) {
   303  	var uconf TopLevel
   304  
   305  	config := viper.New()
   306  	coreconfig.InitViper(config, "orderer")
   307  	config.SetEnvPrefix(Prefix)
   308  	config.AutomaticEnv()
   309  	replacer := strings.NewReplacer(".", "_")
   310  	config.SetEnvKeyReplacer(replacer)
   311  
   312  	if err := config.ReadInConfig(); err != nil {
   313  		return nil, fmt.Errorf("Error reading configuration: %s", err)
   314  	}
   315  
   316  	c.mutex.Lock()
   317  	defer c.mutex.Unlock()
   318  	serializedConf, ok := c.cache[config.ConfigFileUsed()]
   319  	if !ok {
   320  		err := viperutil.EnhancedExactUnmarshal(config, &uconf)
   321  		if err != nil {
   322  			return nil, fmt.Errorf("Error unmarshaling config into struct: %s", err)
   323  		}
   324  
   325  		serializedConf, err = json.Marshal(uconf)
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  
   330  		if c.cache == nil {
   331  			c.cache = map[string][]byte{}
   332  		}
   333  		c.cache[config.ConfigFileUsed()] = serializedConf
   334  	}
   335  
   336  	err := json.Unmarshal(serializedConf, &uconf)
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  	uconf.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
   341  
   342  	return &uconf, nil
   343  }
   344  
   345  func (c *TopLevel) completeInitialization(configDir string) {
   346  	defer func() {
   347  		// Translate any paths for cluster TLS configuration if applicable
   348  		if c.General.Cluster.ClientPrivateKey != "" {
   349  			coreconfig.TranslatePathInPlace(configDir, &c.General.Cluster.ClientPrivateKey)
   350  		}
   351  		if c.General.Cluster.ClientCertificate != "" {
   352  			coreconfig.TranslatePathInPlace(configDir, &c.General.Cluster.ClientCertificate)
   353  		}
   354  		c.General.Cluster.RootCAs = translateCAs(configDir, c.General.Cluster.RootCAs)
   355  		// Translate any paths for general TLS configuration
   356  		c.General.TLS.RootCAs = translateCAs(configDir, c.General.TLS.RootCAs)
   357  		c.General.TLS.ClientRootCAs = translateCAs(configDir, c.General.TLS.ClientRootCAs)
   358  		coreconfig.TranslatePathInPlace(configDir, &c.General.TLS.PrivateKey)
   359  		coreconfig.TranslatePathInPlace(configDir, &c.General.TLS.Certificate)
   360  		coreconfig.TranslatePathInPlace(configDir, &c.General.BootstrapFile)
   361  		coreconfig.TranslatePathInPlace(configDir, &c.General.LocalMSPDir)
   362  		// Translate file ledger location
   363  		coreconfig.TranslatePathInPlace(configDir, &c.FileLedger.Location)
   364  	}()
   365  
   366  	for {
   367  		switch {
   368  		case c.General.ListenAddress == "":
   369  			logger.Infof("General.ListenAddress unset, setting to %s", Defaults.General.ListenAddress)
   370  			c.General.ListenAddress = Defaults.General.ListenAddress
   371  		case c.General.ListenPort == 0:
   372  			logger.Infof("General.ListenPort unset, setting to %v", Defaults.General.ListenPort)
   373  			c.General.ListenPort = Defaults.General.ListenPort
   374  		case c.General.BootstrapMethod == "":
   375  			if c.General.GenesisMethod != "" {
   376  				// This is to keep the compatibility with old config file that uses genesismethod
   377  				logger.Warn("General.GenesisMethod should be replaced by General.BootstrapMethod")
   378  				c.General.BootstrapMethod = c.General.GenesisMethod
   379  			} else {
   380  				c.General.BootstrapMethod = Defaults.General.BootstrapMethod
   381  			}
   382  		case c.General.BootstrapFile == "":
   383  			if c.General.GenesisFile != "" {
   384  				// This is to keep the compatibility with old config file that uses genesisfile
   385  				logger.Warn("General.GenesisFile should be replaced by General.BootstrapFile")
   386  				c.General.BootstrapFile = c.General.GenesisFile
   387  			} else {
   388  				c.General.BootstrapFile = Defaults.General.BootstrapFile
   389  			}
   390  		case c.General.Cluster.RPCTimeout == 0:
   391  			c.General.Cluster.RPCTimeout = Defaults.General.Cluster.RPCTimeout
   392  		case c.General.Cluster.DialTimeout == 0:
   393  			c.General.Cluster.DialTimeout = Defaults.General.Cluster.DialTimeout
   394  		case c.General.Cluster.ReplicationMaxRetries == 0:
   395  			c.General.Cluster.ReplicationMaxRetries = Defaults.General.Cluster.ReplicationMaxRetries
   396  		case c.General.Cluster.SendBufferSize == 0:
   397  			c.General.Cluster.SendBufferSize = Defaults.General.Cluster.SendBufferSize
   398  		case c.General.Cluster.ReplicationBufferSize == 0:
   399  			c.General.Cluster.ReplicationBufferSize = Defaults.General.Cluster.ReplicationBufferSize
   400  		case c.General.Cluster.ReplicationPullTimeout == 0:
   401  			c.General.Cluster.ReplicationPullTimeout = Defaults.General.Cluster.ReplicationPullTimeout
   402  		case c.General.Cluster.ReplicationRetryTimeout == 0:
   403  			c.General.Cluster.ReplicationRetryTimeout = Defaults.General.Cluster.ReplicationRetryTimeout
   404  		case c.General.Cluster.ReplicationBackgroundRefreshInterval == 0:
   405  			c.General.Cluster.ReplicationBackgroundRefreshInterval = Defaults.General.Cluster.ReplicationBackgroundRefreshInterval
   406  		case c.General.Cluster.CertExpirationWarningThreshold == 0:
   407  			c.General.Cluster.CertExpirationWarningThreshold = Defaults.General.Cluster.CertExpirationWarningThreshold
   408  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.Certificate == "":
   409  			logger.Panicf("General.Kafka.TLS.Certificate must be set if General.Kafka.TLS.Enabled is set to true.")
   410  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.PrivateKey == "":
   411  			logger.Panicf("General.Kafka.TLS.PrivateKey must be set if General.Kafka.TLS.Enabled is set to true.")
   412  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.RootCAs == nil:
   413  			logger.Panicf("General.Kafka.TLS.CertificatePool must be set if General.Kafka.TLS.Enabled is set to true.")
   414  
   415  		case c.Kafka.SASLPlain.Enabled && c.Kafka.SASLPlain.User == "":
   416  			logger.Panic("General.Kafka.SASLPlain.User must be set if General.Kafka.SASLPlain.Enabled is set to true.")
   417  		case c.Kafka.SASLPlain.Enabled && c.Kafka.SASLPlain.Password == "":
   418  			logger.Panic("General.Kafka.SASLPlain.Password must be set if General.Kafka.SASLPlain.Enabled is set to true.")
   419  
   420  		case c.General.Profile.Enabled && c.General.Profile.Address == "":
   421  			logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", Defaults.General.Profile.Address)
   422  			c.General.Profile.Address = Defaults.General.Profile.Address
   423  
   424  		case c.General.LocalMSPDir == "":
   425  			logger.Infof("General.LocalMSPDir unset, setting to %s", Defaults.General.LocalMSPDir)
   426  			c.General.LocalMSPDir = Defaults.General.LocalMSPDir
   427  		case c.General.LocalMSPID == "":
   428  			logger.Infof("General.LocalMSPID unset, setting to %s", Defaults.General.LocalMSPID)
   429  			c.General.LocalMSPID = Defaults.General.LocalMSPID
   430  
   431  		case c.General.Authentication.TimeWindow == 0:
   432  			logger.Infof("General.Authentication.TimeWindow unset, setting to %s", Defaults.General.Authentication.TimeWindow)
   433  			c.General.Authentication.TimeWindow = Defaults.General.Authentication.TimeWindow
   434  
   435  		case c.FileLedger.Prefix == "":
   436  			logger.Infof("FileLedger.Prefix unset, setting to %s", Defaults.FileLedger.Prefix)
   437  			c.FileLedger.Prefix = Defaults.FileLedger.Prefix
   438  
   439  		case c.Kafka.Retry.ShortInterval == 0:
   440  			logger.Infof("Kafka.Retry.ShortInterval unset, setting to %v", Defaults.Kafka.Retry.ShortInterval)
   441  			c.Kafka.Retry.ShortInterval = Defaults.Kafka.Retry.ShortInterval
   442  		case c.Kafka.Retry.ShortTotal == 0:
   443  			logger.Infof("Kafka.Retry.ShortTotal unset, setting to %v", Defaults.Kafka.Retry.ShortTotal)
   444  			c.Kafka.Retry.ShortTotal = Defaults.Kafka.Retry.ShortTotal
   445  		case c.Kafka.Retry.LongInterval == 0:
   446  			logger.Infof("Kafka.Retry.LongInterval unset, setting to %v", Defaults.Kafka.Retry.LongInterval)
   447  			c.Kafka.Retry.LongInterval = Defaults.Kafka.Retry.LongInterval
   448  		case c.Kafka.Retry.LongTotal == 0:
   449  			logger.Infof("Kafka.Retry.LongTotal unset, setting to %v", Defaults.Kafka.Retry.LongTotal)
   450  			c.Kafka.Retry.LongTotal = Defaults.Kafka.Retry.LongTotal
   451  
   452  		case c.Kafka.Retry.NetworkTimeouts.DialTimeout == 0:
   453  			logger.Infof("Kafka.Retry.NetworkTimeouts.DialTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.DialTimeout)
   454  			c.Kafka.Retry.NetworkTimeouts.DialTimeout = Defaults.Kafka.Retry.NetworkTimeouts.DialTimeout
   455  		case c.Kafka.Retry.NetworkTimeouts.ReadTimeout == 0:
   456  			logger.Infof("Kafka.Retry.NetworkTimeouts.ReadTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout)
   457  			c.Kafka.Retry.NetworkTimeouts.ReadTimeout = Defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout
   458  		case c.Kafka.Retry.NetworkTimeouts.WriteTimeout == 0:
   459  			logger.Infof("Kafka.Retry.NetworkTimeouts.WriteTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout)
   460  			c.Kafka.Retry.NetworkTimeouts.WriteTimeout = Defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout
   461  
   462  		case c.Kafka.Retry.Metadata.RetryBackoff == 0:
   463  			logger.Infof("Kafka.Retry.Metadata.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Metadata.RetryBackoff)
   464  			c.Kafka.Retry.Metadata.RetryBackoff = Defaults.Kafka.Retry.Metadata.RetryBackoff
   465  		case c.Kafka.Retry.Metadata.RetryMax == 0:
   466  			logger.Infof("Kafka.Retry.Metadata.RetryMax unset, setting to %v", Defaults.Kafka.Retry.Metadata.RetryMax)
   467  			c.Kafka.Retry.Metadata.RetryMax = Defaults.Kafka.Retry.Metadata.RetryMax
   468  
   469  		case c.Kafka.Retry.Producer.RetryBackoff == 0:
   470  			logger.Infof("Kafka.Retry.Producer.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Producer.RetryBackoff)
   471  			c.Kafka.Retry.Producer.RetryBackoff = Defaults.Kafka.Retry.Producer.RetryBackoff
   472  		case c.Kafka.Retry.Producer.RetryMax == 0:
   473  			logger.Infof("Kafka.Retry.Producer.RetryMax unset, setting to %v", Defaults.Kafka.Retry.Producer.RetryMax)
   474  			c.Kafka.Retry.Producer.RetryMax = Defaults.Kafka.Retry.Producer.RetryMax
   475  
   476  		case c.Kafka.Retry.Consumer.RetryBackoff == 0:
   477  			logger.Infof("Kafka.Retry.Consumer.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Consumer.RetryBackoff)
   478  			c.Kafka.Retry.Consumer.RetryBackoff = Defaults.Kafka.Retry.Consumer.RetryBackoff
   479  
   480  		case c.Kafka.Version == sarama.KafkaVersion{}:
   481  			logger.Infof("Kafka.Version unset, setting to %v", Defaults.Kafka.Version)
   482  			c.Kafka.Version = Defaults.Kafka.Version
   483  
   484  		default:
   485  			return
   486  		}
   487  	}
   488  }
   489  
   490  func translateCAs(configDir string, certificateAuthorities []string) []string {
   491  	var results []string
   492  	for _, ca := range certificateAuthorities {
   493  		result := coreconfig.TranslatePath(configDir, ca)
   494  		results = append(results, result)
   495  	}
   496  	return results
   497  }