virt-install: Make --disk $URL 'just work'

If VirtualDisk.path is set to a URL, parse it and fill in all the
source_* values automagically.
This commit is contained in:
Cole Robinson 2014-12-09 09:20:18 -05:00
parent 3ac272e635
commit 9952764dda
7 changed files with 99 additions and 28 deletions

View File

@ -89,6 +89,24 @@
</source>
<target dev="sdc" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="gluster" name="/test-volume/test-gluster.qcow2">
<host name="192.168.1.100"/>
</source>
<target dev="sdd" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="qemu">
<host transport="nbd" socket="/var/foo/bar/socket"/>
</source>
<target dev="sde" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="http" name="/my/path">
<host name="1:2:3:4:1:2:3:4" port="5522"/>
</source>
<target dev="sdf" bus="scsi"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1">
<address type="pci" domain="0" bus="0" slot="4" function="7"/>
</controller>
@ -250,6 +268,24 @@
</source>
<target dev="sdc" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="gluster" name="/test-volume/test-gluster.qcow2">
<host name="192.168.1.100"/>
</source>
<target dev="sdd" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="qemu">
<host transport="nbd" socket="/var/foo/bar/socket"/>
</source>
<target dev="sde" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="http" name="/my/path">
<host name="1:2:3:4:1:2:3:4" port="5522"/>
</source>
<target dev="sdf" bus="scsi"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1">
<address type="pci" domain="0" bus="0" slot="4" function="7"/>
</controller>

View File

@ -558,6 +558,9 @@ c.add_compare("""--hvm --pxe \
--disk source_pool=rbd-ceph,source_volume=some-rbd-vol \
--disk source_protocol=http,source_host_name=example.com,source_host_port=8000,source_name=/path/to/my/file,bus=scsi \
--disk source_protocol=nbd,source_host_transport=unix,source_host_socket=/tmp/socket,bus=scsi \
--disk gluster://192.168.1.100/test-volume/test-gluster.qcow2,bus=scsi \
--disk qemu+nbd:///var/foo/bar/socket,bus=scsi \
--disk path=http://[1:2:3:4:1:2:3:4]:5522/my/path?query=foo,bus=scsi \
--serial tcp,host=:2222,mode=bind,protocol=telnet \
--filesystem /source,/target,mode=squash \
--network user,mac=12:34:56:78:11:22,portgroup=foo \

View File

@ -1858,11 +1858,22 @@ ba</description>
<owner>0</owner>
<group>0</group>
</permissions>
<timestamps>
<atime>1413881655.870313004</atime>
<mtime>1411649104.965642390</mtime>
<ctime>1412163870.190503958</ctime>
</timestamps>
</target>
</volume>
<volume type='network'>
<name>test-gluster.qcow2</name>
<key>gluster://192.168.1.100/test-volume/test-gluster.qcow2</key>
<capacity unit='bytes'>10737418240</capacity>
<allocation unit='bytes'>2489327616</allocation>
<target>
<path>gluster://192.168.1.100/test-volume/test-gluster.qcow2</path>
<format type='qcow2'/>
<permissions>
<mode>0666</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</target>
</volume>
</pool>

View File

@ -40,7 +40,7 @@
<target dev="sda" bus="scsi"/>
<readonly/>
<source protocol="http" name="/my/file">
<host name="exaaaaample.com"/>
<host name="1:2:3:4:5:6:7:8" port="1122"/>
</source>
</disk>
<disk type="file" device="floppy">

View File

@ -349,11 +349,8 @@ class XMLParseTest(unittest.TestCase):
disk = _get_disk("sda")
check = self._make_checker(disk)
check("source_protocol", None, "http")
check("source_name", None, "/my/file")
check("source_host_name", None, "exaaaaample.com")
check("path", None, "http://[1:2:3:4:5:6:7:8]:1122/my/file")
disk.sync_path_props()
check("path", "http://exaaaaample.com/my/file")
disk = _get_disk("fda")
check = self._make_checker(disk)

View File

@ -31,6 +31,7 @@ import urlgrabber.progress as progress
from . import diskbackend
from . import util
from .device import VirtualDevice
from .uri import URISplit
from .xmlbuilder import XMLProperty
@ -217,6 +218,8 @@ class VirtualDisk(VirtualDevice):
return []
if username == "root":
return []
if diskbackend.path_is_url(path):
return []
try:
uid = _name_uid(username)
@ -517,20 +520,21 @@ class VirtualDisk(VirtualDevice):
self._set_default_storage_backend()
return self._storage_backend.path
def _set_path(self, val):
def _set_path(self, newpath):
if (self._storage_backend and
self._storage_backend.will_create_storage()):
raise ValueError("Can't change disk path if storage creation info "
"has been set.")
# User explicitly changed 'path', so try to lookup its storage
# object since we may need it
parent_pool = None
vol_object = None
if val:
(vol_object, parent_pool) = diskbackend.manage_path(self.conn, val)
if newpath:
# User explicitly changed 'path', so try to lookup its storage
# object since we may need it
(vol_object, parent_pool) = diskbackend.manage_path(
self.conn, newpath)
self._change_backend(val, vol_object, parent_pool)
self._change_backend(newpath, vol_object, parent_pool)
self._set_xmlpath(self.path)
path = property(_get_path, _set_path)
@ -603,7 +607,23 @@ class VirtualDisk(VirtualDevice):
source_host_transport = XMLProperty("./source/host/@transport")
source_host_socket = XMLProperty("./source/host/@socket")
def _url_from_network_source(self):
def _set_source_from_url(self, uri):
uriinfo = URISplit(uri)
if uriinfo.scheme:
self.source_protocol = uriinfo.scheme
if uriinfo.transport:
self.source_host_transport = uriinfo.transport
if uriinfo.hostname:
self.source_host_name = uriinfo.hostname
if uriinfo.port:
self.source_host_port = uriinfo.port
if uriinfo.path:
if self.source_host_transport:
self.source_host_socket = uriinfo.path
else:
self.source_name = uriinfo.path
def _build_url_from_network_source(self):
ret = self.source_protocol
if self.source_host_transport:
ret += "+%s" % self.source_host_transport
@ -673,6 +693,10 @@ class VirtualDisk(VirtualDevice):
def _set_xmlpath(self, val):
self._clear_source_xml()
if self._storage_backend.is_network():
self._set_source_from_url(val)
return
propname = self._disk_type_to_object_prop_name()
if not propname:
return
@ -721,13 +745,11 @@ class VirtualDisk(VirtualDevice):
path = None
vol_object = None
parent_pool = None
is_network = False
typ = self._get_default_type()
is_network = (typ == VirtualDisk.TYPE_NETWORK)
if self.type == VirtualDisk.TYPE_NETWORK:
# Fill in a completed URL for virt-manager UI, path comparison, etc
path = self._url_from_network_source()
path = self._build_url_from_network_source()
if typ == VirtualDisk.TYPE_VOLUME:
conn = self.conn

View File

@ -128,6 +128,8 @@ def manage_path(conn, path):
"""
if not conn.check_support(conn.SUPPORT_CONN_STORAGE):
return None, None
if path_is_url(path):
return None, None
path = os.path.abspath(path)
vol, pool = check_if_path_managed(conn, path)
@ -452,15 +454,15 @@ class StorageBackend(_StorageBase):
parsexml=self._vol_object.XMLDesc(0))
return self._vol_xml
def _is_network(self):
if self._path:
return path_is_url(self._path)
return False
##############
# Public API #
##############
def is_network(self):
if self._path:
return path_is_url(self._path)
return False
def _get_path(self):
if self._vol_object:
return self._get_vol_xml().target_path
@ -493,13 +495,13 @@ class StorageBackend(_StorageBase):
self._exists = True
elif self._vol_object:
self._exists = True
elif (not self._is_network() and
elif (not self.is_network() and
not self._conn.is_remote() and
os.path.exists(self._path)):
self._exists = True
elif self._parent_pool:
self._exists = False
elif self._is_network():
elif self.is_network():
self._exists = True
elif (self._conn.is_remote() and
not _can_auto_manage(self._path)):
@ -526,7 +528,7 @@ class StorageBackend(_StorageBase):
else:
self._dev_type = "file"
elif (not self._is_network() and
elif (not self.is_network() and
self._path and
not self._conn.is_remote()):
if os.path.isdir(self._path):