def check(self): try: network = ConfigObj(self.netfile) except ConfigObjError as err: raise NetemError("Syntax error in the network file: %s" % err) # first, be sure we can record images and configs image_dir = os.path.join( os.path.dirname(self.netfile), network["config"]["image_dir"]) config_dir = os.path.join( os.path.dirname(self.netfile), network["config"]["config_dir"]) for path in (image_dir, config_dir): if not os.path.isdir(path): os.mkdir(path) # check network files before start it errors = check_network(network, self.daemon) if len(errors) > 0: msg = "" for e_mod in errors: err_msg = "\n\t".join(errors[e_mod]["errors"]) msg += "%s:\n\t%s\n" % (errors[e_mod]["desc"], err_msg) raise NetemError("The network file has errors\n %s" % msg) return network
def handle(self): cmd = self.request.recv(1024).decode("utf-8").strip() logging.debug("Receive data: %s" % cmd) msg = "" try: cmd_args = cmd.split() if len(cmd_args) < 1: raise NetemError("The sent command is empty") cmd_name = cmd_args[0] if cmd_name not in CMD_LIST: raise NetemError("Unknown command %s" % cmd) cmd_regexp = CMD_LIST[cmd_name] # verify arguments match_obj = re.match(cmd_regexp, cmd) if match_obj is None: raise NetemError("Wrong number of args for " "command %s" % cmd_name) # execute command ret = getattr(self, cmd_name)(*match_obj.groups()) except NetemError as err: msg = "%s" % err except Exception: logging.error(get_exc_desc()) msg = "Unknown exception happen see log for details" else: msg = "OK" if ret is not None: msg += " %s" % ret self.request.sendall(msg.encode("utf-8"))
def do_copy(self, source, dest): def get_path_type(p): docker_re = r"^(\w+):([^\0]+)$" args = re.match(docker_re, p) if args is None: return "host", None, p else: return "docker", args.group(1), args.group(2) def get_node(name): node = self.project.topology.get_node(name) if node is None: raise NetemError("Node {} does not exist".format(name)) elif node.get_type() != "node.docker": raise NetemError("Copy cmd works only with docker nodes") return node s_type, s_name, s_path = get_path_type(source) d_type, d_name, d_path = get_path_type(dest) if s_type == d_type: raise NetemError("Can not do copy {0}/{0}".format(s_type)) if s_type == "docker": # d_type = host node = get_node(s_name) node.source_copy(s_path, d_path) else: # s_type = host if not os.path.exists(s_path): raise NetemError("Host path {} does not exist".format(d_path)) node = get_node(d_name) node.dest_copy(s_path, d_path)
def get_node(name): node = self.project.topology.get_node(name) if node is None: raise NetemError("Node {} does not exist".format(name)) elif node.get_type() != "node.docker": raise NetemError("Copy cmd works only with docker nodes") return node
async def __send_rpc_cmd(self, cmd_name, args=[]): request = RPCRequest(cmd_name, args) loop = asyncio.get_running_loop() on_answer = loop.create_future() transport, _ = await loop.create_connection( lambda: NetemClientProtocol(request, self.__on_signal, on_answer), "127.0.0.1", self.s_port, ) result = await on_answer transport.close() if result is None: raise NetemError("No valid answer has been received from server") elif result["state"] == "error": raise NetemError(result["content"]) elif result["state"] == "interrupt": # command has been interrupt by user self.pwarning( "Running command {} has been interrupt".format(cmd_name) ) return None return result["content"]
def build_node_instance(prj_id, p2p_sw, img_dir, conf_dir, n_name, n_config): logging.debug("Create node instance %s" % n_name) if "type" in n_config: nc_type = n_config["type"].split('.', 1) n_type, n_image = "qemu", None if len(nc_type) == 1: n_image = nc_type[0] elif len(nc_type) == 2: n_type, n_image = nc_type else: raise NetemError("type args for node %s has wrong format" % n_name) # create instance based on type field if n_type == "qemu": return QEMUInstance(p2p_sw, prj_id, img_dir, n_image, n_name, n_config) if n_type == "junos": return JunosInstance(p2p_sw, prj_id, conf_dir, n_image, n_name, n_config) if n_type == "docker": try: return DOCKER_NODES[n_image](p2p_sw, prj_id, conf_dir, n_name, n_config) except KeyError: raise NetemError("docker image %s does not exist" % n_image) raise NetemError("Type is not specified for %s" % n_name)
def test_project(prj_path): _, ext = os.path.splitext(prj_path) if ext.lower() != ".pnet": raise NetemError("Project %s has wrong ext" % prj_path) if not os.path.isfile(prj_path): raise NetemError("Project %s does not exist" % prj_path) if not zipfile.is_zipfile(prj_path): raise NetemError("Project %s is not a zip file" % prj_path)
def _command(self, cmd_line, check_output=True, shell=False): args = shlex.split(cmd_line) try: return subprocess.run(args, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) except subprocess.CalledProcessError as err: msg = "%s --> %s" % (err.cmd, err.stderr) raise NetemError(msg) except FileNotFoundError as err: raise NetemError(str(err))
def docker_pull(image_name): client = docker.from_env() try: client.images.pull(image_name) except docker.errors.APIError as ex: raise NetemError("Unable to pull {} image: {}".format( image_name, ex))
def build_sw_instance(prj_id, sw_name, sw_config): logging.debug("Create switch instance %s" % sw_name) try: sw_type = sw_config["type"] s_inst = SWITCH_CLASSES[sw_type](prj_id, sw_name, sw_config) except KeyError: raise NetemError("Wrong switch type for %s" % sw_name) return s_inst
def save(self, conf_file): try: tn = telnetlib.Telnet("localhost", port=self.port, timeout=5) except (ConnectionRefusedError, TimeoutError): raise NetemError("Unable to connect to %s router" % self.name) if not self.logout(tn): raise NetemError("Unable to save %s router, perhaps you forget to " "commit your configuration" % self.name) self.login(tn, self.name.encode("ascii")) tn.write(b"configure\n") with open(conf_file, "bw") as hd: tn.write(b"save terminal\n") data = tn.read_until(b"Wrote") hd.write(self.__format_conf(data)) tn.close()
def cmd_run_app(cmd_line): args = shlex.split(cmd_line) try: return subprocess.Popen(args, shell=False, env={"DISPLAY": get_x11_env()}) except FileNotFoundError as err: raise NetemError(str(err))
def run_command(cmd_line, check_output=False, shell=False): args = shlex.split(cmd_line) if check_output: try: result = subprocess.check_output(args, shell=shell) except subprocess.CalledProcessError: msg = "Unable to execute command %s" % (cmd_line, ) logging.error(msg) raise NetemError(msg) except FileNotFoundError as err: raise NetemError(str(err)) return result.decode("utf-8").strip("\n") else: ret = subprocess.call(args, shell=shell) if ret != 0: msg = "Unable to excecute command %s" % (cmd_line, ) logging.error(msg) raise NetemError(msg)
def cmd_func(self, *args): logging.debug("Call daemon command: %s -> %s" % (cmd, args)) if len(args) != nb_args: raise NetemError("Wrong number of arguments for cmd %s" % cmd) cmd_line = "%s %s" % (cmd, " ".join(args)) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: sock.connect(self.socket_path) except socket.error as err: raise NetemError("Unable to connect to daemon: %s" % err) sock.sendall(cmd_line.encode("utf-8")) ans = sock.recv(1024).decode("utf-8").strip() sock.close() if not ans.startswith("OK"): raise NetemError("Daemon returns an error:\n\t%s" % ans) return ans.replace("OK ", "")
def set_if_state(self, if_number, state): if len(self.interfaces) > if_number: if_entry = self.interfaces[if_number] if_name = if_entry["target_if"] self._docker_exec("ip link set {} {}".format(if_name, state)) if_entry["state"] = state else: raise NetemError("%s: interface %d does not " "exist" % (self.name, if_number))
def __get_node_if(self, if_id): if_ids = if_id.rsplit(".", 1) if len(if_ids) == 2: node_id, if_number = if_ids node = self.get_node(node_id) if node is None: raise NetemError("Node %s does not exist" % node_id) try: if_number = int(if_number) except (TypeError, ValueError): raise NetemError( "%s is not a correct interface identifier" % if_number ) else: raise NetemError( "if_name must follow the syntax <host>.<if_number>" ) return node, if_number
def ifdown(cls, if_name): logging.debug("Ifdown %s" % if_name) with IPDB() as ipdb: if if_name not in ipdb.interfaces: raise NetemError("interface %s does not exist" % if_name) # be sure that host if is UP if_obj = ipdb.interfaces[if_name] if if_obj.operstate == 'UP': if_obj.freeze() if_obj.down().commit() if_obj.unfreeze()
def stop(self): if self.is_started: self.is_started = False self.watch_thread.join() try: self.process.terminate() self.process.wait() except OSError as e: raise NetemError("Unable to stop %s -> %s" % (self.name, e)) finally: self.process = None self.watch_thread = None
def capture(self, if_number): if not shutil.which("wireshark"): raise NetemError( "Unable to start capture -> Wireshark is not installed on" " your computer") if len(self.interfaces) <= if_number: raise NetemError("%s: interface %d does not " "exist" % (self.name, if_number)) if_name = "eth%s" % if_number if CAPTURE_PROCESS == "daemon": # capture is launch by the daemon display = get_x11_env() self.daemon.docker_capture(display, self.container_name, if_name) else: # user cmd = "/bin/bash -c 'docker exec {0} tcpdump -s 0 -U -w - -i {1} "\ "2>/dev/null | wireshark -o 'gui.window_title:{1}@{2}' "\ "-k -i - &'".format(self.container_name, if_name, self.name) cmd_run_app(cmd)
def loads_request(request, **kws): err = NetemError("Malformed request") try: unmarshalled = json.loads(request, **kws) except ValueError: raise err if (isinstance(unmarshalled, dict)): for key in ("method", "params", "id"): if key not in unmarshalled: raise err return unmarshalled raise err
def loads_response(response, **kws): err = NetemError("Malformed response") try: unmarshalled = json.loads(response, **kws) except ValueError: raise err if (isinstance(unmarshalled, dict)): for key in ("type", "id"): if key not in unmarshalled: raise err return unmarshalled raise err
def __init__(self, daemon, netid, prj_path): self.__id = netid self.daemon = daemon self.prj_path = prj_path self.tmp_folder = tempfile.mkdtemp(prefix=netid) with zipfile.ZipFile(prj_path) as prj_zip: prj_zip.extractall(path=self.tmp_folder) # init topology topology_file = os.path.join(self.tmp_folder, TOPOLOGY_FILE) if not os.path.isfile(topology_file): raise NetemError("Project %s does not contain " "a topology file" % prj_path) self.topology = TopologyManager(self.__id, topology_file, daemon)
def open_shell(self, bash=False): if self.shell_process is not None \ and self.shell_process.poll() is None: raise NetemError("The console is already opened") term_cmd = NetemConfig.instance().get("general", "terminal") % { "title": self.name, "cmd": "telnet localhost %d" % self.telnet_port, } args = shlex.split(term_cmd) self.shell_process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
def capture(self, if_number): if len(self.interfaces) > if_number: if if_number in self.capture_processes: process = self.capture_processes[if_number] if process.poll() is None: raise NetemError("Capture process is already running") w_options = "-o 'gui.window_title:{}.{}'".format( self.name, if_number) if_obj = self.interfaces[if_number] if if_obj["peer"] == "switch" \ and if_obj["peer_instance"] is not None: sw_type = if_obj["peer_instance"].get_type() if sw_type == "switch.ovs": if_name = if_obj["tap"] elif sw_type == "switch.vde": if_name = if_obj["peer_instance"].get_tap_name() if if_name is None: raise NetemError("Unable to launch capture, no tap" "if exists on this switch") cmd_ln = shlex.split("wireshark -k %s -i %s" % (w_options, if_name)) self.capture_processes[if_number] = subprocess.Popen(cmd_ln) elif if_obj["peer"] in ("bridge", "node"): if_name = if_obj["tap"] cmd_ln = shlex.split("wireshark -k %s -i %s" % (w_options, if_name)) self.capture_processes[if_number] = subprocess.Popen(cmd_ln) else: raise NetemError("%s: interface %d is not " "plugged" % (self.name, if_number)) else: raise NetemError("%s: interface %d does not " "exist" % (self.name, if_number))
def docker_shell(cls, c_name, name, shell, display, term_cmd): logging.debug("Docker open shell for container %s" % c_name) term_cmd = term_cmd % { "title": name, "cmd": "docker exec -it %s %s" % (c_name, shell) } args = shlex.split(term_cmd) try: subprocess.Popen(args, shell=False, env={ "DISPLAY": display, "HOME": "/root" }) except FileNotFoundError as err: raise NetemError(str(err))
def cmd_func(self, *args, **kwargs): # test args if len(cmd_args) != len(args): raise NetemError("Wrong number of arguments") # run original func return func(self, *args, **kwargs)
def do_config(self, conf_path): conf_path = os.path.abspath(conf_path) if not os.path.isdir(conf_path): raise NetemError("%s is not a valid path" % conf_path) self.project.save_config(conf_path)
def set_if_state(self, if_number, state): raise NetemError("ifstate command is not supported for qemu nodes.")
def __open_shell(self, node_id, bash): nodes = self.__get_nodes(node_id) if len(nodes) == 0: raise NetemError("Node '%s' does not exist" % node_id) for node in nodes: node.open_shell(bash=bash)
def chown(host_path, uid, gid): logging.debug("chown %s:%s %s" % (uid, gid, host_path)) if not os.path.exists(host_path): raise NetemError("Path %s does not exist" % host_path) cmd = "chown -R %s:%s \"%s\"" % (uid, gid, host_path) run_command(cmd)