Skip to content

Commit 3ec8eca

Browse files
[FAB-11861] Add etcdraft config defaults
This CR adds configuration defaults to the etcdraft plugin Metadata definition under the Options namespace. Change-Id: I37214d6ff3da9e7f5a26820feaea882d49e79736 Signed-off-by: Adarsh Saraf <adarshsaraf123@gmail.com>
1 parent 635cd8c commit 3ec8eca

File tree

6 files changed

+382
-26
lines changed

6 files changed

+382
-26
lines changed

common/tools/configtxgen/localconfig/config.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ var genesisDefaults = TopLevel{
199199
Kafka: Kafka{
200200
Brokers: []string{"127.0.0.1:9092"},
201201
},
202+
EtcdRaft: &etcdraft.Metadata{
203+
Options: &etcdraft.Options{
204+
TickInterval: 100,
205+
ElectionTick: 10,
206+
HeartbeatTick: 1,
207+
MaxInflightMsgs: 256,
208+
MaxSizePerMsg: 1048576,
209+
},
210+
},
202211
},
203212
}
204213

@@ -379,8 +388,12 @@ loop:
379388
}
380389
}
381390

391+
logger.Infof("orderer type: %s", ord.OrdererType)
382392
// Additional, consensus type-dependent initialization goes here
393+
// Also using this to panic on unknown orderer type.
383394
switch ord.OrdererType {
395+
case "solo":
396+
// nothing to be done here
384397
case "kafka":
385398
if ord.Kafka.Brokers == nil {
386399
logger.Infof("Orderer.Kafka unset, setting to %v", genesisDefaults.Orderer.Kafka.Brokers)
@@ -390,14 +403,68 @@ loop:
390403
if ord.EtcdRaft == nil {
391404
logger.Panicf("%s raft configuration missing", etcdraft.TypeKey)
392405
}
406+
if ord.EtcdRaft.Options == nil {
407+
logger.Infof("Orderer.EtcdRaft.Options unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options)
408+
ord.EtcdRaft.Options = genesisDefaults.Orderer.EtcdRaft.Options
409+
}
410+
second_loop:
411+
for {
412+
switch {
413+
case ord.EtcdRaft.Options.TickInterval == 0:
414+
logger.Infof("Orderer.EtcdRaft.Options.TickInterval unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.TickInterval)
415+
ord.EtcdRaft.Options.TickInterval = genesisDefaults.Orderer.EtcdRaft.Options.TickInterval
416+
417+
case ord.EtcdRaft.Options.ElectionTick == 0:
418+
logger.Infof("Orderer.EtcdRaft.Options.ElectionTick unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.ElectionTick)
419+
ord.EtcdRaft.Options.ElectionTick = genesisDefaults.Orderer.EtcdRaft.Options.ElectionTick
420+
421+
case ord.EtcdRaft.Options.HeartbeatTick == 0:
422+
logger.Infof("Orderer.EtcdRaft.Options.HeartbeatTick unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.HeartbeatTick)
423+
ord.EtcdRaft.Options.HeartbeatTick = genesisDefaults.Orderer.EtcdRaft.Options.HeartbeatTick
424+
425+
case ord.EtcdRaft.Options.MaxInflightMsgs == 0:
426+
logger.Infof("Orderer.EtcdRaft.Options.MaxInflightMsgs unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.MaxInflightMsgs)
427+
ord.EtcdRaft.Options.MaxInflightMsgs = genesisDefaults.Orderer.EtcdRaft.Options.MaxInflightMsgs
428+
429+
case ord.EtcdRaft.Options.MaxSizePerMsg == 0:
430+
logger.Infof("Orderer.EtcdRaft.Options.MaxSizePerMsg unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.MaxSizePerMsg)
431+
ord.EtcdRaft.Options.MaxSizePerMsg = genesisDefaults.Orderer.EtcdRaft.Options.MaxSizePerMsg
432+
433+
case len(ord.EtcdRaft.Consenters) == 0:
434+
logger.Panicf("%s configuration did not specify any consenter", etcdraft.TypeKey)
435+
436+
default:
437+
break second_loop
438+
}
439+
}
440+
441+
// validate the specified members for Options
442+
if ord.EtcdRaft.Options.ElectionTick <= ord.EtcdRaft.Options.HeartbeatTick {
443+
logger.Panicf("election tick must be greater than heartbeat tick")
444+
}
445+
393446
for _, c := range ord.EtcdRaft.GetConsenters() {
447+
if c.Host == "" {
448+
logger.Panicf("consenter info in %s configuration did not specify host", etcdraft.TypeKey)
449+
}
450+
if c.Port == 0 {
451+
logger.Panicf("consenter info in %s configuration did not specify port", etcdraft.TypeKey)
452+
}
453+
if c.ClientTlsCert == nil {
454+
logger.Panicf("consenter info in %s configuration did not specify client TLS cert", etcdraft.TypeKey)
455+
}
456+
if c.ServerTlsCert == nil {
457+
logger.Panicf("consenter info in %s configuration did not specify server TLS cert", etcdraft.TypeKey)
458+
}
394459
clientCertPath := string(c.GetClientTlsCert())
395460
cf.TranslatePathInPlace(configDir, &clientCertPath)
396461
c.ClientTlsCert = []byte(clientCertPath)
397462
serverCertPath := string(c.GetServerTlsCert())
398463
cf.TranslatePathInPlace(configDir, &serverCertPath)
399464
c.ServerTlsCert = []byte(serverCertPath)
400465
}
466+
default:
467+
logger.Panicf("unknown orderer type: %s", ord.OrdererType)
401468
}
402469
}
403470

common/tools/configtxgen/localconfig/config_test.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"testing"
1111

1212
"github.com/hyperledger/fabric/core/config/configtest"
13+
"github.com/hyperledger/fabric/protos/orderer/etcdraft"
14+
1315
"github.com/stretchr/testify/assert"
1416
"github.com/stretchr/testify/require"
1517
)
@@ -83,6 +85,29 @@ func TestConsensusSpecificInit(t *testing.T) {
8385
devConfigDir, err := configtest.GetDevConfigDir()
8486
require.NoError(t, err)
8587

88+
t.Run("nil orderer type", func(t *testing.T) {
89+
profile := &Profile{
90+
Orderer: &Orderer{
91+
OrdererType: "",
92+
},
93+
}
94+
profile.completeInitialization(devConfigDir)
95+
96+
assert.Equal(t, profile.Orderer.OrdererType, genesisDefaults.Orderer.OrdererType)
97+
})
98+
99+
t.Run("unknown orderer type", func(t *testing.T) {
100+
profile := &Profile{
101+
Orderer: &Orderer{
102+
OrdererType: "unknown",
103+
},
104+
}
105+
106+
assert.Panics(t, func() {
107+
profile.completeInitialization(devConfigDir)
108+
})
109+
})
110+
86111
t.Run("solo", func(t *testing.T) {
87112
profile := &Profile{
88113
Orderer: &Orderer{
@@ -102,4 +127,137 @@ func TestConsensusSpecificInit(t *testing.T) {
102127
profile.completeInitialization(devConfigDir)
103128
assert.NotNil(t, profile.Orderer.Kafka.Brokers, "Kafka config settings should be set")
104129
})
130+
131+
t.Run("raft", func(t *testing.T) {
132+
makeProfile := func(consenters []*etcdraft.Consenter, options *etcdraft.Options) *Profile {
133+
return &Profile{
134+
Orderer: &Orderer{
135+
OrdererType: "etcdraft",
136+
EtcdRaft: &etcdraft.Metadata{
137+
Consenters: consenters,
138+
Options: options,
139+
},
140+
},
141+
}
142+
}
143+
t.Run("EtcdRaft section not specified in profile", func(t *testing.T) {
144+
profile := &Profile{
145+
Orderer: &Orderer{
146+
OrdererType: "etcdraft",
147+
},
148+
}
149+
150+
assert.Panics(t, func() {
151+
profile.completeInitialization(devConfigDir)
152+
})
153+
})
154+
155+
t.Run("nil consenter set", func(t *testing.T) { // should panic
156+
profile := makeProfile(nil, nil)
157+
158+
assert.Panics(t, func() {
159+
profile.completeInitialization(devConfigDir)
160+
})
161+
})
162+
163+
t.Run("single consenter", func(t *testing.T) {
164+
consenters := []*etcdraft.Consenter{
165+
{
166+
Host: "node-1.example.com",
167+
Port: 7050,
168+
ClientTlsCert: []byte("path/to/client/cert"),
169+
ServerTlsCert: []byte("path/to/server/cert"),
170+
},
171+
}
172+
173+
t.Run("invalid consenters specification", func(t *testing.T) {
174+
failingConsenterSpecifications := []*etcdraft.Consenter{
175+
{ // missing Host
176+
Port: 7050,
177+
ClientTlsCert: []byte("path/to/client/cert"),
178+
ServerTlsCert: []byte("path/to/server/cert"),
179+
},
180+
{ // missing Port
181+
Host: "node-1.example.com",
182+
ClientTlsCert: []byte("path/to/client/cert"),
183+
ServerTlsCert: []byte("path/to/server/cert"),
184+
},
185+
{ // missing ClientTlsCert
186+
Host: "node-1.example.com",
187+
Port: 7050,
188+
ServerTlsCert: []byte("path/to/server/cert"),
189+
},
190+
{ // missing ServerTlsCert
191+
Host: "node-1.example.com",
192+
Port: 7050,
193+
ClientTlsCert: []byte("path/to/client/cert"),
194+
},
195+
}
196+
197+
for _, consenter := range failingConsenterSpecifications {
198+
profile := makeProfile([]*etcdraft.Consenter{consenter}, nil)
199+
200+
assert.Panics(t, func() {
201+
profile.completeInitialization(devConfigDir)
202+
})
203+
}
204+
})
205+
206+
t.Run("nil Options", func(t *testing.T) {
207+
profile := makeProfile(consenters, nil)
208+
profile.completeInitialization(devConfigDir)
209+
210+
// need not be tested in subsequent tests
211+
assert.NotNil(t, profile.Orderer.EtcdRaft, "EtcdRaft config settings should be set")
212+
assert.Equal(t, profile.Orderer.EtcdRaft.Consenters[0].ClientTlsCert, consenters[0].ClientTlsCert,
213+
"Client TLS cert path should be correctly set")
214+
215+
// specific assertion for this test context
216+
assert.Equal(t, profile.Orderer.EtcdRaft.Options, genesisDefaults.Orderer.EtcdRaft.Options,
217+
"Options should be set to the default value")
218+
})
219+
220+
t.Run("heartbeat tick specified in Options", func(t *testing.T) {
221+
heartbeatTick := uint32(2)
222+
options := &etcdraft.Options{ // partially set so that we can check that the other members are set to defaults
223+
HeartbeatTick: heartbeatTick,
224+
}
225+
profile := makeProfile(consenters, options)
226+
profile.completeInitialization(devConfigDir)
227+
228+
// specific assertions for this test context
229+
assert.Equal(t, profile.Orderer.EtcdRaft.Options.HeartbeatTick, heartbeatTick,
230+
"HeartbeatTick should be set to the specified value")
231+
assert.Equal(t, profile.Orderer.EtcdRaft.Options.ElectionTick, genesisDefaults.Orderer.EtcdRaft.Options.ElectionTick,
232+
"ElectionTick should be set to the default value")
233+
})
234+
235+
t.Run("election tick specified in Options", func(t *testing.T) {
236+
electionTick := uint32(20)
237+
options := &etcdraft.Options{ // partially set so that we can check that the other members are set to defaults
238+
ElectionTick: electionTick,
239+
}
240+
profile := makeProfile(consenters, options)
241+
profile.completeInitialization(devConfigDir)
242+
243+
// specific assertions for this test context
244+
assert.Equal(t, profile.Orderer.EtcdRaft.Options.ElectionTick, electionTick,
245+
"ElectionTick should be set to the specified value")
246+
assert.Equal(t, profile.Orderer.EtcdRaft.Options.HeartbeatTick, genesisDefaults.Orderer.EtcdRaft.Options.HeartbeatTick,
247+
"HeartbeatTick should be set to the default value")
248+
})
249+
250+
t.Run("panic on invalid options", func(t *testing.T) {
251+
options := &etcdraft.Options{
252+
HeartbeatTick: 2,
253+
ElectionTick: 1,
254+
}
255+
profile := makeProfile(consenters, options)
256+
257+
assert.Panics(t, func() {
258+
profile.completeInitialization(devConfigDir)
259+
})
260+
})
261+
})
262+
})
105263
}

protos/orderer/etcdraft/configuration.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0
77
package etcdraft
88

99
import (
10-
fmt "fmt"
10+
"fmt"
1111
"io/ioutil"
1212

1313
"github.com/hyperledger/fabric/protos/orderer"

0 commit comments

Comments
 (0)