Skip to content

Commit f42b999

Browse files
committed
[FAB-1362] Add KafkaBrokers to shared config
https://jira.hyperledger.org/browse/FAB-1362 The list of Kafka brokers used for ordering needs to be shared across the shims (ordering service nodes). This changeset introduces the key and the getter of that key's value to the sharedconfig package. It also adds the necessary definition in the orderer protos. This value is not yet encoded as a configuration item in the genesis block that the static bootstrapper produces. This will come at a subsequent changeset, with the introduction of the provisional bootstrapper. Change-Id: I6268e79dc25ca2cee8da248ba44c9a572c04d909 Signed-off-by: Kostas Christidis <[email protected]>
1 parent be08bc5 commit f42b999

File tree

8 files changed

+211
-48
lines changed

8 files changed

+211
-48
lines changed

orderer/common/sharedconfig/sharedconfig.go

+73-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ package sharedconfig
1818

1919
import (
2020
"fmt"
21+
"regexp"
22+
"strconv"
23+
"strings"
2124

2225
cb "github.com/hyperledger/fabric/protos/common"
2326
ab "github.com/hyperledger/fabric/protos/orderer"
@@ -26,14 +29,19 @@ import (
2629
"github.com/op/go-logging"
2730
)
2831

29-
// ConsensusTypeKey is the cb.ConfigurationItem type key name for the ConsensusType message
30-
const ConsensusTypeKey = "ConsensusType"
32+
const (
33+
// ConsensusTypeKey is the cb.ConfigurationItem type key name for the ConsensusType message
34+
ConsensusTypeKey = "ConsensusType"
3135

32-
// BatchSizeKey is the cb.ConfigurationItem type key name for the BatchSize message
33-
const BatchSizeKey = "BatchSize"
36+
// BatchSizeKey is the cb.ConfigurationItem type key name for the BatchSize message
37+
BatchSizeKey = "BatchSize"
3438

35-
// ChainCreatorsKey is the cb.ConfigurationItem type key name for the ChainCreators message
36-
const ChainCreatorsKey = "ChainCreators"
39+
// ChainCreatorsKey is the cb.ConfigurationItem type key name for the ChainCreators message
40+
ChainCreatorsKey = "ChainCreators"
41+
42+
// KafkaBrokersKey is the cb.ConfigurationItem type key name for the KafkaBrokers message
43+
KafkaBrokersKey = "KafkaBrokers"
44+
)
3745

3846
var logger = logging.MustGetLogger("orderer/common/sharedconfig")
3947

@@ -55,12 +63,18 @@ type Manager interface {
5563
// ChainCreators returns the policy names which are allowed for chain creation
5664
// This field is only set for the system ordering chain
5765
ChainCreators() []string
66+
67+
// KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
68+
// Kafka brokers, i.e. this is not necessarily the entire set of Kafka brokers
69+
// used for ordering
70+
KafkaBrokers() []string
5871
}
5972

6073
type ordererConfig struct {
6174
consensusType string
6275
batchSize uint32
6376
chainCreators []string
77+
kafkaBrokers []string
6478
}
6579

6680
// ManagerImpl is an implementation of Manager and configtx.ConfigHandler
@@ -93,6 +107,13 @@ func (pm *ManagerImpl) ChainCreators() []string {
93107
return pm.config.chainCreators
94108
}
95109

110+
// KafkaBrokers returns the addresses (IP:port notation) of a set of "bootstrap"
111+
// Kafka brokers, i.e. this is not necessarily the entire set of Kafka brokers
112+
// used for ordering
113+
func (pm *ManagerImpl) KafkaBrokers() []string {
114+
return pm.config.kafkaBrokers
115+
}
116+
96117
// BeginConfig is used to start a new configuration proposal
97118
func (pm *ManagerImpl) BeginConfig() {
98119
if pm.pendingConfig != nil {
@@ -135,7 +156,6 @@ func (pm *ManagerImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
135156
if consensusType.Type != pm.config.consensusType {
136157
return fmt.Errorf("Attempted to change the consensus type from %s to %s after init", pm.config.consensusType, consensusType.Type)
137158
}
138-
139159
pm.pendingConfig.consensusType = consensusType.Type
140160
case BatchSizeKey:
141161
batchSize := &ab.BatchSize{}
@@ -147,17 +167,60 @@ func (pm *ManagerImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
147167
if batchSize.Messages <= 0 {
148168
return fmt.Errorf("Attempted to set the batch size to %d which is less than or equal to 0", batchSize.Messages)
149169
}
150-
151170
pm.pendingConfig.batchSize = batchSize.Messages
152171
case ChainCreatorsKey:
153172
chainCreators := &ab.ChainCreators{}
154173
err := proto.Unmarshal(configItem.Value, chainCreators)
155174
if err != nil {
156175
return fmt.Errorf("Unmarshaling error for ChainCreator: %s", err)
157176
}
158-
159177
pm.pendingConfig.chainCreators = chainCreators.Policies
178+
case KafkaBrokersKey:
179+
kafkaBrokers := &ab.KafkaBrokers{}
180+
err := proto.Unmarshal(configItem.Value, kafkaBrokers)
181+
if err != nil {
182+
return fmt.Errorf("Unmarshaling error for KafkaBrokers: %s", err)
183+
}
184+
if len(kafkaBrokers.Brokers) == 0 {
185+
return fmt.Errorf("Kafka broker set cannot be nil")
186+
}
187+
for _, broker := range kafkaBrokers.Brokers {
188+
if !brokerEntrySeemsValid(broker) {
189+
return fmt.Errorf("Invalid broker entry: %s", broker)
190+
}
191+
}
192+
pm.pendingConfig.kafkaBrokers = kafkaBrokers.Brokers
160193
}
161-
162194
return nil
163195
}
196+
197+
// This does just a barebones sanitfy check.
198+
func brokerEntrySeemsValid(broker string) bool {
199+
if !strings.Contains(broker, ":") {
200+
return false
201+
}
202+
203+
parts := strings.Split(broker, ":")
204+
if len(parts) > 2 {
205+
return false
206+
}
207+
208+
host := parts[0]
209+
port := parts[1]
210+
211+
if _, err := strconv.ParseUint(port, 10, 16); err != nil {
212+
return false
213+
}
214+
215+
// Valid hostnames may contain only the ASCII letters 'a' through 'z' (in a
216+
// case-insensitive manner), the digits '0' through '9', and the hyphen. IP
217+
// v4 addresses are represented in dot-decimal notation, which consists of
218+
// four decimal numbers, each ranging from 0 to 255, separated by dots,
219+
// e.g., 172.16.254.1
220+
// The following regular expression:
221+
// 1. allows just a-z (case-insensitive), 0-9, and the dot and hyphen characters
222+
// 2. does not allow leading trailing dots or hyphens
223+
re, _ := regexp.Compile("^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9])$")
224+
matched := re.FindString(host)
225+
return len(matched) == len(host)
226+
}

orderer/common/sharedconfig/sharedconfig_test.go

+72-8
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ func TestCommitWithoutBegin(t *testing.T) {
6262
if !crashes {
6363
t.Fatalf("Should have crashed on multiple begin configs")
6464
}
65-
6665
}
6766

6867
func TestRollback(t *testing.T) {
@@ -123,17 +122,15 @@ func TestConsensusType(t *testing.T) {
123122
if nowType := m.ConsensusType(); nowType != endType {
124123
t.Fatalf("Consensus type should have ended as %s but was %s", endType, nowType)
125124
}
126-
127125
}
128126

129127
func TestBatchSize(t *testing.T) {
130128
endBatchSize := uint32(10)
131-
invalidMessage :=
132-
&cb.ConfigurationItem{
133-
Type: cb.ConfigurationItem_Orderer,
134-
Key: BatchSizeKey,
135-
Value: []byte("Garbage Data"),
136-
}
129+
invalidMessage := &cb.ConfigurationItem{
130+
Type: cb.ConfigurationItem_Orderer,
131+
Key: BatchSizeKey,
132+
Value: []byte("Garbage Data"),
133+
}
137134
zeroBatchSize := &cb.ConfigurationItem{
138135
Type: cb.ConfigurationItem_Orderer,
139136
Key: BatchSizeKey,
@@ -167,5 +164,72 @@ func TestBatchSize(t *testing.T) {
167164
if nowBatchSize := m.BatchSize(); nowBatchSize != endBatchSize {
168165
t.Fatalf("Got batch size of %d when expecting batch size of %d", nowBatchSize, endBatchSize)
169166
}
167+
}
168+
169+
func TestKafkaBrokers(t *testing.T) {
170+
endList := []string{"127.0.0.1:9092", "foo.bar:9092"}
171+
172+
invalidMessage := &cb.ConfigurationItem{
173+
Type: cb.ConfigurationItem_Orderer,
174+
Key: KafkaBrokersKey,
175+
Value: []byte("Garbage Data"),
176+
}
177+
178+
zeroBrokers := &cb.ConfigurationItem{
179+
Type: cb.ConfigurationItem_Orderer,
180+
Key: KafkaBrokersKey,
181+
Value: utils.MarshalOrPanic(&ab.KafkaBrokers{}),
182+
}
183+
184+
badList := []string{"127.0.0.1", "foo.bar", "127.0.0.1:-1", "localhost:65536", "foo.bar.:9092", ".127.0.0.1:9092", "-foo.bar:9092"}
185+
badMessages := []*cb.ConfigurationItem{}
186+
for _, badAddress := range badList {
187+
msg := &cb.ConfigurationItem{
188+
Type: cb.ConfigurationItem_Orderer,
189+
Key: KafkaBrokersKey,
190+
Value: utils.MarshalOrPanic(&ab.KafkaBrokers{Brokers: []string{badAddress}}),
191+
}
192+
badMessages = append(badMessages, msg)
193+
}
194+
195+
validMessage := &cb.ConfigurationItem{
196+
Type: cb.ConfigurationItem_Orderer,
197+
Key: KafkaBrokersKey,
198+
Value: utils.MarshalOrPanic(&ab.KafkaBrokers{Brokers: endList}),
199+
}
200+
201+
m := NewManagerImpl()
202+
m.BeginConfig()
203+
204+
err := m.ProposeConfig(validMessage)
205+
if err != nil {
206+
t.Fatalf("Error applying valid config: %s", err)
207+
}
208+
209+
err = m.ProposeConfig(invalidMessage)
210+
if err == nil {
211+
t.Fatalf("Should have failed on invalid message")
212+
}
213+
214+
err = m.ProposeConfig(zeroBrokers)
215+
if err == nil {
216+
t.Fatalf("Should have rejected empty brokers list")
217+
}
170218

219+
for i := range badMessages {
220+
err = m.ProposeConfig(badMessages[i])
221+
if err == nil {
222+
t.Fatalf("Should have rejected broker address which is obviously malformed")
223+
}
224+
}
225+
226+
m.CommitConfig()
227+
228+
nowList := m.KafkaBrokers()
229+
switch {
230+
case len(nowList) != len(endList), nowList[0] != endList[0]:
231+
t.Fatalf("Got brokers list %s when expecting brokers list %s", nowList, endList)
232+
default:
233+
return
234+
}
171235
}

orderer/mocks/sharedconfig/sharedconfig.go

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type Manager struct {
2424
BatchSizeVal uint32
2525
// ChainCreatorsVal is returned as the result of ChainCreators()
2626
ChainCreatorsVal []string
27+
// KafkaBrokersVal is returned as the result of KafkaBrokers()
28+
KafkaBrokersVal []string
2729
}
2830

2931
// ConsensusType returns the ConsensusTypeVal
@@ -40,3 +42,8 @@ func (scm *Manager) BatchSize() uint32 {
4042
func (scm *Manager) ChainCreators() []string {
4143
return scm.ChainCreatorsVal
4244
}
45+
46+
// KafkaBrokers returns the KafkaBrokersVal
47+
func (scm *Manager) KafkaBrokers() []string {
48+
return scm.KafkaBrokersVal
49+
}

orderer/multichain/systemchain_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ func (msc *mockSharedConfig) ChainCreators() []string {
6262
return msc.chainCreators
6363
}
6464

65+
func (msc *mockSharedConfig) KafkaBrokers() []string {
66+
panic("Unimplemented")
67+
}
68+
6569
type mockSupport struct {
6670
mpm *mockPolicyManager
6771
msc *mockSharedConfig

protos/common/common.proto

+5-5
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ enum Status {
3535
}
3636

3737
enum HeaderType {
38-
MESSAGE = 0; // Used for messages which are signed but opaque
39-
CONFIGURATION_TRANSACTION = 1; // Used for messages which reconfigure the chain
40-
CONFIGURATION_ITEM = 2; // Used inside of the the reconfiguration message for signing over ConfigurationItems
41-
ENDORSER_TRANSACTION = 3; // Used by the SDK to submit endorser based transactions
42-
ORDERER_TRANSACTION = 4; // Used internally by the orderer for management
38+
MESSAGE = 0; // Used for messages which are signed but opaque
39+
CONFIGURATION_TRANSACTION = 1; // Used for messages which reconfigure the chain
40+
CONFIGURATION_ITEM = 2; // Used inside of the the reconfiguration message for signing over ConfigurationItems
41+
ENDORSER_TRANSACTION = 3; // Used by the SDK to submit endorser based transactions
42+
ORDERER_TRANSACTION = 4; // Used internally by the orderer for management
4343
}
4444

4545
// This enum enlist indexes of the block metadata array

protos/orderer/ab.pb.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protos/orderer/configuration.pb.go

+27-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)