github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/orderer/localconfig/config.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package config
    18  
    19  import (
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/inklabsfoundation/inkchain/common/flogging"
    24  	"github.com/inklabsfoundation/inkchain/common/viperutil"
    25  	"github.com/inklabsfoundation/inkchain/core/wallet"
    26  
    27  	"github.com/Shopify/sarama"
    28  	"github.com/op/go-logging"
    29  	"github.com/spf13/viper"
    30  
    31  	cf "github.com/inklabsfoundation/inkchain/core/config"
    32  
    33  	"path/filepath"
    34  
    35  	bccsp "github.com/inklabsfoundation/inkchain/bccsp/factory"
    36  )
    37  
    38  const (
    39  	pkgLogID = "orderer/localconfig"
    40  
    41  	// Prefix identifies the prefix for the orderer-related ENV vars.
    42  	Prefix = "ORDERER"
    43  )
    44  
    45  var (
    46  	logger *logging.Logger
    47  
    48  	configName string
    49  )
    50  
    51  func init() {
    52  	logger = flogging.MustGetLogger(pkgLogID)
    53  	flogging.SetModuleLevel(pkgLogID, "error")
    54  
    55  	configName = strings.ToLower(Prefix)
    56  }
    57  
    58  // TopLevel directly corresponds to the orderer config YAML.
    59  // Note, for non 1-1 mappings, you may append
    60  // something like `mapstructure:"weirdFoRMat"` to
    61  // modify the default mapping, see the "Unmarshal"
    62  // section of https://github.com/spf13/viper for more info
    63  type TopLevel struct {
    64  	General    General
    65  	FileLedger FileLedger
    66  	RAMLedger  RAMLedger
    67  	Kafka      Kafka
    68  }
    69  
    70  // General contains config which should be common among all orderer types.
    71  type General struct {
    72  	LedgerType     string
    73  	ListenAddress  string
    74  	ListenPort     uint16
    75  	TLS            TLS
    76  	GenesisMethod  string
    77  	GenesisProfile string
    78  	GenesisFile    string
    79  	Profile        Profile
    80  	LogLevel       string
    81  	LocalMSPDir    string
    82  	LocalMSPID     string
    83  	BCCSP          *bccsp.FactoryOpts
    84  	FeeAddress     string
    85  	BlockVersion   uint64
    86  }
    87  
    88  // TLS contains config for TLS connections.
    89  type TLS struct {
    90  	Enabled           bool
    91  	PrivateKey        string
    92  	Certificate       string
    93  	RootCAs           []string
    94  	ClientAuthEnabled bool
    95  	ClientRootCAs     []string
    96  }
    97  
    98  // Profile contains configuration for Go pprof profiling.
    99  type Profile struct {
   100  	Enabled bool
   101  	Address string
   102  }
   103  
   104  // FileLedger contains configuration for the file-based ledger.
   105  type FileLedger struct {
   106  	Location string
   107  	Prefix   string
   108  }
   109  
   110  // RAMLedger contains configuration for the RAM ledger.
   111  type RAMLedger struct {
   112  	HistorySize uint
   113  }
   114  
   115  // Kafka contains configuration for the Kafka-based orderer.
   116  type Kafka struct {
   117  	Retry   Retry
   118  	Verbose bool
   119  	Version sarama.KafkaVersion // TODO Move this to global config
   120  	TLS     TLS
   121  }
   122  
   123  // Retry contains configuration related to retries and timeouts when the
   124  // connection to the Kafka cluster cannot be established, or when Metadata
   125  // requests needs to be repeated (because the cluster is in the middle of a
   126  // leader election).
   127  type Retry struct {
   128  	ShortInterval   time.Duration
   129  	ShortTotal      time.Duration
   130  	LongInterval    time.Duration
   131  	LongTotal       time.Duration
   132  	NetworkTimeouts NetworkTimeouts
   133  	Metadata        Metadata
   134  	Producer        Producer
   135  	Consumer        Consumer
   136  }
   137  
   138  // NetworkTimeouts contains the socket timeouts for network requests to the
   139  // Kafka cluster.
   140  type NetworkTimeouts struct {
   141  	DialTimeout  time.Duration
   142  	ReadTimeout  time.Duration
   143  	WriteTimeout time.Duration
   144  }
   145  
   146  // Metadata contains configuration for the metadata requests to the Kafka
   147  // cluster.
   148  type Metadata struct {
   149  	RetryMax     int
   150  	RetryBackoff time.Duration
   151  }
   152  
   153  // Producer contains configuration for the producer's retries when failing to
   154  // post a message to a Kafka partition.
   155  type Producer struct {
   156  	RetryMax     int
   157  	RetryBackoff time.Duration
   158  }
   159  
   160  // Consumer contains configuration for the consumer's retries when failing to
   161  // read from a Kafa partition.
   162  type Consumer struct {
   163  	RetryBackoff time.Duration
   164  }
   165  
   166  var defaults = TopLevel{
   167  	General: General{
   168  		LedgerType:     "file",
   169  		ListenAddress:  "127.0.0.1",
   170  		ListenPort:     7050,
   171  		GenesisMethod:  "provisional",
   172  		GenesisProfile: "SampleSingleMSPSolo",
   173  		GenesisFile:    "genesisblock",
   174  		Profile: Profile{
   175  			Enabled: false,
   176  			Address: "0.0.0.0:6060",
   177  		},
   178  		LogLevel:     "INFO",
   179  		LocalMSPDir:  "msp",
   180  		LocalMSPID:   "DEFAULT",
   181  		BCCSP:        bccsp.GetDefaultOpts(),
   182  		FeeAddress:   wallet.ADDRESS_PREFIX + "411b6f8f24F28CaAFE514c16E11800167f8EBd89",
   183  		BlockVersion: 1,
   184  	},
   185  	RAMLedger: RAMLedger{
   186  		HistorySize: 10000,
   187  	},
   188  	FileLedger: FileLedger{
   189  		Location: "/var/inkchain/production/orderer",
   190  		Prefix:   "inkchain-inkchain-ordererledger",
   191  	},
   192  	Kafka: Kafka{
   193  		Retry: Retry{
   194  			ShortInterval: 1 * time.Minute,
   195  			ShortTotal:    10 * time.Minute,
   196  			LongInterval:  10 * time.Minute,
   197  			LongTotal:     12 * time.Hour,
   198  			NetworkTimeouts: NetworkTimeouts{
   199  				DialTimeout:  30 * time.Second,
   200  				ReadTimeout:  30 * time.Second,
   201  				WriteTimeout: 30 * time.Second,
   202  			},
   203  			Metadata: Metadata{
   204  				RetryBackoff: 250 * time.Millisecond,
   205  				RetryMax:     3,
   206  			},
   207  			Producer: Producer{
   208  				RetryBackoff: 100 * time.Millisecond,
   209  				RetryMax:     3,
   210  			},
   211  			Consumer: Consumer{
   212  				RetryBackoff: 2 * time.Second,
   213  			},
   214  		},
   215  		Verbose: false,
   216  		Version: sarama.V0_9_0_1,
   217  		TLS: TLS{
   218  			Enabled: false,
   219  		},
   220  	},
   221  }
   222  
   223  // Load parses the orderer.yaml file and environment, producing a struct suitable for config use
   224  func Load() *TopLevel {
   225  	config := viper.New()
   226  	cf.InitViper(config, configName)
   227  
   228  	// for environment variables
   229  	config.SetEnvPrefix(Prefix)
   230  	config.AutomaticEnv()
   231  	replacer := strings.NewReplacer(".", "_")
   232  	config.SetEnvKeyReplacer(replacer)
   233  
   234  	err := config.ReadInConfig()
   235  	if err != nil {
   236  		logger.Panic("Error reading configuration:", err)
   237  	}
   238  
   239  	var uconf TopLevel
   240  	err = viperutil.EnhancedExactUnmarshal(config, &uconf)
   241  	if err != nil {
   242  		logger.Panic("Error unmarshaling config into struct:", err)
   243  	}
   244  
   245  	uconf.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
   246  
   247  	return &uconf
   248  }
   249  
   250  func (c *TopLevel) completeInitialization(configDir string) {
   251  	defer func() {
   252  		// Translate any paths
   253  		c.General.TLS.RootCAs = translateCAs(configDir, c.General.TLS.RootCAs)
   254  		c.General.TLS.ClientRootCAs = translateCAs(configDir, c.General.TLS.ClientRootCAs)
   255  		cf.TranslatePathInPlace(configDir, &c.General.TLS.PrivateKey)
   256  		cf.TranslatePathInPlace(configDir, &c.General.TLS.Certificate)
   257  		cf.TranslatePathInPlace(configDir, &c.General.GenesisFile)
   258  		cf.TranslatePathInPlace(configDir, &c.General.LocalMSPDir)
   259  	}()
   260  
   261  	for {
   262  		switch {
   263  		case c.General.LedgerType == "":
   264  			logger.Infof("General.LedgerType unset, setting to %s", defaults.General.LedgerType)
   265  			c.General.LedgerType = defaults.General.LedgerType
   266  
   267  		case c.General.ListenAddress == "":
   268  			logger.Infof("General.ListenAddress unset, setting to %s", defaults.General.ListenAddress)
   269  			c.General.ListenAddress = defaults.General.ListenAddress
   270  		case c.General.ListenPort == 0:
   271  			logger.Infof("General.ListenPort unset, setting to %s", defaults.General.ListenPort)
   272  			c.General.ListenPort = defaults.General.ListenPort
   273  
   274  		case c.General.LogLevel == "":
   275  			logger.Infof("General.LogLevel unset, setting to %s", defaults.General.LogLevel)
   276  			c.General.LogLevel = defaults.General.LogLevel
   277  
   278  		case c.General.GenesisMethod == "":
   279  			c.General.GenesisMethod = defaults.General.GenesisMethod
   280  		case c.General.GenesisFile == "":
   281  			c.General.GenesisFile = defaults.General.GenesisFile
   282  		case c.General.GenesisProfile == "":
   283  			c.General.GenesisProfile = defaults.General.GenesisProfile
   284  
   285  		case c.General.FeeAddress == "":
   286  			c.General.FeeAddress = "ACAdB8391bc793495C203D58d57776DcD5CA83AD"
   287  		case c.General.BlockVersion == 0:
   288  			c.General.BlockVersion = 1
   289  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.Certificate == "":
   290  			logger.Panicf("General.Kafka.TLS.Certificate must be set if General.Kafka.TLS.Enabled is set to true.")
   291  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.PrivateKey == "":
   292  			logger.Panicf("General.Kafka.TLS.PrivateKey must be set if General.Kafka.TLS.Enabled is set to true.")
   293  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.RootCAs == nil:
   294  			logger.Panicf("General.Kafka.TLS.CertificatePool must be set if General.Kafka.TLS.Enabled is set to true.")
   295  
   296  		case c.General.Profile.Enabled && c.General.Profile.Address == "":
   297  			logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", defaults.General.Profile.Address)
   298  			c.General.Profile.Address = defaults.General.Profile.Address
   299  
   300  		case c.General.LocalMSPDir == "":
   301  			logger.Infof("General.LocalMSPDir unset, setting to %s", defaults.General.LocalMSPDir)
   302  			c.General.LocalMSPDir = defaults.General.LocalMSPDir
   303  		case c.General.LocalMSPID == "":
   304  			logger.Infof("General.LocalMSPID unset, setting to %s", defaults.General.LocalMSPID)
   305  			c.General.LocalMSPID = defaults.General.LocalMSPID
   306  
   307  		case c.FileLedger.Prefix == "":
   308  			logger.Infof("FileLedger.Prefix unset, setting to %s", defaults.FileLedger.Prefix)
   309  			c.FileLedger.Prefix = defaults.FileLedger.Prefix
   310  
   311  		case c.Kafka.Retry.ShortInterval == 0*time.Minute:
   312  			logger.Infof("Kafka.Retry.ShortInterval unset, setting to %v", defaults.Kafka.Retry.ShortInterval)
   313  			c.Kafka.Retry.ShortInterval = defaults.Kafka.Retry.ShortInterval
   314  		case c.Kafka.Retry.ShortTotal == 0*time.Minute:
   315  			logger.Infof("Kafka.Retry.ShortTotal unset, setting to %v", defaults.Kafka.Retry.ShortTotal)
   316  			c.Kafka.Retry.ShortTotal = defaults.Kafka.Retry.ShortTotal
   317  		case c.Kafka.Retry.LongInterval == 0*time.Minute:
   318  			logger.Infof("Kafka.Retry.LongInterval unset, setting to %v", defaults.Kafka.Retry.LongInterval)
   319  			c.Kafka.Retry.LongInterval = defaults.Kafka.Retry.LongInterval
   320  		case c.Kafka.Retry.LongTotal == 0*time.Minute:
   321  			logger.Infof("Kafka.Retry.LongTotal unset, setting to %v", defaults.Kafka.Retry.LongTotal)
   322  			c.Kafka.Retry.LongTotal = defaults.Kafka.Retry.LongTotal
   323  
   324  		case c.Kafka.Retry.NetworkTimeouts.DialTimeout == 0*time.Second:
   325  			logger.Infof("Kafka.Retry.NetworkTimeouts.DialTimeout unset, setting to %v", defaults.Kafka.Retry.NetworkTimeouts.DialTimeout)
   326  			c.Kafka.Retry.NetworkTimeouts.DialTimeout = defaults.Kafka.Retry.NetworkTimeouts.DialTimeout
   327  		case c.Kafka.Retry.NetworkTimeouts.ReadTimeout == 0*time.Second:
   328  			logger.Infof("Kafka.Retry.NetworkTimeouts.ReadTimeout unset, setting to %v", defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout)
   329  			c.Kafka.Retry.NetworkTimeouts.ReadTimeout = defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout
   330  		case c.Kafka.Retry.NetworkTimeouts.WriteTimeout == 0*time.Second:
   331  			logger.Infof("Kafka.Retry.NetworkTimeouts.WriteTimeout unset, setting to %v", defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout)
   332  			c.Kafka.Retry.NetworkTimeouts.WriteTimeout = defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout
   333  
   334  		case c.Kafka.Retry.Metadata.RetryBackoff == 0*time.Second:
   335  			logger.Infof("Kafka.Retry.Metadata.RetryBackoff unset, setting to %v", defaults.Kafka.Retry.Metadata.RetryBackoff)
   336  			c.Kafka.Retry.Metadata.RetryBackoff = defaults.Kafka.Retry.Metadata.RetryBackoff
   337  		case c.Kafka.Retry.Metadata.RetryMax == 0:
   338  			logger.Infof("Kafka.Retry.Metadata.RetryMax unset, setting to %v", defaults.Kafka.Retry.Metadata.RetryMax)
   339  			c.Kafka.Retry.Metadata.RetryMax = defaults.Kafka.Retry.Metadata.RetryMax
   340  
   341  		case c.Kafka.Retry.Producer.RetryBackoff == 0*time.Second:
   342  			logger.Infof("Kafka.Retry.Producer.RetryBackoff unset, setting to %v", defaults.Kafka.Retry.Producer.RetryBackoff)
   343  			c.Kafka.Retry.Producer.RetryBackoff = defaults.Kafka.Retry.Producer.RetryBackoff
   344  		case c.Kafka.Retry.Producer.RetryMax == 0:
   345  			logger.Infof("Kafka.Retry.Producer.RetryMax unset, setting to %v", defaults.Kafka.Retry.Producer.RetryMax)
   346  			c.Kafka.Retry.Producer.RetryMax = defaults.Kafka.Retry.Producer.RetryMax
   347  
   348  		case c.Kafka.Retry.Consumer.RetryBackoff == 0*time.Second:
   349  			logger.Infof("Kafka.Retry.Consumer.RetryBackoff unset, setting to %v", defaults.Kafka.Retry.Consumer.RetryBackoff)
   350  			c.Kafka.Retry.Consumer.RetryBackoff = defaults.Kafka.Retry.Consumer.RetryBackoff
   351  
   352  		case c.Kafka.Version == sarama.KafkaVersion{}:
   353  			logger.Infof("Kafka.Version unset, setting to %v", defaults.Kafka.Version)
   354  			c.Kafka.Version = defaults.Kafka.Version
   355  
   356  		default:
   357  			return
   358  		}
   359  	}
   360  }
   361  
   362  func translateCAs(configDir string, certificateAuthorities []string) []string {
   363  	var results []string
   364  	for _, ca := range certificateAuthorities {
   365  		result := cf.TranslatePath(configDir, ca)
   366  		results = append(results, result)
   367  	}
   368  	return results
   369  }