def test_add_node_with_bad_code(network, args): if args.enclave_type == "virtual": LOG.warning( "Skipping test_add_node_with_bad_code with virtual enclave") return network replacement_package = ("liblogging" if args.package == "libjs_generic" else "libjs_generic") new_code_id = get_code_id( args.oe_binary, infra.path.build_lib_path(replacement_package, args.enclave_type), ) LOG.info(f"Adding a node with unsupported code id {new_code_id}") code_not_found_exception = None try: network.create_and_add_pending_node(replacement_package, "local://localhost", args, timeout=3) except infra.network.CodeIdNotFound as err: code_not_found_exception = err assert ( code_not_found_exception is not None ), f"Adding a node with unsupported code id {new_code_id} should fail" return network
def test_add_as_many_pending_nodes(network, args): # Should not change the raft consensus rules (i.e. majority) number_new_nodes = len(network.nodes) LOG.info( f"Adding {number_new_nodes} pending nodes - consensus rules should not change" ) for _ in range(number_new_nodes): network.create_and_add_pending_node(args.package, "localhost", args) check_can_progress(network.find_primary()[0]) return network
def test_node_filter(network, args): primary, _ = network.find_primary_and_any_backup() with primary.client() as c: def get_nodes(status): r = c.get(f"/node/network/nodes?status={status}") nodes = r.body.json()["nodes"] return sorted(nodes, key=lambda node: node["node_id"]) trusted_before = get_nodes("Trusted") pending_before = get_nodes("Pending") retired_before = get_nodes("Retired") new_node = network.create_and_add_pending_node( args.package, "local://localhost", args, target_node=primary ) trusted_after = get_nodes("Trusted") pending_after = get_nodes("Pending") retired_after = get_nodes("Retired") assert trusted_before == trusted_after, (trusted_before, trusted_after) assert len(pending_before) + 1 == len(pending_after), ( pending_before, pending_after, ) assert retired_before == retired_after, (retired_before, retired_after) assert all(info["status"] == "Trusted" for info in trusted_after), trusted_after assert all(info["status"] == "Pending" for info in pending_after), pending_after assert all(info["status"] == "Retired" for info in retired_after), retired_after assert new_node return network
def test_no_quote(network, args, notifications_queue=None, verify=True): untrusted_node = network.create_and_add_pending_node( args.package, "localhost", args) with untrusted_node.client(ca=os.path.join( untrusted_node.common_dir, f"{untrusted_node.node_id}.pem")) as uc: r = uc.get("/node/quote") assert r.status_code == http.HTTPStatus.NOT_FOUND
def test_no_quote(network, args): untrusted_node = network.create_and_add_pending_node( args.package, "local://localhost", args) with untrusted_node.client(ca=os.path.join( untrusted_node.common_dir, f"{untrusted_node.node_id}.pem")) as uc: r = uc.get("/node/quotes/self") assert r.status_code == http.HTTPStatus.NOT_FOUND return network
def test_add_node_untrusted_code(network, args): if args.enclave_type != "virtual": LOG.info("Adding an invalid node (unknown code id)") code_not_found_exception = None try: network.create_and_add_pending_node( "liblua_generic", "localhost", args, timeout=3 ) except infra.network.CodeIdNotFound as err: code_not_found_exception = err assert ( code_not_found_exception is not None ), "Adding node with unknown code id should fail" else: LOG.warning("Skipping unknown code id test with virtual enclave") return network
def test_add_node_with_bad_code(network, args): new_code_id = get_code_id( args.oe_binary, infra.path.build_lib_path(args.replacement_package, args.enclave_type), ) LOG.info(f"Adding a node with unsupported code id {new_code_id}") code_not_found_exception = None try: network.create_and_add_pending_node( args.replacement_package, "local://localhost", args, timeout=3 ) except infra.network.CodeIdNotFound as err: code_not_found_exception = err assert ( code_not_found_exception is not None ), f"Adding a node with unsupported code id {new_code_id} should fail" return network
def test_add_as_many_pending_nodes(network, args): # Should not change the raft consensus rules (i.e. majority) primary, _ = network.find_primary() number_new_nodes = len(network.nodes) LOG.info( f"Adding {number_new_nodes} pending nodes - consensus rules should not change" ) new_nodes = [ network.create_and_add_pending_node( args.package, "local://localhost", args, ) for _ in range(number_new_nodes) ] check_can_progress(primary) for new_node in new_nodes: network.consortium.retire_node(primary, new_node) network.nodes.remove(new_node) return network
def run(args): hosts = ["localhost", "localhost"] with infra.network.network(hosts, args.binary_dir, args.debug_nodes, args.perf_nodes, pdb=args.pdb) as network: network.start_and_join(args) primary, _ = network.find_nodes() first_code_id = get_code_id( infra.path.build_lib_path(args.package, args.enclave_type)) with primary.client() as uc: r = uc.get("/node/code") assert r.body.json() == { "versions": [{ "digest": first_code_id, "status": "ACCEPTED" }], }, r.body LOG.info("Adding a new node") new_node = network.create_and_trust_node(args.package, "localhost", args) assert new_node new_code_id = get_code_id( infra.path.build_lib_path(args.patched_file_name, args.enclave_type)) LOG.info(f"Adding a node with unsupported code id {new_code_id}") code_not_found_exception = None try: network.create_and_add_pending_node(args.patched_file_name, "localhost", args, timeout=3) except infra.network.CodeIdNotFound as err: code_not_found_exception = err assert ( code_not_found_exception is not None ), f"Adding a node with unsupported code id {new_code_id} should fail" # Slow quote verification means that any attempt to add a node may cause an election, so confirm primary after adding node primary, _ = network.find_primary() network.consortium.add_new_code(primary, new_code_id) with primary.client() as uc: r = uc.get("/node/code") versions = sorted(r.body.json()["versions"], key=lambda x: x["digest"]) expected = sorted( [ { "digest": first_code_id, "status": "ACCEPTED" }, { "digest": new_code_id, "status": "ACCEPTED" }, ], key=lambda x: x["digest"], ) assert versions == expected, versions new_nodes = set() old_nodes_count = len(network.nodes) new_nodes_count = old_nodes_count + 1 LOG.info( f"Adding more new nodes ({new_nodes_count}) than originally existed ({old_nodes_count})" ) for _ in range(0, new_nodes_count): new_node = network.create_and_trust_node(args.patched_file_name, "localhost", args) assert new_node new_nodes.add(new_node) LOG.info("Stopping all original nodes") old_nodes = set(network.nodes).difference(new_nodes) for node in old_nodes: LOG.debug(f"Stopping old node {node.node_id}") node.stop() new_primary, _ = network.wait_for_new_primary(primary.node_id) LOG.info(f"New_primary is {new_primary.node_id}") LOG.info("Adding another node to the network") new_node = network.create_and_trust_node(args.patched_file_name, "localhost", args) assert new_node network.wait_for_node_commit_sync(args.consensus) LOG.info("Remove first code id") network.consortium.retire_code(new_node, first_code_id) with new_node.client() as uc: r = uc.get("/node/code") versions = sorted(r.body.json()["versions"], key=lambda x: x["digest"]) expected = sorted( [ { "digest": first_code_id, "status": "RETIRED" }, { "digest": new_code_id, "status": "ACCEPTED" }, ], key=lambda x: x["digest"], ) assert versions == expected, versions LOG.info(f"Adding a node with retired code id {first_code_id}") code_not_found_exception = None try: network.create_and_add_pending_node(args.package, "localhost", args, timeout=3) except infra.network.CodeIdRetired as err: code_not_found_exception = err assert ( code_not_found_exception is not None ), f"Adding a node with unsupported code id {new_code_id} should fail" LOG.info("Adding another node with the new code to the network") new_node = network.create_and_trust_node(args.patched_file_name, "localhost", args) assert new_node network.wait_for_node_commit_sync(args.consensus)