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