github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/integration/nwo/network.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package nwo 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "net" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "runtime" 19 "sort" 20 "strconv" 21 "strings" 22 "syscall" 23 "text/template" 24 "time" 25 26 docker "github.com/fsouza/go-dockerclient" 27 "github.com/osdi23p228/fabric/integration/helpers" 28 "github.com/osdi23p228/fabric/integration/nwo/commands" 29 "github.com/osdi23p228/fabric/integration/nwo/fabricconfig" 30 "github.com/osdi23p228/fabric/integration/runner" 31 "github.com/onsi/ginkgo" 32 . "github.com/onsi/gomega" 33 "github.com/onsi/gomega/gexec" 34 . "github.com/onsi/gomega/gstruct" 35 "github.com/onsi/gomega/matchers" 36 "github.com/onsi/gomega/types" 37 "github.com/tedsuo/ifrit" 38 "github.com/tedsuo/ifrit/ginkgomon" 39 "github.com/tedsuo/ifrit/grouper" 40 "gopkg.in/yaml.v2" 41 ) 42 43 // Organization models information about an Organization. It includes 44 // the information needed to populate an MSP with cryptogen. 45 type Organization struct { 46 MSPID string `yaml:"msp_id,omitempty"` 47 MSPType string `yaml:"msp_type,omitempty"` 48 Name string `yaml:"name,omitempty"` 49 Domain string `yaml:"domain,omitempty"` 50 EnableNodeOUs bool `yaml:"enable_node_organizational_units"` 51 Users int `yaml:"users,omitempty"` 52 CA *CA `yaml:"ca,omitempty"` 53 } 54 55 type CA struct { 56 Hostname string `yaml:"hostname,omitempty"` 57 } 58 59 // A Consortium is a named collection of Organizations. It is used to populate 60 // the Orderer geneesis block profile. 61 type Consortium struct { 62 Name string `yaml:"name,omitempty"` 63 Organizations []string `yaml:"organizations,omitempty"` 64 } 65 66 // Consensus indicates the orderer types and how many broker and zookeeper 67 // instances. 68 type Consensus struct { 69 Type string `yaml:"type,omitempty"` 70 Brokers int `yaml:"brokers,omitempty"` 71 ZooKeepers int `yaml:"zookeepers,omitempty"` 72 } 73 74 // The SystemChannel declares the name of the network system channel and its 75 // associated configtxgen profile name. 76 type SystemChannel struct { 77 Name string `yaml:"name,omitempty"` 78 Profile string `yaml:"profile,omitempty"` 79 } 80 81 // Channel associates a channel name with a configtxgen profile name. 82 type Channel struct { 83 Name string `yaml:"name,omitempty"` 84 Profile string `yaml:"profile,omitempty"` 85 BaseProfile string `yaml:"baseprofile,omitempty"` 86 } 87 88 // Orderer defines an orderer instance and its owning organization. 89 type Orderer struct { 90 Name string `yaml:"name,omitempty"` 91 Organization string `yaml:"organization,omitempty"` 92 } 93 94 // ID provides a unique identifier for an orderer instance. 95 func (o Orderer) ID() string { 96 return fmt.Sprintf("%s.%s", o.Organization, o.Name) 97 } 98 99 // Peer defines a peer instance, it's owning organization, and the list of 100 // channels that the peer should be joined to. 101 type Peer struct { 102 Name string `yaml:"name,omitempty"` 103 DevMode bool `yaml:"devmode,omitempty"` 104 Organization string `yaml:"organization,omitempty"` 105 Channels []*PeerChannel `yaml:"channels,omitempty"` 106 } 107 108 // PeerChannel names of the channel a peer should be joined to and whether or 109 // not the peer should be an anchor for the channel. 110 type PeerChannel struct { 111 Name string `yaml:"name,omitempty"` 112 Anchor bool `yaml:"anchor"` 113 } 114 115 // ID provides a unique identifier for a peer instance. 116 func (p *Peer) ID() string { 117 return fmt.Sprintf("%s.%s", p.Organization, p.Name) 118 } 119 120 // Anchor returns true if this peer is an anchor for any channel it has joined. 121 func (p *Peer) Anchor() bool { 122 for _, c := range p.Channels { 123 if c.Anchor { 124 return true 125 } 126 } 127 return false 128 } 129 130 // A profile encapsulates basic information for a configtxgen profile. 131 type Profile struct { 132 Name string `yaml:"name,omitempty"` 133 Orderers []string `yaml:"orderers,omitempty"` 134 Consortium string `yaml:"consortium,omitempty"` 135 Organizations []string `yaml:"organizations,omitempty"` 136 AppCapabilities []string `yaml:"app_capabilities,omitempty"` 137 ChannelCapabilities []string `yaml:"channel_capabilities,omitempty"` 138 } 139 140 // Network holds information about a fabric network. 141 type Network struct { 142 RootDir string 143 StartPort uint16 144 Components *Components 145 DockerClient *docker.Client 146 ExternalBuilders []fabricconfig.ExternalBuilder 147 NetworkID string 148 EventuallyTimeout time.Duration 149 SessionCreateInterval time.Duration 150 MetricsProvider string 151 StatsdEndpoint string 152 ClientAuthRequired bool 153 ChannelParticipationEnabled bool 154 TLSEnabled bool 155 156 PortsByBrokerID map[string]Ports 157 PortsByOrdererID map[string]Ports 158 PortsByPeerID map[string]Ports 159 Organizations []*Organization 160 SystemChannel *SystemChannel 161 Channels []*Channel 162 Consensus *Consensus 163 Orderers []*Orderer 164 Peers []*Peer 165 Profiles []*Profile 166 Consortiums []*Consortium 167 Templates *Templates 168 169 colorIndex uint 170 sessLastExecuted map[string]time.Time 171 } 172 173 // New creates a Network from a simple configuration. All generated or managed 174 // artifacts for the network will be located under rootDir. Ports will be 175 // allocated sequentially from the specified startPort. 176 func New(c *Config, rootDir string, client *docker.Client, startPort int, components *Components) *Network { 177 network := &Network{ 178 StartPort: uint16(startPort), 179 RootDir: rootDir, 180 Components: components, 181 DockerClient: client, 182 183 NetworkID: helpers.UniqueName(), 184 EventuallyTimeout: time.Minute, 185 MetricsProvider: "prometheus", 186 PortsByBrokerID: map[string]Ports{}, 187 PortsByOrdererID: map[string]Ports{}, 188 PortsByPeerID: map[string]Ports{}, 189 190 Organizations: c.Organizations, 191 Consensus: c.Consensus, 192 Orderers: c.Orderers, 193 Peers: c.Peers, 194 SystemChannel: c.SystemChannel, 195 Channels: c.Channels, 196 Profiles: c.Profiles, 197 Consortiums: c.Consortiums, 198 Templates: c.Templates, 199 TLSEnabled: true, // Set TLS enabled as true for default 200 201 sessLastExecuted: make(map[string]time.Time), 202 } 203 204 cwd, err := os.Getwd() 205 Expect(err).NotTo(HaveOccurred()) 206 network.ExternalBuilders = []fabricconfig.ExternalBuilder{{ 207 Path: filepath.Join(cwd, "..", "externalbuilders", "binary"), 208 Name: "binary", 209 PropagateEnvironment: []string{"GOPROXY"}, 210 }} 211 212 if network.Templates == nil { 213 network.Templates = &Templates{} 214 } 215 if network.SessionCreateInterval == 0 { 216 network.SessionCreateInterval = time.Second 217 } 218 219 for i := 0; i < network.Consensus.Brokers; i++ { 220 ports := Ports{} 221 for _, portName := range BrokerPortNames() { 222 ports[portName] = network.ReservePort() 223 } 224 network.PortsByBrokerID[strconv.Itoa(i)] = ports 225 } 226 227 for _, o := range c.Orderers { 228 ports := Ports{} 229 for _, portName := range OrdererPortNames() { 230 ports[portName] = network.ReservePort() 231 } 232 network.PortsByOrdererID[o.ID()] = ports 233 } 234 235 for _, p := range c.Peers { 236 ports := Ports{} 237 for _, portName := range PeerPortNames() { 238 ports[portName] = network.ReservePort() 239 } 240 network.PortsByPeerID[p.ID()] = ports 241 } 242 return network 243 } 244 245 // AddOrg adds an organization to a network. 246 func (n *Network) AddOrg(o *Organization, peers ...*Peer) { 247 for _, p := range peers { 248 ports := Ports{} 249 for _, portName := range PeerPortNames() { 250 ports[portName] = n.ReservePort() 251 } 252 n.PortsByPeerID[p.ID()] = ports 253 n.Peers = append(n.Peers, p) 254 } 255 256 n.Organizations = append(n.Organizations, o) 257 n.Consortiums[0].Organizations = append(n.Consortiums[0].Organizations, o.Name) 258 } 259 260 // ConfigTxPath returns the path to the generated configtxgen configuration 261 // file. 262 func (n *Network) ConfigTxConfigPath() string { 263 return filepath.Join(n.RootDir, "configtx.yaml") 264 } 265 266 // CryptoPath returns the path to the directory where cryptogen will place its 267 // generated artifacts. 268 func (n *Network) CryptoPath() string { 269 return filepath.Join(n.RootDir, "crypto") 270 } 271 272 // CryptoConfigPath returns the path to the generated cryptogen configuration 273 // file. 274 func (n *Network) CryptoConfigPath() string { 275 return filepath.Join(n.RootDir, "crypto-config.yaml") 276 } 277 278 // OutputBlockPath returns the path to the genesis block for the named system 279 // channel. 280 func (n *Network) OutputBlockPath(channelName string) string { 281 return filepath.Join(n.RootDir, fmt.Sprintf("%s_block.pb", channelName)) 282 } 283 284 // CreateChannelTxPath returns the path to the create channel transaction for 285 // the named channel. 286 func (n *Network) CreateChannelTxPath(channelName string) string { 287 return filepath.Join(n.RootDir, fmt.Sprintf("%s_tx.pb", channelName)) 288 } 289 290 // OrdererDir returns the path to the configuration directory for the specified 291 // Orderer. 292 func (n *Network) OrdererDir(o *Orderer) string { 293 return filepath.Join(n.RootDir, "orderers", o.ID()) 294 } 295 296 // OrdererConfigPath returns the path to the orderer configuration document for 297 // the specified Orderer. 298 func (n *Network) OrdererConfigPath(o *Orderer) string { 299 return filepath.Join(n.OrdererDir(o), "orderer.yaml") 300 } 301 302 // ReadOrdererConfig unmarshals an orderer's orderer.yaml and returns an 303 // object approximating its contents. 304 func (n *Network) ReadOrdererConfig(o *Orderer) *fabricconfig.Orderer { 305 var orderer fabricconfig.Orderer 306 ordererBytes, err := ioutil.ReadFile(n.OrdererConfigPath(o)) 307 Expect(err).NotTo(HaveOccurred()) 308 309 err = yaml.Unmarshal(ordererBytes, &orderer) 310 Expect(err).NotTo(HaveOccurred()) 311 312 return &orderer 313 } 314 315 // WriteOrdererConfig serializes the provided configuration as the specified 316 // orderer's orderer.yaml document. 317 func (n *Network) WriteOrdererConfig(o *Orderer, config *fabricconfig.Orderer) { 318 ordererBytes, err := yaml.Marshal(config) 319 Expect(err).NotTo(HaveOccurred()) 320 321 err = ioutil.WriteFile(n.OrdererConfigPath(o), ordererBytes, 0644) 322 Expect(err).NotTo(HaveOccurred()) 323 } 324 325 // ReadConfigTxConfig unmarshals the configtx.yaml and returns an 326 // object approximating its contents. 327 func (n *Network) ReadConfigTxConfig() *fabricconfig.ConfigTx { 328 var configtx fabricconfig.ConfigTx 329 configtxBytes, err := ioutil.ReadFile(n.ConfigTxConfigPath()) 330 Expect(err).NotTo(HaveOccurred()) 331 332 err = yaml.Unmarshal(configtxBytes, &configtx) 333 Expect(err).NotTo(HaveOccurred()) 334 335 return &configtx 336 } 337 338 // WriteConfigTxConfig serializes the provided configuration to configtx.yaml. 339 func (n *Network) WriteConfigTxConfig(config *fabricconfig.ConfigTx) { 340 configtxBytes, err := yaml.Marshal(config) 341 Expect(err).NotTo(HaveOccurred()) 342 343 err = ioutil.WriteFile(n.ConfigTxConfigPath(), configtxBytes, 0644) 344 Expect(err).NotTo(HaveOccurred()) 345 } 346 347 // PeerDir returns the path to the configuration directory for the specified 348 // Peer. 349 func (n *Network) PeerDir(p *Peer) string { 350 return filepath.Join(n.RootDir, "peers", p.ID()) 351 } 352 353 // PeerConfigPath returns the path to the peer configuration document for the 354 // specified peer. 355 func (n *Network) PeerConfigPath(p *Peer) string { 356 return filepath.Join(n.PeerDir(p), "core.yaml") 357 } 358 359 // PeerLedgerDir returns the ledger root directory for the specified peer. 360 func (n *Network) PeerLedgerDir(p *Peer) string { 361 return filepath.Join(n.PeerDir(p), "filesystem/ledgersData") 362 } 363 364 // ReadPeerConfig unmarshals a peer's core.yaml and returns an object 365 // approximating its contents. 366 func (n *Network) ReadPeerConfig(p *Peer) *fabricconfig.Core { 367 var core fabricconfig.Core 368 coreBytes, err := ioutil.ReadFile(n.PeerConfigPath(p)) 369 Expect(err).NotTo(HaveOccurred()) 370 371 err = yaml.Unmarshal(coreBytes, &core) 372 Expect(err).NotTo(HaveOccurred()) 373 374 return &core 375 } 376 377 // WritePeerConfig serializes the provided configuration as the specified 378 // peer's core.yaml document. 379 func (n *Network) WritePeerConfig(p *Peer, config *fabricconfig.Core) { 380 coreBytes, err := yaml.Marshal(config) 381 Expect(err).NotTo(HaveOccurred()) 382 383 err = ioutil.WriteFile(n.PeerConfigPath(p), coreBytes, 0644) 384 Expect(err).NotTo(HaveOccurred()) 385 } 386 387 // peerUserCryptoDir returns the path to the directory containing the 388 // certificates and keys for the specified user of the peer. 389 func (n *Network) peerUserCryptoDir(p *Peer, user, cryptoMaterialType string) string { 390 org := n.Organization(p.Organization) 391 Expect(org).NotTo(BeNil()) 392 393 return n.userCryptoDir(org, "peerOrganizations", user, cryptoMaterialType) 394 } 395 396 // ordererUserCryptoDir returns the path to the directory containing the 397 // certificates and keys for the specified user of the orderer. 398 func (n *Network) ordererUserCryptoDir(o *Orderer, user, cryptoMaterialType string) string { 399 org := n.Organization(o.Organization) 400 Expect(org).NotTo(BeNil()) 401 402 return n.userCryptoDir(org, "ordererOrganizations", user, cryptoMaterialType) 403 } 404 405 // userCryptoDir returns the path to the folder with crypto materials for either peers or orderer organizations 406 // specific user 407 func (n *Network) userCryptoDir(org *Organization, nodeOrganizationType, user, cryptoMaterialType string) string { 408 return filepath.Join( 409 n.RootDir, 410 "crypto", 411 nodeOrganizationType, 412 org.Domain, 413 "users", 414 fmt.Sprintf("%s@%s", user, org.Domain), 415 cryptoMaterialType, 416 ) 417 } 418 419 // PeerOrgCADir returns the path to the folder containing the CA certificate(s) and/or 420 // keys for the specified peer organization. 421 func (n *Network) PeerOrgCADir(o *Organization) string { 422 return filepath.Join( 423 n.CryptoPath(), 424 "peerOrganizations", 425 o.Domain, 426 "ca", 427 ) 428 } 429 430 // OrdererOrgCADir returns the path to the folder containing the CA certificate(s) and/or 431 // keys for the specified orderer organization. 432 func (n *Network) OrdererOrgCADir(o *Organization) string { 433 return filepath.Join( 434 n.CryptoPath(), 435 "ordererOrganizations", 436 o.Domain, 437 "ca", 438 ) 439 } 440 441 // PeerUserMSPDir returns the path to the MSP directory containing the 442 // certificates and keys for the specified user of the peer. 443 func (n *Network) PeerUserMSPDir(p *Peer, user string) string { 444 return n.peerUserCryptoDir(p, user, "msp") 445 } 446 447 // IdemixUserMSPDir returns the path to the MSP directory containing the 448 // idemix-related crypto material for the specified user of the organization. 449 func (n *Network) IdemixUserMSPDir(o *Organization, user string) string { 450 return n.userCryptoDir(o, "peerOrganizations", user, "") 451 } 452 453 // OrdererUserMSPDir returns the path to the MSP directory containing the 454 // certificates and keys for the specified user of the peer. 455 func (n *Network) OrdererUserMSPDir(o *Orderer, user string) string { 456 return n.ordererUserCryptoDir(o, user, "msp") 457 } 458 459 // PeerUserTLSDir returns the path to the TLS directory containing the 460 // certificates and keys for the specified user of the peer. 461 func (n *Network) PeerUserTLSDir(p *Peer, user string) string { 462 return n.peerUserCryptoDir(p, user, "tls") 463 } 464 465 // PeerUserCert returns the path to the certificate for the specified user in 466 // the peer organization. 467 func (n *Network) PeerUserCert(p *Peer, user string) string { 468 org := n.Organization(p.Organization) 469 Expect(org).NotTo(BeNil()) 470 471 return filepath.Join( 472 n.PeerUserMSPDir(p, user), 473 "signcerts", 474 fmt.Sprintf("%s@%s-cert.pem", user, org.Domain), 475 ) 476 } 477 478 // OrdererUserCert returns the path to the certificate for the specified user in 479 // the orderer organization. 480 func (n *Network) OrdererUserCert(o *Orderer, user string) string { 481 org := n.Organization(o.Organization) 482 Expect(org).NotTo(BeNil()) 483 484 return filepath.Join( 485 n.OrdererUserMSPDir(o, user), 486 "signcerts", 487 fmt.Sprintf("%s@%s-cert.pem", user, org.Domain), 488 ) 489 } 490 491 // PeerUserKey returns the path to the private key for the specified user in 492 // the peer organization. 493 func (n *Network) PeerUserKey(p *Peer, user string) string { 494 org := n.Organization(p.Organization) 495 Expect(org).NotTo(BeNil()) 496 497 keystore := filepath.Join( 498 n.PeerUserMSPDir(p, user), 499 "keystore", 500 ) 501 502 // file names are the SKI and non-deterministic 503 keys, err := ioutil.ReadDir(keystore) 504 Expect(err).NotTo(HaveOccurred()) 505 Expect(keys).To(HaveLen(1)) 506 507 return filepath.Join(keystore, keys[0].Name()) 508 } 509 510 // OrdererUserKey returns the path to the private key for the specified user in 511 // the orderer organization. 512 func (n *Network) OrdererUserKey(o *Orderer, user string) string { 513 org := n.Organization(o.Organization) 514 Expect(org).NotTo(BeNil()) 515 516 keystore := filepath.Join( 517 n.OrdererUserMSPDir(o, user), 518 "keystore", 519 ) 520 521 // file names are the SKI and non-deterministic 522 keys, err := ioutil.ReadDir(keystore) 523 Expect(err).NotTo(HaveOccurred()) 524 Expect(keys).To(HaveLen(1)) 525 526 return filepath.Join(keystore, keys[0].Name()) 527 } 528 529 // peerLocalCryptoDir returns the path to the local crypto directory for the peer. 530 func (n *Network) peerLocalCryptoDir(p *Peer, cryptoType string) string { 531 org := n.Organization(p.Organization) 532 Expect(org).NotTo(BeNil()) 533 534 return filepath.Join( 535 n.RootDir, 536 "crypto", 537 "peerOrganizations", 538 org.Domain, 539 "peers", 540 fmt.Sprintf("%s.%s", p.Name, org.Domain), 541 cryptoType, 542 ) 543 } 544 545 // PeerLocalMSPDir returns the path to the local MSP directory for the peer. 546 func (n *Network) PeerLocalMSPDir(p *Peer) string { 547 return n.peerLocalCryptoDir(p, "msp") 548 } 549 550 // PeerLocalTLSDir returns the path to the local TLS directory for the peer. 551 func (n *Network) PeerLocalTLSDir(p *Peer) string { 552 return n.peerLocalCryptoDir(p, "tls") 553 } 554 555 // PeerCert returns the path to the peer's certificate. 556 func (n *Network) PeerCert(p *Peer) string { 557 org := n.Organization(p.Organization) 558 Expect(org).NotTo(BeNil()) 559 560 return filepath.Join( 561 n.PeerLocalMSPDir(p), 562 "signcerts", 563 fmt.Sprintf("%s.%s-cert.pem", p.Name, org.Domain), 564 ) 565 } 566 567 // PeerOrgMSPDir returns the path to the MSP directory of the Peer organization. 568 func (n *Network) PeerOrgMSPDir(org *Organization) string { 569 return filepath.Join( 570 n.RootDir, 571 "crypto", 572 "peerOrganizations", 573 org.Domain, 574 "msp", 575 ) 576 } 577 578 func (n *Network) IdemixOrgMSPDir(org *Organization) string { 579 return filepath.Join( 580 n.RootDir, 581 "crypto", 582 "peerOrganizations", 583 org.Domain, 584 ) 585 } 586 587 // OrdererOrgMSPDir returns the path to the MSP directory of the Orderer 588 // organization. 589 func (n *Network) OrdererOrgMSPDir(o *Organization) string { 590 return filepath.Join( 591 n.RootDir, 592 "crypto", 593 "ordererOrganizations", 594 o.Domain, 595 "msp", 596 ) 597 } 598 599 // OrdererLocalCryptoDir returns the path to the local crypto directory for the 600 // Orderer. 601 func (n *Network) OrdererLocalCryptoDir(o *Orderer, cryptoType string) string { 602 org := n.Organization(o.Organization) 603 Expect(org).NotTo(BeNil()) 604 605 return filepath.Join( 606 n.RootDir, 607 "crypto", 608 "ordererOrganizations", 609 org.Domain, 610 "orderers", 611 fmt.Sprintf("%s.%s", o.Name, org.Domain), 612 cryptoType, 613 ) 614 } 615 616 // OrdererLocalMSPDir returns the path to the local MSP directory for the 617 // Orderer. 618 func (n *Network) OrdererLocalMSPDir(o *Orderer) string { 619 return n.OrdererLocalCryptoDir(o, "msp") 620 } 621 622 // OrdererLocalTLSDir returns the path to the local TLS directory for the 623 // Orderer. 624 func (n *Network) OrdererLocalTLSDir(o *Orderer) string { 625 return n.OrdererLocalCryptoDir(o, "tls") 626 } 627 628 // ProfileForChannel gets the configtxgen profile name associated with the 629 // specified channel. 630 func (n *Network) ProfileForChannel(channelName string) string { 631 for _, ch := range n.Channels { 632 if ch.Name == channelName { 633 return ch.Profile 634 } 635 } 636 return "" 637 } 638 639 // CACertsBundlePath returns the path to the bundle of CA certificates for the 640 // network. This bundle is used when connecting to peers. 641 func (n *Network) CACertsBundlePath() string { 642 return filepath.Join( 643 n.RootDir, 644 "crypto", 645 "ca-certs.pem", 646 ) 647 } 648 649 // GenerateConfigTree generates the configuration documents required to 650 // bootstrap a fabric network. A configuration file will be generated for 651 // cryptogen, configtxgen, and for each peer and orderer. The contents of the 652 // documents will be based on the Config used to create the Network. 653 // 654 // When this method completes, the resulting tree will look something like 655 // this: 656 // 657 // ${rootDir}/configtx.yaml 658 // ${rootDir}/crypto-config.yaml 659 // ${rootDir}/orderers/orderer0.orderer-org/orderer.yaml 660 // ${rootDir}/peers/peer0.org1/core.yaml 661 // ${rootDir}/peers/peer0.org2/core.yaml 662 // ${rootDir}/peers/peer1.org1/core.yaml 663 // ${rootDir}/peers/peer1.org2/core.yaml 664 // 665 func (n *Network) GenerateConfigTree() { 666 n.GenerateCryptoConfig() 667 n.GenerateConfigTxConfig() 668 for _, o := range n.Orderers { 669 n.GenerateOrdererConfig(o) 670 } 671 for _, p := range n.Peers { 672 n.GenerateCoreConfig(p) 673 } 674 } 675 676 // Bootstrap generates the cryptographic material, orderer system channel 677 // genesis block, and create channel transactions needed to run a fabric 678 // network. 679 // 680 // The cryptogen tool is used to create crypto material from the contents of 681 // ${rootDir}/crypto-config.yaml. The generated artifacts will be placed in 682 // ${rootDir}/crypto/... 683 // 684 // The gensis block is generated from the profile referenced by the 685 // SystemChannel.Profile attribute. The block is written to 686 // ${rootDir}/${SystemChannel.Name}_block.pb. 687 // 688 // The create channel transactions are generated for each Channel referenced by 689 // the Network using the channel's Profile attribute. The transactions are 690 // written to ${rootDir}/${Channel.Name}_tx.pb. 691 func (n *Network) Bootstrap() { 692 if n.DockerClient != nil { 693 n.CreateDockerNetwork() 694 } 695 696 sess, err := n.Cryptogen(commands.Generate{ 697 Config: n.CryptoConfigPath(), 698 Output: n.CryptoPath(), 699 }) 700 Expect(err).NotTo(HaveOccurred()) 701 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 702 703 n.bootstrapIdemix() 704 705 sess, err = n.ConfigTxGen(commands.OutputBlock{ 706 ChannelID: n.SystemChannel.Name, 707 Profile: n.SystemChannel.Profile, 708 ConfigPath: n.RootDir, 709 OutputBlock: n.OutputBlockPath(n.SystemChannel.Name), 710 }) 711 Expect(err).NotTo(HaveOccurred()) 712 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 713 714 for _, c := range n.Channels { 715 sess, err := n.ConfigTxGen(commands.CreateChannelTx{ 716 ChannelID: c.Name, 717 Profile: c.Profile, 718 BaseProfile: c.BaseProfile, 719 ConfigPath: n.RootDir, 720 OutputCreateChannelTx: n.CreateChannelTxPath(c.Name), 721 }) 722 Expect(err).NotTo(HaveOccurred()) 723 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 724 } 725 726 n.ConcatenateTLSCACertificates() 727 } 728 729 func (n *Network) CreateDockerNetwork() { 730 _, err := n.DockerClient.CreateNetwork( 731 docker.CreateNetworkOptions{ 732 Name: n.NetworkID, 733 Driver: "bridge", 734 }, 735 ) 736 Expect(err).NotTo(HaveOccurred()) 737 738 if runtime.GOOS == "darwin" { 739 n.checkDockerNetworks() 740 } 741 } 742 743 // checkDockerNetworks attempts to discover if the docker network configuration 744 // will prevent a container from accessing the host. This commonly happens when 745 // using Docker for Mac on home networks because most home routers provide DHCP 746 // addresses from 192.168.1.0/24 and the default Docker daemon config uses 747 // 192.168.0.0/20 as one of the default local address pools. 748 // 749 // https://github.com/moby/libnetwork/blob/1a17fb36132631a95fe6bb055b91e24a516ad81d/ipamutils/utils.go#L18-L20 750 // 751 // Docker can be configured to use different addresses by adding an 752 // appropriate default-address-pools configuration element to "daemon.json". 753 // 754 // For example: 755 // "default-address-pools":[ 756 // {"base":"172.30.0.0/16","size":24}, 757 // {"base":"172.31.0.0/16","size":24} 758 // ] 759 func (n *Network) checkDockerNetworks() { 760 hostAddrs := hostIPv4Addrs() 761 for _, nw := range n.dockerIPNets() { 762 for _, a := range hostAddrs { 763 if nw.Contains(a) { 764 fmt.Fprintf(ginkgo.GinkgoWriter, "\x1b[01;37;41mWARNING: docker network %s overlaps with host address %s.\x1b[0m\n", nw, a) 765 fmt.Fprintf(ginkgo.GinkgoWriter, "\x1b[01;37;41mDocker containers may not have connectivity causing chaincode registration to fail with 'no route to host'.\x1b[0m\n") 766 } 767 } 768 } 769 } 770 771 func (n *Network) dockerIPNets() []*net.IPNet { 772 dockerNetworks, err := n.DockerClient.ListNetworks() 773 Expect(err).NotTo(HaveOccurred()) 774 775 var nets []*net.IPNet 776 for _, nw := range dockerNetworks { 777 for _, ipconf := range nw.IPAM.Config { 778 if ipconf.Subnet != "" { 779 _, ipn, err := net.ParseCIDR(ipconf.Subnet) 780 Expect(err).NotTo(HaveOccurred()) 781 nets = append(nets, ipn) 782 } 783 } 784 } 785 return nets 786 } 787 788 func hostIPv4Addrs() []net.IP { 789 interfaces, err := net.Interfaces() 790 Expect(err).NotTo(HaveOccurred()) 791 792 var addresses []net.IP 793 for _, i := range interfaces { 794 addrs, err := i.Addrs() 795 Expect(err).NotTo(HaveOccurred()) 796 797 for _, a := range addrs { 798 a := a 799 switch v := a.(type) { 800 case *net.IPAddr: 801 if v.IP.To4() != nil { 802 addresses = append(addresses, v.IP) 803 } 804 case *net.IPNet: 805 if v.IP.To4() != nil { 806 addresses = append(addresses, v.IP) 807 } 808 } 809 } 810 } 811 return addresses 812 } 813 814 // bootstrapIdemix creates the idemix-related crypto material 815 func (n *Network) bootstrapIdemix() { 816 for j, org := range n.IdemixOrgs() { 817 818 output := n.IdemixOrgMSPDir(org) 819 // - ca-keygen 820 sess, err := n.Idemixgen(commands.CAKeyGen{ 821 Output: output, 822 }) 823 Expect(err).NotTo(HaveOccurred()) 824 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 825 826 // - signerconfig 827 usersOutput := filepath.Join(n.IdemixOrgMSPDir(org), "users") 828 userOutput := filepath.Join(usersOutput, fmt.Sprintf("User%d@%s", 1, org.Domain)) 829 sess, err = n.Idemixgen(commands.SignerConfig{ 830 CAInput: output, 831 Output: userOutput, 832 OrgUnit: org.Domain, 833 EnrollmentID: "User" + string(1), 834 RevocationHandle: fmt.Sprintf("1%d%d", 1, j), 835 }) 836 Expect(err).NotTo(HaveOccurred()) 837 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 838 } 839 } 840 841 // ConcatenateTLSCACertificates concatenates all TLS CA certificates into a 842 // single file to be used by peer CLI. 843 func (n *Network) ConcatenateTLSCACertificates() { 844 bundle := &bytes.Buffer{} 845 for _, tlsCertPath := range n.listTLSCACertificates() { 846 certBytes, err := ioutil.ReadFile(tlsCertPath) 847 Expect(err).NotTo(HaveOccurred()) 848 bundle.Write(certBytes) 849 } 850 err := ioutil.WriteFile(n.CACertsBundlePath(), bundle.Bytes(), 0660) 851 Expect(err).NotTo(HaveOccurred()) 852 } 853 854 // listTLSCACertificates returns the paths of all TLS CA certificates in the 855 // network, across all organizations. 856 func (n *Network) listTLSCACertificates() []string { 857 fileName2Path := make(map[string]string) 858 filepath.Walk(filepath.Join(n.RootDir, "crypto"), func(path string, info os.FileInfo, err error) error { 859 // File starts with "tlsca" and has "-cert.pem" in it 860 if strings.HasPrefix(info.Name(), "tlsca") && strings.Contains(info.Name(), "-cert.pem") { 861 fileName2Path[info.Name()] = path 862 } 863 return nil 864 }) 865 866 var tlsCACertificates []string 867 for _, path := range fileName2Path { 868 tlsCACertificates = append(tlsCACertificates, path) 869 } 870 return tlsCACertificates 871 } 872 873 // Cleanup attempts to cleanup docker related artifacts that may 874 // have been created by the network. 875 func (n *Network) Cleanup() { 876 if n == nil || n.DockerClient == nil { 877 return 878 } 879 880 nw, err := n.DockerClient.NetworkInfo(n.NetworkID) 881 Expect(err).NotTo(HaveOccurred()) 882 883 err = n.DockerClient.RemoveNetwork(nw.ID) 884 Expect(err).NotTo(HaveOccurred()) 885 886 containers, err := n.DockerClient.ListContainers(docker.ListContainersOptions{All: true}) 887 Expect(err).NotTo(HaveOccurred()) 888 for _, c := range containers { 889 for _, name := range c.Names { 890 if strings.HasPrefix(name, "/"+n.NetworkID) { 891 err := n.DockerClient.RemoveContainer(docker.RemoveContainerOptions{ID: c.ID, Force: true}) 892 Expect(err).NotTo(HaveOccurred()) 893 break 894 } 895 } 896 } 897 898 images, err := n.DockerClient.ListImages(docker.ListImagesOptions{All: true}) 899 Expect(err).NotTo(HaveOccurred()) 900 for _, i := range images { 901 for _, tag := range i.RepoTags { 902 if strings.HasPrefix(tag, n.NetworkID) { 903 err := n.DockerClient.RemoveImage(i.ID) 904 Expect(err).NotTo(HaveOccurred()) 905 break 906 } 907 } 908 } 909 } 910 911 // CreateAndJoinChannels will create all channels specified in the config that 912 // are referenced by peers. The referencing peers will then be joined to the 913 // channel(s). 914 // 915 // The network must be running before this is called. 916 func (n *Network) CreateAndJoinChannels(o *Orderer) { 917 for _, c := range n.Channels { 918 n.CreateAndJoinChannel(o, c.Name) 919 } 920 } 921 922 // CreateAndJoinChannel will create the specified channel. The referencing 923 // peers will then be joined to the channel. 924 // 925 // The network must be running before this is called. 926 func (n *Network) CreateAndJoinChannel(o *Orderer, channelName string) { 927 peers := n.PeersWithChannel(channelName) 928 if len(peers) == 0 { 929 return 930 } 931 932 n.CreateChannel(channelName, o, peers[0]) 933 n.JoinChannel(channelName, o, peers...) 934 } 935 936 // UpdateChannelAnchors determines the anchor peers for the specified channel, 937 // creates an anchor peer update transaction for each organization, and submits 938 // the update transactions to the orderer. 939 func (n *Network) UpdateChannelAnchors(o *Orderer, channelName string) { 940 tempFile, err := ioutil.TempFile("", "update-anchors") 941 Expect(err).NotTo(HaveOccurred()) 942 tempFile.Close() 943 defer os.Remove(tempFile.Name()) 944 945 peersByOrg := map[string]*Peer{} 946 for _, p := range n.AnchorsForChannel(channelName) { 947 peersByOrg[p.Organization] = p 948 } 949 950 for orgName, p := range peersByOrg { 951 anchorUpdate := commands.OutputAnchorPeersUpdate{ 952 OutputAnchorPeersUpdate: tempFile.Name(), 953 ChannelID: channelName, 954 Profile: n.ProfileForChannel(channelName), 955 ConfigPath: n.RootDir, 956 AsOrg: orgName, 957 } 958 sess, err := n.ConfigTxGen(anchorUpdate) 959 Expect(err).NotTo(HaveOccurred()) 960 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 961 962 sess, err = n.PeerAdminSession(p, commands.ChannelUpdate{ 963 ChannelID: channelName, 964 Orderer: n.OrdererAddress(o, ListenPort), 965 File: tempFile.Name(), 966 ClientAuth: n.ClientAuthRequired, 967 }) 968 Expect(err).NotTo(HaveOccurred()) 969 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 970 } 971 } 972 973 // VerifyMembership checks that each peer has discovered the expected peers in 974 // the network. 975 func (n *Network) VerifyMembership(expectedPeers []*Peer, channel string, chaincodes ...string) { 976 // all peers currently include _lifecycle as an available chaincode 977 chaincodes = append(chaincodes, "_lifecycle") 978 expectedDiscoveredPeerMatchers := make([]types.GomegaMatcher, len(expectedPeers)) 979 for i, peer := range expectedPeers { 980 expectedDiscoveredPeerMatchers[i] = n.DiscoveredPeerMatcher(peer, chaincodes...) 981 } 982 for _, peer := range expectedPeers { 983 Eventually(DiscoverPeers(n, peer, "User1", channel), n.EventuallyTimeout).Should(ConsistOf(expectedDiscoveredPeerMatchers)) 984 } 985 } 986 987 // CreateChannel will submit an existing create channel transaction to the 988 // specified orderer. The channel transaction must exist at the location 989 // returned by CreateChannelTxPath. Optionally, additional signers may be 990 // included in the case where the channel creation tx modifies other aspects of 991 // the channel config for the new channel. 992 // 993 // The orderer must be running when this is called. 994 func (n *Network) CreateChannel(channelName string, o *Orderer, p *Peer, additionalSigners ...interface{}) { 995 channelCreateTxPath := n.CreateChannelTxPath(channelName) 996 n.signConfigTransaction(channelCreateTxPath, p, additionalSigners...) 997 998 createChannel := func() int { 999 sess, err := n.PeerAdminSession(p, commands.ChannelCreate{ 1000 ChannelID: channelName, 1001 Orderer: n.OrdererAddress(o, ListenPort), 1002 File: channelCreateTxPath, 1003 OutputBlock: "/dev/null", 1004 ClientAuth: n.ClientAuthRequired, 1005 }) 1006 Expect(err).NotTo(HaveOccurred()) 1007 return sess.Wait(n.EventuallyTimeout).ExitCode() 1008 } 1009 Eventually(createChannel, n.EventuallyTimeout).Should(Equal(0)) 1010 } 1011 1012 // CreateChannelExitCode will submit an existing create channel transaction to 1013 // the specified orderer, wait for the operation to complete, and return the 1014 // exit status of the "peer channel create" command. 1015 // 1016 // The channel transaction must exist at the location returned by 1017 // CreateChannelTxPath and the orderer must be running when this is called. 1018 func (n *Network) CreateChannelExitCode(channelName string, o *Orderer, p *Peer, additionalSigners ...interface{}) int { 1019 channelCreateTxPath := n.CreateChannelTxPath(channelName) 1020 n.signConfigTransaction(channelCreateTxPath, p, additionalSigners...) 1021 1022 sess, err := n.PeerAdminSession(p, commands.ChannelCreate{ 1023 ChannelID: channelName, 1024 Orderer: n.OrdererAddress(o, ListenPort), 1025 File: channelCreateTxPath, 1026 OutputBlock: "/dev/null", 1027 ClientAuth: n.ClientAuthRequired, 1028 }) 1029 Expect(err).NotTo(HaveOccurred()) 1030 return sess.Wait(n.EventuallyTimeout).ExitCode() 1031 } 1032 1033 func (n *Network) signConfigTransaction(channelTxPath string, submittingPeer *Peer, signers ...interface{}) { 1034 for _, signer := range signers { 1035 switch signer := signer.(type) { 1036 case *Peer: 1037 sess, err := n.PeerAdminSession(signer, commands.SignConfigTx{ 1038 File: channelTxPath, 1039 ClientAuth: n.ClientAuthRequired, 1040 }) 1041 Expect(err).NotTo(HaveOccurred()) 1042 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 1043 1044 case *Orderer: 1045 sess, err := n.OrdererAdminSession(signer, submittingPeer, commands.SignConfigTx{ 1046 File: channelTxPath, 1047 ClientAuth: n.ClientAuthRequired, 1048 }) 1049 Expect(err).NotTo(HaveOccurred()) 1050 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 1051 1052 default: 1053 panic(fmt.Sprintf("unknown signer type %T, expect Peer or Orderer", signer)) 1054 } 1055 } 1056 } 1057 1058 // JoinChannel will join peers to the specified channel. The orderer is used to 1059 // obtain the current configuration block for the channel. 1060 // 1061 // The orderer and listed peers must be running before this is called. 1062 func (n *Network) JoinChannel(name string, o *Orderer, peers ...*Peer) { 1063 if len(peers) == 0 { 1064 return 1065 } 1066 1067 tempFile, err := ioutil.TempFile("", "genesis-block") 1068 Expect(err).NotTo(HaveOccurred()) 1069 tempFile.Close() 1070 defer os.Remove(tempFile.Name()) 1071 1072 sess, err := n.PeerAdminSession(peers[0], commands.ChannelFetch{ 1073 Block: "0", 1074 ChannelID: name, 1075 Orderer: n.OrdererAddress(o, ListenPort), 1076 OutputFile: tempFile.Name(), 1077 ClientAuth: n.ClientAuthRequired, 1078 }) 1079 Expect(err).NotTo(HaveOccurred()) 1080 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 1081 1082 for _, p := range peers { 1083 sess, err := n.PeerAdminSession(p, commands.ChannelJoin{ 1084 BlockPath: tempFile.Name(), 1085 ClientAuth: n.ClientAuthRequired, 1086 }) 1087 Expect(err).NotTo(HaveOccurred()) 1088 Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0)) 1089 } 1090 } 1091 1092 // Cryptogen starts a gexec.Session for the provided cryptogen command. 1093 func (n *Network) Cryptogen(command Command) (*gexec.Session, error) { 1094 cmd := NewCommand(n.Components.Cryptogen(), command) 1095 return n.StartSession(cmd, command.SessionName()) 1096 } 1097 1098 // Idemixgen starts a gexec.Session for the provided idemixgen command. 1099 func (n *Network) Idemixgen(command Command) (*gexec.Session, error) { 1100 cmd := NewCommand(n.Components.Idemixgen(), command) 1101 return n.StartSession(cmd, command.SessionName()) 1102 } 1103 1104 // ConfigTxGen starts a gexec.Session for the provided configtxgen command. 1105 func (n *Network) ConfigTxGen(command Command) (*gexec.Session, error) { 1106 cmd := NewCommand(n.Components.ConfigTxGen(), command) 1107 return n.StartSession(cmd, command.SessionName()) 1108 } 1109 1110 // Discover starts a gexec.Session for the provided discover command. 1111 func (n *Network) Discover(command Command) (*gexec.Session, error) { 1112 cmd := NewCommand(n.Components.Discover(), command) 1113 cmd.Args = append(cmd.Args, "--peerTLSCA", n.CACertsBundlePath()) 1114 return n.StartSession(cmd, command.SessionName()) 1115 } 1116 1117 // ZooKeeperRunner returns a runner for a ZooKeeper instance. 1118 func (n *Network) ZooKeeperRunner(idx int) *runner.ZooKeeper { 1119 colorCode := n.nextColor() 1120 name := fmt.Sprintf("zookeeper-%d-%s", idx, n.NetworkID) 1121 1122 return &runner.ZooKeeper{ 1123 ZooMyID: idx + 1, // IDs must be between 1 and 255 1124 Client: n.DockerClient, 1125 Name: name, 1126 NetworkName: n.NetworkID, 1127 OutputStream: gexec.NewPrefixedWriter( 1128 fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", colorCode, name), 1129 ginkgo.GinkgoWriter, 1130 ), 1131 ErrorStream: gexec.NewPrefixedWriter( 1132 fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", colorCode, name), 1133 ginkgo.GinkgoWriter, 1134 ), 1135 } 1136 } 1137 1138 func (n *Network) minBrokersInSync() int { 1139 if n.Consensus.Brokers < 2 { 1140 return n.Consensus.Brokers 1141 } 1142 return 2 1143 } 1144 1145 func (n *Network) defaultBrokerReplication() int { 1146 if n.Consensus.Brokers < 3 { 1147 return n.Consensus.Brokers 1148 } 1149 return 3 1150 } 1151 1152 // BrokerRunner returns a runner for a Kafka broker instance. 1153 func (n *Network) BrokerRunner(id int, zookeepers []string) *runner.Kafka { 1154 colorCode := n.nextColor() 1155 name := fmt.Sprintf("kafka-%d-%s", id, n.NetworkID) 1156 1157 return &runner.Kafka{ 1158 BrokerID: id + 1, 1159 Client: n.DockerClient, 1160 AdvertisedListeners: "127.0.0.1", 1161 HostPort: int(n.PortsByBrokerID[strconv.Itoa(id)][HostPort]), 1162 Name: name, 1163 NetworkName: n.NetworkID, 1164 MinInsyncReplicas: n.minBrokersInSync(), 1165 DefaultReplicationFactor: n.defaultBrokerReplication(), 1166 ZooKeeperConnect: strings.Join(zookeepers, ","), 1167 OutputStream: gexec.NewPrefixedWriter( 1168 fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", colorCode, name), 1169 ginkgo.GinkgoWriter, 1170 ), 1171 ErrorStream: gexec.NewPrefixedWriter( 1172 fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", colorCode, name), 1173 ginkgo.GinkgoWriter, 1174 ), 1175 } 1176 } 1177 1178 // BrokerGroupRunner returns a runner that manages the processes that make up 1179 // the Kafka broker network for fabric. 1180 func (n *Network) BrokerGroupRunner() ifrit.Runner { 1181 members := grouper.Members{} 1182 zookeepers := []string{} 1183 1184 for i := 0; i < n.Consensus.ZooKeepers; i++ { 1185 zk := n.ZooKeeperRunner(i) 1186 zookeepers = append(zookeepers, fmt.Sprintf("%s:2181", zk.Name)) 1187 members = append(members, grouper.Member{Name: zk.Name, Runner: zk}) 1188 } 1189 1190 for i := 0; i < n.Consensus.Brokers; i++ { 1191 kafka := n.BrokerRunner(i, zookeepers) 1192 members = append(members, grouper.Member{Name: kafka.Name, Runner: kafka}) 1193 } 1194 1195 return grouper.NewOrdered(syscall.SIGTERM, members) 1196 } 1197 1198 // OrdererRunner returns an ifrit.Runner for the specified orderer. The runner 1199 // can be used to start and manage an orderer process. 1200 func (n *Network) OrdererRunner(o *Orderer, env ...string) *ginkgomon.Runner { 1201 cmd := exec.Command(n.Components.Orderer()) 1202 cmd.Env = os.Environ() 1203 cmd.Env = append(cmd.Env, fmt.Sprintf("FABRIC_CFG_PATH=%s", n.OrdererDir(o))) 1204 cmd.Env = append(cmd.Env, env...) 1205 1206 config := ginkgomon.Config{ 1207 AnsiColorCode: n.nextColor(), 1208 Name: o.ID(), 1209 Command: cmd, 1210 StartCheck: "Beginning to serve requests", 1211 StartCheckTimeout: 15 * time.Second, 1212 } 1213 1214 // After consensus-type migration, the #brokers is >0, but the type is etcdraft 1215 if n.Consensus.Type == "kafka" && n.Consensus.Brokers != 0 { 1216 config.StartCheck = "Start phase completed successfully" 1217 config.StartCheckTimeout = 30 * time.Second 1218 } 1219 1220 return ginkgomon.New(config) 1221 } 1222 1223 // OrdererGroupRunner returns a runner that can be used to start and stop all 1224 // orderers in a network. 1225 func (n *Network) OrdererGroupRunner() ifrit.Runner { 1226 members := grouper.Members{} 1227 for _, o := range n.Orderers { 1228 members = append(members, grouper.Member{Name: o.ID(), Runner: n.OrdererRunner(o)}) 1229 } 1230 return grouper.NewParallel(syscall.SIGTERM, members) 1231 } 1232 1233 // PeerRunner returns an ifrit.Runner for the specified peer. The runner can be 1234 // used to start and manage a peer process. 1235 func (n *Network) PeerRunner(p *Peer, env ...string) *ginkgomon.Runner { 1236 cmd := n.peerCommand( 1237 commands.NodeStart{PeerID: p.ID(), DevMode: p.DevMode}, 1238 "", 1239 fmt.Sprintf("FABRIC_CFG_PATH=%s", n.PeerDir(p)), 1240 fmt.Sprintf("CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin"), 1241 fmt.Sprintf("CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw"), 1242 ) 1243 cmd.Env = append(cmd.Env, env...) 1244 1245 return ginkgomon.New(ginkgomon.Config{ 1246 AnsiColorCode: n.nextColor(), 1247 Name: p.ID(), 1248 Command: cmd, 1249 StartCheck: `Started peer with ID=.*, .*, address=`, 1250 StartCheckTimeout: 15 * time.Second, 1251 }) 1252 } 1253 1254 // PeerGroupRunner returns a runner that can be used to start and stop all 1255 // peers in a network. 1256 func (n *Network) PeerGroupRunner() ifrit.Runner { 1257 members := grouper.Members{} 1258 for _, p := range n.Peers { 1259 members = append(members, grouper.Member{Name: p.ID(), Runner: n.PeerRunner(p)}) 1260 } 1261 return grouper.NewParallel(syscall.SIGTERM, members) 1262 } 1263 1264 // NetworkGroupRunner returns a runner that can be used to start and stop an 1265 // entire fabric network. 1266 func (n *Network) NetworkGroupRunner() ifrit.Runner { 1267 members := grouper.Members{ 1268 {Name: "brokers", Runner: n.BrokerGroupRunner()}, 1269 {Name: "orderers", Runner: n.OrdererGroupRunner()}, 1270 {Name: "peers", Runner: n.PeerGroupRunner()}, 1271 } 1272 return grouper.NewOrdered(syscall.SIGTERM, members) 1273 } 1274 1275 func (n *Network) peerCommand(command Command, tlsDir string, env ...string) *exec.Cmd { 1276 cmd := NewCommand(n.Components.Peer(), command) 1277 cmd.Env = append(cmd.Env, env...) 1278 if ConnectsToOrderer(command) && n.TLSEnabled { 1279 cmd.Args = append(cmd.Args, "--tls") 1280 cmd.Args = append(cmd.Args, "--cafile", n.CACertsBundlePath()) 1281 } 1282 1283 if ClientAuthEnabled(command) { 1284 certfilePath := filepath.Join(tlsDir, "client.crt") 1285 keyfilePath := filepath.Join(tlsDir, "client.key") 1286 1287 cmd.Args = append(cmd.Args, "--certfile", certfilePath) 1288 cmd.Args = append(cmd.Args, "--keyfile", keyfilePath) 1289 } 1290 1291 // In case we have a peer invoke with multiple certificates, we need to mimic 1292 // the correct peer CLI usage, so we count the number of --peerAddresses 1293 // usages we have, and add the same (concatenated TLS CA certificates file) 1294 // the same number of times to bypass the peer CLI sanity checks 1295 requiredPeerAddresses := flagCount("--peerAddresses", cmd.Args) 1296 for i := 0; i < requiredPeerAddresses; i++ { 1297 cmd.Args = append(cmd.Args, "--tlsRootCertFiles") 1298 cmd.Args = append(cmd.Args, n.CACertsBundlePath()) 1299 } 1300 return cmd 1301 } 1302 1303 func flagCount(flag string, args []string) int { 1304 var c int 1305 for _, arg := range args { 1306 if arg == flag { 1307 c++ 1308 } 1309 } 1310 return c 1311 } 1312 1313 // PeerAdminSession starts a gexec.Session as a peer admin for the provided 1314 // peer command. This is intended to be used by short running peer cli commands 1315 // that execute in the context of a peer configuration. 1316 func (n *Network) PeerAdminSession(p *Peer, command Command) (*gexec.Session, error) { 1317 return n.PeerUserSession(p, "Admin", command) 1318 } 1319 1320 // PeerUserSession starts a gexec.Session as a peer user for the provided peer 1321 // command. This is intended to be used by short running peer cli commands that 1322 // execute in the context of a peer configuration. 1323 func (n *Network) PeerUserSession(p *Peer, user string, command Command) (*gexec.Session, error) { 1324 cmd := n.peerCommand( 1325 command, 1326 n.PeerUserTLSDir(p, user), 1327 fmt.Sprintf("FABRIC_CFG_PATH=%s", n.PeerDir(p)), 1328 fmt.Sprintf("CORE_PEER_MSPCONFIGPATH=%s", n.PeerUserMSPDir(p, user)), 1329 ) 1330 return n.StartSession(cmd, command.SessionName()) 1331 } 1332 1333 // IdemixUserSession starts a gexec.Session as a idemix user for the provided peer 1334 // command. This is intended to be used by short running peer cli commands that 1335 // execute in the context of a peer configuration. 1336 func (n *Network) IdemixUserSession(p *Peer, idemixOrg *Organization, user string, command Command) (*gexec.Session, error) { 1337 cmd := n.peerCommand( 1338 command, 1339 n.PeerUserTLSDir(p, user), 1340 fmt.Sprintf("FABRIC_CFG_PATH=%s", n.PeerDir(p)), 1341 fmt.Sprintf("CORE_PEER_MSPCONFIGPATH=%s", n.IdemixUserMSPDir(idemixOrg, user)), 1342 fmt.Sprintf("CORE_PEER_LOCALMSPTYPE=%s", "idemix"), 1343 fmt.Sprintf("CORE_PEER_LOCALMSPID=%s", idemixOrg.MSPID), 1344 ) 1345 return n.StartSession(cmd, command.SessionName()) 1346 } 1347 1348 // OrdererAdminSession starts a gexec.Session as an orderer admin user. This 1349 // is used primarily to generate orderer configuration updates. 1350 func (n *Network) OrdererAdminSession(o *Orderer, p *Peer, command Command) (*gexec.Session, error) { 1351 cmd := n.peerCommand( 1352 command, 1353 n.ordererUserCryptoDir(o, "Admin", "tls"), 1354 fmt.Sprintf("CORE_PEER_LOCALMSPID=%s", n.Organization(o.Organization).MSPID), 1355 fmt.Sprintf("FABRIC_CFG_PATH=%s", n.PeerDir(p)), 1356 fmt.Sprintf("CORE_PEER_MSPCONFIGPATH=%s", n.OrdererUserMSPDir(o, "Admin")), 1357 ) 1358 return n.StartSession(cmd, command.SessionName()) 1359 } 1360 1361 // Peer returns the information about the named Peer in the named organization. 1362 func (n *Network) Peer(orgName, peerName string) *Peer { 1363 for _, p := range n.PeersInOrg(orgName) { 1364 if p.Name == peerName { 1365 return p 1366 } 1367 } 1368 return nil 1369 } 1370 1371 // DiscoveredPeer creates a new DiscoveredPeer from the peer and chaincodes 1372 // passed as arguments. 1373 func (n *Network) DiscoveredPeer(p *Peer, chaincodes ...string) DiscoveredPeer { 1374 peerCert, err := ioutil.ReadFile(n.PeerCert(p)) 1375 Expect(err).NotTo(HaveOccurred()) 1376 1377 return DiscoveredPeer{ 1378 MSPID: n.Organization(p.Organization).MSPID, 1379 Endpoint: fmt.Sprintf("127.0.0.1:%d", n.PeerPort(p, ListenPort)), 1380 Identity: string(peerCert), 1381 Chaincodes: chaincodes, 1382 } 1383 } 1384 1385 func (n *Network) DiscoveredPeerMatcher(p *Peer, chaincodes ...string) types.GomegaMatcher { 1386 peerCert, err := ioutil.ReadFile(n.PeerCert(p)) 1387 Expect(err).NotTo(HaveOccurred()) 1388 1389 return MatchAllFields(Fields{ 1390 "MSPID": Equal(n.Organization(p.Organization).MSPID), 1391 "Endpoint": Equal(fmt.Sprintf("127.0.0.1:%d", n.PeerPort(p, ListenPort))), 1392 "Identity": Equal(string(peerCert)), 1393 "Chaincodes": containElements(chaincodes...), 1394 }) 1395 } 1396 1397 // containElements succeeds if a slice contains the passed in elements. 1398 func containElements(elements ...string) types.GomegaMatcher { 1399 ms := make([]types.GomegaMatcher, 0, len(elements)) 1400 for _, element := range elements { 1401 ms = append(ms, &matchers.ContainElementMatcher{ 1402 Element: element, 1403 }) 1404 } 1405 return &matchers.AndMatcher{ 1406 Matchers: ms, 1407 } 1408 } 1409 1410 // Orderer returns the information about the named Orderer. 1411 func (n *Network) Orderer(name string) *Orderer { 1412 for _, o := range n.Orderers { 1413 if o.Name == name { 1414 return o 1415 } 1416 } 1417 return nil 1418 } 1419 1420 // Organization returns the information about the named Organization. 1421 func (n *Network) Organization(orgName string) *Organization { 1422 for _, org := range n.Organizations { 1423 if org.Name == orgName { 1424 return org 1425 } 1426 } 1427 return nil 1428 } 1429 1430 // Consortium returns information about the named Consortium. 1431 func (n *Network) Consortium(name string) *Consortium { 1432 for _, c := range n.Consortiums { 1433 if c.Name == name { 1434 return c 1435 } 1436 } 1437 return nil 1438 } 1439 1440 // PeerOrgs returns all Organizations associated with at least one Peer. 1441 func (n *Network) PeerOrgs() []*Organization { 1442 orgsByName := map[string]*Organization{} 1443 for _, p := range n.Peers { 1444 if n.Organization(p.Organization).MSPType != "idemix" { 1445 orgsByName[p.Organization] = n.Organization(p.Organization) 1446 } 1447 } 1448 1449 orgs := []*Organization{} 1450 for _, org := range orgsByName { 1451 orgs = append(orgs, org) 1452 } 1453 return orgs 1454 } 1455 1456 // IdemixOrgs returns all Organizations of type idemix. 1457 func (n *Network) IdemixOrgs() []*Organization { 1458 orgs := []*Organization{} 1459 for _, org := range n.Organizations { 1460 if org.MSPType == "idemix" { 1461 orgs = append(orgs, org) 1462 } 1463 } 1464 return orgs 1465 } 1466 1467 // PeersWithChannel returns all Peer instances that have joined the named 1468 // channel. 1469 func (n *Network) PeersWithChannel(chanName string) []*Peer { 1470 peers := []*Peer{} 1471 for _, p := range n.Peers { 1472 for _, c := range p.Channels { 1473 if c.Name == chanName { 1474 peers = append(peers, p) 1475 } 1476 } 1477 } 1478 1479 // This is a bit of a hack to make the output of this function deterministic. 1480 // When this function's output is supplied as input to functions such as ApproveChaincodeForMyOrg 1481 // it causes a different subset of peers to be picked, which can create flakiness in tests. 1482 sort.Slice(peers, func(i, j int) bool { 1483 if peers[i].Organization < peers[j].Organization { 1484 return true 1485 } 1486 1487 return peers[i].Organization == peers[j].Organization && peers[i].Name < peers[j].Name 1488 }) 1489 return peers 1490 } 1491 1492 // AnchorsForChannel returns all Peer instances that are anchors for the 1493 // named channel. 1494 func (n *Network) AnchorsForChannel(chanName string) []*Peer { 1495 anchors := []*Peer{} 1496 for _, p := range n.Peers { 1497 for _, pc := range p.Channels { 1498 if pc.Name == chanName && pc.Anchor { 1499 anchors = append(anchors, p) 1500 } 1501 } 1502 } 1503 return anchors 1504 } 1505 1506 // AnchorsInOrg returns all peers that are an anchor for at least one channel 1507 // in the named organization. 1508 func (n *Network) AnchorsInOrg(orgName string) []*Peer { 1509 anchors := []*Peer{} 1510 for _, p := range n.PeersInOrg(orgName) { 1511 if p.Anchor() { 1512 anchors = append(anchors, p) 1513 break 1514 } 1515 } 1516 1517 // No explicit anchor means all peers are anchors. 1518 if len(anchors) == 0 { 1519 anchors = n.PeersInOrg(orgName) 1520 } 1521 1522 return anchors 1523 } 1524 1525 // OrderersInOrg returns all Orderer instances owned by the named organization. 1526 func (n *Network) OrderersInOrg(orgName string) []*Orderer { 1527 orderers := []*Orderer{} 1528 for _, o := range n.Orderers { 1529 if o.Organization == orgName { 1530 orderers = append(orderers, o) 1531 } 1532 } 1533 return orderers 1534 } 1535 1536 // OrgsForOrderers returns all Organization instances that own at least one of 1537 // the named orderers. 1538 func (n *Network) OrgsForOrderers(ordererNames []string) []*Organization { 1539 orgsByName := map[string]*Organization{} 1540 for _, name := range ordererNames { 1541 orgName := n.Orderer(name).Organization 1542 orgsByName[orgName] = n.Organization(orgName) 1543 } 1544 orgs := []*Organization{} 1545 for _, org := range orgsByName { 1546 orgs = append(orgs, org) 1547 } 1548 return orgs 1549 } 1550 1551 // OrdererOrgs returns all Organization instances that own at least one 1552 // orderer. 1553 func (n *Network) OrdererOrgs() []*Organization { 1554 orgsByName := map[string]*Organization{} 1555 for _, o := range n.Orderers { 1556 orgsByName[o.Organization] = n.Organization(o.Organization) 1557 } 1558 1559 orgs := []*Organization{} 1560 for _, org := range orgsByName { 1561 orgs = append(orgs, org) 1562 } 1563 return orgs 1564 } 1565 1566 // PeersInOrg returns all Peer instances that are owned by the named 1567 // organization. 1568 func (n *Network) PeersInOrg(orgName string) []*Peer { 1569 peers := []*Peer{} 1570 for _, o := range n.Peers { 1571 if o.Organization == orgName { 1572 peers = append(peers, o) 1573 } 1574 } 1575 return peers 1576 } 1577 1578 // ReservePort allocates the next available port. 1579 func (n *Network) ReservePort() uint16 { 1580 n.StartPort++ 1581 return n.StartPort - 1 1582 } 1583 1584 type PortName string 1585 type Ports map[PortName]uint16 1586 1587 const ( 1588 ChaincodePort PortName = "Chaincode" 1589 EventsPort PortName = "Events" 1590 HostPort PortName = "HostPort" 1591 ListenPort PortName = "Listen" 1592 ProfilePort PortName = "Profile" 1593 OperationsPort PortName = "Operations" 1594 ClusterPort PortName = "Cluster" 1595 ) 1596 1597 // PeerPortNames returns the list of ports that need to be reserved for a Peer. 1598 func PeerPortNames() []PortName { 1599 return []PortName{ListenPort, ChaincodePort, EventsPort, ProfilePort, OperationsPort} 1600 } 1601 1602 // OrdererPortNames returns the list of ports that need to be reserved for an 1603 // Orderer. 1604 func OrdererPortNames() []PortName { 1605 return []PortName{ListenPort, ProfilePort, OperationsPort, ClusterPort} 1606 } 1607 1608 // BrokerPortNames returns the list of ports that need to be reserved for a 1609 // Kafka broker. 1610 func BrokerPortNames() []PortName { 1611 return []PortName{HostPort} 1612 } 1613 1614 // BrokerAddresses returns the list of broker addresses for the network. 1615 func (n *Network) BrokerAddresses(portName PortName) []string { 1616 addresses := []string{} 1617 for _, ports := range n.PortsByBrokerID { 1618 addresses = append(addresses, fmt.Sprintf("127.0.0.1:%d", ports[portName])) 1619 } 1620 return addresses 1621 } 1622 1623 // OrdererAddress returns the address (host and port) exposed by the Orderer 1624 // for the named port. Command line tools should use the returned address when 1625 // connecting to the orderer. 1626 // 1627 // This assumes that the orderer is listening on 0.0.0.0 or 127.0.0.1 and is 1628 // available on the loopback address. 1629 func (n *Network) OrdererAddress(o *Orderer, portName PortName) string { 1630 return fmt.Sprintf("127.0.0.1:%d", n.OrdererPort(o, portName)) 1631 } 1632 1633 // OrdererPort returns the named port reserved for the Orderer instance. 1634 func (n *Network) OrdererPort(o *Orderer, portName PortName) uint16 { 1635 ordererPorts := n.PortsByOrdererID[o.ID()] 1636 Expect(ordererPorts).NotTo(BeNil()) 1637 return ordererPorts[portName] 1638 } 1639 1640 // PeerAddress returns the address (host and port) exposed by the Peer for the 1641 // named port. Command line tools should use the returned address when 1642 // connecting to a peer. 1643 // 1644 // This assumes that the peer is listening on 0.0.0.0 and is available on the 1645 // loopback address. 1646 func (n *Network) PeerAddress(p *Peer, portName PortName) string { 1647 return fmt.Sprintf("127.0.0.1:%d", n.PeerPort(p, portName)) 1648 } 1649 1650 // PeerPort returns the named port reserved for the Peer instance. 1651 func (n *Network) PeerPort(p *Peer, portName PortName) uint16 { 1652 peerPorts := n.PortsByPeerID[p.ID()] 1653 Expect(peerPorts).NotTo(BeNil()) 1654 return peerPorts[portName] 1655 } 1656 1657 func (n *Network) nextColor() string { 1658 color := n.colorIndex%14 + 31 1659 if color > 37 { 1660 color = color + 90 - 37 1661 } 1662 1663 n.colorIndex++ 1664 return fmt.Sprintf("%dm", color) 1665 } 1666 1667 func commandHash(cmd *exec.Cmd) string { 1668 buf := bytes.NewBuffer(nil) 1669 _, err := buf.WriteString(cmd.Dir) 1670 Expect(err).NotTo(HaveOccurred()) 1671 _, err = buf.WriteString(cmd.Path) 1672 Expect(err).NotTo(HaveOccurred()) 1673 1674 // sort the environment since it's not positional 1675 env := append([]string(nil), cmd.Env...) 1676 sort.Strings(env) 1677 for _, e := range env { 1678 _, err := buf.WriteString(e) 1679 Expect(err).NotTo(HaveOccurred()) 1680 } 1681 1682 // grab the args but ignore references to temporary files 1683 for _, arg := range cmd.Args { 1684 if strings.HasPrefix(arg, os.TempDir()) { 1685 continue 1686 } 1687 _, err := buf.WriteString(arg) 1688 Expect(err).NotTo(HaveOccurred()) 1689 } 1690 1691 return buf.String() 1692 } 1693 1694 // sessionThrottleDuration returns the time StartSession must wait before 1695 // starting a command session. The duration is determined by looking at when a 1696 // command was last executed by the network. If the time between now and the 1697 // last execution was less than SessionCreateInterval, the difference between 1698 // now and (execution + SessionCreateInterval) is returned. If more than 1699 // SessionCreateInterval has elapsed since the last command execution, a 1700 // duration of 0 is returned. 1701 func (n *Network) sessionThrottleDuration(cmd *exec.Cmd) time.Duration { 1702 h := commandHash(cmd) 1703 now := time.Now() 1704 last := n.sessLastExecuted[h] 1705 n.sessLastExecuted[h] = now 1706 1707 if diff := last.Add(n.SessionCreateInterval).Sub(now); diff > 0 { 1708 return diff 1709 } 1710 1711 return 0 1712 } 1713 1714 // StartSession executes a command session. This should be used to launch 1715 // command line tools that are expected to run to completion. 1716 func (n *Network) StartSession(cmd *exec.Cmd, name string) (*gexec.Session, error) { 1717 if d := n.sessionThrottleDuration(cmd); d > 0 { 1718 time.Sleep(d) 1719 } 1720 1721 ansiColorCode := n.nextColor() 1722 fmt.Fprintf( 1723 ginkgo.GinkgoWriter, 1724 "\x1b[33m[d]\x1b[%s[%s]\x1b[0m starting %s %s\n", 1725 ansiColorCode, 1726 name, 1727 filepath.Base(cmd.Args[0]), 1728 strings.Join(cmd.Args[1:], " "), 1729 ) 1730 return gexec.Start( 1731 cmd, 1732 gexec.NewPrefixedWriter( 1733 fmt.Sprintf("\x1b[32m[o]\x1b[%s[%s]\x1b[0m ", ansiColorCode, name), 1734 ginkgo.GinkgoWriter, 1735 ), 1736 gexec.NewPrefixedWriter( 1737 fmt.Sprintf("\x1b[91m[e]\x1b[%s[%s]\x1b[0m ", ansiColorCode, name), 1738 ginkgo.GinkgoWriter, 1739 ), 1740 ) 1741 } 1742 1743 func (n *Network) GenerateCryptoConfig() { 1744 crypto, err := os.Create(n.CryptoConfigPath()) 1745 Expect(err).NotTo(HaveOccurred()) 1746 defer crypto.Close() 1747 1748 t, err := template.New("crypto").Parse(n.Templates.CryptoTemplate()) 1749 Expect(err).NotTo(HaveOccurred()) 1750 1751 pw := gexec.NewPrefixedWriter("[crypto-config.yaml] ", ginkgo.GinkgoWriter) 1752 err = t.Execute(io.MultiWriter(crypto, pw), n) 1753 Expect(err).NotTo(HaveOccurred()) 1754 } 1755 1756 func (n *Network) GenerateConfigTxConfig() { 1757 config, err := os.Create(n.ConfigTxConfigPath()) 1758 Expect(err).NotTo(HaveOccurred()) 1759 defer config.Close() 1760 1761 t, err := template.New("configtx").Parse(n.Templates.ConfigTxTemplate()) 1762 Expect(err).NotTo(HaveOccurred()) 1763 1764 pw := gexec.NewPrefixedWriter("[configtx.yaml] ", ginkgo.GinkgoWriter) 1765 err = t.Execute(io.MultiWriter(config, pw), n) 1766 Expect(err).NotTo(HaveOccurred()) 1767 } 1768 1769 func (n *Network) GenerateOrdererConfig(o *Orderer) { 1770 err := os.MkdirAll(n.OrdererDir(o), 0755) 1771 Expect(err).NotTo(HaveOccurred()) 1772 1773 orderer, err := os.Create(n.OrdererConfigPath(o)) 1774 Expect(err).NotTo(HaveOccurred()) 1775 defer orderer.Close() 1776 1777 t, err := template.New("orderer").Funcs(template.FuncMap{ 1778 "Orderer": func() *Orderer { return o }, 1779 "ToLower": func(s string) string { return strings.ToLower(s) }, 1780 "ReplaceAll": func(s, old, new string) string { return strings.Replace(s, old, new, -1) }, 1781 }).Parse(n.Templates.OrdererTemplate()) 1782 Expect(err).NotTo(HaveOccurred()) 1783 1784 pw := gexec.NewPrefixedWriter(fmt.Sprintf("[%s#orderer.yaml] ", o.ID()), ginkgo.GinkgoWriter) 1785 err = t.Execute(io.MultiWriter(orderer, pw), n) 1786 Expect(err).NotTo(HaveOccurred()) 1787 } 1788 1789 func (n *Network) GenerateCoreConfig(p *Peer) { 1790 err := os.MkdirAll(n.PeerDir(p), 0755) 1791 Expect(err).NotTo(HaveOccurred()) 1792 1793 core, err := os.Create(n.PeerConfigPath(p)) 1794 Expect(err).NotTo(HaveOccurred()) 1795 defer core.Close() 1796 1797 t, err := template.New("peer").Funcs(template.FuncMap{ 1798 "Peer": func() *Peer { return p }, 1799 "ToLower": func(s string) string { return strings.ToLower(s) }, 1800 "ReplaceAll": func(s, old, new string) string { return strings.Replace(s, old, new, -1) }, 1801 }).Parse(n.Templates.CoreTemplate()) 1802 Expect(err).NotTo(HaveOccurred()) 1803 1804 pw := gexec.NewPrefixedWriter(fmt.Sprintf("[%s#core.yaml] ", p.ID()), ginkgo.GinkgoWriter) 1805 err = t.Execute(io.MultiWriter(core, pw), n) 1806 Expect(err).NotTo(HaveOccurred()) 1807 }