github.com/binyushen/fabric@v2.1.1+incompatible/core/peer/config.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // The 'viper' package for configuration handling is very flexible, but has 8 // been found to have extremely poor performance when configuration values are 9 // accessed repeatedly. The function CacheConfiguration() defined here caches 10 // all configuration values that are accessed frequently. These parameters 11 // are now presented as function calls that access local configuration 12 // variables. This seems to be the most robust way to represent these 13 // parameters in the face of the numerous ways that configuration files are 14 // loaded and used (e.g, normal usage vs. test cases). 15 16 // The CacheConfiguration() function is allowed to be called globally to 17 // ensure that the correct values are always cached; See for example how 18 // certain parameters are forced in 'ChaincodeDevMode' in main.go. 19 20 package peer 21 22 import ( 23 "crypto/tls" 24 "fmt" 25 "io/ioutil" 26 "net" 27 "path/filepath" 28 "runtime" 29 "time" 30 31 "github.com/hyperledger/fabric/core/config" 32 "github.com/hyperledger/fabric/internal/pkg/comm" 33 "github.com/pkg/errors" 34 "github.com/spf13/viper" 35 ) 36 37 // ExternalBuilder represents the configuration structure of 38 // a chaincode external builder 39 type ExternalBuilder struct { 40 EnvironmentWhitelist []string `yaml:"environmentWhitelist"` 41 Name string `yaml:"name"` 42 Path string `yaml:"path"` 43 } 44 45 // Config is the struct that defines the Peer configurations. 46 type Config struct { 47 // LocalMSPID is the identifier of the local MSP. 48 LocalMSPID string 49 // ListenAddress is the local address the peer will listen on. It must be 50 // formatted as [host | ipaddr]:port. 51 ListenAddress string 52 // PeerID provides a name for this peer instance. It is used when naming 53 // docker resources to segregate fabric networks and peers. 54 PeerID string 55 // PeerAddress is the address other peers and clients should use to 56 // communicate with the peer. It must be formatted as [host | ipaddr]:port. 57 // When used by the CLI, it represents the target peer endpoint. 58 PeerAddress string 59 // NetworkID specifies a name to use for logical separation of networks. It 60 // is used when naming docker resources to segregate fabric networks and 61 // peers. 62 NetworkID string 63 // ChaincodeListenAddress is the endpoint on which this peer will listen for 64 // chaincode connections. If omitted, it defaults to the host portion of 65 // PeerAddress and port 7052. 66 ChaincodeListenAddress string 67 // ChaincodeAddress specifies the endpoint chaincode launched by the peer 68 // should use to connect to the peer. If omitted, it defaults to 69 // ChaincodeListenAddress and falls back to ListenAddress. 70 ChaincodeAddress string 71 // ValidatorPoolSize indicates the number of goroutines that will execute 72 // transaction validation in parallel. If omitted, it defaults to number of 73 // hardware threads on the machine. 74 ValidatorPoolSize int 75 76 // ----- Peer Delivery Client Keepalive ----- 77 // DeliveryClient Keepalive settings for communication with ordering nodes. 78 DeliverClientKeepaliveOptions comm.KeepaliveOptions 79 80 // ----- Profile ----- 81 // TODO: create separate sub-struct for Profile config. 82 83 // ProfileEnabled determines if the go pprof endpoint is enabled in the peer. 84 ProfileEnabled bool 85 // ProfileListenAddress is the address the pprof server should accept 86 // connections on. 87 ProfileListenAddress string 88 89 // ----- Discovery ----- 90 91 // The discovery service is used by clients to query information about peers, 92 // such as - which peers have joined a certain channel, what is the latest 93 // channel config, and most importantly - given a chaincode and a channel, what 94 // possible sets of peers satisfy the endorsement policy. 95 // TODO: create separate sub-struct for Discovery config. 96 97 // DiscoveryEnabled is used to enable the discovery service. 98 DiscoveryEnabled bool 99 // DiscoveryOrgMembersAllowed allows non-admins to perform non channel-scoped queries. 100 DiscoveryOrgMembersAllowed bool 101 // DiscoveryAuthCacheEnabled is used to enable the authentication cache. 102 DiscoveryAuthCacheEnabled bool 103 // DiscoveryAuthCacheMaxSize sets the maximum size of authentication cache. 104 DiscoveryAuthCacheMaxSize int 105 // DiscoveryAuthCachePurgeRetentionRatio set the proportion of entries remains in cache 106 // after overpopulation purge. 107 DiscoveryAuthCachePurgeRetentionRatio float64 108 109 // ----- Limits ----- 110 // Limits is used to configure some internal resource limits. 111 // TODO: create separate sub-struct for Limits config. 112 113 // LimitsConcurrencyEndorserService sets the limits for concurrent requests sent to 114 // endorser service that handles chaincode deployment, query and invocation, 115 // including both user chaincodes and system chaincodes. 116 LimitsConcurrencyEndorserService int 117 118 // LimitsConcurrencyDeliverService sets the limits for concurrent event listeners 119 // registered to deliver service for blocks and transaction events. 120 LimitsConcurrencyDeliverService int 121 122 // ----- TLS ----- 123 // Require server-side TLS. 124 // TODO: create separate sub-struct for PeerTLS config. 125 126 // PeerTLSEnabled enables/disables Peer TLS. 127 PeerTLSEnabled bool 128 129 // ----- Authentication ----- 130 // Authentication contains configuration parameters related to authenticating 131 // client messages. 132 // TODO: create separate sub-struct for Authentication config. 133 134 // AuthenticationTimeWindow sets the acceptable time duration for current 135 // server time and client's time as specified in a client request message. 136 AuthenticationTimeWindow time.Duration 137 138 // Endpoint of the vm management system. For docker can be one of the following in general 139 // unix:///var/run/docker.sock 140 // http://localhost:2375 141 // https://localhost:2376 142 VMEndpoint string 143 144 // ----- vm.docker.tls ----- 145 // TODO: create separate sub-struct for VM.Docker.TLS config. 146 147 // VMDockerTLSEnabled enables/disables TLS for dockers. 148 VMDockerTLSEnabled bool 149 VMDockerAttachStdout bool 150 // VMNetworkMode sets the networking mode for the container. 151 VMNetworkMode string 152 153 // ChaincodePull enables/disables force pulling of the base docker image. 154 ChaincodePull bool 155 // ExternalBuilders represents the builders and launchers for 156 // chaincode. The external builder detection processing will iterate over the 157 // builders in the order specified below. 158 ExternalBuilders []ExternalBuilder 159 160 // ----- Operations config ----- 161 // TODO: create separate sub-struct for Operations config. 162 163 // OperationsListenAddress provides the host and port for the operations server 164 OperationsListenAddress string 165 // OperationsTLSEnabled enables/disables TLS for operations. 166 OperationsTLSEnabled bool 167 // OperationsTLSCertFile provides the path to PEM encoded server certificate for 168 // the operations server. 169 OperationsTLSCertFile string 170 // OperationsTLSKeyFile provides the path to PEM encoded server key for the 171 // operations server. 172 OperationsTLSKeyFile string 173 // OperationsTLSClientAuthRequired enables/disables the requirements for client 174 // certificate authentication at the TLS layer to access all resource. 175 OperationsTLSClientAuthRequired bool 176 // OperationsTLSClientRootCAs provides the path to PEM encoded ca certiricates to 177 // trust for client authentication. 178 OperationsTLSClientRootCAs []string 179 180 // ----- Metrics config ----- 181 // TODO: create separate sub-struct for Metrics config. 182 183 // MetricsProvider provides the categories of metrics providers, which is one of 184 // statsd, prometheus, or disabled. 185 MetricsProvider string 186 // StatsdNetwork indicate the network type used by statsd metrics. (tcp or udp). 187 StatsdNetwork string 188 // StatsdAaddress provides the address for statsd server. 189 StatsdAaddress string 190 // StatsdWriteInterval set the time interval at which locally cached counters and 191 // gauges are pushed. 192 StatsdWriteInterval time.Duration 193 // StatsdPrefix provides the prefix that prepended to all emitted statsd metrics. 194 StatsdPrefix string 195 196 // ----- Docker config ------ 197 198 // DockerCert is the path to the PEM encoded TLS client certificate required to access 199 // the docker daemon. 200 DockerCert string 201 // DockerKey is the path to the PEM encoded key required to access the docker daemon. 202 DockerKey string 203 // DockerCA is the path to the PEM encoded CA certificate for the docker daemon. 204 DockerCA string 205 } 206 207 // GlobalConfig obtains a set of configuration from viper, build and returns 208 // the config struct. 209 func GlobalConfig() (*Config, error) { 210 c := &Config{} 211 if err := c.load(); err != nil { 212 return nil, err 213 } 214 return c, nil 215 } 216 217 func (c *Config) load() error { 218 preeAddress, err := getLocalAddress() 219 if err != nil { 220 return err 221 } 222 223 configDir := filepath.Dir(viper.ConfigFileUsed()) 224 225 c.PeerAddress = preeAddress 226 c.PeerID = viper.GetString("peer.id") 227 c.LocalMSPID = viper.GetString("peer.localMspId") 228 c.ListenAddress = viper.GetString("peer.listenAddress") 229 230 c.AuthenticationTimeWindow = viper.GetDuration("peer.authentication.timewindow") 231 if c.AuthenticationTimeWindow == 0 { 232 defaultTimeWindow := 15 * time.Minute 233 logger.Warningf("`peer.authentication.timewindow` not set; defaulting to %s", defaultTimeWindow) 234 c.AuthenticationTimeWindow = defaultTimeWindow 235 } 236 237 c.PeerTLSEnabled = viper.GetBool("peer.tls.enabled") 238 c.NetworkID = viper.GetString("peer.networkId") 239 c.LimitsConcurrencyEndorserService = viper.GetInt("peer.limits.concurrency.endorserService") 240 c.LimitsConcurrencyDeliverService = viper.GetInt("peer.limits.concurrency.deliverService") 241 c.DiscoveryEnabled = viper.GetBool("peer.discovery.enabled") 242 c.ProfileEnabled = viper.GetBool("peer.profile.enabled") 243 c.ProfileListenAddress = viper.GetString("peer.profile.listenAddress") 244 c.DiscoveryOrgMembersAllowed = viper.GetBool("peer.discovery.orgMembersAllowedAccess") 245 c.DiscoveryAuthCacheEnabled = viper.GetBool("peer.discovery.authCacheEnabled") 246 c.DiscoveryAuthCacheMaxSize = viper.GetInt("peer.discovery.authCacheMaxSize") 247 c.DiscoveryAuthCachePurgeRetentionRatio = viper.GetFloat64("peer.discovery.authCachePurgeRetentionRatio") 248 c.ChaincodeListenAddress = viper.GetString("peer.chaincodeListenAddress") 249 c.ChaincodeAddress = viper.GetString("peer.chaincodeAddress") 250 251 c.ValidatorPoolSize = viper.GetInt("peer.validatorPoolSize") 252 if c.ValidatorPoolSize <= 0 { 253 c.ValidatorPoolSize = runtime.NumCPU() 254 } 255 256 c.DeliverClientKeepaliveOptions = comm.DefaultKeepaliveOptions 257 if viper.IsSet("peer.keepalive.deliveryClient.interval") { 258 c.DeliverClientKeepaliveOptions.ClientInterval = viper.GetDuration("peer.keepalive.deliveryClient.interval") 259 } 260 if viper.IsSet("peer.keepalive.deliveryClient.timeout") { 261 c.DeliverClientKeepaliveOptions.ClientTimeout = viper.GetDuration("peer.keepalive.deliveryClient.timeout") 262 } 263 264 c.VMEndpoint = viper.GetString("vm.endpoint") 265 c.VMDockerTLSEnabled = viper.GetBool("vm.docker.tls.enabled") 266 c.VMDockerAttachStdout = viper.GetBool("vm.docker.attachStdout") 267 268 c.VMNetworkMode = viper.GetString("vm.docker.hostConfig.NetworkMode") 269 if c.VMNetworkMode == "" { 270 c.VMNetworkMode = "host" 271 } 272 273 c.ChaincodePull = viper.GetBool("chaincode.pull") 274 var externalBuilders []ExternalBuilder 275 err = viper.UnmarshalKey("chaincode.externalBuilders", &externalBuilders) 276 if err != nil { 277 return err 278 } 279 for _, builder := range externalBuilders { 280 if builder.Path == "" { 281 return fmt.Errorf("invalid external builder configuration, path attribute missing in one or more builders") 282 } 283 if builder.Name == "" { 284 return fmt.Errorf("external builder at path %s has no name attribute", builder.Path) 285 } 286 } 287 c.ExternalBuilders = externalBuilders 288 289 c.OperationsListenAddress = viper.GetString("operations.listenAddress") 290 c.OperationsTLSEnabled = viper.GetBool("operations.tls.enabled") 291 c.OperationsTLSCertFile = config.GetPath("operations.tls.cert.file") 292 c.OperationsTLSKeyFile = config.GetPath("operations.tls.key.file") 293 c.OperationsTLSClientAuthRequired = viper.GetBool("operations.tls.clientAuthRequired") 294 295 for _, rca := range viper.GetStringSlice("operations.tls.clientRootCAs.files") { 296 c.OperationsTLSClientRootCAs = append(c.OperationsTLSClientRootCAs, config.TranslatePath(configDir, rca)) 297 } 298 299 c.MetricsProvider = viper.GetString("metrics.provider") 300 c.StatsdNetwork = viper.GetString("metrics.statsd.network") 301 c.StatsdAaddress = viper.GetString("metrics.statsd.address") 302 c.StatsdWriteInterval = viper.GetDuration("metrics.statsd.writeInterval") 303 c.StatsdPrefix = viper.GetString("metrics.statsd.prefix") 304 305 c.DockerCert = config.GetPath("vm.docker.tls.cert.file") 306 c.DockerKey = config.GetPath("vm.docker.tls.key.file") 307 c.DockerCA = config.GetPath("vm.docker.tls.ca.file") 308 309 return nil 310 } 311 312 // getLocalAddress returns the address:port the local peer is operating on. Affected by env:peer.addressAutoDetect 313 func getLocalAddress() (string, error) { 314 peerAddress := viper.GetString("peer.address") 315 if peerAddress == "" { 316 return "", fmt.Errorf("peer.address isn't set") 317 } 318 host, port, err := net.SplitHostPort(peerAddress) 319 if err != nil { 320 return "", errors.Errorf("peer.address isn't in host:port format: %s", peerAddress) 321 } 322 323 localIP, err := comm.GetLocalIP() 324 if err != nil { 325 peerLogger.Errorf("local IP address not auto-detectable: %s", err) 326 return "", err 327 } 328 autoDetectedIPAndPort := net.JoinHostPort(localIP, port) 329 peerLogger.Info("Auto-detected peer address:", autoDetectedIPAndPort) 330 // If host is the IPv4 address "0.0.0.0" or the IPv6 address "::", 331 // then fallback to auto-detected address 332 if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() { 333 peerLogger.Info("Host is", host, ", falling back to auto-detected address:", autoDetectedIPAndPort) 334 return autoDetectedIPAndPort, nil 335 } 336 337 if viper.GetBool("peer.addressAutoDetect") { 338 peerLogger.Info("Auto-detect flag is set, returning", autoDetectedIPAndPort) 339 return autoDetectedIPAndPort, nil 340 } 341 peerLogger.Info("Returning", peerAddress) 342 return peerAddress, nil 343 344 } 345 346 // GetServerConfig returns the gRPC server configuration for the peer 347 func GetServerConfig() (comm.ServerConfig, error) { 348 serverConfig := comm.ServerConfig{ 349 ConnectionTimeout: viper.GetDuration("peer.connectiontimeout"), 350 SecOpts: comm.SecureOptions{ 351 UseTLS: viper.GetBool("peer.tls.enabled"), 352 }, 353 } 354 if serverConfig.SecOpts.UseTLS { 355 // get the certs from the file system 356 serverKey, err := ioutil.ReadFile(config.GetPath("peer.tls.key.file")) 357 if err != nil { 358 return serverConfig, fmt.Errorf("error loading TLS key (%s)", err) 359 } 360 serverCert, err := ioutil.ReadFile(config.GetPath("peer.tls.cert.file")) 361 if err != nil { 362 return serverConfig, fmt.Errorf("error loading TLS certificate (%s)", err) 363 } 364 serverConfig.SecOpts.Certificate = serverCert 365 serverConfig.SecOpts.Key = serverKey 366 serverConfig.SecOpts.RequireClientCert = viper.GetBool("peer.tls.clientAuthRequired") 367 if serverConfig.SecOpts.RequireClientCert { 368 var clientRoots [][]byte 369 for _, file := range viper.GetStringSlice("peer.tls.clientRootCAs.files") { 370 clientRoot, err := ioutil.ReadFile( 371 config.TranslatePath(filepath.Dir(viper.ConfigFileUsed()), file)) 372 if err != nil { 373 return serverConfig, 374 fmt.Errorf("error loading client root CAs (%s)", err) 375 } 376 clientRoots = append(clientRoots, clientRoot) 377 } 378 serverConfig.SecOpts.ClientRootCAs = clientRoots 379 } 380 // check for root cert 381 if config.GetPath("peer.tls.rootcert.file") != "" { 382 rootCert, err := ioutil.ReadFile(config.GetPath("peer.tls.rootcert.file")) 383 if err != nil { 384 return serverConfig, fmt.Errorf("error loading TLS root certificate (%s)", err) 385 } 386 serverConfig.SecOpts.ServerRootCAs = [][]byte{rootCert} 387 } 388 } 389 // get the default keepalive options 390 serverConfig.KaOpts = comm.DefaultKeepaliveOptions 391 // check to see if interval is set for the env 392 if viper.IsSet("peer.keepalive.interval") { 393 serverConfig.KaOpts.ServerInterval = viper.GetDuration("peer.keepalive.interval") 394 } 395 // check to see if timeout is set for the env 396 if viper.IsSet("peer.keepalive.timeout") { 397 serverConfig.KaOpts.ServerTimeout = viper.GetDuration("peer.keepalive.timeout") 398 } 399 // check to see if minInterval is set for the env 400 if viper.IsSet("peer.keepalive.minInterval") { 401 serverConfig.KaOpts.ServerMinInterval = viper.GetDuration("peer.keepalive.minInterval") 402 } 403 return serverConfig, nil 404 } 405 406 // GetClientCertificate returns the TLS certificate to use for gRPC client 407 // connections 408 func GetClientCertificate() (tls.Certificate, error) { 409 cert := tls.Certificate{} 410 411 keyPath := viper.GetString("peer.tls.clientKey.file") 412 certPath := viper.GetString("peer.tls.clientCert.file") 413 414 if keyPath != "" || certPath != "" { 415 // need both keyPath and certPath to be set 416 if keyPath == "" || certPath == "" { 417 return cert, errors.New("peer.tls.clientKey.file and " + 418 "peer.tls.clientCert.file must both be set or must both be empty") 419 } 420 keyPath = config.GetPath("peer.tls.clientKey.file") 421 certPath = config.GetPath("peer.tls.clientCert.file") 422 423 } else { 424 // use the TLS server keypair 425 keyPath = viper.GetString("peer.tls.key.file") 426 certPath = viper.GetString("peer.tls.cert.file") 427 428 if keyPath != "" || certPath != "" { 429 // need both keyPath and certPath to be set 430 if keyPath == "" || certPath == "" { 431 return cert, errors.New("peer.tls.key.file and " + 432 "peer.tls.cert.file must both be set or must both be empty") 433 } 434 keyPath = config.GetPath("peer.tls.key.file") 435 certPath = config.GetPath("peer.tls.cert.file") 436 } else { 437 return cert, errors.New("must set either " + 438 "[peer.tls.key.file and peer.tls.cert.file] or " + 439 "[peer.tls.clientKey.file and peer.tls.clientCert.file]" + 440 "when peer.tls.clientAuthEnabled is set to true") 441 } 442 } 443 // get the keypair from the file system 444 clientKey, err := ioutil.ReadFile(keyPath) 445 if err != nil { 446 return cert, errors.WithMessage(err, 447 "error loading client TLS key") 448 } 449 clientCert, err := ioutil.ReadFile(certPath) 450 if err != nil { 451 return cert, errors.WithMessage(err, 452 "error loading client TLS certificate") 453 } 454 cert, err = tls.X509KeyPair(clientCert, clientKey) 455 if err != nil { 456 return cert, errors.WithMessage(err, 457 "error parsing client TLS key pair") 458 } 459 return cert, nil 460 }