From fc84cd5d479f164cf34ec33b70e75f917489ac30 Mon Sep 17 00:00:00 2001
From: Guido Trotter <ultrotter@google.com>
Date: Thu, 8 Dec 2011 13:28:32 +0000
Subject: [PATCH] kvm: make qmp connections more robust

Currently qmp fails at connect() time if there are socket errors. (eg.
if the instance was started without qmp). Add some better checking.

Also in the only place where we use it avoid hiding the error connecting
to the socket as a failure to read the password file.

In addition one variable is renamed because its name now conflicts with
the newly imported stat module.

Signed-off-by: Guido Trotter <ultrotter@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/hypervisor/hv_kvm.py | 45 +++++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index b0f6724e4..1e51c3547 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -35,6 +35,7 @@ import struct
 import fcntl
 import shutil
 import socket
+import stat
 import StringIO
 try:
   import affinity   # pylint: disable=F0401
@@ -226,6 +227,19 @@ class QmpConnection:
     self._connected = False
     self._buf = ""
 
+  def _check_socket(self):
+    sock_stat = None
+    try:
+      sock_stat = os.stat(self.monitor_filename)
+    except EnvironmentError, err:
+      if err.errno == errno.ENOENT:
+        raise errors.HypervisorError("No qmp socket found")
+      else:
+        raise errors.HypervisorError("Error checking qmp socket: %s",
+                                     utils.ErrnoOrStr(err))
+    if not stat.S_ISSOCK(sock_stat.st_mode):
+      raise errors.HypervisorError("Qmp socket is not a socket")
+
   def _check_connection(self):
     """Make sure that the connection is established.
 
@@ -244,7 +258,16 @@ class QmpConnection:
     @raise errors.ProgrammerError: when there are data serialization errors
 
     """
-    self.sock.connect(self.monitor_filename)
+    if self._connected:
+      raise errors.ProgrammerError("Cannot connect twice")
+
+    self._check_socket()
+
+    # Check file existance/stuff
+    try:
+      self.sock.connect(self.monitor_filename)
+    except EnvironmentError:
+      raise errors.HypervisorError("Can't connect to qmp socket")
     self._connected = True
 
     # Check if we receive a correct greeting message from the server
@@ -890,10 +913,10 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       return None
 
     _, memory, vcpus = self._InstancePidInfo(pid)
-    stat = "---b-"
+    istat = "---b-"
     times = "0"
 
-    return (instance_name, pid, memory, vcpus, stat, times)
+    return (instance_name, pid, memory, vcpus, istat, times)
 
   def GetAllInstancesInfo(self):
     """Get properties of all instances.
@@ -1433,19 +1456,21 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     # for connection.
     spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
     if spice_password_file:
+      spice_pwd = ""
       try:
         spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
-        qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
-        qmp.connect()
-        arguments = {
-            "protocol": "spice",
-            "password": spice_pwd,
-        }
-        qmp.Execute("set_password", arguments)
       except EnvironmentError, err:
         raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
                                      % (spice_password_file, err))
 
+      qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
+      qmp.connect()
+      arguments = {
+          "protocol": "spice",
+          "password": spice_pwd,
+      }
+      qmp.Execute("set_password", arguments)
+
     for filename in temp_files:
       utils.RemoveFile(filename)
 
-- 
GitLab