From ac75977ae0d16d132cb5e03d63a4c1a67cad2aa6 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 12 Oct 2015 15:57:37 -0600 Subject: [PATCH] Send a warning notification if there is not enough RAM left to start a VM. Implements #329. --- gns3server/modules/base_vm.py | 19 +++++++++++++++++++ gns3server/modules/dynamips/nodes/router.py | 4 ++++ gns3server/modules/iou/iou_vm.py | 3 +++ gns3server/modules/qemu/qemu_vm.py | 3 +++ .../modules/virtualbox/virtualbox_vm.py | 3 +++ gns3server/modules/vmware/vmware_vm.py | 3 +++ requirements.txt | 1 + setup.py | 3 ++- 8 files changed, 38 insertions(+), 1 deletion(-) diff --git a/gns3server/modules/base_vm.py b/gns3server/modules/base_vm.py index 891c77c2..d21219af 100644 --- a/gns3server/modules/base_vm.py +++ b/gns3server/modules/base_vm.py @@ -21,6 +21,8 @@ import aiohttp import shutil import asyncio import tempfile +import psutil +import platform from pkg_resources import parse_version from ..utils.asyncio import wait_run_in_executor @@ -309,3 +311,20 @@ class BaseVM: """ return self._hw_virtualization + + def check_available_ram(self, requested_ram): + """ + Sends a warning notification if there is not enough RAM on the system to allocate requested RAM. + + :param requested_ram: requested amount of RAM in MB + """ + + available_ram = int(psutil.virtual_memory().available / (1024 * 1024)) + percentage_left = psutil.virtual_memory().percent + if requested_ram > available_ram: + message = '"{}" requires {}MB of RAM to run but there is only {}MB - {}% of RAM left on "{}"'.format(self.name, + requested_ram, + available_ram, + percentage_left, + platform.node()) + self.project.emit("log.warning", {"message": message}) diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index c7ad1cf0..59e40b8e 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -247,6 +247,10 @@ class Router(BaseVM): if elf_header_start != b'\x7fELF\x01\x02\x01': raise DynamipsError('"{}" is not a valid IOS image'.format(self._image)) + # check if there is enough RAM to run + if not self._ghost_flag: + self.check_available_ram(self.ram) + yield from self._hypervisor.send('vm start "{name}"'.format(name=self._name)) self.status = "started" log.info('router "{name}" [{id}] has been started'.format(name=self._name, id=self._id)) diff --git a/gns3server/modules/iou/iou_vm.py b/gns3server/modules/iou/iou_vm.py index 43b601fc..5aa9be93 100644 --- a/gns3server/modules/iou/iou_vm.py +++ b/gns3server/modules/iou/iou_vm.py @@ -492,6 +492,9 @@ class IOUVM(BaseVM): self._create_netmap_config() self._push_configs_to_nvram() + # check if there is enough RAM to run + self.check_available_ram(self.ram) + # created a environment variable pointing to the iourc file. env = os.environ.copy() diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index 3f186baa..b7ffbc3e 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -849,6 +849,9 @@ class QemuVM(BaseVM): except OSError as e: raise QemuError("Could not find free port for the Qemu monitor: {}".format(e)) + # check if there is enough RAM to run + self.check_available_ram(self.ram) + self._command = yield from self._build_command() command_string = " ".join(shlex.quote(s) for s in self._command) try: diff --git a/gns3server/modules/virtualbox/virtualbox_vm.py b/gns3server/modules/virtualbox/virtualbox_vm.py index c23e0cb2..dc84b1fd 100644 --- a/gns3server/modules/virtualbox/virtualbox_vm.py +++ b/gns3server/modules/virtualbox/virtualbox_vm.py @@ -202,6 +202,9 @@ class VirtualBoxVM(BaseVM): yield from self._set_network_options() yield from self._set_serial_console() + # check if there is enough RAM to run + self.check_available_ram(self.ram) + args = [self._vmname] if self._headless: args.extend(["--type", "headless"]) diff --git a/gns3server/modules/vmware/vmware_vm.py b/gns3server/modules/vmware/vmware_vm.py index 9d3d6cc0..df93beda 100644 --- a/gns3server/modules/vmware/vmware_vm.py +++ b/gns3server/modules/vmware/vmware_vm.py @@ -419,6 +419,9 @@ class VMwareVM(BaseVM): yield from self._start_ubridge() self._read_vmx_file() + # check if there is enough RAM to run + if "memsize" in self._vmx_pairs: + self.check_available_ram(int(self._vmx_pairs["memsize"])) self._set_network_options() self._set_serial_console() self._write_vmx_file() diff --git a/requirements.txt b/requirements.txt index f922056e..3fb771a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ Jinja2>=2.7.3 raven>=5.2.0 gns3-netifaces==0.10.4.1 docker-py==1.4.0 +psutil>=2.2.1 \ No newline at end of file diff --git a/setup.py b/setup.py index 234985b9..9ffb10f5 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,8 @@ dependencies = [ "aiohttp>=0.15.1", "Jinja2>=2.7.3", "raven>=5.2.0", - "docker-py>=1.4.0" + "docker-py>=1.4.0", + "psutil>=2.2.1" ] if not sys.platform.startswith("win"):