Skip to content

Commit

Permalink
[FAB-2225] Create organization config handler
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2225

In order to support organization scoped config (ie AnchorPeers), it's
necessary to introduce the notion of organization config.

This CR only introduces the notion of the organization handler.

Change-Id: I4637f114f36a458fcba82b01b7756d3e4d64da20
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Feb 15, 2017
1 parent 02322a1 commit e99311d
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 10 deletions.
13 changes: 11 additions & 2 deletions common/configtx/handlers/application/sharedconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"

"github.com/hyperledger/fabric/common/configtx/api"
"github.com/hyperledger/fabric/common/configtx/handlers"
"github.com/hyperledger/fabric/common/configtx/handlers/msp"
cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
Expand Down Expand Up @@ -65,6 +66,7 @@ var logger = logging.MustGetLogger("peer/sharedconfig")

type sharedConfig struct {
anchorPeers []*pb.AnchorPeer
orgs map[string]*handlers.OrgConfig
}

// SharedConfigImpl is an implementation of Manager and configtx.ConfigHandler
Expand Down Expand Up @@ -95,7 +97,9 @@ func (di *SharedConfigImpl) BeginConfig() {
if di.pendingConfig != nil {
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
}
di.pendingConfig = &sharedConfig{}
di.pendingConfig = &sharedConfig{
orgs: make(map[string]*handlers.OrgConfig),
}
}

// RollbackConfig is used to abandon a new config proposal
Expand Down Expand Up @@ -142,5 +146,10 @@ func (pm *SharedConfigImpl) Handler(path []string) (api.Handler, error) {
return nil, fmt.Errorf("Application group allows only one further level of nesting")
}

return pm.mspConfig.Handler(path[1:])
org, ok := pm.pendingConfig.orgs[path[0]]
if !ok {
org = handlers.NewOrgConfig(path[0], pm.mspConfig)
pm.pendingConfig.orgs[path[0]] = org
}
return org, nil
}
13 changes: 11 additions & 2 deletions common/configtx/handlers/orderer/sharedconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"time"

"github.com/hyperledger/fabric/common/configtx/api"
"github.com/hyperledger/fabric/common/configtx/handlers"
"github.com/hyperledger/fabric/common/configtx/handlers/msp"
cb "github.com/hyperledger/fabric/protos/common"
ab "github.com/hyperledger/fabric/protos/orderer"
Expand Down Expand Up @@ -98,6 +99,7 @@ type ordererConfig struct {
kafkaBrokers []string
ingressPolicyNames []string
egressPolicyNames []string
orgs map[string]*handlers.OrgConfig
}

// ManagerImpl is an implementation of configtxapi.OrdererConfig and configtxapi.Handler
Expand Down Expand Up @@ -160,7 +162,9 @@ func (pm *ManagerImpl) BeginConfig() {
if pm.pendingConfig != nil {
logger.Fatalf("Programming error, cannot call begin in the middle of a proposal")
}
pm.pendingConfig = &ordererConfig{}
pm.pendingConfig = &ordererConfig{
orgs: make(map[string]*handlers.OrgConfig),
}
}

// RollbackConfig is used to abandon a new config proposal
Expand Down Expand Up @@ -281,7 +285,12 @@ func (pm *ManagerImpl) Handler(path []string) (api.Handler, error) {
return nil, fmt.Errorf("Orderer group allows only one further level of nesting")
}

return pm.mspConfig.Handler(path[1:])
org, ok := pm.pendingConfig.orgs[path[0]]
if !ok {
org = handlers.NewOrgConfig(path[0], pm.mspConfig)
pm.pendingConfig.orgs[path[0]] = org
}
return org, nil
}

// This does just a barebones sanity check.
Expand Down
105 changes: 105 additions & 0 deletions common/configtx/handlers/organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handlers

import (
"fmt"

"github.com/hyperledger/fabric/common/configtx/api"
mspconfig "github.com/hyperledger/fabric/common/configtx/handlers/msp"
"github.com/hyperledger/fabric/msp"
cb "github.com/hyperledger/fabric/protos/common"

"github.com/op/go-logging"
)

// Org config keys
const (
// MSPKey is value key for marshaled *mspconfig.MSPConfig
MSPKey = "MSP"
)

var logger = logging.MustGetLogger("common/configtx/handlers")

type orgConfig struct {
msp msp.MSP
}

// SharedConfigImpl is an implementation of Manager and configtx.ConfigHandler
// In general, it should only be referenced as an Impl for the configtx.Manager
type OrgConfig struct {
id string
pendingConfig *orgConfig
config *orgConfig

mspConfig *mspconfig.MSPConfigHandler
}

// NewSharedConfigImpl creates a new SharedConfigImpl with the given CryptoHelper
func NewOrgConfig(id string, mspConfig *mspconfig.MSPConfigHandler) *OrgConfig {
return &OrgConfig{
id: id,
config: &orgConfig{},
mspConfig: mspConfig,
}
}

// BeginConfig is used to start a new config proposal
func (oc *OrgConfig) BeginConfig() {
logger.Debugf("Beginning a possible new org config")
if oc.pendingConfig != nil {
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
}
oc.pendingConfig = &orgConfig{}
}

// RollbackConfig is used to abandon a new config proposal
func (oc *OrgConfig) RollbackConfig() {
logger.Debugf("Rolling back proposed org config")
oc.pendingConfig = nil
}

// CommitConfig is used to commit a new config proposal
func (oc *OrgConfig) CommitConfig() {
logger.Debugf("Committing new org config")
if oc.pendingConfig == nil {
logger.Panicf("Programming error, cannot call commit without an existing proposal")
}
oc.config = oc.pendingConfig
oc.pendingConfig = nil
}

// ProposeConfig is used to add new config to the config proposal
func (oc *OrgConfig) ProposeConfig(key string, configValue *cb.ConfigValue) error {
switch key {
case MSPKey:
logger.Debugf("Initializing org MSP for id %s", oc.id)
return oc.mspConfig.ProposeConfig(key, configValue)
default:
logger.Warningf("Uknown org config item with key %s", key)
}
return nil
}

// Handler returns the associated api.Handler for the given path
func (oc *OrgConfig) Handler(path []string) (api.Handler, error) {
if len(path) == 0 {
return oc, nil
}

return nil, fmt.Errorf("Organizations do not further nesting")
}
65 changes: 65 additions & 0 deletions common/configtx/handlers/organization_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handlers

import (
"testing"

configtxapi "github.com/hyperledger/fabric/common/configtx/api"

logging "github.com/op/go-logging"
)

func init() {
logging.SetLevel(logging.DEBUG, "")
}

func TestInterface(t *testing.T) {
_ = configtxapi.SubInitializer(NewOrgConfig("id", nil))
}

func TestDoubleBegin(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Fatalf("Should have panicked on multiple begin configs")
}
}()

m := NewOrgConfig("id", nil)
m.BeginConfig()
m.BeginConfig()
}

func TestCommitWithoutBegin(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Fatalf("Should have panicked on multiple begin configs")
}
}()

m := NewOrgConfig("id", nil)
m.CommitConfig()
}

func TestRollback(t *testing.T) {
m := NewOrgConfig("id", nil)
m.pendingConfig = &orgConfig{}
m.RollbackConfig()
if m.pendingConfig != nil {
t.Fatalf("Should have cleared pending config on rollback")
}
}
7 changes: 5 additions & 2 deletions common/configtx/test/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/hyperledger/fabric/common/configtx"
configtxapplication "github.com/hyperledger/fabric/common/configtx/handlers/application"
configtxmsp "github.com/hyperledger/fabric/common/configtx/handlers/msp"
configtxorderer "github.com/hyperledger/fabric/common/configtx/handlers/orderer"
genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
"github.com/hyperledger/fabric/common/configtx/tool/provisional"
"github.com/hyperledger/fabric/common/genesis"
Expand Down Expand Up @@ -86,11 +87,13 @@ func OrdererTemplate() configtx.Template {

// MSPTemplate returns the test MSP template
func MSPTemplate() configtx.Template {
mspConf, err := msp.GetLocalMspConfig(sampleMSPPath, "SAMPLE")
const sampleID = "SAMPLE"
mspConf, err := msp.GetLocalMspConfig(sampleMSPPath, sampleID)
if err != nil {
logger.Panicf("Could not load sample MSP config: %s", err)
}
return configtx.NewSimpleTemplate(configtxmsp.TemplateGroupMSP([]string{configtxapplication.GroupKey}, mspConf))
return configtx.NewSimpleTemplate(configtxmsp.TemplateGroupMSP([]string{configtxapplication.GroupKey, sampleID}, mspConf),
configtxmsp.TemplateGroupMSP([]string{configtxorderer.GroupKey, sampleID}, mspConf))
}

// ApplicationTemplate returns the test application template
Expand Down
10 changes: 6 additions & 4 deletions orderer/sample_clients/broadcast_config/newchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ package main

import (
"github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/common/configtx/tool/provisional"
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
//"github.com/hyperledger/fabric/common/configtx/tool/provisional"
"github.com/hyperledger/fabric/msp"
cb "github.com/hyperledger/fabric/protos/common"
)

func newChainRequest(consensusType, creationPolicy, newChannelId string) *cb.Envelope {
genConf.Orderer.OrdererType = consensusType
generator := provisional.New(genConf)
channelTemplate := generator.ChannelTemplate()
//genConf.Orderer.OrdererType = consensusType
//generator := provisional.New(genConf)
//channelTemplate := generator.ChannelTemplate()
channelTemplate := configtxtest.CompositeTemplate()

signer, err := msp.NewNoopMsp().GetDefaultSigningIdentity()
if err != nil {
Expand Down

0 comments on commit e99311d

Please sign in to comment.