diff --git a/bddtests/compose-defaults.yml b/bddtests/compose-defaults.yml index 324f46527bf..a607584b164 100644 --- a/bddtests/compose-defaults.yml +++ b/bddtests/compose-defaults.yml @@ -10,6 +10,8 @@ services: # TODO: This is currently required due to BUG in variant logic based upon log level. - CORE_LOGGING_LEVEL=DEBUG - CORE_PEER_NETWORKID=${CORE_PEER_NETWORKID} + volumes: + - ./volumes/peer:/var/hyperledger/bddtests/volumes/peer # Script will wait until membersrvc is up (if it exists) before starting # $$GOPATH (double dollar) required to prevent docker-compose doing its own # substitution before the value gets to the container @@ -22,3 +24,7 @@ services: membersrvc: image: hyperledger/fabric-membersrvc command: membersrvc + +volumes: + + peer: \ No newline at end of file diff --git a/bddtests/docker-compose-next-4.yml b/bddtests/docker-compose-next-4.yml index 5ca5886a82f..75260795ea9 100644 --- a/bddtests/docker-compose-next-4.yml +++ b/bddtests/docker-compose-next-4.yml @@ -13,7 +13,7 @@ services: service: orderer0 - vp0: + peer0: extends: file: docker-compose-next.yml service: vpNext @@ -21,8 +21,7 @@ services: - CORE_PEER_ID=vp0 - CORE_PEER_PROFILE_ENABLED=true - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer0:7050 - - CORE_SECURITY_ENROLLID=test_vp0 - - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT + - CORE_PEER_MSPCONFIGPATH=${PEER0_CORE_PEER_MSPCFGPATH} depends_on: - membersrvc0 - orderer0 @@ -30,47 +29,44 @@ services: # - 7050:6060 - vp1: + peer1: extends: file: docker-compose-next.yml service: vpNext environment: - CORE_PEER_ID=vp1 - - CORE_PEER_DISCOVERY_ROOTNODE=vp0:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer0:7050 - - CORE_SECURITY_ENROLLID=test_vp1 - - CORE_SECURITY_ENROLLSECRET=5wgHK9qqYaPy + - CORE_PEER_MSPCONFIGPATH=${PEER1_CORE_PEER_MSPCFGPATH} depends_on: - membersrvc0 - orderer0 - - vp0 + - peer0 - vp2: + peer2: extends: file: docker-compose-next.yml service: vpNext environment: - CORE_PEER_ID=vp2 - - CORE_PEER_DISCOVERY_ROOTNODE=vp0:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer0:7050 - - CORE_SECURITY_ENROLLID=test_vp2 - - CORE_SECURITY_ENROLLSECRET=vQelbRvja7cJ + - CORE_PEER_MSPCONFIGPATH=${PEER2_CORE_PEER_MSPCFGPATH} depends_on: - membersrvc0 - orderer0 - - vp0 + - peer0 - vp3: + peer3: extends: file: docker-compose-next.yml service: vpNext environment: - CORE_PEER_ID=vp3 - - CORE_PEER_DISCOVERY_ROOTNODE=vp0:7051 + - CORE_PEER_GOSSIP_BOOTSTRAP=peer0:7051 - CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer0:7050 - - CORE_SECURITY_ENROLLID=test_vp3 - - CORE_SECURITY_ENROLLSECRET=9LKqKH5peurL + - CORE_PEER_MSPCONFIGPATH=${PEER3_CORE_PEER_MSPCFGPATH} depends_on: - membersrvc0 - orderer0 - - vp0 + - peer0 diff --git a/bddtests/docker-compose-orderer-base.yml b/bddtests/docker-compose-orderer-base.yml index ff9d6f87378..5b73a5d756b 100644 --- a/bddtests/docker-compose-orderer-base.yml +++ b/bddtests/docker-compose-orderer-base.yml @@ -11,6 +11,7 @@ services: - ORDERER_GENERAL_MAXWINDOWSIZE=1000 - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_LOGLEVEL=debug + - ORDERER_GENERAL_GENESISMETHOD=provisional - ORDERER_GENERAL_GENESISIFILE=${ORDERER_GENERAL_GENESISIFILE} - ORDERER_RAMLEDGER_HISTORY_SIZE=100 volumes: diff --git a/bddtests/features/bootstrap.feature b/bddtests/features/bootstrap.feature index a5f13b051b0..cb69cf01355 100644 --- a/bddtests/features/bootstrap.feature +++ b/bddtests/features/bootstrap.feature @@ -25,7 +25,8 @@ Feature: Bootstrap # | User | Orderer | Organization | And the peer network has organizations: - | peerOrg0 | + | Organization | + | peerOrg0 | And a ordererBootstrapAdmin is identified and given access to all public certificates and orderer node info # Order info includes orderer admin/orderer information and address (host:port) from previous steps @@ -37,18 +38,17 @@ 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 "" to configure orderers - And we compose "" - - # We now have an orderer network with NO peers. Now need to configure and start the peer network - And user requests role of peer admin by creating a key and csr for peer and acquires signed certificate from organization: - | peer0Admin | peer0 | peerOrg0 | - - # We now have an orderer network with NO peers. Now need to configure and start the peer network - And user requests role of peer signer by creating a key and csr for peer and acquires signed certificate from organization: - | peer0Signer | peer0 | peerOrg0 | + # 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 | + | peer0Signer | peer0 | peerOrg0 | + | peer1Signer | peer1 | peerOrg0 | + | peer2Signer | peer2 | peerOrg0 | + | peer3Signer | peer3 | peerOrg0 | + And we compose "" And peer admins get the genesis block for chain 'chain1' from chainBoostrapAdmin And the peer admins inspect and approve the genesis block for chain 'chain1' diff --git a/bddtests/steps/bootstrap_impl.py b/bddtests/steps/bootstrap_impl.py index e67ea3e58a2..57fc013ddf7 100644 --- a/bddtests/steps/bootstrap_impl.py +++ b/bddtests/steps/bootstrap_impl.py @@ -33,6 +33,13 @@ def step_impl(context): for row in context.table.rows: directory.registerOrdererAdminTuple(row['User'], row['Orderer'], row['Organization']) +@given(u'user requests role for peer by creating a key and csr for peer and acquires signed certificate from organization') +def step_impl(context): + assert 'table' in context, "Expected table with triplet of User/Peer/Organization" + directory = bootstrap_util.getDirectory(context) + for row in context.table.rows: + directory.registerOrdererAdminTuple(row['User'], row['Peer'], row['Organization']) + @given(u'the peer network has organizations') def step_impl(context): assert 'table' in context, "Expected table of peer network organizations" @@ -50,6 +57,7 @@ def step_impl(context): def step_impl(context, ordererSystemChainId, networkConfigPolicy, consensusType): genesisBlock = bootstrap_util.createGenesisBlock(context, ordererSystemChainId, networkConfigPolicy, consensusType) bootstrap_util.OrdererGensisBlockCompositionCallback(context, genesisBlock) + bootstrap_util.PeerCompositionCallback(context) @given(u'the orderer admins inspect and approve the genesis block for chain "{chainId}"') def step_impl(context, chainId): diff --git a/bddtests/steps/bootstrap_util.py b/bddtests/steps/bootstrap_util.py index faae4f4036a..ec3df279628 100644 --- a/bddtests/steps/bootstrap_util.py +++ b/bddtests/steps/bootstrap_util.py @@ -137,6 +137,9 @@ def __init__(self, name): # Which networks this organization belongs to self.networks = [] + def getSelfSignedCert(self): + return self.signedCert + def createCertificate(self, certReq): numYrs = 1 return createCertificate(certReq, (self.signedCert, self.pKey), 1000, (0, 60*60*24*365*numYrs)) @@ -413,6 +416,66 @@ def getEnv(self, composition, context, env): env["ORDERER_GENERAL_GENESISIFILE"]=self.getGenesisFilePath(composition, pathType=PathType.Container) +class PeerCompositionCallback(compose.CompositionCallback): + 'Responsible for setting up Peer nodes upon composition' + + def __init__(self, context): + self.context = context + self.volumeRootPathInContainer="/var/hyperledger/bddtests" + compose.Composition.RegisterCallbackInContext(context, self) + + def getVolumePath(self, composition, pathType=PathType.Local): + assert pathType in PathType, "Expected pathType of {0}".format(PathType) + basePath = "." + if pathType == PathType.Container: + basePath = self.volumeRootPathInContainer + return "{0}/volumes/peer/{1}".format(basePath, composition.projectName) + + def getPeerList(self, composition): + return [serviceName for serviceName in composition.getServiceNames() if "peer" in serviceName] + + def getLocalMspConfigPath(self, composition, peerService, pathType=PathType.Local): + return "{0}/{1}/localMspConfig".format(self.getVolumePath(composition, pathType), peerService) + + def _createLocalMspConfigDirs(self, mspConfigPath): + os.makedirs("{0}/{1}".format(mspConfigPath, "signcerts")) + os.makedirs("{0}/{1}".format(mspConfigPath, "admincerts")) + os.makedirs("{0}/{1}".format(mspConfigPath, "cacerts")) + os.makedirs("{0}/{1}".format(mspConfigPath, "keystore")) + + + def composing(self, composition, context): + 'Will copy local MSP info over at this point for each peer node' + + directory = getDirectory(context) + + for peerService in self.getPeerList(composition): + localMspConfigPath = self.getLocalMspConfigPath(composition, peerService) + self._createLocalMspConfigDirs(localMspConfigPath) + # Loop through directory and place Peer Organization Certs into cacerts folder + for peerOrg in [org for orgName,org in directory.organizations.items() if Network.Peer in org.networks]: + with open("{0}/cacerts/{1}.pem".format(localMspConfigPath, peerOrg.name), "w") as f: + f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, peerOrg.getSelfSignedCert())) + + # Find the peer signer Tuple for this peer and add to signcerts folder + for pnt, cert in [(peerNodeTuple,cert) for peerNodeTuple,cert in directory.ordererAdminTuples.items() if peerService in peerNodeTuple.user and "signer" in peerNodeTuple.user.lower()]: + # Put the PEM file in the signcerts folder + with open("{0}/signcerts/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f: + f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + # Put the associated private key into the keystore folder + user = directory.getUser(pnt.user, shouldCreate=False) + with open("{0}/keystore/{1}.pem".format(localMspConfigPath, pnt.user), "w") as f: + f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, user.pKey)) + + + def decomposing(self, composition, context): + 'Will remove the orderer volume path folder for the context' + shutil.rmtree(self.getVolumePath(composition)) + + def getEnv(self, composition, context, env): + for peerService in self.getPeerList(composition): + localMspConfigPath = self.getLocalMspConfigPath(composition, peerService, pathType=PathType.Container) + env["{0}_CORE_PEER_MSPCFGPATH".format(peerService.upper())]=localMspConfigPath def setOrdererBootstrapGenesisBlock(genesisBlock): 'Responsible for setting the GensisBlock for the Orderer nodes upon composition' diff --git a/bddtests/steps/compose.py b/bddtests/steps/compose.py index 784991d5bef..958b935e19a 100644 --- a/bddtests/steps/compose.py +++ b/bddtests/steps/compose.py @@ -64,9 +64,19 @@ def __init__(self, context, composeFilesYaml, projectName = GetUUID()): self.context = context self.containerDataList = [] self.composeFilesYaml = composeFilesYaml + self.serviceNames = [] + self.serviceNames = self._collectServiceNames() [callback.composing(self, context) for callback in Composition.GetCompositionCallbacksFromContext(context)] self.issueCommand(["up", "--force-recreate", "-d"]) + def _collectServiceNames(self): + 'First collect the services names.' + servicesList = [service for service in self.issueCommand(["config", "--services"]).splitlines() if "WARNING" not in service] + return servicesList + + def getServiceNames(self): + return list(self.serviceNames) + def parseComposeFilesArg(self, composeFileArgs): args = [arg for sublist in [["-f", file] for file in [file if not os.path.isdir(file) else os.path.join(file, 'docker-compose.yml') for file in composeFileArgs.split()]] for arg in sublist] return args @@ -92,7 +102,7 @@ def issueCommand(self, args): output, error, returncode = \ bdd_test_util.cli_call(["docker-compose"] + cmdArgs, expect_success=True, env=self.getEnv()) # Don't rebuild if ps command - if args[0] !="ps": + if args[0] !="ps" and args[0] !="config": self.rebuildContainerData() return output