Skip to content

Commit a971b0f

Browse files
author
Jason Yellick
committed
[FAB-2319] Implement hierarchical policies storage
https://jira.hyperledger.org/browse/FAB-2319 This CR finally removes the hack of only handling policies stored at the root channel level and creates a policy manager at each level of the config. It also rolls up the policy managers so that policy managers at a higher level may reference policies at a lower level. Change-Id: I18f616ecfc3929f03defdbe02f8a253d0c6b2f69 Signed-off-by: Jason Yellick <[email protected]>
1 parent fee7c6c commit a971b0f

File tree

14 files changed

+453
-183
lines changed

14 files changed

+453
-183
lines changed

common/cauthdsl/policy_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ func makePolicySource(policyResult bool) *cb.Policy {
5656
}
5757
}
5858

59-
func addPolicy(manager *policies.ManagerImpl, id string, policy *cb.Policy) {
60-
manager.BeginConfig(nil)
61-
err := manager.ProposePolicy(id, []string{}, &cb.ConfigPolicy{
59+
func addPolicy(manager policies.Proposer, id string, policy *cb.Policy) {
60+
manager.BeginPolicyProposals(nil)
61+
err := manager.ProposePolicy(id, &cb.ConfigPolicy{
6262
Policy: policy,
6363
})
6464
if err != nil {
@@ -75,7 +75,7 @@ func providerMap() map[int32]policies.Provider {
7575

7676
func TestAccept(t *testing.T) {
7777
policyID := "policyID"
78-
m := policies.NewManagerImpl(providerMap())
78+
m := policies.NewManagerImpl("test", providerMap())
7979
addPolicy(m, policyID, acceptAllPolicy)
8080
policy, ok := m.GetPolicy(policyID)
8181
if !ok {
@@ -89,7 +89,7 @@ func TestAccept(t *testing.T) {
8989

9090
func TestReject(t *testing.T) {
9191
policyID := "policyID"
92-
m := policies.NewManagerImpl(providerMap())
92+
m := policies.NewManagerImpl("test", providerMap())
9393
addPolicy(m, policyID, rejectAllPolicy)
9494
policy, ok := m.GetPolicy(policyID)
9595
if !ok {
@@ -102,7 +102,7 @@ func TestReject(t *testing.T) {
102102
}
103103

104104
func TestRejectOnUnknown(t *testing.T) {
105-
m := policies.NewManagerImpl(providerMap())
105+
m := policies.NewManagerImpl("test", providerMap())
106106
policy, ok := m.GetPolicy("FakePolicyID")
107107
if ok {
108108
t.Error("Should not have found policy which was never added, but did")

common/configtx/api/api.go

+4-9
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,11 @@ type PolicyHandler interface {
8484
// Initializer is used as indirection between Manager and Handler to allow
8585
// for single Handlers to handle multiple paths
8686
type Initializer interface {
87-
// ProposeValue is used for propsing group values
88-
ProposeValue(key string, configValue *cb.ConfigValue) error
87+
// ValueProposer return the root value proposer
88+
ValueProposer() configvalues.ValueProposer
8989

90-
// BeginValueProposals is called when a config proposal is begun
91-
BeginValueProposals(groups []string) ([]configvalues.ValueProposer, error)
92-
93-
Transactional
90+
// PolicyProposer return the root policy proposer
91+
PolicyProposer() policies.Proposer
9492

9593
Resources
96-
97-
// PolicyProposer returns the PolicyHandler to handle updates to policy
98-
PolicyHandler() PolicyHandler
9994
}

common/configtx/config.go

+24-28
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,37 @@ import (
2121

2222
"github.com/hyperledger/fabric/common/configtx/api"
2323
configvaluesapi "github.com/hyperledger/fabric/common/configvalues/api"
24+
"github.com/hyperledger/fabric/common/policies"
2425
cb "github.com/hyperledger/fabric/protos/common"
2526
)
2627

2728
type configResult struct {
28-
handler api.Transactional
29-
subResults []*configResult
29+
handler api.Transactional
30+
policyHandler api.Transactional
31+
subResults []*configResult
3032
}
3133

3234
func (cr *configResult) commit() {
3335
for _, subResult := range cr.subResults {
3436
subResult.commit()
3537
}
3638
cr.handler.CommitProposals()
39+
cr.policyHandler.CommitProposals()
3740
}
3841

3942
func (cr *configResult) rollback() {
4043
for _, subResult := range cr.subResults {
4144
subResult.rollback()
4245
}
4346
cr.handler.RollbackProposals()
47+
cr.policyHandler.RollbackProposals()
4448
}
4549

4650
// proposeGroup proposes a group configuration with a given handler
4751
// it will in turn recursively call itself until all groups have been exhausted
4852
// at each call, it returns the handler that was passed in, plus any handlers returned
4953
// by recursive calls into proposeGroup
50-
func (cm *configManager) proposeGroup(name string, group *cb.ConfigGroup, handler configvaluesapi.ValueProposer) (*configResult, error) {
54+
func (cm *configManager) proposeGroup(name string, group *cb.ConfigGroup, handler configvaluesapi.ValueProposer, policyHandler policies.Proposer) (*configResult, error) {
5155
subGroups := make([]string, len(group.Groups))
5256
i := 0
5357
for subGroup := range group.Groups {
@@ -61,17 +65,23 @@ func (cm *configManager) proposeGroup(name string, group *cb.ConfigGroup, handle
6165
return nil, err
6266
}
6367

64-
if len(subHandlers) != len(subGroups) {
65-
return nil, fmt.Errorf("Programming error, did not return as many handlers as groups %d vs %d", len(subHandlers), len(subGroups))
68+
subPolicyHandlers, err := policyHandler.BeginPolicyProposals(subGroups)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
if len(subHandlers) != len(subGroups) || len(subPolicyHandlers) != len(subGroups) {
74+
return nil, fmt.Errorf("Programming error, did not return as many handlers as groups %d vs %d vs %d", len(subHandlers), len(subGroups), len(subPolicyHandlers))
6675
}
6776

6877
result := &configResult{
69-
handler: handler,
70-
subResults: make([]*configResult, 0, len(subGroups)),
78+
handler: handler,
79+
policyHandler: policyHandler,
80+
subResults: make([]*configResult, 0, len(subGroups)),
7181
}
7282

7383
for i, subGroup := range subGroups {
74-
subResult, err := cm.proposeGroup(name+"/"+subGroup, group.Groups[subGroup], subHandlers[i])
84+
subResult, err := cm.proposeGroup(name+"/"+subGroup, group.Groups[subGroup], subHandlers[i], subPolicyHandlers[i])
7585
if err != nil {
7686
result.rollback()
7787
return nil, err
@@ -86,37 +96,23 @@ func (cm *configManager) proposeGroup(name string, group *cb.ConfigGroup, handle
8696
}
8797
}
8898

89-
return result, nil
90-
}
91-
92-
func (cm *configManager) proposePolicies(rootGroup *cb.ConfigGroup) (*configResult, error) {
93-
cm.initializer.PolicyHandler().BeginConfig(nil) // XXX temporary workaround until policy manager is adapted with sub-policies
94-
95-
for key, policy := range rootGroup.Policies {
96-
logger.Debugf("Proposing policy: %s", key)
97-
if err := cm.initializer.PolicyHandler().ProposePolicy(key, []string{RootGroupKey}, policy); err != nil {
98-
cm.initializer.PolicyHandler().RollbackProposals()
99+
for key, policy := range group.Policies {
100+
if err := policyHandler.ProposePolicy(key, policy); err != nil {
101+
result.rollback()
99102
return nil, err
100103
}
101104
}
102105

103-
return &configResult{handler: cm.initializer.PolicyHandler()}, nil
106+
return result, nil
104107
}
105108

106109
func (cm *configManager) processConfig(channelGroup *cb.ConfigGroup) (*configResult, error) {
107110
helperGroup := cb.NewConfigGroup()
108111
helperGroup.Groups[RootGroupKey] = channelGroup
109-
groupResult, err := cm.proposeGroup("", helperGroup, cm.initializer)
110-
if err != nil {
111-
return nil, err
112-
}
113-
114-
policyResult, err := cm.proposePolicies(channelGroup)
112+
groupResult, err := cm.proposeGroup("", helperGroup, cm.initializer.ValueProposer(), cm.initializer.PolicyProposer())
115113
if err != nil {
116-
groupResult.rollback()
117114
return nil, err
118115
}
119-
policyResult.subResults = []*configResult{groupResult}
120116

121-
return policyResult, nil
117+
return groupResult, nil
122118
}

common/configtx/initializer.go

+54-32
Original file line numberDiff line numberDiff line change
@@ -84,70 +84,92 @@ func newResources() *resources {
8484
applicationConfig := configtxapplication.NewSharedConfigImpl(mspConfigHandler)
8585

8686
return &resources{
87-
policyManager: policies.NewManagerImpl(policyProviderMap),
87+
policyManager: policies.NewManagerImpl(RootGroupKey, policyProviderMap),
8888
channelConfig: configtxchannel.NewSharedConfigImpl(ordererConfig, applicationConfig),
8989
ordererConfig: ordererConfig,
9090
applicationConfig: applicationConfig,
9191
mspConfigHandler: mspConfigHandler,
9292
}
93-
9493
}
9594

96-
type initializer struct {
97-
*resources
98-
is map[string]api.Initializer
95+
type valueProposerRoot struct {
96+
channelConfig *configtxchannel.SharedConfigImpl
97+
mspConfigHandler *configtxmsp.MSPConfigHandler
9998
}
10099

101-
// NewInitializer creates a chain initializer for the basic set of common chain resources
102-
func NewInitializer() api.Initializer {
103-
return &initializer{
104-
resources: newResources(),
105-
}
100+
type policyProposerRoot struct {
101+
policyManager policies.Proposer
106102
}
107103

108104
// BeginValueProposals is used to start a new config proposal
109-
func (i *initializer) BeginValueProposals(groups []string) ([]configvaluesapi.ValueProposer, error) {
105+
func (v *valueProposerRoot) BeginValueProposals(groups []string) ([]configvaluesapi.ValueProposer, error) {
110106
if len(groups) != 1 {
111107
logger.Panicf("Initializer only supports having one root group")
112108
}
113-
i.mspConfigHandler.BeginConfig()
114-
return []configvaluesapi.ValueProposer{i.channelConfig}, nil
109+
logger.Debugf("Calling begin for MSP manager")
110+
v.mspConfigHandler.BeginConfig()
111+
return []configvaluesapi.ValueProposer{v.channelConfig}, nil
115112
}
116113

117114
// RollbackConfig is used to abandon a new config proposal
118-
func (i *initializer) RollbackProposals() {
115+
func (i *valueProposerRoot) RollbackProposals() {
116+
logger.Debugf("Calling rollback for MSP manager")
119117
i.mspConfigHandler.RollbackProposals()
120118
}
121119

122120
// CommitConfig is used to commit a new config proposal
123-
func (i *initializer) CommitProposals() {
121+
func (i *valueProposerRoot) CommitProposals() {
122+
logger.Debugf("Calling commit for MSP manager")
124123
i.mspConfigHandler.CommitProposals()
125124
}
126125

127-
type importHack struct {
128-
*policies.ManagerImpl
126+
func (i *valueProposerRoot) ProposeValue(key string, value *cb.ConfigValue) error {
127+
return fmt.Errorf("Programming error, this should never be invoked")
129128
}
130129

131-
func (ih importHack) BeginConfig(groups []string) ([]api.PolicyHandler, error) {
132-
policyManagers, err := ih.ManagerImpl.BeginConfig(groups)
133-
if err != nil {
134-
return nil, err
135-
}
136-
handlers := make([]api.PolicyHandler, len(policyManagers))
137-
for i, policyManager := range policyManagers {
138-
handlers[i] = &importHack{ManagerImpl: policyManager}
130+
// BeginPolicyProposals is used to start a new config proposal
131+
func (p *policyProposerRoot) BeginPolicyProposals(groups []string) ([]policies.Proposer, error) {
132+
if len(groups) != 1 {
133+
logger.Panicf("Initializer only supports having one root group")
139134
}
140-
return handlers, err
135+
return []policies.Proposer{p.policyManager}, nil
141136
}
142137

143-
func (ih importHack) ProposeConfig(key string, value *cb.ConfigValue) error {
144-
return fmt.Errorf("Temporary hack")
138+
func (i *policyProposerRoot) ProposePolicy(key string, policy *cb.ConfigPolicy) error {
139+
return fmt.Errorf("Programming error, this should never be invoked")
145140
}
146141

147-
func (i *initializer) PolicyHandler() api.PolicyHandler {
148-
return importHack{ManagerImpl: i.policyManager}
142+
// RollbackConfig is used to abandon a new config proposal
143+
func (i *policyProposerRoot) RollbackProposals() {}
144+
145+
// CommitConfig is used to commit a new config proposal
146+
func (i *policyProposerRoot) CommitProposals() {}
147+
148+
type initializer struct {
149+
*resources
150+
vpr *valueProposerRoot
151+
ppr *policyProposerRoot
149152
}
150153

151-
func (i *initializer) ProposeValue(key string, value *cb.ConfigValue) error {
152-
return fmt.Errorf("Programming error, this should never be invoked")
154+
// NewInitializer creates a chain initializer for the basic set of common chain resources
155+
func NewInitializer() api.Initializer {
156+
resources := newResources()
157+
return &initializer{
158+
resources: resources,
159+
vpr: &valueProposerRoot{
160+
channelConfig: resources.channelConfig,
161+
mspConfigHandler: resources.mspConfigHandler,
162+
},
163+
ppr: &policyProposerRoot{
164+
policyManager: resources.policyManager,
165+
},
166+
}
167+
}
168+
169+
func (i *initializer) PolicyProposer() policies.Proposer {
170+
return i.ppr
171+
}
172+
173+
func (i *initializer) ValueProposer() configvaluesapi.ValueProposer {
174+
return i.vpr
153175
}

common/configtx/manager_test.go

+5-11
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,11 @@ func defaultInitializer() *mockconfigtx.Initializer {
3636
Policy: &mockpolicies.Policy{},
3737
},
3838
},
39-
PolicyHandlerVal: &mockconfigtx.PolicyHandler{
40-
Handler: mockconfigtx.Handler{
41-
Transactional: mockconfigtx.Transactional{
42-
HandlerVal: &mockconfigtx.Handler{},
43-
},
44-
},
39+
PolicyProposerVal: &mockconfigtx.PolicyProposer{
40+
Transactional: mockconfigtx.Transactional{},
4541
},
46-
Handler: mockconfigtx.Handler{
47-
Transactional: mockconfigtx.Transactional{
48-
HandlerVal: &mockconfigtx.Handler{},
49-
},
42+
ValueProposerVal: &mockconfigtx.ValueProposer{
43+
Transactional: mockconfigtx.Transactional{},
5044
},
5145
}
5246
}
@@ -412,7 +406,7 @@ func TestInvalidProposal(t *testing.T) {
412406
t.Fatalf("Error constructing config manager: %s", err)
413407
}
414408

415-
initializer.HandlerVal = &mockconfigtx.Handler{ErrorForProposeConfig: fmt.Errorf("err")}
409+
initializer.ValueProposerVal = &mockconfigtx.ValueProposer{ErrorForProposeConfig: fmt.Errorf("err")}
416410

417411
newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo")))
418412

0 commit comments

Comments
 (0)