diff --git a/COT/edit_hardware.py b/COT/edit_hardware.py index 4b3ec67..d06d7ff 100644 --- a/COT/edit_hardware.py +++ b/COT/edit_hardware.py @@ -57,8 +57,8 @@ class COTEditHardware(COTSubmodule): :attr:`nic_names`, :attr:`serial_ports`, :attr:`serial_connectivity`, - :attr:`scsi_subtype`, - :attr:`ide_subtype`, + :attr:`scsi_subtypes`, + :attr:`ide_subtypes`, :attr:`virtual_system_type` """ @@ -88,10 +88,10 @@ def __init__(self, UI): self._serial_ports = None self.serial_connectivity = None """List of serial connection strings.""" - self.scsi_subtype = None - """Subtype string for SCSI controllers""" - self.ide_subtype = None - """Subtype string for IDE controllers""" + self.scsi_subtypes = None + """Subtype string list for SCSI controllers""" + self.ide_subtypes = None + """Subtype string list for IDE controllers""" self.virtual_system_type = None """Virtual system type""" @@ -172,7 +172,7 @@ def nic_type(self): .. deprecated:: 1.5 Use :attr:`nic_types` instead. """ - warnings.warn("Use nic_type instead", DeprecationWarning) + warnings.warn("Use nic_types instead", DeprecationWarning) if self.nic_types is None: return None if len(self.nic_types) > 1: @@ -210,6 +210,48 @@ def serial_ports(self, value): self.vm.platform.validate_serial_count(value) self._serial_ports = value + @property + def scsi_subtype(self): + """SCSI controller subtype string to set. + + .. deprecated:: 1.5 + Use :attr:`scsi_subtypes` instead. + """ + warnings.warn("Use scsi_subtypes instead", DeprecationWarning) + if self.scsi_subtypes is None: + return None + if len(self.scsi_subtypes) > 1: + raise TypeError("scsi_subtypes has more than one element ({0}). " + "Use scsi_subtypes instead of scsi_subtype." + .format(self.scsi_subtypes)) + return self.scsi_subtypes[0] + + @scsi_subtype.setter + def scsi_subtype(self, value): + warnings.warn("Use scsi_subtypes instead", DeprecationWarning) + self.scsi_subtypes = [value] + + @property + def ide_subtype(self): + """NIC type string to set. + + .. deprecated:: 1.5 + Use :attr:`ide_subtypes` instead. + """ + warnings.warn("Use ide_subtypes instead", DeprecationWarning) + if self.ide_subtypes is None: + return None + if len(self.ide_subtypes) > 1: + raise TypeError("ide_subtypes has more than one element ({0}). " + "Use ide_subtypes instead of ide_subtype." + .format(self.ide_subtypes)) + return self.ide_subtypes[0] + + @ide_subtype.setter + def ide_subtype(self, value): + warnings.warn("Use ide_subtypes instead", DeprecationWarning) + self.ide_subtypes = [value] + def ready_to_run(self): """Check whether the module is ready to :meth:`run`. @@ -228,8 +270,8 @@ def ready_to_run(self): self.nic_names is None and self.serial_ports is None and self.serial_connectivity is None and - self.scsi_subtype is None and - self.ide_subtype is None and + self.scsi_subtypes is None and + self.ide_subtypes is None and self.virtual_system_type is None ): return (False, "No work requested! Please specify at least " @@ -360,11 +402,11 @@ def run(self): len(self.serial_connectivity))) vm.set_serial_connectivity(self.serial_connectivity, self.profiles) - if self.scsi_subtype is not None: - vm.set_scsi_subtype(self.scsi_subtype, self.profiles) + if self.scsi_subtypes is not None: + vm.set_scsi_subtypes(self.scsi_subtypes, self.profiles) - if self.ide_subtype is not None: - vm.set_ide_subtype(self.ide_subtype, self.profiles) + if self.ide_subtypes is not None: + vm.set_ide_subtypes(self.ide_subtypes, self.profiles) def create_subparser(self, parent, storage): """Add subparser for the CLI of this submodule. @@ -385,10 +427,10 @@ def create_subparser(self, parent, storage): "PACKAGE [-o OUTPUT] -v TYPE [TYPE2 ...]", "PACKAGE [-o OUTPUT] \ [-p PROFILE [PROFILE2 ...] [--delete-all-other-profiles]] [-c CPUS] \ -[-m MEMORY] [-n NICS] [--nic-types [{e1000,virtio,vmxnet3} ...]] \ +[-m MEMORY] [-n NICS] [--nic-types TYPE [TYPE2 ...]] \ [-N NETWORK [NETWORK2 ...]] [-M MAC1 [MAC2 ...]] \ [--nic-names NAME1 [NAME2 ...]] [-s SERIAL_PORTS] [-S URI1 [URI2 ...]] \ -[--scsi-subtype SCSI_SUBTYPE] [--ide-subtype IDE_SUBTYPE]", +[--scsi-subtypes TYPE [TYPE2 ...]] [--ide-subtypes TYPE [TYPE2 ...]]", ]), help="Edit virtual machine hardware properties of an OVF", description="Edit hardware properties of the specified OVF or OVA", @@ -484,13 +526,15 @@ def create_subparser(self, parent, storage): g = p.add_argument_group("disk and disk controller options") - g.add_argument('--scsi-subtype', - help='Set resource subtype (such as "lsilogic" or ' + g.add_argument('--scsi-subtypes', action='append', nargs='+', + metavar=('TYPE', 'TYPE2'), + help='Set resource subtype(s) (such as "lsilogic" or ' '"virtio") for all SCSI controllers. If an empty ' "string is provided, any existing subtype will be " "removed.") - g.add_argument('--ide-subtype', - help='Set resource subtype (such as "virtio") for ' + g.add_argument('--ide-subtypes', action='append', nargs='+', + metavar=('TYPE', 'TYPE2'), + help='Set resource subtype(s) (such as "virtio") for ' "all IDE controllers. If an empty string is " "provided, any existing subtype will be removed.") diff --git a/COT/ovf.py b/COT/ovf.py index 621a096..8fcc0cd 100644 --- a/COT/ovf.py +++ b/COT/ovf.py @@ -1325,26 +1325,28 @@ def get_serial_connectivity(self, profile): return [item.get_value(self.ADDRESS) for item in self.hardware.find_all_items('serial', profile_list=[profile])] - def set_scsi_subtype(self, type, profile_list): - """Set the device subtype for the SCSI controller(s). + def set_scsi_subtypes(self, type_list, profile_list): + """Set the device subtype(s) for the SCSI controller(s). - :param str type: SCSI subtype string + :param list type_list: SCSI subtype string list :param list profile_list: Change only the given profiles """ # TODO validate supported types by platform self.hardware.set_value_for_all_items('scsi', - self.RESOURCE_SUB_TYPE, type, + self.RESOURCE_SUB_TYPE, + " ".join(type_list), profile_list) - def set_ide_subtype(self, type, profile_list): - """Set the device subtype for the IDE controller(s). + def set_ide_subtypes(self, type_list, profile_list): + """Set the device subtype(s) for the IDE controller(s). - :param str type: IDE subtype string + :param list type_list: IDE subtype string list :param list profile_list: Change only the given profiles """ # TODO validate supported types by platform self.hardware.set_value_for_all_items('ide', - self.RESOURCE_SUB_TYPE, type, + self.RESOURCE_SUB_TYPE, + " ".join(type_list), profile_list) def get_property_value(self, key): diff --git a/COT/tests/test_edit_hardware.py b/COT/tests/test_edit_hardware.py index 1dc8a98..3c50822 100644 --- a/COT/tests/test_edit_hardware.py +++ b/COT/tests/test_edit_hardware.py @@ -1164,6 +1164,7 @@ def test_set_scsi_subtype_all_profiles(self): """Set SCSI controller subtype under all profiles.""" self.instance.package = self.input_ovf self.instance.scsi_subtype = "virtio" + self.assertEqual(self.instance.scsi_subtype, "virtio") self.instance.run() self.instance.finished() self.check_diff(""" @@ -1177,6 +1178,9 @@ def test_clear_scsi_subtype_all_profiles(self): """Clear SCSI controller subtype under all profiles.""" self.instance.package = self.input_ovf self.instance.scsi_subtype = "" + self.assertEqual(self.instance.scsi_subtype, "") + # TODO: this should really be an empty list or None + self.assertEqual(self.instance.scsi_subtypes, [""]) self.instance.run() self.instance.finished() self.check_diff(""" @@ -1188,7 +1192,10 @@ def test_clear_scsi_subtype_all_profiles(self): def test_set_scsi_subtype_one_profile(self): """Set SCSI controller subtype under a single profile.""" self.instance.package = self.input_ovf - self.instance.scsi_subtype = "virtio" + self.instance.scsi_subtypes = ['buslogic', 'lsilogic'] + self.assertEqual(self.instance.scsi_subtypes, ['buslogic', 'lsilogic']) + with self.assertRaises(TypeError): + self.instance.scsi_subtype self.instance.profiles = ['4CPU-4GB-3NIC'] self.instance.run() self.instance.finished() @@ -1201,7 +1208,7 @@ def test_set_scsi_subtype_one_profile(self): + SCSI Controller + SCSI Controller 0 + 3 -+ virtio ++ buslogic lsilogic + 6 + @@ -1210,6 +1217,8 @@ def test_set_scsi_subtype_one_profile(self): def test_set_scsi_subtype_no_existing(self): """Set SCSI controller subtype for an OVF with none (no-op).""" self.instance.package = self.minimal_ovf + self.assertEqual(self.instance.scsi_subtype, None) + self.assertEqual(self.instance.scsi_subtypes, None) self.instance.scsi_subtype = "virtio" self.instance.run() self.assertLogged(**self.NO_ITEMS_NO_WORK) @@ -1219,18 +1228,21 @@ def test_set_scsi_subtype_no_existing(self): def test_set_ide_subtype_all_profiles(self): """Set IDE controller subtype across all profiles.""" self.instance.package = self.input_ovf - self.instance.ide_subtype = "virtio" + self.instance.ide_subtypes = ["virtio", "foobar"] + self.assertEqual(self.instance.ide_subtypes, ["virtio", "foobar"]) + with self.assertRaises(TypeError): + self.instance.ide_subtype self.instance.run() self.instance.finished() # Since there is no pre-existing subtype, we just create it # under each controller: self.check_diff(""" 4 -+ virtio ++ virtio foobar 5 ... 5 -+ virtio ++ virtio foobar 5 """) @@ -1238,6 +1250,8 @@ def test_set_ide_subtype_one_profile(self): """Set IDE controller subtype under a single profile.""" self.instance.package = self.input_ovf self.instance.ide_subtype = "virtio" + self.assertEqual(self.instance.ide_subtype, "virtio") + self.assertEqual(self.instance.ide_subtypes, ["virtio"]) self.instance.profiles = ['4CPU-4GB-3NIC'] self.instance.run() self.instance.finished() @@ -1270,6 +1284,8 @@ def test_set_ide_subtype_one_profile(self): def test_set_ide_subtype_no_existing(self): """Set IDE controller subtype for an OVF with none (no-op).""" self.instance.package = self.minimal_ovf + self.assertEqual(self.instance.ide_subtype, None) + self.assertEqual(self.instance.ide_subtypes, None) self.instance.ide_subtype = "virtio" self.instance.run() self.assertLogged(**self.NO_ITEMS_NO_WORK) diff --git a/COT/vm_description.py b/COT/vm_description.py index c1a52b5..21b492a 100644 --- a/COT/vm_description.py +++ b/COT/vm_description.py @@ -545,18 +545,42 @@ def get_serial_connectivity(self, profile): def set_scsi_subtype(self, type, profile_list): """Set the device subtype for the SCSI controller(s). + .. deprecated:: 1.5 + Use :func:`set_scsi_subtypes` instead. + :param str type: SCSI subtype string :param list profile_list: Change only the given profiles """ - raise NotImplementedError("set_scsi_subtype not implemented!") + warnings.warn("Use set_scsi_subtypes() instead", DeprecationWarning) + self.set_scsi_subtypes([type], profile_list) + + def set_scsi_subtypes(self, type_list, profile_list): + """Set the device subtype list for the SCSI controller(s). + + :param list type_list: SCSI subtype string list + :param list profile_list: Change only the given profiles + """ + raise NotImplementedError("set_scsi_subtypes not implemented!") def set_ide_subtype(self, type, profile_list): """Set the device subtype for the IDE controller(s). + .. deprecated:: 1.5 + Use :func:`set_ide_subtypes` instead. + :param str type: IDE subtype string :param list profile_list: Change only the given profiles """ - raise NotImplementedError("set_ide_subtype not implemented!") + warnings.warn("Use set_ide_subtypes() instead", DeprecationWarning) + self.set_ide_subtypes([type], profile_list) + + def set_ide_subtypes(self, type_list, profile_list): + """Set the device subtype list for the IDE controller(s). + + :param list type: IDE subtype string list + :param list profile_list: Change only the given profiles + """ + raise NotImplementedError("set_ide_subtypes not implemented!") # API methods needed for edit-product # API methods needed for edit-properties