Skip to content

Commit 1066230

Browse files
author
Jason Yellick
committed
[FAB-2638] configtx inspection to include policies
https://jira.hyperledger.org/browse/FAB-2638 The configtxgen tool can currently dump the contents of a config block or config transaction to JSON. It however only dumps the config values and not the policies. This CR enhances the tool to additionally dump the deserialized policy values for inspection. Change-Id: I64f40763c3db8a81ffb2120a21d8e7fdabf0f96d Signed-off-by: Jason Yellick <[email protected]>
1 parent 54dc537 commit 1066230

File tree

11 files changed

+113
-49
lines changed

11 files changed

+113
-49
lines changed

common/cauthdsl/policy.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,24 @@ func NewPolicyProvider(deserializer msp.IdentityDeserializer) policies.Provider
3939
}
4040

4141
// NewPolicy creates a new policy based on the policy bytes
42-
func (pr *provider) NewPolicy(data []byte) (policies.Policy, error) {
42+
func (pr *provider) NewPolicy(data []byte) (policies.Policy, proto.Message, error) {
4343
sigPolicy := &cb.SignaturePolicyEnvelope{}
4444
if err := proto.Unmarshal(data, sigPolicy); err != nil {
45-
return nil, fmt.Errorf("Error unmarshaling to SignaturePolicy: %s", err)
45+
return nil, nil, fmt.Errorf("Error unmarshaling to SignaturePolicy: %s", err)
4646
}
4747

4848
if sigPolicy.Version != 0 {
49-
return nil, fmt.Errorf("This evaluator only understands messages of version 0, but version was %d", sigPolicy.Version)
49+
return nil, nil, fmt.Errorf("This evaluator only understands messages of version 0, but version was %d", sigPolicy.Version)
5050
}
5151

5252
compiled, err := compile(sigPolicy.Policy, sigPolicy.Identities, pr.deserializer)
5353
if err != nil {
54-
return nil, err
54+
return nil, nil, err
5555
}
5656

5757
return &policy{
5858
evaluator: compiled,
59-
}, nil
59+
}, sigPolicy, nil
6060

6161
}
6262

common/cauthdsl/policy_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func makePolicySource(policyResult bool) *cb.Policy {
5858

5959
func addPolicy(manager policies.Proposer, id string, policy *cb.Policy) {
6060
manager.BeginPolicyProposals(id, nil)
61-
err := manager.ProposePolicy(id, id, &cb.ConfigPolicy{
61+
_, err := manager.ProposePolicy(id, id, &cb.ConfigPolicy{
6262
Policy: policy,
6363
})
6464
if err != nil {

common/configtx/api/api.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"github.com/hyperledger/fabric/common/policies"
2222
"github.com/hyperledger/fabric/msp"
2323
cb "github.com/hyperledger/fabric/protos/common"
24+
25+
"github.com/golang/protobuf/proto"
2426
)
2527

2628
// Manager provides a mechanism to query and update config
@@ -81,7 +83,7 @@ type PolicyHandler interface {
8183

8284
BeginConfig(tx interface{}, groups []string) ([]PolicyHandler, error)
8385

84-
ProposePolicy(tx interface{}, key string, path []string, policy *cb.ConfigPolicy) error
86+
ProposePolicy(tx interface{}, key string, path []string, policy *cb.ConfigPolicy) (proto.Message, error)
8587
}
8688

8789
// Proposer contains the references necesssary to appropriately unmarshal

common/configtx/config.go

+52-14
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@ func NewConfigResult(config *cb.ConfigGroup, proposer api.Proposer) (ConfigResul
3838
}
3939

4040
type configResult struct {
41-
tx interface{}
42-
groupName string
43-
group *cb.ConfigGroup
44-
valueHandler config.ValueProposer
45-
policyHandler policies.Proposer
46-
subResults []*configResult
47-
deserializedValues map[string]proto.Message
41+
tx interface{}
42+
groupName string
43+
group *cb.ConfigGroup
44+
valueHandler config.ValueProposer
45+
policyHandler policies.Proposer
46+
subResults []*configResult
47+
deserializedValues map[string]proto.Message
48+
deserializedPolicies map[string]proto.Message
4849
}
4950

5051
func (cr *configResult) JSON() string {
@@ -101,6 +102,40 @@ func (cr *configResult) bufferJSON(buffer *bytes.Buffer) {
101102
// },
102103
buffer.WriteString("},")
103104

105+
count = 0
106+
// "Policies": {
107+
buffer.WriteString("\"Policies\": {")
108+
for key, policy := range cr.group.Policies {
109+
// "Key": {
110+
buffer.WriteString("\"")
111+
buffer.WriteString(key)
112+
buffer.WriteString("\": {")
113+
// "Version": "X",
114+
buffer.WriteString("\"Version\":\"")
115+
buffer.WriteString(fmt.Sprintf("%d", policy.Version))
116+
buffer.WriteString("\",")
117+
// "ModPolicy": "foo",
118+
buffer.WriteString("\"ModPolicy\":\"")
119+
buffer.WriteString(policy.ModPolicy)
120+
buffer.WriteString("\",")
121+
// "Policy": {
122+
buffer.WriteString("\"Policy\":{")
123+
// "PolicyType" :
124+
buffer.WriteString(fmt.Sprintf("\"PolicyType\":\"%d\",", policy.Policy.Type))
125+
// "Policy" : policyAsJSON
126+
buffer.WriteString("\"Policy\":")
127+
jpb.Marshal(buffer, cr.deserializedPolicies[key])
128+
// }
129+
// },
130+
buffer.WriteString("}}")
131+
count++
132+
if count < len(cr.group.Policies) {
133+
buffer.WriteString(",")
134+
}
135+
}
136+
// },
137+
buffer.WriteString("},")
138+
104139
// "Groups": {
105140
count = 0
106141
buffer.WriteString("\"Groups\": {")
@@ -181,22 +216,25 @@ func proposeGroup(result *configResult) error {
181216
}
182217

183218
for key, policy := range result.group.Policies {
184-
if err := result.policyHandler.ProposePolicy(result.tx, key, policy); err != nil {
219+
policy, err := result.policyHandler.ProposePolicy(result.tx, key, policy)
220+
if err != nil {
185221
result.rollback()
186222
return err
187223
}
224+
result.deserializedPolicies[key] = policy
188225
}
189226

190227
result.subResults = make([]*configResult, 0, len(subGroups))
191228

192229
for i, subGroup := range subGroups {
193230
result.subResults = append(result.subResults, &configResult{
194-
tx: result.tx,
195-
groupName: result.groupName + "/" + subGroup,
196-
group: result.group.Groups[subGroup],
197-
valueHandler: subValueHandlers[i],
198-
policyHandler: subPolicyHandlers[i],
199-
deserializedValues: make(map[string]proto.Message),
231+
tx: result.tx,
232+
groupName: result.groupName + "/" + subGroup,
233+
group: result.group.Groups[subGroup],
234+
valueHandler: subValueHandlers[i],
235+
policyHandler: subPolicyHandlers[i],
236+
deserializedValues: make(map[string]proto.Message),
237+
deserializedPolicies: make(map[string]proto.Message),
200238
})
201239

202240
if err := proposeGroup(result.subResults[i]); err != nil {

common/configtx/config_test.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,33 @@ func TestJSON(t *testing.T) {
4444
Values: map[string]*cb.ConfigValue{
4545
"inner1": &cb.ConfigValue{ModPolicy: "mod3"},
4646
},
47+
Policies: map[string]*cb.ConfigPolicy{
48+
"policy1": &cb.ConfigPolicy{Policy: &cb.Policy{}, ModPolicy: "mod1"},
49+
},
4750
},
4851
deserializedValues: map[string]proto.Message{
4952
"inner1": &ab.ConsensusType{Type: "inner1"},
5053
},
54+
deserializedPolicies: map[string]proto.Message{
55+
"policy1": &ab.ConsensusType{Type: "policy1"},
56+
},
5157
},
5258
&configResult{
5359
groupName: "innerGroup2",
5460
group: &cb.ConfigGroup{
5561
Values: map[string]*cb.ConfigValue{
5662
"inner2": &cb.ConfigValue{ModPolicy: "mod3"},
5763
},
64+
Policies: map[string]*cb.ConfigPolicy{
65+
"policy2": &cb.ConfigPolicy{Policy: &cb.Policy{Type: 1}, ModPolicy: "mod2"},
66+
},
5867
},
5968
deserializedValues: map[string]proto.Message{
6069
"inner2": &ab.ConsensusType{Type: "inner2"},
6170
},
71+
deserializedPolicies: map[string]proto.Message{
72+
"policy2": &ab.ConsensusType{Type: "policy2"},
73+
},
6274
},
6375
},
6476
deserializedValues: map[string]proto.Message{
@@ -69,11 +81,10 @@ func TestJSON(t *testing.T) {
6981
buffer := &bytes.Buffer{}
7082
assert.NoError(t, json.Indent(buffer, []byte(cr.JSON()), "", ""), "JSON should parse nicely")
7183

72-
expected := "{\"rootGroup\":{\"Values\":{\"outer\":{\"Version\":\"1\",\"ModPolicy\":\"mod1\",\"Value\":{\"type\":\"outer\"}}},\"Groups\":{\"innerGroup1\":{\"Values\":{\"inner1\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner1\"}}},\"Groups\":{}},\"innerGroup2\":{\"Values\":{\"inner2\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner2\"}}},\"Groups\":{}}}}}"
84+
expected := "{\"rootGroup\":{\"Values\":{\"outer\":{\"Version\":\"1\",\"ModPolicy\":\"mod1\",\"Value\":{\"type\":\"outer\"}}},\"Policies\":{},\"Groups\":{\"innerGroup1\":{\"Values\":{\"inner1\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner1\"}}},\"Policies\":{\"policy1\":{\"Version\":\"0\",\"ModPolicy\":\"mod1\",\"Policy\":{\"PolicyType\":\"0\",\"Policy\":{\"type\":\"policy1\"}}}},\"Groups\":{}},\"innerGroup2\":{\"Values\":{\"inner2\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner2\"}}},\"Policies\":{\"policy2\":{\"Version\":\"0\",\"ModPolicy\":\"mod2\",\"Policy\":{\"PolicyType\":\"1\",\"Policy\":{\"type\":\"policy2\"}}}},\"Groups\":{}}}}}"
7385

7486
// Remove all newlines and spaces from the JSON
7587
compactedJSON := strings.Replace(strings.Replace(buffer.String(), "\n", "", -1), " ", "", -1)
7688

7789
assert.Equal(t, expected, compactedJSON)
78-
7990
}

common/configtx/initializer.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/hyperledger/fabric/common/policies"
2727
"github.com/hyperledger/fabric/msp"
2828
cb "github.com/hyperledger/fabric/protos/common"
29+
30+
"github.com/golang/protobuf/proto"
2931
)
3032

3133
type resources struct {
@@ -94,8 +96,8 @@ func (p *policyProposerRoot) BeginPolicyProposals(tx interface{}, groups []strin
9496
return []policies.Proposer{p.policyManager}, nil
9597
}
9698

97-
func (i *policyProposerRoot) ProposePolicy(tx interface{}, key string, policy *cb.ConfigPolicy) error {
98-
return fmt.Errorf("Programming error, this should never be invoked")
99+
func (i *policyProposerRoot) ProposePolicy(tx interface{}, key string, policy *cb.ConfigPolicy) (proto.Message, error) {
100+
return nil, fmt.Errorf("Programming error, this should never be invoked")
99101
}
100102

101103
// PreCommit is a no-op and returns nil

common/configtx/tool/configtxgen/main.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ func doInspectBlock(inspectBlock string) error {
115115
}
116116

117117
buffer := &bytes.Buffer{}
118-
json.Indent(buffer, []byte(configResult.JSON()), "", " ")
118+
err = json.Indent(buffer, []byte(configResult.JSON()), "", " ")
119+
if err != nil {
120+
return fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
121+
}
119122

120123
fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
121124

@@ -170,7 +173,10 @@ func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
170173
}
171174

172175
buffer := &bytes.Buffer{}
173-
json.Indent(buffer, []byte(configResult.JSON()), "", " ")
176+
err = json.Indent(buffer, []byte(configResult.JSON()), "", " ")
177+
if err != nil {
178+
return fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
179+
}
174180

175181
fmt.Printf("Config for channel: %s\n", header.ChannelId)
176182

common/mocks/configtx/configtx.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ type PolicyProposer struct {
110110
}
111111

112112
// ProposeConfig sets LastKey to key, LastPath to path, and LastPolicy to configPolicy, returning ErrorForProposedConfig
113-
func (pp *PolicyProposer) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) error {
113+
func (pp *PolicyProposer) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) (proto.Message, error) {
114114
pp.LastKey = key
115115
pp.LastPolicy = configPolicy
116-
return pp.ErrorForProposePolicy
116+
return nil, pp.ErrorForProposePolicy
117117
}
118118

119119
// BeginConfig will be removed in the future

common/policies/policy.go

+15-10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
cb "github.com/hyperledger/fabric/protos/common"
2525

26+
"github.com/golang/protobuf/proto"
2627
logging "github.com/op/go-logging"
2728
)
2829

@@ -86,8 +87,9 @@ type Proposer interface {
8687
// BeginPolicyProposals starts a policy update transaction
8788
BeginPolicyProposals(tx interface{}, groups []string) ([]Proposer, error)
8889

89-
// ProposePolicy createss a pending policy update from a ConfigPolicy
90-
ProposePolicy(tx interface{}, name string, policy *cb.ConfigPolicy) error
90+
// ProposePolicy createss a pending policy update from a ConfigPolicy and returns the deserialized
91+
// value of the Policy representation
92+
ProposePolicy(tx interface{}, name string, policy *cb.ConfigPolicy) (proto.Message, error)
9193

9294
// RollbackProposals discards the pending policy updates
9395
RollbackProposals(tx interface{})
@@ -102,7 +104,7 @@ type Proposer interface {
102104
// Provider provides the backing implementation of a policy
103105
type Provider interface {
104106
// NewPolicy creates a new policy based on the policy bytes
105-
NewPolicy(data []byte) (Policy, error)
107+
NewPolicy(data []byte) (Policy, proto.Message, error)
106108
}
107109

108110
// ChannelPolicyManagerGetter is a support interface
@@ -324,7 +326,8 @@ func (pm *ManagerImpl) CommitProposals(tx interface{}) {
324326
}
325327

326328
// ProposePolicy takes key, path, and ConfigPolicy and registers it in the proposed PolicyManager, or errors
327-
func (pm *ManagerImpl) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) error {
329+
// It also returns the deserialized policy value for tracking and inspection at the invocation side.
330+
func (pm *ManagerImpl) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) (proto.Message, error) {
328331
pm.pendingLock.RLock()
329332
pendingConfig, ok := pm.pendingConfig[tx]
330333
pm.pendingLock.RUnlock()
@@ -334,33 +337,35 @@ func (pm *ManagerImpl) ProposePolicy(tx interface{}, key string, configPolicy *c
334337

335338
policy := configPolicy.Policy
336339
if policy == nil {
337-
return fmt.Errorf("Policy cannot be nil")
340+
return nil, fmt.Errorf("Policy cannot be nil")
338341
}
339342

340343
var cPolicy Policy
344+
var deserialized proto.Message
341345

342346
if policy.Type == int32(cb.Policy_IMPLICIT_META) {
343347
imp, err := newImplicitMetaPolicy(policy.Policy)
344348
if err != nil {
345-
return err
349+
return nil, err
346350
}
347351
pendingConfig.imps = append(pendingConfig.imps, imp)
348352
cPolicy = imp
353+
deserialized = imp.conf
349354
} else {
350355
provider, ok := pm.providers[int32(policy.Type)]
351356
if !ok {
352-
return fmt.Errorf("Unknown policy type: %v", policy.Type)
357+
return nil, fmt.Errorf("Unknown policy type: %v", policy.Type)
353358
}
354359

355360
var err error
356-
cPolicy, err = provider.NewPolicy(policy.Policy)
361+
cPolicy, deserialized, err = provider.NewPolicy(policy.Policy)
357362
if err != nil {
358-
return err
363+
return nil, err
359364
}
360365
}
361366

362367
pendingConfig.policies[key] = cPolicy
363368

364369
logger.Debugf("Proposed new policy %s for %s", key, pm.basePath)
365-
return nil
370+
return deserialized, nil
366371
}

common/policies/policy_test.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121

2222
cb "github.com/hyperledger/fabric/protos/common"
2323

24-
"github.com/stretchr/testify/assert"
25-
24+
"github.com/golang/protobuf/proto"
2625
logging "github.com/op/go-logging"
26+
"github.com/stretchr/testify/assert"
2727
)
2828

2929
func init() {
@@ -32,8 +32,8 @@ func init() {
3232

3333
type mockProvider struct{}
3434

35-
func (mpp mockProvider) NewPolicy(data []byte) (Policy, error) {
36-
return nil, nil
35+
func (mpp mockProvider) NewPolicy(data []byte) (Policy, proto.Message, error) {
36+
return nil, nil, nil
3737
}
3838

3939
const mockType = int32(0)
@@ -53,7 +53,7 @@ func TestUnnestedManager(t *testing.T) {
5353
policyNames := []string{"1", "2", "3"}
5454

5555
for _, policyName := range policyNames {
56-
err := m.ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
56+
_, err := m.ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
5757
assert.NoError(t, err)
5858
}
5959

@@ -90,25 +90,25 @@ func TestNestedManager(t *testing.T) {
9090

9191
policyNames := []string{"n0a", "n0b", "n0c"}
9292
for _, policyName := range policyNames {
93-
err := m.ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
93+
_, err := m.ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
9494
assert.NoError(t, err)
9595
}
9696

9797
n1PolicyNames := []string{"n1a", "n1b", "n1c"}
9898
for _, policyName := range n1PolicyNames {
99-
err := nesting1[0].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
99+
_, err := nesting1[0].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
100100
assert.NoError(t, err)
101101
}
102102

103103
n2aPolicyNames := []string{"n2a_1", "n2a_2", "n2a_3"}
104104
for _, policyName := range n2aPolicyNames {
105-
err := nesting2[0].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
105+
_, err := nesting2[0].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
106106
assert.NoError(t, err)
107107
}
108108

109109
n2bPolicyNames := []string{"n2b_1", "n2b_2", "n2b_3"}
110110
for _, policyName := range n2bPolicyNames {
111-
err := nesting2[1].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
111+
_, err := nesting2[1].ProposePolicy(t, policyName, &cb.ConfigPolicy{Policy: &cb.Policy{Type: mockType}})
112112
assert.NoError(t, err)
113113
}
114114

0 commit comments

Comments
 (0)