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