github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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  	cf "github.com/hyperledger/fabric/core/config"
    34  )
    35  
    36  const (
    37  	pkgLogID = "common/configtx/tool/localconfig"
    38  
    39  	// Prefix identifies the prefix for the configtxgen-related ENV vars.
    40  	Prefix string = "CONFIGTX"
    41  )
    42  
    43  var (
    44  	logger *logging.Logger
    45  
    46  	configName string
    47  )
    48  
    49  func init() {
    50  	logger = flogging.MustGetLogger(pkgLogID)
    51  	flogging.SetModuleLevel(pkgLogID, "error")
    52  
    53  	configName = strings.ToLower(Prefix)
    54  }
    55  
    56  const (
    57  	// SampleInsecureProfile references the sample profile which does not include any MSPs and uses solo for ordering.
    58  	SampleInsecureProfile = "SampleInsecureSolo"
    59  	// SampleSingleMSPSoloProfile references the sample profile which includes only the sample MSP and uses solo for ordering.
    60  	SampleSingleMSPSoloProfile = "SampleSingleMSPSolo"
    61  	// SampleSingleMSPChannelProfile references the sample profile which includes only the sample MSP and is used to create a channel
    62  	SampleSingleMSPChannelProfile = "SampleSingleMSPChannel"
    63  
    64  	// SampleConsortiumName is the sample consortium from the sample configtx.yaml
    65  	SampleConsortiumName = "SampleConsortium"
    66  	// SampleOrgName is the name of the sample org in the sample profiles
    67  	SampleOrgName = "SampleOrg"
    68  
    69  	// AdminRoleAdminPrincipal is set as AdminRole to cause the MSP role of type Admin to be used as the admin principal default
    70  	AdminRoleAdminPrincipal = "Role.ADMIN"
    71  	// MemberRoleAdminPrincipal is set as AdminRole to cause the MSP role of type Member to be used as the admin principal default
    72  	MemberRoleAdminPrincipal = "Role.MEMBER"
    73  )
    74  
    75  // TopLevel consists of the structs used by the configtxgen tool.
    76  type TopLevel struct {
    77  	Profiles      map[string]*Profile `yaml:"Profiles"`
    78  	Organizations []*Organization     `yaml:"Organizations"`
    79  	Application   *Application        `yaml:"Application"`
    80  	Orderer       *Orderer            `yaml:"Orderer"`
    81  }
    82  
    83  // Profile encodes orderer/application configuration combinations for the configtxgen tool.
    84  type Profile struct {
    85  	Consortium  string                 `yaml:"Consortium"`
    86  	Application *Application           `yaml:"Application"`
    87  	Orderer     *Orderer               `yaml:"Orderer"`
    88  	Consortiums map[string]*Consortium `yaml:"Consortiums"`
    89  }
    90  
    91  // Consortium represents a group of organizations which may create channels with eachother
    92  type Consortium struct {
    93  	Organizations []*Organization `yaml:"Organizations"`
    94  }
    95  
    96  // Application encodes the application-level configuration needed in config transactions.
    97  type Application struct {
    98  	Organizations []*Organization `yaml:"Organizations"`
    99  }
   100  
   101  // Organization encodes the organization-level configuration needed in config transactions.
   102  type Organization struct {
   103  	Name           string `yaml:"Name"`
   104  	ID             string `yaml:"ID"`
   105  	MSPDir         string `yaml:"MSPDir"`
   106  	AdminPrincipal string `yaml:"AdminPrincipal"`
   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:  10 * 1024 * 1024,
   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  	logger.Infof("Loaded configuration: %s", config.ConfigFileUsed())
   198  
   199  	return result
   200  }
   201  
   202  func (p *Profile) completeInitialization(configDir string) {
   203  	if p.Orderer != nil {
   204  		for _, org := range p.Orderer.Organizations {
   205  			if org.AdminPrincipal == "" {
   206  				org.AdminPrincipal = AdminRoleAdminPrincipal
   207  			}
   208  			translatePaths(configDir, org)
   209  		}
   210  	}
   211  
   212  	if p.Application != nil {
   213  		for _, org := range p.Application.Organizations {
   214  			if org.AdminPrincipal == "" {
   215  				org.AdminPrincipal = AdminRoleAdminPrincipal
   216  			}
   217  			translatePaths(configDir, org)
   218  		}
   219  	}
   220  
   221  	if p.Consortiums != nil {
   222  		for _, consortium := range p.Consortiums {
   223  			for _, org := range consortium.Organizations {
   224  				if org.AdminPrincipal == "" {
   225  					org.AdminPrincipal = AdminRoleAdminPrincipal
   226  				}
   227  				translatePaths(configDir, org)
   228  			}
   229  		}
   230  	}
   231  
   232  	// Some profiles will not define orderer parameters
   233  	if p.Orderer == nil {
   234  		return
   235  	}
   236  
   237  	for {
   238  		switch {
   239  		case p.Orderer.OrdererType == "":
   240  			logger.Infof("Orderer.OrdererType unset, setting to %s", genesisDefaults.Orderer.OrdererType)
   241  			p.Orderer.OrdererType = genesisDefaults.Orderer.OrdererType
   242  		case p.Orderer.Addresses == nil:
   243  			logger.Infof("Orderer.Addresses unset, setting to %s", genesisDefaults.Orderer.Addresses)
   244  			p.Orderer.Addresses = genesisDefaults.Orderer.Addresses
   245  		case p.Orderer.BatchTimeout == 0:
   246  			logger.Infof("Orderer.BatchTimeout unset, setting to %s", genesisDefaults.Orderer.BatchTimeout)
   247  			p.Orderer.BatchTimeout = genesisDefaults.Orderer.BatchTimeout
   248  		case p.Orderer.BatchSize.MaxMessageCount == 0:
   249  			logger.Infof("Orderer.BatchSize.MaxMessageCount unset, setting to %s", genesisDefaults.Orderer.BatchSize.MaxMessageCount)
   250  			p.Orderer.BatchSize.MaxMessageCount = genesisDefaults.Orderer.BatchSize.MaxMessageCount
   251  		case p.Orderer.BatchSize.AbsoluteMaxBytes == 0:
   252  			logger.Infof("Orderer.BatchSize.AbsoluteMaxBytes unset, setting to %s", genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes)
   253  			p.Orderer.BatchSize.AbsoluteMaxBytes = genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes
   254  		case p.Orderer.BatchSize.PreferredMaxBytes == 0:
   255  			logger.Infof("Orderer.BatchSize.PreferredMaxBytes unset, setting to %s", genesisDefaults.Orderer.BatchSize.PreferredMaxBytes)
   256  			p.Orderer.BatchSize.PreferredMaxBytes = genesisDefaults.Orderer.BatchSize.PreferredMaxBytes
   257  		case p.Orderer.Kafka.Brokers == nil:
   258  			logger.Infof("Orderer.Kafka.Brokers unset, setting to %v", genesisDefaults.Orderer.Kafka.Brokers)
   259  			p.Orderer.Kafka.Brokers = genesisDefaults.Orderer.Kafka.Brokers
   260  		default:
   261  			return
   262  		}
   263  	}
   264  }
   265  
   266  func translatePaths(configDir string, org *Organization) {
   267  	cf.TranslatePathInPlace(configDir, &org.MSPDir)
   268  }