github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/bddtests/steps/bootstrap_impl.py (about)

     1  # Copyright IBM Corp. 2016 All Rights Reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  #
    15  
    16  from behave import *
    17  import endorser_util
    18  import bootstrap_util
    19  import orderer_util
    20  import compose
    21  import time
    22  
    23  @given(u'the orderer network has organizations')
    24  def step_impl(context):
    25      assert 'table' in context, "Expected table of orderer organizations"
    26      directory = bootstrap_util.getDirectory(context)
    27      for row in context.table.rows:
    28          org = directory.getOrganization(row['Organization'], shouldCreate = True)
    29          org.addToNetwork(bootstrap_util.Network.Orderer)
    30  
    31  
    32  @given(u'user requests role of orderer admin by creating a key and csr for orderer and acquires signed certificate from organization')
    33  def step_impl(context):
    34      assert 'table' in context, "Expected table with triplet of User/Orderer/Organization"
    35      directory = bootstrap_util.getDirectory(context)
    36      for row in context.table.rows:
    37          nodeAdminTuple = directory.registerOrdererAdminTuple(row['User'], row['Orderer'], row['Organization'])
    38          aliasToSaveUnder = row['AliasSavedUnder']
    39          if aliasToSaveUnder != "":
    40              directory.getUser(row['User']).setTagValue(aliasToSaveUnder, nodeAdminTuple)
    41  
    42  @given(u'user requests role for peer by creating a key and csr for peer and acquires signed certificate from organization')
    43  def step_impl(context):
    44      assert 'table' in context, "Expected table with triplet of User/Peer/Organization"
    45      directory = bootstrap_util.getDirectory(context)
    46      for row in context.table.rows:
    47          nodeAdminTuple = directory.registerOrdererAdminTuple(row['User'], row['Peer'], row['Organization'])
    48          aliasToSaveUnder = row['AliasSavedUnder']
    49          if aliasToSaveUnder != "":
    50              directory.getUser(row['User']).setTagValue(aliasToSaveUnder, nodeAdminTuple)
    51  
    52  
    53  @given(u'the peer network has organizations')
    54  def step_impl(context):
    55      assert 'table' in context, "Expected table of peer network organizations"
    56      directory = bootstrap_util.getDirectory(context)
    57      for row in context.table.rows:
    58          org = directory.getOrganization(row['Organization'], shouldCreate = True)
    59          org.addToNetwork(bootstrap_util.Network.Peer)
    60  
    61  @given(u'a ordererBootstrapAdmin is identified and given access to all public certificates and orderer node info')
    62  def step_impl(context):
    63      directory = bootstrap_util.getDirectory(context)
    64      assert len(directory.ordererAdminTuples) > 0, "No orderer admin tuples defined!!!"
    65      # Simply create the user
    66      bootstrap_util.getOrdererBootstrapAdmin(context, shouldCreate=True)
    67  
    68  @given(u'the ordererBootstrapAdmin using cert alias "{certAlias}" creates the genesis block "{ordererGenesisBlockName}" for chain "{ordererSystemChainIdName}" for composition "{composeFile}" and consensus "{consensusType}" with consortiums modification policy "{consortiumsModPolicy}" using consortiums')
    69  def step_impl(context, certAlias, ordererGenesisBlockName, ordererSystemChainIdName, composeFile, consensusType, consortiumsModPolicy):
    70      directory = bootstrap_util.getDirectory(context=context)
    71      ordererBootstrapAdmin = bootstrap_util.getOrdererBootstrapAdmin(context)
    72      ordererSystemChainIdGUUID = ordererBootstrapAdmin.tags[ordererSystemChainIdName]
    73      # Now collect the named signed config items
    74      configGroups =[bootstrap_util.getDefaultConsortiumGroup(consortiumsModPolicy)]
    75      for row in context.table.rows:
    76          configGroupName = row['Consortium']
    77          configGroups += ordererBootstrapAdmin.tags[configGroupName]
    78      # Concatenate signedConfigItems
    79  
    80      service_names = compose.Composition(context, composeFilesYaml=composeFile, register_and_up=False).getServiceNames()
    81  
    82      # Construct block
    83      nodeAdminTuple = ordererBootstrapAdmin.tags[certAlias]
    84      bootstrapCert = directory.findCertForNodeAdminTuple(nodeAdminTuple=nodeAdminTuple)
    85      (genesisBlock, envelope, genesis_block_channel_config) = bootstrap_util.createGenesisBlock(context=context,
    86                                                                                                 service_names=service_names,
    87                                                                                                 chainId=ordererSystemChainIdGUUID,
    88                                                                                                 consensusType=consensusType,
    89                                                                                                 nodeAdminTuple=nodeAdminTuple,
    90                                                                                                 signedConfigItems=configGroups)
    91      ordererBootstrapAdmin.setTagValue(ordererGenesisBlockName + "_genesis_channel_config", genesis_block_channel_config)
    92      ordererBootstrapAdmin.setTagValue(ordererGenesisBlockName, genesisBlock)
    93      ordererBootstrapAdmin.setTagValue("ConsensusType", consensusType)
    94      bootstrap_util.OrdererGensisBlockCompositionCallback(context, genesisBlock)
    95      bootstrap_util.PeerCompositionCallback(context)
    96  
    97  @given(u'the orderer admins inspect and approve the genesis block for chain "{chainId}"')
    98  def step_impl(context, chainId):
    99      pass
   100  
   101  @given(u'the orderer admins use the genesis block for chain "{chainId}" to configure orderers')
   102  def step_impl(context, chainId):
   103      pass
   104      #raise NotImplementedError(u'STEP: Given the orderer admins use the genesis block for chain "testchainid" to configure orderers')
   105  
   106  @given(u'the ordererBootstrapAdmin generates a GUUID to identify the orderer system chain and refer to it by name as "{ordererSystemChainId}"')
   107  def step_impl(context, ordererSystemChainId):
   108      directory = bootstrap_util.getDirectory(context)
   109      ordererBootstrapAdmin = bootstrap_util.getOrdererBootstrapAdmin(context)
   110      chaind_id = bootstrap_util.GetUniqueChannelName()
   111      ordererBootstrapAdmin.setTagValue(ordererSystemChainId, chaind_id)
   112  
   113  
   114  @given(u'the orderer config admin "{ordererConfigAdmin}" creates a consortium "{consortiumName}" with modification policy "{modPolicy}" for peer orgs who wish to form a network')
   115  def step_impl(context, ordererConfigAdmin, consortiumName, modPolicy):
   116      directory = bootstrap_util.getDirectory(context)
   117      ordererConfigAdmin = directory.getUser(ordererConfigAdmin)
   118  
   119      # Collect the orgs from the table
   120      orgNames = [row['Organization'] for row in context.table.rows]
   121      bootstrap_util.addOrdererBootstrapAdminOrgReferences(context, consortiumName, orgNames)
   122  
   123      consortium = bootstrap_util.createConsortium(context=context, consortium_name=consortiumName, org_names=orgNames, mod_policy=modPolicy)
   124      ordererConfigAdmin.setTagValue(consortiumName, consortium)
   125  
   126  @given(u'the orderer config admin "{ordererConfigAdmin}" creates a consortiums config update "{consortiumsConfigUpdateName}" using config "{configName}" using orderer system channel ID "{ordererSystemChainIdName}" to add consortiums')
   127  def step_impl(context, ordererConfigAdmin, consortiumsConfigUpdateName, configName, ordererSystemChainIdName):
   128      '''
   129      channel group/Consortiums/
   130      Read the consortiums Group from existing genesis block.
   131      '''
   132      directory = bootstrap_util.getDirectory(context)
   133      ordererConfigAdmin = directory.getUser(ordererConfigAdmin)
   134      channel_group = ordererConfigAdmin.getTagValue(configName)
   135      orderer_system_chain_id = ordererConfigAdmin.getTagValue(ordererSystemChainIdName)
   136      config_groups = []
   137      # Now collect the consortiums
   138      for row in context.table.rows:
   139          config_groups.append(ordererConfigAdmin.getTagValue(row['Consortium']))
   140      config_update = bootstrap_util.create_orderer_consortium_config_update(orderer_system_chain_id, channel_group, config_groups)
   141      ordererConfigAdmin.setTagValue(tagKey=consortiumsConfigUpdateName, tagValue=config_update)
   142  
   143  @given(u'the user "{userName}" creates a peer organization set "{peerOrgSetName}" with peer organizations')
   144  def step_impl(context, userName, peerOrgSetName):
   145      ' At the moment, only really defining MSP Config Items (NOT SIGNED)'
   146      directory = bootstrap_util.getDirectory(context)
   147      user = directory.getUser(userName)
   148      user.setTagValue(peerOrgSetName, [directory.getOrganization(row['Organization']).name for row in context.table.rows])
   149  
   150  @given(u'the user "{userName}" creates a configUpdateEnvelope "{configUpdateEnvelopeName}" using configUpdate "{configUpdateName}"')
   151  def step_impl(context, userName, configUpdateEnvelopeName, configUpdateName):
   152      directory = bootstrap_util.getDirectory(context)
   153      user = directory.getUser(userName)
   154      config_update_envelope = bootstrap_util.create_config_update_envelope(config_update=user.getTagValue(configUpdateName))
   155      user.setTagValue(tagKey=configUpdateEnvelopeName, tagValue=config_update_envelope)
   156  
   157  @given(u'the user "{userName}" creates a new channel ConfigUpdate "{create_channel_config_update_name}" using consortium "{consortium_name}"')
   158  def step_impl(context, userName, create_channel_config_update_name, consortium_name):
   159      directory = bootstrap_util.getDirectory(context)
   160      user = directory.getUser(userName)
   161      consortium_config_group = user.getTagValue(tagKey=consortium_name)
   162  
   163      peer_org_set = user.getTagValue(tagKey=context.table.rows[0]["PeerOrgSet"])
   164      peer_anchor_set_tag_key = context.table.rows[0]["[PeerAnchorSet]"]
   165      peer_anchor_config_group = None
   166      if peer_anchor_set_tag_key != "":
   167          peer_anchor_config_group = user.getTagValue(tagKey=peer_anchor_set_tag_key)
   168  
   169      channel_id = context.table.rows[0]["ChannelID"]
   170      # Loop through templates referenced orgs
   171      # mspOrgNames = [org.name for org in user.tags[templateName]]
   172      #TODO: Where does the system_channel_version come from?
   173      system_channel_version = 0
   174      channel_config_update = bootstrap_util.create_channel_config_update(system_channel_version, channel_id, consortium_config_group)
   175  
   176      # Add the anchors config group
   177      if peer_anchor_config_group:
   178          bootstrap_util.mergeConfigGroups(channel_config_update.write_set, peer_anchor_config_group)
   179  
   180      #Make sure orgs exist in consortium
   181      for orgName in peer_org_set:
   182          assert orgName in channel_config_update.write_set.groups['Application'].groups.keys(), "PeerOrgSet entry {0} not found in consortium".format(orgName)
   183  
   184      # Strip out any organizations that are NOT referenced in peerOrgSet
   185      for orgName in channel_config_update.write_set.groups['Application'].groups.keys():
   186          if not orgName in peer_org_set:
   187              del(channel_config_update.read_set.groups['Application'].groups[orgName])
   188              del(channel_config_update.write_set.groups['Application'].groups[orgName])
   189  
   190      user.setTagValue(create_channel_config_update_name, channel_config_update)
   191  
   192  @Given(u'the user "{user_name}" creates an existing channel config update "{existing_channel_config_update_name}" using config update "{input_config_update_name}"')
   193  def step_impl(context, user_name, existing_channel_config_update_name, input_config_update_name):
   194      directory = bootstrap_util.getDirectory(context)
   195      user = directory.getUser(user_name)
   196  
   197      input_config_update = user.getTagValue(tagKey=input_config_update_name)
   198  
   199      channel_id = context.table.rows[0]["ChannelID"]
   200  
   201      peer_anchor_set_tag_key = context.table.rows[0]["[PeerAnchorSet]"]
   202      peer_anchor_config_group = None
   203      if peer_anchor_set_tag_key != "":
   204          peer_anchor_config_group = user.getTagValue(tagKey=peer_anchor_set_tag_key)
   205  
   206  
   207      assert peer_anchor_config_group != None, "Required to specify a PeerAnchorSet for now"
   208      #TODO: Where does the system_channel_version come from?
   209      system_channel_version = 0
   210      channel_config_update = bootstrap_util.create_existing_channel_config_update(system_channel_version=system_channel_version,
   211                                                                                   channel_id=channel_id,
   212                                                                                   input_config_update=input_config_update,
   213                                                                                   config_groups=[peer_anchor_config_group])
   214  
   215      user.setTagValue(existing_channel_config_update_name, channel_config_update)
   216  
   217  @given(u'the following application developers are defined for peer organizations and each saves their cert as alias')
   218  def step_impl(context):
   219      assert 'table' in context, "Expected table with triplet of Developer/Consortium/Organization"
   220      directory = bootstrap_util.getDirectory(context)
   221      for row in context.table.rows:
   222          userName = row['Developer']
   223          nodeAdminNamedTuple = directory.registerOrdererAdminTuple(userName, row['Consortium'], row['Organization'])
   224          user = directory.getUser(userName)
   225          user.setTagValue(row['AliasSavedUnder'], nodeAdminNamedTuple)
   226  
   227  @given(u'the user "{userName}" collects signatures for ConfigUpdateEnvelope "{createChannelSignedConfigEnvelopeName}" from developers')
   228  def step_impl(context, userName, createChannelSignedConfigEnvelopeName):
   229      assert 'table' in context, "Expected table of peer organizations"
   230      directory = bootstrap_util.getDirectory(context)
   231      user = directory.getUser(userName=userName)
   232      config_update_envelope = user.tags[createChannelSignedConfigEnvelopeName]
   233      for row in context.table.rows:
   234          user = directory.getUser(row['Developer'])
   235          namedAdminTuple = user.tags[row['Cert Alias']]
   236          cert = directory.findCertForNodeAdminTuple(namedAdminTuple)
   237          # assert bootstrap_util.Network.Peer in org.networks, "Organization '{0}' not in Peer network".format(org.name)
   238          bootstrap_util.BootstrapHelper.addSignatureToSignedConfigItem(config_update_envelope, (user, namedAdminTuple.organization, cert))
   239      # print("Signatures for signedConfigEnvelope:\n {0}\n".format(signedConfigEnvelope.Items[0]))
   240  
   241  @given(u'the user "{userName}" creates a ConfigUpdate Tx "{configUpdateTxName}" using cert alias "{certAlias}" using signed ConfigUpdateEnvelope "{createChannelSignedConfigEnvelopeName}"')
   242  def step_impl(context, userName, certAlias, configUpdateTxName, createChannelSignedConfigEnvelopeName):
   243      directory = bootstrap_util.getDirectory(context)
   244      user = directory.getUser(userName=userName)
   245      namedAdminTuple = user.tags[certAlias]
   246      cert = directory.findCertForNodeAdminTuple(namedAdminTuple)
   247      config_update_envelope = user.tags[createChannelSignedConfigEnvelopeName]
   248      config_update = bootstrap_util.getChannelIdFromConfigUpdateEnvelope(config_update_envelope)
   249      envelope_for_config_update = bootstrap_util.createEnvelopeForMsg(directory=directory,
   250                                                                       nodeAdminTuple=namedAdminTuple,
   251                                                                       chainId=config_update.channel_id,
   252                                                                       msg=config_update_envelope,
   253                                                                       typeAsString="CONFIG_UPDATE")
   254      user.setTagValue(configUpdateTxName, envelope_for_config_update)
   255  
   256  @given(u'the user "{userName}" using cert alias "{certAlias}" broadcasts ConfigUpdate Tx "{configTxName}" to orderer "{orderer}"')
   257  def step_impl(context, userName, certAlias, configTxName, orderer):
   258      directory = bootstrap_util.getDirectory(context)
   259      user = directory.getUser(userName=userName)
   260      configTxEnvelope = user.tags[configTxName]
   261      bootstrap_util.broadcastCreateChannelConfigTx(context=context,certAlias=certAlias, composeService=orderer, user=user, configTxEnvelope=configTxEnvelope)
   262  
   263  @when(u'the user "{userName}" broadcasts transaction "{transactionAlias}" to orderer "{orderer}"')
   264  def step_impl(context, userName, transactionAlias, orderer):
   265      directory = bootstrap_util.getDirectory(context)
   266      user = directory.getUser(userName=userName)
   267      transaction = user.tags[transactionAlias]
   268      bootstrap_util.broadcastCreateChannelConfigTx(context=context, certAlias=None, composeService=orderer, user=user, configTxEnvelope=transaction)
   269  
   270  
   271  @when(u'user "{userName}" using cert alias "{certAlias}" connects to deliver function on orderer "{composeService}"')
   272  @Given(u'user "{userName}" using cert alias "{certAlias}" connects to deliver function on orderer "{composeService}"')
   273  def step_impl(context, userName, certAlias, composeService):
   274      directory = bootstrap_util.getDirectory(context)
   275      user = directory.getUser(userName=userName)
   276      user.connectToDeliverFunction(context, composeService, nodeAdminTuple=user.tags[certAlias])
   277  
   278  @when(u'user "{userName}" sends deliver a seek request on orderer "{composeService}" with properties')
   279  def step_impl(context, userName, composeService):
   280      directory = bootstrap_util.getDirectory(context)
   281      user = directory.getUser(userName=userName)
   282      row = context.table.rows[0]
   283      chainID = row['ChainId']
   284      start, end, = orderer_util.convertSeek(row['Start']), orderer_util.convertSeek(row['End'])
   285      print("Start and end = {0}/{1}".format(start, end))
   286      print("")
   287      streamHelper = user.getDelivererStreamHelper(context, composeService)
   288      streamHelper.seekToRange(chainID=chainID, start = start, end = end)
   289  
   290  @given(u'user "{userName}" retrieves the latest config update "{latest_config_name}" from orderer "{service_name}" for channel "{channel_id_or_ref}"')
   291  def step_impl(context, userName, latest_config_name, service_name, channel_id_or_ref):
   292  
   293  
   294      directory = bootstrap_util.getDirectory(context)
   295      user = directory.getUser(userName=userName)
   296      (channel_id,) = bootstrap_util.get_args_for_user([channel_id_or_ref], user)
   297      streamHelper = user.getDelivererStreamHelper(context, service_name)
   298      latest_config_block = bootstrap_util.get_latest_configuration_block(deliverer_stream_helper=streamHelper, channel_id=channel_id)
   299      channel_group = bootstrap_util.get_channel_group_from_config_block(latest_config_block)
   300      user.setTagValue(tagKey=latest_config_name, tagValue=channel_group)
   301      # raise NotImplementedError(u'STEP: Given user "configAdminOrdererOrg0" retrieves the latest configuration "latestOrdererConfig" from orderer "orderer0" for channel "OrdererSystemChainId"')
   302  
   303  @then(u'user "{userName}" should get a delivery "{deliveryName}" from "{composeService}" of "{expectedBlocks}" blocks with "{numMsgsToBroadcast}" messages within "{batchTimeout}" seconds')
   304  def step_impl(context, userName, deliveryName, composeService, expectedBlocks, numMsgsToBroadcast, batchTimeout):
   305      directory = bootstrap_util.getDirectory(context)
   306      user = directory.getUser(userName=userName)
   307      streamHelper = user.getDelivererStreamHelper(context, composeService)
   308  
   309      blocks = streamHelper.getBlocks()
   310  
   311      # Verify block count
   312      assert len(blocks) == int(expectedBlocks), "Expected {0} blocks, received {1}".format(expectedBlocks, len(blocks))
   313      user.setTagValue(deliveryName, blocks)
   314  
   315  @when(u'user "{userName}" using cert alias "{certAlias}" requests to join channel using genesis block "{genisisBlockName}" on peers with result "{joinChannelResult}"')
   316  def step_impl(context, userName, certAlias, genisisBlockName, joinChannelResult):
   317      timeout = 10
   318      directory = bootstrap_util.getDirectory(context)
   319      user = directory.getUser(userName)
   320      nodeAdminTuple = user.tags[certAlias]
   321      # Find the cert using the cert tuple information saved for the user under certAlias
   322      signersCert = directory.findCertForNodeAdminTuple(nodeAdminTuple)
   323  
   324      # Retrieve the genesis block from the returned value of deliver (Will be list with first block as genesis block)
   325      genesisBlock = user.tags[genisisBlockName][0]
   326      ccSpec = endorser_util.getChaincodeSpec("GOLANG", "", "cscc", ["JoinChain", genesisBlock.SerializeToString()])
   327      proposal = endorser_util.createInvokeProposalForBDD(context, ccSpec=ccSpec, chainID="",signersCert=signersCert, Mspid=user.tags[certAlias].organization, type="CONFIG")
   328      signedProposal = endorser_util.signProposal(proposal=proposal, entity=user, signersCert=signersCert)
   329  
   330      # Send proposal to each specified endorser, waiting 'timeout' seconds for response/error
   331      endorsers = [row['Peer'] for row in context.table.rows]
   332      proposalResponseFutures = [endorserStub.ProcessProposal.future(signedProposal, int(timeout)) for endorserStub in endorser_util.getEndorserStubs(context,composeServices=endorsers, directory=directory, nodeAdminTuple=nodeAdminTuple)]
   333      resultsDict =  dict(zip(endorsers, [respFuture.result() for respFuture in proposalResponseFutures]))
   334      user.setTagValue(joinChannelResult, resultsDict)
   335  
   336  
   337  @then(u'user "{userName}" expects result code for "{proposalResponseName}" of "{proposalResponseResultCode}" from peers')
   338  def step_impl(context, userName, proposalResponseName, proposalResponseResultCode):
   339      directory = bootstrap_util.getDirectory(context)
   340      user = directory.getUser(userName=userName)
   341      peerToProposalResponseDict = user.tags[proposalResponseName]
   342      unexpectedResponses = [(composeService,proposalResponse) for composeService, proposalResponse in peerToProposalResponseDict.items() if proposalResponse.response.payload != proposalResponseResultCode]
   343      print("ProposalResponse: \n{0}\n".format(proposalResponse))
   344      print("")
   345  
   346  @given(u'the user "{userName}" creates an peer anchor set "{anchorSetName}" for orgs')
   347  def step_impl(context, userName, anchorSetName):
   348      directory = bootstrap_util.getDirectory(context)
   349      user = directory.getUser(userName=userName)
   350      nodeAdminTuples = [directory.findNodeAdminTuple(row['User'], row['Peer'], row['Organization']) for row in context.table.rows]
   351      user.setTagValue(anchorSetName, bootstrap_util.getAnchorPeersConfigGroup(context=context, nodeAdminTuples=nodeAdminTuples))
   352  
   353  @given(u'we compose "{composeYamlFile}"')
   354  def step_impl(context, composeYamlFile):
   355      # time.sleep(10)              # Should be replaced with a definitive interlock guaranteeing that all peers/membersrvc are ready
   356      composition = compose.Composition(context, composeYamlFile)
   357      context.compose_containers = composition.containerDataList
   358      context.composition = composition
   359  
   360  @given(u'I wait "{seconds}" seconds')
   361  def step_impl(context, seconds):
   362      time.sleep(float(seconds))
   363  
   364  @when(u'I wait "{seconds}" seconds')
   365  def step_impl(context, seconds):
   366      time.sleep(float(seconds))
   367  
   368  @then(u'I wait "{seconds}" seconds')
   369  def step_impl(context, seconds):
   370      time.sleep(float(seconds))
   371  
   372  @given(u'user "{userNameSource}" gives "{objectAlias}" to user "{userNameTarget}"')
   373  def step_impl(context, userNameSource, objectAlias, userNameTarget):
   374      directory = bootstrap_util.getDirectory(context)
   375      userSource = directory.getUser(userName=userNameSource)
   376      userTarget = directory.getUser(userName=userNameTarget)
   377      userTarget.setTagValue(objectAlias, userSource.tags[objectAlias])
   378  
   379  @given(u'the ordererBootstrapAdmin creates a cert alias "{certAlias}" for orderer network bootstrap purposes for organizations')
   380  def step_impl(context, certAlias):
   381      assert "table" in context, "Expected table of Organizations"
   382      directory = bootstrap_util.getDirectory(context)
   383      ordererBootstrapAdmin = bootstrap_util.getOrdererBootstrapAdmin(context)
   384      assert len(context.table.rows) == 1, "Only support single orderer orgnaization at moment"
   385      for row in context.table.rows:
   386          nodeAdminNamedTuple = directory.registerOrdererAdminTuple(ordererBootstrapAdmin.name, "ordererBootstrapAdmin", row['Organization'])
   387          ordererBootstrapAdmin.setTagValue(certAlias, nodeAdminNamedTuple)
   388  
   389  @given(u'we "{command}" service "{service_name}"')
   390  def step_impl(context, command, service_name):
   391      assert "composition" in context, "No composition found in context"
   392      composition = context.composition
   393      composition.issueCommand([command], [service_name])