github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/integration/nwo/network.go (about)

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