Skip to content

Commit

Permalink
[FAB-3750] New mspAdmin role BDD
Browse files Browse the repository at this point in the history
Add new role to BDD to account for recent instantiation policy changes
in peer.  The mspAdmin role user's certificate will be added to the
admincerts attribute of the MSPConfig used for the consortiums
definition.

Modify the boostrap.feature to use the mspAdmin for the instantiation
related tasks.

Modify dumping logs to tmp folder for run.

Change-Id: I696efc1ea40451094c204b6752d95ca4d33f86a1
Signed-off-by: Jeff Garratt <garratt.jeff@gmail.com>
  • Loading branch information
jeffgarratt committed May 9, 2017
1 parent c140def commit 4248b9e
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 41 deletions.
6 changes: 4 additions & 2 deletions bddtests/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def after_scenario(context, scenario):
file_suffix = "_" + scenario.name.replace(" ", "_") + ".log"
# get logs from the peer containers
for containerData in context.compose_containers:
with open(containerData.containerName + file_suffix, "w+") as logfile:
(fileName, fileExists) = contextHelper.getTmpPathForName(name="{0}_{1}".format(containerData.containerName, scenario.name), extension="log", path_relative_to_tmp="logs")
with open(fileName, "w+") as logfile:
sys_rc = subprocess.call(["docker", "logs", containerData.containerName], stdout=logfile, stderr=logfile)
if sys_rc !=0 :
print("Cannot get logs for {0}. Docker rc = {1}".format(containerData.containerName,sys_rc))
Expand All @@ -52,7 +53,8 @@ def after_scenario(context, scenario):
cli_call(["docker", "ps", "-f", "name=dev-", "--format", "{{.Names}}"], expect_success=True)
for containerName in cc_output.splitlines():
namePart,sep,junk = containerName.rpartition("-")
with open(namePart + file_suffix, "w+") as logfile:
(fileName, fileExists) = contextHelper.getTmpPathForName(name="{0}_{1}".format(namePart, scenario.name), extension="log", path_relative_to_tmp="logs")
with open(fileName, "w+") as logfile:
sys_rc = subprocess.call(["docker", "logs", containerName], stdout=logfile, stderr=logfile)
if sys_rc !=0 :
print("Cannot get logs for {0}. Docker rc = {1}".format(namepart,sys_rc))
Expand Down
51 changes: 28 additions & 23 deletions bddtests/features/bootstrap.feature
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,28 @@ Feature: Bootstrap

And the ordererBootstrapAdmin generates a GUUID to identify the orderer system chain and refer to it by name as "OrdererSystemChainId"

# We now have an orderer network with NO peers. Now need to configure and start the peer network
# This can be currently automated through folder creation of the proper form and placing PEMs.
And user requests role for peer by creating a key and csr for peer and acquires signed certificate from organization:
| User | Peer | Organization |AliasSavedUnder|
| peer0Signer | peer0 | peerOrg0 | |
| peer1Signer | peer1 | peerOrg0 | |
| peer2Signer | peer2 | peerOrg1 | |
| peer3Signer | peer3 | peerOrg1 | |
| peer0Admin | peer0 | peerOrg0 |peer-admin-cert|
| peer1Admin | peer1 | peerOrg0 |peer-admin-cert|
| peer2Admin | peer2 | peerOrg1 |peer-admin-cert|
| peer3Admin | peer3 | peerOrg1 |peer-admin-cert|
| mspAdminPeerOrg0| mspAdmin | peerOrg0 |msp-admin-cert |
| mspAdminPeerOrg1| mspAdmin | peerOrg1 |msp-admin-cert |

And the ordererBootstrapAdmin creates a consortium "consortium1" (network name) for peer orgs who wish to form a network:
| Organization |
| peerOrg0 |
| peerOrg1 |
# | peerOrg2 |


# Order info includes orderer admin/orderer information and address (host:port) from previous steps
# Only the peer organizations can vary.
And the ordererBootstrapAdmin using cert alias "bootstrapCertAlias" creates the genesis block "ordererGenesisBlock" for chain "OrdererSystemChainId" for network config policy "<PolicyType>" and consensus "<ConsensusType>" using consortiums:
Expand All @@ -62,20 +78,6 @@ Feature: Bootstrap
# to be used for setting the orderer genesis block path parameter in composition
And the orderer admins use the genesis block for chain "OrdererSystemChainId" to configure orderers

# We now have an orderer network with NO peers. Now need to configure and start the peer network
# This can be currently automated through folder creation of the proper form and placing PEMs.
And user requests role for peer by creating a key and csr for peer and acquires signed certificate from organization:
| User | Peer | Organization |AliasSavedUnder|
| peer0Signer | peer0 | peerOrg0 | |
| peer1Signer | peer1 | peerOrg0 | |
| peer2Signer | peer2 | peerOrg1 | |
| peer3Signer | peer3 | peerOrg1 | |
| peer0Admin | peer0 | peerOrg0 |peer-admin-cert|
| peer1Admin | peer1 | peerOrg0 |peer-admin-cert|
| peer2Admin | peer2 | peerOrg1 |peer-admin-cert|
| peer3Admin | peer3 | peerOrg1 |peer-admin-cert|


And we compose "<ComposeFile>"

# Sleep as to allow system up time
Expand Down Expand Up @@ -199,38 +201,41 @@ Feature: Bootstrap


Given user "peer0Admin" gives "cc_spec" to user "dev0Org0"
And user "peer0Admin" gives "cc_spec" to user "mspAdminPeerOrg0"

# Under the covers, create a deployment spec, etc.
When user "dev0Org0" using cert alias "dev0Org0App1" creates a instantiate proposal "instantiateProposal1" for channel "com.acme.blockchain.jdoe.Channel1" using chaincode spec "cc_spec"

And user "dev0Org0" using cert alias "dev0Org0App1" sends proposal "instantiateProposal1" to endorsers with timeout of "90" seconds with proposal responses "instantiateProposalResponses":
When user "mspAdminPeerOrg0" using cert alias "msp-admin-cert" creates a instantiate proposal "instantiateProposal1" for channel "com.acme.blockchain.jdoe.Channel1" using chaincode spec "cc_spec"

And user "mspAdminPeerOrg0" using cert alias "msp-admin-cert" sends proposal "instantiateProposal1" to endorsers with timeout of "90" seconds with proposal responses "instantiateProposalResponses":
| Endorser |
| peer0 |
| peer2 |


Then user "dev0Org0" expects proposal responses "instantiateProposalResponses" with status "200" from endorsers:
Then user "mspAdminPeerOrg0" expects proposal responses "instantiateProposalResponses" with status "200" from endorsers:
| Endorser |
| peer0 |
| peer2 |

And user "dev0Org0" expects proposal responses "instantiateProposalResponses" each have the same value from endorsers:
And user "mspAdminPeerOrg0" expects proposal responses "instantiateProposalResponses" each have the same value from endorsers:
| Endorser |
| peer0 |
| peer2 |

When the user "dev0Org0" creates transaction "instantiateTx1" from proposal "instantiateProposal1" and proposal responses "instantiateProposalResponses" for channel "com.acme.blockchain.jdoe.Channel1"
When the user "mspAdminPeerOrg0" creates transaction "instantiateTx1" from proposal "instantiateProposal1" and proposal responses "instantiateProposalResponses" for channel "com.acme.blockchain.jdoe.Channel1"

And the user "dev0Org0" broadcasts transaction "instantiateTx1" to orderer "<orderer1>" on channel "com.acme.blockchain.jdoe.Channel1"
And the user "mspAdminPeerOrg0" broadcasts transaction "instantiateTx1" to orderer "<orderer1>" on channel "com.acme.blockchain.jdoe.Channel1"

# Sleep as the deliver takes a bit to have the first block ready
And I wait "2" seconds

And user "dev0Org0" sends deliver a seek request on orderer "<orderer0>" with properties:
And user "mspAdminPeerOrg0" using cert alias "msp-admin-cert" connects to deliver function on orderer "<orderer0>"

And user "mspAdminPeerOrg0" sends deliver a seek request on orderer "<orderer0>" with properties:
| ChainId | Start | End |
| com.acme.blockchain.jdoe.Channel1 | 1 | 1 |

Then user "dev0Org0" should get a delivery "deliveredInstantiateTx1Block" from "<orderer0>" of "1" blocks with "1" messages within "1" seconds
Then user "mspAdminPeerOrg0" should get a delivery "deliveredInstantiateTx1Block" from "<orderer0>" of "1" blocks with "1" messages within "1" seconds

# Sleep as the deliver takes a bit to have the first block ready
And I wait "1" seconds
Expand Down
30 changes: 16 additions & 14 deletions bddtests/steps/bootstrap_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,6 @@ def getSelfSignedCert(self):
def getCertAsPEM(self):
return crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())

def getMSPConfig(self):
certPemsList = [crypto.dump_certificate(crypto.FILETYPE_PEM, self.getSelfSignedCert())]
# For now, admin certs and CA certs are the same per @ASO
adminCerts = certPemsList
cacerts = adminCerts
# Currently only 1 component, CN=<orgName>
# name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
name = self.name
fabricMSPConfig = msp_config_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=name)
mspConfig = msp_config_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
return mspConfig

def isInNetwork(self, network):
for n in self.networks:
if str(n)==str(network):
Expand Down Expand Up @@ -657,7 +645,7 @@ def createChannelConfigGroup(directory, hashingAlgoName="SHA256", consensusType=
# Add the orderer org groups MSPConfig info
for ordererOrg in [org for org in directory.getOrganizations().values() if Network.Orderer in org.networks]:
channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
ordererOrg.getMSPConfig())
getMSPConfig(org=ordererOrg, directory=directory))
channel.groups[OrdererGroup].groups[ordererOrg.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
# #Kafka specific
# matchingNATs = [nat for nat in directory.getNamedCtxTuples() if (("orderer" in nat.user) and ("Signer" in nat.user) and ((compose_service in nat.nodeName)))]
Expand Down Expand Up @@ -808,6 +796,20 @@ class PathType(Enum):
Container = 2


def getMSPConfig(org, directory):
adminCerts = [org.getCertAsPEM()]
# Find the mspAdmin Tuple for org and add to admincerts folder
for pnt, cert in [(nat, cert) for nat, cert in directory.ordererAdminTuples.items() if
org.name == nat.organization and "mspadmin" in nat.nodeName.lower()]:
adminCerts.append(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
cacerts = [org.getCertAsPEM()]
# Currently only 1 component, CN=<orgName>
# name = self.getSelfSignedCert().get_subject().getComponents()[0][1]
fabricMSPConfig = msp_config_pb2.FabricMSPConfig(admins=adminCerts, root_certs=cacerts, name=org.name)
mspConfig = msp_config_pb2.MSPConfig(config=fabricMSPConfig.SerializeToString(), type=0)
return mspConfig


class CallbackHelper:
def __init__(self, discriminator, volumeRootPathInContainer = "/var/hyperledger/bddtests"):
self.volumeRootPathInContainer = volumeRootPathInContainer
Expand Down Expand Up @@ -1012,7 +1014,7 @@ def createConsortium(context, consortium_name, org_names):
for consortium_org in [org for org in directory.getOrganizations().values() if org.name in org_names]:
# channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].mod_policy = BootstrapHelper.KEY_POLICY_ADMINS
channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].value = toValue(
consortium_org.getMSPConfig())
getMSPConfig(org=consortium_org, directory=directory))
channel.groups[ConsortiumsGroup].groups[consortium_name].groups[consortium_org.name].values[BootstrapHelper.KEY_MSP_INFO].mod_policy=BootstrapHelper.KEY_POLICY_ADMINS
typeImplicitMeta = common_dot_policies_pb2.Policy.PolicyType.Value("IMPLICIT_META")
Policy = common_dot_policies_pb2.Policy
Expand Down
7 changes: 5 additions & 2 deletions bddtests/steps/contexthelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ def getTmpProjectPath(self):
os.makedirs(pathToReturn)
return pathToReturn

def getTmpPathForName(self, name, extension=None, copyFromCache=False):
def getTmpPathForName(self, name, extension=None, copyFromCache=False, path_relative_to_tmp=''):
'Returns the tmp path for a file, and a flag indicating if the file exists. Will also check in the cache and copy to tmp if copyFromCache==True'
unicodeName = unicode(name)
dir_path = os.path.join(self.getTmpProjectPath(), path_relative_to_tmp)
if not os.path.isdir(dir_path):
os.makedirs(dir_path)
slugifiedName = ".".join([slugify(unicodeName), extension]) if extension else slugify(unicodeName)
tmpPath = os.path.join(self.getTmpProjectPath(), slugifiedName)
tmpPath = os.path.join(dir_path, slugifiedName)
fileExists = False
if os.path.isfile(tmpPath):
# file already exists in tmp path, return path and exists flag
Expand Down

0 comments on commit 4248b9e

Please sign in to comment.