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 }