From cd305da3f889e63c3d7fd9c3f7591cd2a3f42624 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sat, 6 Dec 2014 18:33:11 -0500 Subject: [PATCH] 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. --- .../compare/virt-install-many-devices.xml | 24 ++++++++ tests/clitest.py | 2 + tests/xmlparse-xml/change-disk-in.xml | 16 +++++ tests/xmlparse-xml/change-disk-out.xml | 23 ++++++- tests/xmlparse.py | 24 ++++++++ virtinst/cli.py | 7 +++ virtinst/devicedisk.py | 60 +++++++++++++++++-- virtinst/diskbackend.py | 14 ++++- 8 files changed, 159 insertions(+), 11 deletions(-) diff --git a/tests/cli-test-xml/compare/virt-install-many-devices.xml b/tests/cli-test-xml/compare/virt-install-many-devices.xml index 637c91ec..1aee2791 100644 --- a/tests/cli-test-xml/compare/virt-install-many-devices.xml +++ b/tests/cli-test-xml/compare/virt-install-many-devices.xml @@ -77,6 +77,18 @@ + + + + + + + + + + + +
@@ -226,6 +238,18 @@ + + + + + + + + + + + +
diff --git a/tests/clitest.py b/tests/clitest.py index 32e73645..2d010147 100644 --- a/tests/clitest.py +++ b/tests/clitest.py @@ -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 size=1 \ --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 \ --filesystem /source,/target,mode=squash \ --network user,mac=12:34:56:78:11:22,portgroup=foo \ diff --git a/tests/xmlparse-xml/change-disk-in.xml b/tests/xmlparse-xml/change-disk-in.xml index 2136be95..ba5df828 100644 --- a/tests/xmlparse-xml/change-disk-in.xml +++ b/tests/xmlparse-xml/change-disk-in.xml @@ -68,6 +68,22 @@ + + + + + + + + + + + + + + + + diff --git a/tests/xmlparse-xml/change-disk-out.xml b/tests/xmlparse-xml/change-disk-out.xml index e6b60b95..421ac5ce 100644 --- a/tests/xmlparse-xml/change-disk-out.xml +++ b/tests/xmlparse-xml/change-disk-out.xml @@ -36,9 +36,12 @@ - + + + + @@ -66,10 +69,26 @@ - + + + + + + + + + + + + + + + + + diff --git a/tests/xmlparse.py b/tests/xmlparse.py index f36b57c9..99d4b30e 100644 --- a/tests/xmlparse.py +++ b/tests/xmlparse.py @@ -347,6 +347,14 @@ class XMLParseTest(unittest.TestCase): check("bus", "ide", "fdc") 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") check = self._make_checker(disk) check("path", None, "/dev/default-pool/default-vol") @@ -369,6 +377,22 @@ class XMLParseTest(unittest.TestCase): disk = _get_disk("vdb") check = self._make_checker(disk) 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) diff --git a/virtinst/cli.py b/virtinst/cli.py index b683c261..e3b1b794 100644 --- a/virtinst/cli.py +++ b/virtinst/cli.py @@ -1486,6 +1486,13 @@ class ParserDisk(VirtCLIParser): self.set_param("source_pool", "source_pool") 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("device", "device") self.set_param("bus", "bus") diff --git a/virtinst/devicedisk.py b/virtinst/devicedisk.py index f6689a4a..28ee0423 100644 --- a/virtinst/devicedisk.py +++ b/virtinst/devicedisk.py @@ -139,7 +139,8 @@ class VirtualDisk(VirtualDevice): TYPE_BLOCK = "block" TYPE_DIR = "dir" 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_THREADS = "threads" @@ -490,7 +491,9 @@ class VirtualDisk(VirtualDevice): "driver_name", "driver_type", "driver_cache", "driver_discard", "driver_io", "error_policy", "_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", ] @@ -506,6 +509,10 @@ class VirtualDisk(VirtualDevice): ############################# 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: return self._storage_creator.path return self._storage_backend.path @@ -585,11 +592,42 @@ class VirtualDisk(VirtualDevice): source_pool = XMLProperty("./source/@pool") 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: return VirtualDisk.TYPE_VOLUME + if self.source_protocol: + return VirtualDisk.TYPE_NETWORK if self._storage_creator: 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() type = XMLProperty("./@type", default_cb=_get_default_type) @@ -602,6 +640,12 @@ class VirtualDisk(VirtualDevice): self._source_dir = None self.source_volume = 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): disk_type = self.type @@ -673,8 +717,11 @@ class VirtualDisk(VirtualDevice): path = None vol_object = 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 is_weak = "weakref" in str(type(conn)) if is_weak: @@ -695,7 +742,7 @@ class VirtualDisk(VirtualDevice): path = self._get_xmlpath() return diskbackend.StorageBackend(self.conn, path, - vol_object, parent_pool) + vol_object, parent_pool, is_network=is_network) def _get_storage_backend(self): if self.__storage_backend is None: @@ -747,7 +794,8 @@ class VirtualDisk(VirtualDevice): self.driver_type = self._get_default_driver_type() # Need to retrigger this if self.type changed - self._set_xmlpath(path) + if path: + self._set_xmlpath(path) def wants_storage_creation(self): """ diff --git a/virtinst/diskbackend.py b/virtinst/diskbackend.py index bbad5880..8e795b6b 100644 --- a/virtinst/diskbackend.py +++ b/virtinst/diskbackend.py @@ -373,12 +373,14 @@ class StorageBackend(_StorageBase): Class that carries all the info about any existing storage that 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) self._vol_object = vol_object self._parent_pool = parent_pool self._path = path + self._is_network = is_network if self._vol_object is not None: self._path = None @@ -437,10 +439,14 @@ class StorageBackend(_StorageBase): self._exists = True elif self._vol_object: 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 elif self._parent_pool: self._exists = False + elif self._is_network: + self._exists = True elif (self._conn.is_remote() and not _can_auto_manage(self._path)): # This allows users to pass /dev/sdX and we don't try to @@ -466,7 +472,9 @@ class StorageBackend(_StorageBase): else: 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): self._dev_type = "dir" elif util.stat_disk(self._path)[0]: