github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/server/etcdraft_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package server_test
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"sync/atomic"
    16  	"testing"
    17  	"time"
    18  
    19  	. "github.com/onsi/gomega"
    20  	"github.com/onsi/gomega/gbytes"
    21  	"github.com/onsi/gomega/gexec"
    22  )
    23  
    24  var basePort = int32(8000)
    25  
    26  func nextPort() int32 {
    27  	return atomic.AddInt32(&basePort, 1)
    28  }
    29  
    30  func TestSpawnEtcdRaft(t *testing.T) {
    31  	gt := NewGomegaWithT(t)
    32  
    33  	// Set the fabric root folder for easy navigation to sampleconfig folder
    34  	fabricRootDir, err := filepath.Abs(filepath.Join("..", "..", ".."))
    35  	gt.Expect(err).NotTo(HaveOccurred())
    36  
    37  	// Build the configtxgen binary
    38  	configtxgen, err := gexec.Build("github.com/hyperledger/fabric/cmd/configtxgen")
    39  	gt.Expect(err).NotTo(HaveOccurred())
    40  
    41  	cryptogen, err := gexec.Build("github.com/hyperledger/fabric/cmd/cryptogen")
    42  	gt.Expect(err).NotTo(HaveOccurred())
    43  
    44  	// Build the orderer binary
    45  	orderer, err := gexec.Build("github.com/hyperledger/fabric/cmd/orderer")
    46  	gt.Expect(err).NotTo(HaveOccurred())
    47  
    48  	defer gexec.CleanupBuildArtifacts()
    49  
    50  	tempDir, err := ioutil.TempDir("", "etcdraft-test")
    51  	defer os.RemoveAll(tempDir)
    52  
    53  	copyYamlFiles(gt, "testdata", tempDir)
    54  
    55  	cryptoPath := generateCryptoMaterials(gt, cryptogen, tempDir)
    56  
    57  	t.Run("Bad", func(t *testing.T) {
    58  		t.Run("Invalid bootstrap block", func(t *testing.T) {
    59  			testEtcdRaftOSNFailureInvalidBootstrapBlock(NewGomegaWithT(t), tempDir, orderer, fabricRootDir, configtxgen, cryptoPath)
    60  		})
    61  
    62  		t.Run("TLS disabled single listener", func(t *testing.T) {
    63  			testEtcdRaftOSNNoTLSSingleListener(NewGomegaWithT(t), tempDir, orderer, fabricRootDir, configtxgen, cryptoPath)
    64  		})
    65  	})
    66  
    67  	t.Run("Good", func(t *testing.T) {
    68  		// tests in this suite actually launch process with success, hence we need to avoid
    69  		// conflicts in listening port, opening files.
    70  		t.Run("TLS disabled dual listener", func(t *testing.T) {
    71  			testEtcdRaftOSNNoTLSDualListener(NewGomegaWithT(t), tempDir, orderer, fabricRootDir, configtxgen, cryptoPath)
    72  		})
    73  
    74  		t.Run("TLS enabled single listener", func(t *testing.T) {
    75  			testEtcdRaftOSNSuccess(NewGomegaWithT(t), tempDir, configtxgen, orderer, fabricRootDir, cryptoPath)
    76  		})
    77  	})
    78  }
    79  
    80  func copyYamlFiles(gt *GomegaWithT, src, dst string) {
    81  	for _, file := range []string{"configtx.yaml", "examplecom-config.yaml", "orderer.yaml"} {
    82  		fileBytes, err := ioutil.ReadFile(filepath.Join(src, file))
    83  		gt.Expect(err).NotTo(HaveOccurred())
    84  		err = ioutil.WriteFile(filepath.Join(dst, file), fileBytes, 0644)
    85  		gt.Expect(err).NotTo(HaveOccurred())
    86  	}
    87  }
    88  
    89  func generateBootstrapBlock(gt *GomegaWithT, tempDir, configtxgen, channel, profile string) string {
    90  	// create a genesis block for the specified channel and profile
    91  	genesisBlockPath := filepath.Join(tempDir, "genesis.block")
    92  	cmd := exec.Command(
    93  		configtxgen,
    94  		"-channelID", channel,
    95  		"-profile", profile,
    96  		"-outputBlock", genesisBlockPath,
    97  		"--configPath", tempDir,
    98  	)
    99  	configtxgenProcess, err := gexec.Start(cmd, nil, nil)
   100  	gt.Expect(err).NotTo(HaveOccurred())
   101  	gt.Eventually(configtxgenProcess, time.Minute).Should(gexec.Exit(0))
   102  	gt.Expect(configtxgenProcess.Err).To(gbytes.Say("Writing genesis block"))
   103  
   104  	return genesisBlockPath
   105  }
   106  
   107  func generateCryptoMaterials(gt *GomegaWithT, cryptogen, path string) string {
   108  	cryptoPath := filepath.Join(path, "crypto")
   109  
   110  	cmd := exec.Command(
   111  		cryptogen,
   112  		"generate",
   113  		"--config", filepath.Join(path, "examplecom-config.yaml"),
   114  		"--output", cryptoPath,
   115  	)
   116  	cryptogenProcess, err := gexec.Start(cmd, nil, nil)
   117  	gt.Expect(err).NotTo(HaveOccurred())
   118  	gt.Eventually(cryptogenProcess, time.Minute).Should(gexec.Exit(0))
   119  
   120  	return cryptoPath
   121  }
   122  
   123  func testEtcdRaftOSNSuccess(gt *GomegaWithT, tempDir, configtxgen, orderer, fabricRootDir, cryptoPath string) {
   124  	genesisBlockPath := generateBootstrapBlock(gt, tempDir, configtxgen, "system", "SampleEtcdRaftSystemChannel")
   125  
   126  	// Launch the OSN
   127  	ordererProcess := launchOrderer(gt, orderer, tempDir, genesisBlockPath, fabricRootDir, cryptoPath)
   128  	defer func() { gt.Eventually(ordererProcess.Kill(), time.Minute).Should(gexec.Exit()) }()
   129  	// The following configuration parameters are not specified in the orderer.yaml, so let's ensure
   130  	// they are really configured autonomously via the localconfig code.
   131  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.DialTimeout = 5s"))
   132  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.RPCTimeout = 7s"))
   133  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.ReplicationBufferSize = 20971520"))
   134  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.ReplicationPullTimeout = 5s"))
   135  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.ReplicationRetryTimeout = 5s"))
   136  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.ReplicationBackgroundRefreshInterval = 5m0s"))
   137  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.ReplicationMaxRetries = 12"))
   138  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.SendBufferSize = 10"))
   139  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("General.Cluster.CertExpirationWarningThreshold = 168h0m0s"))
   140  
   141  	// Consensus.EvictionSuspicion is not specified in orderer.yaml, so let's ensure
   142  	// it is really configured autonomously via the etcdraft chain itself.
   143  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("EvictionSuspicion not set, defaulting to 10m"))
   144  	// Wait until the the node starts up and elects itself as a single leader in a single node cluster.
   145  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("Beginning to serve requests"))
   146  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("becomeLeader"))
   147  }
   148  
   149  func testEtcdRaftOSNFailureInvalidBootstrapBlock(gt *GomegaWithT, tempDir, orderer, fabricRootDir, configtxgen, cryptoPath string) {
   150  	// create an application channel genesis block
   151  	genesisBlockPath := generateBootstrapBlock(gt, tempDir, configtxgen, "mychannel", "SampleOrgChannel")
   152  	genesisBlockBytes, err := ioutil.ReadFile(genesisBlockPath)
   153  	gt.Expect(err).NotTo(HaveOccurred())
   154  
   155  	// Copy it to the designated location in the temporary folder
   156  	genesisBlockPath = filepath.Join(tempDir, "genesis.block")
   157  	err = ioutil.WriteFile(genesisBlockPath, genesisBlockBytes, 0644)
   158  	gt.Expect(err).NotTo(HaveOccurred())
   159  
   160  	// Launch the OSN
   161  	ordererProcess := launchOrderer(gt, orderer, tempDir, genesisBlockPath, fabricRootDir, cryptoPath)
   162  	defer func() { gt.Eventually(ordererProcess.Kill(), time.Minute).Should(gexec.Exit()) }()
   163  
   164  	expectedErr := "Failed validating bootstrap block: the block isn't a system channel block because it lacks ConsortiumsConfig"
   165  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say(expectedErr))
   166  }
   167  
   168  func testEtcdRaftOSNNoTLSSingleListener(gt *GomegaWithT, tempDir, orderer, fabricRootDir string, configtxgen, cryptoPath string) {
   169  	genesisBlockPath := generateBootstrapBlock(gt, tempDir, configtxgen, "system", "SampleEtcdRaftSystemChannel")
   170  
   171  	cmd := exec.Command(orderer)
   172  	cmd.Env = []string{
   173  		fmt.Sprintf("ORDERER_GENERAL_LISTENPORT=%d", nextPort()),
   174  		"ORDERER_GENERAL_BOOTSTRAPMETHOD=file",
   175  		"ORDERER_GENERAL_SYSTEMCHANNEL=system",
   176  		fmt.Sprintf("ORDERER_FILELEDGER_LOCATION=%s", filepath.Join(tempDir, "ledger")),
   177  		fmt.Sprintf("ORDERER_GENERAL_BOOTSTRAPFILE=%s", genesisBlockPath),
   178  		fmt.Sprintf("FABRIC_CFG_PATH=%s", tempDir),
   179  	}
   180  	ordererProcess, err := gexec.Start(cmd, nil, nil)
   181  	gt.Expect(err).NotTo(HaveOccurred())
   182  	defer func() { gt.Eventually(ordererProcess.Kill(), time.Minute).Should(gexec.Exit()) }()
   183  
   184  	expectedErr := "TLS is required for running ordering nodes of type etcdraft."
   185  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say(expectedErr))
   186  }
   187  
   188  func testEtcdRaftOSNNoTLSDualListener(gt *GomegaWithT, tempDir, orderer, fabricRootDir string, configtxgen, cryptoPath string) {
   189  	ordererTLSPath := filepath.Join(cryptoPath, "ordererOrganizations", "example.com", "orderers", "127.0.0.1.example.com", "tls")
   190  	genesisBlockPath := generateBootstrapBlock(gt, tempDir, configtxgen, "system", "SampleEtcdRaftSystemChannel")
   191  
   192  	cmd := exec.Command(orderer)
   193  	cmd.Env = []string{
   194  		fmt.Sprintf("ORDERER_GENERAL_LISTENPORT=%d", nextPort()),
   195  		"ORDERER_GENERAL_BOOTSTRAPMETHOD=file",
   196  		"ORDERER_GENERAL_SYSTEMCHANNEL=system",
   197  		"ORDERER_GENERAL_TLS_ENABLED=false",
   198  		"ORDERER_OPERATIONS_TLS_ENABLED=false",
   199  		fmt.Sprintf("ORDERER_FILELEDGER_LOCATION=%s", filepath.Join(tempDir, "ledger")),
   200  		fmt.Sprintf("ORDERER_GENERAL_BOOTSTRAPFILE=%s", genesisBlockPath),
   201  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_LISTENPORT=%d", nextPort()),
   202  		"ORDERER_GENERAL_CLUSTER_LISTENADDRESS=127.0.0.1",
   203  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_SERVERCERTIFICATE=%s", filepath.Join(ordererTLSPath, "server.crt")),
   204  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_SERVERPRIVATEKEY=%s", filepath.Join(ordererTLSPath, "server.key")),
   205  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=%s", filepath.Join(ordererTLSPath, "server.crt")),
   206  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=%s", filepath.Join(ordererTLSPath, "server.key")),
   207  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_ROOTCAS=[%s]", filepath.Join(ordererTLSPath, "ca.crt")),
   208  		fmt.Sprintf("ORDERER_CONSENSUS_WALDIR=%s", filepath.Join(tempDir, "wal")),
   209  		fmt.Sprintf("ORDERER_CONSENSUS_SNAPDIR=%s", filepath.Join(tempDir, "snapshot")),
   210  		fmt.Sprintf("FABRIC_CFG_PATH=%s", tempDir),
   211  		"ORDERER_OPERATIONS_LISTENADDRESS=127.0.0.1:0",
   212  	}
   213  	ordererProcess, err := gexec.Start(cmd, nil, nil)
   214  	gt.Expect(err).NotTo(HaveOccurred())
   215  	defer func() { gt.Eventually(ordererProcess.Kill(), time.Minute).Should(gexec.Exit()) }()
   216  
   217  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("Beginning to serve requests"))
   218  	gt.Eventually(ordererProcess.Err, time.Minute).Should(gbytes.Say("becomeLeader"))
   219  }
   220  
   221  func launchOrderer(gt *GomegaWithT, orderer, tempDir, genesisBlockPath, fabricRootDir, cryptoPath string) *gexec.Session {
   222  	ordererTLSPath := filepath.Join(cryptoPath, "ordererOrganizations", "example.com", "orderers", "127.0.0.1.example.com", "tls")
   223  	// Launch the orderer process
   224  	cmd := exec.Command(orderer)
   225  	cmd.Env = []string{
   226  		fmt.Sprintf("ORDERER_GENERAL_LISTENPORT=%d", nextPort()),
   227  		"ORDERER_GENERAL_BOOTSTRAPMETHOD=file",
   228  		"ORDERER_GENERAL_SYSTEMCHANNEL=system",
   229  		"ORDERER_GENERAL_TLS_CLIENTAUTHREQUIRED=true",
   230  		"ORDERER_GENERAL_TLS_ENABLED=true",
   231  		"ORDERER_OPERATIONS_TLS_ENABLED=false",
   232  		fmt.Sprintf("ORDERER_FILELEDGER_LOCATION=%s", filepath.Join(tempDir, "ledger")),
   233  		fmt.Sprintf("ORDERER_GENERAL_BOOTSTRAPFILE=%s", genesisBlockPath),
   234  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_LISTENPORT=%d", nextPort()),
   235  		"ORDERER_GENERAL_CLUSTER_LISTENADDRESS=127.0.0.1",
   236  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_SERVERCERTIFICATE=%s", filepath.Join(ordererTLSPath, "server.crt")),
   237  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_SERVERPRIVATEKEY=%s", filepath.Join(ordererTLSPath, "server.key")),
   238  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=%s", filepath.Join(ordererTLSPath, "server.crt")),
   239  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=%s", filepath.Join(ordererTLSPath, "server.key")),
   240  		fmt.Sprintf("ORDERER_GENERAL_CLUSTER_ROOTCAS=[%s]", filepath.Join(ordererTLSPath, "ca.crt")),
   241  		fmt.Sprintf("ORDERER_GENERAL_TLS_ROOTCAS=[%s]", filepath.Join(ordererTLSPath, "ca.crt")),
   242  		fmt.Sprintf("ORDERER_GENERAL_TLS_CERTIFICATE=%s", filepath.Join(ordererTLSPath, "server.crt")),
   243  		fmt.Sprintf("ORDERER_GENERAL_TLS_PRIVATEKEY=%s", filepath.Join(ordererTLSPath, "server.key")),
   244  		fmt.Sprintf("ORDERER_CONSENSUS_WALDIR=%s", filepath.Join(tempDir, "wal")),
   245  		fmt.Sprintf("ORDERER_CONSENSUS_SNAPDIR=%s", filepath.Join(tempDir, "snapshot")),
   246  		fmt.Sprintf("FABRIC_CFG_PATH=%s", tempDir),
   247  	}
   248  	sess, err := gexec.Start(cmd, nil, nil)
   249  	gt.Expect(err).NotTo(HaveOccurred())
   250  	return sess
   251  }