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