FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Fedora/Linux Management Tools

 
 
LinkBack Thread Tools
 
Old 07-23-2008, 03:51 PM
Cole Robinson
 
Default virtinst: build libvirt storage xml

I've been working on a virtinst API to build and install xml
for libvirt storage objects. The current version is attached:
so far only nfs, filesystem and dir pools are implemented, as
well as their associated file volumes, but the remainder will
be mostly a cut and paste job. I have some UI wizards for
building these in virt-manager mostly complete, so this has
been tested to be pretty solid, though there is still some clean
up that needs doing.

The general workflow is as follows:

=========================================
import virtinst.Storage.StoragePool as sp

# This gives the appropriate class for the specified pool type
pool_class = sp.get_pool_class(sp.TYPE_FOO)

# Only required params are a conn/uri and name. Default formats
# and target paths have default values, but source paths/
# devices and hostnames obviously have no sensible default, but
# they still aren't required for object instantiation
pool = pool_class(name="foo", uri="xen:///")

pool.source_path = "/dev/foo"
etc.

# Prints xml config: will error if all required members aren't
# specified
pool.get_xml_config()

# Attempts to install and build pool on the passed connection
poolobj = pool.install()

# Will return appropriate volume class for this pool type
vol_class = pool.get_volume_class()

# For volumes, we require a pool instead of conn/uri, as well
# as name and capacity
vol = vol_class(name="volfoo", pool=poolobj)

volobj = vol.install()

=====================================

An active connection/URI/pool object is required. I figure
there isn't a real use case for wanting to generate xml on a
machine without a libvirt setup, and this will ensure in the
future we can check against capabilities xml, make sure we
aren't colliding names and other things.

I think the implemented code covers most of the different
cases for generating storage xml, with the exception of
username and password for iscsi: I see this in the libvirt
code but this isn't documented anywhere, so I'm not sure
if their are any real catches.

Comments welcome.

Thanks,
Cole



#
# Classes for building libvirt storage xml
#
# Copyright 2008 Red Hat, Inc.
# Cole Robinson <crobinso@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 libvirt

import re
import logging
import libxml2
from xml.sax.saxutils import escape

import util
from virtinst import _virtinst as _

DEFAULT_DEV_TARGET = "/dev"
DEFAULT_LVM_TARGET_BASE = "/dev/"
DEFAULT_DIR_TARGET_BASE = "/var/lib/libvirt/images/"
DEFAULT_ISCSI_TARGET = "/dev/disk/by-path"

# Pools:
# DirectoryPool : A flat filesystem directory
# FilesystemPool : A formatted partition
# NetworkFilesystemPool : NFS
# LogicalPool : LVM Volume Group
# DiskPool : Raw disk
# iSCSIPool : iSCSI

class StorageObject(object):
"""Base class for building any libvirt storage object, meaningless to
directly instantiate"""

TYPE_POOL = "pool"
TYPE_VOLUME = "volume"

def __init__(self, object_type, name):
if object_type not in [self.TYPE_POOL, self.TYPE_VOLUME]:
raise ValueError, _("Unknown storage object type: %s") % type
self._object_type = object_type

self.name = name

# Initialize all optional properties
self._perms = None


## Properties
"""object_type: pool or volume"""
def get_object_type(self):
return self._object_type
object_type = property(get_object_type)

"""type: type of the underlying object. could be "dir" for a pool, etc."""
def get_type(self):
raise RuntimeError, "Must be implemented in child class."
type = property(get_type)

"""name: name of the storage object"""
def get_name(self):
return self._name
def set_name(self, val):
if type(val) is not type("string") or len(val) > 50 or len(val) == 0:
raise ValueError, _("Storage object name must be a string " +
"between 0 and 50 characters")
if re.match("^[0-9]+$", val):
raise ValueError, _("Storage object name can not be only " +
"numeric characters")
if re.match("^[a-zA-Z0-9._-]+$", val) == None:
raise ValueError, _("Storage object name can only contain " +
"alphanumeric, '_', '.', or '-' characters")

# Check that name doesn't collide with other storage objects
self._check_name_collision(val)
self._name = val
name = property(get_name, set_name)

# Get/Set methods for use by some objects. Will register where applicable
def get_perms(self):
return self._perms
def set_perms(self, val):
if type(val) is not dict:
raise ValueError(_("Permissions must be passed as a dict object"))
for key in ["mode", "owner", "group", "label"]:
if not key in val:
raise ValueError(_("Permissions must contain 'mode', 'owner', 'group' and 'label' keys."))
self._perms = val


# Validation helper functions
def _validate_path(self, path):
if type(path) is not type("str") or not path.startswith("/"):
raise ValueError(_("'%s' is not an absolute path." % path))

def _check_name_collision(self, name):
raise RuntimeError, "Must be implemented in subclass"

# XML Building
def _get_storage_xml(self):
"""Returns the pool/volume specific xml blob"""
raise RuntimeError, "Must be implemented in subclass"

def _get_perms_xml(self):
if not self.perms:
return ""
return " <permissions>
" +
" <mode>%o</mode>
" % self.perms["mode"] +
" <owner>%d</owner>
" % self.perms["owner"] +
" <group>%d</group>
" % self.perms["group"] +
" <label>%s</label>
" % self.perms["label"] +
" </permissions>
"


def get_xml_config(self):
"""Returns the full xml description of the storage object"""
if self.type is None:
root_xml = "<%s>
" % self.object_type
else:
root_xml = "<%s type='%s'>
" % (self.object_type, self.type)

xml = "%s" % (root_xml) +
""" <name>%s</name>
""" % (self.name) +
"""%(stor_xml)s""" % { "stor_xml" : self._get_storage_xml() } +
"""</%s>""" % (self.object_type)
return xml

def install(self, create=False):
"""Define the object XML and build if appropriate"""
raise RuntimeError, "Must be implemented in subclass"

class StoragePool(StorageObject):
"""Base class for building a libvirt storage pool xml definition"""

TYPE_DIR = "dir"
TYPE_FS = "fs"
TYPE_NETFS = "netfs"
TYPE_LOGICAL = "logical"
TYPE_DISK = "disk"
TYPE_ISCSI = "iscsi"

# Pool type descriptions for use in higher level programs
_types = {}
_types[TYPE_DIR] = _("Filesystem directory")
_types[TYPE_FS] = _("Formatted block device")
_types[TYPE_NETFS] = _("Network exported directory")
_types[TYPE_LOGICAL] = _("LVM Volume Group")
_types[TYPE_DISK] = _("Raw disk device")
_types[TYPE_ISCSI] = _("iSCSI Target")

def get_pool_class(type):
"""Convenience method, return class associated with passed pool type"""
if type not in StoragePool._types:
raise ValueError, _("Unknown storage pool type: %s" % type)
if type == StoragePool.TYPE_DIR:
return DirectoryPool
if type == StoragePool.TYPE_FS:
return FilesystemPool
if type == StoragePool.TYPE_NETFS:
return NetworkFilesystemPool
if type == StoragePool.TYPE_LOGICAL:
return LogicalPool
if type == StoragePool.TYPE_DISK:
return DiskPool
if type == StoragePool.TYPE_ISCSI:
return iSCSIPool
get_pool_class = staticmethod(get_pool_class)

def get_volume_for_pool(pool_type):
"""Convenience method, returns volume class associated with pool_type"""
pool_class = StoragePool.get_pool_class(pool_type)
return pool_class.get_volume_class()
get_volume_for_pool = staticmethod(get_volume_for_pool)

def get_pool_types():
"""Return list of appropriate pool types"""
return StoragePool._types.keys()
get_pool_types = staticmethod(get_pool_types)

def get_pool_type_desc(pool_type):
"""Return human readable description for passed pool type"""
return StoragePool._types[pool_type]
get_pool_type_desc = staticmethod(get_pool_type_desc)


def __init__(self, name, type, target_path=None, uuid=None,
uri=None, conn=None):
if conn:
self.conn = conn
self.uri = conn.getURI()
else:
if uri:
self.uri = uri
self.conn = util.open_conn(uri=uri)
else:
raise ValueError(_("A connection or URI must be specified."))

StorageObject.__init__(self, object_type=StorageObject.TYPE_POOL,
name=name)

if type not in self.get_pool_types():
raise ValueError, _("Unknown storage pool type: %s" % type)
self._type = type
if target_path is None:
target_path = self._get_default_target_path()
self.target_path = target_path

# Initialize all optional properties
self._host = None
self._source_path = None
if not uuid:
self._uuid = None
self._random_uuid = util.uuidToString(util.randomUUID())

# Properties used by all pools
def get_type(self):
return self._type
type = property(get_type)

"""conn: libvirt connection to check object against/install on"""
def get_conn(self):
return self._conn
def set_conn(self, val):
if not isinstance(val, libvirt.virConnect):
raise ValueError(_("'conn' must be a libvirt connection object."))
self._conn = val
conn = property(get_conn, set_conn)

def get_target_path(self):
return self._target_path
def set_target_path(self, val):
self._validate_path(val)
self._target_path = val
target_path = property(get_target_path, set_target_path)

# Get/Set methods for use by some pools. Will be registered when applicable
def get_source_path(self):
return self._source_path
def set_source_path(self, val):
self._validate_path(val)
self._source_path = val

def get_host(self):
return self._host
def set_host(self, val):
if type(val) is not type("str"):
raise ValueError(_("Host name must be a string"))
self._host = val

"""uuid: uuid of the storage object. optional: generated if not set"""
def get_uuid(self):
return self._uuid
def set_uuid(self, val):
if type(val) is not type("string"):
raise ValueError, _("UUID must be a string.")

form = re.match("[a-fA-F0-9]{8}[-]([a-fA-F0-9]{4}[-]){3}[a-fA-F0-9]{12}$", val)
if form is None:
form = re.match("[a-fA-F0-9]{32}$", val)
if form is None:
raise ValueError, _("UUID must be a 32-digit hexadecimal number. It may take the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX or may omit hyphens altogether.")

else: # UUID had no dashes, so add them in
val=val[0:8] + "-" + val[8:12] + "-" + val[12:16] +
"-" + val[16:20] + "-" + val[20:32]
self._uuid = val
uuid = property(get_uuid, set_uuid)

# Validation functions
def _check_name_collision(self, name):
pool = None
try:
pool = self.conn.storagePoolLookupByName(name)
except libvirt.libvirtError:
pass
if pool:
raise ValueError(_("Name '%s' already in use by another pool." %
name))

def _get_default_target_path(self):
raise RuntimeError, "Must be implemented in subclass"

# XML Building
def _get_target_xml(self):
raise RuntimeError, "Must be implemented in subclass"

def _get_source_xml(self):
raise RuntimeError, "Must be implemented in subclass"

def _get_storage_xml(self):
src_xml = ""
if self._get_source_xml() != "":
src_xml = " <source>
" +
"%s" % (self._get_source_xml()) +
" </source>
"
tar_xml = " <target>
" +
"%s" % (self._get_target_xml()) +
" </target>
"

return " <uuid>%s</uuid>
" % (self.uuid or self._random_uuid) +
"%s" % src_xml +
"%s" % tar_xml

def install(self, create=False):
xml = self.get_xml_config()
logging.debug("Defining storage xml:
%s" % xml)

# Define the pool xml
try:
pool = self.conn.storagePoolDefineXML(xml, 0)
except Exception, e:
raise RuntimeError(_("Could not define storage pool: %s" % str(e)))

# Build the pool?
errmsg = None
try:
pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW)
except Exception, e:
errmsg = _("Could not build storage pool: %s" % str(e))

if create and not errmsg:
try:
pool.create(0)
except Exception, e:
errmsg = _("Could not start storage pool: %s" % str(e))

if errmsg:
# Try and clean up the leftover pool
try:
pool.undefine()
except Exception, e:
logging.debug("Error cleaning up pool after failure: " +
"%s" % str(e))
raise RuntimeError(errmsg)

return pool


class DirectoryPool(StoragePool):
"""Class for building a directory based storage pool"""

def get_volume_class():
return FileVolume
get_volume_class = staticmethod(get_volume_class)

# Register applicable property methods from parent class
perms = property(StorageObject.get_perms, StorageObject.set_perms)

def __init__(self, name, target_path=None, uuid=None, perms=None, uri=None,
conn=None):
StoragePool.__init__(self, name=name, type=StoragePool.TYPE_DIR,
target_path=target_path, uuid=uuid, uri=uri,
conn=conn)
if perms:
self.perms = perms

def _get_default_target_path(self):
path = (DEFAULT_DIR_TARGET_BASE + self.name)
return path

def _get_target_xml(self):
xml = " <path>%s</path>
" % escape(self.target_path) +
"%s" % self._get_perms_xml()
return xml

def _get_source_xml(self):
return ""

class FilesystemPool(StoragePool):
"""Class for building a formatted partition based storage pool"""

def get_volume_class():
return FileVolume
get_volume_class = staticmethod(get_volume_class)

formats = [ "auto", "ext2", "ext3", "ext4", "ufs", "iso9660", "udf",
"gfs", "gfs2", "vfat", "hfs+", "xfs" ]

# Register applicable property methods from parent class
perms = property(StorageObject.get_perms, StorageObject.set_perms)
source_path = property(StoragePool.get_source_path,
StoragePool.set_source_path)

def __init__(self, name, source_path=None, target_path=None,
format="auto", uuid=None, perms=None, uri=None, conn=None):
StoragePool.__init__(self, name=name, type=StoragePool.TYPE_FS,
target_path=target_path, uuid=uuid, uri=uri,
conn=conn)

self.format = format

if source_path:
self.source_path = source_path
if perms:
self.perms = perms

def get_format(self):
return self._format
def set_format(self, val):
if not val in self.formats:
raise ValueError(_("Unknown Filesystem format: %s" % val))
self._format = val
format = property(get_format, set_format)

def _get_default_target_path(self):
path = (DEFAULT_DIR_TARGET_BASE + self.name)
return path

def _get_target_xml(self):
xml = " <path>%s</path>
" % escape(self.target_path) +
"%s" % self._get_perms_xml()
return xml

def _get_source_xml(self):
if not self.source_path:
raise RuntimeError(_("Device path is required"))
xml = " <format type='%s'/>
" % self.format +
" <device path='%s'/>
" % escape(self.source_path)
return xml

class NetworkFilesystemPool(StoragePool):
"""Class for building a Network Filesystem pool xml object"""

def get_volume_class():
return FileVolume
get_volume_class = staticmethod(get_volume_class)

formats = [ "auto", "nfs" ]

# Register applicable property methods from parent class
source_path = property(StoragePool.get_source_path,
StoragePool.set_source_path)
host = property(StoragePool.get_host, StoragePool.set_host)

def __init__(self, name, source_path=None, host=None, target_path=None,
format="auto", uuid=None, uri=None, conn=None):
StoragePool.__init__(self, name=name, type=StoragePool.TYPE_NETFS,
uuid=None, target_path=target_path, uri=uri,
conn=conn)

self.format = format

if source_path:
self.source_path = source_path
if host:
self.host = host

def get_format(self):
return self._format
def set_format(self, val):
if not val in self.formats:
raise ValueError(_("Unknown Network Filesystem format: %s" % val))
self._format = val
format = property(get_format, set_format)

def _get_default_target_path(self):
path = (DEFAULT_DIR_TARGET_BASE + self.name)
return path

def _get_target_xml(self):
xml = " <path>%s</path>
" % escape(self.target_path)
return xml

def _get_source_xml(self):
if not self.host:
raise RuntimeError(_("Hostname is required"))
if not self.source_path:
raise RuntimeError(_("Host path is required"))
xml = """ <format type="%s"/>
""" % self.format +
""" <host name="%s"/>
""" % self.host +
""" <dir path="%s"/>
""" % escape(self.source_path)
return xml

class LogicalPool(StoragePool):
def __init__(self, *args, **kwargs):
raise RuntimeError, "Not implemented"
class DiskPool(StoragePool):
def __init__(self, *args, **kwargs):
raise RuntimeError, "Not implemented"
class iSCSIPool(StoragePool):
def __init__(self, *args, **kwargs):
raise RuntimeError, "Not implemented"



class StorageVolume(StorageObject):
"""Base class for building a libvirt storage volume xml definition"""

formats = []

def __init__(self, name, capacity, pool, target_path=None,
allocation=None):
self.pool = pool
StorageObject.__init__(self, object_type=StorageObject.TYPE_VOLUME,
name=name)
if not target_path:
self.target_path = self._get_default_target_path()
else:
self.target_path = target_path

self.capacity = capacity
self.allocation = allocation or self.capacity

def get_type(self):
return None
type = property(get_type)

# Properties used by all volumes
def get_capacity(self):
return self._capacity
def set_capacity(self, val):
if type(val) not in (int, float) or val <= 0:
raise ValueError(_("Capacity must be a positive number"))
val = int(val)
self._capacity = val
if self.allocation and (val > self.allocation):
self.allocation = val
capacity = property(get_capacity, set_capacity)

def get_allocation(self):
return self._allocation
def set_allocation(self, val):
if type(val) not in (int, float) and val <= 0:
raise ValueError(_("Allocation must be a positive number"))
val = int(val)
if val > self.capacity:
val = self.capacity
self._allocation = val
allocation = property(get_allocation, set_allocation)

def get_target_path(self):
return self._target_path
def set_target_path(self, val):
self._validate_path(val)
self._target_path = val
target_path = property(get_target_path, set_target_path)

def get_pool(self):
return self._pool
def set_pool(self, newpool):
if not isinstance(newpool, libvirt.virStoragePool):
raise ValueError, _("'pool' must be a virStoragePool instance.")
self._pool = newpool
pool = property(get_pool, set_pool)

# Property functions used by more than one child class
def get_format(self):
return self._format
def set_format(self, val):
if val not in self.formats:
raise ValueError(_("'%s' is not a valid format.") % val)
self._format = val

def _check_name_collision(self, name):
vol = None
try:
vol = self.pool.storageVolLookupByName(name)
except libvirt.libvirtError:
pass
if vol:
raise ValueError(_("Name '%s' already in use by another volume." %
name))

def _get_default_target_path(self):
raise RuntimeError, "Must be implemented in subclass"

def _get_xml_path(self, path):
doc = None
ctx = None
try:
xml = self.pool.XMLDesc(0)
doc = libxml2.parseDoc(xml)
try:
ctx = doc.xpathNewContext()

ret = ctx.xpathEval(path)
str = None
if ret != None:
if type(ret) == list:
if len(ret) == 1:
str = ret[0].content
else:
str = ret
ctx.xpathFreeContext()
return str
except:
if ctx:
ctx.xpathFreeContext()
return None
finally:
if doc is not None:
doc.freeDoc()


# xml building functions
def _get_target_xml(self):
raise RuntimeError, "Must be implemented in subclass"

def _get_source_xml(self):
raise RuntimeError, "Must be implemented in subclass"

def _get_storage_xml(self):
src_xml = format_xml = ""
if self._get_source_xml() != "":
src_xml = " <source>
" +
"%s" % (self._get_source_xml()) +
" </source>
"
tar_xml = " <target>
" +
"%s" % (self._get_target_xml()) +
" </target>
"
alloc = self.allocation or self.capacity

return " <capacity>%d</capacity>
" % self.capacity +
" <allocation>%d</allocation>
" % alloc +
"%s" % src_xml +
"%s" % tar_xml

def install(self):
try:
vol = self.pool.createXML(self.get_xml_config(), 0)
except Exception, e:
raise RuntimeError("Couldn't create storage volume '%s': '%s'" %
(self.name, str(e)))
return vol

class FileVolume(StorageVolume):

formats = ["raw", "bochs", "cloop", "cow", "dmg", "iso", "qcow",
"qcow2", "vmdk", "vpc"]

# Register applicable property methods from parent class
perms = property(StorageObject.get_perms, StorageObject.set_perms)
format = property(StorageVolume.get_format, StorageVolume.set_format)

def __init__(self, name, capacity, pool, target_path=None, format="raw",
allocation=None, perms=None):
StorageVolume.__init__(self, name=name, target_path=target_path,
allocation=allocation, capacity=capacity,
pool=pool)
self.format = format
if perms:
self.perms = perms

def _get_default_target_path(self):
poolpath = self._get_xml_path("/pool/target/path")
return poolpath + "/" + self.name

def _get_target_xml(self):
return " <path>%s</path>
" % escape(self.target_path) +
" <format type='%s'/>
" % self.format +
"%s" % self._get_perms_xml()

def _get_source_xml(self):
return ""
_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-24-2008, 12:18 PM
"Daniel P. Berrange"
 
Default virtinst: build libvirt storage xml

On Wed, Jul 23, 2008 at 11:51:40AM -0400, Cole Robinson wrote:
> I've been working on a virtinst API to build and install xml
> for libvirt storage objects. The current version is attached:
> so far only nfs, filesystem and dir pools are implemented, as
> well as their associated file volumes, but the remainder will
> be mostly a cut and paste job. I have some UI wizards for
> building these in virt-manager mostly complete, so this has
> been tested to be pretty solid, though there is still some clean
> up that needs doing.

I think this is generally sound - the proof of any such API is how well
it suits its users, so if it works well for virt-manager and virt-install
CLI then go for it.

> The general workflow is as follows:
>
> =========================================
> import virtinst.Storage.StoragePool as sp
>
> # This gives the appropriate class for the specified pool type
> pool_class = sp.get_pool_class(sp.TYPE_FOO)
>
> # Only required params are a conn/uri and name. Default formats
> # and target paths have default values, but source paths/
> # devices and hostnames obviously have no sensible default, but
> # they still aren't required for object instantiation
> pool = pool_class(name="foo", uri="xen:///")

Should proably allow a existing connection to be passed in, otherwise
this class has to deal with authentication issues too.

Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-25-2008, 04:01 PM
Cole Robinson
 
Default virtinst: build libvirt storage xml

Daniel P. Berrange wrote:
>> The general workflow is as follows:
>>
>> =========================================
>> import virtinst.Storage.StoragePool as sp
>>
>> # This gives the appropriate class for the specified pool type
>> pool_class = sp.get_pool_class(sp.TYPE_FOO)
>>
>> # Only required params are a conn/uri and name. Default formats
>> # and target paths have default values, but source paths/
>> # devices and hostnames obviously have no sensible default, but
>> # they still aren't required for object instantiation
>> pool = pool_class(name="foo", uri="xen:///")
>
> Should proably allow a existing connection to be passed in, otherwise
> this class has to deal with authentication issues too.
>

I didn't show it in the example, but passing a connection is allowed.

On a side note, we should add support for openAuth in virtinst,
everything is just hardcoded to use libvirt.open at the moment.

- Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-25-2008, 04:07 PM
"Daniel P. Berrange"
 
Default virtinst: build libvirt storage xml

On Fri, Jul 25, 2008 at 12:01:15PM -0400, Cole Robinson wrote:
> Daniel P. Berrange wrote:
> >> The general workflow is as follows:
> >>
> >> =========================================
> >> import virtinst.Storage.StoragePool as sp
> >>
> >> # This gives the appropriate class for the specified pool type
> >> pool_class = sp.get_pool_class(sp.TYPE_FOO)
> >>
> >> # Only required params are a conn/uri and name. Default formats
> >> # and target paths have default values, but source paths/
> >> # devices and hostnames obviously have no sensible default, but
> >> # they still aren't required for object instantiation
> >> pool = pool_class(name="foo", uri="xen:///")
> >
> > Should proably allow a existing connection to be passed in, otherwise
> > this class has to deal with authentication issues too.
> >
>
> I didn't show it in the example, but passing a connection is allowed.
>
> On a side note, we should add support for openAuth in virtinst,
> everything is just hardcoded to use libvirt.open at the moment.

No, that's exactly why we shouldn't take a URI. openAuth requires user
interaction, so that's unavoidably application specific. We just need
a helper in virtinst/cli.py for the command line tools to use to create
their connection object, and virt-manager already knows how to do
authentication. So everything should just pass ina connection object
instead of URI.

Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-25-2008, 04:27 PM
Cole Robinson
 
Default virtinst: build libvirt storage xml

Daniel P. Berrange wrote:
> On Fri, Jul 25, 2008 at 12:01:15PM -0400, Cole Robinson wrote:
>> Daniel P. Berrange wrote:
>> >> The general workflow is as follows:
>>>> =========================================
>>>> import virtinst.Storage.StoragePool as sp
>>>>
>>>> # This gives the appropriate class for the specified pool type
>>>> pool_class = sp.get_pool_class(sp.TYPE_FOO)
>>>>
>>>> # Only required params are a conn/uri and name. Default formats
>>>> # and target paths have default values, but source paths/
>>>> # devices and hostnames obviously have no sensible default, but
>>>> # they still aren't required for object instantiation
>>>> pool = pool_class(name="foo", uri="xen:///")
>>> Should proably allow a existing connection to be passed in, otherwise
>>> this class has to deal with authentication issues too.
>>>
>> I didn't show it in the example, but passing a connection is allowed.
>>
>> On a side note, we should add support for openAuth in virtinst,
>> everything is just hardcoded to use libvirt.open at the moment.
>
> No, that's exactly why we shouldn't take a URI. openAuth requires user
> interaction, so that's unavoidably application specific. We just need
> a helper in virtinst/cli.py for the command line tools to use to create
> their connection object, and virt-manager already knows how to do
> authentication. So everything should just pass ina connection object
> instead of URI.
>
> Daniel

Ahh okay, that makes sense. I'll remove the option to pass a URI then,
since we really shouldn't even encourage passing a URI and expecting
the library to open it.

- Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-25-2008, 04:34 PM
"Daniel P. Berrange"
 
Default virtinst: build libvirt storage xml

On Fri, Jul 25, 2008 at 12:27:29PM -0400, Cole Robinson wrote:
> Daniel P. Berrange wrote:
> > On Fri, Jul 25, 2008 at 12:01:15PM -0400, Cole Robinson wrote:
> >> Daniel P. Berrange wrote:
> >> >> The general workflow is as follows:
> >>>> =========================================
> >>>> import virtinst.Storage.StoragePool as sp
> >>>>
> >>>> # This gives the appropriate class for the specified pool type
> >>>> pool_class = sp.get_pool_class(sp.TYPE_FOO)
> >>>>
> >>>> # Only required params are a conn/uri and name. Default formats
> >>>> # and target paths have default values, but source paths/
> >>>> # devices and hostnames obviously have no sensible default, but
> >>>> # they still aren't required for object instantiation
> >>>> pool = pool_class(name="foo", uri="xen:///")
> >>> Should proably allow a existing connection to be passed in, otherwise
> >>> this class has to deal with authentication issues too.
> >>>
> >> I didn't show it in the example, but passing a connection is allowed.
> >>
> >> On a side note, we should add support for openAuth in virtinst,
> >> everything is just hardcoded to use libvirt.open at the moment.
> >
> > No, that's exactly why we shouldn't take a URI. openAuth requires user
> > interaction, so that's unavoidably application specific. We just need
> > a helper in virtinst/cli.py for the command line tools to use to create
> > their connection object, and virt-manager already knows how to do
> > authentication. So everything should just pass ina connection object
> > instead of URI.
> >
> > Daniel
>
> Ahh okay, that makes sense. I'll remove the option to pass a URI then,
> since we really shouldn't even encourage passing a URI and expecting
> the library to open it.

Just don't remove it from the existing Guest modules, because Koan is
relying on this API to remain stable & since Koan is local only it
doesn't have to worry about auth.

Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 
Old 07-25-2008, 04:41 PM
Cole Robinson
 
Default virtinst: build libvirt storage xml

Daniel P. Berrange wrote:
>>> No, that's exactly why we shouldn't take a URI. openAuth requires user
>>> interaction, so that's unavoidably application specific. We just need
>>> a helper in virtinst/cli.py for the command line tools to use to create
>>> their connection object, and virt-manager already knows how to do
>>> authentication. So everything should just pass ina connection object
>>> instead of URI.
>>>
>>> Daniel
>> Ahh okay, that makes sense. I'll remove the option to pass a URI then,
>> since we really shouldn't even encourage passing a URI and expecting
>> the library to open it.
>
> Just don't remove it from the existing Guest modules, because Koan is
> relying on this API to remain stable & since Koan is local only it
> doesn't have to worry about auth.
>
> Daniel

Right understandably we need to maintain the existing expected behavior.

- Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools
 

Thread Tools




All times are GMT. The time now is 12:01 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org