Beispiel #1
0
    def __init__(self, log_ctl):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        port = lnst_config.get_option("environment", "rpcport")
        logging.info("Using RPC port %d." % port)
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)

        self._server_handler.set_if_manager(self._if_manager)

        self._net_namespaces = {}

        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager, self._net_namespaces,
                                     self._server_handler, self)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())
Beispiel #2
0
    def init_if_manager(self):
        self._if_manager = InterfaceManager(self._server_handler)
        for cls_name in dir(Devices):
            cls = getattr(Devices, cls_name)
            if isclass(cls):
                self._if_manager.add_device_class(cls_name, cls)

        self._if_manager.rescan_devices()
        self._server_handler.set_if_manager(self._if_manager)
        return True
Beispiel #3
0
    def init_if_manager(self):
        self._if_manager = InterfaceManager(self._server_handler)
        for cls_name in dir(Devices):
            cls = getattr(Devices, cls_name)
            if isclass(cls):
                self._if_manager.add_device_class(cls_name, cls)

        self._if_manager.rescan_devices()
        self._server_handler.set_if_manager(self._if_manager)
        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())
        return True
Beispiel #4
0
    def __init__(self, log_ctl):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        port = lnst_config.get_option("environment", "rpcport")
        logging.info("Using RPC port %d." % port)
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)

        self._net_namespaces = {}

        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager, self._net_namespaces,
                                     self._server_handler, self)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())
Beispiel #5
0
    def __init__(self, log_ctl, port=DefaultRPCPort):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)

        self._net_namespaces = {}

        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager, self._net_namespaces,
                                     self._server_handler, self)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())
Beispiel #6
0
    def __init__(self, log_ctl, port = DefaultRPCPort):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)
        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())
Beispiel #7
0
class SlaveMethods:
    '''
    Exported xmlrpc methods
    '''
    def __init__(self, job_context, log_ctl, net_namespaces,
                 server_handler, slave_config, slave_server):
        self._packet_captures = {}
        self._if_manager = None
        self._job_context = job_context
        self._log_ctl = log_ctl
        self._net_namespaces = net_namespaces
        self._server_handler = server_handler
        self._slave_server = slave_server
        self._slave_config = slave_config

        self._capture_files = {}
        self._copy_targets = {}
        self._copy_sources = {}
        self._system_config = {}

        self._cache = ResourceCache(slave_config.get_option("cache", "dir"),
                        slave_config.get_option("cache", "expiration_period"))

        self._dynamic_modules = {}
        self._dynamic_classes = {}
        self._dynamic_objects = {}

    def hello(self):
        logging.info("Recieved a controller connection.")

        slave_desc = {}
        if check_process_running("NetworkManager"):
            slave_desc["nm_running"] = True
        else:
            slave_desc["nm_running"] = False

        k_release, _ = exec_cmd("uname -r", False, False, False)
        r_release, _ = exec_cmd("cat /etc/redhat-release", False, False, False)
        slave_desc["kernel_release"] = k_release.strip()
        slave_desc["redhat_release"] = r_release.strip()
        slave_desc["lnst_version"] = lnst_version

        return ("hello", slave_desc)

    def prepare_machine(self):
        self.machine_cleanup()

        self._cache.del_old_entries()
        self.reset_file_transfers()
        return True

    def start_recipe(self, recipe_name):
        date = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")
        self._log_ctl.set_recipe(recipe_name, expand=date)
        sleep(1)

        if check_process_running("NetworkManager"):
            logging.warning("=============================================")
            logging.warning("NetworkManager is running on a slave machine!")
            logging.warning("=============================================")

        for device in self._if_manager.get_devices():
            try:
                device.store_cleanup_data()
            except DeviceDisabled:
                pass

        return True

    def bye(self):
        self.restore_system_config()
        self._cache.del_old_entries()
        self.reset_file_transfers()
        self._remove_capture_files()
        return "bye"

    def map_device_class(self, cls_name, module_name):
        if cls_name in self._dynamic_classes:
            return

        module = self._dynamic_modules[module_name]
        cls = getattr(module, cls_name)

        self._dynamic_classes["{}.{}".format(module_name, cls_name)] = cls

        setattr(Devices, cls_name, cls)

    def load_cached_module(self, module_name, res_hash):
        self._cache.renew_entry(res_hash)
        if module_name in self._dynamic_modules:
            return
        module_path = self._cache.get_path(res_hash)
        module = imp.load_source(module_name, module_path)
        self._dynamic_modules[module_name] = module

    def init_cls(self, cls_name, module_name, args, kwargs):
        module = self._dynamic_modules[module_name]
        cls = getattr(module, cls_name)

        self._dynamic_classes["{}.{}".format(module_name, cls_name)] = cls

        new_obj = cls(*args, **kwargs)
        self._dynamic_objects[id(new_obj)] = new_obj
        return id(new_obj)

    def init_if_manager(self):
        self._if_manager = InterfaceManager(self._server_handler)
        for cls_name in dir(Devices):
            cls = getattr(Devices, cls_name)
            if isclass(cls):
                self._if_manager.add_device_class(cls_name, cls)

        self._if_manager.rescan_devices()
        self._server_handler.set_if_manager(self._if_manager)
        return True

    def obj_method(self, obj_ref, name, args, kwargs):
        try:
            obj = self._dynamic_objects[obj_ref]
            method = getattr(obj, name)
            return method(*args, **kwargs)
        except LnstError:
            raise
        except Exception as exc:
            log_exc_traceback()
            raise LnstError(exc)

    def obj_getattr(self, obj_ref, name):
        try:
            obj = self._dynamic_objects[obj_ref]
            return getattr(obj, name)
        except LnstError:
            raise
        except Exception as exc:
            log_exc_traceback()
            raise LnstError(exc)

    def obj_setattr(self, obj_ref, name, value):
        try:
            obj = self._dynamic_objects[obj_ref]
            return setattr(obj, name, value)
        except LnstError:
            raise
        except Exception as exc:
            log_exc_traceback()
            raise LnstError(exc)

    def dev_method(self, ifindex, name, args, kwargs):
        dev = self._if_manager.get_device(ifindex)
        method = getattr(dev, name)

        return method(*args, **kwargs)

    def dev_getattr(self, ifindex, name):
        dev = self._if_manager.get_device(ifindex)
        return getattr(dev, name)

    def dev_setattr(self, ifindex, name, value):
        dev = self._if_manager.get_device(ifindex)
        return setattr(dev, name, value)

    def get_devices(self):
        devices = self._if_manager.get_devices()
        result = {}
        for device in devices:
            result[device.ifindex] = device._get_if_data()
        return result

    def get_device(self, ifindex):
        device = self._if_manager.get_device(ifindex)
        if device:
            return device._get_if_data()
        else:
            return None

    def get_devices_by_devname(self, devname):
        name_scan = self._if_manager.get_devices()
        netdevs = []

        for entry in name_scan:
            if entry["name"] == devname:
                netdevs.append(entry)
        return netdevs

    def get_devices_by_hwaddr(self, hwaddr):
        devices = self._if_manager.get_devices()
        matched = []
        for dev in devices:
            if dev.get_hwaddr() == hwaddr:
                entry = {"name": dev.get_name(),
                         "hwaddr": dev.get_hwaddr()}
                matched.append(entry)
        return matched

    def get_devices_by_params(self, params):
        devices = self._if_manager.get_devices()
        matched = []
        for dev in devices:
            dev_data = dev._get_if_data()
            entry = {"name": dev.get_name(),
                     "hwaddr": dev.get_hwaddr()}
            for key, value in params.items():
                if key not in dev_data or dev_data[key] != value:
                    entry = None
                    break

            if entry is not None:
                matched.append(entry)
        return matched

    def destroy_devices(self):
        if self._if_manager is None:
            return

        devices = self._if_manager.get_devices()
        for dev in devices:
            try:
                dev.destroy()
            except (DeviceDisabled, DeviceDeleted, DeviceConfigValueError):
                pass
            self._if_manager.rescan_devices()

    # def add_route(self, if_id, dest):
        # dev = self._if_manager.get_mapped_device(if_id)
        # if dev is None:
            # logging.error("Device with id '%s' not found." % if_id)
            # return False
        # dev.add_route(dest)
        # return True

    # def del_route(self, if_id, dest):
        # dev = self._if_manager.get_mapped_device(if_id)
        # if dev is None:
            # logging.error("Device with id '%s' not found." % if_id)
            # return False
        # dev.del_route(dest)
        # return True

    def create_device(self, clsname, args=[], kwargs={}):
        dev =  self._if_manager.create_device(clsname, args, kwargs)
        return {"ifindex": dev.ifindex, "name": dev.name}

    def start_packet_capture(self, filt):
        if not is_installed("tcpdump"):
            raise Exception("Can't start packet capture, tcpdump not available")

        files = {}
        for if_id, dev in self._if_manager.get_mapped_devices().items():
            if dev.get_netns() != None:
                continue
            dev_name = dev.get_name()

            df_handle = NamedTemporaryFile(delete=False)
            dump_file = df_handle.name
            df_handle.close()

            files[if_id] = dump_file

            pcap = PacketCapture()
            pcap.set_interface(dev_name)
            pcap.set_output_file(dump_file)
            pcap.set_filter(filt)
            pcap.start()

            self._packet_captures[if_id] = pcap

        self._capture_files = files
        return files

    def stop_packet_capture(self):
        if self._packet_captures == None:
            return True

        for ifindex, pcap in self._packet_captures.items():
            pcap.stop()

        self._packet_captures.clear()

        return True

    def _remove_capture_files(self):
        for key, name in self._capture_files.items():
            logging.debug("Removing temporary packet capture file %s", name)
            os.unlink(name)

        self._capture_files.clear()

    def _update_system_config(self, options, persistent):
        system_config = self._system_config
        for opt in options:
            option = opt["name"]
            prev = opt["previous_val"]
            curr = opt["current_val"]

            if persistent:
                if option in system_config:
                    del system_config[option]
            else:
                if not option in system_config:
                    system_config[option] = {"initial_val": prev}
                system_config[option]["current_val"] = curr

    def restore_system_config(self):
        logging.info("Restoring system configuration")
        for option, values in self._system_config.items():
            try:
                cmd_str = "echo \"%s\" >%s" % (values["initial_val"], option)
                (stdout, stderr) = exec_cmd(cmd_str)
            except ExecCmdFail:
                logging.warn("Unable to restore '%s' config option!", option)
                return False

        self._system_config = {}
        return True

    def run_job(self, job):
        job_instance = Job(job, self._log_ctl)
        self._job_context.add_job(job_instance)

        res = job_instance.run()

        return res

    def kill_job(self, job_id, signal):
        job = self._job_context.get_job(job_id)

        if job is None:
            logging.error("No job %s found" % job_id)
            return False

        return job.kill(signal)

    def kill_jobs(self):
        logging.info("Killing all forked processes.")
        self._job_context.cleanup()
        return "Commands killed"

    def machine_cleanup(self):
        logging.info("Performing machine cleanup.")
        self._job_context.cleanup()

        self.restore_system_config()

        if self._if_manager is not None:
            self._if_manager.deconfigure_all()

        for netns in list(self._net_namespaces.keys()):
            self.del_namespace(netns)
        self._net_namespaces = {}

        for obj_id, obj in list(self._dynamic_objects.items()):
            del obj

        for cls_name in dir(Devices):
            cls = getattr(Devices, cls_name)
            if isclass(cls):
                delattr(Devices, cls_name)

        for module_name, module in list(self._dynamic_modules.items()):
            del sys.modules[module_name]

        self._dynamic_objects = {}
        self._dynamic_classes = {}
        self._dynamic_modules = {}
        self._if_manager = None
        self._server_handler.set_if_manager(None)
        self._cache.del_old_entries()
        self._remove_capture_files()
        return True

    def has_resource(self, res_hash):
        if self._cache.query(res_hash):
            return True

        return False

    def add_resource_to_cache(self, res_type, local_path, name):
        if res_type == "file":
            self._cache.add_file_entry(local_path, name)
            return True
        else:
            raise Exception("Unknown resource type")

    def start_copy_to(self, filepath=None):
        if filepath in self._copy_targets:
            return ""

        if filepath:
            self._copy_targets[filepath] = open(filepath, "w+b")
        else:
            tmpfile = NamedTemporaryFile("w+b", delete=False)
            filepath = tmpfile.name
            self._copy_targets[filepath] = tmpfile

        return filepath

    def copy_part_to(self, filepath, data):
        if self._copy_targets[filepath]:
            self._copy_targets[filepath].write(data)
            return True

        return False

    def finish_copy_to(self, filepath):
        if self._copy_targets[filepath]:
            self._copy_targets[filepath].close()

            del self._copy_targets[filepath]
            return True

        return False

    def start_copy_from(self, filepath):
        if filepath in self._copy_sources or not os.path.exists(filepath):
            return False

        self._copy_sources[filepath] = open(filepath, "rb")
        return True

    def copy_part_from(self, filepath, buffsize):
        data = self._copy_sources[filepath].read(buffsize)
        return data

    def finish_copy_from(self, filepath):
        if filepath in self._copy_sources:
            self._copy_sources[filepath].close()
            del self._copy_sources[filepath]
            return True

        return False

    def reset_file_transfers(self):
        for file_handle in self._copy_targets.values():
            file_handle.close()
        self._copy_targets = {}

        for file_handle in self._copy_sources.values():
            file_handle.close()
        self._copy_sources = {}

    def add_namespace(self, netns):
        if netns in self._net_namespaces:
            logging.debug("Network namespace %s already exists." % netns)
        else:
            logging.debug("Creating network namespace %s." % netns)
            read_pipe, write_pipe = multiprocessing.Pipe()
            pid = os.fork()
            if pid != 0:
                self._net_namespaces[netns] = {"pid": pid,
                                               "pipe": read_pipe}
                self._server_handler.add_netns(netns, read_pipe)

                result = self._slave_server.wait_for_result(netns)
                if result["result"] != True:
                    raise Exception("Namespace creation failed")

                return True
            elif pid == 0:
                self._slave_server.set_netns_sighandlers()
                #create new network namespace
                libc_name = ctypes.util.find_library("c")
                #from sched.h
                CLONE_NEWNET = 0x40000000
                CLONE_NEWNS = 0x00020000
                #based on ipnetns.c from the iproute2 project
                MNT_DETACH = 0x00000002
                MS_BIND = 4096
                MS_SLAVE = 1<<19
                MS_REC = 16384
                libc = ctypes.CDLL(libc_name)

                #based on ipnetns.c from the iproute2 project
                #bind to named namespace
                netns_path = "/var/run/netns/"
                if not os.path.exists(netns_path):
                    os.mkdir(netns_path, stat.S_IRWXU | stat.S_IRGRP |
                                         stat.S_IXGRP | stat.S_IROTH |
                                         stat.S_IXOTH)
                netns_path = netns_path + netns
                f = os.open(netns_path, os.O_RDONLY | os.O_CREAT | os.O_EXCL, 0)
                os.close(f)
                libc.unshare(CLONE_NEWNET)
                libc.mount("/proc/self/ns/net", netns_path, "none", MS_BIND, 0)

                #map network sysfs to new net
                libc.unshare(CLONE_NEWNS)
                libc.mount("", "/", "none", MS_SLAVE | MS_REC, 0)
                libc.umount2("/sys", MNT_DETACH)
                libc.mount(netns, "/sys", "sysfs", 0, 0)

                #set ctl socket to pipe to main netns
                self._server_handler.close_s_sock()
                self._server_handler.close_c_sock()
                self._server_handler.clear_connections()
                self._server_handler.clear_netns_connections()

                self._server_handler.set_netns(netns)
                self._server_handler.set_ctl_sock((write_pipe, "root_netns"))

                self._log_ctl.disable_logging()
                self._log_ctl.set_origin_name(netns)
                self._log_ctl.set_connection(write_pipe)

                self.init_if_manager()

                logging.debug("Created network namespace %s" % netns)
                return True
            else:
                raise Exception("Fork failed!")

    def del_namespace(self, netns):
        if netns not in self._net_namespaces:
            logging.debug("Network namespace %s doesn't exist." % netns)
            return False
        else:
            MNT_DETACH = 0x00000002
            libc_name = ctypes.util.find_library("c")
            libc = ctypes.CDLL(libc_name)
            netns_path = "/var/run/netns/" + netns

            netns_pid = self._net_namespaces[netns]["pid"]
            os.kill(netns_pid, signal.SIGUSR1)
            os.waitpid(netns_pid, 0)

            # Remove named namespace
            try:
                libc.umount2(netns_path, MNT_DETACH)
                os.unlink(netns_path)
            except:
                logging.warning("Unable to remove named namespace %s." % netns_path)

            logging.debug("Network namespace %s removed." % netns)

            self._net_namespaces[netns]["pipe"].close()
            self._server_handler.del_netns(netns)
            del self._net_namespaces[netns]
            return True

    def set_dev_netns(self, dev, dst):
        exec_cmd("ip link set %s netns %s" % (dev.name, dst))
        self._if_manager.untrack_device(dev)
        dev._deleted = True
        self._if_manager.rescan_devices()
        #TODO check if device appeared in the destination namespace
        return True

    # def return_if_netns(self, if_id):
        # device = self._if_manager.get_mapped_device(if_id)
        # if device.get_netns() == None:
            # dev_name = device.get_name()
            # ppid = os.getppid()
            # exec_cmd("ip link set %s netns %d" % (dev_name, ppid))
            # self._if_manager.unmap_if(if_id)
            # return True
        # else:
            # netns = device.get_netns()
            # msg = {"type": "command", "method_name": "return_if_netns",
                   # "args": [if_id]}
            # self._server_handler.send_data_to_netns(netns, msg)
            # result = self._slave_server.wait_for_result(netns)
            # if result["result"] != True:
                # raise Exception("Return from netns failed.")

            # device.set_netns(None)
            # return True

    def add_br_vlan(self, if_id, br_vlan_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.add_vlan(br_vlan_info)
        return True

    def del_br_vlan(self, if_id, br_vlan_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.del_vlan(br_vlan_info)
        return True

    def get_br_vlans(self, if_id):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        return brt.get_vlans()

    def add_br_fdb(self, if_id, br_fdb_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.add_fdb(br_fdb_info)
        return True

    def del_br_fdb(self, if_id, br_fdb_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.del_fdb(br_fdb_info)
        return True

    def get_br_fdbs(self, if_id):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        return brt.get_fdbs()

    def set_br_learning(self, if_id, br_learning_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.set_learning(br_learning_info)
        return True

    def set_br_learning_sync(self, if_id, br_learning_sync_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.set_learning_sync(br_learning_sync_info)
        return True

    def set_br_flooding(self, if_id, br_flooding_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.set_flooding(br_flooding_info)
        return True

    def set_br_state(self, if_id, br_state_info):
        dev = self._if_manager.get_mapped_device(if_id)
        if not dev:
            logging.error("Device with id '%s' not found." % if_id)
            return False
        brt = BridgeTool(dev.get_name())
        brt.set_state(br_state_info)
        return True
Beispiel #8
0
class NetTestSlave:
    def __init__(self, log_ctl, port = DefaultRPCPort):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)
        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())

    def run(self):
        while not self._finished:
            if self._server_handler.get_ctl_sock() == None:
                self._log_ctl.cancel_connection()
                try:
                    logging.info("Waiting for connection.")
                    self._server_handler.accept_connection()
                except socket.error:
                    continue
                self._log_ctl.set_connection(
                                            self._server_handler.get_ctl_sock())

            msgs = self._server_handler.get_messages()

            for msg in msgs:
                self._process_msg(msg[1])

        self._methods.machine_cleanup()

    def _process_msg(self, msg):
        if msg["type"] == "command":
            method = getattr(self._methods, msg["method_name"], None)
            if method != None:
                try:
                    result = method(*msg["args"])
                except:
                    log_exc_traceback()
                    type, value, tb = sys.exc_info()
                    exc_trace = ''.join(traceback.format_exception(type,
                                                                   value, tb))
                    response = {"type": "exception", "Exception": value}

                    self._server_handler.send_data_to_ctl(response)
                    return

                if result != None:
                    response = {"type": "result", "result": result}
                    self._server_handler.send_data_to_ctl(response)
            else:
                err = "Method '%s' not supported." % msg["method_name"]
                response = {"type": "error", "err": err}
                self._server_handler.send_data_to_ctl(response)
        elif msg["type"] == "log":
            logger = logging.getLogger()
            record = logging.makeLogRecord(msg["record"])
            logger.handle(record)
        elif msg["type"] == "exception":
            if msg["cmd_id"] != None:
                logging.debug("Recieved an exception from command with id: %s"
                                % msg["cmd_id"])
            else:
                logging.debug("Recieved an exception from foreground command")
            logging.debug(msg["Exception"])
            cmd = self._cmd_context.get_cmd(msg["cmd_id"])
            cmd.join()
            self._cmd_context.del_cmd(cmd)
            self._server_handler.send_data_to_ctl(msg)
        elif msg["type"] == "result":
            if msg["cmd_id"] == None:
                del msg["cmd_id"]
                self._server_handler.send_data_to_ctl(msg)
                cmd = self._cmd_context.get_cmd(None)
                cmd.join()
                self._cmd_context.del_cmd(cmd)
            else:
                cmd = self._cmd_context.get_cmd(msg["cmd_id"])
                cmd.join()
                del msg["cmd_id"]

                cmd.set_result(msg["result"])
                if cmd.finished():
                    msg["result"] = cmd.get_result()
                    self._server_handler.send_data_to_ctl(msg)
                    self._cmd_context.del_cmd(cmd)
        elif msg["type"] == "netlink":
            self._if_manager.handle_netlink_msgs(msg["data"])
        else:
            raise Exception("Recieved unknown command")

        pipes = self._cmd_context.get_read_pipes()
        self._server_handler.update_connections(pipes)

    def register_die_signal(self, signum):
        signal.signal(signum, self._signal_die_handler)

    def _signal_die_handler(self, signum, frame):
        logging.info("Caught signal %d -> dying" % signum)
        self._finished = True
Beispiel #9
0
class NetTestSlave:
    def __init__(self, log_ctl):
        die_when_parent_die()

        self._cmd_context = NetTestCommandContext()
        port = lnst_config.get_option("environment", "rpcport")
        logging.info("Using RPC port %d." % port)
        self._server_handler = ServerHandler(("", port))
        self._if_manager = InterfaceManager(self._server_handler)

        self._server_handler.set_if_manager(self._if_manager)

        self._net_namespaces = {}

        self._methods = SlaveMethods(self._cmd_context, log_ctl,
                                     self._if_manager, self._net_namespaces,
                                     self._server_handler, self)

        self.register_die_signal(signal.SIGHUP)
        self.register_die_signal(signal.SIGINT)
        self.register_die_signal(signal.SIGTERM)

        self._finished = False

        self._log_ctl = log_ctl

        self._server_handler.add_connection('netlink',
                                            self._if_manager.get_nl_socket())

    def run(self):
        while not self._finished:
            if self._server_handler.get_ctl_sock() == None:
                self._log_ctl.cancel_connection()
                try:
                    logging.info("Waiting for connection.")
                    self._server_handler.accept_connection()
                except (socket.error, SecSocketException):
                    continue
                self._log_ctl.set_connection(
                    self._server_handler.get_ctl_sock())

            msgs = self._server_handler.get_messages()

            for msg in msgs:
                self._process_msg(msg[1])

        self._methods.machine_cleanup()

    def wait_for_result(self, id):
        result = None
        while result == None:
            msgs = self._server_handler.get_messages_from_con(id)
            for msg in msgs:
                if msg[1]["type"] == "result":
                    result = msg[1]
                elif msg[1]["type"] == "from_netns" and\
                     msg[1]["data"]["type"] == "result":
                    result = msg[1]["data"]
                else:
                    self._process_msg(msg[1])
        return result

    def _process_msg(self, msg):
        if msg["type"] == "command":
            method = getattr(self._methods, msg["method_name"], None)
            if method != None:
                try:
                    result = method(*msg["args"])
                except:
                    log_exc_traceback()
                    type, value, tb = sys.exc_info()
                    exc_trace = ''.join(
                        traceback.format_exception(type, value, tb))
                    response = {"type": "exception", "Exception": value}

                    self._server_handler.send_data_to_ctl(response)
                    return

                if result != None:
                    response = {"type": "result", "result": result}
                    self._server_handler.send_data_to_ctl(response)
            else:
                err = "Method '%s' not supported." % msg["method_name"]
                response = {"type": "error", "err": err}
                self._server_handler.send_data_to_ctl(response)
        elif msg["type"] == "log":
            logger = logging.getLogger()
            record = logging.makeLogRecord(msg["record"])
            logger.handle(record)
        elif msg["type"] == "exception":
            if msg["cmd_id"] != None:
                logging.debug(
                    "Recieved an exception from command with id: %s" %
                    msg["cmd_id"])
            else:
                logging.debug("Recieved an exception from foreground command")
            logging.debug(msg["Exception"])
            cmd = self._cmd_context.get_cmd(msg["cmd_id"])
            cmd.join()
            self._cmd_context.del_cmd(cmd)
            self._server_handler.send_data_to_ctl(msg)
        elif msg["type"] == "result":
            if msg["cmd_id"] == None:
                del msg["cmd_id"]
                self._server_handler.send_data_to_ctl(msg)
                cmd = self._cmd_context.get_cmd(None)
                cmd.join()
                cmd.set_result_sent()
            else:
                cmd = self._cmd_context.get_cmd(msg["cmd_id"])
                cmd.join()
                del msg["cmd_id"]

                cmd.set_result(msg["result"])
                if cmd.finished():
                    msg["result"] = cmd.get_result()
                    self._server_handler.send_data_to_ctl(msg)
                    cmd.set_result_sent()
        elif msg["type"] == "netlink":
            self._if_manager.handle_netlink_msgs(msg["data"])
        elif msg["type"] == "from_netns":
            self._server_handler.send_data_to_ctl(msg["data"])
        elif msg["type"] == "to_netns":
            netns = msg["netns"]
            try:
                self._server_handler.send_data_to_netns(netns, msg["data"])
            except:
                log_exc_traceback()
                type, value, tb = sys.exc_info()
                exc_trace = ''.join(traceback.format_exception(
                    type, value, tb))
                response = {"type": "exception", "Exception": value}

                self._server_handler.send_data_to_ctl(response)
                return
        else:
            raise Exception("Recieved unknown command")

        pipes = self._cmd_context.get_read_pipes()
        self._server_handler.update_connections(pipes)

    def register_die_signal(self, signum):
        signal.signal(signum, self._signal_die_handler)

    def _signal_die_handler(self, signum, frame):
        logging.info("Caught signal %d -> dying" % signum)
        self._finished = True

    def _parent_resend_signal_handler(self, signum, frame):
        logging.info("Caught signal %d -> resending to parent" % signum)
        os.kill(os.getppid(), signum)

    def set_netns_sighandlers(self):
        signal.signal(signal.SIGHUP, self._parent_resend_signal_handler)
        signal.signal(signal.SIGINT, self._parent_resend_signal_handler)
        signal.signal(signal.SIGTERM, self._parent_resend_signal_handler)
        signal.signal(signal.SIGUSR1, self._signal_die_handler)