Skip to content

Commit

Permalink
[FAB-7047] Resource Mgmt Client - Join Channel
Browse files Browse the repository at this point in the history
Change-Id: Ied8c821efa9631e450ebb911945404f238d424fe
Signed-off-by: Sandra Vrtikapa <sandra.vrtikapa@securekey.com>
  • Loading branch information
sandrask committed Nov 21, 2017
1 parent 59a0a8e commit e9fa53a
Show file tree
Hide file tree
Showing 27 changed files with 1,098 additions and 88 deletions.
2 changes: 2 additions & 0 deletions api/apiconfig/configprovider.go
Expand Up @@ -20,12 +20,14 @@ type Config interface {
CAClientCertFile(org string) (string, error)
TimeoutOrDefault(TimeoutType) time.Duration
MspID(org string) (string, error)
PeerMspID(name string) (string, error)
OrderersConfig() ([]OrdererConfig, error)
RandomOrdererConfig() (*OrdererConfig, error)
OrdererConfig(name string) (*OrdererConfig, error)
PeersConfig(org string) ([]PeerConfig, error)
PeerConfig(org string, name string) (*PeerConfig, error)
NetworkConfig() (*NetworkConfig, error)
NetworkPeers() ([]NetworkPeer, error)
ChannelConfig(name string) (*ChannelConfig, error)
ChannelPeers(name string) ([]ChannelPeer, error)
ChannelOrderers(name string) ([]OrdererConfig, error)
Expand Down
26 changes: 26 additions & 0 deletions api/apiconfig/mocks/mockconfig.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/apiconfig/network.go
Expand Up @@ -76,6 +76,11 @@ type PeerChannelConfig struct {
// ChannelPeer combines channel peer info with raw peerConfig info
type ChannelPeer struct {
PeerChannelConfig
NetworkPeer
}

// NetworkPeer combines peer info with MSP info
type NetworkPeer struct {
PeerConfig
MspID string
}
Expand Down
31 changes: 31 additions & 0 deletions api/apitxn/resmgmtclient/resmgmt.go
@@ -0,0 +1,31 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package resmgmt

import fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"

// TargetFilter allows for filtering target peers
type TargetFilter interface {
// Accept returns true if peer should be included in the list of target peers
Accept(peer fab.Peer) bool
}

// JoinChannelOpts contains options for peers joining channel
type JoinChannelOpts struct {
Targets []fab.Peer // target peers
TargetFilter TargetFilter // peer filter
}

// ResourceMgmtClient is responsible for managing resources: peers joining channels, and installing and instantiating chaincodes(TODO).
type ResourceMgmtClient interface {

// JoinChannel allows for peers to join existing channel
JoinChannel(channelID string) error

//JoinChannelWithOpts allows for customizing set of peers about to join the channel (specific peers/filtered peers)
JoinChannelWithOpts(channelID string, opts JoinChannelOpts) error
}
20 changes: 20 additions & 0 deletions def/fabapi/context/defprovider/session.go
Expand Up @@ -10,7 +10,9 @@ import (
"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
"github.com/hyperledger/fabric-sdk-go/api/apitxn"

chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
resmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/resmgmtclient"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/context"

"github.com/hyperledger/fabric-sdk-go/pkg/errors"
Expand All @@ -19,6 +21,7 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/orderer"
chImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chclient"
chmgmtImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/chmgmtclient"
resmgmtImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/resmgmtclient"
)

// SessionClientFactory represents the default implementation of a session client.
Expand Down Expand Up @@ -52,6 +55,23 @@ func (f *SessionClientFactory) NewChannelMgmtClient(sdk context.SDK, session con
return chmgmtImpl.NewChannelMgmtClient(client, config)
}

// NewResourceMgmtClient returns a client that manager resources
func (f *SessionClientFactory) NewResourceMgmtClient(sdk context.SDK, session context.Session, config apiconfig.Config, filter resmgmt.TargetFilter) (resmgmt.ResourceMgmtClient, error) {

// For now settings are the same as for system client
client, err := f.NewSystemClient(sdk, session, config)
if err != nil {
return nil, err
}

discovery, err := sdk.DiscoveryProvider().NewDiscoveryService("")
if err != nil {
return nil, errors.WithMessage(err, "create discovery service failed")
}

return resmgmtImpl.NewResourceMgmtClient(client, discovery, filter, config)
}

// NewChannelClient returns a client that can execute transactions on specified channel
func (f *SessionClientFactory) NewChannelClient(sdk context.SDK, session context.Session, config apiconfig.Config, channelID string) (apitxn.ChannelClient, error) {

Expand Down
2 changes: 2 additions & 0 deletions def/fabapi/context/provider.go
Expand Up @@ -13,6 +13,7 @@ import (
fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
txn "github.com/hyperledger/fabric-sdk-go/api/apitxn"
chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
resmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/resmgmtclient"
"github.com/hyperledger/fabric-sdk-go/def/fabapi/opt"
)

Expand All @@ -37,5 +38,6 @@ type OrgClientFactory interface {
type SessionClientFactory interface {
NewSystemClient(context SDK, session Session, config apiconfig.Config) (fab.FabricClient, error)
NewChannelMgmtClient(context SDK, session Session, config apiconfig.Config) (chmgmt.ChannelMgmtClient, error)
NewResourceMgmtClient(context SDK, session Session, config apiconfig.Config, filter resmgmt.TargetFilter) (resmgmt.ResourceMgmtClient, error)
NewChannelClient(context SDK, session Session, config apiconfig.Config, channelID string) (txn.ChannelClient, error)
}
51 changes: 51 additions & 0 deletions def/fabapi/fabapi.go
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/hyperledger/fabric-sdk-go/pkg/logging/deflogger"

chmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/chmgmtclient"
resmgmt "github.com/hyperledger/fabric-sdk-go/api/apitxn/resmgmtclient"
)

// Options encapsulates configuration for the SDK
Expand Down Expand Up @@ -66,6 +67,13 @@ type ChannelMgmtClientOpts struct {
ConfigProvider apiconfig.Config
}

// ResourceMgmtClientOpts provides options for creating resource management client
type ResourceMgmtClientOpts struct {
OrgName string
TargetFilter resmgmt.TargetFilter
ConfigProvider apiconfig.Config
}

// ProviderInit interface allows for initializing providers
type ProviderInit interface {
Initialize(sdk *FabricSDK) error
Expand Down Expand Up @@ -246,6 +254,49 @@ func (sdk *FabricSDK) NewChannelMgmtClientWithOpts(userName string, opt *Channel
return client, nil
}

// NewResourceMgmtClient returns a new client for managing system resources
func (sdk *FabricSDK) NewResourceMgmtClient(userName string) (resmgmt.ResourceMgmtClient, error) {

// Read default org name from configuration
client, err := sdk.configProvider.Client()
if err != nil {
return nil, errors.WithMessage(err, "unable to retrieve client from network config")
}

if client.Organization == "" {
return nil, errors.New("must provide default organisation name in configuration")
}

opt := &ResourceMgmtClientOpts{OrgName: client.Organization, ConfigProvider: sdk.configProvider}

return sdk.NewResourceMgmtClientWithOpts(userName, opt)
}

// NewResourceMgmtClientWithOpts returns a new resource management client (user has to be pre-enrolled)
func (sdk *FabricSDK) NewResourceMgmtClientWithOpts(userName string, opt *ResourceMgmtClientOpts) (resmgmt.ResourceMgmtClient, error) {

if opt == nil || opt.OrgName == "" {
return nil, errors.New("organization name must be provided")
}

session, err := sdk.NewPreEnrolledUserSession(opt.OrgName, userName)
if err != nil {
return nil, errors.WithMessage(err, "failed to get pre-enrolled user session")
}

configProvider := sdk.ConfigProvider()
if opt.ConfigProvider != nil {
configProvider = opt.ConfigProvider
}

client, err := sdk.SessionFactory.NewResourceMgmtClient(sdk, session, configProvider, opt.TargetFilter)
if err != nil {
return nil, errors.WithMessage(err, "failed to created new resource management client")
}

return client, nil
}

// NewChannelClient returns a new client for a channel
func (sdk *FabricSDK) NewChannelClient(channelID string, userName string) (apitxn.ChannelClient, error) {

Expand Down
51 changes: 51 additions & 0 deletions def/fabapi/fabapi_test.go
Expand Up @@ -52,6 +52,20 @@ func TestNewDefaultSDK(t *testing.T) {
t.Fatalf("Failed to create new channel client: %s", err)
}

}

func TestNewChannelMgmtClient(t *testing.T) {

setup := Options{
ConfigFile: "../../test/fixtures/config/config_test.yaml",
StateStoreOpts: opt.StateStoreOpts{Path: "/tmp/state"},
}

sdk, err := NewSDK(setup)
if err != nil {
t.Fatalf("Error initializing SDK: %s", err)
}

// Test configuration failure for channel management client (invalid user/default organisation)
_, err = sdk.NewChannelMgmtClient("Invalid")
if err == nil {
Expand All @@ -78,6 +92,43 @@ func TestNewDefaultSDK(t *testing.T) {

}

func TestNewResourceMgmtClient(t *testing.T) {

setup := Options{
ConfigFile: "../../test/fixtures/config/config_test.yaml",
StateStoreOpts: opt.StateStoreOpts{Path: "/tmp/state"},
}

sdk, err := NewSDK(setup)
if err != nil {
t.Fatalf("Error initializing SDK: %s", err)
}

// Test configuration failure for resource management client (invalid user/default organisation)
_, err = sdk.NewResourceMgmtClient("Invalid")
if err == nil {
t.Fatalf("Should have failed to create resource management client due to invalid user")
}

// Test valid configuration for resource management client
_, err = sdk.NewResourceMgmtClient("Admin")
if err != nil {
t.Fatalf("Failed to create new resource management client: %s", err)
}

// Test configuration failure for new resource management client with options (invalid org)
_, err = sdk.NewResourceMgmtClientWithOpts("Admin", &ResourceMgmtClientOpts{OrgName: "Invalid"})
if err == nil {
t.Fatalf("Should have failed to create resource management client due to invalid organization")
}

// Test new resource management client with options (Org2 configuration)
_, err = sdk.NewResourceMgmtClientWithOpts("Admin", &ResourceMgmtClientOpts{OrgName: "Org2"})
if err != nil {
t.Fatalf("Failed to create new resource management client with opts: %s", err)
}
}

func TestNewDefaultTwoValidSDK(t *testing.T) {
setup := Options{
ConfigFile: "../../test/fixtures/config/config_test.yaml",
Expand Down
2 changes: 1 addition & 1 deletion def/fabapi/pkgfactory.go
Expand Up @@ -176,7 +176,7 @@ func NewPeer(url string, certificate string, serverHostOverride string, config c
}

// NewPeerFromConfig returns a new default implementation of Peer based configuration
func NewPeerFromConfig(peerCfg *config.PeerConfig, config config.Config) (fab.Peer, error) {
func NewPeerFromConfig(peerCfg *config.NetworkPeer, config config.Config) (fab.Peer, error) {
return peerImpl.NewPeerFromConfig(peerCfg, config)
}

Expand Down
73 changes: 61 additions & 12 deletions pkg/config/config.go
Expand Up @@ -487,20 +487,14 @@ func (c *Config) ChannelPeers(name string) ([]apiconfig.ChannelPeer, error) {
p.TLSCACerts.Path = strings.Replace(p.TLSCACerts.Path, "$GOPATH", os.Getenv("GOPATH"), -1)
}

var mspID string

// Find organisation/msp that peer belongs to
for _, org := range netConfig.Organizations {
for i := 0; i < len(org.Peers); i++ {
if strings.EqualFold(org.Peers[i], peerName) {
// peer belongs to this org add org msp
mspID = org.MspID
break
}
}
mspID, err := c.PeerMspID(peerName)
if err != nil {
return nil, errors.Errorf("failed to retrieve msp id for peer %s", peerName)
}

peer := apiconfig.ChannelPeer{PeerChannelConfig: chPeerConfig, PeerConfig: p, MspID: mspID}
networkPeer := apiconfig.NetworkPeer{PeerConfig: p, MspID: mspID}

peer := apiconfig.ChannelPeer{PeerChannelConfig: chPeerConfig, NetworkPeer: networkPeer}

peers = append(peers, peer)
}
Expand All @@ -509,6 +503,61 @@ func (c *Config) ChannelPeers(name string) ([]apiconfig.ChannelPeer, error) {

}

// NetworkPeers returns the network peers configuration
func (c *Config) NetworkPeers() ([]apiconfig.NetworkPeer, error) {
netConfig, err := c.NetworkConfig()
if err != nil {
return nil, err
}

netPeers := []apiconfig.NetworkPeer{}

for name, p := range netConfig.Peers {

if err = verifyPeerConfig(p, name, urlutil.IsTLSEnabled(p.URL)); err != nil {
return nil, err
}

if p.TLSCACerts.Path != "" {
p.TLSCACerts.Path = strings.Replace(p.TLSCACerts.Path, "$GOPATH", os.Getenv("GOPATH"), -1)
}

mspID, err := c.PeerMspID(name)
if err != nil {
return nil, errors.Errorf("failed to retrieve msp id for peer %s", name)
}

netPeer := apiconfig.NetworkPeer{PeerConfig: p, MspID: mspID}
netPeers = append(netPeers, netPeer)
}

return netPeers, nil
}

// PeerMspID returns msp that peer belongs to
func (c *Config) PeerMspID(name string) (string, error) {
netConfig, err := c.NetworkConfig()
if err != nil {
return "", err
}

var mspID string

// Find organisation/msp that peer belongs to
for _, org := range netConfig.Organizations {
for i := 0; i < len(org.Peers); i++ {
if strings.EqualFold(org.Peers[i], name) {
// peer belongs to this org add org msp
mspID = org.MspID
break
}
}
}

return mspID, nil

}

func verifyPeerConfig(p apiconfig.PeerConfig, peerName string, tlsEnabled bool) error {
if p.URL == "" {
return errors.Errorf("URL does not exist or empty for peer %s", peerName)
Expand Down

0 comments on commit e9fa53a

Please sign in to comment.