diff --git a/gns3server/handlers/api/iou_handler.py b/gns3server/handlers/api/iou_handler.py index 5769a992..5e076c4e 100644 --- a/gns3server/handlers/api/iou_handler.py +++ b/gns3server/handlers/api/iou_handler.py @@ -61,7 +61,8 @@ class IOUHandler: ram=request.json.get("ram"), nvram=request.json.get("nvram"), l1_keepalives=request.json.get("l1_keepalives"), - initial_config=request.json.get("initial_config_content") + initial_config=request.json.get("initial_config_content"), + iourc_content=request.json.get("iourc_content") ) vm.path = request.json.get("path", vm.path) response.set_status(201) diff --git a/gns3server/modules/base_vm.py b/gns3server/modules/base_vm.py index 67db308a..cfbcc2a2 100644 --- a/gns3server/modules/base_vm.py +++ b/gns3server/modules/base_vm.py @@ -20,6 +20,7 @@ import logging import aiohttp import shutil import asyncio +import tempfile from ..utils.asyncio import wait_run_in_executor @@ -45,6 +46,7 @@ class BaseVM: self._project = project self._manager = manager self._console = console + self._temporary_directory = None if self._console is not None: self._console = self._manager.port_manager.reserve_tcp_port(self._console) @@ -61,6 +63,9 @@ class BaseVM: def __del__(self): self.close() + if self._temporary_directory is not None: + if os.path.exists(self._temporary_directory): + shutil.rmtree(self._temporary_directory) @property def project(self): @@ -124,6 +129,12 @@ class BaseVM: return self._project.vm_working_directory(self) + @property + def temporary_directory(self): + if self._temporary_directory is None: + self._temporary_directory = tempfile.mkdtemp() + return self._temporary_directory + def create(self): """ Creates the VM. diff --git a/gns3server/modules/iou/iou_vm.py b/gns3server/modules/iou/iou_vm.py index e1c7bc77..cb5f917d 100644 --- a/gns3server/modules/iou/iou_vm.py +++ b/gns3server/modules/iou/iou_vm.py @@ -67,6 +67,7 @@ class IOUVM(BaseVM): :params nvram: Nvram KB :params l1_keepalives: Always up ethernet interface: :params initial_config: Content of the initial configuration file + :params iourc_content: Content of the iourc file if no licence is installed on server """ def __init__(self, name, vm_id, project, manager, @@ -76,7 +77,8 @@ class IOUVM(BaseVM): ethernet_adapters=None, serial_adapters=None, l1_keepalives=None, - initial_config=None): + initial_config=None, + iourc_content=None): super().__init__(name, vm_id, project, manager, console=console) @@ -99,6 +101,7 @@ class IOUVM(BaseVM): self._ram = 256 if ram is None else ram # Megabytes self._l1_keepalives = False if l1_keepalives is None else l1_keepalives # used to overcome the always-up Ethernet interfaces (not supported by all IOSes). + self.iourc_content = iourc_content if initial_config is not None: self.initial_config = initial_config @@ -209,7 +212,8 @@ class IOUVM(BaseVM): "nvram": self._nvram, "l1_keepalives": self._l1_keepalives, "initial_config": self.relative_initial_config_file, - "use_default_iou_values": self._use_default_iou_values} + "use_default_iou_values": self._use_default_iou_values, + "iourc_path": self.iourc_path} # return the relative path if the IOU image is in the images_path directory server_config = self.manager.config.get_section_config("Server") @@ -250,6 +254,10 @@ class IOUVM(BaseVM): path = os.path.join(self.working_dir, "iourc") if os.path.exists(path): return path + # look for the iourc file in the temporary dir. + path = os.path.join(self.temporary_directory, "iourc") + if os.path.exists(path): + return path return iourc_path @property @@ -322,6 +330,17 @@ class IOUVM(BaseVM): def application_id(self): return self._manager.get_application_id(self.id) + @property + def iourc_content(self): + with open(os.path.join(self.temporary_directory, "iourc")) as f: + return f.read() + + @iourc_content.setter + def iourc_content(self, value): + if value is not None: + with open(os.path.join(self.temporary_directory, "iourc"), "w+") as f: + f.write(value) + @asyncio.coroutine def _library_check(self): """ diff --git a/gns3server/schemas/iou.py b/gns3server/schemas/iou.py index df04039a..83f8fd7f 100644 --- a/gns3server/schemas/iou.py +++ b/gns3server/schemas/iou.py @@ -73,6 +73,10 @@ IOU_CREATE_SCHEMA = { "initial_config_content": { "description": "Initial configuration of the IOU", "type": ["string", "null"] + }, + "iourc_content": { + "description": "Content of the iourc file, if a file exist on servers this variable is ignored. It's mostly for compatibility with < 1.3 releases", + "type": ["string", "null"] } }, "additionalProperties": False, @@ -192,6 +196,10 @@ IOU_OBJECT_SCHEMA = { "use_default_iou_values": { "description": "Use default IOU values", "type": ["boolean", "null"] + }, + "iourc_path": { + "description": "Path of the iourc file used by remote servers", + "type": ["string", "null"] } }, "additionalProperties": False, diff --git a/tests/handlers/api/test_iou.py b/tests/handlers/api/test_iou.py index ecf07f78..bae3076d 100644 --- a/tests/handlers/api/test_iou.py +++ b/tests/handlers/api/test_iou.py @@ -75,6 +75,7 @@ def test_iou_create_with_params(server, project, base_params): params["l1_keepalives"] = True params["initial_config_content"] = "hostname test" params["use_default_iou_values"] = True + params["iourc_content"] = "test" response = server.post("/projects/{project_id}/iou/vms".format(project_id=project.id), params, example=True) assert response.status == 201 @@ -92,6 +93,8 @@ def test_iou_create_with_params(server, project, base_params): with open(initial_config_file(project, response.json)) as f: assert f.read() == params["initial_config_content"] + assert "iourc" in response.json["iourc_path"] + def test_iou_get(server, project, vm): response = server.get("/projects/{project_id}/iou/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), example=True) diff --git a/tests/modules/iou/test_iou_vm.py b/tests/modules/iou/test_iou_vm.py index 42fa4c70..7bbaf769 100644 --- a/tests/modules/iou/test_iou_vm.py +++ b/tests/modules/iou/test_iou_vm.py @@ -367,3 +367,11 @@ def test_invalid_iou_file(loop, vm, iourc_file): with pytest.raises(IOUError): os.remove(iourc_file) loop.run_until_complete(asyncio.async(vm._check_iou_licence())) + + +def test_iourc_content(vm): + + vm.iourc_content = "test" + + with open(os.path.join(vm.temporary_directory, "iourc")) as f: + assert f.read() == "test" diff --git a/tests/modules/test_base_vm.py b/tests/modules/test_base_vm.py new file mode 100644 index 00000000..f12844f9 --- /dev/null +++ b/tests/modules/test_base_vm.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 GNS3 Technologies Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import pytest +import aiohttp +import asyncio +import os +from tests.utils import asyncio_patch + + +from unittest.mock import patch, MagicMock +from gns3server.modules.vpcs.vpcs_vm import VPCSVM +from gns3server.modules.vpcs.vpcs_error import VPCSError +from gns3server.modules.vpcs import VPCS + + +@pytest.fixture(scope="module") +def manager(port_manager): + m = VPCS.instance() + m.port_manager = port_manager + return m + + +@pytest.fixture(scope="function") +def vm(project, manager): + return VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + + +def test_temporary_directory(project, manager): + vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager) + assert isinstance(vm.temporary_directory, str)