@@ -26,6 +26,7 @@ import (
26
26
protosorderer "github.com/hyperledger/fabric-protos-go/orderer"
27
27
"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
28
28
"github.com/hyperledger/fabric/common/crypto/tlsgen"
29
+ "github.com/hyperledger/fabric/integration/channelparticipation"
29
30
"github.com/hyperledger/fabric/integration/nwo"
30
31
"github.com/hyperledger/fabric/integration/nwo/commands"
31
32
"github.com/hyperledger/fabric/integration/ordererclient"
@@ -1237,6 +1238,128 @@ var _ = Describe("EndToEnd reconfiguration and onboarding", func() {
1237
1238
})
1238
1239
})
1239
1240
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
+
1240
1363
When ("an orderer node is joined" , func () {
1241
1364
It ("isn't influenced by outdated orderers" , func () {
1242
1365
// This test checks that if a lagged is not aware of newly added nodes,
0 commit comments