[virt-who] vsdm: make extraction of CN from cert more robust
by Radek Novacek
commit 8d4f397b94f056347bcaffb64c22ba38539fc0fb
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Thu Oct 30 12:47:54 2014 +0100
vsdm: make extraction of CN from cert more robust
The subject might contain different entries than just CN.
virt/vdsm/vdsm.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
---
diff --git a/virt/vdsm/vdsm.py b/virt/vdsm/vdsm.py
index 84cdbc3..af0c797 100644
--- a/virt/vdsm/vdsm.py
+++ b/virt/vdsm/vdsm.py
@@ -21,6 +21,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
+import re
import xmlrpclib
from ConfigParser import SafeConfigParser, NoSectionError, NoOptionError
import subprocess
@@ -68,7 +69,7 @@ class Vdsm(DirectVirt):
out, err = p.communicate()
if p.returncode != 0:
return '0'
- return out.split('=')[-1].strip()
+ return re.search('/CN=([^/]+)/', out).group(1)
def _secureConnect(self):
addr = self._getLocalVdsName(self.trust_store_path)
9 years, 6 months
[virt-who] satellite: fix wrong options used when connecting to satellite
by Radek Novacek
commit ea34f2538726aa5b622eaab128edabc6c9feb77a
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Thu Oct 30 12:45:55 2014 +0100
satellite: fix wrong options used when connecting to satellite
Patch by: Paul Wayper <paulway(a)redhat.com>
manager/satellite/satellite.py | 18 ++++++++++--------
tests/test_satellite.py | 6 +++---
2 files changed, 13 insertions(+), 11 deletions(-)
---
diff --git a/manager/satellite/satellite.py b/manager/satellite/satellite.py
index 8f9360d..1526b4b 100644
--- a/manager/satellite/satellite.py
+++ b/manager/satellite/satellite.py
@@ -43,21 +43,23 @@ class Satellite(Manager):
self.options = options
def _connect(self):
- if not self.options.server.startswith("http://") and not self.options.server.startswith("https://"):
- self.options.server = "https://%s" % self.options.server
- if not self.options.server.endswith("XMLRPC"):
- self.options.server = "%s/XMLRPC" % self.options.server
+ server = self.options.sat_server
+ self.username = self.options.sat_username
+ self.password = self.options.sat_password
+
+ if not server.startswith("http://") and not server.startswith("https://"):
+ server = "https://%s" % server
+ if not server.endswith("XMLRPC"):
+ server = "%s/XMLRPC" % server
- self.username = self.options.username
- self.password = self.options.password
try:
self.force_register = self.options.force_register
except AttributeError:
self.force_register = False
- self.logger.debug("Initializing satellite connection to %s" % self.options.server)
+ self.logger.debug("Initializing satellite connection to %s" % server)
try:
- self.server = xmlrpclib.Server(self.options.server, verbose=0)
+ self.server = xmlrpclib.Server(server, verbose=0)
except Exception:
self.logger.exception("Unable to connect to the Satellite server")
raise SatelliteError("Unable to connect to the Satellite server")
diff --git a/tests/test_satellite.py b/tests/test_satellite.py
index bb781e7..a0344af 100644
--- a/tests/test_satellite.py
+++ b/tests/test_satellite.py
@@ -85,9 +85,9 @@ class FakeSatellite(SimpleXMLRPCServer):
class Options(object):
def __init__(self, server, username, password):
- self.server = server
- self.username = username
- self.password = password
+ self.sat_server = server
+ self.sat_username = username
+ self.sat_password = password
class TestSatellite(TestBase):
9 years, 6 months
[virt-who] libvirt: add support for remote libvirt usage
by Radek Novacek
commit bfc6385a0052eb5425951de21f894a3771032332
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Wed Oct 1 14:28:23 2014 +0200
libvirt: add support for remote libvirt usage
config.py | 46 +++++++++++++++++++++++-------------
tests/test_config.py | 22 +++++++++++++++++
tests/test_libvirtd.py | 38 +++++++++++++++++++++++++++++-
virt-who-config.5 | 6 ++--
virt-who.8 | 19 +++++++++++++++
virt-who.conf | 9 ++++++-
virt/libvirtd/libvirtd.py | 57 ++++++++++++++++++++++++++++++++++++++++++++-
virtwho.py | 23 +++++++++++++++---
8 files changed, 193 insertions(+), 27 deletions(-)
---
diff --git a/config.py b/config.py
index f366180..0df1159 100644
--- a/config.py
+++ b/config.py
@@ -38,7 +38,10 @@ class Config(object):
self._type = type
if self._type not in VIRTWHO_TYPES:
raise InvalidOption('Invalid type "%s", must be one of following %s' % (self._type, ", ".join(VIRTWHO_TYPES)))
- self._server = server
+ if server is None and self._type == 'libvirt':
+ self._server = ''
+ else:
+ self._server = server
self._username = username
self._password = password
self._owner = owner
@@ -60,29 +63,38 @@ class Config(object):
def fromParser(self, name, parser):
type = parser.get(name, "type").lower()
server = username = password = owner = env = None
- if type != 'libvirt':
+ try:
server = parser.get(name, "server")
+ except NoOptionError:
+ # Use '' as libvirt url when not given, for backward compatibility
+ if type == 'libvirt':
+ server = ''
+ else:
+ raise
+ try:
username = parser.get(name, "username")
+ except NoOptionError:
+ username = None
+ try:
+ password = parser.get(name, "password")
+ except NoOptionError:
+ password = None
+ if password is None:
try:
- password = parser.get(name, "password")
+ crypted = parser.get(name, "encrypted_password")
+ password = Password.decrypt(crypted)
except NoOptionError:
password = None
- if password is None:
- try:
- crypted = parser.get(name, "encrypted_password")
- password = Password.decrypt(crypted)
- except NoOptionError:
- password = None
- try:
- owner = parser.get(name, "owner")
- except NoOptionError:
- owner = None
- try:
- env = parser.get(name, "env")
- except NoOptionError:
- env = None
+ try:
+ owner = parser.get(name, "owner")
+ except NoOptionError:
+ owner = None
+ try:
+ env = parser.get(name, "env")
+ except NoOptionError:
+ env = None
return Config(name, type, server, username, password, owner, env)
@property
diff --git a/tests/test_config.py b/tests/test_config.py
index 59e067e..08eb4f2 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -184,3 +184,25 @@ env=staging
self.assertEqual(config2.password, "password")
self.assertEqual(config2.owner, "root")
self.assertEqual(config2.env, "staging")
+
+ def testLibvirtConfig(self):
+ with open(os.path.join(self.config_dir, "test1.conf"), "w") as f:
+ f.write("""
+[test1]
+type=libvirt
+server=1.2.3.4
+username=admin
+password=password
+owner=root
+env=staging
+""")
+ manager = ConfigManager(self.config_dir)
+ self.assertEqual(len(manager.configs), 1)
+ config = manager.configs[0]
+ self.assertEqual(config.name, "test1")
+ self.assertEqual(config.type, "libvirt")
+ self.assertEqual(config.server, "1.2.3.4")
+ self.assertEqual(config.username, "admin")
+ self.assertEqual(config.password, "password")
+ self.assertEqual(config.owner, "root")
+ self.assertEqual(config.env, "staging")
diff --git a/tests/test_libvirtd.py b/tests/test_libvirtd.py
index 58160e2..9eff12d 100644
--- a/tests/test_libvirtd.py
+++ b/tests/test_libvirtd.py
@@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import threading
from base import TestBase
-from mock import patch, Mock
+from mock import patch, Mock, ANY
import logging
from config import Config
@@ -78,3 +78,39 @@ class TestLibvirtd(TestBase):
LibvirtMonitor()._callback()
self.assertTrue(event.is_set())
event.clear()
+
+ @patch('libvirt.openReadOnly')
+ def test_remote_hostname(self, virt):
+ config = Config('test', 'libvirt', 'server')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('qemu+ssh://server/system?no_tty=1')
+
+ @patch('libvirt.openReadOnly')
+ def test_remote_url(self, virt):
+ config = Config('test', 'libvirt', 'abc://server/test')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('abc://server/test?no_tty=1')
+
+ @patch('libvirt.openReadOnly')
+ def test_remote_hostname_with_username(self, virt):
+ config = Config('test', 'libvirt', 'server', 'user')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('qemu+ssh://user@server/system?no_tty=1')
+
+ @patch('libvirt.openReadOnly')
+ def test_remote_url_with_username(self, virt):
+ config = Config('test', 'libvirt', 'abc://server/test', 'user')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('abc://user@server/test?no_tty=1')
+
+ @patch('libvirt.openAuth')
+ def test_remote_hostname_with_username_and_password(self, virt):
+ config = Config('test', 'libvirt', 'server', 'user', 'pass')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('qemu+ssh://user@server/system?no_tty=1', ANY, ANY)
+
+ @patch('libvirt.openAuth')
+ def test_remote_url_with_username_and_password(self, virt):
+ config = Config('test', 'libvirt', 'abc://server/test', 'user', 'pass')
+ Virt.fromConfig(self.logger, config).listDomains()
+ virt.assert_called_with('abc://user@server/test?no_tty=1', ANY, ANY)
diff --git a/virt-who-config.5 b/virt-who-config.5
index a055912..6fbc2a7 100644
--- a/virt-who-config.5
+++ b/virt-who-config.5
@@ -11,13 +11,13 @@ Only required key is \fBtype\fR that has to have one of the allowed virtualizati
Another options that could be supplied are:
.TP
\fBserver\fR
-hostname, IP address or URL of the server that provides virtualization information (not applicable for libvirt and vdsm mode).
+hostname, IP address or URL of the server that provides virtualization information (not applicable for vdsm mode).
.TP
\fBusername\fR
-username for authentication to the server (not applicable for libvirt and vdsm mode).
+username for authentication to the server (not applicable for vdsm mode).
.TP
\fBpassword\fR
-password for authentication to the server (not applicable for libvirt and vdsm mode).
+password for authentication to the server (not applicable for vdsm mode).
.TP
\fBencrypted_password\fR
encrypted password that is generated by virt-who-password(8) utility
diff --git a/virt-who.8 b/virt-who.8
index a189e5e..f4ab3c6 100644
--- a/virt-who.8
+++ b/virt-who.8
@@ -49,6 +49,25 @@ Report host/guest associations to the Subscription Asset Manager [default]
\fB\-\-satellite\fR
Report host/guest associations to the Satellite
.IP
+.SS Libvirt options
+.IP
+Use this options with \fB\-\-libvirt\fR
+.TP
+\fB\-\-libvirt\-owner\fR=\fIOWNER\fR
+Organization who has purchased subscriptions of the products, same as current system registration by default
+.TP
+\fB\-\-libvirt\-env\fR=\fIENV\fR
+Environment where the libvirt server belongs to, same as current system registration by default
+.TP
+\fB\-\-libvirt\-server\fR=\fISERVER\fR
+URL of the remote libvirt server to connect to, local server by default
+.TP
+\fB\-\-libvirt\-username\fR=\fIUSERNAME\fR
+Username for connecting to libvirt, username of current user by default
+.TP
+\fB\-\-libvirt\-password\fR=\fIPASSWORD\fR
+Password for connecting to libvirt
+.IP
.SS vCenter/ESX options
.IP
Use this options with \fB\-\-esx\fR
diff --git a/virt-who.conf b/virt-who.conf
index fa68c7a..eff8133 100644
--- a/virt-who.conf
+++ b/virt-who.conf
@@ -39,7 +39,14 @@ VIRTWHO_DEBUG=0
# Register guest using Hyper-V
#VIRTWHO_HYPERV=0
-# Option for ESX mode
+# Options for Libvirt mode
+#VIRTWHO_LIBVIRT_OWNER=
+#VIRTWHO_LIBVIRT_ENV=
+#VIRTWHO_LIBVIRT_SERVER=
+#VIRTWHO_LIBVIRT_USERNAME=
+#VIRTWHO_LIBVIRT_PASSWORD=
+
+# Options for ESX mode
#VIRTWHO_ESX_OWNER=
#VIRTWHO_ESX_ENV=
#VIRTWHO_ESX_SERVER=
diff --git a/virt/libvirtd/libvirtd.py b/virt/libvirtd/libvirtd.py
index a46869c..60fdb32 100644
--- a/virt/libvirtd/libvirtd.py
+++ b/virt/libvirtd/libvirtd.py
@@ -22,6 +22,7 @@ import time
import logging
import libvirt
import threading
+import urlparse
import virt
@@ -113,6 +114,18 @@ class LibvirtMonitor(object):
return self.eventLoopThread is not None and self.eventLoopThread.isAlive()
+def libvirt_cred_request(credentials, config):
+ """ Callback function for requesting credentials from libvirt """
+ for credential in credentials:
+ if credential[0] == libvirt.VIR_CRED_AUTHNAME:
+ credential[4] = config.username
+ elif credential[0] == libvirt.VIR_CRED_PASSPHRASE:
+ credential[4] = config.password
+ else:
+ return -1
+ return 0
+
+
class Libvirtd(virt.DirectVirt):
""" Class for interacting with libvirt. """
CONFIG_TYPE = "libvirt"
@@ -120,13 +133,55 @@ class Libvirtd(virt.DirectVirt):
def __init__(self, logger, config, registerEvents=True):
self.changedCallback = None
self.logger = logger
+ self.config = config
self.registerEvents = registerEvents
libvirt.registerErrorHandler(lambda ctx, error: None, None)
+ def _get_url(self):
+ if self.config.server:
+ scheme = username = netloc = path = None
+ url = self.config.server
+ if "//" not in url:
+ url = "//" + url
+ splitted_url = urlparse.urlsplit(url)
+
+ netloc = splitted_url.netloc
+
+ if splitted_url.scheme:
+ scheme = splitted_url.scheme
+ else:
+ self.logger.info("Protocol is not specified in libvirt url, using qemu+ssh://")
+ scheme = 'qemu+ssh'
+
+ if self.config.username:
+ username = self.config.username
+ elif splitted_url.username:
+ username = splitted_url.username
+
+ if len(splitted_url.path) > 1:
+ path = splitted_url.path
+ else:
+ self.logger.info("Libvirt path is not specified in the url, using /system")
+ path = '/system'
+
+ return "%(scheme)s://%(username)s%(netloc)s%(path)s?no_tty=1" % {
+ 'username': ("%s@" % username) if username else '',
+ 'scheme': scheme,
+ 'netloc': netloc,
+ 'path': path
+ }
+ return ''
+
def _connect(self):
+ url = self._get_url()
+ self.logger.info("Using libvirt url: %s", url if url else '""')
monitor = LibvirtMonitor()
try:
- self.virt = libvirt.openReadOnly('')
+ if self.config.password:
+ auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE], libvirt_cred_request, self.config]
+ self.virt = libvirt.openAuth(url, auth, libvirt.VIR_CONNECT_RO)
+ else:
+ self.virt = libvirt.openReadOnly(url)
except libvirt.libvirtError, e:
self.logger.exception("Error in libvirt backend")
raise virt.VirtError(str(e))
diff --git a/virtwho.py b/virtwho.py
index 81f9c2a..783bad8 100644
--- a/virtwho.py
+++ b/virtwho.py
@@ -220,6 +220,14 @@ def parseOptions():
managerGroup.add_option("--satellite", action="store_const", dest="smType", const="satellite", help="Report host/guest associations to the Satellite")
parser.add_option_group(managerGroup)
+ libvirtGroup = OptionGroup(parser, "Libvirt options", "Use this options with --libvirt")
+ libvirtGroup.add_option("--libvirt-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products, default is owner of current system")
+ libvirtGroup.add_option("--libvirt-env", action="store", dest="env", default="", help="Environment where the vCenter server belongs to, default is environment of current system")
+ libvirtGroup.add_option("--libvirt-server", action="store", dest="server", default="", help="URL of the libvirt server to connect to, default is empty for libvirt on local computer")
+ libvirtGroup.add_option("--libvirt-username", action="store", dest="username", default="", help="Username for connecting to the libvirt daemon")
+ libvirtGroup.add_option("--libvirt-password", action="store", dest="password", default="", help="Password for connecting to the libvirt daemon")
+ parser.add_option_group(libvirtGroup)
+
esxGroup = OptionGroup(parser, "vCenter/ESX options", "Use this options with --esx")
esxGroup.add_option("--esx-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products")
esxGroup.add_option("--esx-env", action="store", dest="env", default="", help="Environment where the vCenter server belongs to")
@@ -303,14 +311,14 @@ def parseOptions():
if env in ["1", "true"]:
options.virtType = "hyperv"
- def checkEnv(variable, option, name):
+ def checkEnv(variable, option, name, required=True):
"""
If `option` is empty, check enviromental `variable` and return its value.
Exit if it's still empty
"""
if len(option) == 0:
option = os.getenv(variable, "").strip()
- if len(option) == 0:
+ if required and len(option) == 0:
logger.error("Required parameter '%s' is not set, exitting" % name)
sys.exit(1)
return option
@@ -321,6 +329,14 @@ def parseOptions():
if len(options.sat_password) == 0:
options.sat_password = os.getenv("VIRTWHO_SATELLITE_PASSWORD", "")
+ if options.virtType == "libvirt":
+ options.owner = checkEnv("VIRTWHO_LIBVIRT_OWNER", options.owner, "owner", required=False)
+ options.env = checkEnv("VIRTWHO_LIBVIRT_ENV", options.env, "env", required=False)
+ options.server = checkEnv("VIRTWHO_LIBVIRT_SERVER", options.server, "server", required=False)
+ options.username = checkEnv("VIRTWHO_LIBVIRT_USERNAME", options.username, "username", required=False)
+ if len(options.password) == 0:
+ options.password = os.getenv("VIRTWHO_LIBVIRT_PASSWORD", "")
+
if options.virtType == "esx":
options.owner = checkEnv("VIRTWHO_ESX_OWNER", options.owner, "owner")
options.env = checkEnv("VIRTWHO_ESX_ENV", options.env, "env")
@@ -394,8 +410,7 @@ class PIDLock(object):
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
- if logger is not None:
- logger.error("Unable to create pid file: %s" % str(e))
+ print >>sys.stderr, "Unable to create pid file: %s" % str(e)
def __exit__(self, exc_type, exc_value, traceback):
try:
9 years, 6 months