..through qemu monitor sockets using fdsend. For the hmp the `get-fd` command is used while for the qmp the `add-fd` command is used, where the fd is added to the first available fdset. Currently the first one is used during NIC hot-add while the second will be used during disk hot-add.
Add also RemoveFdset() method for cleaning up fdsets. Signed-off-by: Dimitris Aragiorgis <[email protected]> --- lib/hypervisor/hv_kvm/monitor.py | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/lib/hypervisor/hv_kvm/monitor.py b/lib/hypervisor/hv_kvm/monitor.py index 7667730..ceb42a9 100644 --- a/lib/hypervisor/hv_kvm/monitor.py +++ b/lib/hypervisor/hv_kvm/monitor.py @@ -29,6 +29,11 @@ import stat import errno import socket import StringIO +import logging +try: + import fdsend # pylint: disable=F0401 +except ImportError: + fdsend = None from ganeti import errors from ganeti import utils @@ -181,6 +186,16 @@ class MonitorSocket(object): """ self.sock.close() + def GetFd(self, fds, kvm_devid): + """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS + + """ + self._check_connection() + + command = "getfd %s\n" % kvm_devid + logging.info("Passing %s fds to %s", fds, self.monitor_filename) + fdsend.sendfds(self.sock, command, fds=fds) + class QmpConnection(MonitorSocket): """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP). @@ -369,6 +384,16 @@ class QmpConnection(MonitorSocket): message[self._ARGUMENTS_KEY] = arguments self._Send(message) + return self._GetResponse(command) + + def _GetResponse(self, command): + """Parse the QMP response + + If error key found in the response message raise HypervisorError. + Ignore any async event and thus return the response message + related to command. + + """ # According the the QMP specification, there are only two reply types to a # command: either error (containing the "error" key) or success (containing # the "return" key). There is also a third possibility, that of an @@ -389,3 +414,52 @@ class QmpConnection(MonitorSocket): continue return response[self._RETURN_KEY] + + def AddFd(self, fds): + """Pass file descriptor to kvm process via qmp socket using SCM_RIGHTS + + Add the fds to an fdset so that they can be used later by hot-add commands + + @type fds: list + @param fds: The list of file descriptors to pass + + @return: The fdset ID that the fds have been added to + (None if operation fails) + + """ + self._check_connection() + + if not fdsend or "add-fd" not in self.supported_commands: + return None + + try: + # Omit fdset-id and let qemu create a new one (see qmp-commands.hx) + command = {"execute": "add-fd"} + fdsend.sendfds(self.sock, serializer.Dump(command), fds=fds) + # Get the response out of the buffer + response = self._GetResponse("add-fd") + fdset = response[self._RETURN_KEY]["fdset-id"] + logging.info("Sent fds %s and added to fdset %s", fds, fdset) + except errors.HypervisorError, err: + # In case _GetResponse() fails + fdset = None + logging.info("Sending fds %s failed: %s", fds, err) + + return fdset + + def RemoveFdset(self, fdset): + """Remove the file descriptor previously passed + + After qemu has dup'd the fd (e.g. during disk hotplug), + it can be safely removed. + + """ + self._check_connection() + # Omit the fd to cleanup all fds in the fdset (see qmp-commands.hx) + command = "remove-fd" + arguments = {"fdset-id": fdset} + logging.info("Removing fdset %s", fdset) + try: + self.Execute(command, arguments=arguments) + except errors.HypervisorError, err: + logging.info("Removing %s fdset failed: %s", fdset, err) -- 1.7.10.4
