def __init__(self, remote_system: RemoteSystem, link_iface_name='eth0'): """ Creats a VLAN and a Namespace for the specific RemoteSystem(Router,PowerStrip) and 'eth0' as the link-interface. The VLAN will be encapsulate in the Namespace. Also the a SSHClient will be created. :param remote_system: Could e a Router or a powerstrip object """ Logger().info("Create Network Controller ...", 1) self.remote_system = remote_system # TODO: ausgelagert in NVAssisten. soll beides aber in Zukunft gelöscht/ausgelagert werden ''' self.vlan = Vlan(link_iface_name, router.vlan_iface_name, router.vlan_iface_id, vlan_iface_ip=None, vlan_iface_ip_mask=None) self.vlan.create_interface() self.namespace = Namespace(self.router.namespace_name, self.vlan.ipdb) self.namespace.encapsulate_interface(self.vlan.vlan_iface_name) ''' self.nv_assisten = NVAssistent() self.nv_assisten.create_namespace_vlan(str(self.remote_system.namespace_name), link_iface_name, str(self.remote_system.vlan_iface_name), int(self.remote_system.vlan_iface_id)) self.ssh = paramiko.SSHClient()
def test_setup_expert(self): """ This UnitTest executes the wca_setup_expert-function with the given config-file. It sets the values of all the from WebInterface of the Router. """ print("Test if the 'wca_setup_expert'-function is working") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # Config config = ConfigManager().get_web_interface_list()[router.id] self.assertEqual(len(config), 30, "Wrong size of the Config-Directory") self.assertEqual(config["node_name"], "64293-testframework1", "Wrong Node_name") print("Set the following configuration: \n" + str(config)) router_web_config = RouterWebConfiguration(router, config, wizard=False) router_web_config.start() router_web_config.join() assert router.mode == Mode.configuration nv_assist.close()
def _reboot_into_normal(self, router: Router, q: Queue): print("Reboot Router back into normalmode ...") nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) router_reboot = RouterReboot(router, configmode=False) router_reboot.start() router_reboot.join() assert router.mode == Mode.normal nv_assist.close() q.put(router)
def test_setup_expert(self): """ This UnitTest executes the wca_setup_expert-function with the given config-file. It sets the values of all the from WebInterface of the Router. """ print("Test if the 'wca_setup_wizard'-function is working") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) try: # Config config = ConfigManager.get_web_interface_list()[router.id] self.assertEqual(len(config), 30, "Wrong size of the Config-Directory") print("Set the following configuration: \n" + str(config)) router_web_config = RouterWebConfiguration(router, config, wizard=True) router_web_config.start() router_web_config.join() except Exception as e: nv_assist.close() raise e assert router.mode == Mode.normal nv_assist.close()
def _reboot_into_config(self, router: Router, q: Queue): print("Reboot Router into configmode ...") # Create NVAssistent nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # Reboot Router into configmode router_reboot = RouterReboot(router, configmode=True) router_reboot.start() router_reboot.join() assert router.mode == Mode.configuration nv_assist.close() q.put(router)
def __init__(self, remote_system: RemoteSystem, link_iface_name="eth0"): """ Creats a VLAN and a Namespace for the specific RemoteSystem(Router,PowerStrip) and 'eth0' as the link-interface. The VLAN will be encapsulate in the Namespace. Also the a SSHClient will be created. :param remote_system: Could e a Router or a powerstrip object """ Logger().info("Create Network Controller ...", 1) self.remote_system = remote_system # TODO: ausgelagert in NVAssisten. soll beides aber in Zukunft gelöscht/ausgelagert werden """ self.vlan = Vlan(link_iface_name, router.vlan_iface_name, router.vlan_iface_id, vlan_iface_ip=None, vlan_iface_ip_mask=None) self.vlan.create_interface() self.namespace = Namespace(self.router.namespace_name, self.vlan.ipdb) self.namespace.encapsulate_interface(self.vlan.vlan_iface_name) """ self.nv_assisten = NVAssistent() self.nv_assisten.create_namespace_vlan( str(self.remote_system.namespace_name), link_iface_name, str(self.remote_system.vlan_iface_name), int(self.remote_system.vlan_iface_id), ) self.ssh = paramiko.SSHClient()
def test_flash_firmware(self): print("Test Router_Flash_Firmware") router = self._create_router() print("Download/Import firmware-image from UpdateServer/PI ...") # Download firmare-image from UpdateServer sysupdate = Sysupdate(router) sysupdate.start() sysupdate.join() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # The IP where the Router can download the firmware image (should be the frameworks IP) web_server_ip = nv_assist.get_ip_address(router.namespace_name, router.vlan_iface_name)[0] try: # Copy firmware-image to the Router (/tmp/image) print("Copy firmware-image to Router ...") sysupgrade = Sysupgrade(router, n=True, web_server_ip=web_server_ip, debug=True) sysupgrade.start() sysupgrade.join() except Exception: raise finally: nv_assist.close()
def test_router_info(self): print("Test Router_Info") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) print("Get informations via ssh-commands ...") router_info = RouterInfo(router) router_info.start() router_info.join() print(str(router)) # Close Namespaces and VLANs nv_assist.close()
def setUpClass(cls): cls.router = cls._create_router() # NVAssisten cls.nv_assist = NVAssistent("eth0") cls.nv_assist.create_namespace_vlan(cls.router) # Set netns for the current process netns.setns(cls.router.namespace_name) # Create NetworkCrtl cls.network_ctrl = NetworkCtrl(cls.router) assert isinstance(cls.network_ctrl, NetworkCtrl)
def test_create_namespace_vlan_veth(self): router = self._create_router() print("Test NVAssistent ...") for i in range(0, 2): print("Test" + str(i)) nv_assi = NVAssistent("eth0") assert isinstance(nv_assi, NVAssistent) nv_assi.create_namespace_vlan(router) # Test if the Namespace now exists process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE) stdout, sterr = process.communicate() assert sterr.decode('utf-8') == "" assert router.namespace_name in stdout.decode('utf-8') # Test if the VLAN now in Namespace exists process = Popen([ "ip", "netns", "exec", router.namespace_name, "ip", "link", "show", "dev", router.vlan_iface_name ], stdout=PIPE, stderr=PIPE) stdout, sterr = process.communicate() assert sterr.decode('utf-8') == "" assert router.vlan_iface_name in stdout.decode('utf-8') nv_assi.close()
def _reboot_into_normal(self, router: Router, q: Queue): print("Reboot Router back into normalmode ...") nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) try: router_reboot = RouterReboot(router, configmode=False) router_reboot.start() router_reboot.join() except Exception as e: nv_assist.close() raise e assert router.mode == Mode.normal nv_assist.close() q.put(router)
def test_create_namespace_vlan_veth(self): router = self._create_router() print("Test NVAssistent ...") for i in range(0, 2): print("Test" + str(i)) nv_assi = NVAssistent("eth0") assert isinstance(nv_assi, NVAssistent) nv_assi.create_namespace_vlan(router) # Test if the Namespace now exists process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE) stdout, sterr = process.communicate() assert sterr.decode('utf-8') == "" assert router.namespace_name in stdout.decode('utf-8') # Test if the VLAN now in Namespace exists process = Popen(["ip", "netns", "exec", router.namespace_name, "ip", "link", "show", "dev", router.vlan_iface_name], stdout=PIPE, stderr=PIPE) stdout, sterr = process.communicate() assert sterr.decode('utf-8') == "" assert router.vlan_iface_name in stdout.decode('utf-8') nv_assi.close()
def _power_off(self, ps: Ubnt, q: Queue, port: int): nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(ps) netns.setns(ps.namespace_name) power_on = PowerStripControl(self.router, ps, False, port) power_on.start() power_on.join() nv_assist.close() q.put(ps)
def _reboot_into_config(self, router: Router, q: Queue): print("Reboot Router into configmode ...") # Create NVAssistent nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) # Reboot Router into configmode try: router_reboot = RouterReboot(router, configmode=True) router_reboot.start() router_reboot.join() except Exception as e: nv_assist.close() raise e assert router.mode == Mode.configuration nv_assist.close() q.put(router)
def test_router_online(self): print("Test if the Router is reachable") router = self._create_router() # NVAssisten nv_assist = NVAssistent("eth0") nv_assist.create_namespace_vlan(router) # Set netns for the current process netns.setns(router.namespace_name) print("Send a Ping to the two static IP-addresses ...") router_online = RouterOnline(router) router_online.start() router_online.join() print("Router is online with IP " + router.ip + "/" + str(router.ip_mask)) self.assertEqual(router.mode, Mode.configuration, "The Configuration Mode is not correct") # Close Namespaces and VLANs nv_assist.close()
class NetworkCtrl: """ The NetworkCtrl manages: 1. Creates a Vlan and a Namespace 2. Encapsulates the Vlan inside the Namespace 3. Provides a SSH-Connection via paramiko 4. Provides a WebServer 5. Provides a Web_configuration_Assistent """ def __init__(self, remote_system: RemoteSystem, link_iface_name="eth0"): """ Creats a VLAN and a Namespace for the specific RemoteSystem(Router,PowerStrip) and 'eth0' as the link-interface. The VLAN will be encapsulate in the Namespace. Also the a SSHClient will be created. :param remote_system: Could e a Router or a powerstrip object """ Logger().info("Create Network Controller ...", 1) self.remote_system = remote_system # TODO: ausgelagert in NVAssisten. soll beides aber in Zukunft gelöscht/ausgelagert werden """ self.vlan = Vlan(link_iface_name, router.vlan_iface_name, router.vlan_iface_id, vlan_iface_ip=None, vlan_iface_ip_mask=None) self.vlan.create_interface() self.namespace = Namespace(self.router.namespace_name, self.vlan.ipdb) self.namespace.encapsulate_interface(self.vlan.vlan_iface_name) """ self.nv_assisten = NVAssistent() self.nv_assisten.create_namespace_vlan( str(self.remote_system.namespace_name), link_iface_name, str(self.remote_system.vlan_iface_name), int(self.remote_system.vlan_iface_id), ) self.ssh = paramiko.SSHClient() def connect_with_remote_system(self): """ Connects to the remote_system via SSH(Paramiko). Ignores a missing signatur. """ Logger().info("Connect with RemoteSystem ...", 1) try: self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.ssh.connect( str(self.remote_system.ip), port=22, username=str(self.remote_system.usr_name), password=str(self.remote_system.usr_password), ) Logger().debug("[+] Successfully connected", 2) except Exception as e: Logger().error("[-] Couldn't connect", 2) Logger().error("" + str(e), 1) def send_command(self, command) -> str: """ Sends the given command via SSH to the RemoteSystem. :param command: like "ping 8.8.8.8" :return: The output of the command given by the RemoteSystem """ try: stdin, stdout, stderr = self.ssh.exec_command(command) output = stdout.readlines() Logger().debug("[+] Sent the command (" + command + ") to the RemoteSystem", 2) return str(output) except Exception as e: Logger().error("[-] Couldn't send the command (" + command + ")", 2) raise e def send_data(self, local_file: str, remote_file: str): """ Sends Data via sftp to the RemoteSystem :param local_file: Path to the local file :param remote_file: Path on the Router, where the file should be saved """ try: # TODO: If sftp is installed on the Router """ sftp = self.ssh.open_sftp() sftp.put(local_file, remote_file) sftp.close() """ command = ( "sshpass -p" + str(self.remote_system.usr_password) + " scp " + local_file + " " + str(self.remote_system.usr_name) + "@" + str(self.remote_system.ip) + ":" + remote_file ) os.system(command) # TODO: Paramiko_scp have to installed """ scp = SCPClient(self.ssh.get_transport()) scp.put(local_file, remote_file) """ Logger().debug( "[+] Sent data '" + local_file + "' to RemoteSystem '" + str(self.remote_system.usr_name) + "@" + str(self.remote_system.ip) + ":" + remote_file + "'", 2, ) except Exception as e: Logger().error( "[-] Couldn't send '" + local_file + "' to RemoteSystem '" + str(self.remote_system.usr_name) + "@" + str(self.remote_system.ip) + ":" + remote_file + "'", 2, ) Logger().error(str(e), 2) def remote_system_wget(self, file: str, remote_path: str): """ The RemoteSystem downloads the file from the PI and stores it at remote_file :param file: like /root/TestFramework/firmware/.../<firmware>.bin :param remote_path: like /tmp/ """ try: webserver = WebServer() webserver.start() # Proves first if file already exists self.send_command( "test -f /" + remote_path + "/" + file.split("/")[-1] + " || wget http://" + self.nv_assisten.namespace.get_ip_of_encapsulate_interface() + ":" + str(WebServer.PORT_WEBSERVER) + file.replace(WebServer.BASE_DIR, "") + " -P " + remote_path ) webserver.join() except Exception as e: Logger().error(str(e), 2) def wca_setup_wizard(self, config): """ Starts the WebConfigurationAssist and sets the values provided by the wizard-mode (in the WebConfiguration) :param config: {node_name, mesh_vpn, limit_bandwidth, show_location, latitude, longitude, altitude, contact,...} """ try: # remote_sytem has to be a router object wca = WebConfigurationAssist(config, self.remote_system) wca.setup_wizard() wca.exit() except Exception as e: Logger().error(str(e), 2) self.exit() raise e def wca_setup_expert(self, config): """ Starts the WebConfigurationAssist and sets the values provided by the expert-mode(in the WebConfiguration) :param config: {node_name, mesh_vpn, limit_bandwidth, show_location, latitude, longitude, altitude, contact,...} """ try: # remote_sytem has to be a router object wca = WebConfigurationAssist(config, self.remote_system) wca.setup_expert_private_wlan() wca.setup_expert_remote_access() wca.setup_expert_network() wca.setup_expert_mesh_vpn() wca.setup_expert_wlan() wca.setup_expert_autoupdate() wca.exit() except Exception as e: Logger().error(str(e), 2) self.exit() raise e def test_connection(self) -> bool: """ Sends a 'Ping' to the RemoteSystem :return: """ output = os.system("ping -c 1 " + str(self.remote_system.ip)) if not output: return True else: return False def exit(self): """ Delete the VLAN resp. the Namespace with the VLAN """ Logger().info("Close Network Controller ...", 1) self.nv_assisten.delete_namespace()
def start(cls, config_path: str = CONFIG_PATH) -> None: """ Starts the runtime server with all components :param config_path: Path to an alternative config directory """ # server has to be run with root rights - except on travis CI if not os.geteuid() == 0 and not os.environ.get('TRAVIS'): sys.exit('Script must be run as root') cls.CONFIG_PATH = config_path # set the config_path at the manager ConfigManager.set_config_path(config_path) # read from config the Vlan mode vlan_activate = ConfigManager.get_server_property("Vlan_On") cls.VLAN = vlan_activate # read from config if debug mode is on log_level = int(ConfigManager.get_server_property("Log_Level")) debug_mode = False if log_level is 10: debug_mode = True cls.DEBUG = debug_mode cls._server_stop_event = Event() cls._pid = os.getpid() # create instance and give params to the logger object LoggerSetup.setup(log_level) # load Router configs cls.__load_configuration() for router in cls.get_routers(): cls._running_task.append(None) cls._waiting_tasks.append(deque()) # start thread for multiprocess stop wait t = threading.Thread(target=cls._close_wait) t.start() # start process/thread pool for job and test handling cls._max_subprocesses = (len(cls._routers) + 2) cls._task_pool = Pool(processes=cls._max_subprocesses, initializer=init_process, initargs=(cls._server_stop_event, ), maxtasksperchild=1) cls._job_wait_executor = ThreadPoolExecutor( max_workers=(cls._max_subprocesses + 5)) # add Namespace and Vlan for each Router if cls.VLAN: cls._nv_assistent = NVAssistent("eth0") for router in cls.get_routers(): logging.debug("Add Namespace and Vlan for Router(" + str(router.id) + ")") cls._nv_assistent.create_namespace_vlan(router) # add Namespace and Vlan for 1 Powerstrip (expand to more if necessary) logging.debug("Add Namespace and Vlan for Powerstrip") cls._nv_assistent.create_namespace_vlan(cls.get_power_strip()) # update Router cls.router_online(None, update_all=True, blocked=True) cls.update_router_info(None, update_all=True) logging.info("Runtime Server started") try: cls._ipc_server.start_ipc_server( cls, True) # serves forever - works like a while(true) except (KeyboardInterrupt, SystemExit): logging.info("Received an interrupt signal") cls.stop()
class NetworkCtrl: """ The NetworkCtrl manages: 1. Creates a Vlan and a Namespace 2. Encapsulates the Vlan inside the Namespace 3. Provides a SSH-Connection via paramiko 4. Provides a WebServer """ def __init__(self, remote_system: RemoteSystem, link_iface_name='eth0'): """ Creats a VLAN and a Namespace for the specific RemoteSystem(Router,PowerStrip) and 'eth0' as the link-interface. The VLAN will be encapsulate in the Namespace. Also the a SSHClient will be created. :param remote_system: Could e a Router or a powerstrip object """ Logger().info("Create Network Controller ...", 1) self.remote_system = remote_system # TODO: ausgelagert in NVAssisten. soll beides aber in Zukunft gelöscht/ausgelagert werden ''' self.vlan = Vlan(link_iface_name, router.vlan_iface_name, router.vlan_iface_id, vlan_iface_ip=None, vlan_iface_ip_mask=None) self.vlan.create_interface() self.namespace = Namespace(self.router.namespace_name, self.vlan.ipdb) self.namespace.encapsulate_interface(self.vlan.vlan_iface_name) ''' self.nv_assisten = NVAssistent() self.nv_assisten.create_namespace_vlan(str(self.remote_system.namespace_name), link_iface_name, str(self.remote_system.vlan_iface_name), int(self.remote_system.vlan_iface_id)) self.ssh = paramiko.SSHClient() def connect_with_remote_system(self): """ Connects to the remote_system via SSH(Paramiko). Ignores a missing signatur. """ Logger().info("Connect with RemoteSystem ...", 1) try: self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.ssh.connect(str(self.remote_system.ip), port=22, username=str(self.remote_system.usr_name), password=str(self.remote_system.usr_password)) Logger().debug("[+] Successfully connected", 2) except Exception as e: Logger().error("[-] Couldn't connect", 2) Logger().error("" + str(e), 1) def send_command(self, command) -> str: """ Sends the given command via SSH to the RemoteSystem. :param command: like "ping 8.8.8.8" :return: The output of the command given by the RemoteSystem """ try: stdin, stdout, stderr = self.ssh.exec_command(command) output = stdout.readlines() Logger().debug("[+] Sent the command (" + command + ") to the RemoteSystem", 2) return str(output) except Exception as e: Logger().error("[-] Couldn't send the command (" + command + ")", 2) raise e def send_data(self, local_file: str, remote_file: str): """ Sends Data via sftp to the RemoteSystem :param local_file: Path to the local file :param remote_file: Path on the Router, where the file should be saved """ try: # TODO: If sftp is installed on the Router ''' sftp = self.ssh.open_sftp() sftp.put(local_file, remote_file) sftp.close() ''' command = 'sshpass -p' + str(self.remote_system.usr_password) + ' scp ' + local_file + ' ' + \ str(self.remote_system.usr_name) + '@' + str(self.remote_system.ip) + ':' + remote_file os.system(command) # TODO: Paramiko_scp have to installed ''' scp = SCPClient(self.ssh.get_transport()) scp.put(local_file, remote_file) ''' Logger().debug("[+] Sent data '" + local_file + "' to RemoteSystem '" + str(self.remote_system.usr_name) + "@" + str(self.remote_system.ip) + ":" + remote_file + "'", 2) except Exception as e: Logger().error("[-] Couldn't send '" + local_file + "' to RemoteSystem '" + str(self.remote_system.usr_name) + "@" + str(self.remote_system.ip) + ":" + remote_file + "'", 2) Logger().error(str(e), 2) def remote_system_wget(self, file: str, remote_path: str): """ The RemoteSystem downloads the file from the PI and stores it at remote_file :param file: like /root/TestFramework/firmware/.../<firmware>.bin :param remote_path: like /tmp/ """ try: webserver = WebServer() webserver.start() # Proves first if file already exists self.send_command('test -f /' + remote_path + '/' + file.split('/')[-1] + ' || wget http://' + self.nv_assisten.namespace.get_ip_of_encapsulate_interface() + ':' + str(WebServer.PORT_WEBSERVER) + file.replace(WebServer.BASE_DIR, '') + ' -P ' + remote_path) webserver.join() except Exception as e: Logger().error(str(e), 2) def test_connection(self) -> bool: """ Sends a 'Ping' to the RemoteSystem :return: """ output = os.system("ping -c 1 " + str(self.remote_system.ip)) if not output: return True else: return False def exit(self): """ Delete the VLAN resp. the Namespace with the VLAN """ Logger().info("Close Network Controller ...", 1) self.nv_assisten.delete_namespace()