virt-install: support network --disk's

Handle type=network in devicedisk.py, and wire up all the network fields
for virt-install --disk. Right now it requires manually spelling out
all the protocol, name, host/port etc fields.

The one 'magic' bit is that VirtualDisk.path will be a pretty URL when
all those network fields are specified. This is keeps things mostly
working in various parts of the code where we expect 'path' to be an
identifier for a VirtualDisk.
This commit is contained in:
Cole Robinson 2014-12-06 18:33:11 -05:00
parent c5f5827499
commit cd305da3f8
8 changed files with 159 additions and 11 deletions

View File

@ -77,6 +77,18 @@
<source volume="some-rbd-vol" pool="rbd-ceph"/> <source volume="some-rbd-vol" pool="rbd-ceph"/>
<target dev="hdd" bus="ide"/> <target dev="hdd" bus="ide"/>
</disk> </disk>
<disk type="network" device="disk">
<source protocol="http" name="/path/to/my/file">
<host name="example.com" port="8000"/>
</source>
<target dev="sdb" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="nbd">
<host transport="unix" socket="/tmp/socket"/>
</source>
<target dev="sdc" bus="scsi"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"> <controller type="usb" index="0" model="ich9-ehci1">
<address type="pci" domain="0" bus="0" slot="4" function="7"/> <address type="pci" domain="0" bus="0" slot="4" function="7"/>
</controller> </controller>
@ -226,6 +238,18 @@
<source volume="some-rbd-vol" pool="rbd-ceph"/> <source volume="some-rbd-vol" pool="rbd-ceph"/>
<target dev="hdd" bus="ide"/> <target dev="hdd" bus="ide"/>
</disk> </disk>
<disk type="network" device="disk">
<source protocol="http" name="/path/to/my/file">
<host name="example.com" port="8000"/>
</source>
<target dev="sdb" bus="scsi"/>
</disk>
<disk type="network" device="disk">
<source protocol="nbd">
<host transport="unix" socket="/tmp/socket"/>
</source>
<target dev="sdc" bus="scsi"/>
</disk>
<controller type="usb" index="0" model="ich9-ehci1"> <controller type="usb" index="0" model="ich9-ehci1">
<address type="pci" domain="0" bus="0" slot="4" function="7"/> <address type="pci" domain="0" bus="0" slot="4" function="7"/>
</controller> </controller>

View File

@ -562,6 +562,8 @@ c.add_compare("""--hvm --pxe \
--disk device=cdrom,bus=sata,read_bytes_sec=1,read_iops_sec=2,total_bytes_sec=10,total_iops_sec=20,write_bytes_sec=5,write_iops_sec=6 \ --disk device=cdrom,bus=sata,read_bytes_sec=1,read_iops_sec=2,total_bytes_sec=10,total_iops_sec=20,write_bytes_sec=5,write_iops_sec=6 \
--disk size=1 \ --disk size=1 \
--disk source_pool=rbd-ceph,source_volume=some-rbd-vol \ --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 \
--serial tcp,host=:2222,mode=bind,protocol=telnet \ --serial tcp,host=:2222,mode=bind,protocol=telnet \
--filesystem /source,/target,mode=squash \ --filesystem /source,/target,mode=squash \
--network user,mac=12:34:56:78:11:22,portgroup=foo \ --network user,mac=12:34:56:78:11:22,portgroup=foo \

View File

@ -68,6 +68,22 @@
<target dev='vdb' bus='virtio'/> <target dev='vdb' bus='virtio'/>
<readonly/> <readonly/>
</disk> </disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw'/>
<source protocol='rbd' name='pool/image'>
<host name='mon1.example.org' port='6321'/>
<host name='mon2.example.org' port='6322'/>
<host name='mon3.example.org' port='6322'/>
</source>
<target dev='vdc' bus='virtio'/>
</disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw'/>
<source protocol='nbd'>
<host transport='unix' socket='/var/run/nbdsock'/>
</source>
<target dev='vdd' bus='virtio'/>
</disk>
<input type="mouse" bus="ps2"/> <input type="mouse" bus="ps2"/>
<graphics type="vnc" display=":3.4" xauth="/tmp/.Xauthority"/> <graphics type="vnc" display=":3.4" xauth="/tmp/.Xauthority"/>
<console type="pty"/> <console type="pty"/>

View File

@ -36,9 +36,12 @@
<source dev="/dev/null"/> <source dev="/dev/null"/>
<target dev="hdd" bus="ide"/> <target dev="hdd" bus="ide"/>
</disk> </disk>
<disk type="block" device="cdrom"> <disk type="network" device="cdrom">
<target dev="sda" bus="scsi"/> <target dev="sda" bus="scsi"/>
<readonly/> <readonly/>
<source protocol="http" name="/my/file">
<host name="exaaaaample.com"/>
</source>
</disk> </disk>
<disk type="file" device="floppy"> <disk type="file" device="floppy">
<target dev="fda" bus="fdc"/> <target dev="fda" bus="fdc"/>
@ -66,10 +69,26 @@
</disk> </disk>
<disk type="volume" device="disk"> <disk type="volume" device="disk">
<driver name="qemu"/> <driver name="qemu"/>
<source pool="anotherPool" volume="foobar"/> <source pool="anotherPool" volume="newvol"/>
<target dev="vdb" bus="virtio"/> <target dev="vdb" bus="virtio"/>
<readonly/> <readonly/>
</disk> </disk>
<disk type="network" device="disk">
<driver name="qemu" type="raw"/>
<source protocol="gluster" name="new-val/vol">
<host name="diff.example.org" port="1234"/>
<host name="mon2.example.org" port="6322"/>
<host name="mon3.example.org" port="6322"/>
</source>
<target dev="vdc" bus="virtio"/>
</disk>
<disk type="network" device="disk">
<driver name="qemu" type="raw"/>
<source protocol="nbd">
<host transport="unix" socket="/var/run/nbdsock"/>
</source>
<target dev="vdd" bus="virtio"/>
</disk>
<input type="mouse" bus="ps2"/> <input type="mouse" bus="ps2"/>
<graphics type="vnc" display=":3.4" xauth="/tmp/.Xauthority"/> <graphics type="vnc" display=":3.4" xauth="/tmp/.Xauthority"/>
<console type="pty"/> <console type="pty"/>

View File

@ -347,6 +347,14 @@ class XMLParseTest(unittest.TestCase):
check("bus", "ide", "fdc") check("bus", "ide", "fdc")
check("error_policy", "stop", None) check("error_policy", "stop", None)
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")
disk.sync_path_props()
check("path", "http://exaaaaample.com/my/file")
disk = _get_disk("fda") disk = _get_disk("fda")
check = self._make_checker(disk) check = self._make_checker(disk)
check("path", None, "/dev/default-pool/default-vol") check("path", None, "/dev/default-pool/default-vol")
@ -369,6 +377,22 @@ class XMLParseTest(unittest.TestCase):
disk = _get_disk("vdb") disk = _get_disk("vdb")
check = self._make_checker(disk) check = self._make_checker(disk)
check("source_pool", "defaultPool", "anotherPool") check("source_pool", "defaultPool", "anotherPool")
check("source_volume", "foobar", "newvol")
disk = _get_disk("vdc")
check = self._make_checker(disk)
check("source_protocol", "rbd", "gluster")
check("source_name", "pool/image", "new-val/vol")
check("source_host_name", "mon1.example.org", "diff.example.org")
check("source_host_port", 6321, 1234)
check("path", "gluster://diff.example.org:1234/new-val/vol")
disk = _get_disk("vdd")
check = self._make_checker(disk)
check("source_protocol", "nbd")
check("source_host_transport", "unix")
check("source_host_socket", "/var/run/nbdsock")
check("path", "nbd+unix:///var/run/nbdsock")
self._alter_compare(guest.get_xml_config(), outfile) self._alter_compare(guest.get_xml_config(), outfile)

View File

@ -1486,6 +1486,13 @@ class ParserDisk(VirtCLIParser):
self.set_param("source_pool", "source_pool") self.set_param("source_pool", "source_pool")
self.set_param("source_volume", "source_volume") self.set_param("source_volume", "source_volume")
self.set_param("source_name", "source_name")
self.set_param("source_protocol", "source_protocol")
self.set_param("source_host_name", "source_host_name")
self.set_param("source_host_port", "source_host_port")
self.set_param("source_host_socket", "source_host_socket")
self.set_param("source_host_transport", "source_host_transport")
self.set_param("path", "path") self.set_param("path", "path")
self.set_param("device", "device") self.set_param("device", "device")
self.set_param("bus", "bus") self.set_param("bus", "bus")

View File

@ -139,7 +139,8 @@ class VirtualDisk(VirtualDevice):
TYPE_BLOCK = "block" TYPE_BLOCK = "block"
TYPE_DIR = "dir" TYPE_DIR = "dir"
TYPE_VOLUME = "volume" TYPE_VOLUME = "volume"
types = [TYPE_FILE, TYPE_BLOCK, TYPE_DIR, TYPE_VOLUME] TYPE_NETWORK = "network"
types = [TYPE_FILE, TYPE_BLOCK, TYPE_DIR, TYPE_NETWORK]
IO_MODE_NATIVE = "native" IO_MODE_NATIVE = "native"
IO_MODE_THREADS = "threads" IO_MODE_THREADS = "threads"
@ -490,7 +491,9 @@ class VirtualDisk(VirtualDevice):
"driver_name", "driver_type", "driver_name", "driver_type",
"driver_cache", "driver_discard", "driver_io", "error_policy", "driver_cache", "driver_discard", "driver_io", "error_policy",
"_source_file", "_source_dev", "_source_dir", "_source_file", "_source_dev", "_source_dir",
"source_volume", "source_pool", "source_volume", "source_pool", "source_protocol", "source_name",
"source_host_name", "source_host_port",
"source_host_transport", "source_host_socket",
"target", "bus", "target", "bus",
] ]
@ -506,6 +509,10 @@ class VirtualDisk(VirtualDevice):
############################# #############################
def _get_path(self): def _get_path(self):
if self.type == VirtualDisk.TYPE_NETWORK:
# Fill in a completed URL for virt-manager UI, path comparison, etc
return self._url_from_network_source()
if self._storage_creator: if self._storage_creator:
return self._storage_creator.path return self._storage_creator.path
return self._storage_backend.path return self._storage_backend.path
@ -585,11 +592,42 @@ class VirtualDisk(VirtualDevice):
source_pool = XMLProperty("./source/@pool") source_pool = XMLProperty("./source/@pool")
source_volume = XMLProperty("./source/@volume") source_volume = XMLProperty("./source/@volume")
def _get_default_type(self): source_name = XMLProperty("./source/@name")
source_protocol = XMLProperty("./source/@protocol")
# Technically multiple host lines can be listed
source_host_name = XMLProperty("./source/host/@name")
source_host_port = XMLProperty("./source/host/@port", is_int=True)
source_host_transport = XMLProperty("./source/host/@transport")
source_host_socket = XMLProperty("./source/host/@socket")
def _url_from_network_source(self):
ret = self.source_protocol
if self.source_host_transport:
ret += "+%s" % self.source_host_transport
ret += "://"
if self.source_host_name:
ret += self.source_host_name
if self.source_host_port:
ret += ":" + str(self.source_host_port)
if self.source_name:
if not self.source_name.startswith("/"):
ret += "/"
ret += self.source_name
elif self.source_host_socket:
if not self.source_host_socket.startswith("/"):
ret += "/"
ret += self.source_host_socket
return ret
def _get_default_type(self, skip_backend=False):
if self.source_pool or self.source_volume: if self.source_pool or self.source_volume:
return VirtualDisk.TYPE_VOLUME return VirtualDisk.TYPE_VOLUME
if self.source_protocol:
return VirtualDisk.TYPE_NETWORK
if self._storage_creator: if self._storage_creator:
return self._storage_creator.get_dev_type() return self._storage_creator.get_dev_type()
if not self.__storage_backend and skip_backend:
return self.TYPE_FILE
return self._storage_backend.get_dev_type() return self._storage_backend.get_dev_type()
type = XMLProperty("./@type", default_cb=_get_default_type) type = XMLProperty("./@type", default_cb=_get_default_type)
@ -602,6 +640,12 @@ class VirtualDisk(VirtualDevice):
self._source_dir = None self._source_dir = None
self.source_volume = None self.source_volume = None
self.source_pool = None self.source_pool = None
self.source_name = None
self.source_protocol = None
self.source_host_name = None
self.source_host_port = None
self.source_host_transport = None
self.source_host_socket = None
def _disk_type_to_object_prop_name(self): def _disk_type_to_object_prop_name(self):
disk_type = self.type disk_type = self.type
@ -673,8 +717,11 @@ class VirtualDisk(VirtualDevice):
path = None path = None
vol_object = None vol_object = None
parent_pool = None parent_pool = None
is_network = False
typ = self._get_default_type(skip_backend=True)
is_network = (typ == VirtualDisk.TYPE_NETWORK)
if self.source_pool and self.source_volume: if typ == VirtualDisk.TYPE_VOLUME:
conn = self.conn conn = self.conn
is_weak = "weakref" in str(type(conn)) is_weak = "weakref" in str(type(conn))
if is_weak: if is_weak:
@ -695,7 +742,7 @@ class VirtualDisk(VirtualDevice):
path = self._get_xmlpath() path = self._get_xmlpath()
return diskbackend.StorageBackend(self.conn, path, return diskbackend.StorageBackend(self.conn, path,
vol_object, parent_pool) vol_object, parent_pool, is_network=is_network)
def _get_storage_backend(self): def _get_storage_backend(self):
if self.__storage_backend is None: if self.__storage_backend is None:
@ -747,7 +794,8 @@ class VirtualDisk(VirtualDevice):
self.driver_type = self._get_default_driver_type() self.driver_type = self._get_default_driver_type()
# Need to retrigger this if self.type changed # Need to retrigger this if self.type changed
self._set_xmlpath(path) if path:
self._set_xmlpath(path)
def wants_storage_creation(self): def wants_storage_creation(self):
""" """

View File

@ -373,12 +373,14 @@ class StorageBackend(_StorageBase):
Class that carries all the info about any existing storage that Class that carries all the info about any existing storage that
the disk references the disk references
""" """
def __init__(self, conn, path, vol_object, parent_pool): def __init__(self, conn, path, vol_object, parent_pool,
is_network=False):
_StorageBase.__init__(self, conn) _StorageBase.__init__(self, conn)
self._vol_object = vol_object self._vol_object = vol_object
self._parent_pool = parent_pool self._parent_pool = parent_pool
self._path = path self._path = path
self._is_network = is_network
if self._vol_object is not None: if self._vol_object is not None:
self._path = None self._path = None
@ -437,10 +439,14 @@ class StorageBackend(_StorageBase):
self._exists = True self._exists = True
elif self._vol_object: elif self._vol_object:
self._exists = True self._exists = True
elif not self._conn.is_remote() and os.path.exists(self._path): elif (not self._is_network and
not self._conn.is_remote() and
os.path.exists(self._path)):
self._exists = True self._exists = True
elif self._parent_pool: elif self._parent_pool:
self._exists = False self._exists = False
elif self._is_network:
self._exists = True
elif (self._conn.is_remote() and elif (self._conn.is_remote() and
not _can_auto_manage(self._path)): not _can_auto_manage(self._path)):
# This allows users to pass /dev/sdX and we don't try to # This allows users to pass /dev/sdX and we don't try to
@ -466,7 +472,9 @@ class StorageBackend(_StorageBase):
else: else:
self._dev_type = "file" self._dev_type = "file"
elif self._path and not self._conn.is_remote(): elif (not self._is_network and
self._path and
not self._conn.is_remote()):
if os.path.isdir(self._path): if os.path.isdir(self._path):
self._dev_type = "dir" self._dev_type = "dir"
elif util.stat_disk(self._path)[0]: elif util.stat_disk(self._path)[0]: