github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+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/comm" 32 "github.com/hyperledger/fabric/core/config" 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 // LimitsConcurrencyQSCC sets the limits for number of concurrently running 114 // qscc system chaincode requests. 115 LimitsConcurrencyQSCC int 116 117 // ----- TLS ----- 118 // Require server-side TLS. 119 // TODO: create separate sub-struct for PeerTLS config. 120 121 // PeerTLSEnabled enables/disables Peer TLS. 122 PeerTLSEnabled bool 123 124 // ----- Authentication ----- 125 // Authentication contains configuration parameters related to authenticating 126 // client messages. 127 // TODO: create separate sub-struct for Authentication config. 128 129 // AuthenticationTimeWindow sets the acceptable time duration for current 130 // server time and client's time as specified in a client request message. 131 AuthenticationTimeWindow time.Duration 132 133 // Endpoint of the vm management system. For docker can be one of the following in general 134 // unix:///var/run/docker.sock 135 // http://localhost:2375 136 // https://localhost:2376 137 VMEndpoint string 138 139 // ----- vm.docker.tls ----- 140 // TODO: create separate sub-struct for VM.Docker.TLS config. 141 142 // VMDockerTLSEnabled enables/disables TLS for dockers. 143 VMDockerTLSEnabled bool 144 VMDockerAttachStdout bool 145 // VMNetworkMode sets the networking mode for the container. 146 VMNetworkMode string 147 148 // ChaincodePull enables/disables force pulling of the base docker image. 149 ChaincodePull bool 150 // ExternalBuilders represents the builders and launchers for 151 // chaincode. The external builder detection processing will iterate over the 152 // builders in the order specified below. 153 ExternalBuilders []ExternalBuilder 154 155 // ----- Operations config ----- 156 // TODO: create separate sub-struct for Operations config. 157 158 // OperationsListenAddress provides the host and port for the operations server 159 OperationsListenAddress string 160 // OperationsTLSEnabled enables/disables TLS for operations. 161 OperationsTLSEnabled bool 162 // OperationsTLSCertFile provides the path to PEM encoded server certificate for 163 // the operations server. 164 OperationsTLSCertFile string 165 // OperationsTLSKeyFile provides the path to PEM encoded server key for the 166 // operations server. 167 OperationsTLSKeyFile string 168 // OperationsTLSClientAuthRequired enables/disables the requirements for client 169 // certificate authentication at the TLS layer to access all resource. 170 OperationsTLSClientAuthRequired bool 171 // OperationsTLSClientRootCAs provides the path to PEM encoded ca certiricates to 172 // trust for client authentication. 173 OperationsTLSClientRootCAs []string 174 175 // ----- Metrics config ----- 176 // TODO: create separate sub-struct for Metrics config. 177 178 // MetricsProvider provides the categories of metrics providers, which is one of 179 // statsd, prometheus, or disabled. 180 MetricsProvider string 181 // StatsdNetwork indicate the network type used by statsd metrics. (tcp or udp). 182 StatsdNetwork string 183 // StatsdAaddress provides the address for statsd server. 184 StatsdAaddress string 185 // StatsdWriteInterval set the time interval at which locally cached counters and 186 // gauges are pushed. 187 StatsdWriteInterval time.Duration 188 // StatsdPrefix provides the prefix that prepended to all emitted statsd metrics. 189 StatsdPrefix string 190 191 // ----- Docker config ------ 192 193 // DockerCert is the path to the PEM encoded TLS client certificate required to access 194 // the docker daemon. 195 DockerCert string 196 // DockerKey is the path to the PEM encoded key required to access the docker daemon. 197 DockerKey string 198 // DockerCA is the path to the PEM encoded CA certificate for the docker daemon. 199 DockerCA string 200 } 201 202 // GlobalConfig obtains a set of configuration from viper, build and returns 203 // the config struct. 204 func GlobalConfig() (*Config, error) { 205 c := &Config{} 206 if err := c.load(); err != nil { 207 return nil, err 208 } 209 return c, nil 210 } 211 212 func (c *Config) load() error { 213 preeAddress, err := getLocalAddress() 214 if err != nil { 215 return err 216 } 217 218 configDir := filepath.Dir(viper.ConfigFileUsed()) 219 220 c.PeerAddress = preeAddress 221 c.PeerID = viper.GetString("peer.id") 222 c.LocalMSPID = viper.GetString("peer.localMspId") 223 c.ListenAddress = viper.GetString("peer.listenAddress") 224 225 c.AuthenticationTimeWindow = viper.GetDuration("peer.authentication.timewindow") 226 if c.AuthenticationTimeWindow == 0 { 227 defaultTimeWindow := 15 * time.Minute 228 logger.Warningf("`peer.authentication.timewindow` not set; defaulting to %s", defaultTimeWindow) 229 c.AuthenticationTimeWindow = defaultTimeWindow 230 } 231 232 c.PeerTLSEnabled = viper.GetBool("peer.tls.enabled") 233 c.NetworkID = viper.GetString("peer.networkId") 234 c.LimitsConcurrencyQSCC = viper.GetInt("peer.limits.concurrency.qscc") 235 c.DiscoveryEnabled = viper.GetBool("peer.discovery.enabled") 236 c.ProfileEnabled = viper.GetBool("peer.profile.enabled") 237 c.ProfileListenAddress = viper.GetString("peer.profile.listenAddress") 238 c.DiscoveryOrgMembersAllowed = viper.GetBool("peer.discovery.orgMembersAllowedAccess") 239 c.DiscoveryAuthCacheEnabled = viper.GetBool("peer.discovery.authCacheEnabled") 240 c.DiscoveryAuthCacheMaxSize = viper.GetInt("peer.discovery.authCacheMaxSize") 241 c.DiscoveryAuthCachePurgeRetentionRatio = viper.GetFloat64("peer.discovery.authCachePurgeRetentionRatio") 242 c.ChaincodeListenAddress = viper.GetString("peer.chaincodeListenAddress") 243 c.ChaincodeAddress = viper.GetString("peer.chaincodeAddress") 244 245 c.ValidatorPoolSize = viper.GetInt("peer.validatorPoolSize") 246 if c.ValidatorPoolSize <= 0 { 247 c.ValidatorPoolSize = runtime.NumCPU() 248 } 249 250 c.DeliverClientKeepaliveOptions = comm.DefaultKeepaliveOptions 251 if viper.IsSet("peer.keepalive.deliveryClient.interval") { 252 c.DeliverClientKeepaliveOptions.ClientInterval = viper.GetDuration("peer.keepalive.deliveryClient.interval") 253 } 254 if viper.IsSet("peer.keepalive.deliveryClient.timeout") { 255 c.DeliverClientKeepaliveOptions.ClientTimeout = viper.GetDuration("peer.keepalive.deliveryClient.timeout") 256 } 257 258 c.VMEndpoint = viper.GetString("vm.endpoint") 259 c.VMDockerTLSEnabled = viper.GetBool("vm.docker.tls.enabled") 260 c.VMDockerAttachStdout = viper.GetBool("vm.docker.attachStdout") 261 262 c.VMNetworkMode = viper.GetString("vm.docker.hostConfig.NetworkMode") 263 if c.VMNetworkMode == "" { 264 c.VMNetworkMode = "host" 265 } 266 267 c.ChaincodePull = viper.GetBool("chaincode.pull") 268 var externalBuilders []ExternalBuilder 269 err = viper.UnmarshalKey("chaincode.externalBuilders", &externalBuilders) 270 if err != nil { 271 return err 272 } 273 for _, builder := range externalBuilders { 274 if builder.Path == "" { 275 return fmt.Errorf("invalid external builder configuration, path attribute missing in one or more builders") 276 } 277 if builder.Name == "" { 278 return fmt.Errorf("external builder at path %s has no name attribute", builder.Path) 279 } 280 } 281 c.ExternalBuilders = externalBuilders 282 283 c.OperationsListenAddress = viper.GetString("operations.listenAddress") 284 c.OperationsTLSEnabled = viper.GetBool("operations.tls.enabled") 285 c.OperationsTLSCertFile = config.GetPath("operations.tls.cert.file") 286 c.OperationsTLSKeyFile = config.GetPath("operations.tls.key.file") 287 c.OperationsTLSClientAuthRequired = viper.GetBool("operations.tls.clientAuthRequired") 288 289 for _, rca := range viper.GetStringSlice("operations.tls.clientRootCAs.files") { 290 c.OperationsTLSClientRootCAs = append(c.OperationsTLSClientRootCAs, config.TranslatePath(configDir, rca)) 291 } 292 293 c.MetricsProvider = viper.GetString("metrics.provider") 294 c.StatsdNetwork = viper.GetString("metrics.statsd.network") 295 c.StatsdAaddress = viper.GetString("metrics.statsd.address") 296 c.StatsdWriteInterval = viper.GetDuration("metrics.statsd.writeInterval") 297 c.StatsdPrefix = viper.GetString("metrics.statsd.prefix") 298 299 c.DockerCert = config.GetPath("vm.docker.tls.cert.file") 300 c.DockerKey = config.GetPath("vm.docker.tls.key.file") 301 c.DockerCA = config.GetPath("vm.docker.tls.ca.file") 302 303 return nil 304 } 305 306 // getLocalAddress returns the address:port the local peer is operating on. Affected by env:peer.addressAutoDetect 307 func getLocalAddress() (string, error) { 308 peerAddress := viper.GetString("peer.address") 309 if peerAddress == "" { 310 return "", fmt.Errorf("peer.address isn't set") 311 } 312 host, port, err := net.SplitHostPort(peerAddress) 313 if err != nil { 314 return "", errors.Errorf("peer.address isn't in host:port format: %s", peerAddress) 315 } 316 317 localIP, err := comm.GetLocalIP() 318 if err != nil { 319 peerLogger.Errorf("local IP address not auto-detectable: %s", err) 320 return "", err 321 } 322 autoDetectedIPAndPort := net.JoinHostPort(localIP, port) 323 peerLogger.Info("Auto-detected peer address:", autoDetectedIPAndPort) 324 // If host is the IPv4 address "0.0.0.0" or the IPv6 address "::", 325 // then fallback to auto-detected address 326 if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() { 327 peerLogger.Info("Host is", host, ", falling back to auto-detected address:", autoDetectedIPAndPort) 328 return autoDetectedIPAndPort, nil 329 } 330 331 if viper.GetBool("peer.addressAutoDetect") { 332 peerLogger.Info("Auto-detect flag is set, returning", autoDetectedIPAndPort) 333 return autoDetectedIPAndPort, nil 334 } 335 peerLogger.Info("Returning", peerAddress) 336 return peerAddress, nil 337 338 } 339 340 // GetServerConfig returns the gRPC server configuration for the peer 341 func GetServerConfig() (comm.ServerConfig, error) { 342 serverConfig := comm.ServerConfig{ 343 ConnectionTimeout: viper.GetDuration("peer.connectiontimeout"), 344 SecOpts: comm.SecureOptions{ 345 UseTLS: viper.GetBool("peer.tls.enabled"), 346 }, 347 } 348 if serverConfig.SecOpts.UseTLS { 349 // get the certs from the file system 350 serverKey, err := ioutil.ReadFile(config.GetPath("peer.tls.key.file")) 351 if err != nil { 352 return serverConfig, fmt.Errorf("error loading TLS key (%s)", err) 353 } 354 serverCert, err := ioutil.ReadFile(config.GetPath("peer.tls.cert.file")) 355 if err != nil { 356 return serverConfig, fmt.Errorf("error loading TLS certificate (%s)", err) 357 } 358 serverConfig.SecOpts.Certificate = serverCert 359 serverConfig.SecOpts.Key = serverKey 360 serverConfig.SecOpts.RequireClientCert = viper.GetBool("peer.tls.clientAuthRequired") 361 if serverConfig.SecOpts.RequireClientCert { 362 var clientRoots [][]byte 363 for _, file := range viper.GetStringSlice("peer.tls.clientRootCAs.files") { 364 clientRoot, err := ioutil.ReadFile( 365 config.TranslatePath(filepath.Dir(viper.ConfigFileUsed()), file)) 366 if err != nil { 367 return serverConfig, 368 fmt.Errorf("error loading client root CAs (%s)", err) 369 } 370 clientRoots = append(clientRoots, clientRoot) 371 } 372 serverConfig.SecOpts.ClientRootCAs = clientRoots 373 } 374 // check for root cert 375 if config.GetPath("peer.tls.rootcert.file") != "" { 376 rootCert, err := ioutil.ReadFile(config.GetPath("peer.tls.rootcert.file")) 377 if err != nil { 378 return serverConfig, fmt.Errorf("error loading TLS root certificate (%s)", err) 379 } 380 serverConfig.SecOpts.ServerRootCAs = [][]byte{rootCert} 381 } 382 } 383 // get the default keepalive options 384 serverConfig.KaOpts = comm.DefaultKeepaliveOptions 385 // check to see if interval is set for the env 386 if viper.IsSet("peer.keepalive.interval") { 387 serverConfig.KaOpts.ServerInterval = viper.GetDuration("peer.keepalive.interval") 388 } 389 // check to see if timeout is set for the env 390 if viper.IsSet("peer.keepalive.timeout") { 391 serverConfig.KaOpts.ServerTimeout = viper.GetDuration("peer.keepalive.timeout") 392 } 393 // check to see if minInterval is set for the env 394 if viper.IsSet("peer.keepalive.minInterval") { 395 serverConfig.KaOpts.ServerMinInterval = viper.GetDuration("peer.keepalive.minInterval") 396 } 397 return serverConfig, nil 398 } 399 400 // GetClientCertificate returns the TLS certificate to use for gRPC client 401 // connections 402 func GetClientCertificate() (tls.Certificate, error) { 403 cert := tls.Certificate{} 404 405 keyPath := viper.GetString("peer.tls.clientKey.file") 406 certPath := viper.GetString("peer.tls.clientCert.file") 407 408 if keyPath != "" || certPath != "" { 409 // need both keyPath and certPath to be set 410 if keyPath == "" || certPath == "" { 411 return cert, errors.New("peer.tls.clientKey.file and " + 412 "peer.tls.clientCert.file must both be set or must both be empty") 413 } 414 keyPath = config.GetPath("peer.tls.clientKey.file") 415 certPath = config.GetPath("peer.tls.clientCert.file") 416 417 } else { 418 // use the TLS server keypair 419 keyPath = viper.GetString("peer.tls.key.file") 420 certPath = viper.GetString("peer.tls.cert.file") 421 422 if keyPath != "" || certPath != "" { 423 // need both keyPath and certPath to be set 424 if keyPath == "" || certPath == "" { 425 return cert, errors.New("peer.tls.key.file and " + 426 "peer.tls.cert.file must both be set or must both be empty") 427 } 428 keyPath = config.GetPath("peer.tls.key.file") 429 certPath = config.GetPath("peer.tls.cert.file") 430 } else { 431 return cert, errors.New("must set either " + 432 "[peer.tls.key.file and peer.tls.cert.file] or " + 433 "[peer.tls.clientKey.file and peer.tls.clientCert.file]" + 434 "when peer.tls.clientAuthEnabled is set to true") 435 } 436 } 437 // get the keypair from the file system 438 clientKey, err := ioutil.ReadFile(keyPath) 439 if err != nil { 440 return cert, errors.WithMessage(err, 441 "error loading client TLS key") 442 } 443 clientCert, err := ioutil.ReadFile(certPath) 444 if err != nil { 445 return cert, errors.WithMessage(err, 446 "error loading client TLS certificate") 447 } 448 cert, err = tls.X509KeyPair(clientCert, clientKey) 449 if err != nil { 450 return cert, errors.WithMessage(err, 451 "error parsing client TLS key pair") 452 } 453 return cert, nil 454 }