github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/common/configtx/tool/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 localconfig
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/hyperledger/fabric/common/flogging"
    26  	"github.com/hyperledger/fabric/common/viperutil"
    27  	logging "github.com/op/go-logging"
    28  
    29  	"github.com/spf13/viper"
    30  
    31  	"path/filepath"
    32  
    33  	bccsp "github.com/hyperledger/fabric/bccsp/factory"
    34  	cf "github.com/hyperledger/fabric/core/config"
    35  )
    36  
    37  const (
    38  	pkgLogID = "common/configtx/tool/localconfig"
    39  
    40  	// Prefix identifies the prefix for the configtxgen-related ENV vars.
    41  	Prefix string = "CONFIGTX"
    42  )
    43  
    44  var (
    45  	logger *logging.Logger
    46  
    47  	configName string
    48  )
    49  
    50  func init() {
    51  	logger = flogging.MustGetLogger(pkgLogID)
    52  	flogging.SetModuleLevel(pkgLogID, "error")
    53  
    54  	configName = strings.ToLower(Prefix)
    55  }
    56  
    57  const (
    58  	// SampleInsecureProfile references the sample profile which does not include any MSPs and uses solo for ordering.
    59  	SampleInsecureProfile = "SampleInsecureSolo"
    60  	// SampleSingleMSPSoloProfile references the sample profile which includes only the sample MSP and uses solo for ordering.
    61  	SampleSingleMSPSoloProfile = "SampleSingleMSPSolo"
    62  
    63  	// SampleConsortiumName is the sample consortium from the sample configtx.yaml
    64  	SampleConsortiumName = "SampleConsortium"
    65  	// SampleOrgName is the name of the sample org in the sample profiles
    66  	SampleOrgName = "SampleOrg"
    67  
    68  	// AdminRoleAdminPrincipal is set as AdminRole to cause the MSP role of type Admin to be used as the admin principal default
    69  	AdminRoleAdminPrincipal = "Role.ADMIN"
    70  	// MemberRoleAdminPrincipal is set as AdminRole to cause the MSP role of type Member to be used as the admin principal default
    71  	MemberRoleAdminPrincipal = "Role.MEMBER"
    72  )
    73  
    74  // TopLevel consists of the structs used by the configtxgen tool.
    75  type TopLevel struct {
    76  	Profiles      map[string]*Profile `yaml:"Profiles"`
    77  	Organizations []*Organization     `yaml:"Organizations"`
    78  	Application   *Application        `yaml:"Application"`
    79  	Orderer       *Orderer            `yaml:"Orderer"`
    80  }
    81  
    82  // Profile encodes orderer/application configuration combinations for the configtxgen tool.
    83  type Profile struct {
    84  	Consortium  string                 `yaml:"Consortium"`
    85  	Application *Application           `yaml:"Application"`
    86  	Orderer     *Orderer               `yaml:"Orderer"`
    87  	Consortiums map[string]*Consortium `yaml:"Consortiums"`
    88  }
    89  
    90  // Consortium represents a group of organizations which may create channels with eachother
    91  type Consortium struct {
    92  	Organizations []*Organization `yaml:"Organizations"`
    93  }
    94  
    95  // Application encodes the application-level configuration needed in config transactions.
    96  type Application struct {
    97  	Organizations []*Organization `yaml:"Organizations"`
    98  }
    99  
   100  // Organization encodes the organization-level configuration needed in config transactions.
   101  type Organization struct {
   102  	Name           string             `yaml:"Name"`
   103  	ID             string             `yaml:"ID"`
   104  	MSPDir         string             `yaml:"MSPDir"`
   105  	AdminPrincipal string             `yaml:"AdminPrincipal"`
   106  	BCCSP          *bccsp.FactoryOpts `yaml:"BCCSP"`
   107  
   108  	// Note: Viper deserialization does not seem to care for
   109  	// embedding of types, so we use one organization struct
   110  	// for both orderers and applications.
   111  	AnchorPeers []*AnchorPeer `yaml:"AnchorPeers"`
   112  }
   113  
   114  // AnchorPeer encodes the necessary fields to identify an anchor peer.
   115  type AnchorPeer struct {
   116  	Host string `yaml:"Host"`
   117  	Port int    `yaml:"Port"`
   118  }
   119  
   120  // ApplicationOrganization ...
   121  // TODO This should probably be removed
   122  type ApplicationOrganization struct {
   123  	Organization `yaml:"Organization"`
   124  }
   125  
   126  // Orderer contains configuration which is used for the
   127  // bootstrapping of an orderer by the provisional bootstrapper.
   128  type Orderer struct {
   129  	OrdererType   string          `yaml:"OrdererType"`
   130  	Addresses     []string        `yaml:"Addresses"`
   131  	BatchTimeout  time.Duration   `yaml:"BatchTimeout"`
   132  	BatchSize     BatchSize       `yaml:"BatchSize"`
   133  	Kafka         Kafka           `yaml:"Kafka"`
   134  	Organizations []*Organization `yaml:"Organizations"`
   135  	MaxChannels   uint64          `yaml:"MaxChannels"`
   136  }
   137  
   138  // BatchSize contains configuration affecting the size of batches.
   139  type BatchSize struct {
   140  	MaxMessageCount   uint32 `yaml:"MaxMessageSize"`
   141  	AbsoluteMaxBytes  uint32 `yaml:"AbsoluteMaxBytes"`
   142  	PreferredMaxBytes uint32 `yaml:"PreferredMaxBytes"`
   143  }
   144  
   145  // Kafka contains configuration for the Kafka-based orderer.
   146  type Kafka struct {
   147  	Brokers []string `yaml:"Brokers"`
   148  }
   149  
   150  var genesisDefaults = TopLevel{
   151  	Orderer: &Orderer{
   152  		OrdererType:  "solo",
   153  		Addresses:    []string{"127.0.0.1:7050"},
   154  		BatchTimeout: 2 * time.Second,
   155  		BatchSize: BatchSize{
   156  			MaxMessageCount:   10,
   157  			AbsoluteMaxBytes:  100000000,
   158  			PreferredMaxBytes: 512 * 1024,
   159  		},
   160  		Kafka: Kafka{
   161  			Brokers: []string{"127.0.0.1:9092"},
   162  		},
   163  	},
   164  }
   165  
   166  // Load returns the orderer/application config combination that corresponds to a given profile.
   167  func Load(profile string) *Profile {
   168  	config := viper.New()
   169  	cf.InitViper(config, configName)
   170  
   171  	// For environment variables
   172  	config.SetEnvPrefix(Prefix)
   173  	config.AutomaticEnv()
   174  	// This replacer allows substitution within the particular profile without having to fully qualify the name
   175  	replacer := strings.NewReplacer(strings.ToUpper(fmt.Sprintf("profiles.%s.", profile)), "", ".", "_")
   176  	config.SetEnvKeyReplacer(replacer)
   177  
   178  	err := config.ReadInConfig()
   179  	if err != nil {
   180  		logger.Panic("Error reading configuration:", err)
   181  	}
   182  	logger.Debugf("Using config file: %s", config.ConfigFileUsed())
   183  
   184  	var uconf TopLevel
   185  	err = viperutil.EnhancedExactUnmarshal(config, &uconf)
   186  	if err != nil {
   187  		logger.Panic("Error unmarshaling config into struct:", err)
   188  	}
   189  
   190  	result, ok := uconf.Profiles[profile]
   191  	if !ok {
   192  		logger.Panic("Could not find profile", profile)
   193  	}
   194  
   195  	result.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
   196  
   197  	return result
   198  }
   199  
   200  func (p *Profile) completeInitialization(configDir string) {
   201  	if p.Orderer != nil {
   202  		for _, org := range p.Orderer.Organizations {
   203  			if org.AdminPrincipal == "" {
   204  				org.AdminPrincipal = AdminRoleAdminPrincipal
   205  			}
   206  			translatePaths(configDir, org)
   207  		}
   208  	}
   209  
   210  	if p.Application != nil {
   211  		for _, org := range p.Application.Organizations {
   212  			if org.AdminPrincipal == "" {
   213  				org.AdminPrincipal = AdminRoleAdminPrincipal
   214  			}
   215  			translatePaths(configDir, org)
   216  		}
   217  	}
   218  
   219  	if p.Consortiums != nil {
   220  		for _, consortium := range p.Consortiums {
   221  			for _, org := range consortium.Organizations {
   222  				if org.AdminPrincipal == "" {
   223  					org.AdminPrincipal = AdminRoleAdminPrincipal
   224  				}
   225  				translatePaths(configDir, org)
   226  			}
   227  		}
   228  	}
   229  
   230  	// Some profiles will not define orderer parameters
   231  	if p.Orderer == nil {
   232  		return
   233  	}
   234  
   235  	for {
   236  		switch {
   237  		case p.Orderer.OrdererType == "":
   238  			logger.Infof("Orderer.OrdererType unset, setting to %s", genesisDefaults.Orderer.OrdererType)
   239  			p.Orderer.OrdererType = genesisDefaults.Orderer.OrdererType
   240  		case p.Orderer.Addresses == nil:
   241  			logger.Infof("Orderer.Addresses unset, setting to %s", genesisDefaults.Orderer.Addresses)
   242  			p.Orderer.Addresses = genesisDefaults.Orderer.Addresses
   243  		case p.Orderer.BatchTimeout == 0:
   244  			logger.Infof("Orderer.BatchTimeout unset, setting to %s", genesisDefaults.Orderer.BatchTimeout)
   245  			p.Orderer.BatchTimeout = genesisDefaults.Orderer.BatchTimeout
   246  		case p.Orderer.BatchSize.MaxMessageCount == 0:
   247  			logger.Infof("Orderer.BatchSize.MaxMessageCount unset, setting to %s", genesisDefaults.Orderer.BatchSize.MaxMessageCount)
   248  			p.Orderer.BatchSize.MaxMessageCount = genesisDefaults.Orderer.BatchSize.MaxMessageCount
   249  		case p.Orderer.BatchSize.AbsoluteMaxBytes == 0:
   250  			logger.Infof("Orderer.BatchSize.AbsoluteMaxBytes unset, setting to %s", genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes)
   251  			p.Orderer.BatchSize.AbsoluteMaxBytes = genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes
   252  		case p.Orderer.BatchSize.PreferredMaxBytes == 0:
   253  			logger.Infof("Orderer.BatchSize.PreferredMaxBytes unset, setting to %s", genesisDefaults.Orderer.BatchSize.PreferredMaxBytes)
   254  			p.Orderer.BatchSize.PreferredMaxBytes = genesisDefaults.Orderer.BatchSize.PreferredMaxBytes
   255  		case p.Orderer.Kafka.Brokers == nil:
   256  			logger.Infof("Orderer.Kafka.Brokers unset, setting to %v", genesisDefaults.Orderer.Kafka.Brokers)
   257  			p.Orderer.Kafka.Brokers = genesisDefaults.Orderer.Kafka.Brokers
   258  		default:
   259  			return
   260  		}
   261  	}
   262  }
   263  
   264  func translatePaths(configDir string, org *Organization) {
   265  	cf.TranslatePathInPlace(configDir, &org.MSPDir)
   266  	cf.TranslatePathInPlace(configDir, &org.BCCSP.SwOpts.FileKeystore.KeyStorePath)
   267  }