@@ -26,6 +26,7 @@ import (
2626 protosorderer "github.com/hyperledger/fabric-protos-go/orderer"
2727 "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
2828 "github.com/hyperledger/fabric/common/crypto/tlsgen"
29+ "github.com/hyperledger/fabric/integration/channelparticipation"
2930 "github.com/hyperledger/fabric/integration/nwo"
3031 "github.com/hyperledger/fabric/integration/nwo/commands"
3132 "github.com/hyperledger/fabric/integration/ordererclient"
@@ -1237,6 +1238,128 @@ var _ = Describe("EndToEnd reconfiguration and onboarding", func() {
12371238 })
12381239 })
12391240
1241+ Describe ("an all orderer nodes are evicted" , func () {
1242+ BeforeEach (func () {
1243+ ordererRunners = nil
1244+ ordererProcesses = nil
1245+
1246+ network = nwo .New (nwo .MultiNodeEtcdRaftNoSysChan (), testDir , client , StartPort (), components )
1247+ network .GenerateConfigTree ()
1248+ network .Bootstrap ()
1249+
1250+ o1 , o2 , o3 := network .Orderer ("orderer1" ), network .Orderer ("orderer2" ), network .Orderer ("orderer3" )
1251+ orderers := []* nwo.Orderer {o1 , o2 , o3 }
1252+ peer = network .Peer ("Org1" , "peer0" )
1253+
1254+ By ("Launching the orderers" )
1255+ for _ , o := range orderers {
1256+ runner := network .OrdererRunner (o , "FABRIC_LOGGING_SPEC=orderer.consensus.etcdraft=debug:info" )
1257+ ordererRunners = append (ordererRunners , runner )
1258+ process := ifrit .Invoke (runner )
1259+ ordererProcesses = append (ordererProcesses , process )
1260+ }
1261+
1262+ for _ , ordererProc := range ordererProcesses {
1263+ Eventually (ordererProc .Ready (), network .EventuallyTimeout ).Should (BeClosed ())
1264+ }
1265+ channelparticipation .JoinOrderersAppChannelCluster (network , "testchannel" , o1 , o2 , o3 )
1266+ })
1267+
1268+ AfterEach (func () {
1269+ for _ , ordererInstance := range ordererProcesses {
1270+ ordererInstance .Signal (syscall .SIGTERM )
1271+ Eventually (ordererInstance .Wait (), network .EventuallyTimeout ).Should (Receive ())
1272+ }
1273+ })
1274+
1275+ It ("remove channel from all orderers and add channel back" , func () {
1276+ o1 := network .Orderer ("orderer1" )
1277+ o2 := network .Orderer ("orderer2" )
1278+ o3 := network .Orderer ("orderer3" )
1279+
1280+ By ("Waiting for them to elect a leader" )
1281+ findLeader (ordererRunners )
1282+
1283+ assertBlockReception (map [string ]int {
1284+ "testchannel" : 0 ,
1285+ }, network .Orderers , peer , network )
1286+
1287+ By ("Removing channel from all orderers" )
1288+ // TODO the channelparticipation.Remove does not clean up the etcdraft folder. This may prevent the
1289+ // correct re-creation of the channel on this orderer.
1290+ // See: https://github.com/hyperledger/fabric/issues/3992
1291+ for _ , o := range network .Orderers {
1292+ ready := make (chan struct {})
1293+ go func () {
1294+ defer GinkgoRecover ()
1295+ channelparticipation .Remove (network , o , "testchannel" )
1296+ close (ready )
1297+ }()
1298+ Eventually (ready , network .EventuallyTimeout ).Should (BeClosed ())
1299+
1300+ Eventually (func () int { // Removal is async
1301+ channelList := channelparticipation .List (network , o )
1302+ return len (channelList .Channels )
1303+ }()).Should (BeZero ())
1304+ }
1305+
1306+ // TODO It is recommended to remove the etcdraft folder for the WAL to be re-created correctly
1307+ // See: https://github.com/hyperledger/fabric/issues/3992
1308+ for _ , o := range network .Orderers {
1309+ err := os .RemoveAll (path .Join (network .OrdererDir (o ), "etcdraft" , "wal" , "testchannel" ))
1310+ Expect (err ).NotTo (HaveOccurred ())
1311+ err = os .RemoveAll (path .Join (network .OrdererDir (o ), "etcdraft" , "snapshot" , "testchannel" ))
1312+ Expect (err ).NotTo (HaveOccurred ())
1313+ }
1314+
1315+ By ("Re-create the genesis block" )
1316+ for _ , c := range network .Channels {
1317+ sess , err := network .ConfigTxGen (commands.OutputBlock {
1318+ ChannelID : c .Name ,
1319+ Profile : c .Profile ,
1320+ ConfigPath : network .RootDir ,
1321+ OutputBlock : network .OutputBlockPath (c .Name ),
1322+ })
1323+ Expect (err ).NotTo (HaveOccurred ())
1324+ Eventually (sess , network .EventuallyTimeout ).Should (gexec .Exit (0 ))
1325+ }
1326+
1327+ By ("Re-adding the channel to the orderers" )
1328+ channelparticipation .JoinOrderersAppChannelCluster (network , "testchannel" , o1 , o2 , o3 )
1329+
1330+ findLeader (ordererRunners )
1331+
1332+ assertBlockReception (map [string ]int {
1333+ "testchannel" : 0 ,
1334+ }, network .Orderers , peer , network )
1335+
1336+ expectedInfo := channelparticipation .ListOne (network , o1 , "testchannel" )
1337+
1338+ By ("Submitting tx" )
1339+ env := CreateBroadcastEnvelope (network , o2 , "testchannel" , []byte ("foo" ))
1340+ resp , err := ordererclient .Broadcast (network , o2 , env )
1341+ Expect (err ).NotTo (HaveOccurred ())
1342+ Expect (resp .Status ).To (Equal (common .Status_SUCCESS ))
1343+
1344+ By ("Waiting for the channel to stabilize" )
1345+ expectedInfo .Height ++
1346+ assertCatchup := func (expected channelparticipation.ChannelInfo ) bool {
1347+ current := channelparticipation .ListOne (network , o1 , "testchannel" )
1348+ ok := current == expected
1349+ if ! ok {
1350+ fmt .Fprintf (GinkgoWriter , "Current ChannelInfo: %+v" , current )
1351+ }
1352+ return ok
1353+ }
1354+
1355+ Eventually (assertCatchup (expectedInfo ), network .EventuallyTimeout , 100 * time .Millisecond ).Should (BeTrue ())
1356+
1357+ assertBlockReception (map [string ]int {
1358+ "testchannel" : 1 ,
1359+ }, []* nwo.Orderer {o1 , o2 , o3 }, peer , network )
1360+ })
1361+ })
1362+
12401363 When ("an orderer node is joined" , func () {
12411364 It ("isn't influenced by outdated orderers" , func () {
12421365 // This test checks that if a lagged is not aware of newly added nodes,
0 commit comments