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  }