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