Skip to content

Commit

Permalink
[FAB-1141] Bootstrap now creates local MSP config
Browse files Browse the repository at this point in the history
The boostrap feature now configures the local MSP folders
(cacerts, signcerts, and keystore) properly.

Added GenesisMethod parameter to orderer base docker
compose file.

Removed pre-V1 security configuration from docker compose
file.

Changed discovery configuration in docker compose to gossip
mechanism.

Change-Id: Ib97fca264eb5c93b81464ab3d76c55ccedd085ac
Signed-off-by: jeffgarratt <garratt.jeff@gmail.com>
  • Loading branch information
jeffgarratt committed Jan 10, 2017
1 parent 75e960a commit 8126b2e
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 29 deletions.
6 changes: 6 additions & 0 deletions bddtests/compose-defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -22,3 +24,7 @@ services:
membersrvc:
image: hyperledger/fabric-membersrvc
command: membersrvc

volumes:

peer:
32 changes: 14 additions & 18 deletions bddtests/docker-compose-next-4.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,64 +13,60 @@ services:
service: orderer0


vp0:
peer0:
extends:
file: docker-compose-next.yml
service: vpNext
environment:
- 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
# ports:
# - 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
1 change: 1 addition & 0 deletions bddtests/docker-compose-orderer-base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
20 changes: 10 additions & 10 deletions bddtests/features/bootstrap.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 "<OrdererSystemChainId>" to configure orderers
And we compose "<ComposeFile>"



# 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 "<ComposeFile>"

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'
Expand Down
8 changes: 8 additions & 0 deletions bddtests/steps/bootstrap_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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):
Expand Down
63 changes: 63 additions & 0 deletions bddtests/steps/bootstrap_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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'
Expand Down
12 changes: 11 additions & 1 deletion bddtests/steps/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down

0 comments on commit 8126b2e

Please sign in to comment.