github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/hyperledger/fabric/common/viperutil"
    27  
    28  	"github.com/Shopify/sarama"
    29  	"github.com/op/go-logging"
    30  	"github.com/spf13/viper"
    31  
    32  	bccsp "github.com/hyperledger/fabric/bccsp/factory"
    33  )
    34  
    35  var logger = logging.MustGetLogger("orderer/config")
    36  
    37  func init() {
    38  	logging.SetLevel(logging.ERROR, "")
    39  }
    40  
    41  // Prefix is the default config prefix for the orderer
    42  const Prefix string = "ORDERER"
    43  
    44  // General contains config which should be common among all orderer types
    45  type General struct {
    46  	LedgerType     string
    47  	ListenAddress  string
    48  	ListenPort     uint16
    49  	TLS            TLS
    50  	GenesisMethod  string
    51  	GenesisProfile string
    52  	GenesisFile    string
    53  	Profile        Profile
    54  	LogLevel       string
    55  	LocalMSPDir    string
    56  	LocalMSPID     string
    57  	BCCSP          *bccsp.FactoryOpts
    58  }
    59  
    60  //TLS contains config used to configure TLS
    61  type TLS struct {
    62  	Enabled           bool
    63  	PrivateKey        string
    64  	Certificate       string
    65  	RootCAs           []string
    66  	ClientAuthEnabled bool
    67  	ClientRootCAs     []string
    68  }
    69  
    70  // Genesis is a deprecated structure which was used to put
    71  // values into the genesis block, but this is now handled elsewhere
    72  // SBFT did not reference these values via the genesis block however
    73  // so it is being left here for backwards compatibility purposes
    74  type Genesis struct {
    75  	DeprecatedBatchTimeout time.Duration
    76  	DeprecatedBatchSize    uint32
    77  	SbftShared             SbftShared
    78  }
    79  
    80  // Profile contains configuration for Go pprof profiling
    81  type Profile struct {
    82  	Enabled bool
    83  	Address string
    84  }
    85  
    86  // RAMLedger contains config for the RAM ledger
    87  type RAMLedger struct {
    88  	HistorySize uint
    89  }
    90  
    91  // FileLedger contains config for the File ledger
    92  type FileLedger struct {
    93  	Location string
    94  	Prefix   string
    95  }
    96  
    97  // Kafka contains config for the Kafka orderer
    98  type Kafka struct {
    99  	Retry   Retry
   100  	Verbose bool
   101  	Version sarama.KafkaVersion
   102  	TLS     TLS
   103  }
   104  
   105  // SbftLocal contains config for the SBFT peer/replica
   106  type SbftLocal struct {
   107  	PeerCommAddr string
   108  	CertFile     string
   109  	KeyFile      string
   110  	DataDir      string
   111  }
   112  
   113  // SbftShared contains config for the SBFT network
   114  type SbftShared struct {
   115  	N                  uint64
   116  	F                  uint64
   117  	RequestTimeoutNsec uint64
   118  	Peers              map[string]string // Address to Cert mapping
   119  }
   120  
   121  // Retry contains config for the reconnection attempts to the Kafka brokers
   122  type Retry struct {
   123  	Period time.Duration
   124  	Stop   time.Duration
   125  }
   126  
   127  type RuntimeAndGenesis struct {
   128  	runtime *TopLevel
   129  	genesis *Genesis
   130  }
   131  
   132  // TopLevel directly corresponds to the orderer config yaml
   133  // Note, for non 1-1 mappings, you may append
   134  // something like `mapstructure:"weirdFoRMat"` to
   135  // modify the default mapping, see the "Unmarshal"
   136  // section of https://github.com/spf13/viper for more info
   137  type TopLevel struct {
   138  	General    General
   139  	RAMLedger  RAMLedger
   140  	FileLedger FileLedger
   141  	Kafka      Kafka
   142  	Genesis    Genesis
   143  	SbftLocal  SbftLocal
   144  }
   145  
   146  var defaults = TopLevel{
   147  	General: General{
   148  		LedgerType:     "ram",
   149  		ListenAddress:  "127.0.0.1",
   150  		ListenPort:     7050,
   151  		GenesisMethod:  "provisional",
   152  		GenesisProfile: "SampleSingleMSPSolo",
   153  		GenesisFile:    "./genesisblock",
   154  		Profile: Profile{
   155  			Enabled: false,
   156  			Address: "0.0.0.0:6060",
   157  		},
   158  		LogLevel:    "INFO",
   159  		LocalMSPDir: "../msp/sampleconfig/",
   160  		LocalMSPID:  "DEFAULT",
   161  		BCCSP:       &bccsp.DefaultOpts,
   162  	},
   163  	RAMLedger: RAMLedger{
   164  		HistorySize: 10000,
   165  	},
   166  	FileLedger: FileLedger{
   167  		Location: "",
   168  		Prefix:   "hyperledger-fabric-ordererledger",
   169  	},
   170  	Kafka: Kafka{
   171  		Retry: Retry{
   172  			Period: 3 * time.Second,
   173  			Stop:   60 * time.Second,
   174  		},
   175  		Verbose: false,
   176  		Version: sarama.V0_9_0_1,
   177  		TLS: TLS{
   178  			Enabled: false,
   179  		},
   180  	},
   181  	Genesis: Genesis{
   182  		SbftShared: SbftShared{
   183  			N:                  1,
   184  			F:                  0,
   185  			RequestTimeoutNsec: uint64(time.Second.Nanoseconds()),
   186  			Peers:              map[string]string{":6101": "sbft/testdata/cert1.pem"},
   187  		},
   188  	},
   189  	SbftLocal: SbftLocal{
   190  		PeerCommAddr: ":6101",
   191  		CertFile:     "sbft/testdata/cert1.pem",
   192  		KeyFile:      "sbft/testdata/key.pem",
   193  		DataDir:      "/tmp",
   194  	},
   195  }
   196  
   197  func (c *TopLevel) completeInitialization() {
   198  	defer logger.Infof("Validated configuration to: %+v", c)
   199  
   200  	for {
   201  		switch {
   202  		case c.General.LedgerType == "":
   203  			logger.Infof("General.LedgerType unset, setting to %s", defaults.General.LedgerType)
   204  			c.General.LedgerType = defaults.General.LedgerType
   205  		case c.General.ListenAddress == "":
   206  			logger.Infof("General.ListenAddress unset, setting to %s", defaults.General.ListenAddress)
   207  			c.General.ListenAddress = defaults.General.ListenAddress
   208  		case c.General.ListenPort == 0:
   209  			logger.Infof("General.ListenPort unset, setting to %s", defaults.General.ListenPort)
   210  			c.General.ListenPort = defaults.General.ListenPort
   211  		case c.General.LogLevel == "":
   212  			logger.Infof("General.LogLevel unset, setting to %s", defaults.General.LogLevel)
   213  			c.General.LogLevel = defaults.General.LogLevel
   214  		case c.General.GenesisMethod == "":
   215  			c.General.GenesisMethod = defaults.General.GenesisMethod
   216  		case c.General.GenesisFile == "":
   217  			c.General.GenesisFile = defaults.General.GenesisFile
   218  		case c.General.GenesisProfile == "":
   219  			c.General.GenesisProfile = defaults.General.GenesisProfile
   220  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.Certificate == "":
   221  			logger.Panicf("General.Kafka.TLS.Certificate must be set if General.Kafka.TLS.Enabled is set to true.")
   222  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.PrivateKey == "":
   223  			logger.Panicf("General.Kafka.TLS.PrivateKey must be set if General.Kafka.TLS.Enabled is set to true.")
   224  		case c.Kafka.TLS.Enabled && c.Kafka.TLS.RootCAs == nil:
   225  			logger.Panicf("General.Kafka.TLS.CertificatePool must be set if General.Kafka.TLS.Enabled is set to true.")
   226  		case c.General.Profile.Enabled && (c.General.Profile.Address == ""):
   227  			logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", defaults.General.Profile.Address)
   228  			c.General.Profile.Address = defaults.General.Profile.Address
   229  		case c.General.LocalMSPDir == "":
   230  			logger.Infof("General.LocalMSPDir unset, setting to %s", defaults.General.LocalMSPDir)
   231  			// Note, this is a bit of a weird one, the orderer may set the ORDERER_CFG_PATH after
   232  			// the file is initialized, so we cannot initialize this in the structure, so we
   233  			// deference the env portion here
   234  			c.General.LocalMSPDir = filepath.Join(os.Getenv("ORDERER_CFG_PATH"), defaults.General.LocalMSPDir)
   235  		case c.General.LocalMSPID == "":
   236  			logger.Infof("General.LocalMSPID unset, setting to %s", defaults.General.LocalMSPID)
   237  			c.General.LocalMSPID = defaults.General.LocalMSPID
   238  		case c.FileLedger.Prefix == "":
   239  			logger.Infof("FileLedger.Prefix unset, setting to %s", defaults.FileLedger.Prefix)
   240  			c.FileLedger.Prefix = defaults.FileLedger.Prefix
   241  		case c.Kafka.Retry.Period == 0*time.Second:
   242  			logger.Infof("Kafka.Retry.Period unset, setting to %v", defaults.Kafka.Retry.Period)
   243  			c.Kafka.Retry.Period = defaults.Kafka.Retry.Period
   244  		case c.Kafka.Retry.Stop == 0*time.Second:
   245  			logger.Infof("Kafka.Retry.Stop unset, setting to %v", defaults.Kafka.Retry.Stop)
   246  			c.Kafka.Retry.Stop = defaults.Kafka.Retry.Stop
   247  		default:
   248  			// A bit hacky, but its type makes it impossible to test for a nil value.
   249  			// This may be overwritten by the Kafka orderer upon instantiation.
   250  			c.Kafka.Version = defaults.Kafka.Version
   251  			return
   252  		}
   253  	}
   254  }
   255  
   256  // Load parses the orderer.yaml file and environment, producing a struct suitable for config use
   257  func Load() *TopLevel {
   258  	config := viper.New()
   259  
   260  	config.SetConfigName("orderer")
   261  	cfgPath := os.Getenv("ORDERER_CFG_PATH")
   262  	if cfgPath == "" {
   263  		logger.Infof("No orderer cfg path set, assuming development environment, deriving from go path")
   264  		// Path to look for the config file in based on GOPATH
   265  		gopath := os.Getenv("GOPATH")
   266  		for _, p := range filepath.SplitList(gopath) {
   267  			ordererPath := filepath.Join(p, "src/github.com/hyperledger/fabric/orderer/")
   268  			if _, err := os.Stat(filepath.Join(ordererPath, "orderer.yaml")); err != nil {
   269  				// The yaml file does not exist in this component of the go src
   270  				continue
   271  			}
   272  			cfgPath = ordererPath
   273  		}
   274  		if cfgPath == "" {
   275  			logger.Fatalf("Could not find orderer.yaml, try setting ORDERER_CFG_PATH or GOPATH correctly")
   276  		}
   277  		logger.Infof("Setting ORDERER_CFG_PATH to: %s", cfgPath)
   278  		os.Setenv("ORDERER_CFG_PATH", cfgPath)
   279  	}
   280  	config.AddConfigPath(cfgPath) // Path to look for the config file in
   281  
   282  	// for environment variables
   283  	config.SetEnvPrefix(Prefix)
   284  	config.AutomaticEnv()
   285  	replacer := strings.NewReplacer(".", "_")
   286  	config.SetEnvKeyReplacer(replacer)
   287  
   288  	err := config.ReadInConfig()
   289  	if err != nil {
   290  		panic(fmt.Errorf("Error reading %s plugin config: %s", Prefix, err))
   291  	}
   292  
   293  	var uconf TopLevel
   294  
   295  	err = viperutil.EnhancedExactUnmarshal(config, &uconf)
   296  	if err != nil {
   297  		panic(fmt.Errorf("Error unmarshaling into structure: %s", err))
   298  	}
   299  
   300  	uconf.completeInitialization()
   301  
   302  	return &uconf
   303  }