def test_sending_requests_without_auth_token(controller_url: str): client_library = ClientLibrary(controller_url, username="******", password="******", ssl_verify=False, allow_http=True) # it probably won't be a common case to override `auth` by ClientLibrary users # but missing auth token may happen when using API directly via HTTP: client_library.session.auth = None with pytest.raises(requests.exceptions.HTTPError) as exc: client_library.create_lab() exc.match('401 Client Error: Unauthorized for url')
def test_server_node_deletion(client_library: ClientLibrary): lab = client_library.create_lab("lab_1") lab.auto_sync = False s1 = lab.create_node("s1", "server", 5, 100) s2 = lab.create_node("s2", "server", 102, 201) s1_iface = lab.create_interface(s1, 2) s2_iface = lab.create_interface(s2, 2) lab.create_link(s1_iface, s2_iface) lab.start() s3 = lab.create_node("s3", "server", 200, 400) s3_iface = lab.create_interface(s3) s2.stop() lab.create_link(s2.interfaces()[0], s3_iface) lab.start() # can't remove node while running with pytest.raises(requests.exceptions.HTTPError) as exc: lab.remove_node(s3) assert exc.value.response.status_code == 403 # need to stop and wipe to be able to remove node. s3.stop() s3.wipe() lab.remove_node(s3)
def test_lab_state(client_library: ClientLibrary): lab = client_library.create_lab("lab_1") s1 = lab.create_node("s1", "server", 5, 100) s2 = lab.create_node("s2", "server", 102, 201) s1_iface = lab.create_interface(s1, 2) s2_iface = lab.create_interface(s2, 2) lab.create_link(s1_iface, s2_iface) state = lab.state() assert state == "DEFINED_ON_CORE" lab.start() state = lab.state() assert state == "STARTED" assert lab.is_active() lab.stop() state = lab.state() assert state == "STOPPED" lab.wipe() state = lab.state() assert state == "DEFINED_ON_CORE"
def test_connect(client_library: ClientLibrary): lab = client_library.create_lab("my lab name") lab = client_library.join_existing_lab(lab.id) lab.auto_sync = False s1 = lab.create_node("s1", "server", 50, 100) s2 = lab.create_node("s2", "server", 50, 200) print(s1, s2) # create a link between s1 and s2 s1_i1 = s1.create_interface() s2_i1 = s2.create_interface() lab.create_link(s1_i1, s2_i1) # this must remove the link between s1 and s2 lab.remove_node(s2) lab.sync_states() for node in lab.nodes(): print(node, node.state) for iface in node.interfaces(): print(iface, iface.state) assert [link for link in lab.links() if link.state is not None] == []
def test_lab_details(client_library: ClientLibrary): lab = client_library.create_lab("lab_1") s1 = lab.create_node("s1", "server", 5, 100) s2 = lab.create_node("s2", "server", 102, 201) s1_iface = lab.create_interface(s1, 2) s2_iface = lab.create_interface(s2, 2) lab.create_link(s1_iface, s2_iface) expected_keys = ( "state", "created", "lab_title", "lab_description", "node_count", "link_count", "id", ) details = lab.details() assert all(k in details.keys() for k in expected_keys) assert details["node_count"] == 2 assert details["link_count"] == 1 assert details["state"] == "DEFINED_ON_CORE"
def test_node_with_unavailable_vnc(client_library: ClientLibrary): lab = client_library.create_lab("lab_111") node = lab.create_node("s1", "unmanaged_switch", 5, 100) lab.start() assert lab.state() == "STARTED" with pytest.raises(requests.exceptions.HTTPError) as err: node.vnc_key() assert err.value.response.status_code == 404
def test_link_conditioning(register_licensing, client_library_keep_labs: ClientLibrary): lab = client_library_keep_labs.create_lab() alpine = lab.create_node("alpine-0", "alpine", 0, 0) ums = lab.create_node("unmanaged-switch-0", "unmanaged_switch", 100, 0) ext = lab.create_node("ext", "external_connector", 200, 0) lab.connect_two_nodes(alpine, ums) lab.connect_two_nodes(ums, ext) lab.start(wait=True) alpine = lab.get_node_by_label("alpine-0") ums = lab.get_node_by_label("unmanaged-switch-0") link = lab.get_link_by_nodes(alpine, ums) pylab = ClPyats(lab) pylab.sync_testbed("cml2", "cml2cml2") # ensure there's no link condition result = link.get_condition() assert result is None # remove, just to be sure link.remove_condition() result = pylab.run_command("alpine-0", "time ping -Aqc100 192.168.255.1") check_result(result, False, 0.0, 10.0) # link.set_condition_by_name("dsl1") # 2mbps, 50ms delay, 0ms jitter, 5.1% loss) # 5.1 to ensure that the float is understood and returned link.set_condition(2000, 50, 0, 5.1) result = link.get_condition() assert result == { "bandwidth": 2000, "latency": 50, "loss": 5.1, "jitter": 0 } result = pylab.run_command("alpine-0", "time ping -Aqc100 192.168.255.1") check_result(result, True, 90.0, 110.0) link.remove_condition() result = pylab.run_command("alpine-0", "time ping -Aqc100 192.168.255.1") check_result(result, False, 0.0, 10.0) lab.stop() lab.wipe() lab.remove()
def test_sync_lab(register_licensing, client_library: ClientLibrary): lab = client_library.create_lab("my test lab name") lab = client_library.join_existing_lab(lab.id) r1 = lab.create_node("r1", "server", 5, 100) r2 = lab.create_node("r2", "server", 102, 201) r3 = lab.create_node("r3", "server", 200, 400) # print(r1, r2, r3) r1.x = 400 r1.label = "abc" r1_i1 = r1.create_interface() r1_i2 = r1.create_interface() r2_i1 = r2.create_interface() r2_i2 = r2.create_interface() r3_i1 = r3.create_interface() r3_i2 = r3.create_interface() # lab.create_link(r1_i1, r2_i1) lab.create_link(r2_i2, r3_i1) lab.create_link(r3_i2, r1_i2) r1.start() r2.start() r3.start() # lab.stop() r1.stop() r2.stop() r3.stop() # lab.remove_link(link_1) # lab.remove_link(link_2) # lab.remove_link(link_3) # lab.remove_node(r1) # lab.remove_node(r2) # lab.remove_node(r3) # TODO: wait for convergence here lab.stop()
def test_node_console_logs(client_library_session: ClientLibrary): lab = client_library_session.create_lab("lab_space") ext_conn = lab.create_node("ec", "external_connector", 100, 50, wait=False) server = lab.create_node("s1", "server", 100, 100) iosv = lab.create_node("n", "iosv", 50, 0) lab.start() assert lab.state() == "STARTED" # server has one serial console on id 0 logs = server.console_logs(console_id=0) assert type(logs) == str # external connector - no serial console with pytest.raises(requests.exceptions.HTTPError) as err: ext_conn.console_logs(console_id=0) assert err.value.response.status_code == 400 assert "Serial port does not exist on node" in err.value.response.text # test limited number of lines num_lines = 5 logs = server.console_logs(console_id=0, lines=num_lines) assert type(logs) == str assert len(logs.split("\n")) == num_lines # assert 400 for non existent console id for server >0 with pytest.raises(requests.exceptions.HTTPError) as err: server.console_logs(console_id=55) assert err.value.response.status_code == 400 assert "Serial port does not exist on node" in err.value.response.text # iosv has 2 serial consoles logs = iosv.console_logs(console_id=0) assert type(logs) == str logs = iosv.console_logs(console_id=1) assert type(logs) == str with pytest.raises(requests.exceptions.HTTPError) as err: iosv.console_logs(console_id=2) assert err.value.response.status_code == 400 assert "Serial port does not exist on node" in err.value.response.text lab.stop() lab.wipe() lab.remove()
class DSTTopology(object): __client = None __lab = None __started = False __wiped = True __base_config_dir = None __nodes = { "Internet Router": { "type": "iosv", "node": None, "config": "internet_router.txt" }, "HQ Firewall": { "type": "asav", "node": None, "config": "hq_firewall.txt" }, "HQ Switch": { "type": "unmanaged_switch", "node": None }, "HQ Server": { "type": "ubuntu", "node": None, "config": "hq_server.txt" }, "Internet": { "type": "external_connector", "node": None }, "OOB Management": { "type": "external_connector", "node": None, "config": "oob_management.txt" }, } def __init__(self, cml_controller, base_config_dir): self.__base_config_dir = base_config_dir ssl_cert = False if "CA_BUNDLE" in os.environ: ssl_cert = os.environ["CA_BUNDLE"] # Create a client and use the environment to provide the username, password, and CA bundle self.__client = ClientLibrary(cml_controller, ssl_verify=ssl_cert) @staticmethod def __get_lab_suffix(): return "".join( random.choice(string.ascii_lowercase + string.digits) for i in range(8)) def __create_lab(self): # Wait for the low-level drive to connect self.__client.wait_for_lld_connected() lab_prefix = "Dynamic Split Tunnel Test-" lab_suffix = DSTTopology.__get_lab_suffix() # Find a unique name for this lab while True: labs = self.__client.find_labs_by_title(lab_prefix + lab_suffix) if labs is not None and len(labs) > 0: lab_suffix = DSTTopology.__get_lab_suffix() else: break self.__lab = self.__client.create_lab(title=lab_prefix + lab_suffix) self.__lab.description = "This lab is for testing a Dynamic Split Tunnel config change (created at: {ctime})".format( ctime=time.ctime()) self.__lab.wait_for_convergence = False def __add_nodes(self): # Create each node for node in list(self.__nodes.keys()): self.__nodes[node]["node"] = self.__lab.create_node( node, self.__nodes[node]["type"], populate_interfaces=True) def __connect_nodes(self): """ Connect all nodes in the test topology is a known, static way. """ # First connect Gi0/0 of the Internet Router to the Internet igi0 = self.__nodes["Internet Router"]["node"].get_interface_by_label( "GigabitEthernet0/0") iport = self.__nodes["Internet"]["node"].get_interface_by_label("port") self.__lab.create_link(igi0, iport) # Next connect Gi0/1 of the Internet Router to Gi0/0 of the HQ Firewall igi1 = self.__nodes["Internet Router"]["node"].get_interface_by_label( "GigabitEthernet0/1") fgi0 = self.__nodes["HQ Firewall"]["node"].get_interface_by_label( "GigabitEthernet0/0") self.__lab.create_link(igi1, fgi0) # Next connect Gi0/1 of the HQ Firewall to port0 of the HQ Switch # ...But before we can do that, we need to add a new interface. self.__nodes["HQ Firewall"]["node"].create_interface() fgi1 = self.__nodes["HQ Firewall"]["node"].get_interface_by_label( "GigabitEthernet0/1") sport0 = self.__nodes["HQ Switch"]["node"].get_interface_by_label( "port0") self.__lab.create_link(fgi1, sport0) # Next connect Management0/0 of HQ Firewall to the OOB Management network fm0 = self.__nodes["HQ Firewall"]["node"].get_interface_by_label( "Management0/0") oport = self.__nodes["OOB Management"]["node"].get_interface_by_label( "port") self.__lab.create_link(fm0, oport) # Next connect port1 of HQ Switch to port enp0s2 of the HQ Server sport1 = self.__nodes["HQ Switch"]["node"].get_interface_by_label( "port1") seth = self.__nodes["HQ Server"]["node"].get_interface_by_label( "enp0s2") self.__lab.create_link(sport1, seth) def __configure_nodes(self): for node, properties in list(self.__nodes.items()): if "config" in properties: config = self.__base_config_dir + "/" + properties["config"] if not os.path.exists(config): raise FileNotFoundError(config) with open(config, "r") as fd: conf_contents = fd.read() properties["node"].config = conf_contents def create_topology(self): """ Create a DST test topology and configure it. """ self.__create_lab() self.__add_nodes() self.__connect_nodes() self.__configure_nodes() def start(self): """ Start the DST test lab. """ if self.__started: return self.__lab.start() self.__started = True self.__wiped = False def stop(self): """ Stop the DST test lab. """ if not self.__started: return self.__lab.stop(wait=True) self.__started = False def is_ready(self): """ Check if the overall lab is ready. Returns: Boolean: True if all nodes have converged, False otherwise. """ if not self.__started: raise Exception("Lab has not been started yet.") ready = True for node, properties in list(self.__nodes.items()): if not properties["node"].has_converged( ) or properties["node"].has_converged( ) == 0 or not properties["node"].is_booted(): ready = False break return ready def get_fw_ip(self, wait=False): """ Return the IP address of the OOB Management interface on the firewall node. Parameters: wait (Boolean): Whether or not to wait for the firewall node to converge (default: False) Returns: string: The first IP address on Management0/0 if found, else None """ if not self.__started: raise Exception("Lab has not been started yet.") if not wait and not self.__nodes["HQ Firewall"]["node"].has_converged( ): raise Exception("Firewall node has not yet converged.") elif not self.__nodes["HQ Firewall"]["node"].has_converged(): while not self.__nodes["HQ Firewall"]["node"].has_converged(): time.sleep(1) fm0 = self.__nodes["HQ Firewall"]["node"].get_interface_by_label( "Management0/0") ip4_addr = fm0.discovered_ipv4 if len(ip4_addr) > 0: return ip4_addr[0] return None def wipe(self): """ Wipe the DST test lab """ if self.__started: raise Exception("Lab must be stopped first.") self.__lab.wipe(wait=True) self.__wiped = True def remove(self): """ Remove the lab from the CML controller. """ if not self.__wiped: raise Exception("Lab must be wiped before it can be removed.") self.__lab.remove()
def test_group_api_permissions(controller_url, client_library_session: ClientLibrary): cl_admin = client_library_session # create non-admin user username = "******" satoshi_pwd = "super-secret-pwd" satoshi = cl_admin.user_management.create_user(username=username, pwd=satoshi_pwd) halfinn = cl_admin.user_management.create_user(username="******", pwd=satoshi_pwd) satoshi_uid = satoshi["id"] cml2_uid = client_library_session.user_management.user_id(username="******") halfinn_uid = client_library_session.user_management.user_id( username="******") # assert there is no lab assert cl_admin.all_labs(show_all=True) == [] # create lab lab0 = cl_admin.create_lab(title="lab0") lab1 = cl_admin.create_lab(title="lab1") # create students group lab0_ro = [{"id": lab0.id, "permission": "read_only"}] lab0_1_rw = [ { "id": lab0.id, "permission": "read_write" }, { "id": lab1.id, "permission": "read_write" }, ] students_group = cl_admin.group_management.create_group( name="students", description="students group", members=[satoshi_uid], labs=lab0_ro, ) teachers_group = cl_admin.group_management.create_group( name="teachers", description="teachers group", members=[], labs=lab0_1_rw) all_groups = cl_admin.group_management.groups() assert len(all_groups) == 2 all_groups_names = [group["id"] for group in all_groups] assert students_group["id"] in all_groups_names assert teachers_group["id"] in all_groups_names # log in as non-admin satoshi user cl_satoshi = ClientLibrary( controller_url, username=username, password=satoshi_pwd, ssl_verify=False, allow_http=True, ) # satoshi must only see groups that he is part of satoshi_groups = cl_satoshi.group_management.groups() assert len(satoshi_groups) == 1 assert satoshi_groups[0]["name"] == "students" assert cl_satoshi.user_management.user_groups(user_id=satoshi_uid) == [ students_group["id"] ] # cannot check other user info with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.user_management.user_groups(user_id=cml2_uid) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # user cannot see groups he is not part of with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.get_group(group_id=teachers_group["id"]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # can see those where he is member students_group = cl_satoshi.group_management.get_group( group_id=students_group["id"]) assert students_group["members"] == [satoshi_uid] # only admin can create, delete and modify group # create with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.create_group(name="xxx") assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # update with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.update_group(group_id=teachers_group["id"], description="new") assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # delete with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.delete_group(group_id=teachers_group["id"]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # user cannot see members of group that he is not part of with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.group_members( group_id=teachers_group["id"]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # can see those where he is member students_group_members = cl_satoshi.group_management.group_members( group_id=students_group["id"]) assert students_group_members == [satoshi_uid] # user cannot see labs of group that he is not part of with pytest.raises(requests.exceptions.HTTPError) as err: cl_satoshi.group_management.group_labs(group_id=teachers_group["id"]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # can see those where he is member students_group_labs = cl_satoshi.group_management.group_labs( group_id=students_group["id"]) assert students_group_labs == [lab0.id] # we need to get lab objects again so that they are bound to satoshi user lab0 = cl_satoshi.find_labs_by_title(title="lab0")[0] # satishi can only see groups where he is a member - in this case students assert lab0.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # we cannot modify groups associations as satoshi is not owner or admin with pytest.raises(requests.exceptions.HTTPError) as err: lab0.update_lab_groups(group_list=[]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # we cannot modify notes with pytest.raises(requests.exceptions.HTTPError) as err: lab0.notes = "new note" assert err.value.response.status_code == 403 assert "User does not have write permission to lab" in err.value.response.text # we cannot modify description with pytest.raises(requests.exceptions.HTTPError) as err: lab0.description = "new description" assert err.value.response.status_code == 403 assert "User does not have write permission to lab" in err.value.response.text # change students association to lab0 to read_write assert cl_admin.group_management.update_group( group_id=students_group["id"], labs=[{ "id": lab0.id, "permission": "read_write" }], ) # now user can perform writes to associated lab lab0.notes = "new note" assert lab0.notes == "new note" lab0.description = "new description" assert lab0.description == "new description" # get students groups association to lab0 back to read only # satoshi cannot - he is not admin or owner with pytest.raises(requests.exceptions.HTTPError) as err: lab0.update_lab_groups(group_list=[ { "id": students_group["id"], "permission": "read_only" }, ]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # admin can lab0 = cl_admin.find_labs_by_title(title="lab0")[0] lab0.update_lab_groups(group_list=[ { "id": students_group["id"], "permission": "read_only" }, ]) lab0 = cl_satoshi.find_labs_by_title(title="lab0")[0] assert lab0.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # add teachers group rw association to lab0 (admin action) teachers_group = cl_admin.group_management.update_group( group_id=teachers_group["id"], labs=lab0_1_rw) # we cannot modify groups associations as satoshi is not admin or owner with pytest.raises(requests.exceptions.HTTPError) as err: lab0.update_lab_groups(group_list=[]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # we cannot modify notes with pytest.raises(requests.exceptions.HTTPError) as err: lab0.notes = "new note" assert err.value.response.status_code == 403 assert "User does not have write permission to lab" in err.value.response.text # we cannot modify description with pytest.raises(requests.exceptions.HTTPError) as err: lab0.description = "new description" assert err.value.response.status_code == 403 assert "User does not have write permission to lab" in err.value.response.text # as satoshi has no access to lab1 - below list is empty assert cl_satoshi.find_labs_by_title(title="lab1") == [] # add satoshi to teachers group - by doing this now he gains read write # access to both ;ab0 and lab1 cl_admin.group_management.update_group(group_id=teachers_group["id"], members=[satoshi_uid]) # now we can access teachers group and related data assert cl_satoshi.group_management.get_group(group_id=teachers_group["id"]) assert cl_satoshi.group_management.group_members( group_id=teachers_group["id"]) == [satoshi_uid] assert (len( cl_satoshi.group_management.group_labs( group_id=teachers_group["id"])) == 2) user_groups = cl_satoshi.user_management.user_groups(user_id=satoshi_uid) assert students_group["id"] in user_groups and teachers_group[ "id"] in user_groups associated_groups_names = [ group["name"] for group in cl_satoshi.group_management.groups() ] assert ("students" in associated_groups_names and "teachers" in associated_groups_names) # test adjusting lab groups (only owner and admin can change lab group associations) # admin must see all associations # owner and non-admin users can only see those associations where they are members of group # log in as non-admin satoshi user cl_halfinn = ClientLibrary( controller_url, username="******", password=satoshi_pwd, ssl_verify=False, allow_http=True, ) # create lab owned by halfin lab2 = cl_halfinn.create_lab(title="lab2") # only satoshi in students group + add lab2 association cl_admin.group_management.update_group( group_id=students_group["id"], members=[satoshi_uid], labs=[{ "id": lab2.id, "permission": "read_only" }], ) # only halfinney in teachers group + add lab2 association cl_admin.group_management.update_group( group_id=teachers_group["id"], members=[halfinn_uid], labs=[{ "id": lab2.id, "permission": "read_only" }], ) halfinn_lab2 = cl_halfinn.find_labs_by_title(title="lab2")[0] # get lab owned by halfinney with satoshi (who is not owner) satoshi_lab2 = cl_satoshi.find_labs_by_title(title="lab2")[0] # get lab owned by halfinney with admin admin_lab2 = cl_admin.find_labs_by_title(title="lab2")[0] # admin must see both groups associated with lab2 assert admin_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ] # halfinney only sees group that he is member of (teachers) assert halfinn_lab2.groups == [ { "id": teachers_group["id"], "permission": "read_only" }, ] # satoshi only sees group that he is member of (students) assert satoshi_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # satoshi cannot update lab groups associations for lab2 -> 403 (not owner or admin) with pytest.raises(requests.exceptions.HTTPError) as err: satoshi_lab2.update_lab_groups(group_list=[]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # associations mus still be present after above failure assert admin_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ] # halfinney cannot add/remove students association to lab2 as he is not member of students halfinn_lab2.update_lab_groups(group_list=[]) # above only removed the group teachers as halfinn is owner and also member of teachers assert halfinn_lab2.groups == [] # sees nothing assert satoshi_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # sees students assert admin_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # admin too sees only students as that is now only associtation # halfinney cannot add students group as he is not member with pytest.raises(requests.exceptions.HTTPError) as err: halfinn_lab2.update_lab_groups(group_list=[{ "id": students_group["id"], "permission": "read_only" }]) assert err.value.response.status_code == 403 assert "User does not have required access" in err.value.response.text # halfinney can add teachers as he is a member halfinn_lab2.update_lab_groups(group_list=[{ "id": teachers_group["id"], "permission": "read_only" }]) # halfinney only sees group that he is member of (teachers) assert halfinn_lab2.groups == [ { "id": teachers_group["id"], "permission": "read_only" }, ] # add halfinney to students group cl_admin.group_management.update_group( group_id=students_group["id"], members=[satoshi_uid, halfinn_uid], ) # halfinney now sees both students and teachers # associations mus still be present after above failure assert halfinn_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ] # he can now also remove both associations halfinn_lab2.update_lab_groups(group_list=[]) assert admin_lab2.groups == [] assert halfinn_lab2.groups == [] # satoshi lost access --> 404 with pytest.raises(requests.exceptions.HTTPError) as err: assert satoshi_lab2.groups == [] assert err.value.response.status_code == 404 assert "Lab not found" in err.value.response.text # add also possible halfinn_lab2.update_lab_groups(group_list=[ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ]) assert halfinn_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ] assert satoshi_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, ] # sees students as he is only part of students not teachers assert admin_lab2.groups == [ { "id": students_group["id"], "permission": "read_only" }, { "id": teachers_group["id"], "permission": "read_only" }, ] # admin can do whatever he pleases admin_lab2.update_lab_groups(group_list=[]) assert admin_lab2.groups == [] assert halfinn_lab2.groups == [] # satoshi lost access --> 404 with pytest.raises(requests.exceptions.HTTPError) as err: assert satoshi_lab2.groups == [] assert err.value.response.status_code == 404 assert "Lab not found" in err.value.response.text # CLEAN UP # again need to get lab0 from admin account lab0 = cl_admin.find_labs_by_title(title="lab0")[0] lab0.remove() lab1.remove() lab2.remove() cl_admin.user_management.delete_user(user_id=satoshi_uid) cl_admin.user_management.delete_user(user_id=halfinn_uid) assert cl_admin.group_management.delete_group( group_id=students_group["id"]) is None assert cl_admin.group_management.delete_group( group_id=teachers_group["id"]) is None assert cl_admin.group_management.groups() == [] assert cl_admin.all_labs(show_all=True) == []
def test_topology_owner(client_library_keep_labs: ClientLibrary): lab = client_library_keep_labs.create_lab("owned_by_cml2") lab.sync(topology_only=True) assert lab.owner == "cml2"
def test_links_on_various_slots(client_library: ClientLibrary): """ Creating a link between two nodes on higher interfaces, then removing the link and re-adding a link on lower interfaces. """ lab = client_library.create_lab() s1 = lab.create_node("s1", "server", 50, 100) s2 = lab.create_node("s2", "server", 50, 200) assert s1.interfaces() == [] assert s2.interfaces() == [] # create a link between s1 and s2 s1_i1 = s1.create_interface(slot=4) s2_i1 = s2.create_interface(slot=4) assert len(s1.interfaces()) == 5 assert len(s2.interfaces()) == 5 link = lab.create_link(s1_i1, s2_i1) assert link.interface_a.slot == 4 assert link.interface_b.slot == 4 lab.remove_link(link) # verify that removing the link doesn't delete interfaces: assert len(s1.interfaces()) == 5 assert len(s2.interfaces()) == 5 # create a link between s1 and s2 on lower slot than before s1_i1 = s1.create_interface(slot=0) s2_i1 = s2.create_interface(slot=0) link = lab.create_link(s1_i1, s2_i1) assert link.interface_a.slot == 0 assert link.interface_b.slot == 0 assert list(lab._interfaces.keys()) == [ "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", "i9", ] assert [ifc.label for ifc in lab.interfaces()] == [ "eth0", "eth1", "eth2", "eth3", "eth4", "eth0", "eth1", "eth2", "eth3", "eth4", ] # create a link between s1 and s2, again on the 4th slot s1_i1 = s1.create_interface(slot=4) s2_i1 = s2.create_interface(slot=4) link = lab.create_link(s1_i1, s2_i1) assert link.interface_a.slot == 4 assert link.interface_b.slot == 4 lab.remove_link(link)
def test_create_client_lab(client_library: ClientLibrary): lab = client_library.create_lab() lab.auto_sync = False print("Created lab {}".format(lab.id)) # using server nodes, not IOSv nodes as they are not available # without a reference platform ISO attached r1 = lab.create_node("r1", "server", 5, 100) r2 = lab.create_node("r2", "server", 102, 201) r3 = lab.create_node("r3", "server", 200, 400) print(r1, r2, r3) r1_i1 = r1.create_interface() r1_i2 = r1.create_interface() print(r1_i1, r1_i2) r2_i1 = r2.create_interface() r2_i2 = r2.create_interface() r3_i1 = r3.create_interface() r3_i2 = r3.create_interface() link_1 = lab.create_link(r1_i1, r2_i1) link_2 = lab.create_link(r2_i2, r3_i1) link_3 = lab.create_link(r3_i2, r1_i2) # r1.config = "test" # r2.x = 50 # r2.y = 200 # # r1.start() # r2.start() # r3.start() # r1.stop() # r2.stop() # r3.stop() r1.label = "r1_test" # lab.remove_node(r1) lab.remove_link(link_1) lab.remove_link(link_2) lab.remove_link(link_3) lab.remove_node(r1) lab.remove_node(r2) lab.remove_node(r3) lab.sync_states() for node in lab.nodes(): print(node, node.state) for iface in node.interfaces(): print(iface, iface.state) for link in lab.links(): print(link, link.state) # lab.remove() # print("clear lab") # lab.clear() # print("remove lab") # events = lab.sync_events() # for event in lab.events: # print(event) # lab.wait_until_lab_converged() lab.remove()
ssl_verify=False, raise_for_auth_failure=True, allow_http=True) log.info("LOGGING INFO: Successfully connected with CML through the API") # Read in the config file config_files = os.listdir(path='./config') config_files = [file for file in config_files if ".txt" in file] log.info("LOGGING INFO: Successfully read in the config files") routers = [] for file in config_files: routers.append(file[:-4]) # Create a new lab in CML lab = client.create_lab(title=LAB_TITLE) log.info("LOGGING INFO: Successfully created the lab in CML") # Create the nodes in the lab coordinates = [(0, 0), (200, 0), (200, 200), (0, 200)] coordinates_counter = 0 for router in routers: x, y = coordinates[coordinates_counter] lab.create_node(label=router, node_definition='csr1000v', populate_interfaces=8, x=x, y=y) coordinates_counter += 1 log.info("LOGGING INFO: Successfully created the nodes in the lab")
# cl.licensing.licensing.set_transport(ssms=ssms, proxy_server="172.16.1.100", proxy_port=8888) cl.licensing.set_transport(ssms=SSMS) cl.licensing.install_certificate(cert=CERT) # 'register_wait' method waits max 45s for registration status to become COMPLETED # and another 45s for authorization status to become IN_COMPLIANCE cl.licensing.register_wait(token=TOKEN) lab_list = cl.get_lab_list() for lab_id in lab_list: lab = cl.join_existing_lab(lab_id) lab.stop() lab.wipe() cl.remove_lab(lab_id) lab = cl.create_lab() lab = cl.join_existing_lab(lab_id="lab_1") s1 = lab.create_node("s1", "server", 50, 100) s2 = lab.create_node("s2", "server", 50, 200) print(s1, s2) # create a link between s1 and s2, equivalent to # s1_i1 = s1.create_interface() # s2_i1 = s2.create_interface() # lab.create_link(s1_i1, s2_i1) lab.connect_two_nodes(s1, s2) # this must remove the link between s1 and s2 lab.remove_node(s2)
def test_user_role_change(controller_url, client_library_session: ClientLibrary): cl_admin = client_library_session cl_admin_uid = client_library_session.user_management.user_id( cl_admin.username) # create non admin users cl_user1, cl_user2 = "cl_user1", "cl_user2" password = "******" res = cl_admin.user_management.create_user(username=cl_user1, pwd=password) cl_user1_uid = res["id"] res = cl_admin.user_management.create_user(username=cl_user2, pwd=password) cl_user2_uid = res["id"] cl_user1 = ClientLibrary( controller_url, username=cl_user1, password=password, ssl_verify=False, allow_http=True, ) cl_user2 = ClientLibrary( controller_url, username=cl_user2, password=password, ssl_verify=False, allow_http=True, ) cl_user1.create_lab("lab1-cl_user1") cl_user1.create_lab("lab2-cl_user1") assert cl_user2.all_labs(show_all=True) == [] # promote cl_user2 to admin cl_admin.user_management.update_user(user_id=cl_user2_uid, admin=True) # check if cl_user2 can see all the labs as admin all_labs = cl_user2.all_labs(show_all=True) assert len(all_labs) == 2 assert all_labs[0].owner == cl_user1_uid # check if cl_user2 can create user and delete users res = cl_user2.user_management.create_user(username="******", pwd=password) assert cl_user2.user_management.get_user(user_id=res["id"]) cl_user2.user_management.delete_user(user_id=res["id"]) with pytest.raises(requests.exceptions.HTTPError) as err: cl_user2.user_management.get_user(user_id=res["id"]) assert err.value.response.status_code == 404 # check cl_user2 can see licensing assert cl_user2.licensing.status() for lab in all_labs: cl_user2.remove_lab(lab.id) assert cl_user2.all_labs(show_all=True) == [] # promote cl_user1 to admin cl_admin.user_management.update_user(user_id=cl_user1_uid, admin=True) # check if cl_user1 can remove admin cl_user2 cl_user1.user_management.delete_user(user_id=cl_user2_uid) with pytest.raises(requests.exceptions.HTTPError) as err: cl_user1.user_management.get_user(user_id=cl_user2_uid) assert err.value.response.status_code == 404 # remove admin rights from cl_user1 cl_admin.user_management.update_user(user_id=cl_user1_uid, admin=False) lab = cl_admin.create_lab("origin-lab") assert cl_user1.all_labs(show_all=True) == [] with pytest.raises(requests.exceptions.HTTPError) as err: cl_user1.user_management.create_user(username="******", pwd=password) assert err.value.response.status_code == 403 with pytest.raises(requests.exceptions.HTTPError) as err: cl_user1.licensing.status() assert err.value.response.status_code == 403 cl_admin.user_management.delete_user(user_id=cl_user1_uid) # check that user cannot update its own user role with pytest.raises(requests.exceptions.HTTPError) as err: cl_admin.user_management.update_user(user_id=cl_admin_uid, admin=False) assert err.value.response.status_code == 400 # cleanup cl_admin.remove_lab(lab.id)
def test_topology_owner(client_library_session: ClientLibrary): cml2_uid = client_library_session.user_management.user_id("cml2") lab = client_library_session.create_lab("owned_by_cml2") lab.sync(topology_only=True) assert lab.owner == cml2_uid lab.remove()
if 'programmatic_network_build' in [lab.title for lab in all_labs]: print(f"\nprogrammatic_network_build exists, deleting lab..") lab = client.find_labs_by_title(title='programmatic_network_build')[0] try: lab.stop() lab.wipe() lab.remove() except Exception as e: print(f"Unable to stop programmatic_network_build lab, error: {e}") print(f"\nprogrammatic_network_build has been successfully deleted..") print(f"\nprogrammatic_network_build doesn't exist, creating lab..") # create new programmatic_network_build lab try: lab = client.create_lab(title='programmatic_network_build') # create nodes print(f"\nCreating nodes..") spine1 = lab.create_node("spine1", "iosv", 300, 100, populate_interfaces=True) spine2 = lab.create_node("spine2", "iosv", 500, 100, populate_interfaces=True) leaf1 = lab.create_node("leaf1", "iosv", 0, 300, populate_interfaces=True) leaf2 = lab.create_node("leaf2",
class virlModule(object): def __init__(self, module, function=None): self.module = module self.params = module.params self.result = dict(changed=False) self.headers = dict() self.function = function self.cookies = None self.json = None self.method = None self.path = None self.response = None self.status = None self.url = None self.params['force_basic_auth'] = True self.user = self.params['user'] self.password = self.params['password'] self.host = self.params['host'] self.timeout = self.params['timeout'] self.modifiable_methods = ['POST', 'PUT', 'DELETE'] self.client = None self.login() def login(self): self.client = ClientLibrary('https://{0}'.format(self.host), self.user, self.password, ssl_verify=False) def get_lab_by_name(self, name): for lab in self.client.all_labs(): if lab.name == name: return lab return None def get_node_by_name(self, lab, name): for node in lab.nodes(): if node.label == name: return node return None def get_lab_by_id(self, id): try: lab = self.client.join_existing_lab(id, sync_lab=True) except: lab = None return lab def create_lab(self, name): lab = self.client.create_lab(name=name) lab.set_title(name) lab.sync() return lab def exit_json(self, **kwargs): self.result.update(**kwargs) self.module.exit_json(**self.result) def fail_json(self, msg, **kwargs): self.result.update(**kwargs) self.module.fail_json(msg=msg, **self.result)