From b344def8871b4cbce7539886040087a97be94aa0 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Wed, 3 Jun 2015 11:59:53 +0200 Subject: [PATCH 1/5] Fix crash when virtualbox list of VMS return an empty line Fix #206 --- gns3server/modules/virtualbox/__init__.py | 2 +- tests/modules/virtualbox/test_virtualbox_manager.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gns3server/modules/virtualbox/__init__.py b/gns3server/modules/virtualbox/__init__.py index 509b7182..890ad6e7 100644 --- a/gns3server/modules/virtualbox/__init__.py +++ b/gns3server/modules/virtualbox/__init__.py @@ -168,7 +168,7 @@ class VirtualBox(BaseManager): vms = [] result = yield from self.execute("list", ["vms"]) for line in result: - if line[0] != '"' or line[-1:] != "}": + if len(line) == 0 or line[0] != '"' or line[-1:] != "}": continue # Broken output (perhaps a carriage return in VM name vmname, _ = line.rsplit(' ', 1) vmname = vmname.strip('"') diff --git a/tests/modules/virtualbox/test_virtualbox_manager.py b/tests/modules/virtualbox/test_virtualbox_manager.py index 54289554..caae45e3 100644 --- a/tests/modules/virtualbox/test_virtualbox_manager.py +++ b/tests/modules/virtualbox/test_virtualbox_manager.py @@ -75,9 +75,9 @@ def test_get_list(manager, loop): vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}', '"Carriage', 'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}', + '', '"" {42b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}', - '"Linux Microcore 4.7.1" {ccd8c50b-c172-457d-99fa-dd69371ede0e}' - ] + '"Linux Microcore 4.7.1" {ccd8c50b-c172-457d-99fa-dd69371ede0e}'] @asyncio.coroutine def execute_mock(cmd, args): From 78891ae00e21149c7d461e2893c27cd0be178260 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Wed, 3 Jun 2015 15:38:34 +0200 Subject: [PATCH 2/5] Basic Auth support --- gns3server/web/route.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/gns3server/web/route.py b/gns3server/web/route.py index f376b820..8cf70b0b 100644 --- a/gns3server/web/route.py +++ b/gns3server/web/route.py @@ -83,6 +83,28 @@ class Route(object): def delete(cls, path, *args, **kw): return cls._route('DELETE', path, *args, **kw) + @classmethod + def authenticate(cls, request, route, server_config): + """ + Ask user for authentication + + :returns: Response if you need to auth the user otherwise None + """ + user = server_config.get("user", "").strip() + password = server_config.get("password", "").strip() + + if len(user) == 0: + return + + if "AUTHORIZATION" in request.headers: + if request.headers["AUTHORIZATION"] == aiohttp.helpers.BasicAuth(user, password).encode(): + return + + response = Response(request=request, route=route) + response.set_status(401) + response.headers["WWW-Authenticate"] = 'Basic realm="GNS3 server"' + return response + @classmethod def _route(cls, method, path, *args, **kw): # This block is executed only the first time @@ -118,6 +140,13 @@ class Route(object): def control_schema(request): # This block is executed at each method call + server_config = Config.instance().get_section_config("Server") + + # Authenticate + response = cls.authenticate(request, route, server_config) + if response: + return response + # Non API call if api_version is None: response = Response(request=request, route=route, output_schema=output_schema) @@ -127,7 +156,6 @@ class Route(object): # API call try: request = yield from parse_request(request, input_schema) - server_config = Config.instance().get_section_config("Server") record_file = server_config.get("record") if record_file: try: From d9de1718b7b9700e7c8c6358535b1381040f9a75 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 5 Jun 2015 15:30:30 +0200 Subject: [PATCH 3/5] Fix crash if a private config exist in IOS but no private config file Fix #217 --- gns3server/modules/dynamips/nodes/router.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index 0b0d6492..c23f10f5 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -1498,7 +1498,7 @@ class Router(BaseVM): if self.startup_config or self.private_config: module_workdir = self.project.module_working_directory(self.manager.module_name.lower()) startup_config_base64, private_config_base64 = yield from self.extract_config() - if startup_config_base64: + if self.startup_config and startup_config_base64: try: config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace") config = "!\n" + config.replace("\r", "") @@ -1509,7 +1509,7 @@ class Router(BaseVM): except (binascii.Error, OSError) as e: raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) - if private_config_base64: + if self.private_config and private_config_base64: try: config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace") config = "!\n" + config.replace("\r", "") From fff3e1474f3204ed5b426f7016891b361048ec96 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 5 Jun 2015 15:59:43 +0200 Subject: [PATCH 4/5] Distribute our own version of netifaces working with python 3 Fix #97 --- requirements.txt | 2 +- setup.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 8dc813ff..35469ed7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -netifaces==0.10.4 +gns3-netifaces==0.10.4.1 jsonschema==2.4.0 aiohttp==0.14.4 Jinja2==2.7.3 diff --git a/setup.py b/setup.py index f72b781d..21c69b57 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,8 @@ class PyTest(TestCommand): sys.exit(errcode) -dependencies = ["aiohttp>=0.14.4", +dependencies = ["gns3-netifaces>=0.10.4.1", + "aiohttp>=0.14.4", "jsonschema>=2.4.0", "Jinja2>=2.7.3", "raven>=5.2.0"] From 02650fa4909e1e46832650a795c143e8104e7e34 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 5 Jun 2015 16:23:52 +0200 Subject: [PATCH 5/5] Create a private config file if expected Fix #217 --- gns3server/modules/dynamips/nodes/router.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index c23f10f5..784e9451 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -1498,7 +1498,10 @@ class Router(BaseVM): if self.startup_config or self.private_config: module_workdir = self.project.module_working_directory(self.manager.module_name.lower()) startup_config_base64, private_config_base64 = yield from self.extract_config() - if self.startup_config and startup_config_base64: + if startup_config_base64: + if not self.startup_config: + self._startup_config = os.path.join("configs", "i{}_startup-config.cfg".format(self._dynamips_id)) + try: config = base64.b64decode(startup_config_base64).decode("utf-8", errors="replace") config = "!\n" + config.replace("\r", "") @@ -1509,7 +1512,10 @@ class Router(BaseVM): except (binascii.Error, OSError) as e: raise DynamipsError("Could not save the startup configuration {}: {}".format(config_path, e)) - if self.private_config and private_config_base64: + if private_config_base64: + if not self.private_config: + self._private_config = os.path.join("configs", "i{}_private-config.cfg".format(self._dynamips_id)) + try: config = base64.b64decode(private_config_base64).decode("utf-8", errors="replace") config = "!\n" + config.replace("\r", "")