From 743f1392b56936fb72c7e0991cbd65df82da4563 Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 2 Jun 2015 22:33:38 -0600 Subject: [PATCH] ACPI shutdown support for Qemu VMs. --- gns3server/modules/qemu/qemu_vm.py | 40 ++++++++++++++++--- .../modules/virtualbox/virtualbox_vm.py | 1 + gns3server/schemas/qemu.py | 17 ++++++-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index f27c2518..d7d2bf12 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -27,6 +27,7 @@ import subprocess import shlex import asyncio import socket +import gns3server from .qemu_error import QemuError from ..adapters.ethernet_adapter import EthernetAdapter @@ -36,7 +37,6 @@ from ..nios.nio_nat import NIONAT from ..base_vm import BaseVM from ...schemas.qemu import QEMU_OBJECT_SCHEMA from ...utils.asyncio import monitor_process -from ...config import Config import logging log = logging.getLogger(__name__) @@ -83,6 +83,7 @@ class QemuVM(BaseVM): self._kernel_image = "" self._kernel_command_line = "" self._legacy_networking = False + self._acpi_shutdown = False self._cpu_throttling = 0 # means no CPU throttling self._process_priority = "low" @@ -299,6 +300,30 @@ class QemuVM(BaseVM): log.info('QEMU VM "{name}" [{id}] has disabled legacy networking'.format(name=self._name, id=self._id)) self._legacy_networking = legacy_networking + @property + def acpi_shutdown(self): + """ + Returns either this QEMU VM can be ACPI shutdown. + + :returns: boolean + """ + + return self._acpi_shutdown + + @acpi_shutdown.setter + def acpi_shutdown(self, acpi_shutdown): + """ + Sets either this QEMU VM can be ACPI shutdown. + + :param acpi_shutdown: boolean + """ + + if acpi_shutdown: + log.info('QEMU VM "{name}" [{id}] has enabled ACPI shutdown'.format(name=self._name, id=self._id)) + else: + log.info('QEMU VM "{name}" [{id}] has disabled ACPI shutdown'.format(name=self._name, id=self._id)) + self._acpi_shutdown = acpi_shutdown + @property def cpu_throttling(self): """ @@ -616,14 +641,18 @@ class QemuVM(BaseVM): if self.is_running(): log.info('Stopping QEMU VM "{}" PID={}'.format(self._name, self._process.pid)) try: - self._process.terminate() - self._process.wait() - except subprocess.TimeoutExpired: + if self.acpi_shutdown: + yield from self._control_vm("system_powerdown") + yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=30) + else: + self._process.terminate() + yield from gns3server.utils.asyncio.wait_for_process_termination(self._process, timeout=3) + except asyncio.TimeoutError: self._process.kill() if self._process.returncode is None: log.warn('QEMU VM "{}" PID={} is still running'.format(self._name, self._process.pid)) - self._process = None self.status = "stopped" + self._process = None self._stop_cpulimit() @asyncio.coroutine @@ -674,6 +703,7 @@ class QemuVM(BaseVM): """ log.debug('QEMU VM "{name}" [{id}] is closing'.format(name=self._name, id=self._id)) + self.acpi_shutdown = False yield from self.stop() if self._console: self._manager.port_manager.release_tcp_port(self._console, self._project) diff --git a/gns3server/modules/virtualbox/virtualbox_vm.py b/gns3server/modules/virtualbox/virtualbox_vm.py index 33452363..ab0911f7 100644 --- a/gns3server/modules/virtualbox/virtualbox_vm.py +++ b/gns3server/modules/virtualbox/virtualbox_vm.py @@ -325,6 +325,7 @@ class VirtualBoxVM(BaseVM): if nio and isinstance(nio, NIOUDP): self.manager.port_manager.release_udp_port(nio.lport, self._project) + self.acpi_shutdown = False yield from self.stop() if self._linked_clone: diff --git a/gns3server/schemas/qemu.py b/gns3server/schemas/qemu.py index 3385c3a9..7f597ca6 100644 --- a/gns3server/schemas/qemu.py +++ b/gns3server/schemas/qemu.py @@ -94,6 +94,10 @@ QEMU_CREATE_SCHEMA = { "description": "Use QEMU legagy networking commands (-net syntax)", "type": ["boolean", "null"], }, + "acpi_shutdown": { + "description": "ACPI shutdown support", + "type": ["boolean", "null"], + }, "cpu_throttling": { "description": "Percentage of CPU allowed for QEMU", "minimum": 0, @@ -187,6 +191,10 @@ QEMU_UPDATE_SCHEMA = { "description": "Use QEMU legagy networking commands (-net syntax)", "type": ["boolean", "null"], }, + "acpi_shutdown": { + "description": "ACPI shutdown support", + "type": ["boolean", "null"], + }, "cpu_throttling": { "description": "Percentage of CPU allowed for QEMU", "minimum": 0, @@ -289,6 +297,10 @@ QEMU_OBJECT_SCHEMA = { "description": "Use QEMU legagy networking commands (-net syntax)", "type": "boolean", }, + "acpi_shutdown": { + "description": "ACPI shutdown support", + "type": "boolean", + }, "cpu_throttling": { "description": "Percentage of CPU allowed for QEMU", "minimum": 0, @@ -312,9 +324,8 @@ QEMU_OBJECT_SCHEMA = { "additionalProperties": False, "required": ["vm_id", "project_id", "name", "qemu_path", "hda_disk_image", "hdb_disk_image", "hdc_disk_image", "hdd_disk_image", "ram", "adapters", "adapter_type", "console", - "initrd", "kernel_image", "kernel_command_line", - "legacy_networking", "cpu_throttling", "process_priority", "options" - ] + "initrd", "kernel_image", "kernel_command_line", "legacy_networking", "acpi_shutdown", + "cpu_throttling", "process_priority", "options"] } QEMU_BINARY_LIST_SCHEMA = {