[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[et-mgmt-tools] [PATCH] Fossilize public virtinst.util API



# HG changeset patch
# User john levon sun com
# Date 1228924505 28800
# Node ID 1f7482ff5250d388c7b22376304002ce16a01301
# Parent  10a5001f9200d6377e8f016fd67c24c16742a9ad
Fossilize public virtinst.util API

Make virtinst.util API frozen, and move the utility functions into a
private namespace away from the prying eyes of API clients.

As a consequence, create a User class for checking privileges.

Signed-off-by: John Levon <john levon sun com>

diff --git a/virt-clone b/virt-clone
--- a/virt-clone
+++ b/virt-clone
@@ -29,6 +29,7 @@ import locale
 import locale
 import virtinst.cli as cli
 from virtinst.cli import fail
+from virtinst.User import User
 
 locale.setlocale(locale.LC_ALL, '')
 gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
@@ -184,9 +185,8 @@ def main():
 
     logging.debug("start clone with HV " + options.connect)
 
-    if options.connect is None or options.connect.lower()[0:3] == "xen":
-        if not virtinst.util.privileged_user():
-            fail(_("Must be root to clone Xen guests"))
+    if not User.current().has_priv(User.PRIV_CLONE, options.connect):
+        fail(_("Must be privileged to clone Xen guests"))
 
     conn = cli.getConnection(options.connect)
     design = clmgr.CloneDesign(connection=conn)
diff --git a/virtinst/CloneManager.py b/virtinst/CloneManager.py
--- a/virtinst/CloneManager.py
+++ b/virtinst/CloneManager.py
@@ -23,7 +23,7 @@ import libxml2
 import libxml2
 import logging
 import urlgrabber.progress as progress
-import util
+import _util
 import libvirt
 import Guest
 from VirtualDisk import VirtualDisk
@@ -263,7 +263,7 @@ class CloneDesign(object):
             node[0].setContent(self._clone_uuid)
         else:
             while 1:
-                uuid = util.uuidToString(util.randomUUID())
+                uuid = _util.uuidToString(_util.randomUUID())
                 if self._check_uuid(uuid) == True:
                     continue
                 else:
@@ -278,7 +278,7 @@ class CloneDesign(object):
                 node[0].setContent(self._clone_mac[i-1])
             except Exception:
                 while 1:
-                    mac = util.randomMAC(typ)
+                    mac = _util.randomMAC(typ)
                     dummy, msg = self._check_mac(mac)
                     if msg is not None:
                         continue
@@ -396,7 +396,7 @@ class CloneDesign(object):
         for i in lst:
             mode = os.stat(i)[stat.ST_MODE]
             if stat.S_ISBLK(mode):
-                size.append(util.blkdev_size(i))
+                size.append(_util.blkdev_size(i))
                 typ.append(False)
             elif stat.S_ISREG(mode):
                 size.append(os.path.getsize(i))
@@ -450,7 +450,7 @@ class CloneDesign(object):
                 continue
             mode = os.stat(i)[stat.ST_MODE]
             if stat.S_ISBLK(mode):
-                size.append(util.blkdev_size(i))
+                size.append(_util.blkdev_size(i))
                 typ.append(False)
             elif stat.S_ISREG(mode):
                 size.append(os.path.getsize(i))
diff --git a/virtinst/DistroManager.py b/virtinst/DistroManager.py
--- a/virtinst/DistroManager.py
+++ b/virtinst/DistroManager.py
@@ -22,9 +22,10 @@
 
 import logging
 import os
-import util
+import _util
 import Guest
 from VirtualDisk import VirtualDisk
+from User import User
 from virtinst import _virtinst as _
 
 import virtinst
@@ -158,7 +159,7 @@ class DistroInstaller(Guest.Installer):
             logging.debug("DistroInstaller location is a (poolname, volname)"
                           " tuple")
         elif os.path.exists(os.path.abspath(val)) \
-             and (not self.conn or not util.is_uri_remote(self.conn.getURI())):
+             and (not self.conn or not _util.is_uri_remote(self.conn.getURI())):
             val = os.path.abspath(val)
             logging.debug("DistroInstaller location is a local "
                           "file/path: %s" % val)
@@ -178,8 +179,8 @@ class DistroInstaller(Guest.Installer):
         elif (val.startswith("http://";) or val.startswith("ftp://";) or
               val.startswith("nfs:")):
             logging.debug("DistroInstaller location is a network source.")
-        elif self.conn and util.is_storage_capable(self.conn) and \
-             util.is_uri_remote(self.conn.getURI()):
+        elif self.conn and _util.is_storage_capable(self.conn) and \
+             _util.is_uri_remote(self.conn.getURI()):
             # If conn is specified, pass the path to a VirtualDisk object
             # and see what comes back
             try:
@@ -193,8 +194,9 @@ class DistroInstaller(Guest.Installer):
                                "or FTP network install source, or an existing "
                                "local file/device"))
 
-        if val.startswith("nfs:") and not util.privileged_user():
-            raise ValueError(_("NFS installations are only supported as root"))
+        if (val.startswith("nfs:") and not
+            User.current().has_priv(User.PRIV_NFS_MOUNT, self.conn.getURI())):
+            raise ValueError(_('Privilege is required for NFS installations'))
 
         self._location = val
     location = property(get_location, set_location)
diff --git a/virtinst/FullVirtGuest.py b/virtinst/FullVirtGuest.py
--- a/virtinst/FullVirtGuest.py
+++ b/virtinst/FullVirtGuest.py
@@ -20,7 +20,7 @@
 # MA 02110-1301 USA.
 
 import os
-import util
+import _util
 import DistroManager
 import logging
 import time
@@ -38,7 +38,7 @@ class FullVirtGuest(Guest):
             installer = DistroManager.DistroInstaller(type = type, os_type = "hvm")
         Guest.__init__(self, type, connection, hypervisorURI, installer)
         self.disknode = "hd"
-        self.features = { "acpi": None, "pae": util.is_pae_capable(), "apic": None }
+        self.features = { "acpi": None, "pae": _util.is_pae_capable(), "apic": None }
         if arch is None:
             arch = platform.machine()
         self.arch = arch
diff --git a/virtinst/Guest.py b/virtinst/Guest.py
--- a/virtinst/Guest.py
+++ b/virtinst/Guest.py
@@ -26,7 +26,7 @@ import re
 import re
 import libxml2
 import urlgrabber.progress as progress
-import util
+import _util
 import libvirt
 import platform
 import __builtin__
@@ -131,7 +131,7 @@ class VirtualNetworkInterface(VirtualDev
                 logging.warn("conflict_net: Failed to lookup domain %d" % name)
 
         # get the Host's NIC MACaddress
-        hostdevs = util.get_host_network_devices()
+        hostdevs = _util.get_host_network_devices()
 
         if self.countMACaddr(vms) > 0:
             return (True, _("The MAC address you entered is already in use by another active virtual machine."))
@@ -145,7 +145,7 @@ class VirtualNetworkInterface(VirtualDev
     def setup(self, conn):
         if self.macaddr is None:
             while 1:
-                self.macaddr = util.randomMAC(type=conn.getType().lower())
+                self.macaddr = _util.randomMAC(type=conn.getType().lower())
                 if self.is_conflict_net(conn)[1] is not None:
                     continue
                 else:
@@ -159,7 +159,7 @@ class VirtualNetworkInterface(VirtualDev
                     raise RuntimeError(msg)
 
         if not self.bridge and self.type == "bridge":
-            self.bridge = util.default_bridge()
+            self.bridge = _util.default_bridge()
 
     def get_xml_config(self):
         src_xml = ""
@@ -192,7 +192,7 @@ class VirtualNetworkInterface(VirtualDev
             try:
                 for mac in ctx.xpathEval("/domain/devices/interface/mac"):
                     macaddr = mac.xpathEval("attribute::address")[0].content
-                    if macaddr and util.compareMAC(self.macaddr, macaddr) == 0:
+                    if macaddr and _util.compareMAC(self.macaddr, macaddr) == 0:
                         count += 1
             finally:
                 if ctx is not None:
@@ -250,7 +250,7 @@ class VirtualGraphics(object):
         return self._keymap
     def set_keymap(self, val):
         if not val:
-            val = util.default_keymap()
+            val = _util.default_keymap()
         if not val or type(val) != type("string"):
             raise ValueError, _("Keymap must be a string")
         if len(val) > 16:
@@ -352,7 +352,7 @@ class Installer(object):
             return '/var/tmp'
         if self.type == "xen" and os.path.exists(XEN_SCRATCH):
             return XEN_SCRATCH
-        if util.privileged_user() and os.path.exists(LIBVIRT_SCRATCH):
+        if os.geteuid() == 0 and os.path.exists(LIBVIRT_SCRATCH):
             return LIBVIRT_SCRATCH
         else:
             return os.path.expanduser("~/.virtinst/boot")
@@ -407,7 +407,7 @@ class Installer(object):
                            conn=None, kernel=None, bootdev=None):
         osblob = ""
         if not isinstall and not ishvm:
-            return "<bootloader>%s</bootloader>" % util.pygrub_path(conn)
+            return "<bootloader>%s</bootloader>" % _util.pygrub_path(conn)
 
         osblob = "<os>\n"
 
@@ -425,9 +425,9 @@ class Installer(object):
             osblob += "    <loader>%s</loader>\n" % loader
 
         if isinstall and kernel and kernel["kernel"]:
-            osblob += "    <kernel>%s</kernel>\n"   % util.xml_escape(kernel["kernel"])
-            osblob += "    <initrd>%s</initrd>\n"   % util.xml_escape(kernel["initrd"])
-            osblob += "    <cmdline>%s</cmdline>\n" % util.xml_escape(kernel["extraargs"])
+            osblob += "    <kernel>%s</kernel>\n"   % _util.xml_escape(kernel["kernel"])
+            osblob += "    <initrd>%s</initrd>\n"   % _util.xml_escape(kernel["initrd"])
+            osblob += "    <cmdline>%s</cmdline>\n" % _util.xml_escape(kernel["extraargs"])
         elif bootdev is not None:
             osblob += "    <boot dev='%s'/>\n" % bootdev
 
@@ -466,7 +466,7 @@ class Installer(object):
         @type L{Guest}
         """
 
-        if util.is_uri_remote(guest.conn.getURI()):
+        if _util.is_uri_remote(guest.conn.getURI()):
             # XXX: Use block peek for this?
             return True
 
@@ -479,7 +479,7 @@ class Installer(object):
             fd = os.open(guest.disks[0].path, os.O_RDONLY)
         except OSError, (err, msg):
             logging.debug("Failed to open guest disk: %s" % msg)
-            if err == errno.EACCES and not util.privileged_user():
+            if err == errno.EACCES and os.geteuid() != 0:
                 return True # non root might not have access to block devices
             else:
                 raise
@@ -624,7 +624,7 @@ class Guest(object):
     def get_vcpus(self):
         return self._vcpus
     def set_vcpus(self, val):
-        maxvcpus = util.get_max_vcpus(self.conn, self.type)
+        maxvcpus = _util.get_max_vcpus(self.conn, self.type)
         if type(val) is not int or val < 1:
             raise ValueError, _("Number of vcpus must be a postive integer.")
         if val > maxvcpus:
@@ -642,7 +642,7 @@ class Guest(object):
         if re.match("^[0-9,-]*$", val) is None:
             raise ValueError, _("cpuset can only contain numeric, ',', or '-' characters")
 
-        pcpus = util.get_phy_cpus(self.conn)
+        pcpus = _util.get_phy_cpus(self.conn)
         for c in val.split(','):
             if c.find('-') != -1:
                 (x, y) = c.split('-')
@@ -1061,7 +1061,7 @@ class Guest(object):
     def _set_defaults(self):
         if self.uuid is None:
             while 1:
-                self.uuid = util.uuidToString(util.randomUUID())
+                self.uuid = _util.uuidToString(_util.randomUUID())
                 try:
                     if self.conn.lookupByUUIDString(self.uuid) is not None:
                         continue
diff --git a/virtinst/ImageManager.py b/virtinst/ImageManager.py
--- a/virtinst/ImageManager.py
+++ b/virtinst/ImageManager.py
@@ -23,7 +23,7 @@ import CapabilitiesParser as Cap
 import CapabilitiesParser as Cap
 from VirtualDisk import VirtualDisk
 import os
-import util
+import _util
 from virtinst import _virtinst as _
 
 class ImageInstallerException(Exception):
@@ -101,7 +101,7 @@ class ImageInstaller(Guest.Installer):
             d = VirtualDisk(p, s,
                             device = device,
                             type = VirtualDisk.TYPE_FILE)
-            if self.boot_caps.type == "xen" and util.is_blktap_capable():
+            if self.boot_caps.type == "xen" and _util.is_blktap_capable():
                 d.driver_name = VirtualDisk.DRIVER_TAP
             d.target = m.target
 
@@ -127,9 +127,9 @@ class ImageInstaller(Guest.Installer):
         if loader:
             osblob += "    <loader>%s</loader>\n" % loader
         if self.boot_caps.kernel:
-            osblob += "    <kernel>%s</kernel>\n"   % util.xml_escape(self._abspath(self.boot_caps.kernel))
-            osblob += "    <initrd>%s</initrd>\n"   % util.xml_escape(self._abspath(self.boot_caps.initrd))
-            osblob += "    <cmdline>%s</cmdline>\n" % util.xml_escape(self.boot_caps.cmdline)
+            osblob += "    <kernel>%s</kernel>\n"   % _util.xml_escape(self._abspath(self.boot_caps.kernel))
+            osblob += "    <initrd>%s</initrd>\n"   % _util.xml_escape(self._abspath(self.boot_caps.initrd))
+            osblob += "    <cmdline>%s</cmdline>\n" % _util.xml_escape(self.boot_caps.cmdline)
             osblob += "  </os>"
         elif hvm:
             if self.boot_caps.bootdev:
@@ -137,7 +137,7 @@ class ImageInstaller(Guest.Installer):
             osblob += "  </os>"
         elif self.boot_caps.loader == "pygrub" or (self.boot_caps.loader is None and self.boot_caps.type == "xen"):
             osblob += "  </os>\n"
-            osblob += "  <bootloader>%s</bootloader>" % util.pygrub_path(conn)
+            osblob += "  <bootloader>%s</bootloader>" % _util.pygrub_path(conn)
 
         return osblob
 
diff --git a/virtinst/Storage.py b/virtinst/Storage.py
--- a/virtinst/Storage.py
+++ b/virtinst/Storage.py
@@ -52,7 +52,7 @@ import logging
 import logging
 from xml.sax.saxutils import escape
 
-import util
+import _util
 from virtinst import _virtinst as _
 
 DEFAULT_DEV_TARGET = "/dev"
@@ -112,7 +112,7 @@ class StorageObject(object):
     def set_conn(self, val):
         if not isinstance(val, libvirt.virConnect):
             raise ValueError(_("'conn' must be a libvirt connection object."))
-        if not util.is_storage_capable(val):
+        if not _util.is_storage_capable(val):
             raise ValueError(_("Passed connection is not libvirt storage "
                                "capable"))
         self._conn = val
@@ -278,7 +278,7 @@ class StoragePool(StorageObject):
         self._source_path = None
         if not uuid:
             self._uuid = None
-        self._random_uuid = util.uuidToString(util.randomUUID())
+        self._random_uuid = _util.uuidToString(_util.randomUUID())
 
     # Properties used by all pools
     def get_type(self):
@@ -705,7 +705,7 @@ class StorageVolume(StorageObject):
         pool_object = StorageVolume.lookup_pool_by_name(pool_object=pool_object,
                                                         pool_name=pool_name,
                                                         conn=conn)
-        return StoragePool.get_volume_for_pool(util.get_xml_path(pool_object.XMLDesc(0), "/pool/@type"))
+        return StoragePool.get_volume_for_pool(_util.get_xml_path(pool_object.XMLDesc(0), "/pool/@type"))
     get_volume_for_pool = staticmethod(get_volume_for_pool)
 
     def find_free_name(name, pool_object=None, pool_name=None, conn=None,
@@ -756,7 +756,7 @@ class StorageVolume(StorageObject):
         if pool_name is not None and pool_object is None:
             if conn is None:
                 raise ValueError(_("'conn' must be specified with 'pool_name'"))
-            if not util.is_storage_capable(conn):
+            if not _util.is_storage_capable(conn):
                 raise ValueError(_("Connection does not support storage "
                                    "management."))
             try:
diff --git a/virtinst/User.py b/virtinst/User.py
new file mode 100644
--- /dev/null
+++ b/virtinst/User.py
@@ -0,0 +1,74 @@
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# 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 platform
+import os
+
+class User(object):
+    """Defines a particular user account."""
+
+    PRIV_CLONE = 1
+    PRIV_NFS_MOUNT = 2
+    PRIV_QEMU_SYSTEM = 3
+    PRIV_CREATE_DOMAIN = 4
+    PRIV_CREATE_NETWORK = 5
+
+    _privs = [ PRIV_CLONE, PRIV_NFS_MOUNT, PRIV_QEMU_SYSTEM,
+        PRIV_CREATE_DOMAIN, PRIV_CREATE_NETWORK ]
+
+    def __init__(self, euid):
+        self._euid = euid
+
+    def has_priv(self, priv, conn=None):
+        """Return if the given user is privileged enough to perform the
+           given operation. This isn't entirely accurate currently,
+           especially on Solaris."""
+
+        if priv not in self._privs:
+            raise ValueError('unknown privilege %s' % priv)
+
+        if priv == self.PRIV_QEMU_SYSTEM:
+            return self._euid == 0
+
+        if platform.system() != 'SunOS':
+            is_xen = not conn or conn.lower()[0:3] == 'xen'
+            if priv in [ self.PRIV_CLONE, self.PRIV_CREATE_DOMAIN ]:
+                if is_xen:
+                    return self._euid == 0
+                return True
+
+            return self._euid == 0
+
+        # Not easy to work out!
+        if self._euid != User.current()._euid:
+            return self._euid == 0
+
+        import ucred
+        cred = ucred.get(os.getpid())
+        if priv in [ self.PRIV_CLONE, self.PRIV_CREATE_DOMAIN, self.PRIV_CREATE_NETWORK ]:
+            return cred.has_priv('Effective', 'virt_manage')
+        if priv == self.PRIV_NFS_MOUNT:
+            return (cred.has_priv('Effective', 'sys_mount') and
+                cred.has_priv('Effective', 'net_privaddr'))
+
+    def current():
+        """Return the current user."""
+        return User(os.geteuid())
+
+    current = staticmethod(current)
diff --git a/virtinst/VirtualDevice.py b/virtinst/VirtualDevice.py
--- a/virtinst/VirtualDevice.py
+++ b/virtinst/VirtualDevice.py
@@ -22,7 +22,7 @@ import libvirt
 import libvirt
 
 import CapabilitiesParser
-import util
+import _util
 from virtinst import _virtinst as _
 
 class VirtualDevice(object):
@@ -45,7 +45,7 @@ class VirtualDevice(object):
 
         self.__remote = None
         if self.conn:
-            self.__remote = util.is_uri_remote(self.conn.getURI())
+            self.__remote = _util.is_uri_remote(self.conn.getURI())
 
         self._caps = None
         if self.conn:
diff --git a/virtinst/VirtualDisk.py b/virtinst/VirtualDisk.py
--- a/virtinst/VirtualDisk.py
+++ b/virtinst/VirtualDisk.py
@@ -24,7 +24,7 @@ import logging
 import logging
 import libvirt
 
-import util
+import _util
 import Storage
 from VirtualDevice import VirtualDevice
 from virtinst import _virtinst as _
@@ -302,7 +302,7 @@ class VirtualDisk(VirtualDevice):
                                "('poolname', 'volname')"))
         if not self.conn:
             raise ValueError(_("'volName' requires a passed connection."))
-        if not util.is_storage_capable(self.conn):
+        if not _util.is_storage_capable(self.conn):
             raise ValueError(_("Connection does not support storage lookup."))
         try:
             pool = self.conn.storagePoolLookupByName(name_tuple[0])
@@ -321,7 +321,7 @@ class VirtualDisk(VirtualDevice):
     def __check_if_path_managed(self):
         vol = None
         verr = None
-        pool = util.lookup_pool_by_path(self.conn,
+        pool = _util.lookup_pool_by_path(self.conn,
                                         os.path.dirname(self.path))
         if pool:
             try:
@@ -378,7 +378,7 @@ class VirtualDisk(VirtualDevice):
         # if no obj: if remote, error
         storage_capable = False
         if self.conn:
-            storage_capable = util.is_storage_capable(self.conn)
+            storage_capable = _util.is_storage_capable(self.conn)
         if not storage_capable and self._is_remote():
             raise ValueError, _("Connection doesn't support remote storage.")
 
@@ -528,7 +528,7 @@ class VirtualDisk(VirtualDevice):
         elif self.path:
             path = self.path
         if path:
-            path = util.xml_escape(path)
+            path = _util.xml_escape(path)
 
         ret = "    <disk type='%(type)s' device='%(device)s'>\n" % { "type": self.type, "device": self.device }
         if not(self.driver_name is None):
diff --git a/virtinst/__init__.py b/virtinst/__init__.py
--- a/virtinst/__init__.py
+++ b/virtinst/__init__.py
@@ -34,3 +34,4 @@ from LiveCDInstaller import LiveCDInstal
 from LiveCDInstaller import LiveCDInstaller
 from ImageManager import ImageInstaller
 from CloneManager import CloneDesign
+from User import User
diff --git a/virtinst/util.py b/virtinst/_util.py
copy from virtinst/util.py
copy to virtinst/_util.py
--- a/virtinst/_util.py
+++ b/virtinst/_util.py
@@ -1,5 +1,3 @@
-#
-# Utility functions used for guest installation
 #
 # Copyright 2006  Red Hat, Inc.
 # Jeremy Katz <katzj redhat com>
@@ -18,246 +16,17 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA 02110-1301 USA.
+#
 
-import platform
-import random
-import os.path
-import re
-import libxml2
-import logging
-from sys import stderr
+#
+# Internal utility functions. These do NOT form part of the API and must
+# not be used by clients.
+#
 
-import libvirt
-from virtinst import _virtinst as _
-from virtinst import CapabilitiesParser
+import os
 
+from virtinst import util
 
-KEYBOARD_DIR = "/etc/sysconfig/keyboard"
-XORG_CONF = "/etc/X11/xorg.conf"
-
-def default_route():
-    route_file = "/proc/net/route"
-    d = file(route_file)
-
-    defn = 0
-    for line in d.xreadlines():
-        info = line.split()
-        if (len(info) != 11): # 11 = typical num of fields in the file
-            print >> stderr, _("Invalid line length while parsing %s.") %(route_file)
-            print >> stderr, _("Defaulting bridge to xenbr%d") % (defn)
-            break
-        try:
-            route = int(info[1],16)
-            if route == 0:
-                return info[0]
-        except ValueError:
-            continue
-    return None
-
-# Legacy for compat only.
-def default_bridge():
-    rt = default_route()
-    if rt is None:
-        defn = None
-    else:
-        defn = int(rt[-1])
-
-    if defn is None:
-        return "xenbr0"
-    else:
-        return "xenbr%d"%(defn)
-
-def default_network(conn):
-    dev = default_route()
-
-    if dev is not None and not is_uri_remote(conn.getURI()):
-        # New style peth0 == phys dev, eth0 == bridge, eth0 == default route
-        if os.path.exists("/sys/class/net/%s/bridge" % dev):
-            return ["bridge", dev]
-
-        # Old style, peth0 == phys dev, eth0 == netloop, xenbr0 == bridge,
-        # vif0.0 == netloop enslaved, eth0 == default route
-        defn = int(dev[-1])
-        if os.path.exists("/sys/class/net/peth%d/brport" % defn) and \
-           os.path.exists("/sys/class/net/xenbr%d/bridge" % defn):
-            return ["bridge", "xenbr%d" % defn]
-
-    return ["network", "default"]
-
-def default_connection():
-    if os.path.exists("/var/lib/xend") and os.path.exists("/proc/xen"):
-        return "xen"
-    elif os.path.exists("/usr/bin/qemu") or \
-         os.path.exists("/usr/bin/qemu-kvm") or \
-         os.path.exists("/usr/bin/kvm") or \
-         os.path.exists("/usr/bin/xenner"):
-        if privileged_user():
-            return "qemu:///system"
-        else:
-            return "qemu:///session"
-    return None
-
-def get_cpu_flags():
-    f = open("/proc/cpuinfo")
-    lines = f.readlines()
-    f.close()
-    for line in lines:
-        if not line.startswith("flags"):
-            continue
-        # get the actual flags
-        flags = line[:-1].split(":", 1)[1]
-        # and split them
-        flst = flags.split(" ")
-        return flst
-    return []
-
-def is_pae_capable():
-    """Determine if a machine is PAE capable or not."""
-    flags = get_cpu_flags()
-    if "pae" in flags:
-        return True
-    return False
-
-def is_hvm_capable():
-    """Determine if a machine is HVM capable or not."""
-
-    caps = ""
-    if os.path.exists("/sys/hypervisor/properties/capabilities"):
-        caps = open("/sys/hypervisor/properties/capabilities").read()
-    if caps.find("hvm") != -1:
-        return True
-    return False
-
-def is_kqemu_capable():
-    return os.path.exists("/dev/kqemu")
-
-def is_kvm_capable():
-    return os.path.exists("/dev/kvm")
-
-def is_blktap_capable():
-    #return os.path.exists("/dev/xen/blktapctrl")
-    f = open("/proc/modules")
-    lines = f.readlines()
-    f.close()
-    for line in lines:
-        if line.startswith("blktap ") or line.startswith("xenblktap "):
-            return True
-    return False
-
-def get_default_arch():
-    arch = os.uname()[4]
-    if arch == "x86_64":
-        return "x86_64"
-    return "i686"
-
-# this function is directly from xend/server/netif.py and is thus
-# available under the LGPL,
-# Copyright 2004, 2005 Mike Wray <mike wray hp com>
-# Copyright 2005 XenSource Ltd
-def randomMAC(type = "xen"):
-    """Generate a random MAC address.
-
-    00-16-3E allocated to xensource
-    54-52-00 used by qemu/kvm
-
-    The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt.
-
-    The remaining 3 fields are random, with the first bit of the first
-    random field set 0.
-
-    >>> randomMAC().startswith("00:16:36")
-    True
-    >>> randomMAC("foobar").startswith("00:16:36")
-    True
-    >>> randomMAC("xen").startswith("00:16:36")
-    True
-    >>> randomMAC("qemu").startswith("54:52:00")
-    True
-
-    @return: MAC address string
-    """
-    ouis = { 'xen': [ 0x00, 0x16, 0x36 ], 'qemu': [ 0x54, 0x52, 0x00 ] }
-
-    try:
-        oui = ouis[type]
-    except KeyError:
-        oui = ouis['xen']
-
-    mac = oui + [
-            random.randint(0x00, 0x7f),
-            random.randint(0x00, 0xff),
-            random.randint(0x00, 0xff) ]
-    return ':'.join(map(lambda x: "%02x" % x, mac))
-
-# the following three functions are from xend/uuid.py and are thus
-# available under the LGPL,
-# Copyright 2005 Mike Wray <mike wray hp com>
-# Copyright 2005 XenSource Ltd
-def randomUUID():
-    """Generate a random UUID."""
-
-    return [ random.randint(0, 255) for dummy in range(0, 16) ]
-
-def uuidToString(u):
-    return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
-                     "%02x" * 6]) % tuple(u)
-
-def uuidFromString(s):
-    s = s.replace('-', '')
-    return [ int(s[i : i + 2], 16) for i in range(0, 32, 2) ]
-
-# the following function quotes from python2.5/uuid.py
-def get_host_network_devices():
-    device = []
-    for dirname in ['', '/sbin/', '/usr/sbin']:
-        executable = os.path.join(dirname, "ifconfig")
-        if not os.path.exists(executable):
-            continue
-        try:
-            cmd = 'LC_ALL=C %s -a 2>/dev/null' % (executable)
-            pipe = os.popen(cmd)
-        except IOError:
-            continue
-        for line in pipe:
-            if line.find("encap:Ethernet") > 0:
-                words = line.lower().split()
-                for i in range(len(words)):
-                    if words[i] == "hwaddr":
-                        device.append(words)
-    return device
-
-def get_max_vcpus(conn, type=None):
-    """@conn libvirt connection to poll for max possible vcpus
-       @type optional guest type (kvm, etc.)"""
-    if type is None:
-        type = conn.getType()
-    try:
-        m = conn.getMaxVcpus(type.lower())
-    except libvirt.libvirtError:
-        m = 32
-    return m
-
-def get_phy_cpus(conn):
-    """Get number of physical CPUs."""
-    hostinfo = conn.getInfo()
-    pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7]
-    return pcpus
-
-def system(cmd):
-    st = os.system(cmd)
-    if os.WIFEXITED(st) and os.WEXITSTATUS(st) != 0:
-        raise OSError("Failed to run %s, exited with %d" % 
-                      (cmd, os.WEXITSTATUS(st)))
-
-def xml_escape(str):
-    """Replaces chars ' " < > & with xml safe counterparts"""
-    str = str.replace("&", "&amp;")
-    str = str.replace("'", "&apos;")
-    str = str.replace("\"", "&quot;")
-    str = str.replace("<", "&lt;")
-    str = str.replace(">", "&gt;")
-    return str
- 
 def blkdev_size(path):
     """Return the size of the block device.  We can't use os.stat() as
     that returns zero on many platforms."""
@@ -267,255 +36,33 @@ def blkdev_size(path):
     os.close(fd)
     return size
 
-def compareMAC(p, q):
-    """Compare two MAC addresses"""
-    pa = p.split(":")
-    qa = q.split(":")
-
-    if len(pa) != len(qa):
-        if p > q:
-            return 1
-        else:
-            return -1
-
-    for i in xrange(len(pa)):
-        n = int(pa[i], 0x10) - int(qa[i], 0x10)
-        if n > 0:
-            return 1
-        elif n < 0:
-            return -1
-    return 0
-
-def _xorg_keymap():
-    """Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to
-       map it to a keymap supported by qemu"""
-
-    kt = None
-    try:
-        f = open(XORG_CONF, "r")
-    except IOError, e:
-        logging.debug('Could not open "%s": %s ' % (XORG_CONF, str(e)))
-    else:
-        keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P<kt>[a-z-]+)"')
-        for line in f:
-            m = keymap_re.match(line)
-            if m:
-                kt = m.group('kt')
-                break
-        else:
-            logging.debug("Didn't find keymap in '%s'!" % XORG_CONF)
-        f.close()
-    return kt
-
-def default_keymap():
-    """Look in /etc/sysconfig for the host machine's keymap, and attempt to
-       map it to a keymap supported by qemu"""
-
-    # Set keymap to same as hosts
-    import keytable
-    keymap = "en-us"
-    kt = None
-    try:
-        f = open(KEYBOARD_DIR, "r")
-    except IOError, e:
-        logging.debug('Could not open "/etc/sysconfig/keyboard" ' + str(e))
-        kt = _xorg_keymap()
-    else:
-        while 1:
-            s = f.readline()
-            if s == "":
-                break
-            if re.search("KEYTABLE", s) != None or \
-               (re.search("KEYBOARD", s) != None and
-                re.search("KEYBOARDTYPE", s) == None):
-                if s.count('"'):
-                    delim = '"'
-                elif s.count('='):
-                    delim = '='
-                else:
-                    continue
-                kt = s.split(delim)[1].strip()
-        f.close()
-
-    if kt and keytable.keytable.has_key(kt.lower()):
-        keymap = keytable.keytable[kt]
-    else:
-        logging.debug("Didn't find keymap '%s' in keytable!" % kt)
-    return keymap
-
-def pygrub_path(conn=None):
-    """
-    Return the pygrub path for the current host, or connection if
-    available.
-    """
-    # FIXME: This should be removed/deprecated when capabilities are
-    #        fixed to provide bootloader info
-    if conn:
-        cap = CapabilitiesParser.parse(conn.getCapabilities())
-        if (cap.host.arch == "i86pc"):
-            return "/usr/lib/xen/bin/pygrub"
-        else:
-            return "/usr/bin/pygrub"
-
-    if platform.system() == "SunOS":
-        return "/usr/lib/xen/bin/pygrub"
-    return "/usr/bin/pygrub"
-
-def uri_split(uri):
-    """
-    Parse a libvirt hypervisor uri into it's individual parts
-    @returns: tuple of the form (scheme (ex. 'qemu', 'xen+ssh'), username,
-                                 hostname, path (ex. '/system'), query,
-                                 fragment)
-    """
-    def splitnetloc(url, start=0):
-        for c in '/?#': # the order is important!
-            delim = url.find(c, start)
-            if delim >= 0:
-                break
-        else:
-            delim = len(url)
-        return url[start:delim], url[delim:]
-
-    username = netloc = query = fragment = ''
-    i = uri.find(":")
-    if i > 0:
-        scheme, uri = uri[:i].lower(), uri[i+1:]
-        if uri[:2] == '//':
-            netloc, uri = splitnetloc(uri, 2)
-            offset = netloc.find("@")
-            if offset > 0:
-                username = netloc[0:offset]
-                netloc = netloc[offset+1:]
-        if '#' in uri:
-            uri, fragment = uri.split('#', 1)
-        if '?' in uri:
-            uri, query = uri.split('?', 1)
-    else:
-        scheme = uri.lower()
-    return scheme, username, netloc, uri, query, fragment
-
-
-def is_uri_remote(uri):
-    try:
-        split_uri = uri_split(uri)
-        netloc = split_uri[2]
-
-        if netloc == "":
-            return False
-        return True
-    except Exception, e:
-        logging.exception("Error parsing URI in is_remote: %s" % e)
-        return True
-
-def get_uri_hostname(uri):
-    try:
-        split_uri = uri_split(uri)
-        netloc = split_uri[2]
-
-        if netloc != "":
-            return netloc
-    except Exception, e:
-        logging.warning("Cannot parse URI %s: %s" % (uri, str(e)))
-    return "localhost"
-
-def get_uri_transport(uri):
-    try:
-        split_uri = uri_split(uri)
-        scheme = split_uri[0]
-        username = split_uri[1]
-
-        if scheme:
-            offset = scheme.index("+")
-            if offset > 0:
-                return [scheme[offset+1:], username]
-    except:
-        pass
-    return [None, None]
-
-def get_uri_driver(uri):
-    try:
-        split_uri = uri_split(uri)
-        scheme = split_uri[0]
-
-        if scheme:
-            offset = scheme.find("+")
-            if offset > 0:
-                return scheme[:offset]
-            return scheme
-    except Exception:
-        pass
-    return "xen"
-
-def is_storage_capable(conn):
-    """check if virConnectPtr passed has storage API support"""
-    if not conn:
-        return False
-    if not isinstance(conn, libvirt.virConnect):
-        raise ValueError(_("'conn' must be a virConnect instance."))
-    try:
-        if not dir(conn).count("listStoragePools"):
-            return False
-        conn.listStoragePools()
-    except libvirt.libvirtError, e:
-        if e.get_error_code() == libvirt.VIR_ERR_RPC or \
-           e.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT:
-            return False
-    return True
-
-def get_xml_path(xml, path):
-    """return the xpath from the passed xml"""
-    doc = None
-    ctx = None
-    result = None
-    try:
-        doc = libxml2.parseDoc(xml)
-        ctx = doc.xpathNewContext()
-        ret = ctx.xpathEval(path)
-        val = None
-        if ret != None:
-            if type(ret) == list:
-                if len(ret) == 1:
-                    val = ret[0].content
-            else:
-                val = ret
-        result = val
-    finally:
-        if doc:
-            doc.freeDoc()
-        if ctx:
-            ctx.xpathFreeContext()
-    return result
-
-def lookup_pool_by_path(conn, path):
-    """
-    Return the first pool with matching matching target path.
-    return the first we find, active or inactive. This iterates over
-    all pools and dumps their xml, so it is NOT quick.
-    @return virStoragePool object if found, None otherwise
-    """
-    if not is_storage_capable(conn):
-        return None
-
-    pool_list = conn.listStoragePools() + conn.listDefinedStoragePools()
-    for name in pool_list:
-        pool = conn.storagePoolLookupByName(name)
-        xml_path = get_xml_path(pool.XMLDesc(0), "/pool/target/path")
-        if os.path.abspath(xml_path) == path:
-            return pool
-    return None
-
-def privileged_user():
-    """
-    Return true if the user is privileged enough.  On Linux, this
-    equates to being root.  On Solaris, it's more complicated, so we
-    just assume we're OK.
-    """
-    return os.uname()[0] == 'SunOS' or os.geteuid() == 0
-
-def _test():
-    import doctest
-    doctest.testmod()
- 
-if __name__ == "__main__":
-    _test()
+#
+# These functions accidentally ended up in the API under virtinst.util
+#
+default_route = util.default_route
+default_bridge = util.default_bridge
+default_network = util.default_network
+default_connection = util.default_connection
+get_cpu_flags = util.get_cpu_flags
+is_pae_capable = util.is_pae_capable
+is_blktap_capable = util.is_blktap_capable
+get_default_arch = util.get_default_arch
+randomMAC = util.randomMAC
+randomUUID = util.randomUUID
+uuidToString = util.uuidToString
+uuidFromString = util.uuidFromString
+get_host_network_devices = util.get_host_network_devices
+get_max_vcpus = util.get_max_vcpus
+get_phy_cpus = util.get_phy_cpus
+xml_escape = util.xml_escape
+compareMAC = util.compareMAC
+default_keymap = util.default_keymap
+pygrub_path = util.pygrub_path
+uri_split = util.uri_split
+is_uri_remote = util.is_uri_remote
+get_uri_hostname = util.get_uri_hostname
+get_uri_transport = util.get_uri_transport
+get_uri_driver = util.get_uri_driver
+is_storage_capable = util.is_storage_capable
+get_xml_path = util.get_xml_path
+lookup_pool_by_path = util.lookup_pool_by_path
diff --git a/virtinst/cli.py b/virtinst/cli.py
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -26,9 +26,9 @@ from optparse import OptionValueError, O
 from optparse import OptionValueError, OptionParser
 
 import libvirt
-import util
+import _util
 from virtinst import CapabilitiesParser, VirtualNetworkInterface, \
-                     VirtualGraphics, VirtualAudio
+                     VirtualGraphics, VirtualAudio, User
 from virtinst import _virtinst as _
 
 MIN_RAM = 64
@@ -117,9 +117,8 @@ def nice_exit():
     sys.exit(0)
 
 def getConnection(connect):
-    if connect and connect.lower()[0:3] == "xen":
-        if not util.privileged_user():
-            fail(_("Must be root to create Xen guests"))
+    if not User.current().has_priv(User.PRIV_CREATE_DOMAIN, connect):
+        fail(_("Must be root to create Xen guests"))
     if connect is None:
         fail(_("Could not find usable default libvirt connection."))
 
@@ -298,8 +297,8 @@ def digest_networks(conn, macs, bridges,
     # With just one mac, create a default network if one is not
     # specified.
     if len(macs) == 1 and len(networks) == 0:
-        if util.privileged_user():
-            net = util.default_network(conn)
+        if User.current().has_priv(User.PRIV_CREATE_NETWORK, conn.getURI()):
+            net = _util.default_network(conn)
             networks.append(net[0] + ":" + net[1])
         else:
             networks.append("user")
@@ -316,8 +315,8 @@ def digest_networks(conn, macs, bridges,
     # Create extra networks up to the number of nics requested 
     if len(macs) < nics:
         for dummy in range(len(macs),nics):
-            if util.privileged_user():
-                net = util.default_network(conn)
+            if User.current().has_priv(User.PRIV_CREATE_NETWORK, conn.getURI()):
+                net = _util.default_network(conn)
                 networks.append(net[0] + ":" + net[1])
             else:
                 networks.append("user")
diff --git a/virtinst/util.py b/virtinst/util.py
--- a/virtinst/util.py
+++ b/virtinst/util.py
@@ -18,6 +18,14 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA 02110-1301 USA.
+
+#
+# WARNING: the contents of this file, somewhat unfortunately, are legacy
+# API. No incompatible changes are allowed to this file, and no new
+# code should be added here (utility functions live in _util.py).
+# Clients of virtinst shouldn't use these functions: if you think you
+# need to, tell us why.
+#
 
 import platform
 import random
@@ -30,6 +38,7 @@ import libvirt
 import libvirt
 from virtinst import _virtinst as _
 from virtinst import CapabilitiesParser
+from virtinst import User
 
 
 KEYBOARD_DIR = "/etc/sysconfig/keyboard"
@@ -54,7 +63,6 @@ def default_route():
             continue
     return None
 
-# Legacy for compat only.
 def default_bridge():
     rt = default_route()
     if rt is None:
@@ -91,7 +99,7 @@ def default_connection():
          os.path.exists("/usr/bin/qemu-kvm") or \
          os.path.exists("/usr/bin/kvm") or \
          os.path.exists("/usr/bin/xenner"):
-        if privileged_user():
+        if User.current().has_priv(User.PRIV_QEMU_SYSTEM):
             return "qemu:///system"
         else:
             return "qemu:///session"
@@ -258,15 +266,6 @@ def xml_escape(str):
     str = str.replace(">", "&gt;")
     return str
  
-def blkdev_size(path):
-    """Return the size of the block device.  We can't use os.stat() as
-    that returns zero on many platforms."""
-    fd = os.open(path, os.O_RDONLY)
-    # os.SEEK_END is not present on all systems
-    size = os.lseek(fd, 0, 2)
-    os.close(fd)
-    return size
-
 def compareMAC(p, q):
     """Compare two MAC addresses"""
     pa = p.split(":")
@@ -505,14 +504,6 @@ def lookup_pool_by_path(conn, path):
             return pool
     return None
 
-def privileged_user():
-    """
-    Return true if the user is privileged enough.  On Linux, this
-    equates to being root.  On Solaris, it's more complicated, so we
-    just assume we're OK.
-    """
-    return os.uname()[0] == 'SunOS' or os.geteuid() == 0
-
 def _test():
     import doctest
     doctest.testmod()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]