Skip to content

Commit

Permalink
[FAB-1776] Policy manager instantiation to common
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1776

The policy manager is currently only initialized within the orderer, but
this is a common function and needs to be moved into the common
components.

Change-Id: I7bed73fdccbc3258418f226eb1ff11e3e29147f9
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 20, 2017
1 parent 0372dae commit b3f03b1
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 83 deletions.
5 changes: 4 additions & 1 deletion common/configtx/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package configtx
package configtx_test

import (
"fmt"
"reflect"
"testing"

. "github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/orderer/common/filter"
mockconfigtx "github.com/hyperledger/fabric/orderer/mocks/configtx"
cb "github.com/hyperledger/fabric/protos/common"

"github.com/golang/protobuf/proto"
)

type mockConfigManager struct {
mockconfigtx.Manager
applied *cb.ConfigurationEnvelope
err error
}
Expand Down
28 changes: 14 additions & 14 deletions common/configtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type Handler interface {

// Manager provides a mechanism to query and update configuration
type Manager interface {
Resources

// Apply attempts to apply a configtx to become the new configuration
Apply(configtx *cb.ConfigurationEnvelope) error

Expand All @@ -70,11 +72,10 @@ func (ap *acceptAllPolicy) Evaluate(signedData []*cb.SignedData) error {
}

type configurationManager struct {
Initializer
sequence uint64
chainID string
pm policies.Manager
configuration map[cb.ConfigurationItem_ConfigurationType]map[string]*cb.ConfigurationItem
handlers map[cb.ConfigurationItem_ConfigurationType]Handler
}

// computeChainIDAndSequence returns the chain id and the sequence number for a configuration envelope
Expand Down Expand Up @@ -118,10 +119,10 @@ func computeChainIDAndSequence(configtx *cb.ConfigurationEnvelope) (string, uint
return chainID, m, nil
}

// NewConfigurationManager creates a new Manager unless an error is encountered
func NewConfigurationManager(configtx *cb.ConfigurationEnvelope, pm policies.Manager, handlers map[cb.ConfigurationItem_ConfigurationType]Handler) (Manager, error) {
// NewManagerImpl creates a new Manager unless an error is encountered
func NewManagerImpl(configtx *cb.ConfigurationEnvelope, initializer Initializer) (Manager, error) {
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
if _, ok := handlers[cb.ConfigurationItem_ConfigurationType(ctype)]; !ok {
if _, ok := initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)]; !ok {
return nil, errors.New("Must supply a handler for all known types")
}
}
Expand All @@ -132,10 +133,9 @@ func NewConfigurationManager(configtx *cb.ConfigurationEnvelope, pm policies.Man
}

cm := &configurationManager{
Initializer: initializer,
sequence: seq - 1,
chainID: chainID,
pm: pm,
handlers: handlers,
configuration: makeConfigMap(),
}

Expand All @@ -159,21 +159,21 @@ func makeConfigMap() map[cb.ConfigurationItem_ConfigurationType]map[string]*cb.C
func (cm *configurationManager) beginHandlers() {
logger.Debugf("Beginning new configuration for chain %s", cm.chainID)
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
cm.handlers[cb.ConfigurationItem_ConfigurationType(ctype)].BeginConfig()
cm.Initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)].BeginConfig()
}
}

func (cm *configurationManager) rollbackHandlers() {
logger.Debugf("Rolling back configuration for chain %s", cm.chainID)
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
cm.handlers[cb.ConfigurationItem_ConfigurationType(ctype)].RollbackConfig()
cm.Initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)].RollbackConfig()
}
}

func (cm *configurationManager) commitHandlers() {
logger.Debugf("Committing configuration for chain %s", cm.chainID)
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
cm.handlers[cb.ConfigurationItem_ConfigurationType(ctype)].CommitConfig()
cm.Initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)].CommitConfig()
}
}

Expand All @@ -193,7 +193,7 @@ func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope
return nil, fmt.Errorf("Config is for the wrong chain, expected %s, got %s", cm.chainID, chainID)
}

defaultModificationPolicy, defaultPolicySet := cm.pm.GetPolicy(NewConfigurationItemPolicyKey)
defaultModificationPolicy, defaultPolicySet := cm.PolicyManager().GetPolicy(NewConfigurationItemPolicyKey)

// If the default modification policy is not set, it indicates this is an uninitialized chain, so be permissive of modification
if !defaultPolicySet {
Expand Down Expand Up @@ -226,7 +226,7 @@ func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope

// If a config item was modified, its LastModified must be set correctly, and it must satisfy the modification policy
if isModified {
logger.Debugf("Proposed configuration item of type %v and key %t on chain %s has been modified", config.Type, config.Key, cm.chainID)
logger.Debugf("Proposed configuration item of type %v and key %s on chain %s has been modified", config.Type, config.Key, cm.chainID)

if config.LastModified != seq {
return nil, fmt.Errorf("Key %v for type %v was modified, but its LastModified %d does not equal current configtx Sequence %d", config.Key, config.Type, config.LastModified, seq)
Expand All @@ -237,7 +237,7 @@ func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope
var policy policies.Policy
oldItem, ok := cm.configuration[config.Type][config.Key]
if ok {
policy, _ = cm.pm.GetPolicy(oldItem.ModificationPolicy)
policy, _ = cm.PolicyManager().GetPolicy(oldItem.ModificationPolicy)
} else {
policy = defaultModificationPolicy
}
Expand All @@ -256,7 +256,7 @@ func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope

// Ensure the type handler agrees the config is well formed
logger.Debugf("Proposing configuration item of type %v for key %s on chain %s", config.Type, config.Key, cm.chainID)
err = cm.handlers[config.Type].ProposeConfig(config)
err = cm.Initializer.Handlers()[config.Type].ProposeConfig(config)
if err != nil {
return nil, fmt.Errorf("Error proposing configuration item of type %v for key %s on chain %s: %s", config.Type, config.Key, chainID, err)
}
Expand Down
76 changes: 39 additions & 37 deletions common/configtx/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package configtx
package configtx_test

import (
"fmt"
"testing"

. "github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/common/policies"
mockconfigtx "github.com/hyperledger/fabric/orderer/mocks/configtx"
cb "github.com/hyperledger/fabric/protos/common"

"errors"
Expand Down Expand Up @@ -88,9 +90,9 @@ func makeSignedConfigurationItem(id, modificationPolicy string, lastModified uin

// TestOmittedHandler tests that startup fails if not all configuration types have an associated handler
func TestOmittedHandler(t *testing.T) {
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, map[cb.ConfigurationItem_ConfigurationType]Handler{})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: map[cb.ConfigurationItem_ConfigurationType]Handler{}})

if err == nil {
t.Fatal("Should have failed to construct manager because handlers were missing")
Expand All @@ -99,9 +101,9 @@ func TestOmittedHandler(t *testing.T) {

// TestWrongChainID tests that a configuration update for a different chain ID fails
func TestWrongChainID(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -124,9 +126,9 @@ func TestWrongChainID(t *testing.T) {

// TestOldConfigReplay tests that resubmitting a config for a sequence number which is not newer is ignored
func TestOldConfigReplay(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -151,9 +153,9 @@ func TestOldConfigReplay(t *testing.T) {
func TestInvalidInitialConfigByStructure(t *testing.T) {
entries := []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)}
entries[0].ConfigurationItem = []byte("Corrupted")
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: entries,
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err == nil {
t.Fatal("Should have failed to construct configuration by policy")
Expand All @@ -162,9 +164,9 @@ func TestInvalidInitialConfigByStructure(t *testing.T) {

// TestValidConfigChange tests the happy path of updating a configuration value with no defaultModificationPolicy
func TestValidConfigChange(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -188,9 +190,9 @@ func TestValidConfigChange(t *testing.T) {
// TestConfigChangeRegressedSequence tests to make sure that a new config cannot roll back one of the
// config values while advancing another
func TestConfigChangeRegressedSequence(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -217,9 +219,9 @@ func TestConfigChangeRegressedSequence(t *testing.T) {
// TestConfigChangeOldSequence tests to make sure that a new config cannot roll back one of the
// config values while advancing another
func TestConfigChangeOldSequence(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -246,12 +248,12 @@ func TestConfigChangeOldSequence(t *testing.T) {
// TestConfigImplicitDelete tests to make sure that a new config does not implicitly delete config items
// by omitting them in the new config
func TestConfigImplicitDelete(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain),
makeSignedConfigurationItem("bar", "bar", 0, []byte("bar"), defaultChain),
},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -276,9 +278,9 @@ func TestConfigImplicitDelete(t *testing.T) {

// TestEmptyConfigUpdate tests to make sure that an empty config is rejected as an update
func TestEmptyConfigUpdate(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -301,12 +303,12 @@ func TestEmptyConfigUpdate(t *testing.T) {
// is substituted into an otherwise valid new config, that the new config is rejected for attempting a modification without
// increasing the config item's LastModified
func TestSilentConfigModification(t *testing.T) {
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain),
makeSignedConfigurationItem("bar", "bar", 0, []byte("bar"), defaultChain),
},
}, &mockPolicyManager{&mockPolicy{}}, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -333,10 +335,9 @@ func TestSilentConfigModification(t *testing.T) {
// TestInvalidInitialConfigByPolicy tests to make sure that if an existing policies does not validate the config that
// even construction fails
func TestInvalidInitialConfigByPolicy(t *testing.T) {
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{policyResult: fmt.Errorf("err")}}, defaultHandlers())
// mockPolicyManager will return non-validating defualt policy
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{policyResult: fmt.Errorf("err")}}, HandlersVal: defaultHandlers()})

if err == nil {
t.Fatal("Should have failed to construct configuration by policy")
Expand All @@ -347,9 +348,9 @@ func TestInvalidInitialConfigByPolicy(t *testing.T) {
// it is rejected in a config update
func TestConfigChangeViolatesPolicy(t *testing.T) {
mpm := &mockPolicyManager{}
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, mpm, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -376,9 +377,9 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
// as the policy may have changed, certs revoked, etc. since the config was adopted.
func TestUnchangedConfigViolatesPolicy(t *testing.T) {
mpm := &mockPolicyManager{}
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, mpm, defaultHandlers())
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()})

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -420,15 +421,16 @@ func (fh failHandler) ProposeConfig(item *cb.ConfigurationItem) error {
// that if the handler does not accept the config, it is rejected
func TestInvalidProposal(t *testing.T) {
handlers := defaultHandlers()
cm, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
initializer := &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers}
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockPolicyManager{&mockPolicy{}}, handlers)
}, initializer)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
}

cm.(*configurationManager).handlers[cb.ConfigurationItem_ConfigurationType(0)] = failHandler{}
initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(0)] = failHandler{}

newConfig := &cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
Expand All @@ -451,9 +453,9 @@ func TestMissingHeader(t *testing.T) {
configItem := makeConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)
configItem.Header = nil
data, _ := proto.Marshal(configItem)
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{&cb.SignedConfigurationItem{ConfigurationItem: data}},
}, &mockPolicyManager{&mockPolicy{}}, handlers)
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand All @@ -463,9 +465,9 @@ func TestMissingHeader(t *testing.T) {
// TestMissingChainID checks that a configuration item with a missing chainID causes the config to be rejected
func TestMissingChainID(t *testing.T) {
handlers := defaultHandlers()
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "")},
}, &mockPolicyManager{&mockPolicy{}}, handlers)
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand All @@ -475,12 +477,12 @@ func TestMissingChainID(t *testing.T) {
// TestMismatchedChainID checks that a configuration envelope with items with mixed chainIDs causes the config to be rejected
func TestMismatchedChainID(t *testing.T) {
handlers := defaultHandlers()
_, err := NewConfigurationManager(&cb.ConfigurationEnvelope{
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "chain1"),
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "chain2"),
},
}, &mockPolicyManager{&mockPolicy{}}, handlers)
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand Down
Loading

0 comments on commit b3f03b1

Please sign in to comment.