def test_upload_previous_checksum(server, tmpdir): content = ''.join(['a' for _ in range(0, 1025)]) with open(str(tmpdir / "test"), "w+") as f: f.write(content) body = aiohttp.FormData() body.add_field("type", "QEMU") body.add_field("file", open(str(tmpdir / "test"), "rb"), content_type="application/iou", filename="test2") Config.instance().set("Server", "images_path", str(tmpdir)) os.makedirs(str(tmpdir / "QEMU")) with open(str(tmpdir / "QEMU" / "test2.md5sum"), 'w+') as f: f.write("FAKE checksum") response = server.post('/upload', api_version=None, body=body, raw=True) assert "test2" in response.body.decode("utf-8") with open(str(tmpdir / "QEMU" / "test2")) as f: assert f.read() == content with open(str(tmpdir / "QEMU" / "test2.md5sum")) as f: checksum = f.read() assert checksum == "ae187e1febee2a150b64849c32d566ca"
def test_backup_projects(server, tmpdir, loop): Config.instance().set('Server', 'projects_path', str(tmpdir)) os.makedirs(str(tmpdir / 'a')) with open(str(tmpdir / 'a' / 'a.gns3'), 'w+') as f: f.write('hello') os.makedirs(str(tmpdir / 'b')) with open(str(tmpdir / 'b' / 'b.gns3'), 'w+') as f: f.write('world') response = server.get('/backup/projects.tar', api_version=None, raw=True) assert response.status == 200 assert response.headers['CONTENT-TYPE'] == 'application/x-gtar' with open(str(tmpdir / 'projects.tar'), 'wb+') as f: print(len(response.body)) f.write(response.body) tar = tarfile.open(str(tmpdir / 'projects.tar'), 'r') os.makedirs(str(tmpdir / 'extract')) os.chdir(str(tmpdir / 'extract')) # Extract to current working directory tar.extractall() tar.close() assert os.path.exists(os.path.join('a', 'a.gns3')) assert open(os.path.join('a', 'a.gns3')).read() == 'hello' assert os.path.exists(os.path.join('b', 'b.gns3')) assert open(os.path.join('b', 'b.gns3')).read() == 'world'
def __init__(self, name, *args, **kwargs): config = Config.instance() # a new process start when calling IModule IModule.__init__(self, name, *args, **kwargs) self._host = kwargs["host"] self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] self._working_dir = self._projects_dir self._heartbeat_file = "%s/heartbeat_file_for_gnsdms" % ( self._tempdir) if 'heartbeat_file' in kwargs: self._heartbeat_file = kwargs['heartbeat_file'] self._is_enabled = False try: cloud_config = Config.instance().get_section_config("CLOUD_SERVER") instance_id = cloud_config["instance_id"] cloud_user_name = cloud_config["cloud_user_name"] cloud_api_key = cloud_config["cloud_api_key"] self._is_enabled = True except KeyError: log.critical("Missing cloud.conf - disabling Deadman Switch") self._deadman_process = None self.heartbeat() self.start()
def main(): """ Entry point for GNS3 server """ level = logging.INFO args = parse_arguments(sys.argv[1:], Config.instance().get_section_config("Server")) if args.debug: level = logging.DEBUG user_log = init_logger(level, quiet=args.quiet) user_log.info("GNS3 server version {}".format(__version__)) current_year = datetime.date.today().year user_log.info( "Copyright (c) 2007-{} GNS3 Technologies Inc.".format(current_year)) for config_file in Config.instance().get_config_files(): user_log.info("Config file {} loaded".format(config_file)) set_config(args) server_config = Config.instance().get_section_config("Server") if server_config.getboolean("local"): log.warning( "Local mode is enabled. Beware, clients will have full control on your filesystem" ) # we only support Python 3 version >= 3.3 if sys.version_info < (3, 3): raise RuntimeError("Python 3.3 or higher is required") user_log.info( "Running with Python {major}.{minor}.{micro} and has PID {pid}".format( major=sys.version_info[0], minor=sys.version_info[1], micro=sys.version_info[2], pid=os.getpid())) # check for the correct locale (UNIX/Linux only) locale_check() try: os.getcwd() except FileNotFoundError: log.critical("The current working directory doesn't exist") return Project.clean_project_directory() CrashReport.instance() host = server_config["host"] port = int(server_config["port"]) server = Server.instance(host, port) try: server.run() except Exception as e: log.critical("Critical error while running the server: {}".format(e), exc_info=1) CrashReport.instance().capture_exception() return
def __init__(self, name, node_id, project, manager, ports=None): allowed_interfaces = Config.instance().get_section_config("Server").get("allowed_interfaces", None) if allowed_interfaces: allowed_interfaces = allowed_interfaces.split(',') if sys.platform.startswith("linux"): nat_interface = Config.instance().get_section_config("Server").get("default_nat_interface", "virbr0") if allowed_interfaces and nat_interface not in allowed_interfaces: raise NodeError("NAT interface {} is not allowed be used on this server. " "Please check the server configuration file.".format(nat_interface)) if nat_interface not in [interface["name"] for interface in gns3server.utils.interfaces.interfaces()]: raise NodeError("NAT interface {} is missing, please install libvirt".format(nat_interface)) interface = nat_interface else: nat_interface = Config.instance().get_section_config("Server").get("default_nat_interface", "vmnet8") if allowed_interfaces and nat_interface not in allowed_interfaces: raise NodeError("NAT interface {} is not allowed be used on this server. " "Please check the server configuration file.".format(nat_interface)) interfaces = list(filter(lambda x: nat_interface in x.lower(), [interface["name"] for interface in gns3server.utils.interfaces.interfaces()])) if not len(interfaces): raise NodeError("NAT interface {} is missing. You need to install VMware or use the NAT node on GNS3 VM".format(nat_interface)) interface = interfaces[0] # take the first available interface containing the vmnet8 name log.info("NAT node '{}' configured to use NAT interface '{}'".format(name, interface)) ports = [ { "name": "nat0", "type": "ethernet", "interface": interface, "port_number": 0 } ] super().__init__(name, node_id, project, manager, ports=ports)
def __init__(self, name, *args, **kwargs): config = Config.instance() # a new process start when calling IModule IModule.__init__(self, name, *args, **kwargs) self._host = kwargs["host"] self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] self._working_dir = self._projects_dir self._heartbeat_file = "%s/heartbeat_file_for_gnsdms" % (self._tempdir) if 'heartbeat_file' in kwargs: self._heartbeat_file = kwargs['heartbeat_file'] self._is_enabled = False try: cloud_config = Config.instance().get_section_config("CLOUD_SERVER") instance_id = cloud_config["instance_id"] cloud_user_name = cloud_config["cloud_user_name"] cloud_api_key = cloud_config["cloud_api_key"] self._is_enabled = True except KeyError: log.critical("Missing cloud.conf - disabling Deadman Switch") self._deadman_process = None self.heartbeat() self.start()
def test_upload_projects_backup(server, tmpdir): Config.instance().set("Server", "projects_path", str(tmpdir / 'projects')) os.makedirs(str(tmpdir / 'projects' / 'b')) # An old b image that we need to replace with open(str(tmpdir / 'projects' / 'b' / 'b.img'), 'w+') as f: f.write('bad') os.makedirs(str(tmpdir / 'old' / 'a')) with open(str(tmpdir / 'old' / 'a' / 'a.img'), 'w+') as f: f.write('hello') os.makedirs(str(tmpdir / 'old' / 'b')) with open(str(tmpdir / 'old' / 'b' / 'b.img'), 'w+') as f: f.write('world') os.chdir(str(tmpdir / 'old')) with tarfile.open(str(tmpdir / 'test.tar'), 'w') as tar: tar.add('.', recursive=True) body = aiohttp.FormData() body.add_field('type', 'PROJECTS') body.add_field('file', open(str(tmpdir / 'test.tar'), 'rb'), content_type='application/x-gtar', filename='test.tar') response = server.post('/upload', api_version=None, body=body, raw=True) assert response.status == 200 with open(str(tmpdir / 'projects' / 'a' / 'a.img')) as f: assert f.read() == 'hello' with open(str(tmpdir / 'projects' / 'b' / 'b.img')) as f: assert f.read() == 'world' assert 'a.img' not in response.body.decode('utf-8') assert 'b.img' not in response.body.decode('utf-8') assert not os.path.exists(str(tmpdir / 'projects' / 'archive.tar'))
def test_backup_projects(server, tmpdir, loop): Config.instance().set('Server', 'projects_path', str(tmpdir)) os.makedirs(str(tmpdir / 'a')) with open(str(tmpdir / 'a' / 'a.gns3'), 'w+') as f: f.write('hello') os.makedirs(str(tmpdir / 'b')) with open(str(tmpdir / 'b' / 'b.gns3'), 'w+') as f: f.write('world') response = server.get('/backup/projects.tar', api_version=None, raw=True) assert response.status == 200 assert response.headers['CONTENT-TYPE'] == 'application/x-gtar' with open(str(tmpdir / 'projects.tar'), 'wb+') as f: print(len(response.body)) f.write(response.body) tar = tarfile.open(str(tmpdir / 'projects.tar'), 'r') os.makedirs(str(tmpdir / 'extract')) os.chdir(str(tmpdir / 'extract')) # Extract to current working directory tar.extractall() tar.close() assert os.path.exists(os.path.join('a', 'a.gns3')) open(os.path.join('a', 'a.gns3')).read() == 'hello' assert os.path.exists(os.path.join('b', 'b.gns3')) open(os.path.join('b', 'b.gns3')).read() == 'world'
def main(): """ Entry point for GNS3 server """ level = logging.INFO args = parse_arguments(sys.argv[1:], Config.instance().get_section_config("Server")) if args.debug: level = logging.DEBUG user_log = init_logger(level, logfile=args.log, quiet=args.quiet) user_log.info("GNS3 server version {}".format(__version__)) current_year = datetime.date.today().year user_log.info("Copyright (c) 2007-{} GNS3 Technologies Inc.".format(current_year)) for config_file in Config.instance().get_config_files(): user_log.info("Config file {} loaded".format(config_file)) set_config(args) server_config = Config.instance().get_section_config("Server") if server_config.getboolean("local"): log.warning("Local mode is enabled. Beware, clients will have full control on your filesystem") # we only support Python 3 version >= 3.3 if sys.version_info < (3, 3): raise RuntimeError("Python 3.3 or higher is required") user_log.info("Running with Python {major}.{minor}.{micro} and has PID {pid}".format( major=sys.version_info[0], minor=sys.version_info[1], micro=sys.version_info[2], pid=os.getpid())) # check for the correct locale (UNIX/Linux only) locale_check() try: os.getcwd() except FileNotFoundError: log.critical("The current working directory doesn't exist") return Project.clean_project_directory() CrashReport.instance() host = server_config["host"] port = int(server_config["port"]) server = Server.instance(host, port) try: server.run() except OSError as e: # This is to ignore OSError: [WinError 0] The operation completed successfully exception on Windows. if not sys.platform.startswith("win") and not e.winerror == 0: raise except Exception as e: log.critical("Critical error while running the server: {}".format(e), exc_info=1) CrashReport.instance().capture_exception() return
def parse_arguments(argv): """ Parse command line arguments and override local configuration :params args: Array of command line arguments """ parser = argparse.ArgumentParser(description="GNS3 server version {}".format(__version__)) parser.add_argument("-v", "--version", help="show the version", action="version", version=__version__) parser.add_argument("--host", help="run on the given host/IP address") parser.add_argument("--port", help="run on the given port", type=int) parser.add_argument("--ssl", action="store_true", help="run in SSL mode") parser.add_argument("--controller", action="store_true", help="start as a GNS3 controller") parser.add_argument("--config", help="Configuration file") parser.add_argument("--certfile", help="SSL cert file") parser.add_argument("--certkey", help="SSL key file") parser.add_argument("--record", help="save curl requests into a file (for developers)") parser.add_argument("-L", "--local", action="store_true", help="local mode (allows some insecure operations)") parser.add_argument("-A", "--allow", action="store_true", help="allow remote connections to local console ports") parser.add_argument("-q", "--quiet", action="store_true", help="do not show logs on stdout") parser.add_argument("-d", "--debug", action="store_true", help="show debug logs") parser.add_argument("--live", action="store_true", help="enable code live reload") parser.add_argument("--shell", action="store_true", help="start a shell inside the server (debugging purpose only you need to install ptpython before)") parser.add_argument("--log", help="send output to logfile instead of console") parser.add_argument("--daemon", action="store_true", help="start as a daemon") parser.add_argument("--pid", help="store process pid") args = parser.parse_args(argv) if args.config: Config.instance(files=[args.config]) config = Config.instance().get_section_config("Server") defaults = { "host": config.get("host", "0.0.0.0"), "port": config.get("port", 3080), "ssl": config.getboolean("ssl", False), "certfile": config.get("certfile", ""), "certkey": config.get("certkey", ""), "record": config.get("record", ""), "local": config.getboolean("local", False), "controller": config.getboolean("controller", False), "allow": config.getboolean("allow_remote_console", False), "quiet": config.getboolean("quiet", False), "debug": config.getboolean("debug", False), "live": config.getboolean("live", False), "logfile": config.getboolean("logfile", ""), } parser.set_defaults(**defaults) return parser.parse_args(argv)
def parse_arguments(argv): """ Parse command line arguments and override local configuration :params args: Array of command line arguments """ parser = argparse.ArgumentParser(description="GNS3 server version {}".format(__version__)) parser.add_argument("-v", "--version", help="show the version", action="version", version=__version__) parser.add_argument("--host", help="run on the given host/IP address") parser.add_argument("--port", help="run on the given port", type=int) parser.add_argument("--ssl", action="store_true", help="run in SSL mode") parser.add_argument("--config", help="Configuration file") parser.add_argument("--certfile", help="SSL cert file") parser.add_argument("--certkey", help="SSL key file") parser.add_argument("--record", help="save curl requests into a file (for developers)") parser.add_argument("-L", "--local", action="store_true", help="local mode (allows some insecure operations)") parser.add_argument("-A", "--allow", action="store_true", help="allow remote connections to local console ports") parser.add_argument("-q", "--quiet", action="store_true", help="do not show logs on stdout") parser.add_argument("-d", "--debug", action="store_true", help="show debug logs") parser.add_argument("--shell", action="store_true", help="start a shell inside the server (debugging purpose only you need to install ptpython before)") parser.add_argument("--log", help="send output to logfile instead of console") parser.add_argument("--daemon", action="store_true", help="start as a daemon") parser.add_argument("--pid", help="store process pid") parser.add_argument("--profile", help="Settings profile (blank will use default settings files)") args = parser.parse_args(argv) if args.config: Config.instance(files=[args.config], profile=args.profile) else: Config.instance(profile=args.profile) config = Config.instance().get_section_config("Server") defaults = { "host": config.get("host", "0.0.0.0"), "port": config.get("port", 3080), "ssl": config.getboolean("ssl", False), "certfile": config.get("certfile", ""), "certkey": config.get("certkey", ""), "record": config.get("record", ""), "local": config.getboolean("local", False), "allow": config.getboolean("allow_remote_console", False), "quiet": config.getboolean("quiet", False), "debug": config.getboolean("debug", False), "logfile": config.getboolean("logfile", "") } parser.set_defaults(**defaults) return parser.parse_args(argv)
def __init__(self, name, *args, **kwargs): # get the vboxmanage location self._vboxmanage_path = None if sys.platform.startswith("win"): if "VBOX_INSTALL_PATH" in os.environ: self._vboxmanage_path = os.path.join(os.environ["VBOX_INSTALL_PATH"], "VBoxManage.exe") elif "VBOX_MSI_INSTALL_PATH" in os.environ: self._vboxmanage_path = os.path.join(os.environ["VBOX_MSI_INSTALL_PATH"], "VBoxManage.exe") elif sys.platform.startswith("darwin"): self._vboxmanage_path = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage" else: config = Config.instance() vbox_config = config.get_section_config(name.upper()) self._vboxmanage_path = vbox_config.get("vboxmanage_path") if not self._vboxmanage_path or not os.path.isfile(self._vboxmanage_path): paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep) # look for vboxmanage in the current working directory and $PATH for path in paths: try: if "vboxmanage" in [s.lower() for s in os.listdir(path)] and os.access( os.path.join(path, "vboxmanage"), os.X_OK ): self._vboxmanage_path = os.path.join(path, "vboxmanage") break except OSError: continue if not self._vboxmanage_path: log.warning("vboxmanage couldn't be found!") elif not os.access(self._vboxmanage_path, os.X_OK): log.warning("vboxmanage is not executable") # a new process start when calling IModule IModule.__init__(self, name, *args, **kwargs) self._vbox_instances = {} config = Config.instance() vbox_config = config.get_section_config(name.upper()) self._console_start_port_range = vbox_config.get("console_start_port_range", 3501) self._console_end_port_range = vbox_config.get("console_end_port_range", 4000) self._allocated_udp_ports = [] self._udp_start_port_range = vbox_config.get("udp_start_port_range", 35001) self._udp_end_port_range = vbox_config.get("udp_end_port_range", 35500) self._host = vbox_config.get("host", kwargs["host"]) self._console_host = vbox_config.get("console_host", kwargs["console_host"]) self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] self._working_dir = self._projects_dir
def test_upload(server, tmpdir): with open(str(tmpdir / "test"), "w+") as f: f.write("TEST") body = aiohttp.FormData() body.add_field("type", "QEMU") body.add_field("file", open(str(tmpdir / "test"), "rb"), content_type="application/iou", filename="test2") Config.instance().set("Server", "images_path", str(tmpdir)) response = server.post('/upload', api_version=None, body=body, raw=True) with open(str(tmpdir / "QEMU" / "test2")) as f: assert f.read() == "TEST" assert "test2" in response.body.decode("utf-8")
def run_around_tests(monkeypatch, port_manager): """ This setup a temporay project file environnement around tests """ tmppath = tempfile.mkdtemp() port_manager._instance = port_manager config = Config.instance() config.clear() os.makedirs(os.path.join(tmppath, 'projects')) config.set("Server", "project_directory", os.path.join(tmppath, 'projects')) config.set("Server", "images_path", os.path.join(tmppath, 'images')) config.set("Server", "auth", False) # Prevent executions of the VM if we forgot to mock something config.set("VirtualBox", "vboxmanage_path", tmppath) config.set("VPCS", "vpcs_path", tmppath) config.set("VMware", "vmrun_path", tmppath) # Force turn off KVM because it's not available on CI config.set("Qemu", "enable_kvm", False) monkeypatch.setattr("gns3server.modules.project.Project._get_default_project_directory", lambda *args: os.path.join(tmppath, 'projects')) # Force sys.platform to the original value. Because it seem not be restore correctly at each tests sys.platform = sys.original_platform yield # An helper should not raise Exception try: shutil.rmtree(tmppath) except: pass
async def import_project(request, response): controller = Controller.instance() if request.get("path"): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return path = request.json.get("path") name = request.json.get("name") # We write the content to a temporary location and after we extract it all. # It could be more optimal to stream this but it is not implemented in Python. try: begin = time.time() with tempfile.TemporaryDirectory() as tmpdir: temp_project_path = os.path.join(tmpdir, "project.zip") async with aiofiles.open(temp_project_path, 'wb') as f: while True: chunk = await request.content.read(CHUNK_SIZE) if not chunk: break await f.write(chunk) with open(temp_project_path, "rb") as f: project = await import_project(controller, request.match_info["project_id"], f, location=path, name=name) log.info("Project '{}' imported in {:.4f} seconds".format(project.name, time.time() - begin)) except OSError as e: raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e)) response.json(project) response.set_status(201)
def __init__(self, host="127.0.0.1"): self._console_host = host self._udp_host = host self._used_tcp_ports = set() self._used_udp_ports = set() server_config = Config.instance().get_section_config("Server") remote_console_connections = server_config.getboolean("allow_remote_console") console_start_port_range = server_config.getint("console_start_port_range", 2000) console_end_port_range = server_config.getint("console_end_port_range", 5000) self._console_port_range = (console_start_port_range, console_end_port_range) log.debug("Console port range is {}-{}".format(console_start_port_range, console_end_port_range)) udp_start_port_range = server_config.getint("udp_start_port_range", 10000) udp_end_port_range = server_config.getint("udp_end_port_range", 20000) self._udp_port_range = (udp_start_port_range, udp_end_port_range) log.debug("UDP port range is {}-{}".format(udp_start_port_range, udp_end_port_range)) if remote_console_connections: log.warning("Remote console connections are allowed") if ipaddress.ip_address(host).version == 6: self._console_host = "::" else: self._console_host = "0.0.0.0" else: self._console_host = host PortManager._instance = self
def __init__(self, path, working_dir, host='127.0.0.1', console_host='0.0.0.0'): self._hypervisors = [] self._path = path self._working_dir = working_dir self._console_host = console_host self._host = console_host # FIXME: Dynamips must be patched to bind on a different address than the one used by the hypervisor. config = Config.instance() dynamips_config = config.get_section_config("DYNAMIPS") self._hypervisor_start_port_range = dynamips_config.get("hypervisor_start_port_range", 7200) self._hypervisor_end_port_range = dynamips_config.get("hypervisor_end_port_range", 7700) self._console_start_port_range = dynamips_config.get("console_start_port_range", 2001) self._console_end_port_range = dynamips_config.get("console_end_port_range", 2500) self._aux_start_port_range = dynamips_config.get("aux_start_port_range", 2501) self._aux_end_port_range = dynamips_config.get("aux_end_port_range", 3000) self._udp_start_port_range = dynamips_config.get("udp_start_port_range", 10001) self._udp_end_port_range = dynamips_config.get("udp_end_port_range", 20000) self._ghost_ios_support = dynamips_config.get("ghost_ios_support", True) self._mmap_support = dynamips_config.get("mmap_support", True) self._jit_sharing_support = dynamips_config.get("jit_sharing_support", False) self._sparse_memory_support = dynamips_config.get("sparse_memory_support", True) self._allocate_hypervisor_per_device = dynamips_config.get("allocate_hypervisor_per_device", True) self._memory_usage_limit_per_hypervisor = dynamips_config.get("memory_usage_limit_per_hypervisor", 1024) self._allocate_hypervisor_per_ios_image = dynamips_config.get("allocate_hypervisor_per_ios_image", True)
def test_index_upload(server, tmpdir): Config.instance().set("Server", "images_path", str(tmpdir)) open(str(tmpdir / "alpha"), "w+").close() open(str(tmpdir / "alpha.md5sum"), "w+").close() open(str(tmpdir / ".beta"), "w+").close() response = server.get('/upload', api_version=None) assert response.status == 200 html = response.html assert "GNS3 Server" in html assert "Select & Upload" in html assert "alpha" in html assert ".beta" not in html assert "alpha.md5sum" not in html
def test_set_config_with_args(): config = Config.instance() args = run.parse_arguments(["--host", "192.168.1.1", "--local", "--allow", "--port", "8001", "--ssl", "--certfile", "bla", "--certkey", "blu", "--debug"]) run.set_config(args) server_config = config.get_section_config("Server") assert server_config.getboolean("local") assert server_config.getboolean("allow_remote_console") assert server_config["host"] == "192.168.1.1" assert server_config["port"] == "8001" assert server_config.getboolean("ssl") assert server_config["certfile"] == "bla" assert server_config["certkey"] == "blu" assert server_config.getboolean("debug")
def import_project(request, response): controller = Controller.instance() if request.get("path"): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return path = request.json.get("path") name = request.json.get("name") # We write the content to a temporary location and after we extract it all. # It could be more optimal to stream this but it is not implemented in Python. # Spooled means the file is temporary kept in memory until max_size is reached try: with tempfile.SpooledTemporaryFile(max_size=10000) as temp: while True: packet = yield from request.content.read(512) if not packet: break temp.write(packet) project = yield from import_project(controller, request.match_info["project_id"], temp, location=path, name=name) except OSError as e: raise aiohttp.web.HTTPInternalServerError(text="Could not import the project: {}".format(e)) response.json(project) response.set_status(201)
def test_version_output(http_compute): config = Config.instance() config.set("Server", "local", "true") response = http_compute.get('/version', example=True) assert response.status == 200 assert response.json == {'local': True, 'version': __version__}
def test_version_output(http_controller): config = Config.instance() config.set("Server", "local", "true") response = http_controller.get('/version', example=True) assert response.status == 200 assert response.json == {'local': True, 'version': __version__}
def __init__(self, name, *args, **kwargs): # get the VPCS location config = Config.instance() vpcs_config = config.get_section_config(name.upper()) self._vpcs = vpcs_config.get("vpcs_path") if not self._vpcs or not os.path.isfile(self._vpcs): paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep) # look for VPCS in the current working directory and $PATH for path in paths: try: if "vpcs" in os.listdir(path) and os.access(os.path.join(path, "vpcs"), os.X_OK): self._vpcs = os.path.join(path, "vpcs") break except OSError: continue if not self._vpcs: log.warning("VPCS binary couldn't be found!") elif not os.access(self._vpcs, os.X_OK): log.warning("VPCS is not executable") # a new process start when calling IModule IModule.__init__(self, name, *args, **kwargs) self._vpcs_instances = {} self._console_start_port_range = vpcs_config.get("console_start_port_range", 4501) self._console_end_port_range = vpcs_config.get("console_end_port_range", 5000) self._allocated_udp_ports = [] self._udp_start_port_range = vpcs_config.get("udp_start_port_range", 20501) self._udp_end_port_range = vpcs_config.get("udp_end_port_range", 21000) self._host = vpcs_config.get("host", kwargs["host"]) self._console_host = vpcs_config.get("console_host", kwargs["console_host"]) self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] self._working_dir = self._projects_dir
def run_around_tests(monkeypatch): """ This setup a temporay project file environnement around tests """ tmppath = tempfile.mkdtemp() config = Config.instance() config.clear() config.set("Server", "project_directory", tmppath) config.set("Server", "auth", False) # Prevent exectuions of the VM if we forgot to mock something config.set("VirtualBox", "vboxmanage_path", tmppath) config.set("VPCS", "vpcs_path", tmppath) monkeypatch.setattr("gns3server.modules.project.Project._get_default_project_directory", lambda *args: tmppath) yield # An helper should not raise Exception try: shutil.rmtree(tmppath) except: pass
async def duplicate(request, response): controller = Controller.instance() project = await controller.get_loaded_project( request.match_info["project_id"]) if request.json.get("path"): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return location = request.json.get("path") else: location = None reset_mac_addresses = request.json.get("reset_mac_addresses", False) new_project = await project.duplicate( name=request.json.get("name"), location=location, reset_mac_addresses=reset_mac_addresses) response.json(new_project) response.set_status(201)
def shutdown(request, response): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: raise HTTPForbidden(text="You can only stop a local server") log.info("Start shutting down the server") # close all the projects first controller = Controller.instance() projects = controller.projects.values() tasks = [] for project in projects: tasks.append(asyncio. async (project.close())) if tasks: done, _ = yield from asyncio.wait(tasks) for future in done: try: future.result() except Exception as e: log.error("Could not close project {}".format(e), exc_info=1) continue # then shutdown the server itself from gns3server.web.web_server import WebServer server = WebServer.instance() asyncio. async (server.shutdown_server()) response.set_status(201)
def test_node_working_directory(tmpdir, node): directory = Config.instance().get_section_config("Server").get("projects_path") with patch("gns3server.compute.project.Project.is_local", return_value=True): p = Project(project_id=str(uuid4())) assert p.node_working_directory(node) == os.path.join(directory, p.id, 'project-files', node.module_name, node.id) assert os.path.exists(p.node_working_directory(node))
def __init__(self, host="127.0.0.1"): self._console_host = host # UDP host must be 0.0.0.0, reason: https://github.com/GNS3/gns3-server/issues/265 self._udp_host = "0.0.0.0" self._used_tcp_ports = set() self._used_udp_ports = set() server_config = Config.instance().get_section_config("Server") remote_console_connections = server_config.getboolean("allow_remote_console") console_start_port_range = server_config.getint("console_start_port_range", 5000) console_end_port_range = server_config.getint("console_end_port_range", 10000) self._console_port_range = (console_start_port_range, console_end_port_range) log.debug("Console port range is {}-{}".format(console_start_port_range, console_end_port_range)) udp_start_port_range = server_config.getint("udp_start_port_range", 10000) udp_end_port_range = server_config.getint("udp_end_port_range", 20000) self._udp_port_range = (udp_start_port_range, udp_end_port_range) log.debug("UDP port range is {}-{}".format(udp_start_port_range, udp_end_port_range)) if remote_console_connections: log.warning("Remote console connections are allowed") if ipaddress.ip_address(host).version == 6: self._console_host = "::" else: self._console_host = "0.0.0.0" else: self._console_host = host PortManager._instance = self
def shutdown(request, response): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: raise HTTPForbidden(text="You can only stop a local server") log.info("Start shutting down the server") # close all the projects first controller = Controller.instance() projects = controller.projects.values() tasks = [] for project in projects: tasks.append(asyncio.async(project.close())) if tasks: done, _ = yield from asyncio.wait(tasks) for future in done: try: future.result() except Exception as e: log.error("Could not close project {}".format(e), exc_info=1) continue # then shutdown the server itself from gns3server.web.web_server import WebServer server = WebServer.instance() asyncio.async(server.shutdown_server()) response.set_status(201)
def __init__(self, name, *args, **kwargs): # get the VPCS location config = Config.instance() vpcs_config = config.get_section_config(name.upper()) self._vpcs = vpcs_config.get("vpcs_path") if not self._vpcs or not os.path.isfile(self._vpcs): paths = [os.getcwd()] + os.environ["PATH"].split(os.pathsep) # look for VPCS in the current working directory and $PATH for path in paths: try: if "vpcs" in os.listdir(path) and os.access(os.path.join(path, "vpcs"), os.X_OK): self._vpcs = os.path.join(path, "vpcs") break except OSError: continue if not self._vpcs: log.warning("VPCS binary couldn't be found!") elif not os.access(self._vpcs, os.X_OK): log.warning("VPCS is not executable") # a new process start when calling IModule IModule.__init__(self, name, *args, **kwargs) self._vpcs_instances = {} self._console_start_port_range = vpcs_config.get("console_start_port_range", 4501) self._console_end_port_range = vpcs_config.get("console_end_port_range", 5000) self._allocated_udp_ports = [] self._udp_start_port_range = vpcs_config.get("udp_start_port_range", 20501) self._udp_end_port_range = vpcs_config.get("udp_end_port_range", 21000) self._host = vpcs_config.get("host", kwargs["host"]) self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] self._working_dir = self._projects_dir
def import_project(request, response): controller = Controller.instance() if request.get("path"): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return path = request.json.get("path") name = request.json.get("name") # We write the content to a temporary location and after we extract it all. # It could be more optimal to stream this but it is not implemented in Python. # Spooled means the file is temporary kept in memory until max_size is reached try: with tempfile.SpooledTemporaryFile(max_size=10000) as temp: while True: packet = yield from request.content.read(512) if not packet: break temp.write(packet) project = yield from import_project( controller, request.match_info["project_id"], temp, location=path, name=name) except OSError as e: raise aiohttp.web.HTTPInternalServerError( text="Could not import the project: {}".format(e)) response.json(project) response.set_status(201)
def test_set_config_with_args(): config = Config.instance() args = main.parse_arguments(["--host", "192.168.1.1", "--local", "--allow", "--port", "8001", "--ssl", "--certfile", "bla", "--certkey", "blu", "--debug"], config.get_section_config("Server")) main.set_config(args) server_config = config.get_section_config("Server") assert server_config.getboolean("local") assert server_config.getboolean("allow_remote_console") assert server_config["host"] == "192.168.1.1" assert server_config["port"] == "8001" assert server_config.getboolean("ssl") assert server_config["certfile"] == "bla" assert server_config["certkey"] == "blu" assert server_config.getboolean("debug")
def test_path(tmpdir): directory = Config.instance().get_section_config("Server").get("projects_path") with patch("gns3server.utils.path.get_default_project_directory", return_value=directory): p = Project(project_id=str(uuid4()), name="Test") assert p.path == os.path.join(directory, p.id) assert os.path.exists(os.path.join(directory, p.id))
def test_reload_forbidden(server): config = Config.instance() config.set("Server", "local", "false") response = server.post('/config/reload') assert response.status == 403
def test_dump(): directory = Config.instance().get_section_config("Server").get("projects_path") with patch("gns3server.utils.path.get_default_project_directory", return_value=directory): p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test") p.dump() with open(os.path.join(directory, p.id, "Test.gns3")) as f: content = f.read() assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
def load(request, response): controller = Controller.instance() config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return project = yield from controller.load_project(request.json.get("path"),) response.set_status(201) response.json(project)
def test_node_working_directory(tmpdir, node): directory = Config.instance().get_section_config("Server").get( "projects_path") with patch("gns3server.compute.project.Project.is_local", return_value=True): p = Project(project_id=str(uuid4())) assert p.node_working_directory(node) == os.path.join( directory, p.id, 'project-files', node.module_name, node.id) assert os.path.exists(p.node_working_directory(node))
def fake_qemu_vm(tmpdir): img_dir = Config.instance().get_section_config("Server").get("images_path") img_dir = os.path.join(img_dir, "QEMU") os.makedirs(img_dir) bin_path = os.path.join(img_dir, "linux载.img") with open(bin_path, "w+") as f: f.write("1") os.chmod(bin_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) return bin_path
def console_host(self, new_host): """ If allow remote connection we need to bind console host to 0.0.0.0 """ server_config = Config.instance().get_section_config("Server") remote_console_connections = server_config.getboolean("allow_remote_console") if remote_console_connections: log.warning("Remote console connections are allowed") self._console_host = "0.0.0.0" else: self._console_host = new_host
async def load(request, response): controller = Controller.instance() config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: log.error("Can't load the project the server is not started with --local") response.set_status(403) return project = await controller.load_project(request.json.get("path"),) response.set_status(201) response.json(project)
def test_router_invalid_dynamips_path(project, manager, loop): config = Config.instance() config.set("Dynamips", "dynamips_path", "/bin/test_fake") config.set("Dynamips", "allocate_aux_console_ports", False) with pytest.raises(DynamipsError): router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0e", project, manager) loop.run_until_complete(asyncio.ensure_future(router.create())) assert router.name == "test" assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
async def load(request, response): controller = Controller.instance() config = Config.instance() dot_gns3_file = request.json.get("path") if config.get_section_config("Server").getboolean("local", False) is False: log.error("Cannot load '{}' because the server has not been started with the '--local' parameter".format(dot_gns3_file)) response.set_status(403) return project = await controller.load_project(dot_gns3_file,) response.set_status(201) response.json(project)
def test_reload_accepted(server): gns_config = MagicMock() config = Config.instance() config.set("Server", "local", "true") gns_config.get_section_config.return_value = config.get_section_config("Server") with patch("gns3server.config.Config.instance", return_value=gns_config): response = server.post('/config/reload', example=True) assert response.status == 201 assert gns_config.reload.called
async def create_img(request, response): qemu_img = request.json.pop("qemu_img") path = request.json.pop("path") if os.path.isabs(path): config = Config.instance() if config.get_section_config("Server").getboolean("local", False) is False: response.set_status(403) return await Qemu.instance().create_disk(qemu_img, path, request.json) response.set_status(201)
def load_config(tmpdir, settings): """ Create a configuration file for the test. :params tmpdir: Temporary directory :params settings: Configuration settings :returns: Configuration instance """ path = write_config(tmpdir, settings) return Config(files=[path])