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 }