def test_get_pod(self, mock_execute, mock_Executer): mock_execute.side_effect = [("a-pod", None)] get_pod("a-namespace", "an-identifier") mock_execute.assert_called_once_with( "kubectl get pods -n a-namespace an-identifier " + '-o jsonpath="{.items[0].metadata.name}"', ) mock_Executer.assert_called_once_with("a-pod", namespace="a-namespace")
def test_get_pod_fail(self, mock_execute, mock_Executer): mock_execute.side_effect = [(None, "error")] with pytest.raises(ValueError): get_pod("a-namespace", "an-identifier", item=3) mock_execute.assert_called_once_with( "kubectl get pods -n a-namespace an-identifier " + '-o jsonpath="{.items[3].metadata.name}"', ) mock_Executer.assert_not_called()
def test_get_pod_fail(self, mock_execute, mock_Executer): mock_execute.side_effect = [''] with pytest.raises(ValueError): get_pod('a-namespace', 'a-release', 'an-app', verbose=True) mock_execute.assert_called_once_with( 'kubectl get pods -n a-namespace -l "app=an-app,release=a-release" ' + '-o jsonpath="{.items[0].metadata.name}"', verbose=True) mock_Executer.assert_not_called()
def test_get_pod(self, mock_execute, mock_Executer): mock_execute.side_effect = ['a-pod'] get_pod('a-namespace', 'a-release', 'an-app') mock_execute.assert_called_once_with( 'kubectl get pods -n a-namespace -l "app=an-app,release=a-release" ' + '-o jsonpath="{.items[0].metadata.name}"', verbose=False) mock_Executer.assert_called_once_with('a-pod', namespace='a-namespace', verbose=False)
def test_get_pod(self, mock_execute, mock_Executer): mock_execute.side_effect = [("a-pod", None)] get_pod("a-namespace", "a-release", "an-app") mock_execute.assert_called_once_with( 'kubectl get pods -n a-namespace -l "app=an-app,release=a-release" ' + '-o jsonpath="{.items[0].metadata.name}"', verbose=False, ) mock_Executer.assert_called_once_with("a-pod", namespace="a-namespace", verbose=False)
def install_network(opts, verbose=False): """Install Hyperledger Composer network. Args: opts (dict): Nephos options dict. verbose (bool): Verbosity. False by default. """ peer_namespace = get_namespace(opts, opts["peers"]["msp"]) hlc_cli_ex = get_pod( peer_namespace, opts["composer"]["name"], "hl-composer", verbose=verbose ) # Install network # TODO: Getting BNA could be a helper function bna, _ = hlc_cli_ex.execute("ls /hl_config/blockchain_network") bna_name, bna_rem = bna.split("_") bna_version, _ = bna_rem.split(".bna") # TODO: This could be a single function peer_msp = opts["peers"]["msp"] bna_admin = opts["msps"][peer_msp]["org_admin"] admin_creds(opts, peer_msp, verbose=verbose) bna_pw = opts["msps"][peer_msp]["org_adminpw"] ls_res, _ = hlc_cli_ex.execute( "composer card list --card {bna_admin}@{bna_name}".format( bna_admin=bna_admin, bna_name=bna_name ) ) if not ls_res: hlc_cli_ex.execute( ( "composer network install --card PeerAdmin@hlfv1 " + "--archiveFile /hl_config/blockchain_network/{bna}" ).format(bna=bna) ) hlc_cli_ex.execute( ( "composer network start " + "--card PeerAdmin@hlfv1 " + "--networkName {bna_name} --networkVersion {bna_version} " + "--networkAdmin {bna_admin} --networkAdminEnrollSecret {bna_pw}" ).format( bna_name=bna_name, bna_version=bna_version, bna_admin=bna_admin, bna_pw=bna_pw, ) ) hlc_cli_ex.execute( "composer card import --file {bna_admin}@{bna_name}.card".format( bna_admin=bna_admin, bna_name=bna_name ) ) hlc_cli_ex.execute( "composer network ping --card {bna_admin}@{bna_name}".format( bna_admin=bna_admin, bna_name=bna_name ) )
def setup_ca(opts, upgrade=False, verbose=False): for ca_name, ca_values in opts['cas'].items(): ca_namespace = get_namespace(opts, ca=ca_name) # Install Charts ca_chart(opts=opts, release=ca_name, upgrade=upgrade, verbose=verbose) # Obtain CA pod and Enroll pod_exec = get_pod(namespace=ca_namespace, release=ca_name, app='hlf-ca', verbose=verbose) ca_enroll(pod_exec) # Get CA Ingress and check it is running try: # Get ingress of CA ingress_urls = ingress_read(ca_name + '-hlf-ca', namespace=ca_namespace, verbose=verbose) except ApiException: print('No ingress found for CA') continue # Check the CA is running check_ca(ingress_host=ingress_urls[0], verbose=verbose)
def check_id(ca_namespace, ca, username, verbose=False): """ Args: ca_namespace (str): K8S namespace where CA is located. ca (str): K8S release name of CA. username (str): Username for identity. verbose (bool) Verbosity. False by default. Returns: bool: Does the ID exist? """ # Get CA ca_exec = get_pod(namespace=ca_namespace, release=ca, app="hlf-ca", verbose=verbose) # Check if Orderer is registered with the relevant CA got_id = False while not got_id: ord_id, err = ca_exec.execute( "fabric-ca-client identity list --id {id}".format(id=username)) if err: # Expected error (identity does not exist) if "no rows in result set" in err: got_id = True # Otherwise, unexpected error, we are having issues connecting to CA else: sleep(15) else: got_id = True return ord_id
def extract_crypto(opts, node_type, verbose=False): # Get chart type chart = NODE_MAPPER[node_type] node_namespace = get_namespace(opts, opts[node_type + 's']['msp']) for release in opts[node_type + 's']['names']: pod_ex = get_pod(node_namespace, release, chart) # Secrets crypto_info = [ CryptoInfo('idcert', 'signcerts', 'cert.pem', True), CryptoInfo('idkey', 'keystore', 'key.pem', True), CryptoInfo('cacert', 'cacerts', 'cacert.pem', True), CryptoInfo('caintcert', 'intermediatecerts', 'intermediatecacert.pem', False) ] for item in crypto_info: secret_name = 'hlf--{}-{}'.format(release, item.secret_type) try: secret_read(secret_name, node_namespace) if verbose: print('{} secret already exists'.format(secret_name)) except ApiException: command = "bash -c 'ls /var/hyperledger/msp/{}' | wc -l".format(item.subfolder) file_num = pod_ex.execute(command) if file_num.strip() != '1': if item.required: raise ValueError('We should only have 1 file in each of these folders') else: print('Wrong number of files in {} directory'.format(item.subfolder)) else: command = "bash -c 'cat /var/hyperledger/msp/{}/*'".format(item.subfolder) content = pod_ex.execute(command) secret_data = { item.key: content } secret_create(secret_data, secret_name, node_namespace, verbose=verbose)
def setup_admin(opts, verbose=False): """Setup the Peer Admin for Hyperledger Composer. Args: opts (dict): Nephos options dict. verbose (bool): Verbosity. False by default. """ peer_namespace = get_namespace(opts, opts["peers"]["msp"]) hlc_cli_ex = get_pod(peer_namespace, opts["composer"]["name"], "hl-composer", verbose=verbose) # Set up the PeerAdmin card ls_res, _ = hlc_cli_ex.execute("composer card list --card PeerAdmin@hlfv1") if not ls_res: hlc_cli_ex.execute( ("composer card create " + "-p /hl_config/hlc-connection/connection.json " + "-u PeerAdmin -c /hl_config/admin/signcerts/cert.pem " + "-k /hl_config/admin/keystore/key.pem " + " -r PeerAdmin -r ChannelAdmin " + "--file /home/composer/PeerAdmin@hlfv1")) hlc_cli_ex.execute("composer card import " + "--file /home/composer/[email protected]")
def upgrade_network(opts, verbose=False): # Set up the PeerAdmin card hlc_cli_ex = get_pod(get_namespace(opts, opts['peers']['msp']), 'hlc', 'hl-composer', verbose=verbose) bna = hlc_cli_ex.execute('ls /hl_config/blockchain_network') bna_name, bna_rem = bna.split('_') bna_version, _ = bna_rem.split('.bna') peer_ca = opts['peers']['ca'] bna_admin = opts['cas'][peer_ca]['org-admin'] res = hlc_cli_ex.execute('composer network ping --card {bna_admin}@{bna_name}'.format( bna_admin=bna_admin, bna_name=bna_name)) curr_version = (res.split('Business network version: ')[1]).split()[0] print(curr_version) if curr_version != bna_version: hlc_cli_ex.execute( ('composer network install --card PeerAdmin@hlfv1 ' + '--archiveFile /hl_config/blockchain_network/{bna}').format(bna=bna)) hlc_cli_ex.execute( ('composer network upgrade ' + '--card PeerAdmin@hlfv1 ' + '--networkName {bna_name} --networkVersion {bna_version}').format( bna_name=bna_name, bna_version=bna_version ))
def check_ord(namespace, release, verbose=False): pod_exec = get_pod(namespace=namespace, release=release, app='hlf-ord', verbose=verbose) res = pod_exec.logs(1000) if 'fetching metadata for all topics from broker' in res: return True while True: if 'Starting orderer' in res: return True else: sleep(15) res = pod_exec.logs(1000)
def create_channel(opts, verbose=False): """Create Channel for Peer. Args: opts (dict): Nephos options dict. verbose (bool): Verbosity. False by default. """ peer_namespace = get_namespace(opts, opts["peers"]["msp"]) ord_namespace = get_namespace(opts, opts["orderers"]["msp"]) channel = opts["peers"]["channel_name"] # Get orderer TLS status ord_name = random.choice(opts["orderers"]["names"]) # TODO: This should be a function cmd_suffix = peer_channel_suffix(opts, ord_name, verbose=verbose) for index, release in enumerate(opts["peers"]["names"]): # Get peer pod pod_ex = get_pod(peer_namespace, release, "hlf-peer", verbose=verbose) # Check if the file exists has_channel = False while not has_channel: has_channel = get_channel_block( pod_ex, ord_name, ord_namespace, channel, cmd_suffix ) if not has_channel: pod_ex.execute( ( "bash -c 'peer channel create " + "-o {orderer}-hlf-ord.{ns}.svc.cluster.local:7050 " + "-c {channel} -f /hl_config/channel/{channel}.tx {cmd_suffix}'" ).format( orderer=ord_name, ns=ord_namespace, channel=opts["peers"]["channel_name"], cmd_suffix=cmd_suffix, ) ) res, _ = pod_ex.execute("peer channel list") channels = (res.split("Channels peers has joined: ")[1]).split() if opts["peers"]["channel_name"] not in channels: pod_ex.execute( ( "bash -c " + "'CORE_PEER_MSPCONFIGPATH=$ADMIN_MSP_PATH " + "peer channel join -b /var/hyperledger/{channel}.block {cmd_suffix}'" ).format(channel=opts["peers"]["channel_name"], cmd_suffix=cmd_suffix) )
def create_admin(opts, msp_name, verbose=False): dir_config = opts['core']['dir_config'] msp_values = opts['msps'][msp_name] ca_values = opts['cas'][msp_values['ca']] # TODO: Refactor this into its own function ca_name = msp_values['ca'] ca_namespace = get_namespace(opts, ca=ca_name) # Obtain CA pod pod_exec = get_pod(namespace=ca_namespace, release=ca_name, app='hlf-ca', verbose=verbose) # Get CA ingress ingress_urls = ingress_read(ca_name + '-hlf-ca', namespace=ca_namespace, verbose=verbose) ca_ingress = ingress_urls[0] # Register the Organisation with the CAs admin_id = pod_exec.execute( ('fabric-ca-client identity list --id {id}').format( id=msp_values['org_admin'])) # If we cannot find the identity, we must create it if not admin_id: pod_exec.execute(( "fabric-ca-client register --id.name {id} --id.secret {pw} --id.attrs 'admin=true:ecert'" ).format(id=msp_values['org_admin'], pw=msp_values['org_adminpw'])) # If our keystore does not exist or is empty, we need to enroll the identity... keystore = path.join(dir_config, msp_name, 'keystore') if not path.isdir(keystore) or not listdir(keystore): execute(( 'FABRIC_CA_CLIENT_HOME={dir} fabric-ca-client enroll ' + '-u https://{id}:{pw}@{ingress} -M {msp_dir} --tls.certfiles {ca_server_tls}' ).format(dir=dir_config, id=msp_values['org_admin'], pw=msp_values['org_adminpw'], ingress=ca_ingress, msp_dir=msp_name, ca_server_tls=ca_values['tls_cert']), verbose=verbose)
def register_node(ca_namespace, ca, node_type, username, password, verbose=False): # Get CA ca_exec = get_pod(namespace=ca_namespace, release=ca, app='hlf-ca', verbose=verbose) # Check if Orderer is registered with the relevant CA ord_id = ca_exec.execute( 'fabric-ca-client identity list --id {id}'.format(id=username)) # Registered if needed if not ord_id: ca_exec.execute( 'fabric-ca-client register --id.name {id} --id.secret {pw} --id.type {type}' .format(id=username, pw=password, type=node_type))
def setup_admin(opts, verbose=False): peer_namespace = get_namespace(opts, opts['peers']['msp']) hlc_cli_ex = get_pod(peer_namespace, opts['composer']['name'], 'hl-composer', verbose=verbose) # Set up the PeerAdmin card ls_res = hlc_cli_ex.execute('composer card list --card PeerAdmin@hlfv1') if not ls_res: hlc_cli_ex.execute( ('composer card create ' + '-p /hl_config/hlc-connection/connection.json ' + '-u PeerAdmin -c /hl_config/admin/signcerts/cert.pem ' + '-k /hl_config/admin/keystore/key.pem ' + ' -r PeerAdmin -r ChannelAdmin ' + '--file /home/composer/PeerAdmin@hlfv1')) hlc_cli_ex.execute('composer card import ' + '--file /home/composer/[email protected]')
def upgrade_charts(opts, node_type, verbose=False): # Get chart type chart = NODE_MAPPER[node_type] node_namespace = get_namespace(opts, opts[node_type + 's']['msp']) for release in opts[node_type + 's']['names']: pod_ex = get_pod(node_namespace, release, chart) res = pod_ex.execute('ls /var/hyperledger/msp_old') if not res: pod_ex.execute('mv /var/hyperledger/msp /var/hyperledger/msp_old') else: print('/var/hyperledger/msp_old already exists') config_yaml = '{dir}/{chart}/{name}.yaml'.format( dir=opts['core']['dir_values'], chart=chart, name=release) helm_upgrade(opts['core']['chart_repo'], chart, release, node_namespace, config_yaml=config_yaml, verbose=verbose) if node_type == 'orderer': check_ord(node_namespace, release, verbose=verbose) elif node_type == 'peer': check_peer(node_namespace, release, verbose=verbose)
def install_network(opts, verbose=False): peer_namespace = get_namespace(opts, opts['peers']['msp']) hlc_cli_ex = get_pod(peer_namespace, opts['composer']['name'], 'hl-composer', verbose=verbose) # Install network # TODO: Getting BNA could be a helper function bna = hlc_cli_ex.execute('ls /hl_config/blockchain_network') bna_name, bna_rem = bna.split('_') bna_version, _ = bna_rem.split('.bna') peer_ca = opts['peers']['ca'] bna_admin = opts['cas'][peer_ca]['org_admin'] admin_creds(opts['cas'][peer_ca], peer_namespace, verbose=verbose) bna_pw = opts['cas'][peer_ca]['org_adminpw'] ls_res = hlc_cli_ex.execute( 'composer card list --card {bna_admin}@{bna_name}'.format( bna_admin=bna_admin, bna_name=bna_name)) if not ls_res: hlc_cli_ex.execute( ('composer network install --card PeerAdmin@hlfv1 ' + '--archiveFile /hl_config/blockchain_network/{bna}').format( bna=bna)) hlc_cli_ex.execute( ('composer network start ' + '--card PeerAdmin@hlfv1 ' + '--networkName {bna_name} --networkVersion {bna_version} ' + '--networkAdmin {bna_admin} --networkAdminEnrollSecret {bna_pw}' ).format(bna_name=bna_name, bna_version=bna_version, bna_admin=bna_admin, bna_pw=bna_pw)) hlc_cli_ex.execute( 'composer card import --file {bna_admin}@{bna_name}.card'.format( bna_admin=bna_admin, bna_name=bna_name)) hlc_cli_ex.execute( 'composer network ping --card {bna_admin}@{bna_name}'.format( bna_admin=bna_admin, bna_name=bna_name))
def upgrade_network(opts, verbose=False): """Upgrade Hyperledger Composer network. Args: opts (dict): Nephos options dict. verbose (bool): Verbosity. False by default. """ peer_namespace = get_namespace(opts, opts["peers"]["msp"]) secret_from_file(secret=opts["composer"]["secret_bna"], namespace=peer_namespace, verbose=verbose) # Set up the PeerAdmin card hlc_cli_ex = get_pod(peer_namespace, "hlc", "hl-composer", verbose=verbose) bna, _ = hlc_cli_ex.execute("ls /hl_config/blockchain_network") bna_name, bna_rem = bna.split("_") bna_version, _ = bna_rem.split(".bna") peer_msp = opts["peers"]["msp"] bna_admin = opts["msps"][peer_msp]["org_admin"] res, _ = hlc_cli_ex.execute( "composer network ping --card {bna_admin}@{bna_name}".format( bna_admin=bna_admin, bna_name=bna_name)) curr_version = (res.split("Business network version: ")[1]).split()[0] print(curr_version) if curr_version != bna_version: hlc_cli_ex.execute( ("composer network install --card PeerAdmin@hlfv1 " + "--archiveFile /hl_config/blockchain_network/{bna}").format( bna=bna)) hlc_cli_ex.execute( ("composer network upgrade " + "--card PeerAdmin@hlfv1 " + "--networkName {bna_name} --networkVersion {bna_version}").format( bna_name=bna_name, bna_version=bna_version)) res, _ = hlc_cli_ex.execute( "composer network ping --card {bna_admin}@{bna_name}".format( bna_admin=bna_admin, bna_name=bna_name)) curr_version = (res.split("Business network version: ")[1]).split()[0] print("Upgraded to {version}".format(version=curr_version))
def register_id(ca_namespace, ca, username, password, node_type="client", admin=False, verbose=False): """Register an ID with a Fabric Certificate Authority Args: ca_namespace (str): K8S namespace where CA is located. ca (str): K8S release name of CA. username (str): Username for identity. password (str): Password for identity. node_type (str): Node type for identity. "client" by default. admin (bool): Whether the identity is an admin. False by default. verbose (bool): Verbosity. False by default. """ # Get CA ord_id = check_id(ca_namespace, ca, username, verbose=verbose) # Registered if needed ca_exec = get_pod(namespace=ca_namespace, release=ca, app="hlf-ca", verbose=verbose) if not ord_id: command = ( "fabric-ca-client register --id.name {id} --id.secret {pw} --id.type {type}" ) if admin: command += " --id.attrs 'admin=true:ecert'" registered_id = False while not registered_id: res, err = ca_exec.execute( command.format(id=username, pw=password, type=node_type)) if not err: registered_id = True # Otherwise, unexpected error, we are having issues connecting to CA else: sleep(15)
def setup_ca(opts, upgrade=False, verbose=False): """Setup CA. Setup involves enrolling the CA admin, checking the Ingress is responsive. Args: opts (dict): Nephos options dict. upgrade (bool): Do we upgrade the deployment? False by default. verbose (bool): Verbosity. False by default. """ for ca_name, ca_values in opts["cas"].items(): ca_namespace = get_namespace(opts, ca=ca_name) # Install Charts ca_chart(opts=opts, release=ca_name, upgrade=upgrade, verbose=verbose) # Obtain CA pod and Enroll pod_exec = get_pod(namespace=ca_namespace, release=ca_name, app="hlf-ca", verbose=verbose) ca_enroll(pod_exec) # Get CA Ingress and check it is running try: # Get ingress of CA ingress_urls = ingress_read(ca_name + "-hlf-ca", namespace=ca_namespace, verbose=verbose) except ApiException: print("No ingress found for CA") continue # Check the CA is running check_ca( ingress_host=ingress_urls[0], cacert=ca_values.get("tls_cert"), verbose=verbose, )
def check_peer(namespace, release, verbose=False): """Check if Peer is running. Args: namespace: Namespace where Peer is located. release: Name of Peer Helm release. verbose (bool): Verbosity. False by default. Returns: bool: True once Peer is correctly running. """ pod_exec = get_pod( namespace=namespace, release=release, app="hlf-peer", verbose=verbose ) res = pod_exec.logs(1000) if "Received block" in res: return True while True: if "Starting peer" in res or "Sleeping" in res: return True else: sleep(15) res = pod_exec.logs(1000)
def check_ord(namespace, release, verbose=False): """Check if Orderer is running. Args: namespace (str): Namespace where Orderer is located. release (str): Name of Orderer Helm release. verbose (bool): Verbosity. False by default. Returns: bool: True once Orderer is correctly running. """ pod_exec = get_pod(namespace=namespace, release=release, app="hlf-ord", verbose=verbose) res = pod_exec.logs(1000) if "fetching metadata for all topics from broker" in res: return True while True: if "Starting orderer" in res: return True else: sleep(15) res = pod_exec.logs(1000)