github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/orderer/common/localconfig/config.go (about) 1 // Copyright IBM Corp. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package localconfig 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "path/filepath" 10 "strings" 11 "sync" 12 "time" 13 14 "github.com/Shopify/sarama" 15 bccsp "github.com/osdi23p228/fabric/bccsp/factory" 16 "github.com/osdi23p228/fabric/common/flogging" 17 "github.com/osdi23p228/fabric/common/viperutil" 18 coreconfig "github.com/osdi23p228/fabric/core/config" 19 "github.com/spf13/viper" 20 ) 21 22 // Prefix for environment variables. 23 const Prefix = "ORDERER" 24 25 var logger = flogging.MustGetLogger("localconfig") 26 27 // TopLevel directly corresponds to the orderer config YAML. 28 // Note, for non 1-1 mappings, you may append 29 // something like `mapstructure:"weirdFoRMat"` to 30 // modify the default mapping, see the "Unmarshal" 31 // section of https://github.com/spf13/viper for more info. 32 type TopLevel struct { 33 General General 34 FileLedger FileLedger 35 Kafka Kafka 36 Debug Debug 37 Consensus interface{} 38 Operations Operations 39 Metrics Metrics 40 ChannelParticipation ChannelParticipation 41 } 42 43 // General contains config which should be common among all orderer types. 44 type General struct { 45 ListenAddress string 46 ListenPort uint16 47 TLS TLS 48 Cluster Cluster 49 Keepalive Keepalive 50 ConnectionTimeout time.Duration 51 GenesisMethod string // For compatibility only, will be replaced by BootstrapMethod 52 GenesisFile string // For compatibility only, will be replaced by BootstrapFile 53 BootstrapMethod string 54 BootstrapFile string 55 Profile Profile 56 LocalMSPDir string 57 LocalMSPID string 58 BCCSP *bccsp.FactoryOpts 59 Authentication Authentication 60 } 61 62 type Cluster struct { 63 ListenAddress string 64 ListenPort uint16 65 ServerCertificate string 66 ServerPrivateKey string 67 ClientCertificate string 68 ClientPrivateKey string 69 RootCAs []string 70 DialTimeout time.Duration 71 RPCTimeout time.Duration 72 ReplicationBufferSize int 73 ReplicationPullTimeout time.Duration 74 ReplicationRetryTimeout time.Duration 75 ReplicationBackgroundRefreshInterval time.Duration 76 ReplicationMaxRetries int 77 SendBufferSize int 78 CertExpirationWarningThreshold time.Duration 79 TLSHandshakeTimeShift time.Duration 80 } 81 82 // Keepalive contains configuration for gRPC servers. 83 type Keepalive struct { 84 ServerMinInterval time.Duration 85 ServerInterval time.Duration 86 ServerTimeout time.Duration 87 } 88 89 // TLS contains configuration for TLS connections. 90 type TLS struct { 91 Enabled bool 92 PrivateKey string 93 Certificate string 94 RootCAs []string 95 ClientAuthRequired bool 96 ClientRootCAs []string 97 TLSHandshakeTimeShift time.Duration 98 } 99 100 // SASLPlain contains configuration for SASL/PLAIN authentication 101 type SASLPlain struct { 102 Enabled bool 103 User string 104 Password string 105 } 106 107 // Authentication contains configuration parameters related to authenticating 108 // client messages. 109 type Authentication struct { 110 TimeWindow time.Duration 111 NoExpirationChecks bool 112 } 113 114 // Profile contains configuration for Go pprof profiling. 115 type Profile struct { 116 Enabled bool 117 Address string 118 } 119 120 // FileLedger contains configuration for the file-based ledger. 121 type FileLedger struct { 122 Location string 123 Prefix string 124 } 125 126 // Kafka contains configuration for the Kafka-based orderer. 127 type Kafka struct { 128 Retry Retry 129 Verbose bool 130 Version sarama.KafkaVersion // TODO Move this to global config 131 TLS TLS 132 SASLPlain SASLPlain 133 Topic Topic 134 } 135 136 // Retry contains configuration related to retries and timeouts when the 137 // connection to the Kafka cluster cannot be established, or when Metadata 138 // requests needs to be repeated (because the cluster is in the middle of a 139 // leader election). 140 type Retry struct { 141 ShortInterval time.Duration 142 ShortTotal time.Duration 143 LongInterval time.Duration 144 LongTotal time.Duration 145 NetworkTimeouts NetworkTimeouts 146 Metadata Metadata 147 Producer Producer 148 Consumer Consumer 149 } 150 151 // NetworkTimeouts contains the socket timeouts for network requests to the 152 // Kafka cluster. 153 type NetworkTimeouts struct { 154 DialTimeout time.Duration 155 ReadTimeout time.Duration 156 WriteTimeout time.Duration 157 } 158 159 // Metadata contains configuration for the metadata requests to the Kafka 160 // cluster. 161 type Metadata struct { 162 RetryMax int 163 RetryBackoff time.Duration 164 } 165 166 // Producer contains configuration for the producer's retries when failing to 167 // post a message to a Kafka partition. 168 type Producer struct { 169 RetryMax int 170 RetryBackoff time.Duration 171 } 172 173 // Consumer contains configuration for the consumer's retries when failing to 174 // read from a Kafa partition. 175 type Consumer struct { 176 RetryBackoff time.Duration 177 } 178 179 // Topic contains the settings to use when creating Kafka topics 180 type Topic struct { 181 ReplicationFactor int16 182 } 183 184 // Debug contains configuration for the orderer's debug parameters. 185 type Debug struct { 186 BroadcastTraceDir string 187 DeliverTraceDir string 188 } 189 190 // Operations configures the operations endpoint for the orderer. 191 type Operations struct { 192 ListenAddress string 193 TLS TLS 194 } 195 196 // Metrics configures the metrics provider for the orderer. 197 type Metrics struct { 198 Provider string 199 Statsd Statsd 200 } 201 202 // Statsd provides the configuration required to emit statsd metrics from the orderer. 203 type Statsd struct { 204 Network string 205 Address string 206 WriteInterval time.Duration 207 Prefix string 208 } 209 210 // ChannelParticipation provides the channel participation API configuration for the orderer. 211 // Channel participation uses the same ListenAddress and TLS settings of the Operations service. 212 type ChannelParticipation struct { 213 Enabled bool 214 RemoveStorage bool // Whether to permanently remove storage on channel removal. 215 } 216 217 // Defaults carries the default orderer configuration values. 218 var Defaults = TopLevel{ 219 General: General{ 220 ListenAddress: "127.0.0.1", 221 ListenPort: 7050, 222 BootstrapMethod: "file", 223 BootstrapFile: "genesisblock", 224 Profile: Profile{ 225 Enabled: false, 226 Address: "0.0.0.0:6060", 227 }, 228 Cluster: Cluster{ 229 ReplicationMaxRetries: 12, 230 RPCTimeout: time.Second * 7, 231 DialTimeout: time.Second * 5, 232 ReplicationBufferSize: 20971520, 233 SendBufferSize: 10, 234 ReplicationBackgroundRefreshInterval: time.Minute * 5, 235 ReplicationRetryTimeout: time.Second * 5, 236 ReplicationPullTimeout: time.Second * 5, 237 CertExpirationWarningThreshold: time.Hour * 24 * 7, 238 }, 239 LocalMSPDir: "msp", 240 LocalMSPID: "SampleOrg", 241 BCCSP: bccsp.GetDefaultOpts(), 242 Authentication: Authentication{ 243 TimeWindow: time.Duration(15 * time.Minute), 244 }, 245 }, 246 FileLedger: FileLedger{ 247 Location: "/var/hyperledger/production/orderer", 248 Prefix: "hyperledger-fabric-ordererledger", 249 }, 250 Kafka: Kafka{ 251 Retry: Retry{ 252 ShortInterval: 1 * time.Minute, 253 ShortTotal: 10 * time.Minute, 254 LongInterval: 10 * time.Minute, 255 LongTotal: 12 * time.Hour, 256 NetworkTimeouts: NetworkTimeouts{ 257 DialTimeout: 30 * time.Second, 258 ReadTimeout: 30 * time.Second, 259 WriteTimeout: 30 * time.Second, 260 }, 261 Metadata: Metadata{ 262 RetryBackoff: 250 * time.Millisecond, 263 RetryMax: 3, 264 }, 265 Producer: Producer{ 266 RetryBackoff: 100 * time.Millisecond, 267 RetryMax: 3, 268 }, 269 Consumer: Consumer{ 270 RetryBackoff: 2 * time.Second, 271 }, 272 }, 273 Verbose: false, 274 Version: sarama.V0_10_2_0, 275 TLS: TLS{ 276 Enabled: false, 277 }, 278 Topic: Topic{ 279 ReplicationFactor: 3, 280 }, 281 }, 282 Debug: Debug{ 283 BroadcastTraceDir: "", 284 DeliverTraceDir: "", 285 }, 286 Operations: Operations{ 287 ListenAddress: "127.0.0.1:0", 288 }, 289 Metrics: Metrics{ 290 Provider: "disabled", 291 }, 292 ChannelParticipation: ChannelParticipation{ 293 Enabled: false, 294 RemoveStorage: false, 295 }, 296 } 297 298 // Load parses the orderer YAML file and environment, producing 299 // a struct suitable for config use, returning error on failure. 300 func Load() (*TopLevel, error) { 301 return cache.load() 302 } 303 304 // configCache stores marshalled bytes of config structures that produced from 305 // EnhancedExactUnmarshal. Cache key is the path of the configuration file that was used. 306 type configCache struct { 307 mutex sync.Mutex 308 cache map[string][]byte 309 } 310 311 var cache = &configCache{} 312 313 // Load will load the configuration and cache it on the first call; subsequent 314 // calls will return a clone of the configuration that was previously loaded. 315 func (c *configCache) load() (*TopLevel, error) { 316 var uconf TopLevel 317 318 config := viper.New() 319 coreconfig.InitViper(config, "orderer") 320 config.SetEnvPrefix(Prefix) 321 config.AutomaticEnv() 322 replacer := strings.NewReplacer(".", "_") 323 config.SetEnvKeyReplacer(replacer) 324 325 if err := config.ReadInConfig(); err != nil { 326 return nil, fmt.Errorf("Error reading configuration: %s", err) 327 } 328 329 c.mutex.Lock() 330 defer c.mutex.Unlock() 331 serializedConf, ok := c.cache[config.ConfigFileUsed()] 332 if !ok { 333 err := viperutil.EnhancedExactUnmarshal(config, &uconf) 334 if err != nil { 335 return nil, fmt.Errorf("Error unmarshaling config into struct: %s", err) 336 } 337 338 serializedConf, err = json.Marshal(uconf) 339 if err != nil { 340 return nil, err 341 } 342 343 if c.cache == nil { 344 c.cache = map[string][]byte{} 345 } 346 c.cache[config.ConfigFileUsed()] = serializedConf 347 } 348 349 err := json.Unmarshal(serializedConf, &uconf) 350 if err != nil { 351 return nil, err 352 } 353 uconf.completeInitialization(filepath.Dir(config.ConfigFileUsed())) 354 355 return &uconf, nil 356 } 357 358 func (c *TopLevel) completeInitialization(configDir string) { 359 defer func() { 360 // Translate any paths for cluster TLS configuration if applicable 361 if c.General.Cluster.ClientPrivateKey != "" { 362 coreconfig.TranslatePathInPlace(configDir, &c.General.Cluster.ClientPrivateKey) 363 } 364 if c.General.Cluster.ClientCertificate != "" { 365 coreconfig.TranslatePathInPlace(configDir, &c.General.Cluster.ClientCertificate) 366 } 367 c.General.Cluster.RootCAs = translateCAs(configDir, c.General.Cluster.RootCAs) 368 // Translate any paths for general TLS configuration 369 c.General.TLS.RootCAs = translateCAs(configDir, c.General.TLS.RootCAs) 370 c.General.TLS.ClientRootCAs = translateCAs(configDir, c.General.TLS.ClientRootCAs) 371 coreconfig.TranslatePathInPlace(configDir, &c.General.TLS.PrivateKey) 372 coreconfig.TranslatePathInPlace(configDir, &c.General.TLS.Certificate) 373 coreconfig.TranslatePathInPlace(configDir, &c.General.BootstrapFile) 374 coreconfig.TranslatePathInPlace(configDir, &c.General.LocalMSPDir) 375 // Translate file ledger location 376 coreconfig.TranslatePathInPlace(configDir, &c.FileLedger.Location) 377 }() 378 379 for { 380 switch { 381 case c.General.ListenAddress == "": 382 logger.Infof("General.ListenAddress unset, setting to %s", Defaults.General.ListenAddress) 383 c.General.ListenAddress = Defaults.General.ListenAddress 384 case c.General.ListenPort == 0: 385 logger.Infof("General.ListenPort unset, setting to %v", Defaults.General.ListenPort) 386 c.General.ListenPort = Defaults.General.ListenPort 387 case c.General.BootstrapMethod == "": 388 if c.General.GenesisMethod != "" { 389 // This is to keep the compatibility with old config file that uses genesismethod 390 logger.Warn("General.GenesisMethod should be replaced by General.BootstrapMethod") 391 c.General.BootstrapMethod = c.General.GenesisMethod 392 } else { 393 c.General.BootstrapMethod = Defaults.General.BootstrapMethod 394 } 395 case c.General.BootstrapFile == "": 396 if c.General.GenesisFile != "" { 397 // This is to keep the compatibility with old config file that uses genesisfile 398 logger.Warn("General.GenesisFile should be replaced by General.BootstrapFile") 399 c.General.BootstrapFile = c.General.GenesisFile 400 } else { 401 c.General.BootstrapFile = Defaults.General.BootstrapFile 402 } 403 case c.General.Cluster.RPCTimeout == 0: 404 c.General.Cluster.RPCTimeout = Defaults.General.Cluster.RPCTimeout 405 case c.General.Cluster.DialTimeout == 0: 406 c.General.Cluster.DialTimeout = Defaults.General.Cluster.DialTimeout 407 case c.General.Cluster.ReplicationMaxRetries == 0: 408 c.General.Cluster.ReplicationMaxRetries = Defaults.General.Cluster.ReplicationMaxRetries 409 case c.General.Cluster.SendBufferSize == 0: 410 c.General.Cluster.SendBufferSize = Defaults.General.Cluster.SendBufferSize 411 case c.General.Cluster.ReplicationBufferSize == 0: 412 c.General.Cluster.ReplicationBufferSize = Defaults.General.Cluster.ReplicationBufferSize 413 case c.General.Cluster.ReplicationPullTimeout == 0: 414 c.General.Cluster.ReplicationPullTimeout = Defaults.General.Cluster.ReplicationPullTimeout 415 case c.General.Cluster.ReplicationRetryTimeout == 0: 416 c.General.Cluster.ReplicationRetryTimeout = Defaults.General.Cluster.ReplicationRetryTimeout 417 case c.General.Cluster.ReplicationBackgroundRefreshInterval == 0: 418 c.General.Cluster.ReplicationBackgroundRefreshInterval = Defaults.General.Cluster.ReplicationBackgroundRefreshInterval 419 case c.General.Cluster.CertExpirationWarningThreshold == 0: 420 c.General.Cluster.CertExpirationWarningThreshold = Defaults.General.Cluster.CertExpirationWarningThreshold 421 case c.Kafka.TLS.Enabled && c.Kafka.TLS.Certificate == "": 422 logger.Panicf("General.Kafka.TLS.Certificate must be set if General.Kafka.TLS.Enabled is set to true.") 423 case c.Kafka.TLS.Enabled && c.Kafka.TLS.PrivateKey == "": 424 logger.Panicf("General.Kafka.TLS.PrivateKey must be set if General.Kafka.TLS.Enabled is set to true.") 425 case c.Kafka.TLS.Enabled && c.Kafka.TLS.RootCAs == nil: 426 logger.Panicf("General.Kafka.TLS.CertificatePool must be set if General.Kafka.TLS.Enabled is set to true.") 427 428 case c.Kafka.SASLPlain.Enabled && c.Kafka.SASLPlain.User == "": 429 logger.Panic("General.Kafka.SASLPlain.User must be set if General.Kafka.SASLPlain.Enabled is set to true.") 430 case c.Kafka.SASLPlain.Enabled && c.Kafka.SASLPlain.Password == "": 431 logger.Panic("General.Kafka.SASLPlain.Password must be set if General.Kafka.SASLPlain.Enabled is set to true.") 432 433 case c.General.Profile.Enabled && c.General.Profile.Address == "": 434 logger.Infof("Profiling enabled and General.Profile.Address unset, setting to %s", Defaults.General.Profile.Address) 435 c.General.Profile.Address = Defaults.General.Profile.Address 436 437 case c.General.LocalMSPDir == "": 438 logger.Infof("General.LocalMSPDir unset, setting to %s", Defaults.General.LocalMSPDir) 439 c.General.LocalMSPDir = Defaults.General.LocalMSPDir 440 case c.General.LocalMSPID == "": 441 logger.Infof("General.LocalMSPID unset, setting to %s", Defaults.General.LocalMSPID) 442 c.General.LocalMSPID = Defaults.General.LocalMSPID 443 444 case c.General.Authentication.TimeWindow == 0: 445 logger.Infof("General.Authentication.TimeWindow unset, setting to %s", Defaults.General.Authentication.TimeWindow) 446 c.General.Authentication.TimeWindow = Defaults.General.Authentication.TimeWindow 447 448 case c.FileLedger.Prefix == "": 449 logger.Infof("FileLedger.Prefix unset, setting to %s", Defaults.FileLedger.Prefix) 450 c.FileLedger.Prefix = Defaults.FileLedger.Prefix 451 452 case c.Kafka.Retry.ShortInterval == 0: 453 logger.Infof("Kafka.Retry.ShortInterval unset, setting to %v", Defaults.Kafka.Retry.ShortInterval) 454 c.Kafka.Retry.ShortInterval = Defaults.Kafka.Retry.ShortInterval 455 case c.Kafka.Retry.ShortTotal == 0: 456 logger.Infof("Kafka.Retry.ShortTotal unset, setting to %v", Defaults.Kafka.Retry.ShortTotal) 457 c.Kafka.Retry.ShortTotal = Defaults.Kafka.Retry.ShortTotal 458 case c.Kafka.Retry.LongInterval == 0: 459 logger.Infof("Kafka.Retry.LongInterval unset, setting to %v", Defaults.Kafka.Retry.LongInterval) 460 c.Kafka.Retry.LongInterval = Defaults.Kafka.Retry.LongInterval 461 case c.Kafka.Retry.LongTotal == 0: 462 logger.Infof("Kafka.Retry.LongTotal unset, setting to %v", Defaults.Kafka.Retry.LongTotal) 463 c.Kafka.Retry.LongTotal = Defaults.Kafka.Retry.LongTotal 464 465 case c.Kafka.Retry.NetworkTimeouts.DialTimeout == 0: 466 logger.Infof("Kafka.Retry.NetworkTimeouts.DialTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.DialTimeout) 467 c.Kafka.Retry.NetworkTimeouts.DialTimeout = Defaults.Kafka.Retry.NetworkTimeouts.DialTimeout 468 case c.Kafka.Retry.NetworkTimeouts.ReadTimeout == 0: 469 logger.Infof("Kafka.Retry.NetworkTimeouts.ReadTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout) 470 c.Kafka.Retry.NetworkTimeouts.ReadTimeout = Defaults.Kafka.Retry.NetworkTimeouts.ReadTimeout 471 case c.Kafka.Retry.NetworkTimeouts.WriteTimeout == 0: 472 logger.Infof("Kafka.Retry.NetworkTimeouts.WriteTimeout unset, setting to %v", Defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout) 473 c.Kafka.Retry.NetworkTimeouts.WriteTimeout = Defaults.Kafka.Retry.NetworkTimeouts.WriteTimeout 474 475 case c.Kafka.Retry.Metadata.RetryBackoff == 0: 476 logger.Infof("Kafka.Retry.Metadata.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Metadata.RetryBackoff) 477 c.Kafka.Retry.Metadata.RetryBackoff = Defaults.Kafka.Retry.Metadata.RetryBackoff 478 case c.Kafka.Retry.Metadata.RetryMax == 0: 479 logger.Infof("Kafka.Retry.Metadata.RetryMax unset, setting to %v", Defaults.Kafka.Retry.Metadata.RetryMax) 480 c.Kafka.Retry.Metadata.RetryMax = Defaults.Kafka.Retry.Metadata.RetryMax 481 482 case c.Kafka.Retry.Producer.RetryBackoff == 0: 483 logger.Infof("Kafka.Retry.Producer.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Producer.RetryBackoff) 484 c.Kafka.Retry.Producer.RetryBackoff = Defaults.Kafka.Retry.Producer.RetryBackoff 485 case c.Kafka.Retry.Producer.RetryMax == 0: 486 logger.Infof("Kafka.Retry.Producer.RetryMax unset, setting to %v", Defaults.Kafka.Retry.Producer.RetryMax) 487 c.Kafka.Retry.Producer.RetryMax = Defaults.Kafka.Retry.Producer.RetryMax 488 489 case c.Kafka.Retry.Consumer.RetryBackoff == 0: 490 logger.Infof("Kafka.Retry.Consumer.RetryBackoff unset, setting to %v", Defaults.Kafka.Retry.Consumer.RetryBackoff) 491 c.Kafka.Retry.Consumer.RetryBackoff = Defaults.Kafka.Retry.Consumer.RetryBackoff 492 493 case c.Kafka.Version == sarama.KafkaVersion{}: 494 logger.Infof("Kafka.Version unset, setting to %v", Defaults.Kafka.Version) 495 c.Kafka.Version = Defaults.Kafka.Version 496 497 default: 498 return 499 } 500 } 501 } 502 503 func translateCAs(configDir string, certificateAuthorities []string) []string { 504 var results []string 505 for _, ca := range certificateAuthorities { 506 result := coreconfig.TranslatePath(configDir, ca) 507 results = append(results, result) 508 } 509 return results 510 }