[virt-who] Fix wrong logger usage when processing update errors
by Radek Novacek
commit 37bedd235ea78378a1884c523e30018b95baba22
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Tue Jul 29 09:37:33 2014 +0200
Fix wrong logger usage when processing update errors
virtwho.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
---
diff --git a/virtwho.py b/virtwho.py
index e313fb9..81f9c2a 100644
--- a/virtwho.py
+++ b/virtwho.py
@@ -155,13 +155,13 @@ class VirtWho(object):
# Show the result of hypervisorCheckIn
for fail in result['failedUpdate']:
- logger.error("Error during update list of guests: %s", str(fail))
+ self.logger.error("Error during update list of guests: %s", str(fail))
for updated in result['updated']:
guests = [x['guestId'] for x in updated['guestIds']]
- logger.info("Updated host: %s with guests: [%s]", updated['uuid'], ", ".join(guests))
+ self.logger.info("Updated host: %s with guests: [%s]", updated['uuid'], ", ".join(guests))
for created in result['created']:
guests = [x['guestId'] for x in created['guestIds']]
- logger.info("Created host: %s with guests: [%s]", created['uuid'], ", ".join(guests))
+ self.logger.info("Created host: %s with guests: [%s]", created['uuid'], ", ".join(guests))
def run(self):
if self.options.background and self.options.virtType == "libvirt":
9 years, 9 months
[virt-who] Fix hypervisorCheckIn API and add test for it
by Radek Novacek
commit e348e0328fd01abbd608f51e25a7808bd77ecbdc
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Tue Jul 29 09:22:09 2014 +0200
Fix hypervisorCheckIn API and add test for it
manager/satellite/satellite.py | 2 +-
manager/subscriptionmanager/subscriptionmanager.py | 4 +-
tests/test_manager.py | 155 ++++++++++++++++++++
3 files changed, 158 insertions(+), 3 deletions(-)
---
diff --git a/manager/satellite/satellite.py b/manager/satellite/satellite.py
index c1d6484..8f9360d 100644
--- a/manager/satellite/satellite.py
+++ b/manager/satellite/satellite.py
@@ -139,7 +139,7 @@ class Satellite(Manager):
def sendVirtGuests(self, domains):
raise SatelliteError("virt-who does not support sending local hypervisor data to satellite; use rhn-virtualization-host instead")
- def hypervisorCheckIn(self, owner, env, mapping, type=None):
+ def hypervisorCheckIn(self, config, mapping, type=None):
self._connect()
self.logger.info("Sending update in hosts-to-guests mapping: %s" % mapping)
diff --git a/manager/subscriptionmanager/subscriptionmanager.py b/manager/subscriptionmanager/subscriptionmanager.py
index 3b6ce5a..4d35fa7 100644
--- a/manager/subscriptionmanager/subscriptionmanager.py
+++ b/manager/subscriptionmanager/subscriptionmanager.py
@@ -111,14 +111,14 @@ class SubscriptionManager(Manager):
# Send list of guest uuids to the server
self.connection.updateConsumer(self.uuid(), guest_uuids=domains)
- def hypervisorCheckIn(self, owner, env, mapping, type=None):
+ def hypervisorCheckIn(self, config, mapping, type=None):
""" Send hosts to guests mapping to subscription manager. """
self.logger.info("Sending update in hosts-to-guests mapping: %s" % mapping)
self._connect()
# Send the mapping
- return self.connection.hypervisorCheckIn(owner, env, mapping)
+ return self.connection.hypervisorCheckIn(config.owner, config.env, mapping)
def uuid(self):
""" Read consumer certificate and get consumer UUID from it. """
diff --git a/tests/test_manager.py b/tests/test_manager.py
new file mode 100644
index 0000000..f7377d7
--- /dev/null
+++ b/tests/test_manager.py
@@ -0,0 +1,155 @@
+"""
+Test of subscription managers.
+
+Copyright (C) 2014 Radek Novacek <rnovacek(a)redhat.com>
+
+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 2
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+"""
+
+import os
+import shutil
+import logging
+import tempfile
+import subprocess
+from mock import patch, MagicMock, ANY
+
+from base import unittest
+from config import Config
+from manager import Manager, ManagerError
+
+import rhsm.config as rhsm_config
+import rhsm.certificate
+import rhsm.connection
+
+import xmlrpclib
+
+
+class TestManager(unittest.TestCase):
+ """ Test of all available subscription managers. """
+
+ guestInfo = [
+ {
+ 'guestId': '9c927368-e888-43b4-9cdb-91b10431b258',
+ 'attributes': {
+ 'hypervisorType': 'QEMU',
+ 'virtWhoType': 'libvirt',
+ 'active': 1
+ }
+ }
+ ]
+
+ mapping = {
+ '9c927368-e888-43b4-9cdb-91b10431b258': [
+ ''
+ ],
+ 'ad58b739-5288-4cbc-a984-bd771612d670': [
+ '2147647e-6f06-4ac0-982d-6902c259f9d6',
+ 'd5ffceb5-f79d-41be-a4c1-204f836e144a'
+ ]
+ }
+
+
+class TestSubscriptionManager(TestManager):
+ smType = "sam"
+
+ def prepare(self, create_from_file, connection):
+ self.logger = logging.getLogger()
+ self.options = MagicMock()
+ self.options.smType = self.smType
+
+ tempdir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, tempdir)
+
+ config_file = os.path.join(tempdir, "config")
+ with open(config_file, "w") as f:
+ f.write("[rhsm]\nconsumerCertDir=%s\n" % tempdir)
+
+ cert_file = os.path.join(tempdir, "cert.pem")
+ with open(cert_file, "w") as f:
+ f.write("\n")
+
+ rhsm_config.DEFAULT_CONFIG_PATH = config_file
+
+ create_from_file.return_value.cert_uuid = {'CN': 'Test'}
+ connection.return_value = MagicMock()
+
+ @patch("rhsm.certificate.create_from_file")
+ @patch("rhsm.connection.UEPConnection")
+ def test_sendVirtGuests(self, create_from_file, connection):
+ self.prepare(create_from_file, connection)
+ manager = Manager.fromOptions(self.logger, self.options)
+ manager.sendVirtGuests(self.guestInfo)
+ manager.connection.updateConsumer.assert_called_with(ANY, guest_uuids=self.guestInfo)
+
+ @patch("rhsm.certificate.create_from_file")
+ @patch("rhsm.connection.UEPConnection")
+ def test_hypervisorCheckIn(self, create_from_file, connection):
+ self.prepare(create_from_file, connection)
+ manager = Manager.fromOptions(self.logger, self.options)
+ self.options.env = "ENV"
+ self.options.owner = "OWNER"
+ manager.hypervisorCheckIn(self.options, self.mapping)
+ manager.connection.hypervisorCheckIn.assert_called_with(self.options.owner, self.options.env, self.mapping)
+
+
+class TestSatellite(TestManager):
+ smType = "satellite"
+
+ def test_sendVirtGuests(self):
+ logger = logging.getLogger()
+ options = MagicMock()
+ options.smType = self.smType
+
+ manager = Manager.fromOptions(logger, options)
+ self.assertRaises(ManagerError, manager.sendVirtGuests, self.guestInfo)
+
+ @patch("xmlrpclib.Server")
+ def test_hypervisorCheckIn(self, server):
+ logger = logging.getLogger()
+ options = MagicMock()
+ options.smType = self.smType
+
+ manager = Manager.fromOptions(logger, options)
+ options.env = "ENV"
+ options.owner = "OWNER"
+ manager.hypervisorCheckIn(options, self.mapping)
+ manager.server.registration.virt_notify.assert_called_with(ANY, [
+ [
+ 0, 'exists', 'system', {'uuid': '0000000000000000', 'identity': 'host'}
+ ], [
+ 0, 'crawl_began', 'system', {}
+ ], [
+ 0, 'exists', 'domain', {
+ 'state': 'running',
+ 'memory_size': 0,
+ 'name': 'VM from None hypervisor ad58b739-5288-4cbc-a984-bd771612d670',
+ 'virt_type': 'fully_virtualized',
+ 'vcpus': 1,
+ 'uuid': '2147647e6f064ac0982d6902c259f9d6'
+ }
+ ], [
+ 0, 'exists', 'domain', {
+ 'state': 'running',
+ 'memory_size': 0,
+ 'name': 'VM from None hypervisor ad58b739-5288-4cbc-a984-bd771612d670',
+ 'virt_type': 'fully_virtualized',
+ 'vcpus': 1,
+ 'uuid': 'd5ffceb5f79d41bea4c1204f836e144a'
+ }
+ ], [
+ 0, 'crawl_ended', 'system', {}
+ ]
+ ])
+
9 years, 9 months
[virt-who] libvirtd: use event loop instead of reconnecting all the time
by Radek Novacek
commit 6f52a3bbe00121acb5f11d9ec131c90700b27419
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Tue Jul 1 10:57:58 2014 +0200
libvirtd: use event loop instead of reconnecting all the time
tests/test_libvirtd.py | 24 +++++++-----
virt/libvirtd/libvirtd.py | 86 ++++++++++++++++++++++++--------------------
2 files changed, 61 insertions(+), 49 deletions(-)
---
diff --git a/tests/test_libvirtd.py b/tests/test_libvirtd.py
index 6077702..bb3f428 100644
--- a/tests/test_libvirtd.py
+++ b/tests/test_libvirtd.py
@@ -54,24 +54,28 @@ class TestLibvirtd(unittest.TestCase):
self.assertRaises(VirtError, libvirtd.listDomains)
@patch('libvirt.openReadOnly')
- def test_monitoring(self, virt):
+ @patch('threading.Thread')
+ def test_monitoring(self, thread, virt):
event = threading.Event()
LibvirtMonitor().set_event(event)
- LibvirtMonitor()._prepare()
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor().check()
+
+ thread.assert_called()
virt.assert_called_with('')
- virt.return_value.listDomainsID.assert_called()
- virt.return_value.listDefinedDomains.assert_called()
- virt.return_value.closed.assert_called()
+ virt.return_value.domainEventRegister.assert_called()
+ virt.return_value.setKeepAlive.assert_called()
self.assertFalse(event.is_set())
- virt.return_value.listDomainsID.return_value = [1]
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor()._callback()
+ LibvirtMonitor().check()
self.assertTrue(event.is_set())
event.clear()
- virt.return_value.listDomainsID.return_value = []
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor().check()
+ self.assertFalse(event.is_set())
+ event.clear()
+
+ LibvirtMonitor()._callback()
self.assertTrue(event.is_set())
event.clear()
diff --git a/virt/libvirtd/libvirtd.py b/virt/libvirtd/libvirtd.py
index 1e37759..2b7a3b3 100644
--- a/virt/libvirtd/libvirtd.py
+++ b/virt/libvirtd/libvirtd.py
@@ -29,65 +29,72 @@ import virt
eventLoopThread = None
-class LibvirtMonitor(threading.Thread):
+def virEventLoopNativeRun():
+ while True:
+ libvirt.virEventRunDefaultImpl()
+
+
+class LibvirtMonitor(object):
""" Singleton class that performs background event monitoring. """
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
+ print "Creating new instance of LibvirtMonitor"
cls._instance = super(LibvirtMonitor, cls).__new__(cls, *args, **kwargs)
+ cls._instance.logger = logging.getLogger("rhsm-app")
cls._instance.event = None
+ cls._instance.eventLoopThread = None
cls._instance.terminate = threading.Event()
cls._instance.domainIds = []
cls._instance.definedDomains = []
+ cls._instance.vc = None
return cls._instance
STATUS_NOT_STARTED, STATUS_RUNNING, STATUS_DISABLED = range(3)
def _prepare(self):
- self.logger = logging.getLogger("rhsm-app")
self.running = threading.Event()
self.status = LibvirtMonitor.STATUS_NOT_STARTED
- def run(self):
- self._prepare()
- while not self.terminate.isSet():
- self._checkChange()
- time.sleep(5)
-
- def _checkChange(self):
+ def _loop_start(self):
+ libvirt.virEventRegisterDefaultImpl()
+ if self.eventLoopThread is not None and self.eventLoopThread.isAlive():
+ self.eventLoopThread.terminate()
+ self.eventLoopThread = threading.Thread(target=virEventLoopNativeRun, name="libvirtEventLoop")
+ self.eventLoopThread.setDaemon(True)
+ self.eventLoopThread.start()
+ self._create_connection()
+
+ def _create_connection(self):
+ self.vc = libvirt.openReadOnly('')
try:
- virt = libvirt.openReadOnly('')
- except libvirt.libvirtError, e:
- # Show error only once
- if self.status != LibvirtMonitor.STATUS_DISABLED:
- self.logger.debug("Unable to connect to libvirtd, disabling event monitoring")
- self.logger.exception(e)
- self.status = LibvirtMonitor.STATUS_DISABLED
- return
-
- domainIds = virt.listDomainsID()
- definedDomains = virt.listDefinedDomains()
-
- changed = domainIds != self.domainIds or definedDomains != self.definedDomains
-
- self.domainIds = domainIds
- self.definedDomains = definedDomains
-
- virt.close()
-
- if changed and self.event is not None and self.status != LibvirtMonitor.STATUS_NOT_STARTED:
- self.event.set()
-
- if self.status == LibvirtMonitor.STATUS_DISABLED:
- self.logger.debug("Event monitoring resumed")
- self.status = LibvirtMonitor.STATUS_RUNNING
+ self.vc.registerCloseCallback(self._close_callback, None, None)
+ except AttributeError:
+ self.logger.warn("Can't monitor libvirtd restarts due to bug in libvirt-python")
+ self.vc.domainEventRegister(self._callback, None)
+ self.vc.setKeepAlive(5, 3)
+
+ def check(self):
+ if self.eventLoopThread is None or not self.eventLoopThread.isAlive():
+ self.logger.debug("Starting libvirt monitoring event loop")
+ self._loop_start()
+ if self.vc is None or not self.vc.isAlive():
+ self.logger.debug("Reconnecting to libvirtd")
+ self._create_connection()
+
+ def _callback(self, *args, **kwargs):
+ self.event.set()
+
+ def _close_callback(self, *args, **kwargs):
+ self.logger.info("Connection to libvirtd lost, reconnecting")
+ self._create_connection()
def set_event(self, event):
self.event = event
- def stop(self):
- self.terminate.set()
+ def isAlive(self):
+ return self.eventLoopThread is not None and self.eventLoopThread.isAlive()
class Libvirtd(virt.DirectVirt):
@@ -129,7 +136,9 @@ class Libvirtd(virt.DirectVirt):
domains.append(virt.Domain(self.virt, domain))
self.logger.debug("Virtual machine found: %s: %s" % (domainName, domain.UUIDString()))
except libvirt.libvirtError, e:
+ self.virt.close()
raise virt.VirtError(str(e))
+ self.virt.close()
return domains
def canMonitor(self):
@@ -137,9 +146,8 @@ class Libvirtd(virt.DirectVirt):
def startMonitoring(self, event):
monitor = LibvirtMonitor()
- if not monitor.isAlive():
- monitor.set_event(event)
- monitor.start()
+ monitor.set_event(event)
+ monitor.check()
def eventToString(event):
9 years, 10 months
[virt-who] fix password test
by Radek Novacek
commit 0beeb12570a992daacd57fe0067869462a9d3e8a
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Tue Jul 1 10:57:21 2014 +0200
fix password test
Mock checking if it run as root
password/__init__.py | 6 +++++-
tests/test_password.py | 3 ++-
2 files changed, 7 insertions(+), 2 deletions(-)
---
diff --git a/password/__init__.py b/password/__init__.py
index 1c5e867..7e7cf98 100644
--- a/password/__init__.py
+++ b/password/__init__.py
@@ -85,12 +85,16 @@ class Password(object):
raise InvalidKeyFile(str(e))
@classmethod
+ def _can_write(cls):
+ return os.getuid() == 0
+
+ @classmethod
def _read_or_generate_key_iv(cls):
try:
return cls._read_key_iv()
except InvalidKeyFile:
pass
- if os.getuid() != 0:
+ if not cls._can_write():
raise UnwrittableKeyFile("Only root can write keyfile")
key = hexlify(cls._generate_key())
iv = hexlify(cls._generate_key())
diff --git a/tests/test_password.py b/tests/test_password.py
index 177b18e..7396e80 100644
--- a/tests/test_password.py
+++ b/tests/test_password.py
@@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import tempfile
from binascii import hexlify, unhexlify
+from mock import MagicMock
from base import unittest
@@ -51,9 +52,9 @@ class TestPassword(unittest.TestCase):
self.addCleanup(os.unlink, filename)
Password.KEYFILE = filename
pwd = "Test password"
+ Password._can_write = MagicMock(retun_value=True)
encrypted = Password.encrypt(pwd)
self.assertEqual(pwd, Password.decrypt(encrypted))
- self.assertEqual(os)
def testPad(self):
self.assertEqual(hexlify(Password._pad(unhexlify("00010203040506070809"))), "00010203040506070809060606060606")
9 years, 10 months